diff --git a/DemoApp/DemoApp.csproj b/DemoApp/DemoApp.csproj index 0df1719..dd087d2 100644 --- a/DemoApp/DemoApp.csproj +++ b/DemoApp/DemoApp.csproj @@ -66,6 +66,7 @@ + diff --git a/NotificationWindow.sln b/NotificationWindow.sln index f13d49e..3689713 100644 --- a/NotificationWindow.sln +++ b/NotificationWindow.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30114.128 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotificationWindow", "Tulpep.NotificationWindow\NotificationWindow.csproj", "{605006EB-D4E6-4312-A293-3A43FAC43240}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotificationWindow", "NotificationWindow\NotificationWindow.csproj", "{605006EB-D4E6-4312-A293-3A43FAC43240}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DemoApp", "DemoApp\DemoApp.csproj", "{833625E6-80AC-45E0-8AA4-06BDDEDBEA2F}" EndProject diff --git a/Tulpep.NotificationWindow/Grip.png b/NotificationWindow/Grip.png similarity index 100% rename from Tulpep.NotificationWindow/Grip.png rename to NotificationWindow/Grip.png diff --git a/Tulpep.NotificationWindow/Icon.ico b/NotificationWindow/Icon.ico similarity index 100% rename from Tulpep.NotificationWindow/Icon.ico rename to NotificationWindow/Icon.ico diff --git a/Tulpep.NotificationWindow/NotificationWindow.csproj b/NotificationWindow/NotificationWindow.csproj similarity index 100% rename from Tulpep.NotificationWindow/NotificationWindow.csproj rename to NotificationWindow/NotificationWindow.csproj diff --git a/Tulpep.NotificationWindow/PopupNotifier.cs b/NotificationWindow/PopupNotifier.cs similarity index 97% rename from Tulpep.NotificationWindow/PopupNotifier.cs rename to NotificationWindow/PopupNotifier.cs index cc5bd14..15d490f 100644 --- a/Tulpep.NotificationWindow/PopupNotifier.cs +++ b/NotificationWindow/PopupNotifier.cs @@ -1,638 +1,638 @@ -/* - * Created/modified in 2011 by Simon Baer - * - * Based on the Code Project article by Nicolas Wälti: - * http://www.codeproject.com/KB/cpp/PopupNotifier.aspx - * - * Licensed under the Code Project Open License (CPOL). - */ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Linq; -using System.Runtime.InteropServices; -using System.Threading; -using System.Windows.Forms; -using Timer = System.Windows.Forms.Timer; - -namespace NotificationWindow -{ - /// - /// Non-visual component to show a notification window in the right lower - /// corner of the screen. - /// - [ToolboxBitmap(typeof(PopupNotifier), "Icon.ico")] - [DefaultEvent("Click")] - public class PopupNotifier : Component - { - public static List positions = new List(); - private int currentPosition; - #region Windows API - private const int SW_SHOWNOACTIVATE = 4; - private const int HWND_TOPMOST = -1; - private const uint SWP_NOACTIVATE = 0x0010; - - [DllImport("user32.dll", EntryPoint = "SetWindowPos")] - static extern bool SetWindowPos( - int hWnd, // Window handle - int hWndInsertAfter, // Placement-order handle - int X, // Horizontal position - int Y, // Vertical position - int cx, // Width - int cy, // Height - uint uFlags); // Window positioning flags - - [DllImport("user32.dll")] - static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); - - static void ShowInactiveTopmost(Form frm) - { - ShowWindow(frm.Handle, SW_SHOWNOACTIVATE); - SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST, - frm.Left, frm.Top, frm.Width, frm.Height, - SWP_NOACTIVATE); - } - #endregion - - /// - /// Event that is raised when the text in the notification window is clicked. - /// - public event EventHandler Click; - - /// - /// Event that is raised when the notification window is manually closed. - /// - public event EventHandler Close; - - /// - /// Event that is raised when the notification Appears. - /// - public event EventHandler Appear; - - /// - /// Event that is raised when the notification Dissapers - /// - public event EventHandler Disappear; - - private bool disposed = false; - private PopupNotifierForm frmPopup; - private Timer tmrAnimation; - private Timer tmrWait; - - private bool isAppearing = true; - private bool mouseIsOn = false; - private int maxPosition; - private double maxOpacity; - private int posStart; - private int posStop; - private double opacityStart; - private double opacityStop; - private int realAnimationDuration; - private System.Diagnostics.Stopwatch sw; - - #region Properties - - [Category("Header"), DefaultValue(typeof(Color), "ControlDark")] - [Description("Color of the window header.")] - public Color HeaderColor { get; set; } - - [Category("Appearance"), DefaultValue(typeof(Color), "Control")] - [Description("Color of the window background.")] - public Color BodyColor { get; set; } - - [Category("Title"), DefaultValue(typeof(Color), "Gray")] - [Description("Color of the title text.")] - public Color TitleColor { get; set; } - - [Category("Content"), DefaultValue(typeof(Color), "ControlText")] - [Description("Color of the content text.")] - public Color ContentColor { get; set; } - - [Category("Appearance"), DefaultValue(typeof(Color), "WindowFrame")] - [Description("Color of the window border.")] - public Color BorderColor { get; set; } - - [Category("Buttons"), DefaultValue(typeof(Color), "WindowFrame")] - [Description("Border color of the close and options buttons when the mouse is over them.")] - public Color ButtonBorderColor { get; set; } - - [Category("Buttons"), DefaultValue(typeof(Color), "Highlight")] - [Description("Background color of the close and options buttons when the mouse is over them.")] - public Color ButtonHoverColor { get; set; } - - [Category("Content"), DefaultValue(typeof(Color), "HotTrack")] - [Description("Color of the content text when the mouse is hovering over it.")] - public Color ContentHoverColor { get; set; } - - [Category("Appearance"), DefaultValue(50)] - [Description("Gradient of window background color.")] - public int GradientPower { get; set; } - - [Category("Content")] - [Description("Font of the content text.")] - public Font ContentFont { get; set; } - - [Category("Title")] - [Description("Font of the title.")] - public Font TitleFont { get; set; } - - [Category("Image")] - [Description("Size of the icon image.")] - public Size ImageSize - { - get - { - if (imageSize.Width == 0) - { - if (Image != null) - { - return Image.Size; - } - else - { - return new Size(0, 0); - } - } - else - { - return imageSize; - } - } - set { imageSize = value; } - } - - public void ResetImageSize() - { - imageSize = Size.Empty; - } - - private bool ShouldSerializeImageSize() - { - return !imageSize.Equals(Size.Empty); - } - - private Size imageSize = new Size(0, 0); - - [Category("Image")] - [Description("Icon image to display.")] - public Image Image { get; set; } - - [Category("Header"), DefaultValue(true)] - [Description("Whether to show a 'grip' image within the window header.")] - public bool ShowGrip { get; set; } - - [Category("Behavior"), DefaultValue(true)] - [Description("Whether to scroll the window or only fade it.")] - public bool Scroll { get; set; } - - [Category("Content")] - [Description("Content text to display.")] - public string ContentText { get; set; } - - [Category("Title")] - [Description("Title text to display.")] - public string TitleText { get; set; } - - [Category("Title")] - [Description("Padding of title text.")] - public Padding TitlePadding { get; set; } - - private void ResetTitlePadding() - { - TitlePadding = Padding.Empty; - } - - private bool ShouldSerializeTitlePadding() - { - return !TitlePadding.Equals(Padding.Empty); - } - - [Category("Content")] - [Description("Padding of content text.")] - public Padding ContentPadding { get; set; } - - private void ResetContentPadding() - { - ContentPadding = Padding.Empty; - } - - private bool ShouldSerializeContentPadding() - { - return !ContentPadding.Equals(Padding.Empty); - } - - [Category("Image")] - [Description("Padding of icon image.")] - public Padding ImagePadding { get; set; } - - private void ResetImagePadding() - { - ImagePadding = Padding.Empty; - } - - private bool ShouldSerializeImagePadding() - { - return !ImagePadding.Equals(Padding.Empty); - } - - [Category("Header"), DefaultValue(9)] - [Description("Height of window header.")] - public int HeaderHeight { get; set; } - - [Category("Buttons"), DefaultValue(true)] - [Description("Whether to show the close button.")] - public bool ShowCloseButton { get; set; } - - [Category("Buttons"), DefaultValue(false)] - [Description("Whether to show the options button.")] - public bool ShowOptionsButton { get; set; } - - [Category("Behavior")] - [Description("Context menu to open when clicking on the options button.")] - public ContextMenuStrip OptionsMenu { get; set; } - - [Category("Behavior"), DefaultValue(3000)] - [Description("Time in milliseconds the window is displayed.")] - public int Delay { get; set; } - - [Category("Behavior"), DefaultValue(1000)] - [Description("Time in milliseconds needed to make the window appear or disappear.")] - public int AnimationDuration { get; set; } - - [Category("Behavior"), DefaultValue(10)] - [Description("Interval in milliseconds used to draw the animation.")] - public int AnimationInterval { get; set; } - - [Category("Appearance")] - [Description("Size of the window.")] - public Size Size { get; set; } - - [Category("Content")] - [Description("Show Content Right To Left,نمایش پیغام چپ به راست فعال شود")] - public bool IsRightToLeft { get; set; } - #endregion - - /// - /// Create a new instance of the popup component. - /// - public PopupNotifier() - { - // set default values - HeaderColor = SystemColors.ControlDark; - BodyColor = SystemColors.Control; - TitleColor = Color.Gray; - ContentColor = SystemColors.ControlText; - BorderColor = SystemColors.WindowFrame; - ButtonBorderColor = SystemColors.WindowFrame; - ButtonHoverColor = SystemColors.Highlight; - ContentHoverColor = SystemColors.HotTrack; - GradientPower = 50; - ContentFont = SystemFonts.DialogFont; - TitleFont = SystemFonts.CaptionFont; - ShowGrip = true; - Scroll = true; - TitlePadding = new Padding(0); - ContentPadding = new Padding(0); - ImagePadding = new Padding(0); - HeaderHeight = 9; - ShowCloseButton = true; - ShowOptionsButton = false; - Delay = 3000; - AnimationInterval = 10; - AnimationDuration = 1000; - Size = new Size(400, 100); - - frmPopup = new PopupNotifierForm(this); - frmPopup.FormBorderStyle = FormBorderStyle.None; - frmPopup.StartPosition = FormStartPosition.Manual; - frmPopup.FormBorderStyle = FormBorderStyle.None; - frmPopup.MouseEnter += frmPopup_MouseEnter; - frmPopup.MouseLeave += frmPopup_MouseLeave; - frmPopup.CloseClick += frmPopup_CloseClick; - frmPopup.LinkClick += frmPopup_LinkClick; - frmPopup.ContextMenuOpened += frmPopup_ContextMenuOpened; - frmPopup.ContextMenuClosed += frmPopup_ContextMenuClosed; - frmPopup.VisibleChanged += frmPopup_VisibleChanged; - - tmrAnimation = new Timer(); - tmrAnimation.Tick += tmAnimation_Tick; - - tmrWait = new Timer(); - tmrWait.Tick += tmWait_Tick; - } - private static object lockobj=new object(); - - - private static void Remove(int value) - { - lock (lockobj) - { - positions.Remove(value); - } - } - private void SetNextPosition() - { - lock(lockobj) - { positions.Sort(); - int minimum = 1; - foreach (var pos in positions) - { - if (pos == minimum) minimum = pos + 1; - } - - currentPosition = minimum; - positions.Add(minimum); - } - } - /// - /// Show the notification window if it is not already visible. - /// If the window is currently disappearing, it is shown again. - /// - public void Popup() - { - - if (!disposed) - { - if (!frmPopup.Visible) - { - SetNextPosition(); - frmPopup.Size = Size; - if (Scroll) - { - posStart = Screen.PrimaryScreen.WorkingArea.Bottom - currentPosition *frmPopup.Height; - posStop = Screen.PrimaryScreen.WorkingArea.Bottom - currentPosition * frmPopup.Height; - } - else - { - posStart = Screen.PrimaryScreen.WorkingArea.Bottom -currentPosition * frmPopup.Height; - posStop = Screen.PrimaryScreen.WorkingArea.Bottom - currentPosition * frmPopup.Height; - } - opacityStart = 0; - opacityStop = 1; - - frmPopup.Opacity = opacityStart; - frmPopup.Location = new Point(Screen.PrimaryScreen.WorkingArea.Right - frmPopup.Size.Width - 1, posStart); - ShowInactiveTopmost(frmPopup); - isAppearing = true; - - tmrWait.Interval = Delay; - tmrAnimation.Interval = AnimationInterval; - realAnimationDuration = AnimationDuration; - tmrAnimation.Start(); - sw = System.Diagnostics.Stopwatch.StartNew(); - System.Diagnostics.Debug.WriteLine("Animation started."); - } - else - { - if (!isAppearing) - { - frmPopup.Size = Size; - if (Scroll) - { - posStart = frmPopup.Top; - posStop = Screen.PrimaryScreen.WorkingArea.Bottom - currentPosition * frmPopup.Height; - } - else - { - posStart = Screen.PrimaryScreen.WorkingArea.Bottom -currentPosition * frmPopup.Height; - posStop = Screen.PrimaryScreen.WorkingArea.Bottom - currentPosition *frmPopup.Height; - } - opacityStart = frmPopup.Opacity; - opacityStop = 1; - isAppearing = true; - realAnimationDuration = Math.Max((int)sw.ElapsedMilliseconds, 1); - sw.Restart(); - System.Diagnostics.Debug.WriteLine("Animation direction changed."); - } - frmPopup.Invalidate(); - } - } - } - - /// - /// Hide the notification window. - /// - public void Hide() - { - System.Diagnostics.Debug.WriteLine("Animation stopped."); - System.Diagnostics.Debug.WriteLine("Wait timer stopped."); - tmrAnimation.Stop(); - tmrWait.Stop(); - frmPopup.Hide(); - } - - /// - /// The custom options menu has been closed. Restart the timer for - /// closing the notification window. - /// - /// - /// - private void frmPopup_ContextMenuClosed(object sender, EventArgs e) - { - System.Diagnostics.Debug.WriteLine("Menu closed."); - if (!mouseIsOn) - { - tmrWait.Interval = Delay; - tmrWait.Start(); - System.Diagnostics.Debug.WriteLine("Wait timer started."); - } - } - - - /// - /// The custom options menu has been opened. The window must not be closed - /// as long as the menu is open. - /// - /// - /// - private void frmPopup_ContextMenuOpened(object sender, EventArgs e) - { - System.Diagnostics.Debug.WriteLine("Menu opened."); - tmrWait.Stop(); - System.Diagnostics.Debug.WriteLine("Wait timer stopped."); - } - - /// - /// The text has been clicked. Raise the 'Click' event. - /// - /// - /// - private void frmPopup_LinkClick(object sender, EventArgs e) - { - Click?.Invoke(this, EventArgs.Empty); - } - - /// - /// The close button has been clicked. Hide the notification window - /// and raise the 'Close' event. - /// - /// - /// - private void frmPopup_CloseClick(object sender, EventArgs e) - { - Hide(); - Close?.Invoke(this, EventArgs.Empty); - } - - /// - /// Visibility has changed - /// - /// - /// - private void frmPopup_VisibleChanged(object sender, EventArgs e) - { - if (frmPopup.Visible) - { - Appear?.Invoke(this, EventArgs.Empty); - } - else - { - Disappear?.Invoke(this, EventArgs.Empty); - } - } - - /// - /// Update form position and opacity to show/hide the window. - /// - /// - /// - private void tmAnimation_Tick(object sender, EventArgs e) - { - long elapsed = sw.ElapsedMilliseconds; - - int posCurrent = (int)(posStart + (posStop - posStart) * elapsed / realAnimationDuration); - bool neg = posStop - posStart < 0; - if (neg && posCurrent < posStop || - !neg && posCurrent > posStop) - { - posCurrent = posStop; - } - - double opacityCurrent = opacityStart + (opacityStop - opacityStart) * elapsed / realAnimationDuration; - neg = opacityStop - opacityStart < 0; - if (neg && opacityCurrent < opacityStop || - !neg && opacityCurrent > opacityStop) - { - opacityCurrent = opacityStop; - } - - frmPopup.Top = posCurrent; - frmPopup.Opacity = opacityCurrent; - - // animation has ended - if (elapsed > realAnimationDuration) - { - - sw.Reset(); - tmrAnimation.Stop(); - System.Diagnostics.Debug.WriteLine("Animation stopped."); - - if (isAppearing) - { - if (Scroll) - { - posStart = Screen.PrimaryScreen.WorkingArea.Bottom - frmPopup.Height; - posStop = Screen.PrimaryScreen.WorkingArea.Bottom; - } - else - { - posStart = Screen.PrimaryScreen.WorkingArea.Bottom - frmPopup.Height; - posStop = Screen.PrimaryScreen.WorkingArea.Bottom - frmPopup.Height; - } - opacityStart = 1; - opacityStop = 0; - - realAnimationDuration = AnimationDuration; - - isAppearing = false; - maxPosition = frmPopup.Top; - maxOpacity = frmPopup.Opacity; - if (!mouseIsOn) - { - tmrWait.Stop(); - tmrWait.Start(); - System.Diagnostics.Debug.WriteLine("Wait timer started."); - } - } - else - { - frmPopup.Hide(); - Remove(currentPosition); - } - } - } - - /// - /// The wait timer has elapsed, start the animation to hide the window. - /// - /// - /// - private void tmWait_Tick(object sender, EventArgs e) - { - System.Diagnostics.Debug.WriteLine("Wait timer elapsed."); - tmrWait.Stop(); - tmrAnimation.Interval = AnimationInterval; - tmrAnimation.Start(); - sw.Restart(); - System.Diagnostics.Debug.WriteLine("Animation started."); - } - - /// - /// Start wait timer if the mouse leaves the form. - /// - /// - /// - private void frmPopup_MouseLeave(object sender, EventArgs e) - { - System.Diagnostics.Debug.WriteLine("MouseLeave"); - if (frmPopup.Visible && (OptionsMenu == null || !OptionsMenu.Visible)) - { - tmrWait.Interval = Delay; - tmrWait.Start(); - System.Diagnostics.Debug.WriteLine("Wait timer started."); - } - mouseIsOn = false; - } - - /// - /// Stop wait timer if the mouse enters the form. - /// - /// - /// - private void frmPopup_MouseEnter(object sender, EventArgs e) - { - System.Diagnostics.Debug.WriteLine("MouseEnter"); - if (!isAppearing) - { - frmPopup.Top = maxPosition; - frmPopup.Opacity = maxOpacity; - tmrAnimation.Stop(); - System.Diagnostics.Debug.WriteLine("Animation stopped."); - } - - tmrWait.Stop(); - System.Diagnostics.Debug.WriteLine("Wait timer stopped."); - - mouseIsOn = true; - } - - /// - /// Dispose the notification form. - /// - /// - protected override void Dispose(bool disposing) - { - if (!disposed) - { - if (disposing) - { - frmPopup?.Dispose(); - } - disposed = true; - } - base.Dispose(disposing); - } - } -} +/* + * Created/modified in 2011 by Simon Baer + * + * Based on the Code Project article by Nicolas Wälti: + * http://www.codeproject.com/KB/cpp/PopupNotifier.aspx + * + * Licensed under the Code Project Open License (CPOL). + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; +using System.Windows.Forms; +using Timer = System.Windows.Forms.Timer; + +namespace NotificationWindow +{ + /// + /// Non-visual component to show a notification window in the right lower + /// corner of the screen. + /// + [ToolboxBitmap(typeof(PopupNotifier), "Icon.ico")] + [DefaultEvent("Click")] + public class PopupNotifier : Component + { + public static List positions = new List(); + private int currentPosition; + #region Windows API + private const int SW_SHOWNOACTIVATE = 4; + private const int HWND_TOPMOST = -1; + private const uint SWP_NOACTIVATE = 0x0010; + + [DllImport("user32.dll", EntryPoint = "SetWindowPos")] + static extern bool SetWindowPos( + int hWnd, // Window handle + int hWndInsertAfter, // Placement-order handle + int X, // Horizontal position + int Y, // Vertical position + int cx, // Width + int cy, // Height + uint uFlags); // Window positioning flags + + [DllImport("user32.dll")] + static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + + static void ShowInactiveTopmost(Form frm) + { + ShowWindow(frm.Handle, SW_SHOWNOACTIVATE); + SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST, + frm.Left, frm.Top, frm.Width, frm.Height, + SWP_NOACTIVATE); + } + #endregion + + /// + /// Event that is raised when the text in the notification window is clicked. + /// + public event EventHandler Click; + + /// + /// Event that is raised when the notification window is manually closed. + /// + public event EventHandler Close; + + /// + /// Event that is raised when the notification Appears. + /// + public event EventHandler Appear; + + /// + /// Event that is raised when the notification Dissapers + /// + public event EventHandler Disappear; + + private bool disposed = false; + private PopupNotifierForm frmPopup; + private Timer tmrAnimation; + private Timer tmrWait; + + private bool isAppearing = true; + private bool mouseIsOn = false; + private int maxPosition; + private double maxOpacity; + private int posStart; + private int posStop; + private double opacityStart; + private double opacityStop; + private int realAnimationDuration; + private System.Diagnostics.Stopwatch sw; + + #region Properties + + [Category("Header"), DefaultValue(typeof(Color), "ControlDark")] + [Description("Color of the window header.")] + public Color HeaderColor { get; set; } + + [Category("Appearance"), DefaultValue(typeof(Color), "Control")] + [Description("Color of the window background.")] + public Color BodyColor { get; set; } + + [Category("Title"), DefaultValue(typeof(Color), "Gray")] + [Description("Color of the title text.")] + public Color TitleColor { get; set; } + + [Category("Content"), DefaultValue(typeof(Color), "ControlText")] + [Description("Color of the content text.")] + public Color ContentColor { get; set; } + + [Category("Appearance"), DefaultValue(typeof(Color), "WindowFrame")] + [Description("Color of the window border.")] + public Color BorderColor { get; set; } + + [Category("Buttons"), DefaultValue(typeof(Color), "WindowFrame")] + [Description("Border color of the close and options buttons when the mouse is over them.")] + public Color ButtonBorderColor { get; set; } + + [Category("Buttons"), DefaultValue(typeof(Color), "Highlight")] + [Description("Background color of the close and options buttons when the mouse is over them.")] + public Color ButtonHoverColor { get; set; } + + [Category("Content"), DefaultValue(typeof(Color), "HotTrack")] + [Description("Color of the content text when the mouse is hovering over it.")] + public Color ContentHoverColor { get; set; } + + [Category("Appearance"), DefaultValue(50)] + [Description("Gradient of window background color.")] + public int GradientPower { get; set; } + + [Category("Content")] + [Description("Font of the content text.")] + public Font ContentFont { get; set; } + + [Category("Title")] + [Description("Font of the title.")] + public Font TitleFont { get; set; } + + [Category("Image")] + [Description("Size of the icon image.")] + public Size ImageSize + { + get + { + if (imageSize.Width == 0) + { + if (Image != null) + { + return Image.Size; + } + else + { + return new Size(0, 0); + } + } + else + { + return imageSize; + } + } + set { imageSize = value; } + } + + public void ResetImageSize() + { + imageSize = Size.Empty; + } + + private bool ShouldSerializeImageSize() + { + return !imageSize.Equals(Size.Empty); + } + + private Size imageSize = new Size(0, 0); + + [Category("Image")] + [Description("Icon image to display.")] + public Image Image { get; set; } + + [Category("Header"), DefaultValue(true)] + [Description("Whether to show a 'grip' image within the window header.")] + public bool ShowGrip { get; set; } + + [Category("Behavior"), DefaultValue(true)] + [Description("Whether to scroll the window or only fade it.")] + public bool Scroll { get; set; } + + [Category("Content")] + [Description("Content text to display.")] + public string ContentText { get; set; } + + [Category("Title")] + [Description("Title text to display.")] + public string TitleText { get; set; } + + [Category("Title")] + [Description("Padding of title text.")] + public Padding TitlePadding { get; set; } + + private void ResetTitlePadding() + { + TitlePadding = Padding.Empty; + } + + private bool ShouldSerializeTitlePadding() + { + return !TitlePadding.Equals(Padding.Empty); + } + + [Category("Content")] + [Description("Padding of content text.")] + public Padding ContentPadding { get; set; } + + private void ResetContentPadding() + { + ContentPadding = Padding.Empty; + } + + private bool ShouldSerializeContentPadding() + { + return !ContentPadding.Equals(Padding.Empty); + } + + [Category("Image")] + [Description("Padding of icon image.")] + public Padding ImagePadding { get; set; } + + private void ResetImagePadding() + { + ImagePadding = Padding.Empty; + } + + private bool ShouldSerializeImagePadding() + { + return !ImagePadding.Equals(Padding.Empty); + } + + [Category("Header"), DefaultValue(9)] + [Description("Height of window header.")] + public int HeaderHeight { get; set; } + + [Category("Buttons"), DefaultValue(true)] + [Description("Whether to show the close button.")] + public bool ShowCloseButton { get; set; } + + [Category("Buttons"), DefaultValue(false)] + [Description("Whether to show the options button.")] + public bool ShowOptionsButton { get; set; } + + [Category("Behavior")] + [Description("Context menu to open when clicking on the options button.")] + public ContextMenuStrip OptionsMenu { get; set; } + + [Category("Behavior"), DefaultValue(3000)] + [Description("Time in milliseconds the window is displayed.")] + public int Delay { get; set; } + + [Category("Behavior"), DefaultValue(1000)] + [Description("Time in milliseconds needed to make the window appear or disappear.")] + public int AnimationDuration { get; set; } + + [Category("Behavior"), DefaultValue(10)] + [Description("Interval in milliseconds used to draw the animation.")] + public int AnimationInterval { get; set; } + + [Category("Appearance")] + [Description("Size of the window.")] + public Size Size { get; set; } + + [Category("Content")] + [Description("Show Content Right To Left,نمایش پیغام چپ به راست فعال شود")] + public bool IsRightToLeft { get; set; } + #endregion + + /// + /// Create a new instance of the popup component. + /// + public PopupNotifier() + { + // set default values + HeaderColor = SystemColors.ControlDark; + BodyColor = SystemColors.Control; + TitleColor = Color.Gray; + ContentColor = SystemColors.ControlText; + BorderColor = SystemColors.WindowFrame; + ButtonBorderColor = SystemColors.WindowFrame; + ButtonHoverColor = SystemColors.Highlight; + ContentHoverColor = SystemColors.HotTrack; + GradientPower = 50; + ContentFont = SystemFonts.DialogFont; + TitleFont = SystemFonts.CaptionFont; + ShowGrip = true; + Scroll = true; + TitlePadding = new Padding(0); + ContentPadding = new Padding(0); + ImagePadding = new Padding(0); + HeaderHeight = 9; + ShowCloseButton = true; + ShowOptionsButton = false; + Delay = 3000; + AnimationInterval = 10; + AnimationDuration = 1000; + Size = new Size(400, 100); + + frmPopup = new PopupNotifierForm(this); + frmPopup.FormBorderStyle = FormBorderStyle.None; + frmPopup.StartPosition = FormStartPosition.Manual; + frmPopup.FormBorderStyle = FormBorderStyle.None; + frmPopup.MouseEnter += frmPopup_MouseEnter; + frmPopup.MouseLeave += frmPopup_MouseLeave; + frmPopup.CloseClick += frmPopup_CloseClick; + frmPopup.LinkClick += frmPopup_LinkClick; + frmPopup.ContextMenuOpened += frmPopup_ContextMenuOpened; + frmPopup.ContextMenuClosed += frmPopup_ContextMenuClosed; + frmPopup.VisibleChanged += frmPopup_VisibleChanged; + + tmrAnimation = new Timer(); + tmrAnimation.Tick += tmAnimation_Tick; + + tmrWait = new Timer(); + tmrWait.Tick += tmWait_Tick; + } + private static object lockobj=new object(); + + + private static void Remove(int value) + { + lock (lockobj) + { + positions.Remove(value); + } + } + private void SetNextPosition() + { + lock(lockobj) + { positions.Sort(); + int minimum = 1; + foreach (var pos in positions) + { + if (pos == minimum) minimum = pos + 1; + } + + currentPosition = minimum; + positions.Add(minimum); + } + } + /// + /// Show the notification window if it is not already visible. + /// If the window is currently disappearing, it is shown again. + /// + public void Popup() + { + + if (!disposed) + { + if (!frmPopup.Visible) + { + SetNextPosition(); + frmPopup.Size = Size; + if (Scroll) + { + posStart = Screen.PrimaryScreen.WorkingArea.Bottom - currentPosition *frmPopup.Height; + posStop = Screen.PrimaryScreen.WorkingArea.Bottom - currentPosition * frmPopup.Height; + } + else + { + posStart = Screen.PrimaryScreen.WorkingArea.Bottom -currentPosition * frmPopup.Height; + posStop = Screen.PrimaryScreen.WorkingArea.Bottom - currentPosition * frmPopup.Height; + } + opacityStart = 0; + opacityStop = 1; + + frmPopup.Opacity = opacityStart; + frmPopup.Location = new Point(Screen.PrimaryScreen.WorkingArea.Right - frmPopup.Size.Width - 1, posStart); + ShowInactiveTopmost(frmPopup); + isAppearing = true; + + tmrWait.Interval = Delay; + tmrAnimation.Interval = AnimationInterval; + realAnimationDuration = AnimationDuration; + tmrAnimation.Start(); + sw = System.Diagnostics.Stopwatch.StartNew(); + System.Diagnostics.Debug.WriteLine("Animation started."); + } + else + { + if (!isAppearing) + { + frmPopup.Size = Size; + if (Scroll) + { + posStart = frmPopup.Top; + posStop = Screen.PrimaryScreen.WorkingArea.Bottom - currentPosition * frmPopup.Height; + } + else + { + posStart = Screen.PrimaryScreen.WorkingArea.Bottom -currentPosition * frmPopup.Height; + posStop = Screen.PrimaryScreen.WorkingArea.Bottom - currentPosition *frmPopup.Height; + } + opacityStart = frmPopup.Opacity; + opacityStop = 1; + isAppearing = true; + realAnimationDuration = Math.Max((int)sw.ElapsedMilliseconds, 1); + sw.Restart(); + System.Diagnostics.Debug.WriteLine("Animation direction changed."); + } + frmPopup.Invalidate(); + } + } + } + + /// + /// Hide the notification window. + /// + public void Hide() + { + System.Diagnostics.Debug.WriteLine("Animation stopped."); + System.Diagnostics.Debug.WriteLine("Wait timer stopped."); + tmrAnimation.Stop(); + tmrWait.Stop(); + frmPopup.Hide(); + } + + /// + /// The custom options menu has been closed. Restart the timer for + /// closing the notification window. + /// + /// + /// + private void frmPopup_ContextMenuClosed(object sender, EventArgs e) + { + System.Diagnostics.Debug.WriteLine("Menu closed."); + if (!mouseIsOn) + { + tmrWait.Interval = Delay; + tmrWait.Start(); + System.Diagnostics.Debug.WriteLine("Wait timer started."); + } + } + + + /// + /// The custom options menu has been opened. The window must not be closed + /// as long as the menu is open. + /// + /// + /// + private void frmPopup_ContextMenuOpened(object sender, EventArgs e) + { + System.Diagnostics.Debug.WriteLine("Menu opened."); + tmrWait.Stop(); + System.Diagnostics.Debug.WriteLine("Wait timer stopped."); + } + + /// + /// The text has been clicked. Raise the 'Click' event. + /// + /// + /// + private void frmPopup_LinkClick(object sender, EventArgs e) + { + Click?.Invoke(this, EventArgs.Empty); + } + + /// + /// The close button has been clicked. Hide the notification window + /// and raise the 'Close' event. + /// + /// + /// + private void frmPopup_CloseClick(object sender, EventArgs e) + { + Hide(); + Close?.Invoke(this, EventArgs.Empty); + } + + /// + /// Visibility has changed + /// + /// + /// + private void frmPopup_VisibleChanged(object sender, EventArgs e) + { + if (frmPopup.Visible) + { + Appear?.Invoke(this, EventArgs.Empty); + } + else + { + Disappear?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Update form position and opacity to show/hide the window. + /// + /// + /// + private void tmAnimation_Tick(object sender, EventArgs e) + { + long elapsed = sw.ElapsedMilliseconds; + + int posCurrent = (int)(posStart + (posStop - posStart) * elapsed / realAnimationDuration); + bool neg = posStop - posStart < 0; + if (neg && posCurrent < posStop || + !neg && posCurrent > posStop) + { + posCurrent = posStop; + } + + double opacityCurrent = opacityStart + (opacityStop - opacityStart) * elapsed / realAnimationDuration; + neg = opacityStop - opacityStart < 0; + if (neg && opacityCurrent < opacityStop || + !neg && opacityCurrent > opacityStop) + { + opacityCurrent = opacityStop; + } + + frmPopup.Top = posCurrent; + frmPopup.Opacity = opacityCurrent; + + // animation has ended + if (elapsed > realAnimationDuration) + { + + sw.Reset(); + tmrAnimation.Stop(); + System.Diagnostics.Debug.WriteLine("Animation stopped."); + + if (isAppearing) + { + if (Scroll) + { + posStart = Screen.PrimaryScreen.WorkingArea.Bottom - frmPopup.Height; + posStop = Screen.PrimaryScreen.WorkingArea.Bottom; + } + else + { + posStart = Screen.PrimaryScreen.WorkingArea.Bottom - frmPopup.Height; + posStop = Screen.PrimaryScreen.WorkingArea.Bottom - frmPopup.Height; + } + opacityStart = 1; + opacityStop = 0; + + realAnimationDuration = AnimationDuration; + + isAppearing = false; + maxPosition = frmPopup.Top; + maxOpacity = frmPopup.Opacity; + if (!mouseIsOn) + { + tmrWait.Stop(); + tmrWait.Start(); + System.Diagnostics.Debug.WriteLine("Wait timer started."); + } + } + else + { + frmPopup.Hide(); + Remove(currentPosition); + } + } + } + + /// + /// The wait timer has elapsed, start the animation to hide the window. + /// + /// + /// + private void tmWait_Tick(object sender, EventArgs e) + { + System.Diagnostics.Debug.WriteLine("Wait timer elapsed."); + tmrWait.Stop(); + tmrAnimation.Interval = AnimationInterval; + tmrAnimation.Start(); + sw.Restart(); + System.Diagnostics.Debug.WriteLine("Animation started."); + } + + /// + /// Start wait timer if the mouse leaves the form. + /// + /// + /// + private void frmPopup_MouseLeave(object sender, EventArgs e) + { + System.Diagnostics.Debug.WriteLine("MouseLeave"); + if (frmPopup.Visible && (OptionsMenu == null || !OptionsMenu.Visible)) + { + tmrWait.Interval = Delay; + tmrWait.Start(); + System.Diagnostics.Debug.WriteLine("Wait timer started."); + } + mouseIsOn = false; + } + + /// + /// Stop wait timer if the mouse enters the form. + /// + /// + /// + private void frmPopup_MouseEnter(object sender, EventArgs e) + { + System.Diagnostics.Debug.WriteLine("MouseEnter"); + if (!isAppearing) + { + frmPopup.Top = maxPosition; + frmPopup.Opacity = maxOpacity; + tmrAnimation.Stop(); + System.Diagnostics.Debug.WriteLine("Animation stopped."); + } + + tmrWait.Stop(); + System.Diagnostics.Debug.WriteLine("Wait timer stopped."); + + mouseIsOn = true; + } + + /// + /// Dispose the notification form. + /// + /// + protected override void Dispose(bool disposing) + { + if (!disposed) + { + if (disposing) + { + frmPopup?.Dispose(); + } + disposed = true; + } + base.Dispose(disposing); + } + } +} diff --git a/Tulpep.NotificationWindow/PopupNotifierForm.cs b/NotificationWindow/PopupNotifierForm.cs similarity index 97% rename from Tulpep.NotificationWindow/PopupNotifierForm.cs rename to NotificationWindow/PopupNotifierForm.cs index 10ef841..d357041 100644 --- a/Tulpep.NotificationWindow/PopupNotifierForm.cs +++ b/NotificationWindow/PopupNotifierForm.cs @@ -1,389 +1,389 @@ -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; - -namespace NotificationWindow -{ - /// - /// This is the form of the actual notification window. - /// - internal class PopupNotifierForm : Form - { - /// - /// Event that is raised when the text is clicked. - /// - public event EventHandler LinkClick; - - /// - /// Event that is raised when the notification window is manually closed. - /// - public event EventHandler CloseClick; - - internal event EventHandler ContextMenuOpened; - internal event EventHandler ContextMenuClosed; - - private bool mouseOnClose = false; - private bool mouseOnLink = false; - private bool mouseOnOptions = false; - private int heightOfTitle; - - #region GDI objects - - private bool gdiInitialized = false; - private Rectangle rcBody; - private Rectangle rcHeader; - private Rectangle rcForm; - private LinearGradientBrush brushBody; - private LinearGradientBrush brushHeader; - private Brush brushButtonHover; - private Pen penButtonBorder; - private Pen penContent; - private Pen penBorder; - private Brush brushForeColor; - private Brush brushLinkHover; - private Brush brushContent; - private Brush brushTitle; - - #endregion - - /// - /// Create a new instance. - /// - /// PopupNotifier - public PopupNotifierForm(PopupNotifier parent) - { - Parent = parent; - SetStyle(ControlStyles.OptimizedDoubleBuffer, true); - SetStyle(ControlStyles.ResizeRedraw, true); - SetStyle(ControlStyles.AllPaintingInWmPaint, true); - ShowInTaskbar = false; - - VisibleChanged += PopupNotifierForm_VisibleChanged; - MouseMove += PopupNotifierForm_MouseMove; - MouseUp += PopupNotifierForm_MouseUp; - Paint += PopupNotifierForm_Paint; - } - - /// - /// The form is shown/hidden. - /// - /// - /// - private void PopupNotifierForm_VisibleChanged(object sender, EventArgs e) - { - if (Visible) - { - mouseOnClose = false; - mouseOnLink = false; - mouseOnOptions = false; - } - } - - /// - /// Used in design mode. - /// - private void InitializeComponent() - { - SuspendLayout(); - // - // PopupNotifierForm - // - ClientSize = new Size(392, 66); - FormBorderStyle = FormBorderStyle.None; - Name = "PopupNotifierForm"; - StartPosition = FormStartPosition.Manual; - ResumeLayout(false); - - } - - /// - /// Gets or sets the parent control. - /// - public new PopupNotifier Parent { get; set; } - - /// - /// Add two values but do not return a value greater than 255. - /// - /// first value - /// value to add - /// sum of both values - private int AddValueMax255(int input, int add) - { - return (input + add < 256) ? input + add : 255; - } - - /// - /// Subtract two values but do not returns a value below 0. - /// - /// first value - /// value to subtract - /// first value minus second value - private int DedValueMin0(int input, int ded) - { - return (input - ded > 0) ? input - ded : 0; - } - - /// - /// Returns a color which is darker than the given color. - /// - /// Color - /// darker color - private Color GetDarkerColor(Color color) - { - return Color.FromArgb(255, DedValueMin0((int)color.R, Parent.GradientPower), DedValueMin0((int)color.G, Parent.GradientPower), DedValueMin0((int)color.B, Parent.GradientPower)); - } - - /// - /// Returns a color which is lighter than the given color. - /// - /// Color - /// lighter color - private Color GetLighterColor(Color color) - { - return Color.FromArgb(255, AddValueMax255((int)color.R, Parent.GradientPower), AddValueMax255((int)color.G, Parent.GradientPower), AddValueMax255((int)color.B, Parent.GradientPower)); - } - - /// - /// Gets the rectangle of the content text. - /// - private RectangleF RectContentText - { - get - { - if (Parent.Image != null) - { - return new RectangleF( - Parent.ImagePadding.Left + Parent.ImageSize.Width + Parent.ImagePadding.Right + Parent.ContentPadding.Left, - Parent.HeaderHeight + Parent.TitlePadding.Top + heightOfTitle + Parent.TitlePadding.Bottom + Parent.ContentPadding.Top, - Width - Parent.ImagePadding.Left - Parent.ImageSize.Width - Parent.ImagePadding.Right - Parent.ContentPadding.Left - Parent.ContentPadding.Right - 16 - 5, - Height - Parent.HeaderHeight - Parent.TitlePadding.Top - heightOfTitle - Parent.TitlePadding.Bottom - Parent.ContentPadding.Top - Parent.ContentPadding.Bottom - 1); - } - else - { - return new RectangleF( - Parent.ContentPadding.Left, - Parent.HeaderHeight + Parent.TitlePadding.Top + heightOfTitle + Parent.TitlePadding.Bottom + Parent.ContentPadding.Top, - Width - Parent.ContentPadding.Left - Parent.ContentPadding.Right - 16 - 5, - Height - Parent.HeaderHeight - Parent.TitlePadding.Top - heightOfTitle - Parent.TitlePadding.Bottom - Parent.ContentPadding.Top - Parent.ContentPadding.Bottom - 1); - } - } - } - - /// - /// gets the rectangle of the close button. - /// - private Rectangle RectClose - { - get { return new Rectangle(Width - 5 - 16, Parent.HeaderHeight + 3, 16, 16); } - } - - /// - /// Gets the rectangle of the options button. - /// - private Rectangle RectOptions - { - get { return new Rectangle(Width - 5 - 16, Parent.HeaderHeight + 3 + 16 + 5, 16, 16); } - } - - /// - /// Update form to display hover styles when the mouse moves over the notification form. - /// - /// - /// - private void PopupNotifierForm_MouseMove(object sender, MouseEventArgs e) - { - if (Parent.ShowCloseButton) - { - mouseOnClose = RectClose.Contains(e.X, e.Y); - } - if (Parent.ShowOptionsButton) - { - mouseOnOptions = RectOptions.Contains(e.X, e.Y); - } - mouseOnLink = RectContentText.Contains(e.X, e.Y); - Invalidate(); - } - - /// - /// A mouse button has been released, check if something has been clicked. - /// - /// - /// - private void PopupNotifierForm_MouseUp(object sender, MouseEventArgs e) - { - if (e.Button == MouseButtons.Left) - { - if (RectClose.Contains(e.X, e.Y) && (CloseClick != null)) - { - CloseClick(this, EventArgs.Empty); - } - if (RectContentText.Contains(e.X, e.Y) && (LinkClick != null)) - { - LinkClick(this, EventArgs.Empty); - } - if (RectOptions.Contains(e.X, e.Y) && (Parent.OptionsMenu != null)) - { - if (ContextMenuOpened != null) - { - ContextMenuOpened(this, EventArgs.Empty); - } - Parent.OptionsMenu.Show(this, new Point(RectOptions.Right - Parent.OptionsMenu.Width, RectOptions.Bottom)); - Parent.OptionsMenu.Closed += OptionsMenu_Closed; - } - } - } - - /// - /// The options popup menu has been closed. - /// - /// - /// - private void OptionsMenu_Closed(object sender, ToolStripDropDownClosedEventArgs e) - { - Parent.OptionsMenu.Closed -= OptionsMenu_Closed; - - if (ContextMenuClosed != null) - { - ContextMenuClosed(this, EventArgs.Empty); - } - } - - /// - /// Create all GDI objects used to paint the form. - /// - private void AllocateGDIObjects() - { - rcBody = new Rectangle(0, 0, Width, Height); - rcHeader = new Rectangle(0, 0, Width, Parent.HeaderHeight); - rcForm = new Rectangle(0, 0, Width - 1, Height - 1); - - brushBody = new LinearGradientBrush(rcBody, Parent.BodyColor, GetLighterColor(Parent.BodyColor), LinearGradientMode.Vertical); - brushHeader = new LinearGradientBrush(rcHeader, Parent.HeaderColor, GetDarkerColor(Parent.HeaderColor), LinearGradientMode.Vertical); - brushButtonHover = new SolidBrush(Parent.ButtonHoverColor); - penButtonBorder = new Pen(Parent.ButtonBorderColor); - penContent = new Pen(Parent.ContentColor, 2); - penBorder = new Pen(Parent.BorderColor); - brushForeColor = new SolidBrush(ForeColor); - brushLinkHover = new SolidBrush(Parent.ContentHoverColor); - brushContent = new SolidBrush(Parent.ContentColor); - brushTitle = new SolidBrush(Parent.TitleColor); - - gdiInitialized = true; - } - - /// - /// Free all GDI objects. - /// - private void DisposeGDIObjects() - { - if (gdiInitialized) - { - brushBody.Dispose(); - brushHeader.Dispose(); - brushButtonHover.Dispose(); - penButtonBorder.Dispose(); - penContent.Dispose(); - penBorder.Dispose(); - brushForeColor.Dispose(); - brushLinkHover.Dispose(); - brushContent.Dispose(); - brushTitle.Dispose(); - } - } - - /// - /// Draw the notification form. - /// - /// - /// - private void PopupNotifierForm_Paint(object sender, PaintEventArgs e) - { - if (!gdiInitialized) - { - AllocateGDIObjects(); - } - - // draw window - e.Graphics.FillRectangle(brushBody, rcBody); - e.Graphics.FillRectangle(brushHeader, rcHeader); - e.Graphics.DrawRectangle(penBorder, rcForm); - if (Parent.ShowGrip) - { - e.Graphics.DrawImage(Properties.Resources.Grip, (int)((Width - Properties.Resources.Grip.Width) / 2), (int)((Parent.HeaderHeight - 3) / 2)); - } - if (Parent.ShowCloseButton) - { - if (mouseOnClose) - { - e.Graphics.FillRectangle(brushButtonHover, RectClose); - e.Graphics.DrawRectangle(penButtonBorder, RectClose); - } - e.Graphics.DrawLine(penContent, RectClose.Left + 4, RectClose.Top + 4, RectClose.Right - 4, RectClose.Bottom - 4); - e.Graphics.DrawLine(penContent, RectClose.Left + 4, RectClose.Bottom - 4, RectClose.Right - 4, RectClose.Top + 4); - } - if (Parent.ShowOptionsButton) - { - if (mouseOnOptions) - { - e.Graphics.FillRectangle(brushButtonHover, RectOptions); - e.Graphics.DrawRectangle(penButtonBorder, RectOptions); - } - e.Graphics.FillPolygon(brushForeColor, new Point[] { new Point(RectOptions.Left + 4, RectOptions.Top + 6), new Point(RectOptions.Left + 12, RectOptions.Top + 6), new Point(RectOptions.Left + 8, RectOptions.Top + 4 + 6) }); - } - - // draw icon - if (Parent.Image != null) - { - e.Graphics.DrawImage(Parent.Image, Parent.ImagePadding.Left, Parent.HeaderHeight + Parent.ImagePadding.Top, Parent.ImageSize.Width, Parent.ImageSize.Height); - } - - - if (Parent.IsRightToLeft) - { - heightOfTitle = (int)e.Graphics.MeasureString("A", Parent.TitleFont).Height; - - // the value 30 is because of x close icon - int titleX2 = Width - 30;// Parent.TitlePadding.Right; - - // draw title right to left - StringFormat headerFormat = new StringFormat(StringFormatFlags.DirectionRightToLeft); - e.Graphics.DrawString(Parent.TitleText, Parent.TitleFont, brushTitle, titleX2, Parent.HeaderHeight + Parent.TitlePadding.Top, headerFormat); - - // draw content text, optionally with a bold part - Cursor = mouseOnLink ? Cursors.Hand : Cursors.Default; - Brush brushText = mouseOnLink ? brushLinkHover : brushContent; - - // draw content right to left - StringFormat contentFormat = new StringFormat(StringFormatFlags.DirectionRightToLeft); - e.Graphics.DrawString(Parent.ContentText, Parent.ContentFont, brushText, RectContentText, contentFormat); - } - else - { - // calculate height of title - heightOfTitle = (int)e.Graphics.MeasureString("A", Parent.TitleFont).Height; - int titleX = Parent.TitlePadding.Left; - if (Parent.Image != null) - titleX += Parent.ImagePadding.Left + Parent.ImageSize.Width + Parent.ImagePadding.Right; - e.Graphics.DrawString(Parent.TitleText, Parent.TitleFont, brushTitle, titleX, Parent.HeaderHeight + Parent.TitlePadding.Top); - // draw content text, optionally with a bold part - Cursor = mouseOnLink ? Cursors.Hand : Cursors.Default; - Brush brushText = mouseOnLink ? brushLinkHover : brushContent; - e.Graphics.DrawString(Parent.ContentText, Parent.ContentFont, brushText, RectContentText); - } - } - - /// - /// Dispose GDI objects. - /// - /// - protected override void Dispose(bool disposing) - { - if (disposing) - { - DisposeGDIObjects(); - } - base.Dispose(disposing); - } - } +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace NotificationWindow +{ + /// + /// This is the form of the actual notification window. + /// + internal class PopupNotifierForm : Form + { + /// + /// Event that is raised when the text is clicked. + /// + public event EventHandler LinkClick; + + /// + /// Event that is raised when the notification window is manually closed. + /// + public event EventHandler CloseClick; + + internal event EventHandler ContextMenuOpened; + internal event EventHandler ContextMenuClosed; + + private bool mouseOnClose = false; + private bool mouseOnLink = false; + private bool mouseOnOptions = false; + private int heightOfTitle; + + #region GDI objects + + private bool gdiInitialized = false; + private Rectangle rcBody; + private Rectangle rcHeader; + private Rectangle rcForm; + private LinearGradientBrush brushBody; + private LinearGradientBrush brushHeader; + private Brush brushButtonHover; + private Pen penButtonBorder; + private Pen penContent; + private Pen penBorder; + private Brush brushForeColor; + private Brush brushLinkHover; + private Brush brushContent; + private Brush brushTitle; + + #endregion + + /// + /// Create a new instance. + /// + /// PopupNotifier + public PopupNotifierForm(PopupNotifier parent) + { + Parent = parent; + SetStyle(ControlStyles.OptimizedDoubleBuffer, true); + SetStyle(ControlStyles.ResizeRedraw, true); + SetStyle(ControlStyles.AllPaintingInWmPaint, true); + ShowInTaskbar = false; + + VisibleChanged += PopupNotifierForm_VisibleChanged; + MouseMove += PopupNotifierForm_MouseMove; + MouseUp += PopupNotifierForm_MouseUp; + Paint += PopupNotifierForm_Paint; + } + + /// + /// The form is shown/hidden. + /// + /// + /// + private void PopupNotifierForm_VisibleChanged(object sender, EventArgs e) + { + if (Visible) + { + mouseOnClose = false; + mouseOnLink = false; + mouseOnOptions = false; + } + } + + /// + /// Used in design mode. + /// + private void InitializeComponent() + { + SuspendLayout(); + // + // PopupNotifierForm + // + ClientSize = new Size(392, 66); + FormBorderStyle = FormBorderStyle.None; + Name = "PopupNotifierForm"; + StartPosition = FormStartPosition.Manual; + ResumeLayout(false); + + } + + /// + /// Gets or sets the parent control. + /// + public new PopupNotifier Parent { get; set; } + + /// + /// Add two values but do not return a value greater than 255. + /// + /// first value + /// value to add + /// sum of both values + private int AddValueMax255(int input, int add) + { + return (input + add < 256) ? input + add : 255; + } + + /// + /// Subtract two values but do not returns a value below 0. + /// + /// first value + /// value to subtract + /// first value minus second value + private int DedValueMin0(int input, int ded) + { + return (input - ded > 0) ? input - ded : 0; + } + + /// + /// Returns a color which is darker than the given color. + /// + /// Color + /// darker color + private Color GetDarkerColor(Color color) + { + return Color.FromArgb(255, DedValueMin0((int)color.R, Parent.GradientPower), DedValueMin0((int)color.G, Parent.GradientPower), DedValueMin0((int)color.B, Parent.GradientPower)); + } + + /// + /// Returns a color which is lighter than the given color. + /// + /// Color + /// lighter color + private Color GetLighterColor(Color color) + { + return Color.FromArgb(255, AddValueMax255((int)color.R, Parent.GradientPower), AddValueMax255((int)color.G, Parent.GradientPower), AddValueMax255((int)color.B, Parent.GradientPower)); + } + + /// + /// Gets the rectangle of the content text. + /// + private RectangleF RectContentText + { + get + { + if (Parent.Image != null) + { + return new RectangleF( + Parent.ImagePadding.Left + Parent.ImageSize.Width + Parent.ImagePadding.Right + Parent.ContentPadding.Left, + Parent.HeaderHeight + Parent.TitlePadding.Top + heightOfTitle + Parent.TitlePadding.Bottom + Parent.ContentPadding.Top, + Width - Parent.ImagePadding.Left - Parent.ImageSize.Width - Parent.ImagePadding.Right - Parent.ContentPadding.Left - Parent.ContentPadding.Right - 16 - 5, + Height - Parent.HeaderHeight - Parent.TitlePadding.Top - heightOfTitle - Parent.TitlePadding.Bottom - Parent.ContentPadding.Top - Parent.ContentPadding.Bottom - 1); + } + else + { + return new RectangleF( + Parent.ContentPadding.Left, + Parent.HeaderHeight + Parent.TitlePadding.Top + heightOfTitle + Parent.TitlePadding.Bottom + Parent.ContentPadding.Top, + Width - Parent.ContentPadding.Left - Parent.ContentPadding.Right - 16 - 5, + Height - Parent.HeaderHeight - Parent.TitlePadding.Top - heightOfTitle - Parent.TitlePadding.Bottom - Parent.ContentPadding.Top - Parent.ContentPadding.Bottom - 1); + } + } + } + + /// + /// gets the rectangle of the close button. + /// + private Rectangle RectClose + { + get { return new Rectangle(Width - 5 - 16, Parent.HeaderHeight + 3, 16, 16); } + } + + /// + /// Gets the rectangle of the options button. + /// + private Rectangle RectOptions + { + get { return new Rectangle(Width - 5 - 16, Parent.HeaderHeight + 3 + 16 + 5, 16, 16); } + } + + /// + /// Update form to display hover styles when the mouse moves over the notification form. + /// + /// + /// + private void PopupNotifierForm_MouseMove(object sender, MouseEventArgs e) + { + if (Parent.ShowCloseButton) + { + mouseOnClose = RectClose.Contains(e.X, e.Y); + } + if (Parent.ShowOptionsButton) + { + mouseOnOptions = RectOptions.Contains(e.X, e.Y); + } + mouseOnLink = RectContentText.Contains(e.X, e.Y); + Invalidate(); + } + + /// + /// A mouse button has been released, check if something has been clicked. + /// + /// + /// + private void PopupNotifierForm_MouseUp(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + if (RectClose.Contains(e.X, e.Y) && (CloseClick != null)) + { + CloseClick(this, EventArgs.Empty); + } + if (RectContentText.Contains(e.X, e.Y) && (LinkClick != null)) + { + LinkClick(this, EventArgs.Empty); + } + if (RectOptions.Contains(e.X, e.Y) && (Parent.OptionsMenu != null)) + { + if (ContextMenuOpened != null) + { + ContextMenuOpened(this, EventArgs.Empty); + } + Parent.OptionsMenu.Show(this, new Point(RectOptions.Right - Parent.OptionsMenu.Width, RectOptions.Bottom)); + Parent.OptionsMenu.Closed += OptionsMenu_Closed; + } + } + } + + /// + /// The options popup menu has been closed. + /// + /// + /// + private void OptionsMenu_Closed(object sender, ToolStripDropDownClosedEventArgs e) + { + Parent.OptionsMenu.Closed -= OptionsMenu_Closed; + + if (ContextMenuClosed != null) + { + ContextMenuClosed(this, EventArgs.Empty); + } + } + + /// + /// Create all GDI objects used to paint the form. + /// + private void AllocateGDIObjects() + { + rcBody = new Rectangle(0, 0, Width, Height); + rcHeader = new Rectangle(0, 0, Width, Parent.HeaderHeight); + rcForm = new Rectangle(0, 0, Width - 1, Height - 1); + + brushBody = new LinearGradientBrush(rcBody, Parent.BodyColor, GetLighterColor(Parent.BodyColor), LinearGradientMode.Vertical); + brushHeader = new LinearGradientBrush(rcHeader, Parent.HeaderColor, GetDarkerColor(Parent.HeaderColor), LinearGradientMode.Vertical); + brushButtonHover = new SolidBrush(Parent.ButtonHoverColor); + penButtonBorder = new Pen(Parent.ButtonBorderColor); + penContent = new Pen(Parent.ContentColor, 2); + penBorder = new Pen(Parent.BorderColor); + brushForeColor = new SolidBrush(ForeColor); + brushLinkHover = new SolidBrush(Parent.ContentHoverColor); + brushContent = new SolidBrush(Parent.ContentColor); + brushTitle = new SolidBrush(Parent.TitleColor); + + gdiInitialized = true; + } + + /// + /// Free all GDI objects. + /// + private void DisposeGDIObjects() + { + if (gdiInitialized) + { + brushBody.Dispose(); + brushHeader.Dispose(); + brushButtonHover.Dispose(); + penButtonBorder.Dispose(); + penContent.Dispose(); + penBorder.Dispose(); + brushForeColor.Dispose(); + brushLinkHover.Dispose(); + brushContent.Dispose(); + brushTitle.Dispose(); + } + } + + /// + /// Draw the notification form. + /// + /// + /// + private void PopupNotifierForm_Paint(object sender, PaintEventArgs e) + { + if (!gdiInitialized) + { + AllocateGDIObjects(); + } + + // draw window + e.Graphics.FillRectangle(brushBody, rcBody); + e.Graphics.FillRectangle(brushHeader, rcHeader); + e.Graphics.DrawRectangle(penBorder, rcForm); + if (Parent.ShowGrip) + { + e.Graphics.DrawImage(Properties.Resources.Grip, (int)((Width - Properties.Resources.Grip.Width) / 2), (int)((Parent.HeaderHeight - 3) / 2)); + } + if (Parent.ShowCloseButton) + { + if (mouseOnClose) + { + e.Graphics.FillRectangle(brushButtonHover, RectClose); + e.Graphics.DrawRectangle(penButtonBorder, RectClose); + } + e.Graphics.DrawLine(penContent, RectClose.Left + 4, RectClose.Top + 4, RectClose.Right - 4, RectClose.Bottom - 4); + e.Graphics.DrawLine(penContent, RectClose.Left + 4, RectClose.Bottom - 4, RectClose.Right - 4, RectClose.Top + 4); + } + if (Parent.ShowOptionsButton) + { + if (mouseOnOptions) + { + e.Graphics.FillRectangle(brushButtonHover, RectOptions); + e.Graphics.DrawRectangle(penButtonBorder, RectOptions); + } + e.Graphics.FillPolygon(brushForeColor, new Point[] { new Point(RectOptions.Left + 4, RectOptions.Top + 6), new Point(RectOptions.Left + 12, RectOptions.Top + 6), new Point(RectOptions.Left + 8, RectOptions.Top + 4 + 6) }); + } + + // draw icon + if (Parent.Image != null) + { + e.Graphics.DrawImage(Parent.Image, Parent.ImagePadding.Left, Parent.HeaderHeight + Parent.ImagePadding.Top, Parent.ImageSize.Width, Parent.ImageSize.Height); + } + + + if (Parent.IsRightToLeft) + { + heightOfTitle = (int)e.Graphics.MeasureString("A", Parent.TitleFont).Height; + + // the value 30 is because of x close icon + int titleX2 = Width - 30;// Parent.TitlePadding.Right; + + // draw title right to left + StringFormat headerFormat = new StringFormat(StringFormatFlags.DirectionRightToLeft); + e.Graphics.DrawString(Parent.TitleText, Parent.TitleFont, brushTitle, titleX2, Parent.HeaderHeight + Parent.TitlePadding.Top, headerFormat); + + // draw content text, optionally with a bold part + Cursor = mouseOnLink ? Cursors.Hand : Cursors.Default; + Brush brushText = mouseOnLink ? brushLinkHover : brushContent; + + // draw content right to left + StringFormat contentFormat = new StringFormat(StringFormatFlags.DirectionRightToLeft); + e.Graphics.DrawString(Parent.ContentText, Parent.ContentFont, brushText, RectContentText, contentFormat); + } + else + { + // calculate height of title + heightOfTitle = (int)e.Graphics.MeasureString("A", Parent.TitleFont).Height; + int titleX = Parent.TitlePadding.Left; + if (Parent.Image != null) + titleX += Parent.ImagePadding.Left + Parent.ImageSize.Width + Parent.ImagePadding.Right; + e.Graphics.DrawString(Parent.TitleText, Parent.TitleFont, brushTitle, titleX, Parent.HeaderHeight + Parent.TitlePadding.Top); + // draw content text, optionally with a bold part + Cursor = mouseOnLink ? Cursors.Hand : Cursors.Default; + Brush brushText = mouseOnLink ? brushLinkHover : brushContent; + e.Graphics.DrawString(Parent.ContentText, Parent.ContentFont, brushText, RectContentText); + } + } + + /// + /// Dispose GDI objects. + /// + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + DisposeGDIObjects(); + } + base.Dispose(disposing); + } + } } \ No newline at end of file diff --git a/Tulpep.NotificationWindow/Properties/AssemblyInfo.cs b/NotificationWindow/Properties/AssemblyInfo.cs similarity index 100% rename from Tulpep.NotificationWindow/Properties/AssemblyInfo.cs rename to NotificationWindow/Properties/AssemblyInfo.cs diff --git a/Tulpep.NotificationWindow/Properties/Resources.Designer.cs b/NotificationWindow/Properties/Resources.Designer.cs similarity index 100% rename from Tulpep.NotificationWindow/Properties/Resources.Designer.cs rename to NotificationWindow/Properties/Resources.Designer.cs diff --git a/Tulpep.NotificationWindow/Properties/Resources.resx b/NotificationWindow/Properties/Resources.resx similarity index 100% rename from Tulpep.NotificationWindow/Properties/Resources.resx rename to NotificationWindow/Properties/Resources.resx diff --git a/Nuget/Build.ps1 b/Nuget/Build.ps1 deleted file mode 100644 index 752372c..0000000 --- a/Nuget/Build.ps1 +++ /dev/null @@ -1,16 +0,0 @@ -$root = (split-path -parent $MyInvocation.MyCommand.Definition) + '\..' -Write-Output "Downloading nuget.exe from nuget.org" -Invoke-WebRequest "https://nuget.org/nuget.exe" -OutFile $root\Nuget.exe - - -$version = [System.Reflection.Assembly]::LoadFile("$root\Tulpep.NotificationWindow\bin\Release\Tulpep.NotificationWindow.dll").GetName().Version -$versionStr = "{0}.{1}.{2}" -f ($version.Major, $version.Minor, $version.Build) -Write-Host "Setting .nuspec version tag to $versionStr" -$content = (Get-Content $root\NuGet\specs.nuspec) -$content = $content -replace '\$version\$',$versionStr - -$content | Out-File $root\nuget\specs.nuspec - - -Write-Output "Creating Nuget Package" -& $root\Nuget.exe pack $root\Nuget\specs.nuspec diff --git a/Nuget/specs.nuspec b/Nuget/specs.nuspec deleted file mode 100644 index 418de15..0000000 --- a/Nuget/specs.nuspec +++ /dev/null @@ -1,18 +0,0 @@ - - - - Tulpep.NotificationWindow - $version$ - Notification Popup Window - Simon Baer; Tulpep - https://raw.githubusercontent.com/Tulpep/Notification-Popup-Window/master/LICENSE - https://github.com/Tulpep/Notification-Popup-Window - false - Notification Popup Window - Notification Popup Window - WinForms Windows Forms NotificationWindow Notification Notifications Popup Popups - - - - - diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 79fff14..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,40 +0,0 @@ -# http://www.appveyor.com/docs/appveyor-yml - -# version format -version: 1.1.{build} - -# Fix line endings in Windows. (runs before repo cloning) -init: - - git config --global core.autocrlf input - -# Build worker image (VM template) -image: Visual Studio 2015 - -# Assembly Info -assembly_info: - patch: true - file: AssemblyInfo.* - assembly_version: "{version}" - assembly_file_version: "{version}" - assembly_informational_version: "{version}" - -#Build Relase instead of Debug -configuration: Release - -artifacts: - - path: Tulpep.NotificationWindow\bin\Release\Tulpep.NotificationWindow.dll - name: Tulpep.NotificationWindow.dll - - path: '**\Tulpep.NotificationWindow*.nupkg' - name: Tulpep.NotificationWindow.nupkg - -after_test: - - ps: .\Nuget\build.ps1 - -#Publish NuGet -deploy: - provider: NuGet - api_key: - secure: +Xu610YAOninQxlJRcuTB8nSoP9rh5Ftbm8RyJ9PELNLVj2Z737hV26cS1Xi1J8v - artifact: /.*\.nupkg/ - on: - branch: master