1479 lines
54 KiB
C#
1479 lines
54 KiB
C#
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;
|
|
/// <summary>
|
|
/// Sets alert size based on its content, it respects MinimumSize and MaximumSize property settings.
|
|
/// </summary>
|
|
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;
|
|
///// <summary>
|
|
///// Indicates the array of colors that when set are used to draw the background of the alert.
|
|
///// </summary>
|
|
//[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;
|
|
///// <summary>
|
|
///// Indicates the array of colors that when set are used to draw the border of the alert.
|
|
///// </summary>
|
|
//[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;
|
|
/// <summary>
|
|
/// Gets or sets the color of the Symbol.
|
|
/// </summary>
|
|
[Category("Appearance"), Description("Indicates color of the Symbol.")]
|
|
public Color SymbolColor
|
|
{
|
|
get { return _SymbolColor; }
|
|
set { _SymbolColor = value; this.Invalidate(); }
|
|
}
|
|
/// <summary>
|
|
/// Gets whether property should be serialized.
|
|
/// </summary>
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeSymbolColor()
|
|
{
|
|
return !_SymbolColor.IsEmpty;
|
|
}
|
|
/// <summary>
|
|
/// Resets property to its default value.
|
|
/// </summary>
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void ResetSymbolColor()
|
|
{
|
|
this.SymbolColor = Color.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the realized symbol string.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
public string SymbolRealized
|
|
{
|
|
get { return _SymbolRealized; }
|
|
}
|
|
private string _Symbol = "", _SymbolRealized = "";
|
|
/// <summary>
|
|
/// Indicates the symbol displayed on face of the button instead of the image. Setting the symbol overrides the image setting.
|
|
/// </summary>
|
|
[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);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when Symbol property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
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;
|
|
/// <summary>
|
|
/// Gets or sets the symbol set used to represent the Symbol.
|
|
/// </summary>
|
|
[Browsable(false), DefaultValue(eSymbolSet.Awesome)]
|
|
public eSymbolSet SymbolSet
|
|
{
|
|
get { return _SymbolSet; }
|
|
set
|
|
{
|
|
if (_SymbolSet != value)
|
|
{
|
|
eSymbolSet oldValue = _SymbolSet;
|
|
_SymbolSet = value;
|
|
OnSymbolSetChanged(oldValue, value);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when SymbolSet property value changes.
|
|
/// </summary>
|
|
/// <param name="oldValue">Indciates old value</param>
|
|
/// <param name="newValue">Indicates new value</param>
|
|
protected virtual void OnSymbolSetChanged(eSymbolSet oldValue, eSymbolSet newValue)
|
|
{
|
|
this.Invalidate();
|
|
this.Refresh();
|
|
}
|
|
|
|
|
|
private float _SymbolSize = 22f;
|
|
/// <summary>
|
|
/// Indicates the size of the symbol in points.
|
|
/// </summary>
|
|
[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);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when SymbolSize property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
protected virtual void OnSymbolSizeChanged(float oldValue, float newValue)
|
|
{
|
|
this.Invalidate();
|
|
}
|
|
|
|
private Image _Image = null;
|
|
/// <summary>
|
|
/// Indicates image displayed on alert.
|
|
/// </summary>
|
|
[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 = "";
|
|
///// <summary>
|
|
///// Gets or sets the tile title text displayed by default in lower left corner.
|
|
///// </summary>
|
|
//[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);
|
|
// }
|
|
// }
|
|
//}
|
|
///// <summary>
|
|
///// Called when TitleText property has changed.
|
|
///// </summary>
|
|
///// <param name="oldValue">Old property value</param>
|
|
///// <param name="newValue">New property value</param>
|
|
//protected virtual void OnTitleTextChanged(string oldValue, string newValue)
|
|
//{
|
|
// TitleTextMarkupUpdate();
|
|
// this.Invalidate();
|
|
// //OnPropertyChanged(new PropertyChangedEventArgs("TitleText"));
|
|
//}
|
|
///// <summary>
|
|
///// Gets reference to parsed markup body element if text was markup otherwise returns null.
|
|
///// </summary>
|
|
//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);
|
|
//}
|
|
///// <summary>
|
|
///// Occurs when an hyperlink in title text markup is clicked.
|
|
///// </summary>
|
|
//public event EventHandler TitleTextMarkupLinkClick;
|
|
///// <summary>
|
|
///// Raises TitleTextMarkupLinkClick event.
|
|
///// </summary>
|
|
///// <param name="e">Provides event arguments.</param>
|
|
//protected virtual void OnTitleTextMarkupLinkClick(EventArgs e)
|
|
//{
|
|
// EventHandler handler = TitleTextMarkupLinkClick;
|
|
// if (handler != null)
|
|
// handler(this, e);
|
|
//}
|
|
|
|
|
|
//private Font _TitleTextFont = null;
|
|
///// <summary>
|
|
///// Gets or sets the title text font.
|
|
///// </summary>
|
|
//[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);
|
|
// }
|
|
// }
|
|
//}
|
|
///// <summary>
|
|
///// Called when TitleTextFont property has changed.
|
|
///// </summary>
|
|
///// <param name="oldValue">Old property value</param>
|
|
///// <param name="newValue">New property value</param>
|
|
//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;
|
|
///// <summary>
|
|
///// Gets or sets the color of the title text.
|
|
///// </summary>
|
|
//[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);
|
|
// }
|
|
// }
|
|
//}
|
|
///// <summary>
|
|
///// Called when TitleTextColor property has changed.
|
|
///// </summary>
|
|
///// <param name="oldValue">Old property value</param>
|
|
///// <param name="newValue">New property value</param>
|
|
//protected virtual void OnTitleTextColorChanged(Color oldValue, Color newValue)
|
|
//{
|
|
// this.Invalidate();
|
|
// //OnPropertyChanged(new PropertyChangedEventArgs("TitleTextColor"));
|
|
//}
|
|
///// <summary>
|
|
///// Gets whether property should be serialized.
|
|
///// </summary>
|
|
//[EditorBrowsable(EditorBrowsableState.Never)]
|
|
//public bool ShouldSerializeTitleTextColor()
|
|
//{
|
|
// return !_TitleTextColor.IsEmpty;
|
|
//}
|
|
///// <summary>
|
|
///// Resets property to its default value.
|
|
///// </summary>
|
|
//[EditorBrowsable(EditorBrowsableState.Never)]
|
|
//public void ResetTitleTextColor()
|
|
//{
|
|
// this.TitleTextColor = Color.Empty;
|
|
//}
|
|
|
|
//private ContentAlignment _TitleTextAlignment = ContentAlignment.BottomLeft;
|
|
///// <summary>
|
|
///// Gets or sets title text alignment.
|
|
///// </summary>
|
|
//[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);
|
|
// }
|
|
// }
|
|
//}
|
|
///// <summary>
|
|
///// Called when TitleTextAlignment property has changed.
|
|
///// </summary>
|
|
///// <param name="oldValue">Old property value</param>
|
|
///// <param name="newValue">New property value</param>
|
|
//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;
|
|
/// <summary>
|
|
/// Indicates optional Alert Id.
|
|
/// </summary>
|
|
[Browsable(false), DefaultValue(0)]
|
|
public long AlertId {
|
|
get { return _AlertId; }
|
|
set { _AlertId = value; }
|
|
}
|
|
|
|
private Action<long> _ClickAction = null;
|
|
/// <summary>
|
|
/// Indicates the method that will be invoked if user clicks the alert.
|
|
/// </summary>
|
|
[Browsable(false), DefaultValue(null)]
|
|
public Action<long> ClickAction
|
|
{
|
|
get { return _ClickAction; }
|
|
set { _ClickAction = value; }
|
|
}
|
|
|
|
private bool _TextMarkupEnabled = true;
|
|
/// <summary>
|
|
/// Gets or sets whether text-markup can be used in Text property.
|
|
/// </summary>
|
|
[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);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when TextMarkupEnabled property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Occurs when text markup link is clicked.
|
|
/// </summary>
|
|
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));
|
|
}
|
|
/// <summary>
|
|
/// Occurs when text markup link is clicked. Markup links can be created using "a" tag, for example:
|
|
/// <a name="MyLink">Markup link</a>
|
|
/// </summary>
|
|
[Description("Occurs when text markup link is clicked. Markup links can be created using a tag.")]
|
|
public event MarkupLinkClickEventHandler MarkupLinkClick;
|
|
/// <summary>
|
|
/// Raises MarkupLinkClick event.
|
|
/// </summary>
|
|
/// <param name="e">Provides event arguments.</param>
|
|
protected virtual void OnMarkupLinkClick(MarkupLinkClickEventArgs e)
|
|
{
|
|
MarkupLinkClickEventHandler handler = MarkupLinkClick;
|
|
if (handler != null)
|
|
handler(this, e);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets reference to parsed markup body element if text was markup otherwise returns null.
|
|
/// </summary>
|
|
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;
|
|
/// <summary>
|
|
/// Gets or sets the default alert size.
|
|
/// </summary>
|
|
[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;
|
|
///// <summary>
|
|
///// Gets or sets the animation type used to display Alert.
|
|
///// </summary>
|
|
//[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;
|
|
/// <summary>
|
|
/// Gets or sets the total time in milliseconds alert animation takes.
|
|
/// Default value is 200.
|
|
/// </summary>
|
|
[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;
|
|
/// <summary>
|
|
/// Gets or sets whether balloon will close automatically when user click the close button.
|
|
/// </summary>
|
|
[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;
|
|
/// <summary>
|
|
/// Gets or sets time period in seconds after alert closes automatically.
|
|
/// </summary>
|
|
[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;
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
[DefaultValue(null), Browsable(false)]
|
|
public Control ReferenceControl
|
|
{
|
|
get { return _ReferenceControl; }
|
|
set { _ReferenceControl = value; }
|
|
}
|
|
|
|
private static Semaphore _DisplayPositionsSemaphore = new Semaphore(1, 1);
|
|
private static List<Rectangle> _DisplayPositions = new List<Rectangle>();
|
|
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<Rectangle>
|
|
{
|
|
public int Compare(Rectangle x, Rectangle y)
|
|
{
|
|
return x.Y - y.Y;
|
|
}
|
|
}
|
|
private class RectangleReverseComparer : IComparer<Rectangle>
|
|
{
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Display balloon.
|
|
/// </summary>
|
|
/// <param name="focusAlert">Indicates whether alert receives input focus upon showing.</param>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Displays balloon.
|
|
/// </summary>
|
|
public new void Show()
|
|
{
|
|
this.Show(false);
|
|
}
|
|
|
|
private bool _AnimationInProgress = false;
|
|
/// <summary>
|
|
/// Called when alert needs to be hidden.
|
|
/// </summary>
|
|
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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hides balloon.
|
|
/// </summary>
|
|
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;
|
|
/// <summary>
|
|
/// Indicates spacing between alerts on the screen
|
|
/// </summary>
|
|
[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;
|
|
/// <summary>
|
|
/// Indicates the request screen position for the alert
|
|
/// </summary>
|
|
[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;
|
|
/// <summary>
|
|
/// Indicates spacing in pixels between image and text
|
|
/// </summary>
|
|
[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;
|
|
/// <summary>
|
|
/// Indicates whether alert plays exclamation sound when shown.
|
|
/// </summary>
|
|
[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;
|
|
/// <summary>
|
|
/// Indicates whether close button on alert is visible
|
|
/// </summary>
|
|
[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
|
|
}
|
|
|
|
/// <summary>
|
|
/// Defines the alert positions.
|
|
/// </summary>
|
|
public enum eAlertPosition
|
|
{
|
|
/// <summary>
|
|
/// Top-left screen position.
|
|
/// </summary>
|
|
TopLeft,
|
|
/// <summary>
|
|
/// Top-right screen position.
|
|
/// </summary>
|
|
TopRight,
|
|
/// <summary>
|
|
/// Bottom-right screen position.
|
|
/// </summary>
|
|
BottomRight,
|
|
/// <summary>
|
|
/// Bottom left screen position.
|
|
/// </summary>
|
|
BottomLeft
|
|
}
|
|
/// <summary>
|
|
/// Defines closure sources for the alert.
|
|
/// </summary>
|
|
public enum eAlertClosureSource
|
|
{
|
|
/// <summary>
|
|
/// Alert is closed becouse of timeout
|
|
/// </summary>
|
|
Timeout,
|
|
/// <summary>
|
|
/// Alert is closed becouse user clicked close button.
|
|
/// </summary>
|
|
CloseButton,
|
|
/// <summary>
|
|
/// Alert is closed becouse user clicked on the alert.
|
|
/// </summary>
|
|
AlertClicked
|
|
}
|
|
}
|