using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Drawing.Text; using DevComponents.DotNetBar.Rendering; using DevComponents.DotNetBar.Rendering; namespace DevComponents.DotNetBar { /// /// Indicates the Balloon tip position. /// public enum eTipPosition { /// /// Tip is on the top. /// Top=0, /// /// Tip is on the left side. /// Left=1, /// /// Tip is on the right side. /// Right=2, /// /// Tip is on the bottom. /// Bottom=3 } /// /// Indicates the style of the balloon. /// public enum eBallonStyle { Balloon=0, Alert=1, Office2007Alert } /// /// Indicates type of Alert animation performed when alert is displayed. /// public enum eAlertAnimation { /// /// No animation take place when alert is displayed. /// None=0, /// /// Alert is animated from bottom to top. (Default) /// BottomToTop=1, /// /// Alert is animated from top to bottom. /// TopToBottom=2, /// /// Alert is animated from left to right. /// LeftToRight=3, /// /// Alert is animated from right to left. /// RightToLeft=4 } /// /// Delegate for custom paint event handler. /// public delegate void CustomPaintEventHandler(object sender, CustomPaintEventArgs e); /// /// Summary description for Balloon. /// [ToolboxItem(false), System.Runtime.InteropServices.ComVisible(false), Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design, Version= 2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] public class Balloon : System.Windows.Forms.Form { private System.ComponentModel.IContainer components; #region Event Definition /// /// Occurs when background is redrawn. /// public event CustomPaintEventHandler PaintBackground; /// /// Occurs when caption image is redrawn. /// public event CustomPaintEventHandler PaintCaptionImage; /// /// Occurs when caption text is redrawn. /// public event CustomPaintEventHandler PaintCaptionText; /// /// Occurs when text is redrawn. /// public event CustomPaintEventHandler PaintText; /// /// Occurs when close button is clicked. /// public event EventHandler CloseButtonClick; /// /// Occurs when TipPosition property has changed. /// public event EventHandler TipPositionChanged; #endregion private int m_TipLength=16; private int m_CornerSize=8; private int m_TipOffset=32; private eTipPosition m_TipPosition=eTipPosition.Top; private Color m_BackColor2=Color.Empty; private int m_BackColorGradientAngle=90; private eBackgroundImagePosition m_BackgroundImagePosition=eBackgroundImagePosition.Stretch; private int m_BackgroundImageAlpha=255; private Color m_BorderColor=SystemColors.InfoText; private bool m_ShowCloseButton=true; private ImageButton m_CloseButton=null; private eBallonStyle m_Style=eBallonStyle.Balloon; private Image m_CloseButtonNormal=null, m_CloseButtonHot=null, m_CloseButtonPressed=null; private Image m_CaptionImage=null; private Icon m_CaptionIcon=null; private Font m_CaptionFont=null; private string m_CaptionText=""; private StringAlignment m_CaptionAlignment=StringAlignment.Near; private Color m_CaptionColor=SystemColors.InfoText; private StringAlignment m_TextAlignment=StringAlignment.Near; private StringAlignment m_TextLineAlignment=StringAlignment.Center; // Layout rectangles private Rectangle m_CaptionImageRectangle=Rectangle.Empty; private Rectangle m_CaptionRectangle=Rectangle.Empty; private Rectangle m_TextRectangle=Rectangle.Empty; private bool m_AutoClose=true; private int m_AutoCloseTimeOut=0; private System.Windows.Forms.Timer m_Timer=null; const int IMAGETEXT_SPACING=4; const int TEXTCLOSE_SPACING=4; const int CAPTIONTEXT_VSPACING=1; const int CAPTIONALERT_VSPACING=1; private Color m_BorderColor1=Color.FromArgb(241,239,226); private Color m_BorderColor2=Color.White; private Color m_BorderColor3=Color.FromArgb(236,233,216); private Color m_BorderColor4=Color.FromArgb(172,168,153); private Color m_BorderColor5=Color.FromArgb(113,111,100); private eAlertAnimation m_AlertAnimation=eAlertAnimation.BottomToTop; private int m_AlertAnimationDuration=200; private bool m_AnimationInProgress=false; private bool m_AntiAlias = true; public Balloon() { CreateCloseButton(); // // Required for Windows Form Designer support // InitializeComponent(); if(components==null) this.components = new System.ComponentModel.Container(); m_CaptionFont=new Font(this.Font,FontStyle.Bold); this.SetStyle(ControlStyles.UserPaint,true); this.SetStyle(ControlStyles.AllPaintingInWmPaint,true); //this.SetStyle(ControlStyles.Opaque,true); this.SetStyle(ControlStyles.ResizeRedraw,true); this.SetStyle(DisplayHelp.DoubleBufferFlag,true); this.SetStyle(ControlStyles.ContainerControl,true); } /// /// Clean up any resources being used. /// protected override void Dispose( bool disposing ) { DestroyAutoCloseTimer(); if( disposing ) { if(components != null) { components.Dispose(); } } if (BarUtilities.DisposeItemImages && !this.DesignMode) { BarUtilities.DisposeImage(ref m_CaptionIcon); BarUtilities.DisposeImage(ref m_CaptionImage); BarUtilities.DisposeImage(ref m_CloseButtonHot); BarUtilities.DisposeImage(ref m_CloseButtonNormal); BarUtilities.DisposeImage(ref m_CloseButtonPressed); } base.Dispose( disposing ); } /// /// Gets or sets whether anti-alias smoothing is used while painting. Default value is false. /// [DefaultValue(true), Browsable(true), Category("Appearance"), Description("Gets or sets whether anti-aliasing is used while painting.")] public bool AntiAlias { get { return m_AntiAlias; } set { m_AntiAlias = value; this.Invalidate(); } } #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { // // Balloon // this.AccessibleRole = System.Windows.Forms.AccessibleRole.HelpBalloon; this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.AutoScaleMode = AutoScaleMode.None; this.BackColor = System.Drawing.SystemColors.Info; // ColorScheme.GetColor(0xFFFFBD);// this.ClientSize = new System.Drawing.Size(192, 80); this.ControlBox = false; this.ForeColor = System.Drawing.SystemColors.InfoText; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "Balloon"; this.ShowInTaskbar = false; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; } #endregion protected override void OnClick(EventArgs e) { if(m_ShowCloseButton && m_CloseButton.Bounds.Contains(this.PointToClient(Control.MousePosition))) return; base.OnClick(e); } protected override void OnPaint(PaintEventArgs e) { SmoothingMode sm = e.Graphics.SmoothingMode; TextRenderingHint th = e.Graphics.TextRenderingHint; if (m_AntiAlias) { e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; e.Graphics.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint; } if(m_Style==eBallonStyle.Balloon) PaintBalloon(e.Graphics); else PaintAlert(e.Graphics); e.Graphics.SmoothingMode = sm; e.Graphics.TextRenderingHint = th; } private void PaintAlert(Graphics g) { Rectangle client=this.GetAlertClientRect(); if(PaintBackground!=null) PaintBackground(this,new CustomPaintEventArgs(g,client)); else { PaintBackgroundInternal(g); if (m_Style == eBallonStyle.Alert) { // Paint Caption Background Rectangle rCap = client; rCap.Height = Math.Max(m_CaptionImageRectangle.Bottom, m_CaptionRectangle.Bottom) - rCap.Top; rCap.Height += CAPTIONALERT_VSPACING; if (rCap.Width > 0 && rCap.Height > 0) { using (LinearGradientBrush gradient = BarFunctions.CreateLinearGradientBrush(rCap, this.BackColor, m_BackColor2, m_BackColorGradientAngle)) { Blend b = new Blend(4); b.Positions = new float[] { 0f, .5f, .5f, 1f }; b.Factors = new float[] { 0f, 1f, 1f, 0f }; gradient.Blend = b; g.FillRectangle(gradient, rCap); } } } } // Draw Border Rectangle r=this.DisplayRectangle; if (m_Style == eBallonStyle.Office2007Alert) { DisplayHelp.DrawRectangle(g, m_BorderColor, r); } else { r.Width--; r.Height--; using (Pen pen = new Pen(m_BorderColor1, 1)) { g.DrawLine(pen, r.X, r.Y, r.Right, r.Y); g.DrawLine(pen, r.X, r.Y, r.X, r.Bottom); g.DrawLine(pen, r.X + 4, r.Bottom - 4, r.Right - 4, r.Bottom - 4); g.DrawLine(pen, r.Right - 4, r.Y + 4, r.Right - 4, r.Bottom - 4); } using (Pen pen = new Pen(m_BorderColor2, 1)) { g.DrawLine(pen, r.X + 1, r.Y + 1, r.Right - 1, r.Y + 1); g.DrawLine(pen, r.X + 1, r.Y + 1, r.X + 1, r.Bottom - 1); g.DrawLine(pen, r.X + 3, r.Bottom - 3, r.Right - 3, r.Bottom - 3); g.DrawLine(pen, r.Right - 3, r.Y + 3, r.Right - 3, r.Bottom - 3); } using (Pen pen = new Pen(m_BorderColor3, 1)) { g.DrawLine(pen, r.X + 2, r.Y + 2, r.Right - 2, r.Y + 2); g.DrawLine(pen, r.X + 2, r.Y + 2, r.X + 2, r.Bottom - 2); g.DrawLine(pen, r.X + 2, r.Bottom - 2, r.Right - 2, r.Bottom - 2); g.DrawLine(pen, r.Right - 2, r.Y + 2, r.Right - 2, r.Bottom - 2); } using (Pen pen = new Pen(m_BorderColor4, 1)) { g.DrawLine(pen, r.X + 3, r.Y + 3, r.Right - 3, r.Y + 3); g.DrawLine(pen, r.X + 3, r.Y + 3, r.X + 3, r.Bottom - 3); g.DrawLine(pen, r.X + 1, r.Bottom - 1, r.Right - 1, r.Bottom - 1); g.DrawLine(pen, r.Right - 1, r.Y + 1, r.Right - 1, r.Bottom - 1); } using (Pen pen = new Pen(m_BorderColor5, 1)) { g.DrawLine(pen, r.X + 4, r.Y + 4, r.Right - 4, r.Y + 4); g.DrawLine(pen, r.X + 4, r.Y + 4, r.X + 4, r.Bottom - 4); g.DrawLine(pen, r.X, r.Bottom, r.Right, r.Bottom); g.DrawLine(pen, r.Right, r.Y, r.Right, r.Bottom); } } if(m_CloseButton!=null) m_CloseButton.Paint(g); if(PaintCaptionImage!=null) PaintCaptionImage(this,new CustomPaintEventArgs(g,m_CaptionImageRectangle)); else { CompositeImage image=this.ImageInternal; if(image!=null && !m_CaptionImageRectangle.IsEmpty) image.DrawImage(g,m_CaptionImageRectangle); } if(PaintCaptionText!=null) PaintCaptionText(this,new CustomPaintEventArgs(g,m_CaptionRectangle)); else { if(m_CaptionText!="" && !m_CaptionRectangle.IsEmpty) { eTextFormat format = eTextFormat.Default | eTextFormat.WordBreak; if (m_CaptionAlignment == StringAlignment.Center) format |= eTextFormat.HorizontalCenter; else if (m_CaptionAlignment == StringAlignment.Far) format |= eTextFormat.Right; Font font=m_CaptionFont; if(font==null) font=this.Font; if (_CaptionTextMarkup != null) { TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, font, m_CaptionColor, (this.RightToLeft == RightToLeft.Yes), r, true); _CaptionTextMarkup.Arrange(m_CaptionRectangle, d); _CaptionTextMarkup.Render(d); } else TextDrawing.DrawString(g, m_CaptionText, font, m_CaptionColor, m_CaptionRectangle, format); } } if(PaintText!=null) PaintText(this,new CustomPaintEventArgs(g,m_TextRectangle)); else { if(this.Text!="") { eTextFormat format = eTextFormat.Default | eTextFormat.WordBreak; if (m_TextAlignment == StringAlignment.Center) format |= eTextFormat.HorizontalCenter; else if (m_TextAlignment == StringAlignment.Far) format |= eTextFormat.Right; if (m_TextLineAlignment == StringAlignment.Center) format |= eTextFormat.VerticalCenter; else if (m_TextLineAlignment == StringAlignment.Far) format |= eTextFormat.Bottom; if (_TextMarkup != null) { TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, this.Font, this.ForeColor, (this.RightToLeft == RightToLeft.Yes), r, true); _TextMarkup.Arrange(m_TextRectangle, d); _TextMarkup.Render(d); } else TextDrawing.DrawString(g, this.Text, this.Font, this.ForeColor, m_TextRectangle, format); } } } private void PaintBalloon(Graphics g) { Rectangle r = new Rectangle(0, 0, this.Width, this.Height); //this.DisplayRectangle; GraphicsPath path=this.GetBalloonPath(r); if(PaintBackground!=null) PaintBackground(this,new CustomPaintEventArgs(g,r)); else PaintBackgroundInternal(g); using(Pen pen=new Pen(m_BorderColor,1)) { pen.Alignment=PenAlignment.Inset; g.DrawPath(pen,path); } if(m_CloseButton!=null) m_CloseButton.Paint(g); if(PaintCaptionImage!=null) PaintCaptionImage(this,new CustomPaintEventArgs(g,m_CaptionImageRectangle)); else { CompositeImage image=this.ImageInternal; if(image!=null && !m_CaptionImageRectangle.IsEmpty) image.DrawImage(g,m_CaptionImageRectangle); } if(PaintCaptionText!=null) PaintCaptionText(this,new CustomPaintEventArgs(g,m_CaptionRectangle)); else { if(m_CaptionText!="" && !m_CaptionRectangle.IsEmpty) { eTextFormat format = eTextFormat.Default | TextDrawing.TranslateHorizontal(m_CaptionAlignment) | eTextFormat.WordBreak; Font font = m_CaptionFont; if (font == null) font = this.Font; if (_CaptionTextMarkup != null) { TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, font, m_CaptionColor, (this.RightToLeft == RightToLeft.Yes), r, true); _CaptionTextMarkup.Arrange(m_CaptionRectangle, d); _CaptionTextMarkup.Render(d); } else TextDrawing.DrawString(g, m_CaptionText, font, m_CaptionColor, m_CaptionRectangle, format); } } if(PaintText!=null) PaintText(this,new CustomPaintEventArgs(g,m_TextRectangle)); else { if(this.Text!="") { eTextFormat format = eTextFormat.Default | TextDrawing.TranslateHorizontal(m_TextAlignment) | TextDrawing.TranslateVertical(m_TextLineAlignment) | eTextFormat.WordBreak; if (_TextMarkup != null) { TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, this.Font, this.ForeColor, (this.RightToLeft == RightToLeft.Yes), r, true); _TextMarkup.Arrange(m_TextRectangle, d); _TextMarkup.Render(d); } else TextDrawing.DrawString(g, this.Text, this.Font, this.ForeColor, m_TextRectangle, format); } } } protected override void OnResize(EventArgs e) { base.OnResize(e); if(!m_AnimationInProgress) this.RecalcLayout(); } private int _MinimumBalloonWidth = 180; /// /// Gets or sets the minimum balloon width when auto sizing balloon. Default value is 180. /// [DefaultValue(180), Category("Appearance"), Description("Indicates minimum balloon width when auto sizing balloon.")] public int MinimumBalloonWidth { get { return _MinimumBalloonWidth; } set { _MinimumBalloonWidth = value; } } private TextMarkup.BodyElement _TextMarkup = null; protected override void OnTextChanged(EventArgs e) { string text = this.Text; if (_TextMarkup != null) { _TextMarkup.MouseLeave(this); _TextMarkup.HyperLinkClick -= new EventHandler(TextMarkupLinkClicked); _TextMarkup = null; } if (TextMarkup.MarkupParser.IsMarkup(ref text)) _TextMarkup = TextMarkup.MarkupParser.Parse(text); if (_TextMarkup != null) { _TextMarkup.HyperLinkClick += new EventHandler(TextMarkupLinkClicked); } this.Invalidate(); base.OnTextChanged(e); } private void TextMarkupLinkClicked(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 tag.")] public event MarkupLinkClickEventHandler MarkupLinkClick; protected virtual void OnMarkupLinkClick(MarkupLinkClickEventArgs e) { if (this.MarkupLinkClick != null) MarkupLinkClick(this, e); } protected virtual Size ResizeMarkup(Graphics g, int containerWidth) { if (_TextMarkup != null) { Rectangle r= new Rectangle(0,0,containerWidth, 1); TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, this.Font, SystemColors.Control, (this.RightToLeft == RightToLeft.Yes)); _TextMarkup.Measure(r.Size, d); //_TextMarkup.Arrange(r, d); return _TextMarkup.Bounds.Size; } return Size.Empty; } protected virtual Size ResizeCaptionMarkup(Graphics g, int containerWidth) { if (_CaptionTextMarkup != null) { Rectangle r = new Rectangle(0, 0, containerWidth, 1); TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, this.Font, SystemColors.Control, (this.RightToLeft == RightToLeft.Yes)); _CaptionTextMarkup.Measure(r.Size, d); //_TextMarkup.Arrange(r, d); return _CaptionTextMarkup.Bounds.Size; } return Size.Empty; } /// /// Auto resize balloon to the content. Balloon width is calculated so image and caption text can fit in single line. /// public void AutoResize() { System.Drawing.Size newSize = new Size(Dpi.Width(_MinimumBalloonWidth), 0); Size strSize=Size.Empty; // Calculates caption text rectangle height Font font=m_CaptionFont; if(font==null) font=this.Font; Graphics g=this.CreateGraphics(); try { if (_CaptionTextMarkup != null) strSize = ResizeCaptionMarkup(g, 800); else strSize = TextDrawing.MeasureString(g,(m_CaptionText != "" ? m_CaptionText : " "), font); newSize.Width = Math.Max(newSize.Width, strSize.Width); if(m_CloseButton!=null) newSize.Width+=Dpi.Width(m_CloseButton.Size.Width); else newSize.Width+=Dpi.Width18; newSize.Width+=TEXTCLOSE_SPACING; int imageHeight=0; if(m_CaptionIcon!=null) { newSize.Width+=Dpi.Width(m_CaptionIcon.Width+IMAGETEXT_SPACING); imageHeight = Dpi.Height(m_CaptionIcon.Height); } else if(m_CaptionImage!=null) { newSize.Width+=Dpi.Width(m_CaptionImage.Width+IMAGETEXT_SPACING); imageHeight = Dpi.Height(m_CaptionImage.Height); } newSize.Height+=Math.Max(imageHeight,strSize.Height); newSize.Height+=IMAGETEXT_SPACING*2; if (_TextMarkup == null) strSize = TextDrawing.MeasureString(g, (this.Text != "" ? this.Text : " "), this.Font, newSize.Width, eTextFormat.Default | eTextFormat.WordBreak); else strSize = ResizeMarkup(g, newSize.Width); newSize.Height+=strSize.Height; newSize.Width+=m_CornerSize*2; newSize.Height+=m_CornerSize*2; if(m_Style==eBallonStyle.Balloon) { if(m_TipPosition==eTipPosition.Left || m_TipPosition==eTipPosition.Right) newSize.Width+=Dpi.Width(m_TipLength); else newSize.Height+=Dpi.Height(m_TipLength); } else newSize.Height+=(int)((float)newSize.Height*.3); } finally { g.Dispose(); } this.Size=newSize; } /// /// Recalculates layout of the balloon. /// public void RecalcLayout() { if(this.DisplayRectangle.Width==0 || this.DisplayRectangle.Height==0) return; Size closeButtonSize = Size.Empty; if (m_CloseButton != null) closeButtonSize = m_CloseButton.Size; if(m_Style==eBallonStyle.Balloon) { Rectangle client=new Rectangle(m_CornerSize/2,m_CornerSize/2,this.Width-m_CornerSize,this.Height-m_CornerSize); if(m_TipPosition==eTipPosition.Bottom) client.Height-=m_TipLength; else if(m_TipPosition==eTipPosition.Left) { client.X+=m_TipLength; client.Width-=m_TipLength; } else if(m_TipPosition==eTipPosition.Right) client.Width-=m_TipLength; else { // TOP client.Y+=m_TipLength; client.Height-=m_TipLength; } System.Drawing.Size imageSize=System.Drawing.Size.Empty; if(m_CaptionIcon!=null) imageSize=Dpi.ImageSize(m_CaptionIcon.Size); else if(m_CaptionImage!=null) imageSize=Dpi.ImageSize(m_CaptionImage.Size); m_CaptionRectangle=client; if(!imageSize.IsEmpty) { m_CaptionRectangle.X+=(imageSize.Width+IMAGETEXT_SPACING); m_CaptionRectangle.Width-=(imageSize.Width+IMAGETEXT_SPACING); } // Calculates position of the close button if visible if(m_CloseButton!=null) { m_CloseButton.Location = new Point(client.Right - closeButtonSize.Width, client.Top); m_CaptionRectangle.Width-=(closeButtonSize.Width+TEXTCLOSE_SPACING); } // Calculates caption text rectangle height Font font=m_CaptionFont; if(font==null) font=this.Font; Graphics g=this.CreateGraphics(); try { eTextFormat format = eTextFormat.Default | eTextFormat.WordBreak; if (m_CaptionAlignment == StringAlignment.Center) format = eTextFormat.HorizontalCenter; else if (m_CaptionAlignment == StringAlignment.Far) format = eTextFormat.Right; Size strSize = Size.Empty; if (_CaptionTextMarkup != null) strSize = ResizeCaptionMarkup(g, m_CaptionRectangle.Width); else strSize = TextDrawing.MeasureString(g,(m_CaptionText!=""?m_CaptionText:" "),font,m_CaptionRectangle.Width,format); m_CaptionRectangle.Height=strSize.Height; } finally { g.Dispose(); } // Calculates position of the image rectangle if(!imageSize.IsEmpty) { m_CaptionImageRectangle=new Rectangle(client.X,client.Y,imageSize.Width,imageSize.Height); if(m_CaptionRectangle.Height>imageSize.Height) m_CaptionImageRectangle.Y+=(int)(m_CaptionRectangle.Height-imageSize.Height)/2; else if(imageSize.Height>m_CaptionRectangle.Height) m_CaptionRectangle.Y+=(int)(imageSize.Height-m_CaptionRectangle.Height)/2; } else if(m_CloseButton!=null && closeButtonSize.Height>m_CaptionRectangle.Height) m_CaptionRectangle.Y+=(int)(closeButtonSize.Height-m_CaptionRectangle.Height)/2; // Calculates the rectangle for balloon text if(m_CaptionRectangle.Bottom>m_CaptionImageRectangle.Bottom) m_TextRectangle=new Rectangle(client.X,m_CaptionRectangle.Bottom+CAPTIONTEXT_VSPACING,client.Width,client.Bottom-(m_CaptionRectangle.Bottom+CAPTIONTEXT_VSPACING)); else m_TextRectangle=new Rectangle(client.X,m_CaptionImageRectangle.Bottom+CAPTIONTEXT_VSPACING,client.Width,client.Bottom-(m_CaptionImageRectangle.Bottom+CAPTIONTEXT_VSPACING)); // Calculates and sets the balloon window region GraphicsPath path=this.GetBalloonPath(this.DisplayRectangle); GraphicsPath tmpPath = (GraphicsPath)path.Clone(); tmpPath.Widen(Pens.Black); Region region = new Region(tmpPath); region.Union(path); this.Region=region; path.Dispose(); tmpPath.Dispose(); } else { Rectangle client=this.GetAlertClientRect(); System.Drawing.Size imageSize=System.Drawing.Size.Empty; if(m_CaptionIcon!=null) imageSize=Dpi.ImageSize(m_CaptionIcon.Size); else if(m_CaptionImage!=null) imageSize=Dpi.ImageSize(m_CaptionImage.Size); m_CaptionRectangle=client; if(!imageSize.IsEmpty) { m_CaptionRectangle.X+=(imageSize.Width+IMAGETEXT_SPACING*2); m_CaptionRectangle.Width-=(imageSize.Width+IMAGETEXT_SPACING*2); } // Calculates position of the close button if visible if(m_CloseButton!=null) { m_CloseButton.Location=new Point(client.Right-m_CloseButton.Bounds.Width-CAPTIONALERT_VSPACING,client.Top); m_CaptionRectangle.Width-=(closeButtonSize.Width+TEXTCLOSE_SPACING+CAPTIONALERT_VSPACING); } // Calculates caption text rectangle height Font font=m_CaptionFont; if(font==null) font=this.Font; Graphics g=this.CreateGraphics(); try { eTextFormat format = eTextFormat.Default | eTextFormat.WordBreak; if (m_CaptionAlignment == StringAlignment.Center) format = eTextFormat.HorizontalCenter; else if (m_CaptionAlignment == StringAlignment.Far) format = eTextFormat.Right; Size strSize = TextDrawing.MeasureString(g, (m_CaptionText != "" ? m_CaptionText : " "), font, m_CaptionRectangle.Width, format); m_CaptionRectangle.Height=strSize.Height; } finally { g.Dispose(); } // Calculates position of the image rectangle if(!imageSize.IsEmpty) { m_CaptionImageRectangle=new Rectangle(client.X+IMAGETEXT_SPACING,client.Y,imageSize.Width,imageSize.Height); if(m_CaptionRectangle.Height>imageSize.Height) m_CaptionImageRectangle.Y+=(int)(m_CaptionRectangle.Height-imageSize.Height)/2; else if(imageSize.Height>m_CaptionRectangle.Height) { m_CaptionRectangle.Y+=(int)(imageSize.Height+-m_CaptionRectangle.Height)/2; } } else if(m_CloseButton!=null && closeButtonSize.Height>m_CaptionRectangle.Height) m_CaptionRectangle.Y+=(int)(closeButtonSize.Height-m_CaptionRectangle.Height)/2; m_CaptionRectangle.Offset(0,CAPTIONALERT_VSPACING); m_CaptionImageRectangle.Offset(0,CAPTIONALERT_VSPACING); if(m_CloseButton!=null) { m_CloseButton.Location=new Point(m_CloseButton.Location.X,m_CaptionRectangle.Y+(m_CaptionRectangle.Height-closeButtonSize.Height)/2); } // Calculates the rectangle for balloon text if(m_CaptionRectangle.Bottom>m_CaptionImageRectangle.Bottom) m_TextRectangle=new Rectangle(client.X,m_CaptionRectangle.Bottom+CAPTIONTEXT_VSPACING*4,client.Width,client.Bottom-(m_CaptionRectangle.Bottom+CAPTIONTEXT_VSPACING*4)); else m_TextRectangle=new Rectangle(client.X,m_CaptionImageRectangle.Bottom+CAPTIONTEXT_VSPACING*4,client.Width,client.Bottom-(m_CaptionImageRectangle.Bottom+CAPTIONTEXT_VSPACING*4)); this.Region=new Region(this.DisplayRectangle); } } private Rectangle GetAlertClientRect() { Rectangle r = new Rectangle(0, 0, this.Width, this.Height); // this.DisplayRectangle; r.Inflate(-4,-4); return r; } private GraphicsPath GetBalloonPath(Rectangle rect) { GraphicsPath path = new GraphicsPath(); Rectangle clipBounds=rect; Rectangle balloonBounds=clipBounds; int cornerDiameter=m_CornerSize*2; Matrix matrix=new Matrix(); Point[] anchorPoints=new Point[3]; int tipOffset=m_TipOffset; balloonBounds.Size=new Size(balloonBounds.Width-1,balloonBounds.Height-1); bool adjustOffset = false; if(m_TipPosition==eTipPosition.Bottom) { adjustOffset=true; matrix.Translate(balloonBounds.Width, balloonBounds.Height); matrix.Rotate(180); } else if (m_TipPosition == eTipPosition.Left && this.RightToLeft == RightToLeft.No || m_TipPosition == eTipPosition.Right && this.RightToLeft == RightToLeft.Yes) { adjustOffset = true; balloonBounds.Size=new Size(balloonBounds.Height, balloonBounds.Width); matrix.Translate(0, balloonBounds.Width); matrix.Rotate(-90); } else if(m_TipPosition==eTipPosition.Right && this.RightToLeft == RightToLeft.No || m_TipPosition == eTipPosition.Left && this.RightToLeft == RightToLeft.Yes) { balloonBounds.Size=new Size(balloonBounds.Height, balloonBounds.Width); matrix.Translate(balloonBounds.Height, 0); matrix.Rotate(90); } int balloonEdgeCenter =((int)(balloonBounds.Width-(m_CornerSize*2))/2)+1; int offsetFromEdge = m_CornerSize; if(adjustOffset) { tipOffset=(balloonBounds.Width-(offsetFromEdge*2)-m_TipOffset)+1; } if(tipOffsetballoonEdgeCenter) { anchorPoints[0]=new Point(tipOffset-m_TipLength+offsetFromEdge,balloonBounds.Y+m_TipLength); anchorPoints[1]=new Point(tipOffset+offsetFromEdge,balloonBounds.Y); anchorPoints[2]=new Point(tipOffset+offsetFromEdge,balloonBounds.Y+m_TipLength); } else { anchorPoints[0]=new Point(tipOffset-m_TipLength+offsetFromEdge,balloonBounds.Y+m_TipLength); anchorPoints[1]=new Point(tipOffset+offsetFromEdge,balloonBounds.Y); anchorPoints[2]=new Point(tipOffset+m_TipLength+offsetFromEdge,balloonBounds.Y+m_TipLength); } path.AddArc(balloonBounds.Left,balloonBounds.Top+m_TipLength,cornerDiameter, cornerDiameter,180, 90); path.AddLine(anchorPoints[0],anchorPoints[1]); path.AddLine(anchorPoints[1],anchorPoints[2]); path.AddArc(balloonBounds.Width-cornerDiameter,balloonBounds.Top+m_TipLength,cornerDiameter, cornerDiameter, -90, 90); path.AddArc(balloonBounds.Width-cornerDiameter,balloonBounds.Bottom-cornerDiameter,cornerDiameter, cornerDiameter, 0, 90); path.AddArc(balloonBounds.Left, balloonBounds.Bottom-cornerDiameter,cornerDiameter, cornerDiameter, 90, 90); path.CloseFigure(); path.Transform(matrix); return path; } private void PaintBackgroundInternal(Graphics g) { Rectangle r=this.ClientRectangle; if(r.Width==0 || r.Height==0) return; if(m_BackColor2.IsEmpty) { using(SolidBrush brush=new SolidBrush(this.BackColor)) g.FillRectangle(brush,r); } else { using(LinearGradientBrush gradient=BarFunctions.CreateLinearGradientBrush(r,this.BackColor,m_BackColor2,m_BackColorGradientAngle)) { if(m_Style==eBallonStyle.Alert) { Blend b=new Blend(4); b.Positions=new float[]{0f,.25f,.4f,.5f,.5f,.85f,.85f,1f}; b.Factors=new float[] {0f,1f,1f,0f,0f,0f,0f,1f}; gradient.Blend=b; } g.FillRectangle(gradient,r); } } if(this.BackgroundImage==null) return; // System.Drawing.Imaging.ImageAttributes imageAtt=null; // // if(m_BackgroundImageAlpha!=255) // { // System.Drawing.Imaging.ColorMatrix colorMatrix=new System.Drawing.Imaging.ColorMatrix(); // colorMatrix.Matrix33=255-m_BackgroundImageAlpha; // imageAtt=new System.Drawing.Imaging.ImageAttributes(); // imageAtt.SetColorMatrix(colorMatrix,System.Drawing.Imaging.ColorMatrixFlag.Default,System.Drawing.Imaging.ColorAdjustType.Bitmap); // } BarFunctions.PaintBackgroundImage(g,r,this.BackgroundImage,m_BackgroundImagePosition,m_BackgroundImageAlpha); // switch(m_BackgroundImagePosition) // { // case eBackgroundImagePosition.Stretch: // { // if(imageAtt!=null) // g.DrawImage(this.BackgroundImage,r,0,0,this.BackgroundImage.Width,this.BackgroundImage.Height,GraphicsUnit.Pixel,imageAtt); // else // g.DrawImage(this.BackgroundImage,r,0,0,this.BackgroundImage.Width,this.BackgroundImage.Height,GraphicsUnit.Pixel); // break; // } // case eBackgroundImagePosition.Center: // { // Rectangle destRect=new Rectangle(r.X,r.Y,this.BackgroundImage.Width,this.BackgroundImage.Height); // if(r.Width>this.BackgroundImage.Width) // destRect.X+=(r.Width-this.BackgroundImage.Width)/2; // if(r.Height>this.BackgroundImage.Height) // destRect.Y+=(r.Height-this.BackgroundImage.Height)/2; // if(imageAtt!=null) // g.DrawImage(this.BackgroundImage,destRect,0,0,this.BackgroundImage.Width,this.BackgroundImage.Height,GraphicsUnit.Pixel,imageAtt); // else // g.DrawImage(this.BackgroundImage,destRect,0,0,this.BackgroundImage.Width,this.BackgroundImage.Height,GraphicsUnit.Pixel); // break; // } // case eBackgroundImagePosition.TopLeft: // case eBackgroundImagePosition.TopRight: // case eBackgroundImagePosition.BottomLeft: // case eBackgroundImagePosition.BottomRight: // { // Rectangle destRect=new Rectangle(r.X,r.Y,this.BackgroundImage.Width,this.BackgroundImage.Height); // if(m_BackgroundImagePosition==eBackgroundImagePosition.TopRight) // destRect.X=r.Right-this.BackgroundImage.Width; // else if(m_BackgroundImagePosition==eBackgroundImagePosition.BottomLeft) // destRect.Y=r.Bottom-this.BackgroundImage.Height; // else if(m_BackgroundImagePosition==eBackgroundImagePosition.BottomRight) // { // destRect.Y=r.Bottom-this.BackgroundImage.Height; // destRect.X=r.Right-this.BackgroundImage.Width; // } // // if(imageAtt!=null) // g.DrawImage(this.BackgroundImage,destRect,0,0,this.BackgroundImage.Width,this.BackgroundImage.Height,GraphicsUnit.Pixel,imageAtt); // else // g.DrawImage(this.BackgroundImage,destRect,0,0,this.BackgroundImage.Width,this.BackgroundImage.Height,GraphicsUnit.Pixel); // break; // } // case eBackgroundImagePosition.Tile: // { // if(imageAtt!=null) // { // if(r.Width>this.BackgroundImage.Width || r.Height>this.BackgroundImage.Height) // { // int x=r.X,y=r.Y; // while(yr.Right) // destRect.Width=destRect.Width-(destRect.Right-r.Right); // if(destRect.Bottom>r.Bottom) // destRect.Height=destRect.Height-(destRect.Bottom-r.Bottom); // g.DrawImage(this.BackgroundImage,destRect,0,0,destRect.Width,destRect.Height,GraphicsUnit.Pixel,imageAtt); // x+=this.BackgroundImage.Width; // } // x=r.X; // y+=this.BackgroundImage.Height; // } // } // else // { // g.DrawImage(this.BackgroundImage,new Rectangle(0,0,this.BackgroundImage.Width,this.BackgroundImage.Height),0,0,this.BackgroundImage.Width,this.BackgroundImage.Height,GraphicsUnit.Pixel,imageAtt); // } // } // else // { // TextureBrush brush=new TextureBrush(this.BackgroundImage); //,r); // brush.WrapMode=System.Drawing.Drawing2D.WrapMode.Tile; // g.FillRectangle(brush,r); // brush.Dispose(); // } // break; // } // } } /// /// Gets or sets the target gradient background color. /// [Browsable(true),Description("Indicates the target gradient background color."),Category("Style")] public Color BackColor2 { get {return m_BackColor2;} set { m_BackColor2=value; if(this.DesignMode) this.Refresh(); } } [Browsable(false),EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeBackColor2() { return !m_BackColor2.IsEmpty; } [Browsable(false),EditorBrowsable(EditorBrowsableState.Never)] public void ResetBackColor2() { m_BackColor2=Color.Empty; } /// /// Gets or sets gradient fill angle. /// [Browsable(true),Description("Indicates gradient fill angle."),Category("Style"),DefaultValue(90)] public int BackColorGradientAngle { get {return m_BackColorGradientAngle;} set { if(value!=m_BackColorGradientAngle) { m_BackColorGradientAngle=value; if(this.DesignMode) this.Refresh(); } } } /// /// Specifies the transparency of background image. /// [Browsable(true),DevCoBrowsable(true),Category("Appearance"),DefaultValue(255),Description("Specifies the transparency of background image.")] public int BackgroundImageAlpha { get {return m_BackgroundImageAlpha;} set { if(value<0) value=0; else if(value>255) value=255; if(m_BackgroundImageAlpha!=value) { m_BackgroundImageAlpha=value; if(this.DesignMode) this.Refresh(); } } } /// /// Specifies background image position when container is larger than image. /// [Browsable(true),DevCoBrowsable(true),Category("Appearance"),DefaultValue(eBackgroundImagePosition.Stretch),Description("Specifies background image position when container is larger than image.")] public eBackgroundImagePosition BackgroundImagePosition { get {return m_BackgroundImagePosition;} set { if(m_BackgroundImagePosition!=value) { m_BackgroundImagePosition=value; if(this.DesignMode) this.Refresh(); } } } /// /// Gets or sets the border color.. /// [Browsable(true),Description("Indicates border color."),Category("Style")] public Color BorderColor { get {return m_BorderColor;} set { m_BorderColor=value; if(this.DesignMode) this.Refresh(); } } [Browsable(false),EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeBorderColor() { return m_BorderColor!=SystemColors.InfoText; } [Browsable(false),EditorBrowsable(EditorBrowsableState.Never)] public void ResetBorderColor() { m_BorderColor=SystemColors.InfoText; } /// /// Specifies balloon style. /// [Browsable(true),DevCoBrowsable(true),Category("Style"),DefaultValue(eBallonStyle.Balloon),Description("Specifies balloon style.")] public eBallonStyle Style { get {return m_Style;} set { m_Style=value; if(m_Style==eBallonStyle.Alert) { this.BackColor=Color.FromArgb(207,221,244); this.BackColor2=Color.White; this.ForeColor=Color.FromArgb(102,114,196); m_TextAlignment=StringAlignment.Center; } else if (m_Style == eBallonStyle.Office2007Alert) { Office2007ColorTable ct = GetOffice2007ColorTable(); ColorScheme cs = ct.LegacyColors; if (ct.SuperTooltip.BackgroundColors.IsEmpty) { this.BackColor = cs.PanelBackground; this.BackColor2 = cs.PanelBackground2; this.ForeColor = cs.PanelText; } else { this.BackColor = ct.SuperTooltip.BackgroundColors.Start; this.BackColor2 = ct.SuperTooltip.BackgroundColors.End; this.ForeColor = ct.SuperTooltip.TextColor; } m_BorderColor = cs.PanelBorder; m_TextAlignment = StringAlignment.Near; } else { m_TextAlignment = StringAlignment.Near; m_BorderColor = SystemColors.InfoText; } if(m_ShowCloseButton) this.CreateCloseButton(); this.RecalcLayout(); if(this.DesignMode) this.Refresh(); } } private Office2007ColorTable GetOffice2007ColorTable() { Office2007Renderer r = GlobalManager.Renderer as Office2007Renderer; if (r != null) return r.ColorTable; return new Office2007ColorTable(); } protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); if(m_CloseButton!=null) m_CloseButton.OnMouseDown(e); if(this.Focused) this.Focus(); } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if(m_CloseButton!=null) m_CloseButton.OnMouseMove(e); } protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); if(m_CloseButton!=null) m_CloseButton.OnMouseUp(e); } protected override void OnMouseLeave(EventArgs e) { base.OnMouseLeave(e); if(m_CloseButton!=null) m_CloseButton.OnMouseLeave(e); } /// /// Gets or sets whether the Close button is displayed. /// [Browsable(true),Description("Indicates whether the Close button is displayed."),Category("Behavior"),DefaultValue(true)] public bool ShowCloseButton { get {return m_ShowCloseButton;} set { if(value!=m_ShowCloseButton) { m_ShowCloseButton=value; OnShowCloseButtonChanged(); if(this.DesignMode) this.Refresh(); } } } private void OnShowCloseButtonChanged() { if(m_ShowCloseButton) { CreateCloseButton(); RecalcLayout(); } else { m_CloseButton=null; } } private void CreateCloseButton() { if (m_CloseButtonNormal != null) { m_CloseButton = new ImageButton(this, new Rectangle(0, 0, Dpi.Width(m_CloseButtonNormal.Width), Dpi.Height(m_CloseButtonNormal.Height))); if (m_CloseButton.Normal != null) { m_CloseButton.Normal.Dispose(); m_CloseButton.Normal = null; } m_CloseButton.Normal = m_CloseButtonNormal; if (m_CloseButton.Hover != null) { m_CloseButton.Hover.Dispose(); m_CloseButton.Hover = null; } m_CloseButton.Hover = m_CloseButtonHot; if (m_CloseButton.Pressed != null) { m_CloseButton.Pressed.Dispose(); m_CloseButton.Pressed = null; } m_CloseButton.Pressed = m_CloseButtonPressed; } else // Default Image Size is 18x18 { if (m_Style == eBallonStyle.Balloon) { m_CloseButton = new ImageButton(this, new Rectangle(0, 0, Dpi.Width18, Dpi.Height18)); m_CloseButton.Normal = BarFunctions.LoadBitmap("BalloonImages.BalloonNormal.png"); m_CloseButton.Hover = BarFunctions.LoadBitmap("BalloonImages.BalloonHot.png"); m_CloseButton.Pressed = BarFunctions.LoadBitmap("BalloonImages.BalloonPress.png"); } else { m_CloseButton = new ImageButton(this, new Rectangle(0, 0, Dpi.Width13, Dpi.Height13)); m_CloseButton.Normal = BarFunctions.LoadBitmap("BalloonImages.AlertNormal.png"); m_CloseButton.Hover = BarFunctions.LoadBitmap("BalloonImages.AlertHot.png"); m_CloseButton.Pressed = BarFunctions.LoadBitmap("BalloonImages.AlertPress.png"); } } m_CloseButton.Click+=new EventHandler(this.CloseButtonClickInternal); } private void CloseButtonClickInternal(object sender, EventArgs e) { if(CloseButtonClick!=null) CloseButtonClick(this,new EventArgs()); if(m_AutoClose) { this.Hide(); this.Close(); } } /// /// Gets or sets the animation type used to display Alert type balloon. /// [Browsable(true),Description("Gets or sets the animation type used to display Alert type balloon."),Category("Behavior"),DefaultValue(eAlertAnimation.BottomToTop)] public eAlertAnimation AlertAnimation { get {return m_AlertAnimation;} set {m_AlertAnimation=value;} } /// /// 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 m_AlertAnimationDuration;} set {m_AlertAnimationDuration=value;} } /// /// Gets or sets whether balloon will close automatically when user click the close button. /// [Browsable(true),Description("Indicates whether balloon will close automatically when user click the close button."),Category("Behavior"),DefaultValue(true)] public bool AutoClose { get {return m_AutoClose;} set {m_AutoClose=value;} } /// /// Gets or sets time period in seconds after balloon closes automatically. /// [Browsable(true),Description("Indicates time period in seconds after balloon closes automatically."),Category("Behavior"),DefaultValue(0)] public int AutoCloseTimeOut { get {return m_AutoCloseTimeOut;} set { m_AutoCloseTimeOut=value; OnAutoCloseTimeOutChanged(); } } protected void OnAutoCloseTimeOutChanged() { if(m_AutoCloseTimeOut>0 && !this.DesignMode) { if(m_Timer==null) m_Timer=new System.Windows.Forms.Timer(components); m_Timer.Enabled=false; m_Timer.Interval=m_AutoCloseTimeOut*1000; m_Timer.Tick+=new EventHandler(this.AutoCloseTimeOutEllapsed); if(this.Visible) { m_Timer.Enabled=true; m_Timer.Start(); } } else { DestroyAutoCloseTimer(); } } protected virtual void AutoCloseTimeOutEllapsed(object sender, EventArgs e) { if(this.IsDisposed) return; DestroyAutoCloseTimer(); this.Hide(); this.Close(); } private void DestroyAutoCloseTimer() { if(m_Timer!=null) { m_Timer.Enabled=false; m_Timer.Tick-=new EventHandler(this.AutoCloseTimeOutEllapsed); components.Remove(m_Timer); m_Timer.Dispose(); m_Timer=null; } } protected override void OnVisibleChanged(EventArgs e) { base.OnVisibleChanged(e); if(this.Visible) { if(m_Timer!=null && !m_Timer.Enabled) { m_Timer.Enabled=true; m_Timer.Start(); } } else { if(m_Timer!=null && m_Timer.Enabled) { m_Timer.Stop(); m_Timer.Enabled=false; } } } /// /// Gets or sets the custom image for Close Button. /// [Browsable(true),Description("Indicates custom image for Close Button."),Category("Appearance")] public Image CloseButtonNormal { get {return m_CloseButtonNormal;} set { if(m_CloseButtonNormal!=value) { m_CloseButtonNormal=value; OnShowCloseButtonChanged(); if(this.DesignMode) this.Refresh(); } } } /// /// Gets or sets the custom image for Close Button when mouse is over the button. /// [Browsable(true),Description("Indicates custom image for Close Button when mouse is over the button."),Category("Appearance"),DefaultValue(null)] public Image CloseButtonHot { get {return m_CloseButtonHot;} set { if(m_CloseButtonHot!=value) { m_CloseButtonHot=value; OnShowCloseButtonChanged(); if(this.DesignMode) this.Refresh(); } } } /// /// Gets or sets the custom image for Close Button when button is pressed. /// [Browsable(true),Description("Indicates custom image for Close Button when button is pressed."),Category("Appearance"),DefaultValue(null)] public Image CloseButtonPressed { get {return m_CloseButtonPressed;} set { if(m_CloseButtonPressed!=value) { m_CloseButtonPressed=value; OnShowCloseButtonChanged(); if(this.DesignMode) this.Refresh(); } } } /// /// Gets or sets the Caption image. /// [Browsable(true),Description("Indicates Caption image."),Category("Appearance"),DefaultValue(null)] public Image CaptionImage { get {return m_CaptionImage;} set { if(m_CaptionImage!=value) { m_CaptionImage=value; this.RecalcLayout(); if(this.DesignMode) this.Refresh(); } } } /// /// Gets or sets the Caption icon. Icon is used to provide support for alpha-blended images in caption. /// [Browsable(true),Description("Indicates Caption icon. Icon is used to provide support for alpha-blended images in caption."),Category("Appearance"),DefaultValue(null)] public Icon CaptionIcon { get {return m_CaptionIcon;} set { if(m_CaptionIcon!=value) { m_CaptionIcon=value; this.RecalcLayout(); if(this.DesignMode) this.Refresh(); } } } private CompositeImage ImageInternal { get { if(m_CaptionIcon!=null) return new CompositeImage(m_CaptionIcon,false); else if(m_CaptionImage!=null) return new CompositeImage(m_CaptionImage,false); return null; } } /// /// Gets or sets the Caption font. /// [Browsable(true),Description("Indicates Caption font."),Category("Appearance")] public Font CaptionFont { get {return m_CaptionFont;} set { if(m_CaptionFont!=value) { m_CaptionFont=value; this.RecalcLayout(); if(this.DesignMode) this.Refresh(); } } } private TextMarkup.BodyElement _CaptionTextMarkup = null; /// /// Gets or sets text displayed in caption. /// [Browsable(true),Description("Indicates text displayed in caption."),Category("Appearance"),DefaultValue(""), Localizable(true)] public string CaptionText { get {return m_CaptionText;} set { if(m_CaptionText!=value) { m_CaptionText=value; if (_CaptionTextMarkup != null) { _CaptionTextMarkup.MouseLeave(this); _CaptionTextMarkup.HyperLinkClick -= TextMarkupLinkClicked; _CaptionTextMarkup = null; } if (TextMarkup.MarkupParser.IsMarkup(ref m_CaptionText)) _CaptionTextMarkup = TextMarkup.MarkupParser.Parse(m_CaptionText); if (_CaptionTextMarkup != null) { _CaptionTextMarkup.HyperLinkClick += TextMarkupLinkClicked; } this.RecalcLayout(); if(this.DesignMode) this.Refresh(); } } } /// /// Gets or sets color of caption text. /// [Browsable(true),Description("Indicates color of caption text"),Category("Appearance")] public Color CaptionColor { get {return m_CaptionColor;} set { if(m_CaptionColor!=value) { m_CaptionColor=value; if(this.DesignMode) this.Refresh(); } } } /// /// Gets or set position of the balloon tip. /// [Browsable(true),Description("Indicates position of the balloon tip."),Category("Appearance"),DefaultValue(eTipPosition.Top)] public eTipPosition TipPosition { get {return m_TipPosition;} set { if(m_TipPosition!=value) { m_TipPosition=value; this.RecalcLayout(); if(TipPositionChanged!=null) TipPositionChanged(this,new EventArgs()); if(this.DesignMode) this.Refresh(); } } } private void InternalTipPositionChanged(eTipPosition newValue) { if(this.Controls.Count==0 || this.Style!=eBallonStyle.Balloon) return; if(newValue==eTipPosition.Top && m_TipPosition==eTipPosition.Bottom) { foreach(Control control in this.Controls) { control.Top+=m_TipLength; } } else if(newValue==eTipPosition.Bottom && m_TipPosition==eTipPosition.Top) { foreach(Control control in this.Controls) { control.Top-=m_TipLength; } } } /// /// Gets or sets tip distance from the edge of the balloon. /// [Browsable(true),Description("Indicates tip distance from the edge of the balloon."),Category("Appearance"),DefaultValue(32)] public int TipOffset { get {return m_TipOffset;} set { if(m_TipOffset!=value) { if(valuethis.Width-m_CornerSize-m_TipLength) value=this.Width-m_CornerSize-m_TipLength; else if((m_TipPosition==eTipPosition.Left || m_TipPosition==eTipPosition.Right) && value>this.Height-m_CornerSize-m_TipLength) value=this.Height-m_CornerSize-m_TipLength; m_TipOffset=value; this.RecalcLayout(); if(this.DesignMode) this.Refresh(); } } } /// /// Returns length of the tip. /// [Browsable(false),Description("Returns tip length"),Category("Appearance")] public int TipLength { get {return m_TipLength;} } /// /// Displays balloon using control to automatically calculate balloon location. Method is usually used display balloon that is showing information for the certain control. /// /// Control used for balloon positioning. public void Show(Control referenceControl) { this.Show(referenceControl,true); } /// /// Displays balloon using control to automatically calculate balloon location. Method is usually used display balloon that is showing information for the certain control. /// /// Control used for balloon positioning. /// Indicates whether balloon receives input focus. public void Show(Control referenceControl, bool balloonFocus) { if(referenceControl==null) { this.Show(); return; } Point scrLocCtrl=Point.Empty; if(referenceControl.Parent!=null) scrLocCtrl=referenceControl.Parent.PointToScreen(referenceControl.Location); else scrLocCtrl=referenceControl.Location; this.Show(new Rectangle(scrLocCtrl,referenceControl.Size),balloonFocus); } /// /// Displays balloon using rectangle to automatically calculate balloon location. Method is usually used display balloon that is showing information for the certain screen region. /// /// Rectangle in screen coordinates used for balloon positioning. /// Indicates whether balloon receives input focus. public void Show(Rectangle referenceScreenRect, bool balloonFocus) { if(referenceScreenRect.IsEmpty) { this.Show(); return; } int tipPositionOffset=m_TipLength+m_CornerSize*3; int tipOffset=m_TipLength/2+m_CornerSize*3; Point balloonLocation=Point.Empty; ScreenInformation screen=BarFunctions.ScreenFromPoint(referenceScreenRect.Location); if(referenceScreenRect.X+referenceScreenRect.Width/2+this.Width>screen.WorkingArea.Right) { balloonLocation.X=referenceScreenRect.X+referenceScreenRect.Width/2-this.Width+tipPositionOffset; tipOffset=this.Width-tipPositionOffset; } else balloonLocation.X=referenceScreenRect.X+referenceScreenRect.Width/2-tipPositionOffset; if(referenceScreenRect.Y+referenceScreenRect.Height+this.Height>screen.WorkingArea.Bottom) { balloonLocation.Y=referenceScreenRect.Y-this.Height; InternalTipPositionChanged(eTipPosition.Bottom); this.TipPosition=eTipPosition.Bottom; } else { balloonLocation.Y=referenceScreenRect.Y+referenceScreenRect.Height; InternalTipPositionChanged(eTipPosition.Top); this.TipPosition=eTipPosition.Top; } this.TipOffset=tipOffset; this.Location=balloonLocation; this.Show(balloonFocus); } /// /// Displays balloon using item to automatically calculate balloon location. Method is usually used display balloon that is showing information for the certain item. /// /// Item used for balloon positioning. /// Indicates whether balloon receives input focus. public void Show(BaseItem item, bool balloonFocus) { if(item==null || item.ContainerControl==null) { this.Show(); return; } Point loc=((Control)item.ContainerControl).PointToScreen(item.DisplayRectangle.Location); this.Show(new Rectangle(loc,item.DisplayRectangle.Size),balloonFocus); } /// /// Display balloon. /// /// Indicates whether balloon receives input focus. public void Show(bool balloonFocus) { Rectangle rEnd=new Rectangle(this.Location,this.Size); Rectangle rStart=GetAnimationRectangle(); if(!balloonFocus) { if(this.TopMost) { this.TopMost=false; NativeFunctions.SetWindowPos(this.Handle,new IntPtr(NativeFunctions.HWND_TOP),0,0,0,0,NativeFunctions.SWP_SHOWWINDOW | NativeFunctions.SWP_NOACTIVATE | NativeFunctions.SWP_NOMOVE | NativeFunctions.SWP_NOSIZE); this.TopMost=true; } else NativeFunctions.SetWindowPos(this.Handle,new IntPtr(NativeFunctions.HWND_TOP),0,0,0,0,NativeFunctions.SWP_SHOWWINDOW | NativeFunctions.SWP_NOACTIVATE | NativeFunctions.SWP_NOMOVE | NativeFunctions.SWP_NOSIZE); } if(ShouldAnimate()) { try { m_AnimationInProgress=true; BarFunctions.AnimateControl(this,true,m_AlertAnimationDuration,rStart,rEnd); } finally { m_AnimationInProgress=false; } } else base.Show(); } /// /// Displays balloon. /// public new void Show() { this.Show(true); } /// /// Called when balloon is hidden. /// protected virtual void HideBalloon() { DestroyAutoCloseTimer(); if (ShouldAnimate()) { Rectangle rStart = new Rectangle(this.Location, this.Size); Rectangle rEnd = GetAnimationRectangle(); try { m_AnimationInProgress = true; BarFunctions.AnimateControl(this, false, m_AlertAnimationDuration, rStart, rEnd); } finally { m_AnimationInProgress = false; } } else base.Hide(); } /// /// Hides balloon. /// public new void Hide() { HideBalloon(); } private bool ShouldAnimate() { if (m_Style != eBallonStyle.Balloon && m_AlertAnimation != eAlertAnimation.None && !this.DesignMode) return true; return false; } private Rectangle GetAnimationRectangle() { Rectangle r=new Rectangle(this.Location,this.Size); if(m_AlertAnimation==eAlertAnimation.BottomToTop)// && bShowing || m_AlertAnimation==eAlertAnimation.TopToBottom && !bShowing) { r.Y=r.Bottom-1; r.Height=1; } else if(m_AlertAnimation==eAlertAnimation.TopToBottom) { r.Height=1; } else if(m_AlertAnimation==eAlertAnimation.LeftToRight) { r.Width=2; } else if(m_AlertAnimation==eAlertAnimation.RightToLeft) { r.X=r.Right-1; r.Width=1; } return r; } /// /// Gets/Sets whether Balloon is visible. /// [DevCoBrowsable(true)] public new bool Visible { get { return base.Visible;} set { if(value) this.Show(); else this.Hide(); } } const int WM_MOUSEACTIVATE = 0x21; const int MA_NOACTIVATE = 3; protected override void WndProc(ref Message m) { if(m.Msg==WM_MOUSEACTIVATE) { m.Result=new System.IntPtr(MA_NOACTIVATE); return; } base.WndProc(ref m); } private class ImageButton { private Rectangle m_Bounds=Rectangle.Empty; private Control m_Parent=null; private bool m_MouseOver=false; private bool m_MouseDown=false; public Image Normal=null; public Image Hover=null; public Image Pressed=null; public event EventHandler Click; public ImageButton(Control parent, Rectangle bounds) { m_Parent=parent; m_Bounds=bounds; } public virtual void Paint(Graphics g) { Rectangle bounds = m_Bounds; if(m_MouseDown) { if(Pressed!=null) g.DrawImage(Pressed,bounds); } else if(m_MouseOver) { if(Hover!=null) g.DrawImage(Hover,bounds); } else { if(Normal!=null) g.DrawImage(Normal,bounds); } } public virtual void OnMouseMove(MouseEventArgs e) { if(m_MouseDown) return; if(m_Bounds.Contains(e.X,e.Y)) { if(!m_MouseOver) { m_MouseOver=true; if(m_Parent!=null) m_Parent.Invalidate(m_Bounds); } } else if(m_MouseOver) { m_MouseOver=false; if(m_Parent!=null) m_Parent.Invalidate(m_Bounds); } } public virtual void OnMouseDown(MouseEventArgs e) { if(m_Bounds.Contains(e.X,e.Y) && !m_MouseDown) { m_MouseDown=true; if(m_Parent!=null) m_Parent.Invalidate(m_Bounds); } } public virtual void OnMouseUp(MouseEventArgs e) { if(m_Bounds.Contains(e.X,e.Y) && m_MouseDown) { m_MouseDown=false; if(m_Parent!=null) m_Parent.Invalidate(m_Bounds); if(Click!=null) Click(this,new EventArgs()); } else if(m_MouseOver || m_MouseDown) { m_MouseDown=false; m_MouseOver=false; if(m_Parent!=null) m_Parent.Invalidate(m_Bounds); } } public virtual void OnMouseLeave(EventArgs e) { if(m_MouseOver && !m_MouseDown) { m_MouseOver=false; if(m_Parent!=null) m_Parent.Invalidate(m_Bounds); } } public bool MouseDown { get {return m_MouseDown;} } public bool MouseOver { get {return m_MouseOver;} } public Rectangle Bounds { get {return m_Bounds;} set {m_Bounds=value;} } public Point Location { get {return m_Bounds.Location;} set {m_Bounds.Location=value;} } public System.Drawing.Size Size { get {return m_Bounds.Size;} set {m_Bounds.Size=value;} } } } public class CustomPaintEventArgs:EventArgs { private System.Drawing.Graphics m_Graphics=null; private Rectangle m_PaintRectangle=Rectangle.Empty; public CustomPaintEventArgs(Graphics g, Rectangle r) { m_Graphics=g; m_PaintRectangle=r; } public System.Drawing.Graphics Graphics { get {return m_Graphics;} } public Rectangle PaintRectangle { get {return m_PaintRectangle;} } } }