using DevComponents.DotNetBar.Rendering; using DevComponents.DotNetBar.TextMarkup; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Text; using System.Threading; using System.Windows.Forms; using System.Windows.Forms.VisualStyles; using DevComponents.DotNetBar.Metro.Helpers; namespace DevComponents.DotNetBar.Controls { public class DesktopAlertWindow : Form { #region Constructor public DesktopAlertWindow() { this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque | ControlStyles.ResizeRedraw | ControlStyles.DoubleBuffer, true); this.AccessibleRole = System.Windows.Forms.AccessibleRole.Alert; this.ClientSize = DefaultAlertSizeValue; this.AutoScaleDimensions = new SizeF(96f, 96f); this.AutoScaleMode = AutoScaleMode.Dpi; this.ControlBox = false; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; this.MaximizeBox = false; this.MinimizeBox = false; this.ShowInTaskbar = false; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.StartPosition = FormStartPosition.Manual; this.Padding = new System.Windows.Forms.Padding(8); this.Font = new Font("Segoe UI", 10.125F); } protected override void Dispose(bool disposing) { DestroyAutoCloseTimer(); base.Dispose(disposing); } #endregion #region Implementation protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; Color backColor = this.BackColor; Color foreColor = this.ForeColor; using (SolidBrush brush = new SolidBrush(backColor)) g.FillRectangle(brush, this.ClientRectangle); if (_CloseButtonVisible) { Font symFont = Symbols.GetFont(12f, eSymbolSet.Material); TextDrawing.DrawStringLegacy(g, "\uE14C", symFont, (_CloseButtonMouseOver ? ColorHelpers.GetShadeColor(foreColor) : foreColor), _CloseButtonBounds, eTextFormat.Default | eTextFormat.NoClipping); } if (!string.IsNullOrEmpty(_SymbolRealized)) { Font symFont = Symbols.GetFont(_SymbolSize, _SymbolSet); TextDrawing.DrawStringLegacy(g, _SymbolRealized, symFont, _SymbolColor.IsEmpty ? foreColor : _SymbolColor, _ImageBounds, eTextFormat.Default | eTextFormat.NoClipping | eTextFormat.VerticalCenter); } else if (_Image != null) { g.DrawImage(_Image, _ImageBounds); } Rectangle r = _TextBounds; if (r.Bottom > this.ClientRectangle.Bottom - this.Padding.Bottom) r.Height -= (r.Bottom - (this.ClientRectangle.Bottom - this.Padding.Bottom)); eTextFormat format = TextFormat; if (_TextMarkup == null) { if (this.RightToLeft == RightToLeft.Yes) format |= eTextFormat.RightToLeft; if (UseTextRenderer) { TextRenderer.DrawText(g, Text, Font, r, foreColor, backColor, TextDrawing.GetTextFormatFlags(format)); } else TextDrawing.DrawString(g, Text, this.Font, foreColor, r, format); } else { TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, this.Font, foreColor, (this.RightToLeft == RightToLeft.Yes), r, true); Size markupSize = _TextMarkup.Bounds.Size; if (!markupSize.IsEmpty && (format & eTextFormat.VerticalCenter) == eTextFormat.VerticalCenter && r.Height>markupSize.Height) { r.Y += (r.Height - markupSize.Height) / 2; r.Height = markupSize.Height; } _TextMarkup.Arrange(r, d); _TextMarkup.Render(d); } base.OnPaint(e); } private eTextFormat TextFormat { get { return eTextFormat.Default | eTextFormat.WordBreak | eTextFormat.VerticalCenter | eTextFormat.EndEllipsis; } } protected override void OnMouseEnter(EventArgs e) { if (_AutoClose && _AutoCloseTimer != null) _AutoCloseTimer.Enabled = false; base.OnMouseEnter(e); } protected override void OnMouseLeave(EventArgs e) { if (_TextMarkup != null) _TextMarkup.MouseLeave(this); if (_AutoClose && _AutoCloseTimer != null) _AutoCloseTimer.Enabled = true; base.OnMouseLeave(e); } private bool _CloseButtonMouseOver = false; protected override void OnMouseMove(MouseEventArgs e) { if (_CloseButtonVisible && _CloseButtonBounds.Contains(e.Location)) { _CloseButtonMouseOver = true; Invalidate(_CloseButtonBounds); } else if (_CloseButtonMouseOver) { _CloseButtonMouseOver = false; Invalidate(_CloseButtonBounds); } if (_TextMarkup != null) _TextMarkup.MouseMove(this, e); base.OnMouseMove(e); } protected override void OnMouseDown(MouseEventArgs e) { if (_TextMarkup != null) _TextMarkup.MouseDown(this, e); base.OnMouseDown(e); } protected override void OnMouseUp(MouseEventArgs e) { if (_TextMarkup != null) _TextMarkup.MouseUp(this, e); if (_CloseButtonMouseOver && e.Button == MouseButtons.Left) this.HideAlert(eAlertClosureSource.CloseButton); base.OnMouseUp(e); } private bool _AutoSize = true; [DefaultValue(true)] public override bool AutoSize { get { return _AutoSize; } set { _AutoSize = value; } } private Rectangle _ImageBounds = Rectangle.Empty; private Rectangle _TextBounds = Rectangle.Empty; private Rectangle _CloseButtonBounds = Rectangle.Empty; /// /// Sets alert size based on its content, it respects MinimumSize and MaximumSize property settings. /// public void PerformAutoSize() { Size size = Dpi.Size(_DefaultAlertSize); if (!this.MinimumSize.IsEmpty) size = Dpi.Size(this.MinimumSize); if (!this.IsHandleCreated) this.CreateHandle(); size = LayoutAlert(size); Size maximumSize = this.MaximumSize; if (!maximumSize.IsEmpty) { if (maximumSize.Width > 0 && size.Width > maximumSize.Width) size.Width = maximumSize.Width; if (maximumSize.Height > 0 && size.Height > maximumSize.Height) size.Height = maximumSize.Height; size = LayoutAlert(size); } this.Size = size; } private Size LayoutAlert(Size size) { Rectangle r = new Rectangle(Point.Empty, size); r.X += Dpi.Width(this.Padding.Left); r.Width -= Dpi.Width(this.Padding.Horizontal); r.Y += Dpi.Height(this.Padding.Top); r.Height -= Dpi.Height(this.Padding.Vertical); if (!string.IsNullOrEmpty(Text) || !string.IsNullOrEmpty(_SymbolRealized) || _Image != null) { using (Graphics g = BarFunctions.CreateGraphics(this)) { if (_CloseButtonVisible) { Font symFont = Symbols.GetFont(12f, eSymbolSet.Material); Size closeSize = TextDrawing.MeasureString(g, "\uE14C", symFont); // Need to do this to get consistent size for the symbol since they are not all the same width we pick widest _CloseButtonBounds = new Rectangle(r.Right - closeSize.Width - Dpi.Width4, r.Y + Dpi.Height4, closeSize.Width, closeSize.Height); r.Width -= closeSize.Width + Dpi.Width8; } _ImageBounds = Rectangle.Empty; if (!string.IsNullOrEmpty(_SymbolRealized)) { Size symSize = GetSymbolSize(g); symSize.Width += Dpi.Width2; _ImageBounds = new Rectangle(r.X, r.Y, symSize.Width, symSize.Height); r.X += symSize.Width + _ImageTextPadding; r.Width -= symSize.Width + _ImageTextPadding; if (symSize.Height > r.Height) { size.Height += (symSize.Height - r.Height); r.Height = symSize.Height; } else { _ImageBounds.Height = r.Height; } } else if (_Image != null) { _ImageBounds = new Rectangle(r.X, r.Y, _Image.Width, _Image.Height); r.X += _Image.Width + _ImageTextPadding; r.Width -= _Image.Width + _ImageTextPadding; if (_Image.Height > r.Height) { size.Height += (_Image.Height - r.Height); r.Height = _Image.Height; } } _TextBounds = Rectangle.Empty; if (_TextMarkup != null) { MarkupDrawContext dc = GetMarkupDrawContext(g); _TextMarkup.Measure(r.Size, dc); Size sz = _TextMarkup.Bounds.Size; _TextMarkup.Arrange(new Rectangle(r.Location, sz), dc); if (sz.Width > r.Width) { size.Width += (sz.Width - r.Width); r.Width = size.Width; } if (sz.Height > r.Height) { size.Height += (sz.Height - r.Height); r.Height = size.Height; } _TextBounds = r; } else if (!string.IsNullOrEmpty(this.Text)) { Size sz = (UseTextRenderer ? TextRenderer.MeasureText(g, this.Text, this.Font, r.Size, TextDrawing.GetTextFormatFlags(TextFormat)) : TextDrawing.MeasureString(g, this.Text, this.Font, size, TextFormat)); if (sz.Width > r.Width) { size.Width += (sz.Width - r.Width); r.Width = size.Width; } if (sz.Height > r.Height) { size.Height += (sz.Height - r.Height); r.Height = size.Height; } _TextBounds = r; } } } return size; } private MarkupDrawContext GetMarkupDrawContext(Graphics g) { return new MarkupDrawContext(g, this.Font, this.ForeColor, this.RightToLeft == RightToLeft.Yes); } private Size GetSymbolSize(Graphics g) { Size symbolSize = Size.Empty; if (g == null || string.IsNullOrEmpty(_Symbol)) return symbolSize; Font symFont = Symbols.GetFont(this.SymbolSize, this.SymbolSet); symbolSize = TextDrawing.MeasureString(g, "\uF00A", symFont); // Need to do this to get consistent size for the symbol since they are not all the same width we pick widest //int descent = (int)Math.Ceiling((symFont.FontFamily.GetCellDescent(symFont.Style) * // symFont.Size / symFont.FontFamily.GetEmHeight(symFont.Style))); //symbolSize.Height -= descent; return symbolSize; } //private Color[] _BackColors = null; ///// ///// Indicates the array of colors that when set are used to draw the background of the alert. ///// //[DefaultValue(null), Category("Appearance"), Description("Indicates the array of colors that when set are used to draw the background of the alert."), TypeConverter(typeof(ArrayConverter))] //public Color[] BackColors //{ // get // { // return _BackColors; // } // set // { // if (_BackColors != value) // { // _BackColors = value; // this.Invalidate(); // } // } //} //private Color[] _BorderColors = null; ///// ///// Indicates the array of colors that when set are used to draw the border of the alert. ///// //[DefaultValue(null), Category("Appearance"), Description("Indicates the array of colors that when set are used to draw the border of the alert."), TypeConverter(typeof(ArrayConverter))] //public Color[] BorderColors //{ // get // { // return _BorderColors; // } // set // { // if (_BorderColors != value) // { // _BorderColors = value; // //OnPropertyChanged(new PropertyChangedEventArgs("Colors")); // this.Invalidate(); // } // } //} private Color _SymbolColor = Color.Empty; /// /// Gets or sets the color of the Symbol. /// [Category("Appearance"), Description("Indicates color of the Symbol.")] public Color SymbolColor { get { return _SymbolColor; } set { _SymbolColor = value; this.Invalidate(); } } /// /// Gets whether property should be serialized. /// [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeSymbolColor() { return !_SymbolColor.IsEmpty; } /// /// Resets property to its default value. /// [EditorBrowsable(EditorBrowsableState.Never)] public void ResetSymbolColor() { this.SymbolColor = Color.Empty; } /// /// Gets the realized symbol string. /// [Browsable(false)] public string SymbolRealized { get { return _SymbolRealized; } } private string _Symbol = "", _SymbolRealized = ""; /// /// Indicates the symbol displayed on face of the button instead of the image. Setting the symbol overrides the image setting. /// [DefaultValue(""), Category("Appearance"), Description("Indicates the symbol displayed on face of the button instead of the image. Setting the symbol overrides the image setting.")] [Editor("DevComponents.DotNetBar.Design.SymbolTypeEditor, DevComponents.DotNetBar.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(System.Drawing.Design.UITypeEditor))] public string Symbol { get { return _Symbol; } set { if (value != _Symbol) { string oldValue = _Symbol; _Symbol = value; OnSymbolChanged(oldValue, value); } } } /// /// Called when Symbol property has changed. /// /// Old property value /// New property value protected virtual void OnSymbolChanged(string oldValue, string newValue) { if (string.IsNullOrEmpty(newValue)) _SymbolRealized = ""; else _SymbolRealized = Symbols.GetSymbol(newValue); this.Invalidate(); } private eSymbolSet _SymbolSet = eSymbolSet.Awesome; /// /// Gets or sets the symbol set used to represent the Symbol. /// [Browsable(false), DefaultValue(eSymbolSet.Awesome)] public eSymbolSet SymbolSet { get { return _SymbolSet; } set { if (_SymbolSet != value) { eSymbolSet oldValue = _SymbolSet; _SymbolSet = value; OnSymbolSetChanged(oldValue, value); } } } /// /// Called when SymbolSet property value changes. /// /// Indciates old value /// Indicates new value protected virtual void OnSymbolSetChanged(eSymbolSet oldValue, eSymbolSet newValue) { this.Invalidate(); this.Refresh(); } private float _SymbolSize = 22f; /// /// Indicates the size of the symbol in points. /// [DefaultValue(22f), Category("Appearance"), Description("Indicates the size of the symbol in points.")] public float SymbolSize { get { return _SymbolSize; } set { if (value != _SymbolSize) { float oldValue = _SymbolSize; _SymbolSize = value; OnSymbolSizeChanged(oldValue, value); } } } /// /// Called when SymbolSize property has changed. /// /// Old property value /// New property value protected virtual void OnSymbolSizeChanged(float oldValue, float newValue) { this.Invalidate(); } private Image _Image = null; /// /// Indicates image displayed on alert. /// [DefaultValue(null), Category("Appearance"), Description("Indicates image displayed on alert.")] public Image Image { get { return _Image; } set { _Image = value; this.Invalidate(); } } protected override void OnTextChanged(EventArgs e) { // Markup support MarkupTextChanged(); base.OnTextChanged(e); } //private string _TitleText = ""; ///// ///// Gets or sets the tile title text displayed by default in lower left corner. ///// //[DefaultValue(""), Category("Appearance"), Description("Indicates tile title text displayed by default in lower left corner"), Editor("DevComponents.DotNetBar.Design.TextMarkupUIEditor, DevComponents.DotNetBar.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(System.Drawing.Design.UITypeEditor))] //public string TitleText //{ // get { return _TitleText; } // set // { // if (value != _TitleText) // { // string oldValue = _TitleText; // _TitleText = value; // OnTitleTextChanged(oldValue, value); // } // } //} ///// ///// Called when TitleText property has changed. ///// ///// Old property value ///// New property value //protected virtual void OnTitleTextChanged(string oldValue, string newValue) //{ // TitleTextMarkupUpdate(); // this.Invalidate(); // //OnPropertyChanged(new PropertyChangedEventArgs("TitleText")); //} ///// ///// Gets reference to parsed markup body element if text was markup otherwise returns null. ///// //internal TextMarkup.BodyElement TitleTextMarkupBody //{ // get { return _TitleTextMarkup; } //} //private TextMarkup.BodyElement _TitleTextMarkup = null; //private void TitleTextMarkupUpdate() //{ // if (_TitleTextMarkup != null) // _TitleTextMarkup.HyperLinkClick -= TitleTextMarkupLinkClicked; // _TitleTextMarkup = null; // if (!_TextMarkupEnabled) // return; // if (!TextMarkup.MarkupParser.IsMarkup(ref _TitleText)) // return; // _TitleTextMarkup = TextMarkup.MarkupParser.Parse(_TitleText); // if (_TitleTextMarkup != null) // _TitleTextMarkup.HyperLinkClick += TitleTextMarkupLinkClicked; //} //private void TitleTextMarkupLinkClicked(object sender, EventArgs e) //{ // DevComponents.DotNetBar.TextMarkup.HyperLink link = sender as DevComponents.DotNetBar.TextMarkup.HyperLink; // if (link != null) // OnTitleTextMarkupLinkClick(new MarkupLinkClickEventArgs(link.Name, link.HRef)); // else // OnTitleTextMarkupLinkClick(e); //} ///// ///// Occurs when an hyperlink in title text markup is clicked. ///// //public event EventHandler TitleTextMarkupLinkClick; ///// ///// Raises TitleTextMarkupLinkClick event. ///// ///// Provides event arguments. //protected virtual void OnTitleTextMarkupLinkClick(EventArgs e) //{ // EventHandler handler = TitleTextMarkupLinkClick; // if (handler != null) // handler(this, e); //} //private Font _TitleTextFont = null; ///// ///// Gets or sets the title text font. ///// //[DefaultValue(null), Category("Appearance"), Description("Gets or sets the title text font.")] //public Font TitleTextFont //{ // get { return _TitleTextFont; } // set // { // if (value != _TitleTextFont) // { // Font oldValue = _TitleTextFont; // _TitleTextFont = value; // OnTitleTextFontChanged(oldValue, value); // } // } //} ///// ///// Called when TitleTextFont property has changed. ///// ///// Old property value ///// New property value //protected virtual void OnTitleTextFontChanged(Font oldValue, Font newValue) //{ // this.Invalidate(); // //OnPropertyChanged(new PropertyChangedEventArgs("TitleTextFont")); //} //private Rectangle _TitleTextBounds = Rectangle.Empty; //internal Rectangle TitleTextBounds //{ // get // { // return _TitleTextBounds; // } // set // { // _TitleTextBounds = value; // } //} //private Color _TitleTextColor = Color.Empty; ///// ///// Gets or sets the color of the title text. ///// //[Category("Columns"), Description("Indicates color of title text.")] //public Color TitleTextColor //{ // get { return _TitleTextColor; } // set // { // if (_TitleTextColor != value) // { // Color oldValue = _TitleTextColor; // _TitleTextColor = value; // OnTitleTextColorChanged(oldValue, value); // } // } //} ///// ///// Called when TitleTextColor property has changed. ///// ///// Old property value ///// New property value //protected virtual void OnTitleTextColorChanged(Color oldValue, Color newValue) //{ // this.Invalidate(); // //OnPropertyChanged(new PropertyChangedEventArgs("TitleTextColor")); //} ///// ///// Gets whether property should be serialized. ///// //[EditorBrowsable(EditorBrowsableState.Never)] //public bool ShouldSerializeTitleTextColor() //{ // return !_TitleTextColor.IsEmpty; //} ///// ///// Resets property to its default value. ///// //[EditorBrowsable(EditorBrowsableState.Never)] //public void ResetTitleTextColor() //{ // this.TitleTextColor = Color.Empty; //} //private ContentAlignment _TitleTextAlignment = ContentAlignment.BottomLeft; ///// ///// Gets or sets title text alignment. ///// //[DefaultValue(ContentAlignment.BottomLeft), Category("Appearance"), Description("Indicates title text alignment.")] //public ContentAlignment TitleTextAlignment //{ // get { return _TitleTextAlignment; } // set // { // if (value != _TitleTextAlignment) // { // ContentAlignment oldValue = _TitleTextAlignment; // _TitleTextAlignment = value; // OnTitleTextAlignmentChanged(oldValue, value); // } // } //} ///// ///// Called when TitleTextAlignment property has changed. ///// ///// Old property value ///// New property value //protected virtual void OnTitleTextAlignmentChanged(ContentAlignment oldValue, ContentAlignment newValue) //{ // //OnPropertyChanged(new PropertyChangedEventArgs("TitleTextAlignment")); // this.Invalidate(); //} protected override void OnClick(EventArgs e) { if (_TextMarkup != null && _TextMarkup.MouseOverElement is HyperLink) { _TextMarkup.Click(this); base.OnClick(e); return; } else if (_CloseButtonMouseOver) { base.OnClick(e); return; } if (_ClickAction != null) { _ClickAction.Invoke(_AlertId); this.HideAlert(eAlertClosureSource.AlertClicked); } base.OnClick(e); } private long _AlertId = 0; /// /// Indicates optional Alert Id. /// [Browsable(false), DefaultValue(0)] public long AlertId { get { return _AlertId; } set { _AlertId = value; } } private Action _ClickAction = null; /// /// Indicates the method that will be invoked if user clicks the alert. /// [Browsable(false), DefaultValue(null)] public Action ClickAction { get { return _ClickAction; } set { _ClickAction = value; } } private bool _TextMarkupEnabled = true; /// /// Gets or sets whether text-markup can be used in Text property. /// [DefaultValue(true), Category("Appearance"), Description("Indicates whether text-markup can be used in Text property.")] public bool TextMarkupEnabled { get { return _TextMarkupEnabled; } set { if (value != _TextMarkupEnabled) { bool oldValue = _TextMarkupEnabled; _TextMarkupEnabled = value; OnTextMarkupEnabledChanged(oldValue, value); } } } /// /// Called when TextMarkupEnabled property has changed. /// /// Old property value /// New property value protected virtual void OnTextMarkupEnabledChanged(bool oldValue, bool newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("TextMarkupEnabled")); this.Invalidate(); } #endregion #region Markup Implementation private TextMarkup.BodyElement _TextMarkup = null; private void MarkupTextChanged() { if (_TextMarkup != null) _TextMarkup.HyperLinkClick -= TextMarkupLinkClick; _TextMarkup = null; if (!_TextMarkupEnabled) return; string text = this.Text; if (!TextMarkup.MarkupParser.IsMarkup(ref text)) return; _TextMarkup = TextMarkup.MarkupParser.Parse(text); if (_TextMarkup != null) _TextMarkup.HyperLinkClick += TextMarkupLinkClick; } /// /// Occurs when text markup link is clicked. /// protected virtual void TextMarkupLinkClick(object sender, EventArgs e) { TextMarkup.HyperLink link = sender as TextMarkup.HyperLink; if (link != null) OnMarkupLinkClick(new MarkupLinkClickEventArgs(link.Name, link.HRef)); } /// /// Occurs when text markup link is clicked. Markup links can be created using "a" tag, for example: /// Markup link /// [Description("Occurs when text markup link is clicked. Markup links can be created using a tag.")] public event MarkupLinkClickEventHandler MarkupLinkClick; /// /// Raises MarkupLinkClick event. /// /// Provides event arguments. protected virtual void OnMarkupLinkClick(MarkupLinkClickEventArgs e) { MarkupLinkClickEventHandler handler = MarkupLinkClick; if (handler != null) handler(this, e); } /// /// Gets reference to parsed markup body element if text was markup otherwise returns null. /// internal TextMarkup.BodyElement TextMarkupBody { get { return _TextMarkup; } } internal static Size MeasureText(DesktopAlertWindow item, Graphics g, int containerWidth, Font font, eTextFormat stringFormat, bool rightToLeft) { if (item.Text == "" && item.TextMarkupBody == null) return Size.Empty; Size textSize = Size.Empty; if (item.TextMarkupBody == null) { textSize = TextDrawing.MeasureString(g, ButtonItemPainter.GetDrawText(item.Text), font, containerWidth, stringFormat); } else { Size availSize = new Size(containerWidth, 1); if (containerWidth == 0) availSize.Width = 1600; TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, font, Color.Empty, false); item.TextMarkupBody.Measure(availSize, d); availSize = item.TextMarkupBody.Bounds.Size; if (containerWidth != 0) availSize.Width = containerWidth; d.RightToLeft = rightToLeft; item.TextMarkupBody.Arrange(new Rectangle(0, 0, availSize.Width, availSize.Height), d); textSize = item.TextMarkupBody.Bounds.Size; } return textSize; } private static readonly Size DefaultAlertSizeValue = new Size(360, 64); private Size _DefaultAlertSize = DefaultAlertSizeValue; /// /// Gets or sets the default alert size. /// [Category("Appearance"), Description("Indicates default alert size.")] public Size DefaultAlertSize { get { return _DefaultAlertSize; } set { if (value != _DefaultAlertSize) { Size oldValue = _DefaultAlertSize; _DefaultAlertSize = value; OnDefaultAlertSizeChanged(oldValue, value); } } } [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeDefaultAlertSize() { return _DefaultAlertSize.Width != DefaultAlertSizeValue.Width || _DefaultAlertSize.Height != DefaultAlertSizeValue.Height; } [EditorBrowsable(EditorBrowsableState.Never)] public void ResetDefaultAlertSize() { DefaultAlertSize = DefaultAlertSizeValue; } private void OnDefaultAlertSizeChanged(Size oldValue, Size newValue) { if (_AutoSize && this.IsHandleCreated) PerformAutoSize(); } //private eAlertAnimation _AlertAnimation = eAlertAnimation.RightToLeft; ///// ///// Gets or sets the animation type used to display Alert. ///// //[Browsable(true), Description("Gets or sets the animation type used to display Alert."), Category("Behavior"), DefaultValue(eAlertAnimation.RightToLeft)] //public eAlertAnimation AlertAnimation //{ // get { return _AlertAnimation; } // set { _AlertAnimation = value; } //} private int _AlertAnimationDuration = 200; /// /// Gets or sets the total time in milliseconds alert animation takes. /// Default value is 200. /// [Browsable(true), Description("Gets or sets the total time in milliseconds alert animation takes."), Category("Behavior"), DefaultValue(200)] public int AlertAnimationDuration { get { return _AlertAnimationDuration; } set { _AlertAnimationDuration = value; } } private bool _AutoClose = true; /// /// Gets or sets whether balloon will close automatically when user click the close button. /// [Description("Indicates whether balloon will close automatically when user click the close button."), Category("Behavior"), DefaultValue(true)] public bool AutoClose { get { return _AutoClose; } set { _AutoClose = value; } } private int _AutoCloseTimeOut = 6; /// /// Gets or sets time period in seconds after alert closes automatically. /// [Description("Indicates time period in seconds after balloon closes automatically."), Category("Behavior"), DefaultValue(6)] public int AutoCloseTimeOut { get { return _AutoCloseTimeOut; } set { _AutoCloseTimeOut = value; OnAutoCloseTimeOutChanged(); } } private System.Windows.Forms.Timer _AutoCloseTimer = null; protected void OnAutoCloseTimeOutChanged() { if (_AutoCloseTimeOut > 0 && !this.DesignMode) { StartAutoCloseTimer(); } else { DestroyAutoCloseTimer(); } } private void StartAutoCloseTimer() { if (_AutoCloseTimer == null) { _AutoCloseTimer = new System.Windows.Forms.Timer(); _AutoCloseTimer.Enabled = false; _AutoCloseTimer.Tick += new EventHandler(this.AutoCloseTimeOutEllapsed); } _AutoCloseTimer.Interval = _AutoCloseTimeOut * 1000; if (this.Visible) { _AutoCloseTimer.Enabled = true; _AutoCloseTimer.Start(); } } protected virtual void AutoCloseTimeOutEllapsed(object sender, EventArgs e) { if (this.IsDisposed) return; DestroyAutoCloseTimer(); this.HideAlert(eAlertClosureSource.Timeout); this.Close(); } private void DestroyAutoCloseTimer() { if (_AutoCloseTimer != null) { _AutoCloseTimer.Enabled = false; _AutoCloseTimer.Tick -= new EventHandler(this.AutoCloseTimeOutEllapsed); _AutoCloseTimer.Dispose(); _AutoCloseTimer = null; } } protected override void OnVisibleChanged(EventArgs e) { base.OnVisibleChanged(e); if (this.Visible) { if (_AutoCloseTimeOut > 0) StartAutoCloseTimer(); if (_AutoCloseTimer != null && !_AutoCloseTimer.Enabled) { _AutoCloseTimer.Enabled = true; _AutoCloseTimer.Start(); } } else { if (_AutoCloseTimer != null && _AutoCloseTimer.Enabled) { _AutoCloseTimer.Stop(); _AutoCloseTimer.Enabled = false; } } } private Control _ReferenceControl = null; /// /// Specifies the reference control which is used to find which screen the alert is displayed on. If not specified alert is displayed on primary screen. /// [DefaultValue(null), Browsable(false)] public Control ReferenceControl { get { return _ReferenceControl; } set { _ReferenceControl = value; } } private static Semaphore _DisplayPositionsSemaphore = new Semaphore(1, 1); private static List _DisplayPositions = new List(); private Rectangle GetAlertBounds() { Rectangle r = this.Bounds; ScreenInformation si = null; if (_ReferenceControl == null) si = BarFunctions.PrimaryScreen; else si = BarFunctions.ScreenFromControl(_ReferenceControl); if (_AlertPosition == eAlertPosition.BottomRight) { r = new Rectangle(si.WorkingArea.Right - this.Width, si.WorkingArea.Bottom - this.Height - Dpi.Height12, this.Width, this.Height); } else if (_AlertPosition == eAlertPosition.BottomLeft) { r = new Rectangle(si.WorkingArea.Left, si.WorkingArea.Bottom - this.Height - Dpi.Height12, this.Width, this.Height); } else if (_AlertPosition == eAlertPosition.TopRight) { r = new Rectangle(si.WorkingArea.Right - this.Width, si.WorkingArea.Top + Dpi.Height12, this.Width, this.Height); } else if (_AlertPosition == eAlertPosition.TopLeft) { r = new Rectangle(si.WorkingArea.Left, si.WorkingArea.Top + Dpi.Height12, this.Width, this.Height); } // Now adjust display position if (_DisplayPositions.Count > 0) { if(_AlertPosition == eAlertPosition.TopLeft || _AlertPosition == eAlertPosition.TopRight) _DisplayPositions.Sort(_RectangleComparer); else _DisplayPositions.Sort(_RectangleReverseComparer); Rectangle originalBounds = r; for (int i = 0; i < _DisplayPositions.Count; i++) { if (_DisplayPositions[i].IntersectsWith(r)) { if (_AlertPosition == eAlertPosition.BottomLeft || _AlertPosition == eAlertPosition.BottomRight) r.Y -= _DisplayPositions[i].Height + _AlertsSpacing; else r.Y += _DisplayPositions[i].Height + _AlertsSpacing; } else break; if (!si.WorkingArea.Contains(r)) { r = originalBounds; break; } if (i == _DisplayPositions.Count - 1) break; } } _DisplayPositionsSemaphore.WaitOne(); try { _DisplayPositions.Add(r); } finally { _DisplayPositionsSemaphore.Release(); } return r; } private static readonly RectangleComparer _RectangleComparer = new RectangleComparer(); private static readonly RectangleReverseComparer _RectangleReverseComparer = new RectangleReverseComparer(); private class RectangleComparer : IComparer { public int Compare(Rectangle x, Rectangle y) { return x.Y - y.Y; } } private class RectangleReverseComparer : IComparer { public int Compare(Rectangle x, Rectangle y) { return y.Y - x.Y; } } protected override void OnClosed(EventArgs e) { _DisplayPositionsSemaphore.WaitOne(); try { for (int i = _DisplayPositions.Count - 1; i >= 0; i--) { if (_DisplayPositions[i] == this.Bounds) { _DisplayPositions.RemoveAt(i); break; } } } finally { _DisplayPositionsSemaphore.Release(); } base.OnClosed(e); } /// /// Display balloon. /// /// Indicates whether alert receives input focus upon showing. public void Show(bool focusAlert) { PerformAutoSize(); this.Bounds = GetAlertBounds(); Rectangle rEnd = this.Bounds; DesktopAlert.OnBeforeAlertDisplayed(this, EventArgs.Empty); if(this.IsDisposed) return; if (ShouldAnimate()) { try { _AnimationInProgress = true; eAlertAnimation alertAnimation = GetAlertAnimation(); if (alertAnimation == eAlertAnimation.RightToLeft) NativeFunctions.AnimateWindow(this.Handle, _AlertAnimationDuration, (NativeFunctions.AW_SLIDE | NativeFunctions.AW_HOR_NEGATIVE)); else if (alertAnimation == eAlertAnimation.LeftToRight) NativeFunctions.AnimateWindow(this.Handle, _AlertAnimationDuration, (NativeFunctions.AW_SLIDE | NativeFunctions.AW_HOR_POSITIVE)); else if (alertAnimation == eAlertAnimation.BottomToTop) NativeFunctions.AnimateWindow(this.Handle, _AlertAnimationDuration, (NativeFunctions.AW_SLIDE | NativeFunctions.AW_VER_NEGATIVE)); else if (alertAnimation == eAlertAnimation.TopToBottom) NativeFunctions.AnimateWindow(this.Handle, _AlertAnimationDuration, (NativeFunctions.AW_SLIDE | NativeFunctions.AW_VER_POSITIVE)); } finally { _AnimationInProgress = false; } } base.Show(); if (_TopMost) NativeFunctions.SetWindowPos(this.Handle, new IntPtr(NativeFunctions.HWND_TOPMOST), 0, 0, 0, 0, NativeFunctions.SWP_NOACTIVATE | NativeFunctions.SWP_NOMOVE | NativeFunctions.SWP_NOSIZE); //this.Visible = true; if (_PlaySound) System.Media.SystemSounds.Beep.Play(); } protected override bool ShowWithoutActivation { get { return true; } } private eAlertAnimation GetAlertAnimation() { if (_AlertPosition == eAlertPosition.TopLeft || _AlertPosition == eAlertPosition.BottomLeft) return eAlertAnimation.LeftToRight; else return eAlertAnimation.RightToLeft; } /// /// Displays balloon. /// public new void Show() { this.Show(false); } private bool _AnimationInProgress = false; /// /// Called when alert needs to be hidden. /// protected virtual void HideAlert(eAlertClosureSource source) { DestroyAutoCloseTimer(); if (ShouldAnimate()) { Rectangle rStart = this.Bounds; //Rectangle rEnd = GetAnimationRectangle(); try { _AnimationInProgress = true; eAlertAnimation alertAnimation = GetAlertAnimation(); if (alertAnimation == eAlertAnimation.RightToLeft) NativeFunctions.AnimateWindow(this.Handle, _AlertAnimationDuration, (NativeFunctions.AW_SLIDE | NativeFunctions.AW_HOR_POSITIVE | NativeFunctions.AW_HIDE)); else if (alertAnimation == eAlertAnimation.LeftToRight) NativeFunctions.AnimateWindow(this.Handle, _AlertAnimationDuration, (NativeFunctions.AW_SLIDE | NativeFunctions.AW_HOR_NEGATIVE | NativeFunctions.AW_HIDE)); else if (alertAnimation == eAlertAnimation.BottomToTop) NativeFunctions.AnimateWindow(this.Handle, _AlertAnimationDuration, (NativeFunctions.AW_SLIDE | NativeFunctions.AW_VER_POSITIVE | NativeFunctions.AW_HIDE)); else if (alertAnimation == eAlertAnimation.TopToBottom) NativeFunctions.AnimateWindow(this.Handle, _AlertAnimationDuration, (NativeFunctions.AW_SLIDE | NativeFunctions.AW_VER_NEGATIVE | NativeFunctions.AW_HIDE)); } finally { _AnimationInProgress = false; } } else base.Hide(); this.Close(); DesktopAlert.OnAlertClosed(this, new AlertClosedEventArgs(source)); _ClickAction = null; this.Dispose(); } /// /// Hides balloon. /// public new void Hide() { HideAlert(eAlertClosureSource.Timeout); } private bool ShouldAnimate() { if (_AlertAnimationDuration > 0 && !this.DesignMode && !this.IsDisposed) return true; return false; } private int _AlertsSpacing = 8; /// /// Indicates spacing between alerts on the screen /// [DefaultValue(8), Category("Behavior"), Description("Indicates spacing between alerts on the screen")] public int AlertsSpacing { get { return _AlertsSpacing; } set { if (_AlertsSpacing != value) { int oldValue = _AlertsSpacing; _AlertsSpacing = value; OnAlertsSpacingChanged(value, oldValue); } } } protected virtual void OnAlertsSpacingChanged(int newValue, int oldValue) { throw new NotImplementedException(); } //private Rectangle GetAnimationRectangle() //{ // Rectangle r = new Rectangle(this.Location, this.Size); // if (_AlertAnimation == eAlertAnimation.BottomToTop) // { // r.Y = r.Bottom - 1; // r.Height = 1; // } // else if (_AlertAnimation == eAlertAnimation.TopToBottom) // { // r.Height = 1; // } // else if (_AlertAnimation == eAlertAnimation.LeftToRight) // { // r.Width = 2; // } // else if (_AlertAnimation == eAlertAnimation.RightToLeft) // { // r.X = r.Right - 1; // r.Width = 1; // } // return r; //} private eAlertPosition _AlertPosition = eAlertPosition.BottomRight; /// /// Indicates the request screen position for the alert /// [DefaultValue(eAlertPosition.BottomRight), Category("Behavior"), Description("Indicates the request screen position for the alert")] public eAlertPosition AlertPosition { get { return _AlertPosition; } set { if (_AlertPosition != value) { eAlertPosition oldValue = _AlertPosition; _AlertPosition = value; OnAlertPositionChanged(value, oldValue); } } } protected virtual void OnAlertPositionChanged(eAlertPosition newValue, eAlertPosition oldValue) { //throw new NotImplementedException(); } private bool _TopMost = true; [DefaultValue(true)] public new bool TopMost { get { return _TopMost; } set { if (_TopMost != value) { bool oldValue = _TopMost; _TopMost = value; OnTopMostChanged(value, oldValue); } } } protected virtual void OnTopMostChanged(bool newValue, bool oldValue) { if (IsHandleCreated && Visible) NativeFunctions.SetWindowPos(this.Handle, new IntPtr(newValue ? NativeFunctions.HWND_TOPMOST : NativeFunctions.HWND_NOTOPMOST), 0, 0, 0, 0, NativeFunctions.SWP_NOACTIVATE | NativeFunctions.SWP_NOMOVE | NativeFunctions.SWP_NOSIZE); } private int _ImageTextPadding = 11; /// /// Indicates spacing in pixels between image and text /// [DefaultValue(11), Category("Appearance"), Description("Indicates spacing in pixels between image and text")] public int ImageTextPadding { get { return _ImageTextPadding; } set { if (_ImageTextPadding != value) { int oldValue = _ImageTextPadding; _ImageTextPadding = value; OnImageTextPaddingChanged(value, oldValue); } } } protected virtual void OnImageTextPaddingChanged(int newValue, int oldValue) { } private bool UseTextRenderer { get { return true; /*_BackColors == null || _BackColors.Length < 2;*/ } } private bool _PlaySound = true; /// /// Indicates whether alert plays exclamation sound when shown. /// [DefaultValue(true), Category("Behavior"), Description("Indicates whether alert plays exclamation sound when shown.")] public bool PlaySound { get { return _PlaySound; } set { if (_PlaySound != value) { bool oldValue = _PlaySound; _PlaySound = value; OnPlaySoundChanged(value, oldValue); } } } protected virtual void OnPlaySoundChanged(bool newValue, bool oldValue) { //throw new NotImplementedException(); } private bool _CloseButtonVisible = true; /// /// Indicates whether close button on alert is visible /// [DefaultValue(true), Category("Appearance"), Description("Indicates whether close button on alert is visible")] public bool CloseButtonVisible { get { return _CloseButtonVisible; } set { if (_CloseButtonVisible != value) { bool oldValue = _CloseButtonVisible; _CloseButtonVisible = value; OnCloseButtonVisibleChanged(value, oldValue); } } } protected virtual void OnCloseButtonVisibleChanged(bool newValue, bool oldValue) { //throw new NotImplementedException(); } #endregion } /// /// Defines the alert positions. /// public enum eAlertPosition { /// /// Top-left screen position. /// TopLeft, /// /// Top-right screen position. /// TopRight, /// /// Bottom-right screen position. /// BottomRight, /// /// Bottom left screen position. /// BottomLeft } /// /// Defines closure sources for the alert. /// public enum eAlertClosureSource { /// /// Alert is closed becouse of timeout /// Timeout, /// /// Alert is closed becouse user clicked close button. /// CloseButton, /// /// Alert is closed becouse user clicked on the alert. /// AlertClicked } }