FDForm.cs 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Drawing.Drawing2D;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. using System.Windows.Forms;
  11. namespace ImpulseVision
  12. {
  13. public partial class EgoldsFormStyle : Component
  14. {
  15. #region -- Свойста --
  16. public Form Form { get; set; }
  17. private fStyle formStyle = fStyle.None;
  18. public fStyle FormStyle
  19. {
  20. get => formStyle;
  21. set
  22. {
  23. formStyle = value;
  24. if (Site.DesignMode) return;
  25. if (StyleUsed == false)
  26. {
  27. // Если стиль не был использован, то:
  28. Sign();
  29. }
  30. else
  31. {
  32. // Если стиль был использован то:
  33. SetStyle(formStyle);
  34. }
  35. }
  36. }
  37. public enum fStyle // Набор стилей
  38. {
  39. None,
  40. UserStyle,
  41. SimpleDark,
  42. TelegramStyle
  43. }
  44. [Description("Указывает, может ли пользователь изменять размер окна")]
  45. public bool AllowUserResize { get; set; }
  46. [Description("Указывает, включен ли эффект свечения от курсора при наведении на значки меню окна")]
  47. public bool EnableControlBoxMouseLight { get; set; }
  48. /// <summary>
  49. /// Указывает, включен ли эффект свечения от значков меню окна
  50. /// </summary>
  51. [Description("Указывает, включен ли эффект свечения от значков меню окна")]
  52. public bool EnableControlBoxIconsLight { get; set; }
  53. [Description("Ширина кнопок меню окна")]
  54. public int ControlBoxButtonsWidth { get; set; } = 20;
  55. [Description("Высота шапки (заголовка)")]
  56. public int HeaderHeight { get; set; } = 38;
  57. [Description("Цвет шапки (заголовка)")]
  58. public Color HeaderColor { get; set; } = Color.DimGray;
  59. [Description("Дополнительный цвет шапки (заголовка) используемый для создания градиента (При HeaderColorGradientEnabled = true)")]
  60. public Color HeaderColorAdditional { get; set; } = Color.White;
  61. [Description("Указывает, включен ли градинт цета шапки (заголовка)")]
  62. public bool HeaderColorGradientEnable { get; set; } = false;
  63. [Description("Определяет направление линейного градиента шапки")]
  64. public LinearGradientMode HeaderColorGradientMode { get; set; } = LinearGradientMode.Horizontal;
  65. [Description("Меню быстрого доступа, отображаемое при щелчке правой кнопкой мыши на иконке окна")]
  66. public ContextMenuStrip ContextMenuForm { get; set; }
  67. [Description("Шрифт текста шапки (заголовка)")]
  68. public Font HeaderTextFont { get; set; } = new Font("Segoe UI", 9.75F, FontStyle.Regular);
  69. [Description("Цвет текста шапки (заголовка)")]
  70. public Color HeaderTextColor { get; set; } = Color.White;
  71. public Image HeaderImage { get; set; }
  72. [Description("Фоновый цвет формы")]
  73. public Color BackColor { get; set; } = Color.White;
  74. #endregion
  75. #region -- Поля --
  76. private List<Control> FormControls = new List<Control>();
  77. private Panel MainContainer = null;
  78. private Dictionary<fStyle, StylesForForm> StylesDictionary; // Словарь вида: <Стиль из набора, Объект стиля с параметрами>
  79. private StylesForForm CurrentStyle; // Актуальный стиль, класс с его параметрамы
  80. private bool StyleUsed = false; // Применялся ли стиль(тема)
  81. private Size IconSize = new Size(14, 14); // Размер икноки формы
  82. private Rectangle rectIcon = new Rectangle(); // Структура иконки формы
  83. private bool IconHovered = false; // Наведен ли курсор на иконку
  84. private StringFormat SF = new StringFormat();
  85. private bool MousePressed = false; // Кнопка мыши нажата
  86. private Point clickPosition; // Начальная позиция курсора в момент клика
  87. private Point moveStartPosition; // Начальная позиция формы в момент клика
  88. private bool CanDragForm = false; // Указывает может ли форма перетаскивается
  89. private MouseButtons LastClickedMouseButton; // Какая кнопка мыши была нажата последний раз
  90. private Size ControlBoxIconSize = new Size(10, 10); // Размер иконок меню окна
  91. private Rectangle rectBtnClose = new Rectangle(); // Структура кнопки меню окна Закрыть
  92. private Rectangle rectBtnMax = new Rectangle(); // Структура кнопки меню окна Развернуть/Свернуть в окно
  93. private Rectangle rectBtnMin = new Rectangle(); // Структура кнопки меню окна Свернуть
  94. private bool btnCloseHovered = false; // Наведен ли курсор на кнопку Закрыть
  95. private bool btnMaximizeHovered = false; // Наведен ли курсор на кнопку Развернуть/Свернуть в окно
  96. private bool btnMinimizeHovered = false; // Наведен ли курсор на кнопку Свернуть
  97. private Pen penBtnClose = new Pen(Color.White, 1.55F); // Кисть для кнопки Закрыть
  98. private Pen penBtnMaximize = new Pen(Color.DarkGray, 1.55F); // Кисть для кнопки Развернуть/Свернуть в окно
  99. private Pen penBtnMinimize = new Pen(Color.Gray, 1.55F); // Кисть для кнопки Свернуть
  100. private Rectangle rectHeader = new Rectangle(); // Структура заголовка формы
  101. private Rectangle rectBorder = new Rectangle(); // Структура обводки
  102. private int ResizeBorderSize = 4; // Размер невидимой границы при наведении на которую меняется курсор, чтобы изменять размер формы
  103. private int ResizeAngleBorderOffset = 15; // Смещение от углов, где мы трактуем угловую часть для изменения размера по углам
  104. private bool IsResizing = false; // Режим изменения размера
  105. private BorderHoverPositionEnum BorderHoverPosition = BorderHoverPositionEnum.None; // Куда наведен курсор в отношении обводки для изменения формы
  106. enum BorderHoverPositionEnum
  107. {
  108. None, // Не наведен
  109. Left, Top, Right, Bottom, // Стороны
  110. TopLeft, TopRight, BottomLeft, BottomRight // Углы
  111. }
  112. private int ResizeStartRight = 0;
  113. private int ResizeStartBottom = 0;
  114. // Указывает, нужно ли восстановить позицию окна,
  115. // которая была, перед разворачиванием на весь экран (Maximize), с помощью перетаскивания окна вверх экана
  116. private bool FormNeedReposition = false;
  117. #endregion
  118. public EgoldsFormStyle()
  119. {
  120. InitializeComponent();
  121. }
  122. public EgoldsFormStyle(IContainer container)
  123. {
  124. DefineStyles();
  125. container.Add(this);
  126. InitializeComponent();
  127. }
  128. /// <summary>
  129. /// Определение стилей (тем)
  130. /// </summary>
  131. private void DefineStyles()
  132. {
  133. StylesDictionary = new Dictionary<fStyle, StylesForForm>();
  134. // Стиль стандартной формы, без параметров, кроме HeaderHeight
  135. StylesDictionary.Add(fStyle.None,
  136. new StylesForForm()
  137. {
  138. HeaderHeight = 0
  139. });
  140. // Стиль пользователя, на основе параметров компонента, параметры устанавливаются в SaveUserStyleConfig()
  141. StylesDictionary.Add(fStyle.UserStyle,
  142. new StylesForForm()
  143. {
  144. FormBorderStyle = FormBorderStyle.None
  145. });
  146. // Стиль SimpleDark
  147. StylesDictionary.Add(fStyle.SimpleDark,
  148. new StylesForForm()
  149. {
  150. FormBorderStyle = FormBorderStyle.None,
  151. BackColor = Color.White,
  152. HeaderHeight = 38,
  153. HeaderColor = FlatColors.WetAsphalt,
  154. HeaderTextColor = Color.White,
  155. HeaderTextFont = new Font("Segoe UI", 9.75F, FontStyle.Regular),
  156. ControlBoxButtonsWidth = HeaderHeight,
  157. ControlBoxIconsSize = new Size(10, 10),
  158. UseSecondControlBoxIconsColorOnHover = false, // <-
  159. ControlBoxEnabledIconsColor = Color.White
  160. });
  161. // Стиль TelegramStyle
  162. StylesDictionary.Add(fStyle.TelegramStyle,
  163. new StylesForForm()
  164. {
  165. FormBorderStyle = FormBorderStyle.None,
  166. BackColor = Color.White,
  167. HeaderHeight = 20,
  168. HeaderColor = FlatColors.GrayLight2,
  169. HeaderTextColor = Color.Gray,
  170. HeaderTextFont = new Font("Segoe UI", 9F, FontStyle.Bold),
  171. ControlBoxButtonsWidth = 24,
  172. ControlBoxIconsSize = new Size(8, 8),
  173. UseSecondControlBoxIconsColorOnHover = true,
  174. ControlBoxEnabledIconsColor = Color.Gray,
  175. ControlBoxOnHoverIconsColor = Color.White
  176. });
  177. }
  178. /// <summary>
  179. /// Сохранение значения свойста FormBorderStyle стандартной формы в стиль "NoneStyle", выполняется только один раз
  180. /// </summary>
  181. private void SaveNoneStyleConfig()
  182. {
  183. if (StylesDictionary.ContainsKey(fStyle.None) && StyleUsed == false)
  184. {
  185. StylesForForm NoneStyle = StylesDictionary[fStyle.None];
  186. NoneStyle.FormBorderStyle = Form.FormBorderStyle;
  187. NoneStyle.BackColor = Form.BackColor;
  188. }
  189. }
  190. private void SaveUserStyleConfig()
  191. {
  192. if (StylesDictionary.ContainsKey(fStyle.UserStyle) && StyleUsed == false)
  193. {
  194. // Стиль пользователя, на основе параметров компонента
  195. StylesForForm UserStyle = StylesDictionary[fStyle.UserStyle];
  196. UserStyle.FormBorderStyle = FormBorderStyle.None;
  197. UserStyle.HeaderHeight = HeaderHeight;
  198. UserStyle.HeaderColor = HeaderColor;
  199. UserStyle.BackColor = BackColor;
  200. UserStyle.HeaderTextColor = HeaderTextColor;
  201. UserStyle.HeaderTextFont = HeaderTextFont;
  202. UserStyle.ControlBoxButtonsWidth = ControlBoxButtonsWidth;
  203. UserStyle.ControlBoxIconsSize = ControlBoxIconSize;
  204. }
  205. }
  206. /// <summary>
  207. /// Подписываем форме новое событие, для применения стилей
  208. /// </summary>
  209. private void Sign()
  210. {
  211. if (Form != null)
  212. {
  213. // Используем событие HandleCreated, так как оно вызывается перед тем как форма загрузится
  214. Form.HandleCreated += Form_HandleCreated;
  215. // На случай если изначально форма имела стандартный стиль, тоесть не использовался данный компонент и форма уже загружена
  216. if (Form.IsHandleCreated)
  217. {
  218. Apply();
  219. Form.Refresh();
  220. }
  221. }
  222. }
  223. /// <summary>
  224. /// Первоначальная настройка формы
  225. /// </summary>
  226. private void Apply()
  227. {
  228. SaveNoneStyleConfig();
  229. SaveUserStyleConfig();
  230. MigrateControls();
  231. SetStyle(FormStyle);
  232. StyleUsed = true;
  233. SF.Alignment = StringAlignment.Near;
  234. SF.LineAlignment = StringAlignment.Center;
  235. Size minimumSize = new Size(100, 50);
  236. if (Form.MinimumSize.Width < minimumSize.Width || Form.MinimumSize.Height < minimumSize.Height)
  237. Form.MinimumSize = minimumSize;
  238. SetDoubleBuffered(Form);
  239. // Цепляем необходимые события к форме
  240. Form.Paint += Form_Paint;
  241. Form.MouseDown += Form_MouseDown;
  242. Form.MouseUp += Form_MouseUp;
  243. Form.MouseMove += Form_MouseMove;
  244. Form.MouseLeave += Form_MouseLeave;
  245. Form.SizeChanged += Form_SizeChanged;
  246. Form.DoubleClick += Form_DoubleClick;
  247. Form.Click += Form_Click;
  248. Form.BackColorChanged += Form_BackColorChanged;
  249. }
  250. /// <summary>
  251. /// Изменение стиля
  252. /// </summary>
  253. /// <param name="Style">Стиль из набора fStyle</param>
  254. private void SetStyle(fStyle Style)
  255. {
  256. FormWindowState formWindowStateTEMP = Form.WindowState;
  257. Form.WindowState = FormWindowState.Normal;
  258. if (StyleUsed)
  259. {
  260. //OffsetControls(-HeaderHeight);
  261. OffsetMainContrainer(-HeaderHeight);
  262. Form.Height -= HeaderHeight;
  263. }
  264. CurrentStyle = StylesDictionary[Style];
  265. HeaderHeight = CurrentStyle.HeaderHeight;
  266. HeaderColor = CurrentStyle.HeaderColor;
  267. BackColor = CurrentStyle.BackColor;
  268. HeaderTextFont = CurrentStyle.HeaderTextFont;
  269. HeaderTextColor = CurrentStyle.HeaderTextColor;
  270. IconSize = CurrentStyle.IconSize;
  271. ControlBoxIconSize = CurrentStyle.ControlBoxIconsSize;
  272. ControlBoxButtonsWidth = CurrentStyle.ControlBoxButtonsWidth;
  273. Form.BackColor = BackColor;
  274. //OffsetControls(HeaderHeight);
  275. OffsetMainContrainer(HeaderHeight);
  276. Form.Height += HeaderHeight;
  277. Form.Refresh();
  278. Form.FormBorderStyle = CurrentStyle.FormBorderStyle;
  279. Form.WindowState = formWindowStateTEMP;
  280. }
  281. /// <summary>
  282. /// Смещение контролов
  283. /// </summary>
  284. /// <param name="offsett"></param>
  285. private void OffsetControls(int offsett)
  286. {
  287. foreach (Control ctrl in Form.Controls)
  288. {
  289. ctrl.Location = new Point(ctrl.Location.X, ctrl.Location.Y + offsett);
  290. ctrl.Refresh();
  291. }
  292. }
  293. private void MigrateControls()
  294. {
  295. // Определение панели-контейнера
  296. MainContainer = new Panel();
  297. MainContainer.BackColor = Form.BackColor;
  298. MainContainer.Location = new Point(1, HeaderHeight + 1);
  299. ChangeMainContainerSize();
  300. // Перенос контролов на отдельную панель
  301. if (FormControls.Count == 0)
  302. FormControls.AddRange(Form.Controls.OfType<Control>());
  303. Form.Controls.Clear();
  304. if (FormControls.Count > 0)
  305. MainContainer.Controls.AddRange(FormControls.ToArray());
  306. Form.Controls.Add(MainContainer);
  307. }
  308. private void OffsetMainContrainer(int offset)
  309. {
  310. MainContainer.Location = new Point(MainContainer.Location.X, MainContainer.Location.Y + offset);
  311. MainContainer.Refresh();
  312. }
  313. private void ChangeMainContainerSize()
  314. {
  315. MainContainer.Size = new Size(Form.Width - 2, Form.Height - HeaderHeight - 2);
  316. }
  317. #region -- Form Events --
  318. // В этом событии выполняется раньше чем в Load
  319. private void Form_HandleCreated(object sender, EventArgs e)
  320. {
  321. Apply();
  322. }
  323. private void Form_Paint(object sender, PaintEventArgs e)
  324. {
  325. if (FormStyle != fStyle.None)
  326. DrawStyle(e.Graphics);
  327. }
  328. private void Form_SizeChanged(object sender, EventArgs e)
  329. {
  330. Form.Refresh();
  331. ChangeMainContainerSize();
  332. }
  333. private void Form_BackColorChanged(object sender, EventArgs e)
  334. {
  335. MainContainer.BackColor = Form.BackColor;
  336. }
  337. private void Form_MouseLeave(object sender, EventArgs e)
  338. {
  339. if (FormStyle == fStyle.None) return;
  340. btnCloseHovered = false;
  341. btnMaximizeHovered = false;
  342. btnMinimizeHovered = false;
  343. Form.Invalidate();
  344. }
  345. private void Form_MouseMove(object sender, MouseEventArgs e)
  346. {
  347. if (FormStyle == fStyle.None) return;
  348. // Dragging
  349. if (CanDragForm && e.Button == MouseButtons.Left)
  350. {
  351. if (Form.WindowState == FormWindowState.Maximized)
  352. {
  353. float maxWidth = Form.Width;
  354. float cursosOnMaxPosition = e.X;
  355. float coeff = cursosOnMaxPosition / (maxWidth / 100f) / 100f;
  356. // Change WindowState if is Maximized
  357. Form.WindowState = FormWindowState.Normal;
  358. int XFormOffset = (int)(Form.Width * coeff);
  359. Form.Location = new Point(Cursor.Position.X - XFormOffset, Cursor.Position.Y - HeaderHeight / 2);
  360. moveStartPosition = Form.Location;
  361. clickPosition = Cursor.Position;
  362. }
  363. else
  364. {
  365. // Moving
  366. Size frmOffset = new Size(Point.Subtract(Cursor.Position, new Size(clickPosition)));
  367. Form.Location = Point.Add(moveStartPosition, frmOffset);
  368. }
  369. }
  370. // Hovering
  371. else
  372. {
  373. // Close Button Hovering
  374. if (rectBtnClose.Contains(e.Location))
  375. {
  376. if (btnCloseHovered == false)
  377. {
  378. btnCloseHovered = true;
  379. if (EnableControlBoxMouseLight == false)
  380. Form.Invalidate();
  381. }
  382. if (EnableControlBoxMouseLight == true)
  383. Form.Invalidate();
  384. }
  385. else
  386. {
  387. if (btnCloseHovered == true)
  388. {
  389. btnCloseHovered = false;
  390. Form.Invalidate();
  391. }
  392. }
  393. // Maximize Button Hovering
  394. if (rectBtnMax.Contains(e.Location))
  395. {
  396. if (btnMaximizeHovered == false)
  397. {
  398. btnMaximizeHovered = true;
  399. if (EnableControlBoxMouseLight == false)
  400. Form.Invalidate();
  401. }
  402. if (EnableControlBoxMouseLight == true)
  403. Form.Invalidate();
  404. }
  405. else
  406. {
  407. if (btnMaximizeHovered)
  408. {
  409. btnMaximizeHovered = false;
  410. Form.Invalidate();
  411. }
  412. }
  413. // Minimize Button Hovering
  414. if (rectBtnMin.Contains(e.Location))
  415. {
  416. if (btnMinimizeHovered == false)
  417. {
  418. btnMinimizeHovered = true;
  419. if (EnableControlBoxMouseLight == false)
  420. Form.Invalidate();
  421. }
  422. if (EnableControlBoxMouseLight == true)
  423. Form.Invalidate();
  424. }
  425. else
  426. {
  427. if (btnMinimizeHovered)
  428. {
  429. btnMinimizeHovered = false;
  430. Form.Invalidate();
  431. }
  432. }
  433. // Icon Hovering
  434. if (rectIcon.Contains(e.Location))
  435. {
  436. IconHovered = true;
  437. }
  438. else
  439. {
  440. IconHovered = false;
  441. }
  442. }
  443. // On hover on border for resize
  444. if (AllowUserResize && IsResizing == false && Form.WindowState == FormWindowState.Normal)
  445. {
  446. if (rectBorder.Top + ResizeBorderSize >= e.Location.Y)
  447. {
  448. // Левый верхний угол
  449. if (e.Location.X <= ResizeAngleBorderOffset)
  450. {
  451. Form.Cursor = Cursors.SizeNWSE;
  452. BorderHoverPosition = BorderHoverPositionEnum.TopLeft;
  453. }
  454. // Правый верхний угол
  455. else if (e.Location.X >= rectBorder.Width - ResizeAngleBorderOffset)
  456. {
  457. Form.Cursor = Cursors.SizeNESW;
  458. BorderHoverPosition = BorderHoverPositionEnum.TopRight;
  459. }
  460. else
  461. {
  462. Form.Cursor = Cursors.SizeNS;
  463. BorderHoverPosition = BorderHoverPositionEnum.Top;
  464. }
  465. }
  466. else if (rectBorder.Bottom - ResizeBorderSize <= e.Location.Y)
  467. {
  468. // Левый нижний угол
  469. if (e.Location.X <= ResizeAngleBorderOffset)
  470. {
  471. Form.Cursor = Cursors.SizeNESW;
  472. BorderHoverPosition = BorderHoverPositionEnum.BottomLeft;
  473. }
  474. // Правый нижний угол
  475. else if (e.Location.X >= rectBorder.Width - ResizeAngleBorderOffset)
  476. {
  477. Form.Cursor = Cursors.SizeNWSE;
  478. BorderHoverPosition = BorderHoverPositionEnum.BottomRight;
  479. }
  480. else
  481. {
  482. Form.Cursor = Cursors.SizeNS;
  483. BorderHoverPosition = BorderHoverPositionEnum.Bottom;
  484. }
  485. }
  486. else if (rectBorder.Left + ResizeBorderSize >= e.Location.X)
  487. {
  488. // Левый верхний угол
  489. if (e.Location.Y <= ResizeAngleBorderOffset)
  490. {
  491. Form.Cursor = Cursors.SizeNWSE;
  492. BorderHoverPosition = BorderHoverPositionEnum.TopLeft;
  493. }
  494. // Левый нижний угол
  495. else if (e.Location.Y >= rectBorder.Height - ResizeAngleBorderOffset)
  496. {
  497. Form.Cursor = Cursors.SizeNESW;
  498. BorderHoverPosition = BorderHoverPositionEnum.BottomLeft;
  499. }
  500. else
  501. {
  502. Form.Cursor = Cursors.SizeWE;
  503. BorderHoverPosition = BorderHoverPositionEnum.Left;
  504. }
  505. }
  506. else if (rectBorder.Right - ResizeBorderSize <= e.Location.X)
  507. {
  508. // Правый верхний угол
  509. if (e.Location.Y <= ResizeAngleBorderOffset)
  510. {
  511. Form.Cursor = Cursors.SizeNESW;
  512. BorderHoverPosition = BorderHoverPositionEnum.TopRight;
  513. }
  514. // Правый нижний угол
  515. else if (e.Location.Y >= rectBorder.Height - ResizeAngleBorderOffset)
  516. {
  517. Form.Cursor = Cursors.SizeNWSE;
  518. BorderHoverPosition = BorderHoverPositionEnum.BottomRight;
  519. }
  520. else
  521. {
  522. Form.Cursor = Cursors.SizeWE;
  523. BorderHoverPosition = BorderHoverPositionEnum.Right;
  524. }
  525. }
  526. else if (Form.Cursor != Cursors.Default)
  527. {
  528. Form.Cursor = Cursors.Default;
  529. BorderHoverPosition = BorderHoverPositionEnum.None;
  530. }
  531. }
  532. // Resize
  533. else if (AllowUserResize && IsResizing && Form.WindowState == FormWindowState.Normal)
  534. {
  535. // Resize
  536. switch (BorderHoverPosition)
  537. {
  538. // Стороны / Sides
  539. case BorderHoverPositionEnum.Left:
  540. Form.Location = new Point(Cursor.Position.X, Form.Location.Y);
  541. Form.Width = Form.Width - (Form.Right - ResizeStartRight);
  542. break;
  543. case BorderHoverPositionEnum.Top:
  544. Form.Location = new Point(Form.Location.X, Cursor.Position.Y);
  545. Form.Height = Form.Height - (Form.Bottom - ResizeStartBottom);
  546. break;
  547. case BorderHoverPositionEnum.Right:
  548. Form.Width = Cursor.Position.X - Form.Left;
  549. break;
  550. case BorderHoverPositionEnum.Bottom:
  551. Form.Height = Cursor.Position.Y - Form.Top;
  552. break;
  553. // Углы / Angles
  554. case BorderHoverPositionEnum.TopLeft:
  555. Form.Location = new Point(Form.Location.X, Cursor.Position.Y);
  556. Form.Height = Form.Height - (Form.Bottom - ResizeStartBottom);
  557. Form.Location = new Point(Cursor.Position.X, Form.Location.Y);
  558. Form.Width = Form.Width - (Form.Right - ResizeStartRight);
  559. break;
  560. case BorderHoverPositionEnum.TopRight:
  561. Form.Location = new Point(Form.Location.X, Cursor.Position.Y);
  562. Form.Height = Form.Height - (Form.Bottom - ResizeStartBottom);
  563. Form.Width = Cursor.Position.X - Form.Left;
  564. break;
  565. case BorderHoverPositionEnum.BottomLeft:
  566. Form.Height = Cursor.Position.Y - Form.Top;
  567. Form.Location = new Point(Cursor.Position.X, Form.Location.Y);
  568. Form.Width = Form.Width - (Form.Right - ResizeStartRight);
  569. break;
  570. case BorderHoverPositionEnum.BottomRight:
  571. Form.Height = Cursor.Position.Y - Form.Top;
  572. Form.Width = Cursor.Position.X - Form.Left;
  573. break;
  574. }
  575. }
  576. }
  577. private void Form_MouseUp(object sender, MouseEventArgs e)
  578. {
  579. if (Form.IsHandleCreated == false) return;
  580. MousePressed = false;
  581. CanDragForm = false;
  582. IsResizing = false;
  583. if (AllowUserResize && BorderHoverPosition != BorderHoverPositionEnum.None)
  584. return;
  585. // Если окно поднять вверх -> разворачиваем на весь экран
  586. if (Cursor.Position.Y == Screen.FromHandle(Form.Handle).WorkingArea.Y
  587. && Form.WindowState == FormWindowState.Normal)
  588. {
  589. Form.WindowState = FormWindowState.Maximized;
  590. FormNeedReposition = true;
  591. }
  592. // Огранечение по Y
  593. if (Form.Location.Y < Screen.FromHandle(Form.Handle).WorkingArea.Y)
  594. {
  595. Form.Location = new Point(Form.Location.X, Screen.FromHandle(Form.Handle).WorkingArea.Y);
  596. }
  597. // Нажатия на кнопки управления окном
  598. if (e.Button == MouseButtons.Left && Form.ControlBox == true)
  599. {
  600. // Close Button Click
  601. if (rectBtnClose.Contains(e.Location))
  602. Form.Close();
  603. // Max Button Click
  604. if (rectBtnMax.Contains(e.Location) && Form.MaximizeBox == true)
  605. {
  606. if (Form.WindowState == FormWindowState.Maximized)
  607. {
  608. Form.WindowState = FormWindowState.Normal;
  609. if (FormNeedReposition)
  610. {
  611. FormNeedReposition = false;
  612. Form.Location = moveStartPosition;
  613. }
  614. }
  615. else if (Form.WindowState == FormWindowState.Normal)
  616. {
  617. Form.WindowState = FormWindowState.Maximized;
  618. }
  619. }
  620. // Min Button Click
  621. if (rectBtnMin.Contains(e.Location) && Form.MinimizeBox == true)
  622. Form.WindowState = FormWindowState.Minimized;
  623. }
  624. // Контекстное меню при нажатии на иконку
  625. if (e.Button == MouseButtons.Right && IconHovered)
  626. {
  627. if (ContextMenuForm != null)
  628. {
  629. ContextMenuForm.Show(Cursor.Position);
  630. }
  631. }
  632. }
  633. private void Form_MouseDown(object sender, MouseEventArgs e)
  634. {
  635. if (FormStyle == fStyle.None) return;
  636. MousePressed = true;
  637. if (AllowUserResize && BorderHoverPosition != BorderHoverPositionEnum.None)
  638. {
  639. if (e.Button == MouseButtons.Left)
  640. {
  641. IsResizing = true;
  642. ResizeStartRight = Form.Right;
  643. ResizeStartBottom = Form.Bottom;
  644. return;
  645. }
  646. }
  647. if (e.Location.Y <= HeaderHeight
  648. && !rectBtnClose.Contains(e.Location)
  649. && !rectBtnMax.Contains(e.Location)
  650. && !rectBtnMin.Contains(e.Location))
  651. {
  652. CanDragForm = true;
  653. clickPosition = Cursor.Position;
  654. moveStartPosition = Form.Location;
  655. }
  656. LastClickedMouseButton = e.Button;
  657. }
  658. private void Form_DoubleClick(object sender, EventArgs e)
  659. {
  660. if (FormStyle == fStyle.None) return;
  661. if (BorderHoverPosition != BorderHoverPositionEnum.None)
  662. return;
  663. if (MousePressed && LastClickedMouseButton == MouseButtons.Left && rectHeader.Contains(Form.PointToClient(Cursor.Position)))
  664. {
  665. if (Form.WindowState == FormWindowState.Maximized)
  666. {
  667. Form.WindowState = FormWindowState.Normal;
  668. }
  669. else if (Form.WindowState == FormWindowState.Normal)
  670. {
  671. Form.WindowState = FormWindowState.Maximized;
  672. }
  673. }
  674. }
  675. private void Form_Click(object sender, EventArgs e)
  676. {
  677. Form.Focus();
  678. }
  679. #endregion
  680. /// <summary>
  681. /// Рисование стиля
  682. /// </summary>
  683. /// <param name="graph"></param>
  684. private void DrawStyle(Graphics graph)
  685. {
  686. graph.SmoothingMode = SmoothingMode.HighQuality;
  687. graph.InterpolationMode = InterpolationMode.HighQualityBicubic;
  688. if (HeaderHeight == 0) return;
  689. #region - Structures Defining -
  690. // Header Structure
  691. rectHeader = new Rectangle(0, 0, Form.Width - 1, HeaderHeight);
  692. // Border Structure
  693. rectBorder = new Rectangle(0, 0, Form.Width - 1, Form.Height - 1);
  694. // Icon Structure
  695. rectIcon = new Rectangle(
  696. rectHeader.Height / 2 - IconSize.Width / 2,
  697. rectHeader.Height / 2 - IconSize.Height / 2,
  698. IconSize.Width, IconSize.Height
  699. );
  700. // Title Structure
  701. Rectangle rectTitleText = new Rectangle(Form.ShowIcon ? rectIcon.Right + 5 : rectIcon.Left, rectHeader.Y, rectHeader.Width, rectHeader.Height);
  702. // Title Image Structure
  703. Rectangle rectHeaderImage = new Rectangle();
  704. if (HeaderImage != null)
  705. {
  706. int imageHeight = (int)(HeaderHeight * 0.9f); // Высота картинки = 90% от высоты шапки
  707. int imageWidth = HeaderImage.Width / (HeaderImage.Height / imageHeight); // Получаем ширину с сохранением пропорций
  708. rectHeaderImage = new Rectangle(rectIcon.Left, HeaderHeight / 2 - imageHeight / 2, imageWidth, imageHeight);
  709. }
  710. // Close Button Structure
  711. rectBtnClose = new Rectangle(rectHeader.Width - ControlBoxButtonsWidth, rectHeader.Y, ControlBoxButtonsWidth, rectHeader.Height);
  712. // Crosshair Structure
  713. Rectangle rectCrosshair = new Rectangle(
  714. rectBtnClose.X + rectBtnClose.Width / 2 - ControlBoxIconSize.Width / 2,
  715. rectBtnClose.Height / 2 - ControlBoxIconSize.Height / 2,
  716. ControlBoxIconSize.Width, ControlBoxIconSize.Height);
  717. // Maximize Button Structure
  718. rectBtnMax = new Rectangle(rectBtnClose.X - ControlBoxButtonsWidth, rectHeader.Y, ControlBoxButtonsWidth, rectHeader.Height);
  719. // Maximize Icon Structure
  720. Rectangle rectMaxButtonIcon = new Rectangle(
  721. rectBtnMax.X + rectBtnMax.Width / 2 - ControlBoxIconSize.Width / 2,
  722. rectBtnMax.Height / 2 - ControlBoxIconSize.Height / 2,
  723. ControlBoxIconSize.Width, ControlBoxIconSize.Height);
  724. // Second Maximize Icon Structure [in Maximized state]
  725. Rectangle rectMaxButtonIconSecond = rectMaxButtonIcon;
  726. if (Form.WindowState == FormWindowState.Maximized)
  727. {
  728. //Inflate - изменяет размер и одновременно положение (В данном случае -1 по ширине и +2 по X, -1 по высоте и +2 по Y)
  729. rectMaxButtonIconSecond.Inflate(-1, -1);
  730. rectMaxButtonIconSecond.Offset(1, -1);
  731. rectMaxButtonIcon.Inflate(-1, -1);
  732. rectMaxButtonIcon.Offset(-1, 1);
  733. }
  734. // Minimize Button Structure
  735. rectBtnMin = new Rectangle(rectBtnMax.X - ControlBoxButtonsWidth, rectHeader.Y, ControlBoxButtonsWidth, rectHeader.Height);
  736. Point point1BtnMin = new Point(
  737. rectBtnMin.X + rectBtnMin.Width / 2 - ControlBoxIconSize.Width / 2,
  738. rectBtnMin.Height / 2 + ControlBoxIconSize.Height / 2
  739. );
  740. Point point2BtnMin = new Point(
  741. rectBtnMin.X + rectBtnMin.Width / 2 + ControlBoxIconSize.Width / 2,
  742. rectBtnMin.Height / 2 + ControlBoxIconSize.Height / 2
  743. );
  744. #endregion
  745. #region - Drawing -
  746. Brush headerBrush = new SolidBrush(HeaderColor);
  747. if (HeaderColorGradientEnable)
  748. {
  749. if (rectHeader.Width > 0 && rectHeader.Height > 0)
  750. headerBrush = new LinearGradientBrush(rectHeader, HeaderColor, HeaderColorAdditional, HeaderColorGradientMode);
  751. }
  752. // Шапка / Header
  753. graph.DrawRectangle(new Pen(headerBrush), rectHeader);
  754. graph.FillRectangle(headerBrush, rectHeader);
  755. if (HeaderImage != null)
  756. {
  757. // Картинка, вместо заголовка и иконки
  758. graph.DrawImage(HeaderImage, rectHeaderImage);
  759. }
  760. else
  761. {
  762. // Текст заголовка / Title
  763. graph.DrawString(Form.Text, HeaderTextFont, new SolidBrush(HeaderTextColor), rectTitleText, SF);
  764. // Иконка / Icon
  765. if (Form.ShowIcon)
  766. {
  767. graph.DrawImage(Form.Icon.ToBitmap(), rectIcon);
  768. }
  769. }
  770. if (Form.ControlBox == true)
  771. {
  772. #region - Icon Color Changing -
  773. if (CurrentStyle.UseSecondControlBoxIconsColorOnHover)
  774. {
  775. penBtnClose.Color = btnCloseHovered ? CurrentStyle.ControlBoxOnHoverIconsColor : CurrentStyle.ControlBoxEnabledIconsColor;
  776. penBtnMaximize.Color = btnMaximizeHovered ? CurrentStyle.ControlBoxOnHoverIconsColor : CurrentStyle.ControlBoxEnabledIconsColor;
  777. penBtnMinimize.Color = btnMinimizeHovered ? CurrentStyle.ControlBoxOnHoverIconsColor : CurrentStyle.ControlBoxEnabledIconsColor;
  778. }
  779. else
  780. {
  781. penBtnClose.Color = penBtnMaximize.Color = penBtnMinimize.Color = CurrentStyle.ControlBoxEnabledIconsColor;
  782. }
  783. if (Form.MaximizeBox == false)
  784. penBtnMaximize.Color = CurrentStyle.ControlBoxDisabledIconsColor;
  785. if (Form.MinimizeBox == false)
  786. penBtnMinimize.Color = CurrentStyle.ControlBoxDisabledIconsColor;
  787. #endregion
  788. // Кнопка Х
  789. #region - Button X -
  790. graph.DrawRectangle(new Pen(btnCloseHovered ? FlatColors.Red2 : Color.Transparent), rectBtnClose);
  791. graph.FillRectangle(new SolidBrush(btnCloseHovered ? FlatColors.Red2 : Color.Transparent), rectBtnClose);
  792. DrawCrosshair(graph, rectCrosshair, penBtnClose);
  793. #endregion
  794. // Кнопка [MAX]
  795. #region - Button Maximize -
  796. graph.DrawRectangle(new Pen(btnMaximizeHovered && Form.MaximizeBox ? Color.FromArgb(100, Color.Gray) : Color.Transparent), rectBtnMax);
  797. graph.FillRectangle(new SolidBrush(btnMaximizeHovered && Form.MaximizeBox ? Color.FromArgb(100, Color.Gray) : Color.Transparent), rectBtnMax);
  798. if (EnableControlBoxIconsLight)
  799. {
  800. if (Form.WindowState == FormWindowState.Maximized)
  801. {
  802. Drawer.DrawBlurredRectangle(graph, Color.White, rectMaxButtonIconSecond, 8, 20);
  803. }
  804. Drawer.DrawBlurredRectangle(graph, Color.White, rectMaxButtonIcon, 8, 20);
  805. }
  806. // Draw icon
  807. if (Form.WindowState == FormWindowState.Maximized)
  808. {
  809. graph.DrawRectangle(penBtnMaximize, rectMaxButtonIconSecond);
  810. //graph.FillRectangle(new SolidBrush(HeaderColor), rectMaxButtonIcon);
  811. graph.FillRectangle(headerBrush, rectMaxButtonIcon);
  812. }
  813. graph.DrawRectangle(penBtnMaximize, rectMaxButtonIcon);
  814. #endregion
  815. // Кнопка [ _ ]
  816. #region - Button Minimize -
  817. graph.DrawRectangle(new Pen(btnMinimizeHovered && Form.MinimizeBox ? Color.FromArgb(100, Color.Gray) : Color.Transparent), rectBtnMin);
  818. graph.FillRectangle(new SolidBrush(btnMinimizeHovered && Form.MinimizeBox ? Color.FromArgb(100, Color.Gray) : Color.Transparent), rectBtnMin);
  819. // Draw icon
  820. if (EnableControlBoxIconsLight)
  821. {
  822. Drawer.DrawBlurredLine(graph, Color.White, point1BtnMin, point2BtnMin, 8, 20);
  823. }
  824. graph.DrawLine(penBtnMinimize, point1BtnMin, point2BtnMin);
  825. #endregion
  826. // Свечение от курсора
  827. #region - Mouse Light on ControlBox -
  828. if (EnableControlBoxMouseLight && (btnCloseHovered || btnMaximizeHovered || btnMinimizeHovered))
  829. {
  830. Point cursorPoint1 = Form.PointToClient(Cursor.Position);
  831. Point cursorPoint2 = new Point(cursorPoint1.X, cursorPoint1.Y + 1);
  832. Drawer.DrawBlurredLine(graph, Color.White, cursorPoint1, cursorPoint2, 7, 70);
  833. }
  834. #endregion
  835. }
  836. // Обводка / Border
  837. graph.DrawRectangle(new Pen(Color.Gray), rectBorder);
  838. #endregion
  839. }
  840. /// <summary>
  841. /// Рисование крестика
  842. /// </summary>
  843. /// <param name="graph"></param>
  844. /// <param name="rect"></param>
  845. /// <param name="pen"></param>
  846. private void DrawCrosshair(Graphics graph, Rectangle rect, Pen pen)
  847. {
  848. if (EnableControlBoxIconsLight)
  849. {
  850. Drawer.DrawBlurredLine(
  851. graph,
  852. Color.White,
  853. new Point(rect.X, rect.Y),
  854. new Point(rect.X + rect.Width, rect.Y + rect.Height),
  855. 8,
  856. 20);
  857. Drawer.DrawBlurredLine(graph,
  858. Color.White,
  859. new Point(rect.X + rect.Width, rect.Y),
  860. new Point(rect.X, rect.Y + rect.Height),
  861. 8,
  862. 20);
  863. }
  864. graph.DrawLine(
  865. pen,
  866. rect.X,
  867. rect.Y,
  868. rect.X + rect.Width,
  869. rect.Y + rect.Height);
  870. graph.DrawLine(
  871. pen,
  872. rect.X + rect.Width,
  873. rect.Y,
  874. rect.X,
  875. rect.Y + rect.Height);
  876. }
  877. /// <summary>
  878. /// Включение DoubleBuffered, для предотвращения мерцания
  879. /// </summary>
  880. /// <param name="c"></param>
  881. public static void SetDoubleBuffered(Control c)
  882. {
  883. if (SystemInformation.TerminalServerSession)
  884. return;
  885. System.Reflection.PropertyInfo pDoubleBuffered =
  886. typeof(Control).GetProperty(
  887. "DoubleBuffered",
  888. System.Reflection.BindingFlags.NonPublic |
  889. System.Reflection.BindingFlags.Instance);
  890. pDoubleBuffered.SetValue(c, true, null);
  891. }
  892. }
  893. }