FormNoticeDetail.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  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.Runtime.InteropServices;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. using System.Windows.Forms;
  12. namespace SIMDP
  13. {
  14. public partial class FormNoticeDetail : DevExpress.XtraEditors.XtraForm
  15. {
  16. private string Title;
  17. public System.Drawing.Font TitleFont;
  18. /// <summary>
  19. /// Gets or sets the Font used when the mouse hovers over the main body of text.
  20. /// </summary>
  21. public System.Drawing.Font HoverFont;
  22. /// <summary>
  23. /// Gets or sets the Font used when the mouse hovers over the title text.
  24. /// </summary>
  25. public System.Drawing.Font TitleHoverFont;
  26. /// <summary>
  27. /// Gets or sets the style used when drawing the background of the NotifyWindow.
  28. /// </summary>
  29. public BackgroundStyles BackgroundStyle;
  30. /// <summary>
  31. /// Gets or sets the Blend used when drawing a gradient background for the NotifyWindow.
  32. /// </summary>
  33. public System.Drawing.Drawing2D.Blend Blend;
  34. /// <summary>
  35. /// Gets or sets the StringFormat used when drawing text in the NotifyWindow.
  36. /// </summary>
  37. public System.Drawing.StringFormat StringFormat;
  38. /// <summary>
  39. /// Gets or sets a value specifiying whether or not the window should continue to be displayed if the mouse cursor is inside the bounds
  40. /// of the NotifyWindow.
  41. /// </summary>
  42. public bool WaitOnMouseOver;
  43. /// <summary>
  44. /// An EventHandler called when the NotifyWindow main text is clicked.
  45. /// </summary>
  46. public event System.EventHandler TextClicked;
  47. /// <summary>
  48. /// An EventHandler called when the NotifyWindow title text is clicked.
  49. /// </summary>
  50. public event System.EventHandler TitleClicked;
  51. /// <summary>
  52. /// Gets or sets the color of the title text.
  53. /// </summary>
  54. public System.Drawing.Color TitleColor;
  55. /// <summary>
  56. /// Gets or sets the color of the NotifyWindow main text.
  57. /// </summary>
  58. public System.Drawing.Color TextColor;
  59. /// <summary>
  60. /// Gets or sets the gradient color which will be blended in drawing the background.
  61. /// </summary>
  62. public System.Drawing.Color GradientColor;
  63. /// <summary>
  64. /// Gets or sets the color of text when the user clicks on it.
  65. /// </summary>
  66. public System.Drawing.Color PressedColor;
  67. /// <summary>
  68. /// Gets or sets the amount of milliseconds to display the NotifyWindow for.
  69. /// </summary>
  70. public int WaitTime;
  71. /// <summary>
  72. /// Gets or sets the full height of the NotifyWindow, used after the opening animation has been completed.
  73. /// </summary>
  74. public int ActualHeight;
  75. /// <summary>
  76. /// Gets or sets the full width of the NotifyWindow.
  77. /// </summary>
  78. public int ActualWidth;
  79. /// <param name="title">Title text displayed in the NotifyWindow</param>
  80. /// <param name="text">Main text displayedin the NotifyWindow</param>
  81. public enum BackgroundStyles { BackwardDiagonalGradient, ForwardDiagonalGradient, HorizontalGradient, VerticalGradient, Solid };
  82. public enum ClockStates { Opening, Closing, Showing, None };
  83. public ClockStates ClockState;
  84. #region Protected Variables
  85. protected bool closePressed = false, textPressed = false, titlePressed = false, closeHot = false, textHot = false, titleHot = false;
  86. protected Rectangle rClose, rText, rTitle, rDisplay, rScreen, rGlobClose, rGlobText, rGlobTitle, rGlobDisplay;
  87. protected System.Windows.Forms.Timer viewClock;
  88. #endregion
  89. public FormNoticeDetail(string title, string text) : this() { Title = title; Text = text; }
  90. /// <param name="text">Text displayed in the NotifyWindow</param>
  91. public FormNoticeDetail(string text) : this() { Text = text; }
  92. public FormNoticeDetail()
  93. {
  94. InitializeComponent();
  95. this.TopMost = true;
  96. SetStyle(ControlStyles.UserMouse, true);
  97. SetStyle(ControlStyles.UserPaint, true);
  98. SetStyle(ControlStyles.AllPaintingInWmPaint, true); // WmPaint calls OnPaint and OnPaintBackground
  99. SetStyle(ControlStyles.DoubleBuffer, true);
  100. ShowInTaskbar = false;
  101. FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
  102. StartPosition = System.Windows.Forms.FormStartPosition.Manual;
  103. // Default values
  104. BackgroundStyle = BackgroundStyles.VerticalGradient;
  105. ClockState = ClockStates.None;
  106. BackColor = Color.SteelBlue;
  107. GradientColor = Color.WhiteSmoke;
  108. PressedColor = Color.Gray;
  109. TitleColor = SystemColors.ControlText;
  110. TextColor = SystemColors.ControlText;
  111. WaitOnMouseOver = true;
  112. ActualWidth = 130;
  113. ActualHeight = 110;
  114. WaitTime = 11000;
  115. }
  116. private void FormNoticeDetail_Load(object sender, EventArgs e)
  117. {
  118. //this.TopMost = true;
  119. //this.ShowInTaskbar = false;
  120. //this.WindowStartupLocation = WindowStartuplocation.Manual;
  121. }
  122. #region Public Methods
  123. /// <summary>
  124. /// Sets the width and height of the NotifyWindow.
  125. /// </summary>
  126. public void SetDimensions(int width, int height)
  127. {
  128. ActualWidth = width;
  129. ActualHeight = height;
  130. }
  131. /// <summary>
  132. /// Displays the NotifyWindow.
  133. /// </summary>
  134. public void Notify(Rectangle workArea)
  135. {
  136. //if (Text == null || Text.Length < 1)
  137. // throw new System.Exception("You must set NotifyWindow.Text before calling Notify()");
  138. Width = ActualWidth;
  139. rScreen = workArea;//Screen.GetWorkingArea(Screen.PrimaryScreen.Bounds);
  140. Height = 0;
  141. Top = rScreen.Bottom;
  142. Left = rScreen.Right - Width - 5;
  143. if (HoverFont == null)
  144. HoverFont = new Font(Font, Font.Style | FontStyle.Underline);
  145. if (TitleFont == null)
  146. TitleFont = Font;
  147. if (TitleHoverFont == null)
  148. TitleHoverFont = new Font(TitleFont, TitleFont.Style | FontStyle.Underline);
  149. if (this.StringFormat == null)
  150. {
  151. this.StringFormat = new StringFormat();
  152. this.StringFormat.Alignment = StringAlignment.Center;
  153. this.StringFormat.LineAlignment = StringAlignment.Center;
  154. this.StringFormat.Trimming = StringTrimming.EllipsisWord;
  155. }
  156. rDisplay = new Rectangle(0, 0, Width, ActualHeight);
  157. rClose = new Rectangle(Width - 21, 10, 13, 13);
  158. int offset;
  159. if (Title != null)
  160. {
  161. using (Graphics fx = CreateGraphics())
  162. {
  163. SizeF sz = fx.MeasureString(Title, TitleFont, ActualWidth - rClose.Width - 22, this.StringFormat);
  164. rTitle = new Rectangle(11, 12, (int)Math.Ceiling(sz.Width), (int)Math.Ceiling(sz.Height));
  165. offset = (int)Math.Max(Math.Ceiling(sz.Height + rTitle.Top + 2), rClose.Bottom + 5);
  166. }
  167. }
  168. else
  169. {
  170. offset = rClose.Bottom + 1;
  171. rTitle = new Rectangle(-1, -1, 1, 1);
  172. }
  173. rText = new Rectangle(11, offset, ActualWidth - 22, ActualHeight - (int)(offset * 1.5));
  174. // rGlob* are Rectangle's Offset'ed to their actual position on the screen, for use with Cursor.Position.
  175. rGlobClose = rClose;
  176. rGlobClose.Offset(Left, rScreen.Bottom - ActualHeight);
  177. rGlobText = rText;
  178. rGlobText.Offset(Left, rScreen.Bottom - ActualHeight);
  179. rGlobTitle = rTitle;
  180. if (Title != null)
  181. rGlobTitle.Offset(Left, rScreen.Bottom - ActualHeight);
  182. rGlobDisplay = rDisplay;
  183. rGlobDisplay.Offset(Left, rScreen.Bottom - ActualHeight);
  184. rGlobClose = rClose;
  185. rGlobClose.Offset(Left, rScreen.Bottom - ActualHeight);
  186. rGlobDisplay = rDisplay;
  187. rGlobDisplay.Offset(Left, rScreen.Bottom - ActualHeight);
  188. // Use unmanaged ShowWindow() and SetWindowPos() instead of the managed Show() to display the window - this method will display
  189. // the window TopMost, but without stealing focus (namely the SW_SHOWNOACTIVATE and SWP_NOACTIVATE flags)
  190. ShowWindow(Handle, SW_SHOWNOACTIVATE);
  191. SetWindowPos(Handle, HWND_TOPMOST, rScreen.Right - ActualWidth - 11, rScreen.Bottom, ActualWidth, 0, SWP_NOACTIVATE);
  192. viewClock = new System.Windows.Forms.Timer();
  193. viewClock.Tick += new System.EventHandler(viewTimer);
  194. viewClock.Interval = 1;
  195. viewClock.Start();
  196. ClockState = ClockStates.Opening;
  197. }
  198. #region Drawing
  199. protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
  200. {
  201. // Draw the close button and text.
  202. drawCloseButton(e.Graphics);
  203. Font useFont; Color useColor;
  204. if (Title != null)
  205. {
  206. if (titleHot)
  207. useFont = TitleHoverFont;
  208. else
  209. useFont = TitleFont;
  210. if (titlePressed)
  211. useColor = PressedColor;
  212. else
  213. useColor = TitleColor;
  214. using (SolidBrush sb = new SolidBrush(useColor))
  215. e.Graphics.DrawString(Title, useFont, sb, rTitle, this.StringFormat);
  216. }
  217. if (textHot)
  218. useFont = HoverFont;
  219. else
  220. useFont = Font;
  221. if (textPressed)
  222. useColor = PressedColor;
  223. else
  224. useColor = TextColor;
  225. using (SolidBrush sb = new SolidBrush(useColor))
  226. e.Graphics.DrawString(Text, useFont, sb, rText, this.StringFormat);
  227. }
  228. protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
  229. {
  230. // First paint the background
  231. if (BackgroundStyle == BackgroundStyles.Solid)
  232. {
  233. using (SolidBrush sb = new SolidBrush(BackColor))
  234. e.Graphics.FillRectangle(sb, rDisplay);
  235. }
  236. else
  237. {
  238. LinearGradientMode lgm;
  239. switch (BackgroundStyle)
  240. {
  241. case BackgroundStyles.BackwardDiagonalGradient:
  242. lgm = LinearGradientMode.BackwardDiagonal;
  243. break;
  244. case BackgroundStyles.ForwardDiagonalGradient:
  245. lgm = LinearGradientMode.ForwardDiagonal;
  246. break;
  247. case BackgroundStyles.HorizontalGradient:
  248. lgm = LinearGradientMode.Horizontal;
  249. break;
  250. default:
  251. case BackgroundStyles.VerticalGradient:
  252. lgm = LinearGradientMode.Vertical;
  253. break;
  254. }
  255. using (LinearGradientBrush lgb = new LinearGradientBrush(rDisplay, GradientColor, BackColor, lgm))
  256. {
  257. if (this.Blend != null)
  258. lgb.Blend = this.Blend;
  259. e.Graphics.FillRectangle(lgb, rDisplay);
  260. }
  261. }
  262. // Next draw borders...
  263. drawBorder(e.Graphics);
  264. }
  265. protected virtual void drawBorder(Graphics fx)
  266. {
  267. fx.DrawRectangle(Pens.Silver, 2, 2, Width - 4, ActualHeight - 4);
  268. // Top border
  269. fx.DrawLine(Pens.Silver, 0, 0, Width, 0);
  270. fx.DrawLine(Pens.White, 0, 1, Width, 1);
  271. fx.DrawLine(Pens.DarkGray, 3, 3, Width - 4, 3);
  272. fx.DrawLine(Pens.DimGray, 4, 4, Width - 5, 4);
  273. // Left border
  274. fx.DrawLine(Pens.Silver, 0, 0, 0, ActualHeight);
  275. fx.DrawLine(Pens.White, 1, 1, 1, ActualHeight);
  276. fx.DrawLine(Pens.DarkGray, 3, 3, 3, ActualHeight - 4);
  277. fx.DrawLine(Pens.DimGray, 4, 4, 4, ActualHeight - 5);
  278. // Bottom border
  279. fx.DrawLine(Pens.DarkGray, 1, ActualHeight - 1, Width - 1, ActualHeight - 1);
  280. fx.DrawLine(Pens.White, 3, ActualHeight - 3, Width - 3, ActualHeight - 3);
  281. fx.DrawLine(Pens.Silver, 4, ActualHeight - 4, Width - 4, ActualHeight - 4);
  282. // Right border
  283. fx.DrawLine(Pens.DarkGray, Width - 1, 1, Width - 1, ActualHeight - 1);
  284. fx.DrawLine(Pens.White, Width - 3, 3, Width - 3, ActualHeight - 3);
  285. fx.DrawLine(Pens.Silver, Width - 4, 4, Width - 4, ActualHeight - 4);
  286. }
  287. protected virtual void drawCloseButton(Graphics fx)
  288. {
  289. if (visualStylesEnabled())
  290. drawThemeCloseButton(fx);
  291. else
  292. drawLegacyCloseButton(fx);
  293. }
  294. /// <summary>
  295. /// Draw a Windows XP style close button.
  296. /// </summary>
  297. protected void drawThemeCloseButton(Graphics fx)
  298. {
  299. IntPtr hTheme = OpenThemeData(Handle, "Window");
  300. if (hTheme == IntPtr.Zero)
  301. {
  302. drawLegacyCloseButton(fx);
  303. return;
  304. }
  305. int stateId;
  306. if (closePressed)
  307. stateId = CBS_PUSHED;
  308. else if (closeHot)
  309. stateId = CBS_HOT;
  310. else
  311. stateId = CBS_NORMAL;
  312. RECT reClose = new RECT(rClose);
  313. RECT reClip = reClose; // should fx.VisibleClipBounds be used here?
  314. IntPtr hDC = fx.GetHdc();
  315. DrawThemeBackground(hTheme, hDC, WP_CLOSEBUTTON, stateId, ref reClose, ref reClip);
  316. fx.ReleaseHdc(hDC);
  317. CloseThemeData(hTheme);
  318. }
  319. /// <summary>
  320. /// Draw a Windows 95 style close button.
  321. /// </summary>
  322. protected void drawLegacyCloseButton(Graphics fx)
  323. {
  324. ButtonState bState;
  325. if (closePressed)
  326. bState = ButtonState.Pushed;
  327. else // the Windows 95 theme doesn't have a "hot" button
  328. bState = ButtonState.Normal;
  329. ControlPaint.DrawCaptionButton(fx, rClose, CaptionButton.Close, bState);
  330. }
  331. /// <summary>
  332. /// Determine whether or not XP Visual Styles are active. Compatible with pre-UxTheme.dll versions of Windows.
  333. /// </summary>
  334. protected bool visualStylesEnabled()
  335. {
  336. try
  337. {
  338. if (IsThemeActive() == 1)
  339. return true;
  340. else
  341. return false;
  342. }
  343. catch (System.DllNotFoundException) // pre-XP systems which don't have UxTheme.dll
  344. {
  345. return false;
  346. }
  347. }
  348. #endregion
  349. #region Timers and EventHandlers
  350. protected void viewTimer(object sender, System.EventArgs e)
  351. {
  352. switch (ClockState)
  353. {
  354. case ClockStates.Opening:
  355. if (Top - 2 <= rScreen.Height - ActualHeight)
  356. {
  357. Top = rScreen.Height - ActualHeight;
  358. Height = ActualHeight;
  359. ClockState = ClockStates.Showing;
  360. viewClock.Interval = WaitTime;
  361. }
  362. else
  363. {
  364. Top -= 2;
  365. Height += 2;
  366. }
  367. break;
  368. case ClockStates.Showing:
  369. if (!WaitOnMouseOver || !rGlobDisplay.Contains(Cursor.Position))
  370. {
  371. viewClock.Interval = 1;
  372. //ClockState = ClockStates.Closing;
  373. }
  374. break;
  375. case ClockStates.Closing:
  376. Top += 2;
  377. Height -= 2;
  378. if (Top >= rScreen.Height)
  379. {
  380. ClockState = ClockStates.None;
  381. viewClock.Stop();
  382. viewClock.Dispose();
  383. Close();
  384. }
  385. break;
  386. }
  387. }
  388. protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
  389. {
  390. if (Title != null && rGlobTitle.Contains(Cursor.Position) && !textPressed && !closePressed)
  391. {
  392. Cursor = Cursors.Hand;
  393. titleHot = true;
  394. textHot = false; closeHot = false;
  395. Invalidate();
  396. }
  397. else if (rGlobText.Contains(Cursor.Position) && !titlePressed && !closePressed)
  398. {
  399. Cursor = Cursors.Hand;
  400. textHot = true;
  401. titleHot = false; closeHot = false;
  402. Invalidate();
  403. }
  404. else if (rGlobClose.Contains(Cursor.Position) && !titlePressed && !textPressed)
  405. {
  406. Cursor = Cursors.Hand;
  407. closeHot = true;
  408. titleHot = false; textHot = false;
  409. Invalidate();
  410. }
  411. else if ((textHot || titleHot || closeHot) && (!titlePressed && !textPressed && !closePressed))
  412. {
  413. Cursor = Cursors.Default;
  414. titleHot = false; textHot = false; closeHot = false;
  415. Invalidate();
  416. }
  417. base.OnMouseMove(e);
  418. }
  419. protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
  420. {
  421. if (e.Button == MouseButtons.Left)
  422. {
  423. if (rGlobClose.Contains(Cursor.Position))
  424. {
  425. closePressed = true;
  426. closeHot = false;
  427. Invalidate();
  428. }
  429. else if (rGlobText.Contains(Cursor.Position))
  430. {
  431. textPressed = true;
  432. Invalidate();
  433. }
  434. else if (Title != null && rGlobTitle.Contains(Cursor.Position))
  435. {
  436. titlePressed = true;
  437. Invalidate();
  438. }
  439. }
  440. base.OnMouseDown(e);
  441. }
  442. protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
  443. {
  444. if (e.Button == MouseButtons.Left)
  445. {
  446. if (closePressed)
  447. {
  448. Cursor = Cursors.Default;
  449. closePressed = false;
  450. closeHot = false;
  451. Invalidate();
  452. if (rGlobClose.Contains(Cursor.Position))
  453. Close();
  454. }
  455. else if (textPressed)
  456. {
  457. Cursor = Cursors.Default;
  458. textPressed = false;
  459. textHot = false;
  460. Invalidate();
  461. if (rGlobText.Contains(Cursor.Position))
  462. {
  463. Close();
  464. if (TextClicked != null)
  465. TextClicked(this, new System.EventArgs());
  466. }
  467. }
  468. else if (titlePressed)
  469. {
  470. Cursor = Cursors.Default;
  471. titlePressed = false;
  472. titleHot = false;
  473. Invalidate();
  474. if (rGlobTitle.Contains(Cursor.Position))
  475. {
  476. Close();
  477. if (TitleClicked != null)
  478. TitleClicked(this, new System.EventArgs());
  479. }
  480. }
  481. }
  482. base.OnMouseUp(e);
  483. }
  484. #endregion
  485. #endregion
  486. #region P/Invoke
  487. // DrawThemeBackground()
  488. protected const Int32 WP_CLOSEBUTTON = 18;
  489. protected const Int32 CBS_NORMAL = 1;
  490. protected const Int32 CBS_HOT = 2;
  491. protected const Int32 CBS_PUSHED = 3;
  492. [StructLayout(LayoutKind.Explicit)]
  493. protected struct RECT
  494. {
  495. [FieldOffset(0)] public Int32 Left;
  496. [FieldOffset(4)] public Int32 Top;
  497. [FieldOffset(8)] public Int32 Right;
  498. [FieldOffset(12)] public Int32 Bottom;
  499. public RECT(System.Drawing.Rectangle bounds)
  500. {
  501. Left = bounds.Left;
  502. Top = bounds.Top;
  503. Right = bounds.Right;
  504. Bottom = bounds.Bottom;
  505. }
  506. }
  507. // SetWindowPos()
  508. protected const Int32 HWND_TOPMOST = -1;
  509. protected const Int32 SWP_NOACTIVATE = 0x0010;
  510. // ShowWindow()
  511. protected const Int32 SW_SHOWNOACTIVATE = 4;
  512. // UxTheme.dll
  513. [DllImport("UxTheme.dll")]
  514. protected static extern Int32 IsThemeActive();
  515. [DllImport("UxTheme.dll")]
  516. protected static extern IntPtr OpenThemeData(IntPtr hWnd, [MarshalAs(UnmanagedType.LPTStr)] string classList);
  517. [DllImport("UxTheme.dll")]
  518. protected static extern void CloseThemeData(IntPtr hTheme);
  519. [DllImport("UxTheme.dll")]
  520. protected static extern void DrawThemeBackground(IntPtr hTheme, IntPtr hDC, Int32 partId, Int32 stateId, ref RECT rect, ref RECT clipRect);
  521. // user32.dll
  522. [DllImport("user32.dll")]
  523. protected static extern bool ShowWindow(IntPtr hWnd, Int32 flags);
  524. [DllImport("user32.dll")]
  525. protected static extern bool SetWindowPos(IntPtr hWnd, Int32 hWndInsertAfter, Int32 X, Int32 Y, Int32 cx, Int32 cy, uint uFlags);
  526. #endregion
  527. }
  528. }