4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 // Copyright (c) 2006 Jonathan Pobst
26 // Jonathan Pobst (monkey@jpobst.com)
32 using System.ComponentModel;
34 namespace System.Windows.Forms
36 public abstract class ToolStripItem : Component, IDropTarget, IComponent, IDisposable
38 #region Private Variables
39 private ToolStripItemAlignment alignment;
40 private bool auto_size;
41 private bool auto_tool_tip;
42 private bool available;
43 private Color back_color;
44 private Rectangle bounds;
45 private bool can_select;
46 private ToolStripItemDisplayStyle display_style;
47 private DockStyle dock;
48 private bool double_click_enabled;
51 private Color fore_color;
53 private ContentAlignment image_align;
54 private int image_index;
55 private ToolStripItemImageScaling image_scaling;
56 private bool is_pressed;
57 private bool is_selected;
58 private Padding margin;
60 private ToolStrip owner;
61 private ToolStripItem owner_item;
62 private Padding padding;
65 private ContentAlignment text_align;
66 private TextImageRelation text_image_relation;
67 private string tool_tip_text;
70 private ToolStrip parent;
71 internal Size text_size;
74 #region Public Constructors
75 protected ToolStripItem ()
76 : this (String.Empty, null, null, String.Empty)
80 protected ToolStripItem (string text, Image image, EventHandler onClick)
81 : this (text, image, onClick, String.Empty)
85 protected ToolStripItem (string text, Image image, EventHandler onClick, string name)
87 this.alignment = ToolStripItemAlignment.Left;
88 this.auto_size = true;
89 this.auto_tool_tip = this.DefaultAutoToolTip;
90 this.available = true;
91 this.back_color = Control.DefaultBackColor;
92 this.display_style = this.DefaultDisplayStyle;
93 this.dock = DockStyle.None;
95 this.font = new Font ("Tahoma", 8.25f);
96 this.fore_color = Control.DefaultForeColor;
98 this.image_align = ContentAlignment.MiddleCenter;
99 this.image_index = -1;
100 this.image_scaling = ToolStripItemImageScaling.SizeToFit;
101 this.margin = this.DefaultMargin;
103 this.padding = this.DefaultPadding;
104 this.bounds.Size = this.DefaultSize;
106 this.text_align = ContentAlignment.MiddleCenter;
107 this.text_image_relation = TextImageRelation.ImageBeforeText;
110 this.Click = onClick;
114 #region Public Properties
116 public ToolStripItemAlignment Alignment {
117 get { return this.alignment; }
119 if (!Enum.IsDefined (typeof (ToolStripItemAlignment), value))
120 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripItemAlignment", value));
122 this.alignment = value;
127 public bool AutoSize {
128 get { return this.auto_size; }
130 this.auto_size = value;
131 this.CalculateAutoSize ();
135 [MonoTODO ("Need 2.0 ToolTip to implement tool tips.")]
136 public bool AutoToolTip {
137 get { return this.auto_tool_tip; }
138 set { this.auto_tool_tip = value; }
141 public bool Available {
142 get { return this.visible; }
144 if (this.visible != value) {
147 if (this.owner != null)
148 owner.PerformLayout ();
150 OnAvailableChanged (EventArgs.Empty);
155 public Color BackColor {
156 get { return this.back_color; }
158 if (this.back_color != value) {
160 OnBackColorChanged (EventArgs.Empty);
166 public virtual Rectangle Bounds {
167 get { return this.bounds; }
170 public virtual bool CanSelect {
171 get { return this.can_select; }
174 public Rectangle ContentRectangle {
176 // ToolStripLabels don't have a border
177 if (this is ToolStripLabel)
178 return new Rectangle (0, 0, this.bounds.Width, this.bounds.Height);
180 return new Rectangle (2, 2, this.bounds.Width - 4, this.bounds.Height - 4);
184 public virtual ToolStripItemDisplayStyle DisplayStyle {
185 get { return this.display_style; }
187 if (this.display_style != value) {
188 this.display_style = value;
189 this.CalculateAutoSize ();
190 OnDisplayStyleChanged (EventArgs.Empty);
196 public DockStyle Dock {
197 get { return this.dock; }
199 if (this.dock != value) {
200 if (!Enum.IsDefined (typeof (DockStyle), value))
201 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for DockStyle", value));
204 this.CalculateAutoSize ();
209 public bool DoubleClickEnabled {
210 get { return this.double_click_enabled; }
211 set { this.double_click_enabled = value; }
215 public virtual bool Enabled {
216 get { return enabled; }
218 if (this.enabled != value) {
219 this.enabled = value;
220 OnEnabledChanged (EventArgs.Empty);
227 public virtual Font Font
229 get { return this.font; }
231 if (this.font != value) {
233 this.CalculateAutoSize ();
234 this.OnFontChanged (EventArgs.Empty);
240 public virtual Color ForeColor {
241 get { return this.fore_color; }
243 if (this.fore_color != value) {
244 this.fore_color = value;
245 this.OnForeColorChanged (EventArgs.Empty);
252 get { return this.bounds.Height; }
254 this.bounds.Height = value;
255 this.CalculateAutoSize ();
261 public virtual Image Image {
262 get { return this.image; }
265 this.CalculateAutoSize ();
271 public ContentAlignment ImageAlign {
272 get { return this.image_align; }
274 if (!Enum.IsDefined (typeof (ContentAlignment), value))
275 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ContentAlignment", value));
277 this.image_align = value;
283 public int ImageIndex {
284 get { return this.image_index; }
287 throw new ArgumentException ("ImageIndex cannot be less than -1");
289 this.image_index = value;
290 this.CalculateAutoSize ();
296 public ToolStripItemImageScaling ImageScaling {
297 get { return this.image_scaling; }
299 this.image_scaling = value;
300 this.CalculateAutoSize ();
305 public bool IsOnDropDown {
307 //if (this.owner == null && this.owner is ToolStripDropDown)
314 public Padding Margin {
315 get { return this.margin; }
318 this.CalculateAutoSize ();
323 get { return this.name; }
324 set { this.name = value; }
327 public ToolStrip Owner {
328 get { return this.owner; }
330 if (this.owner != value) {
332 this.CalculateAutoSize ();
333 OnOwnerChanged (EventArgs.Empty);
338 public ToolStripItem OwnerItem {
339 get { return this.owner_item; }
341 this.owner_item = value;
342 this.CalculateAutoSize ();
346 public virtual Padding Padding {
347 get { return this.padding; }
349 this.padding = value;
350 this.CalculateAutoSize ();
355 public virtual bool Pressed { get { return this.is_pressed; } }
357 public virtual bool Selected { get { return this.is_selected; } }
359 public virtual Size Size {
360 get { return this.bounds.Size; }
362 this.bounds.Size = value;
363 this.CalculateAutoSize ();
367 [Localizable (false)]
370 get { return this.tag; }
371 set { this.tag = value; }
375 public virtual string Text
377 get { return this.text; }
379 if (this.text != value) {
381 this.CalculateAutoSize ();
382 this.OnTextChanged (EventArgs.Empty);
389 public virtual ContentAlignment TextAlign {
390 get { return this.text_align; }
392 if (!Enum.IsDefined (typeof (ContentAlignment), value))
393 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ContentAlignment", value));
394 this.text_align = value;
400 public TextImageRelation TextImageRelation {
401 get { return this.text_image_relation; }
403 this.text_image_relation = value;
404 this.CalculateAutoSize ();
410 public string ToolTipText {
411 get { return this.tool_tip_text; }
412 set { this.tool_tip_text = value; }
416 public bool Visible {
418 if (this.parent == null)
421 return this.visible && this.parent.Visible;
424 if (this.visible != value) {
425 this.visible = value;
426 this.OnVisibleChanged (EventArgs.Empty);
434 get { return this.bounds.Width; }
436 this.bounds.Width = value;
437 this.CalculateAutoSize ();
442 #region Protected Properties
443 protected virtual bool DefaultAutoToolTip { get { return false; } }
444 protected virtual ToolStripItemDisplayStyle DefaultDisplayStyle { get { return ToolStripItemDisplayStyle.ImageAndText; } }
445 protected internal virtual Padding DefaultMargin { get { return new Padding (0, 1, 0, 2); } }
446 protected virtual Padding DefaultPadding { get { return new Padding (); } }
447 protected virtual Size DefaultSize { get { return new Size (23, 23); } }
448 protected internal virtual bool DismissWhenClicked { get { return false; } }
449 protected internal ToolStrip Parent {
450 get { return this.parent; }
451 set { this.parent = value; }
453 protected internal virtual bool ShowKeyboardCues { get { return true; } }
456 #region Public Methods
457 public ToolStrip GetCurrentParent ()
462 public virtual Size GetPreferredSize (Size constrainingSize)
464 return this.CalculatePreferredSize (constrainingSize);
467 public void Invalidate ()
470 owner.Invalidate (this.bounds);
473 public void Invalidate (Rectangle r)
476 owner.Invalidate (r);
479 public void PerformClick ()
481 this.OnClick (EventArgs.Empty);
485 [EditorBrowsable (EditorBrowsableState.Never)]
486 public virtual void ResetBackColor () { this.BackColor = Control.DefaultBackColor; }
489 [EditorBrowsable (EditorBrowsableState.Never)]
490 public virtual void ResetDisplayStyle () { this.display_style = this.DefaultDisplayStyle; }
493 [EditorBrowsable (EditorBrowsableState.Never)]
494 public virtual void ResetFont () { this.font = new Font ("Tahoma", 8.25f); }
497 [EditorBrowsable (EditorBrowsableState.Never)]
498 public virtual void ResetForeColor () { this.ForeColor = Control.DefaultForeColor; }
501 [EditorBrowsable (EditorBrowsableState.Never)]
502 public virtual void ResetImage () { this.image = null; }
505 [EditorBrowsable (EditorBrowsableState.Never)]
506 public virtual void ResetMargin () { this.margin = this.DefaultMargin; }
509 [EditorBrowsable (EditorBrowsableState.Never)]
510 public virtual void ResetPadding () { this.padding = this.DefaultPadding; }
512 public void Select ()
514 if (this.CanSelect) {
515 this.is_selected = true;
520 public override string ToString ()
526 #region Protected Methods
527 protected virtual void OnAvailableChanged (EventArgs e)
529 if (AvailableChanged != null) AvailableChanged (this, e);
532 protected virtual void OnBackColorChanged (EventArgs e)
534 if (BackColorChanged != null) BackColorChanged (this, e);
537 protected virtual void OnBoundsChanged (EventArgs e)
541 protected virtual void OnClick (EventArgs e)
543 if (Click != null) Click (this, e);
546 protected virtual void OnDisplayStyleChanged (EventArgs e)
548 if (DisplayStyleChanged != null) DisplayStyleChanged (this, e);
551 protected virtual void OnDoubleClick (EventArgs e)
553 if (DoubleClick != null) DoubleClick (this, e);
555 if (!double_click_enabled)
559 protected virtual void OnEnabledChanged (EventArgs e)
561 if (EnabledChanged != null) EnabledChanged (this, e);
564 protected virtual void OnFontChanged (EventArgs e)
568 protected virtual void OnForeColorChanged (EventArgs e)
570 if (ForeColorChanged != null) ForeColorChanged (this, e);
573 protected virtual void OnLayout (LayoutEventArgs e)
577 protected virtual void OnLocationChanged (EventArgs e)
579 if (LocationChanged != null) LocationChanged (this, e);
582 protected virtual void OnMouseDown (MouseEventArgs e)
585 if (MouseDown != null) MouseDown (this, e);
586 this.is_pressed = true;
591 protected virtual void OnMouseEnter (EventArgs e)
594 if (MouseEnter != null) MouseEnter (this, e);
595 if (this.CanSelect) {
596 this.is_selected = true;
602 protected virtual void OnMouseHover (EventArgs e)
605 if (MouseHover != null) MouseHover (this, e);
608 protected virtual void OnMouseLeave (EventArgs e)
611 if (MouseLeave != null) MouseLeave (this, e);
612 if (this.CanSelect) {
613 this.is_selected = false;
614 this.is_pressed = false;
620 protected virtual void OnMouseMove (MouseEventArgs e)
623 if (MouseMove != null) MouseMove (this, e);
626 protected virtual void OnMouseUp (MouseEventArgs e)
629 if (MouseUp != null) MouseUp (this, e);
630 this.is_pressed = false;
635 protected virtual void OnOwnerChanged (EventArgs e)
637 if (OwnerChanged != null) OwnerChanged (this, e);
640 protected virtual void OnPaint (PaintEventArgs e)
642 if (Paint != null) Paint (this, e);
645 protected virtual void OnTextChanged (EventArgs e)
647 if (TextChanged != null) TextChanged (this, e);
650 protected virtual void OnVisibleChanged (EventArgs e)
652 if (VisibleChanged != null) VisibleChanged (this, e);
655 protected internal virtual void SetBounds (Rectangle bounds)
657 if (this.bounds != bounds) {
658 this.bounds = bounds;
659 OnBoundsChanged (EventArgs.Empty);
664 #region Public Events
665 public event EventHandler AvailableChanged;
666 public event EventHandler BackColorChanged;
667 public event EventHandler BoundsChanged;
668 public event EventHandler Click;
669 public event EventHandler DisplayStyleChanged;
670 public event EventHandler DoubleClick;
671 public event EventHandler EnabledChanged;
672 public event EventHandler ForeColorChanged;
673 public event EventHandler LocationChanged;
674 public event MouseEventHandler MouseDown;
675 public event EventHandler MouseEnter;
676 public event EventHandler MouseHover;
677 public event EventHandler MouseLeave;
678 public event MouseEventHandler MouseMove;
679 public event MouseEventHandler MouseUp;
680 public event EventHandler OwnerChanged;
681 public event PaintEventHandler Paint;
682 public event EventHandler TextChanged;
683 public event EventHandler VisibleChanged;
686 #region Internal Methods
687 internal Rectangle AlignInRectangle (Rectangle outer, Size inner, ContentAlignment align)
692 if (align == ContentAlignment.BottomLeft || align == ContentAlignment.MiddleLeft || align == ContentAlignment.TopLeft)
694 else if (align == ContentAlignment.BottomCenter || align == ContentAlignment.MiddleCenter || align == ContentAlignment.TopCenter)
695 x = Math.Max (outer.X + ((outer.Width - inner.Width) / 2), outer.Left);
696 else if (align == ContentAlignment.BottomRight || align == ContentAlignment.MiddleRight || align == ContentAlignment.TopRight)
697 x = outer.Right - inner.Width;
698 if (align == ContentAlignment.TopCenter || align == ContentAlignment.TopLeft || align == ContentAlignment.TopRight)
700 else if (align == ContentAlignment.MiddleCenter || align == ContentAlignment.MiddleLeft || align == ContentAlignment.MiddleRight)
701 y = outer.Y + (outer.Height - inner.Height) / 2;
702 else if (align == ContentAlignment.BottomCenter || align == ContentAlignment.BottomRight || align == ContentAlignment.BottomLeft)
703 y = outer.Bottom - inner.Height;
705 return new Rectangle (x, y, Math.Min (inner.Width, outer.Width), Math.Min (inner.Height, outer.Height));
708 internal void CalculateAutoSize ()
713 this.text_size = TextRenderer.MeasureText (this.Text, this.Font);
714 //this.text_size.Width += 6;
716 Size final_size = this.CalculatePreferredSize (Size.Empty);
718 if (final_size != this.Size) {
719 this.bounds.Size = final_size;
720 if (this.owner != null)
721 this.owner.PerformLayout ();
725 internal Size CalculatePreferredSize (Size constrainingSize)
727 Size preferred_size = this.DefaultSize;
729 switch (this.display_style) {
730 case ToolStripItemDisplayStyle.Text:
731 int width = text_size.Width + this.padding.Horizontal;
732 int height = text_size.Height + this.padding.Vertical;
733 preferred_size = new Size (width, height);
735 case ToolStripItemDisplayStyle.Image:
736 if (this.image == null)
737 preferred_size = this.DefaultSize;
739 switch (this.image_scaling) {
740 case ToolStripItemImageScaling.None:
741 preferred_size = this.image.Size;
743 case ToolStripItemImageScaling.SizeToFit:
744 if (this.owner == null)
745 preferred_size = this.image.Size;
747 preferred_size = this.owner.ImageScalingSize;
752 case ToolStripItemDisplayStyle.ImageAndText:
753 int width2 = text_size.Width + this.padding.Horizontal;
754 int height2 = text_size.Height + this.padding.Vertical;
756 if (this.image != null) {
757 switch (this.text_image_relation) {
758 case TextImageRelation.Overlay:
759 width2 = Math.Max (width2, this.image.Width);
760 height2 = Math.Max (height2, this.image.Height);
762 case TextImageRelation.ImageAboveText:
763 case TextImageRelation.TextAboveImage:
764 width2 = Math.Max (width2, this.image.Width);
765 height2 += this.image.Height;
767 case TextImageRelation.ImageBeforeText:
768 case TextImageRelation.TextBeforeImage:
769 height2 = Math.Max (height2, this.image.Height);
770 width2 += this.image.Width;
775 preferred_size = new Size (width2, height2);
779 if (!(this is ToolStripLabel)) { // Everything but labels have a border
780 preferred_size.Height += 4;
781 preferred_size.Width += 4;
784 if (preferred_size.Width < 23)
785 preferred_size.Width = 23; // There seems to be a minimum width of 23
786 return preferred_size;
789 internal void CalculateTextAndImageRectangles (out Rectangle text_rect, out Rectangle image_rect)
791 text_rect = Rectangle.Empty;
792 image_rect = Rectangle.Empty;
794 switch (this.display_style) {
795 case ToolStripItemDisplayStyle.None:
797 case ToolStripItemDisplayStyle.Text:
798 if (this.text != string.Empty)
799 text_rect = AlignInRectangle (this.ContentRectangle, this.text_size, this.text_align);
801 case ToolStripItemDisplayStyle.Image:
802 if (this.image != null)
803 image_rect = AlignInRectangle (this.ContentRectangle, this.image.Size, this.image_align);
805 case ToolStripItemDisplayStyle.ImageAndText:
806 if (this.text != string.Empty && this.image == null)
807 text_rect = AlignInRectangle (this.ContentRectangle, this.text_size, this.text_align);
808 else if (this.text == string.Empty && this.image != null)
809 image_rect = AlignInRectangle (this.ContentRectangle, this.image.Size, this.image_align);
810 else if (this.text == string.Empty && this.image == null)
814 Rectangle image_area;
816 switch (this.text_image_relation) {
817 case TextImageRelation.Overlay:
818 text_rect = AlignInRectangle (this.ContentRectangle, this.text_size, this.text_align);
819 image_rect = AlignInRectangle (this.ContentRectangle, this.image.Size, this.image_align);
821 case TextImageRelation.ImageAboveText:
822 text_area = new Rectangle (this.ContentRectangle.Left, this.ContentRectangle.Bottom - (text_size.Height - 4), this.ContentRectangle.Width, text_size.Height - 4);
823 image_area = new Rectangle (this.ContentRectangle.Left, this.ContentRectangle.Top, this.ContentRectangle.Width, this.ContentRectangle.Height - text_area.Height);
825 text_rect = AlignInRectangle (text_area, this.text_size, this.text_align);
826 image_rect = AlignInRectangle (image_area, this.image.Size, this.image_align);
828 case TextImageRelation.TextAboveImage:
829 text_area = new Rectangle (this.ContentRectangle.Left, this.ContentRectangle.Top, this.ContentRectangle.Width, text_size.Height - 4);
830 image_area = new Rectangle (this.ContentRectangle.Left, text_area.Bottom, this.ContentRectangle.Width, this.ContentRectangle.Height - text_area.Height);
832 text_rect = AlignInRectangle (text_area, this.text_size, this.text_align);
833 image_rect = AlignInRectangle (image_area, this.image.Size, this.image_align);
835 case TextImageRelation.ImageBeforeText:
836 text_area = new Rectangle (this.ContentRectangle.Right - this.text_size.Width, this.ContentRectangle.Top, this.text_size.Width, this.ContentRectangle.Height);
837 image_area = new Rectangle (this.ContentRectangle.Left, this.ContentRectangle.Top, text_area.Left - this.ContentRectangle.Left, this.ContentRectangle.Height);
839 text_rect = AlignInRectangle (text_area, this.text_size, this.text_align);
840 image_rect = AlignInRectangle (image_area, this.image.Size, this.image_align);
842 case TextImageRelation.TextBeforeImage:
843 text_area = new Rectangle (this.ContentRectangle.Left, this.ContentRectangle.Top, this.text_size.Width, this.ContentRectangle.Height);
844 image_area = new Rectangle (text_area.Right, this.ContentRectangle.Top, this.ContentRectangle.Width - text_area.Width, this.ContentRectangle.Height);
846 text_rect = AlignInRectangle (text_area, this.text_size, this.text_align);
847 image_rect = AlignInRectangle (image_area, this.image.Size, this.image_align);
855 internal void DoDoubleClick (EventArgs e)
856 { this.OnDoubleClick (e); }
858 internal void DoMouseDown (MouseEventArgs e)
859 { this.OnMouseDown (e); }
861 internal void DoMouseEnter (EventArgs e)
862 { this.OnMouseEnter (e); }
864 internal void DoMouseHover (EventArgs e)
865 { this.OnMouseHover (e); }
867 internal void DoMouseLeave (EventArgs e)
868 { this.OnMouseLeave (e); }
870 internal void DoMouseMove (MouseEventArgs e)
871 { this.OnMouseMove (e); }
873 internal void DoMouseUp (MouseEventArgs e)
874 { this.OnMouseUp (e); }
876 internal void DoPaint (PaintEventArgs e)
877 { this.OnPaint (e); }