1 // System.Windows.Forms.ToolBar.cs
3 // Permission is hereby granted, free of charge, to any person obtaining
4 // a copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to
8 // permit persons to whom the Software is furnished to do so, subject to
9 // the following conditions:
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 // Ravindra (rkumar@novell.com)
24 // Mike Kestner <mkestner@novell.com>
29 // Copyright (C) 2004-2006 Novell, Inc. (http://www.novell.com)
35 using System.Collections;
36 using System.ComponentModel;
37 using System.ComponentModel.Design;
39 using System.Drawing.Imaging;
40 using System.Runtime.InteropServices;
42 namespace System.Windows.Forms
44 [DefaultEvent ("ButtonClick")]
45 [DefaultProperty ("Buttons")]
46 [Designer ("System.Windows.Forms.Design.ToolBarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
47 public class ToolBar : Control
49 #region Instance Variables
50 bool size_specified = false;
51 ToolBarButton current_button;
52 #endregion Instance Variables
56 [EditorBrowsable (EditorBrowsableState.Never)]
57 public new event EventHandler BackColorChanged {
58 add { base.BackColorChanged += value; }
59 remove { base.BackColorChanged -= value; }
63 [EditorBrowsable (EditorBrowsableState.Never)]
64 public new event EventHandler BackgroundImageChanged {
65 add { base.BackgroundImageChanged += value; }
66 remove { base.BackgroundImageChanged -= value; }
69 public event ToolBarButtonClickEventHandler ButtonClick;
70 public event ToolBarButtonClickEventHandler ButtonDropDown;
73 [EditorBrowsable (EditorBrowsableState.Never)]
74 public new event EventHandler ForeColorChanged {
75 add { base.ForeColorChanged += value; }
76 remove { base.ForeColorChanged -= value; }
80 [EditorBrowsable (EditorBrowsableState.Never)]
81 public new event EventHandler ImeModeChanged {
82 add { base.ImeModeChanged += value; }
83 remove { base.ImeModeChanged -= value; }
87 [EditorBrowsable (EditorBrowsableState.Never)]
88 public new event PaintEventHandler Paint {
89 add { base.Paint += value; }
90 remove { base.Paint -= value; }
94 [EditorBrowsable (EditorBrowsableState.Never)]
95 public new event EventHandler RightToLeftChanged {
96 add { base.RightToLeftChanged += value; }
97 remove { base.RightToLeftChanged -= value; }
101 [EditorBrowsable (EditorBrowsableState.Never)]
102 public new event EventHandler TextChanged {
103 add { base.TextChanged += value; }
104 remove { base.TextChanged -= value; }
111 background_color = ThemeEngine.Current.DefaultControlBackColor;
112 foreground_color = ThemeEngine.Current.DefaultControlForeColor;
113 buttons = new ToolBarButtonCollection (this);
114 dock_style = DockStyle.Top;
116 GotFocus += new EventHandler (FocusChanged);
117 LostFocus += new EventHandler (FocusChanged);
118 MouseDown += new MouseEventHandler (ToolBar_MouseDown);
119 MouseLeave += new EventHandler (ToolBar_MouseLeave);
120 MouseMove += new MouseEventHandler (ToolBar_MouseMove);
121 MouseUp += new MouseEventHandler (ToolBar_MouseUp);
123 SetStyle (ControlStyles.UserPaint, false);
124 SetStyle (ControlStyles.FixedHeight, true);
126 #endregion Constructor
128 #region protected Properties
129 protected override CreateParams CreateParams
131 get { return base.CreateParams; }
134 protected override ImeMode DefaultImeMode {
135 get { return ImeMode.Disable; }
138 protected override Size DefaultSize {
139 get { return ThemeEngine.Current.ToolBarDefaultSize; }
143 ToolBarAppearance appearance = ToolBarAppearance.Normal;
145 #region Public Properties
146 [DefaultValue (ToolBarAppearance.Normal)]
148 public ToolBarAppearance Appearance {
149 get { return appearance; }
151 if (value == appearance)
159 bool autosize = true;
161 [DefaultValue (true)]
163 public bool AutoSize {
164 get { return autosize; }
166 if (value == autosize)
175 [EditorBrowsable (EditorBrowsableState.Never)]
176 public override Color BackColor {
177 get { return background_color; }
179 if (value == background_color)
182 background_color = value;
183 OnBackColorChanged (EventArgs.Empty);
189 [EditorBrowsable (EditorBrowsableState.Never)]
190 public override Image BackgroundImage {
191 get { return background_image; }
193 if (value == background_image)
196 background_image = value;
197 OnBackgroundImageChanged (EventArgs.Empty);
202 [DefaultValue (BorderStyle.None)]
203 [DispIdAttribute (-504)]
204 public BorderStyle BorderStyle {
205 get { return InternalBorderStyle; }
206 set { InternalBorderStyle = value; }
209 ToolBarButtonCollection buttons;
211 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
213 [MergableProperty (false)]
214 public ToolBarButtonCollection Buttons {
215 get { return buttons; }
221 [RefreshProperties (RefreshProperties.All)]
222 public Size ButtonSize {
224 if (button_size.IsEmpty) {
225 if (buttons.Count == 0)
226 return new Size (24, 22);
227 Size result = CalcButtonSize ();
229 return new Size (24, 22);
236 size_specified = value != Size.Empty;
237 if (button_size == value)
247 [DefaultValue (true)]
248 public bool Divider {
249 get { return divider; }
251 if (value == divider)
259 [DefaultValue (DockStyle.Top)]
261 public override DockStyle Dock {
262 get { return base.Dock; }
263 set { base.Dock = value; }
266 bool drop_down_arrows = false;
268 [DefaultValue (false)]
270 public bool DropDownArrows {
271 get { return drop_down_arrows; }
273 if (value == drop_down_arrows)
276 drop_down_arrows = value;
282 [EditorBrowsable (EditorBrowsableState.Never)]
283 public override Color ForeColor {
284 get { return foreground_color; }
286 if (value == foreground_color)
289 foreground_color = value;
290 OnForeColorChanged (EventArgs.Empty);
295 ImageList image_list;
297 [DefaultValue (null)]
298 public ImageList ImageList {
299 get { return image_list; }
301 if (image_list == value)
309 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
310 [EditorBrowsable (EditorBrowsableState.Advanced)]
311 public Size ImageSize {
313 if (ImageList == null)
316 return ImageList.ImageSize;
323 [EditorBrowsable (EditorBrowsableState.Never)]
324 public new ImeMode ImeMode {
325 get { return ime_mode; }
327 if (value == ime_mode)
331 OnImeModeChanged (EventArgs.Empty);
336 [EditorBrowsable (EditorBrowsableState.Never)]
337 public override RightToLeft RightToLeft {
338 get { return base.RightToLeft; }
340 if (value == base.RightToLeft)
343 base.RightToLeft = value;
344 OnRightToLeftChanged (EventArgs.Empty);
348 bool show_tooltips = false;
350 [DefaultValue (false)]
352 public bool ShowToolTips {
353 get { return show_tooltips; }
354 set { show_tooltips = value; }
357 [DefaultValue (false)]
358 public new bool TabStop {
359 get { return base.TabStop; }
360 set { base.TabStop = value; }
365 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
366 [EditorBrowsable (EditorBrowsableState.Never)]
367 public override string Text {
375 OnTextChanged (EventArgs.Empty);
379 ToolBarTextAlign text_alignment = ToolBarTextAlign.Underneath;
381 [DefaultValue (ToolBarTextAlign.Underneath)]
383 public ToolBarTextAlign TextAlign {
384 get { return text_alignment; }
386 if (value == text_alignment)
389 text_alignment = value;
394 bool wrappable = true;
396 [DefaultValue (true)]
398 public bool Wrappable {
399 get { return wrappable; }
401 if (value == wrappable)
408 #endregion Public Properties
410 #region Public Methods
411 public override string ToString ()
413 int count = this.Buttons.Count;
416 return string.Format ("System.Windows.Forms.ToolBar, Button.Count: 0");
418 return string.Format ("System.Windows.Forms.ToolBar, Button.Count: {0}, Buttons[0]: {1}",
419 count, this.Buttons [0].ToString ());
421 #endregion Public Methods
423 #region Protected Methods
424 protected override void CreateHandle ()
426 base.CreateHandle ();
429 protected override void Dispose (bool disposing)
434 base.Dispose (disposing);
437 protected virtual void OnButtonClick (ToolBarButtonClickEventArgs e)
439 if (e.Button.Style == ToolBarButtonStyle.ToggleButton) {
440 if (! e.Button.Pushed)
441 e.Button.Pushed = true;
443 e.Button.Pushed = false;
445 e.Button.pressed = false;
447 e.Button.InvalidateBorder ();
449 if (ButtonClick != null)
450 ButtonClick (this, e);
453 protected virtual void OnButtonDropDown (ToolBarButtonClickEventArgs e)
455 if (ButtonDropDown != null)
456 ButtonDropDown (this, e);
458 if (e.Button.DropDownMenu == null)
461 Point loc = new Point (e.Button.Rectangle.X + 1, e.Button.Rectangle.Bottom + 1);
462 ((ContextMenu) e.Button.DropDownMenu).Show (this, loc);
464 e.Button.dd_pressed = false;
465 Invalidate (e.Button.Rectangle);
468 protected override void OnFontChanged (EventArgs e)
470 base.OnFontChanged (e);
474 protected override void OnHandleCreated (EventArgs e)
476 base.OnHandleCreated (e);
479 protected override void OnResize (EventArgs e)
483 if (Width <= 0 || Height <= 0 || !Visible)
486 Redraw (true, background_image != null);
489 bool height_specified = false;
490 int requested_height = -1;
492 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
494 if ((specified & BoundsSpecified.Height) != 0) {
495 requested_height = height;
496 height_specified = true;
498 base.SetBoundsCore (x, y, width, height, specified);
501 protected override void WndProc (ref Message m)
503 base.WndProc (ref m);
506 internal override bool InternalPreProcessMessage (ref Message msg)
508 if (msg.Msg == (int)Msg.WM_KEYDOWN) {
509 Keys key_data = (Keys)msg.WParam.ToInt32();
510 if (HandleKeyDown (key_data))
513 return base.InternalPreProcessMessage (ref msg);
516 #endregion Protected Methods
518 #region Private Methods
519 private void FocusChanged (object sender, EventArgs args)
521 if (Appearance != ToolBarAppearance.Flat || Buttons.Count == 0)
524 ToolBarButton prelit = null;
525 foreach (ToolBarButton b in Buttons)
531 if (Focused && prelit == null)
532 foreach (ToolBarButton btn in Buttons) {
538 else if (prelit != null)
539 prelit.Hilight = false;
542 private bool HandleKeyDown (Keys key_data)
544 if (Appearance != ToolBarAppearance.Flat || Buttons.Count == 0)
550 HighlightButton (-1);
561 void HighlightButton (int offset)
563 ArrayList enabled = new ArrayList ();
566 ToolBarButton curr_button = null;
567 foreach (ToolBarButton btn in Buttons) {
579 int next = (start + offset) % count;
586 if (curr_button != null)
587 curr_button.Hilight = false;
588 (enabled [next] as ToolBarButton).Hilight = true;
591 private void ToolBar_MouseDown (object sender, MouseEventArgs me)
596 Point loc = new Point (me.X, me.Y);
598 // draw the pushed button
599 foreach (ToolBarButton button in buttons) {
600 if (button.Enabled && button.Rectangle.Contains (loc)) {
601 // Mark the DropDown rect as pressed.
602 // We don't redraw the dropdown rect.
603 if (button.Style == ToolBarButtonStyle.DropDownButton) {
604 Rectangle rect = button.Rectangle;
605 rect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
606 rect.X = button.Rectangle.Right - rect.Width;
607 if (rect.Contains (loc)) {
608 if (button.DropDownMenu != null) {
609 button.dd_pressed = true;
615 button.pressed = true;
616 button.inside = true;
617 button.InvalidateBorder ();
623 private void ToolBar_MouseUp (object sender, MouseEventArgs me)
628 Point loc = new Point (me.X, me.Y);
630 // draw the normal button
631 // Make a copy in case the list is modified during enumeration
632 ArrayList buttons = new ArrayList (this.buttons);
633 foreach (ToolBarButton button in buttons) {
634 if (button.Enabled && button.Rectangle.Contains (loc)) {
635 if (button.Style == ToolBarButtonStyle.DropDownButton) {
636 Rectangle ddRect = button.Rectangle;
637 ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
638 ddRect.X = button.Rectangle.Right - ddRect.Width;
639 if (ddRect.Contains (loc)) {
640 if (button.dd_pressed)
641 OnButtonDropDown (new ToolBarButtonClickEventArgs (button));
645 // Fire a ButtonClick
647 OnButtonClick (new ToolBarButtonClickEventArgs (button));
648 } else if (button.pressed) {
649 button.pressed = false;
650 button.InvalidateBorder ();
655 private void ToolBar_MouseLeave (object sender, EventArgs e)
657 if (!Enabled || appearance != ToolBarAppearance.Flat || current_button == null)
660 if (current_button.Hilight) {
661 current_button.Hilight = false;
663 current_button = null;
666 private void ToolBar_MouseMove (object sender, MouseEventArgs me)
671 Point loc = new Point (me.X, me.Y);
674 // If the button was pressed and we leave, release the
675 // button press and vice versa
676 foreach (ToolBarButton button in buttons) {
677 if (button.pressed &&
678 (button.inside != button.Rectangle.Contains (loc))) {
679 button.inside = button.Rectangle.Contains (loc);
680 button.Hilight = false;
685 // following is only for flat style toolbar
686 else if (appearance == ToolBarAppearance.Flat) {
687 if (current_button != null && current_button.Rectangle.Contains (loc)) {
688 if (current_button.Hilight || current_button.Pushed)
690 current_button.Hilight = true;
693 foreach (ToolBarButton button in buttons) {
694 if (button.Rectangle.Contains (loc) && button.Enabled) {
695 current_button = button;
696 if (current_button.Hilight || current_button.Pushed)
698 current_button.Hilight = true;
700 else if (button.Hilight) {
701 button.Hilight = false;
708 internal override void OnPaintInternal (PaintEventArgs pevent)
710 ThemeEngine.Current.DrawToolBar (pevent.Graphics, pevent.ClipRectangle, this);
713 internal void Redraw (bool recalculate)
715 Redraw (recalculate, true);
718 internal void Redraw (bool recalculate, bool force)
720 bool invalidate = true;
722 invalidate = Layout ();
725 if (force || invalidate)
729 internal bool SizeSpecified {
730 get { return size_specified; }
733 const int text_padding = 3;
735 private Size CalcButtonSize ()
737 if (Buttons.Count == 0)
740 string longest_text = Buttons [0].Text;
741 for (int i = 1; i < Buttons.Count; i++) {
742 if (Buttons[i].Text.Length > longest_text.Length)
743 longest_text = Buttons[i].Text;
746 Size size = Size.Empty;
747 if (longest_text != null && longest_text.Length > 0) {
748 SizeF sz = DeviceContext.MeasureString (longest_text, Font);
749 if (sz != SizeF.Empty)
750 size = new Size ((int) Math.Ceiling (sz.Width) + 2 * text_padding, (int) Math.Ceiling (sz.Height));
753 Size img_size = ImageList == null ? new Size (16, 16) : ImageSize;
755 Theme theme = ThemeEngine.Current;
756 int imgWidth = img_size.Width + 2 * theme.ToolBarImageGripWidth;
757 int imgHeight = img_size.Height + 2 * theme.ToolBarImageGripWidth;
759 if (text_alignment == ToolBarTextAlign.Right) {
760 size.Width = imgWidth + size.Width;
761 size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
763 size.Height = imgHeight + size.Height;
764 size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
767 size.Width += theme.ToolBarImageGripWidth;
768 size.Height += theme.ToolBarImageGripWidth;
772 // Flat toolbars disregard specified sizes. Normal toolbars grow the
773 // button size to be at least large enough to show the image.
774 Size AdjustedButtonSize {
776 Size size = ButtonSize;
777 if (size_specified) {
778 if (Appearance == ToolBarAppearance.Flat)
779 size = CalcButtonSize ();
781 int grip = ThemeEngine.Current.ToolBarImageGripWidth;
782 if (size.Width < ImageSize.Width + 2 * grip )
783 size.Width = ImageSize.Width + 2 * grip;
784 if (size.Height < ImageSize.Height + 2 * grip)
785 size.Height = ImageSize.Height + 2 * grip;
794 bool changed = false;
795 Theme theme = ThemeEngine.Current;
796 int x = theme.ToolBarGripWidth;
797 int y = theme.ToolBarGripWidth;
799 Size button_size = AdjustedButtonSize;
801 int ht = button_size.Height + theme.ToolBarGripWidth;
803 if (Wrappable && Parent != null) {
804 int separator_index = -1;
806 for (int i = 0; i < buttons.Count; i++) {
807 ToolBarButton button = buttons [i];
812 if (size_specified) {
813 if (button.Layout (button_size))
817 if (button.Layout ())
821 bool is_separator = button.Style == ToolBarButtonStyle.Separator;
823 if (x + button.Rectangle.Width < Width || is_separator) {
824 if (button.Location.X != x || button.Location.Y != y)
826 button.Location = new Point (x, y);
827 x += button.Rectangle.Width;
830 } else if (separator_index > 0) {
832 separator_index = -1;
833 x = theme.ToolBarGripWidth;
836 x = theme.ToolBarGripWidth;
838 if (button.Location.X != x || button.Location.Y != y)
840 button.Location = new Point (x, y);
841 x += button.Rectangle.Width;
849 else if (!height_specified)
850 Height = DefaultSize.Height;
851 foreach (ToolBarButton button in buttons) {
852 if (size_specified) {
853 if (button.Layout (button_size))
857 if (button.Layout ())
860 if (button.Location.X != x || button.Location.Y != y)
862 button.Location = new Point (x, y);
863 x += button.Rectangle.Width;
869 #endregion Private Methods
872 public class ToolBarButtonCollection : IList, ICollection, IEnumerable
874 #region instance variables
875 private ArrayList list;
876 private ToolBar owner;
880 public ToolBarButtonCollection (ToolBar owner)
883 list = new ArrayList ();
890 get { return list.Count; }
893 public bool IsReadOnly {
894 get { return list.IsReadOnly; }
897 public virtual ToolBarButton this [int index] {
898 get { return (ToolBarButton) list [index]; }
900 value.SetParent (owner);
901 list [index] = value;
906 bool ICollection.IsSynchronized {
907 get { return list.IsSynchronized; }
910 object ICollection.SyncRoot {
911 get { return list.SyncRoot; }
914 bool IList.IsFixedSize {
915 get { return list.IsFixedSize; }
918 object IList.this [int index] {
919 get { return this [index]; }
921 if (! (value is ToolBarButton))
922 throw new ArgumentException("Not of type ToolBarButton", "value");
923 this [index] = (ToolBarButton) value;
929 public int Add (string text)
931 ToolBarButton button = new ToolBarButton (text);
932 return this.Add (button);
935 public int Add (ToolBarButton button)
938 button.SetParent (owner);
939 result = list.Add (button);
944 public void AddRange (ToolBarButton [] buttons)
946 foreach (ToolBarButton button in buttons)
953 owner.Redraw (false);
956 public bool Contains (ToolBarButton button)
958 return list.Contains (button);
961 public IEnumerator GetEnumerator ()
963 return list.GetEnumerator ();
966 void ICollection.CopyTo (Array dest, int index)
968 list.CopyTo (dest, index);
971 int IList.Add (object button)
973 if (! (button is ToolBarButton)) {
974 throw new ArgumentException("Not of type ToolBarButton", "button");
977 return this.Add ((ToolBarButton) button);
980 bool IList.Contains (object button)
982 if (! (button is ToolBarButton)) {
983 throw new ArgumentException("Not of type ToolBarButton", "button");
986 return this.Contains ((ToolBarButton) button);
989 int IList.IndexOf (object button)
991 if (! (button is ToolBarButton)) {
992 throw new ArgumentException("Not of type ToolBarButton", "button");
995 return this.IndexOf ((ToolBarButton) button);
998 void IList.Insert (int index, object button)
1000 if (! (button is ToolBarButton)) {
1001 throw new ArgumentException("Not of type ToolBarButton", "button");
1004 this.Insert (index, (ToolBarButton) button);
1007 void IList.Remove (object button)
1009 if (! (button is ToolBarButton)) {
1010 throw new ArgumentException("Not of type ToolBarButton", "button");
1013 this.Remove ((ToolBarButton) button);
1016 public int IndexOf (ToolBarButton button)
1018 return list.IndexOf (button);
1021 public void Insert (int index, ToolBarButton button)
1023 list.Insert (index, button);
1024 owner.Redraw (true);
1027 public void Remove (ToolBarButton button)
1029 list.Remove (button);
1030 owner.Redraw (true);
1033 public void RemoveAt (int index)
1035 list.RemoveAt (index);
1036 owner.Redraw (true);