UI.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. using SmartCoalApplication.Base;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Drawing;
  6. using System.Drawing.Drawing2D;
  7. using System.Windows.Forms;
  8. using System.Windows.Forms.VisualStyles;
  9. namespace SmartCoalApplication.SystemLayer
  10. {
  11. public static class UI
  12. {
  13. private static bool initScales = false;
  14. private static float xScale;
  15. private static float yScale;
  16. public static void FlashForm(Form form)
  17. {
  18. IntPtr hWnd = form.Handle;
  19. SafeNativeMethods.FlashWindow(hWnd, false);
  20. SafeNativeMethods.FlashWindow(hWnd, false);
  21. GC.KeepAlive(form);
  22. }
  23. public static int GetExtendedFrameBounds(Form window)
  24. {
  25. GC.KeepAlive(window);
  26. return 0;
  27. }
  28. private static void InitScaleFactors(Control c)
  29. {
  30. if (c == null)
  31. {
  32. xScale = 1.0f;
  33. yScale = 1.0f;
  34. }
  35. else
  36. {
  37. using (Graphics g = c.CreateGraphics())
  38. {
  39. xScale = g.DpiX / 96.0f;
  40. yScale = g.DpiY / 96.0f;
  41. }
  42. }
  43. initScales = true;
  44. }
  45. public static void InitScaling(Control c)
  46. {
  47. if (!initScales)
  48. {
  49. InitScaleFactors(c);
  50. }
  51. }
  52. public static float ScaleWidth(float width)
  53. {
  54. return (float)Math.Round(width * GetXScaleFactor());
  55. }
  56. public static int ScaleWidth(int width)
  57. {
  58. return (int)Math.Round((float)width * GetXScaleFactor());
  59. }
  60. public static int ScaleHeight(int height)
  61. {
  62. return (int)Math.Round((float)height * GetYScaleFactor());
  63. }
  64. public static float ScaleHeight(float height)
  65. {
  66. return (float)Math.Round(height * GetYScaleFactor());
  67. }
  68. public static Size ScaleSize(Size size)
  69. {
  70. return new Size(ScaleWidth(size.Width), ScaleHeight(size.Height));
  71. }
  72. public static Point ScalePoint(Point pt)
  73. {
  74. return new Point(ScaleWidth(pt.X), ScaleHeight(pt.Y));
  75. }
  76. public static float GetXScaleFactor()
  77. {
  78. if (!initScales)
  79. {
  80. throw new InvalidOperationException("Must call InitScaling() first");
  81. }
  82. return xScale;
  83. }
  84. public static float GetYScaleFactor()
  85. {
  86. if (!initScales)
  87. {
  88. throw new InvalidOperationException("Must call InitScaling() first");
  89. }
  90. return yScale;
  91. }
  92. public static void DrawCommandButton(
  93. Graphics graphics,
  94. PushButtonState state,
  95. Rectangle rect,
  96. Color backColor,
  97. Control childControl)
  98. {
  99. VisualStyleElement element = null;
  100. int alpha = 255;
  101. if (element == null)
  102. {
  103. switch (state)
  104. {
  105. case PushButtonState.Default:
  106. element = VisualStyleElement.Button.PushButton.Default;
  107. alpha = 95;
  108. break;
  109. case PushButtonState.Disabled:
  110. element = VisualStyleElement.Button.PushButton.Disabled;
  111. break;
  112. case PushButtonState.Hot:
  113. element = VisualStyleElement.Button.PushButton.Hot;
  114. break;
  115. case PushButtonState.Normal:
  116. alpha = 0;
  117. element = VisualStyleElement.Button.PushButton.Normal;
  118. break;
  119. case PushButtonState.Pressed:
  120. element = VisualStyleElement.Button.PushButton.Pressed;
  121. break;
  122. default:
  123. throw new InvalidEnumArgumentException();
  124. }
  125. }
  126. if (element != null)
  127. {
  128. try
  129. {
  130. VisualStyleRenderer renderer = new VisualStyleRenderer(element);
  131. renderer.DrawParentBackground(graphics, rect, childControl);
  132. renderer.DrawBackground(graphics, rect);
  133. }
  134. catch (Exception)
  135. {
  136. element = null;
  137. }
  138. }
  139. if (element == null)
  140. {
  141. ButtonRenderer.DrawButton(graphics, rect, state);
  142. }
  143. if (alpha != 255)
  144. {
  145. using (Brush backBrush = new SolidBrush(Color.FromArgb(255 - alpha, backColor)))
  146. {
  147. CompositingMode oldCM = graphics.CompositingMode;
  148. try
  149. {
  150. graphics.CompositingMode = CompositingMode.SourceOver;
  151. graphics.FillRectangle(backBrush, rect);
  152. }
  153. finally
  154. {
  155. graphics.CompositingMode = oldCM;
  156. }
  157. }
  158. }
  159. }
  160. /// <summary>
  161. /// Sets the control's redraw state.
  162. /// </summary>
  163. /// <param name="control">The control whose state should be modified.</param>
  164. /// <param name="enabled">The new state for redrawing ability.</param>
  165. /// <remarks>
  166. /// Note to implementors: This method is used by SuspendControlPainting() and ResumeControlPainting().
  167. /// This may be implemented as a no-op.
  168. /// </remarks>
  169. private static void SetControlRedrawImpl(Control control, bool enabled)
  170. {
  171. SafeNativeMethods.SendMessageW(control.Handle, NativeConstants.WM_SETREDRAW, enabled ? new IntPtr(1) : IntPtr.Zero, IntPtr.Zero);
  172. GC.KeepAlive(control);
  173. }
  174. private static Dictionary<Control, int> controlRedrawStack = new Dictionary<Control, int>();
  175. /// <summary>
  176. /// Suspends the control's ability to draw itself.
  177. /// </summary>
  178. /// <param name="control">The control to suspend drawing for.</param>
  179. /// <remarks>
  180. /// When drawing is suspended, any painting performed in the control's WM_PAINT, OnPaint(),
  181. /// WM_ERASEBKND, or OnPaintBackground() handlers is completely ignored. Invalidation rectangles
  182. /// are not accumulated during this period, so when drawing is resumed (with
  183. /// ResumeControlPainting()), it is usually a good idea to call Invalidate(true) on the control.
  184. /// This method must be matched at a later time by a corresponding call to ResumeControlPainting().
  185. /// If you call SuspendControlPainting() multiple times for the same control, then you must
  186. /// call ResumeControlPainting() once for each call.
  187. /// Note to implementors: Do not modify this method. Instead, modify SetControlRedrawImpl(),
  188. /// which may be implemented as a no-op.
  189. /// </remarks>
  190. public static void SuspendControlPainting(Control control)
  191. {
  192. int pushCount;
  193. if (controlRedrawStack.TryGetValue(control, out pushCount))
  194. {
  195. ++pushCount;
  196. }
  197. else
  198. {
  199. pushCount = 1;
  200. }
  201. if (pushCount == 1)
  202. {
  203. SetControlRedrawImpl(control, false);
  204. }
  205. controlRedrawStack[control] = pushCount;
  206. }
  207. /// <summary>
  208. /// Resumes the control's ability to draw itself.
  209. /// </summary>
  210. /// <param name="control">The control to suspend drawing for.</param>
  211. /// <remarks>
  212. /// This method must be matched by a preceding call to SuspendControlPainting(). If that method
  213. /// was called multiple times, then this method must be called a corresponding number of times
  214. /// in order to enable drawing.
  215. /// This method must be matched at a later time by a corresponding call to ResumeControlPainting().
  216. /// If you call SuspendControlPainting() multiple times for the same control, then you must
  217. /// call ResumeControlPainting() once for each call.
  218. /// Note to implementors: Do not modify this method. Instead, modify SetControlRedrawImpl(),
  219. /// which may be implemented as a no-op.
  220. /// </remarks>
  221. public static void ResumeControlPainting(Control control)
  222. {
  223. int pushCount;
  224. if (controlRedrawStack.TryGetValue(control, out pushCount))
  225. {
  226. --pushCount;
  227. }
  228. else
  229. {
  230. throw new InvalidOperationException("There was no previous matching SuspendControlPainting() for this control");
  231. }
  232. if (pushCount == 0)
  233. {
  234. SetControlRedrawImpl(control, true);
  235. controlRedrawStack.Remove(control);
  236. }
  237. else
  238. {
  239. controlRedrawStack[control] = pushCount;
  240. }
  241. }
  242. /// <summary>
  243. /// Queries whether painting is enabled for the given control.
  244. /// </summary>
  245. /// <param name="control">The control to query suspension for.</param>
  246. /// <returns>
  247. /// false if the control's painting has been suspended via a call to SuspendControlPainting(),
  248. /// otherwise true.
  249. /// </returns>
  250. /// <remarks>
  251. /// You may use the return value of this method to optimize away painting. If this
  252. /// method returns false, then you may skip your entire OnPaint() method. This saves
  253. /// processor time by avoiding all of the non-painting drawing and resource initialization
  254. /// and destruction that is typically contained in OnPaint().
  255. /// This method assumes painting suspension is being exclusively managed with Suspend-
  256. /// and ResumeControlPainting().
  257. /// </remarks>
  258. public static bool IsControlPaintingEnabled(Control control)
  259. {
  260. int pushCount;
  261. if (!controlRedrawStack.TryGetValue(control, out pushCount))
  262. {
  263. pushCount = 0;
  264. }
  265. return (pushCount == 0);
  266. }
  267. private static IntPtr hRgn = SafeNativeMethods.CreateRectRgn(0, 0, 1, 1);
  268. public static Rectangle[] GetUpdateRegion(Control control)
  269. {
  270. SafeNativeMethods.GetUpdateRgn(control.Handle, hRgn, false);
  271. Rectangle[] scans;
  272. int area;
  273. PdnGraphics.GetRegionScans(hRgn, out scans, out area);
  274. GC.KeepAlive(control);
  275. return scans;
  276. }
  277. public static void SetFormOpacity(Form form, double opacity)
  278. {
  279. if (opacity < 0.0 || opacity > 1.0)
  280. {
  281. throw new ArgumentOutOfRangeException("opacity", "must be in the range [0, 1]");
  282. }
  283. uint exStyle = SafeNativeMethods.GetWindowLongW(form.Handle, NativeConstants.GWL_EXSTYLE);
  284. byte bOldAlpha = 255;
  285. if ((exStyle & NativeConstants.GWL_EXSTYLE) != 0)
  286. {
  287. uint dwOldKey;
  288. uint dwOldFlags;
  289. bool result = SafeNativeMethods.GetLayeredWindowAttributes(form.Handle, out dwOldKey, out bOldAlpha, out dwOldFlags);
  290. }
  291. byte bNewAlpha = (byte)(opacity * 255.0);
  292. uint newExStyle = exStyle;
  293. if (bNewAlpha != 255)
  294. {
  295. newExStyle |= NativeConstants.WS_EX_LAYERED;
  296. }
  297. if (newExStyle != exStyle || (newExStyle & NativeConstants.WS_EX_LAYERED) != 0)
  298. {
  299. if (newExStyle != exStyle)
  300. {
  301. SafeNativeMethods.SetWindowLongW(form.Handle, NativeConstants.GWL_EXSTYLE, newExStyle);
  302. }
  303. if ((newExStyle & NativeConstants.WS_EX_LAYERED) != 0)
  304. {
  305. SafeNativeMethods.SetLayeredWindowAttributes(form.Handle, 0, bNewAlpha, NativeConstants.LWA_ALPHA);
  306. }
  307. }
  308. GC.KeepAlive(form);
  309. }
  310. internal static bool ClickThroughWndProc(ref Message m)
  311. {
  312. bool returnVal = false;
  313. if (m.Msg == NativeConstants.WM_MOUSEACTIVATE)
  314. {
  315. if (m.Result == (IntPtr)NativeConstants.MA_ACTIVATEANDEAT)
  316. {
  317. m.Result = (IntPtr)NativeConstants.MA_ACTIVATE;
  318. returnVal = true;
  319. }
  320. }
  321. return returnVal;
  322. }
  323. public static bool IsOurAppActive
  324. {
  325. get
  326. {
  327. foreach (Form form in Application.OpenForms)
  328. {
  329. if (form == Form.ActiveForm)
  330. {
  331. return true;
  332. }
  333. }
  334. return false;
  335. }
  336. }
  337. private static VisualStyleClass DetermineVisualStyleClass()
  338. {
  339. return DetermineVisualStyleClassImpl();
  340. }
  341. private static VisualStyleClass DetermineVisualStyleClassImpl()
  342. {
  343. VisualStyleClass vsClass;
  344. if (!VisualStyleInformation.IsSupportedByOS)
  345. {
  346. vsClass = VisualStyleClass.Classic;
  347. }
  348. else if (!VisualStyleInformation.IsEnabledByUser)
  349. {
  350. vsClass = VisualStyleClass.Classic;
  351. }
  352. else if (0 == string.Compare(VisualStyleInformation.Author, "MSX", StringComparison.InvariantCulture) &&
  353. 0 == string.Compare(VisualStyleInformation.DisplayName, "Aero style", StringComparison.InvariantCulture))
  354. {
  355. vsClass = VisualStyleClass.Aero;
  356. }
  357. else if (0 == string.Compare(VisualStyleInformation.Company, "Microsoft Corporation", StringComparison.InvariantCulture) &&
  358. 0 == string.Compare(VisualStyleInformation.Author, "Microsoft Design Team", StringComparison.InvariantCulture))
  359. {
  360. if (0 == string.Compare(VisualStyleInformation.DisplayName, "Windows XP style", StringComparison.InvariantCulture) || // Luna
  361. 0 == string.Compare(VisualStyleInformation.DisplayName, "Zune Style", StringComparison.InvariantCulture) || // Zune
  362. 0 == string.Compare(VisualStyleInformation.DisplayName, "Media Center style", StringComparison.InvariantCulture)) // Royale
  363. {
  364. vsClass = VisualStyleClass.Luna;
  365. }
  366. else
  367. {
  368. vsClass = VisualStyleClass.Other;
  369. }
  370. }
  371. else
  372. {
  373. vsClass = VisualStyleClass.Other;
  374. }
  375. return vsClass;
  376. }
  377. public static VisualStyleClass VisualStyleClass
  378. {
  379. get
  380. {
  381. return DetermineVisualStyleClass();
  382. }
  383. }
  384. public static bool HideAllScrollBar(Control control)
  385. {
  386. return SafeNativeMethods.ShowScrollBar(control.Handle, 3, false);
  387. }
  388. public static bool HideHorizontalScrollBar(Control control)
  389. {
  390. return SafeNativeMethods.ShowScrollBar(control.Handle, NativeConstants.SB_HORZ, false);
  391. }
  392. public static bool HideVerticalScrollBar(Control control)
  393. {
  394. return SafeNativeMethods.ShowScrollBar(control.Handle, NativeConstants.SB_VERT, false);
  395. }
  396. public static void RestoreWindow(IWin32Window window)
  397. {
  398. IntPtr hWnd = window.Handle;
  399. SafeNativeMethods.ShowWindow(hWnd, NativeConstants.SW_RESTORE);
  400. GC.KeepAlive(window);
  401. }
  402. public static void DisableCloseBox(IWin32Window window)
  403. {
  404. IntPtr hWnd = window.Handle;
  405. IntPtr hMenu = SafeNativeMethods.GetSystemMenu(hWnd, false);
  406. if (hMenu == IntPtr.Zero)
  407. {
  408. throw new Win32Exception("GetSystemMenu() returned NULL");
  409. }
  410. int result = SafeNativeMethods.EnableMenuItem(
  411. hMenu,
  412. NativeConstants.SC_CLOSE,
  413. NativeConstants.MF_BYCOMMAND | NativeConstants.MF_GRAYED);
  414. bool bResult = SafeNativeMethods.DrawMenuBar(hWnd);
  415. if (!bResult)
  416. {
  417. throw new Win32Exception("DrawMenuBar returned FALSE");
  418. }
  419. GC.KeepAlive(window);
  420. }
  421. internal static void InvokeThroughModalTrampoline(IWin32Window owner, Procedure<IWin32Window> invokeMe)
  422. {
  423. using (Form modalityFix = new Form())
  424. {
  425. modalityFix.ShowInTaskbar = false;
  426. modalityFix.TransparencyKey = modalityFix.BackColor;
  427. UI.SetFormOpacity(modalityFix, 0);
  428. modalityFix.ControlBox = false;
  429. modalityFix.FormBorderStyle = FormBorderStyle.None;
  430. Control ownerAsControl = owner as Control;
  431. if (ownerAsControl != null)
  432. {
  433. Form ownerForm = ownerAsControl.FindForm();
  434. if (ownerForm != null)
  435. {
  436. Rectangle clientRect = ownerForm.RectangleToScreen(ownerForm.ClientRectangle);
  437. modalityFix.Icon = ownerForm.Icon;
  438. modalityFix.Location = clientRect.Location;
  439. modalityFix.Size = clientRect.Size;
  440. modalityFix.StartPosition = FormStartPosition.Manual;
  441. }
  442. }
  443. modalityFix.Shown +=
  444. delegate (object sender, EventArgs e)
  445. {
  446. invokeMe(modalityFix);
  447. modalityFix.Close();
  448. };
  449. modalityFix.ShowDialog(owner);
  450. GC.KeepAlive(modalityFix);
  451. }
  452. }
  453. public static void EnableShield(Button button, bool enableShield)
  454. {
  455. IntPtr hWnd = button.Handle;
  456. SafeNativeMethods.SendMessageW(
  457. hWnd,
  458. NativeConstants.BCM_SETSHIELD,
  459. IntPtr.Zero,
  460. enableShield ? new IntPtr(1) : IntPtr.Zero);
  461. GC.KeepAlive(button);
  462. }
  463. }
  464. }