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 MouseDown += new MouseEventHandler (ToolBar_MouseDown);
117 MouseLeave += new EventHandler (ToolBar_MouseLeave);
118 MouseMove += new MouseEventHandler (ToolBar_MouseMove);
119 MouseUp += new MouseEventHandler (ToolBar_MouseUp);
121 SetStyle (ControlStyles.UserPaint, false);
122 SetStyle (ControlStyles.FixedHeight, true);
124 #endregion Constructor
126 #region protected Properties
127 protected override CreateParams CreateParams
129 get { return base.CreateParams; }
132 protected override ImeMode DefaultImeMode {
133 get { return ImeMode.Disable; }
136 protected override Size DefaultSize {
137 get { return ThemeEngine.Current.ToolBarDefaultSize; }
141 ToolBarAppearance appearance = ToolBarAppearance.Normal;
143 #region Public Properties
144 [DefaultValue (ToolBarAppearance.Normal)]
146 public ToolBarAppearance Appearance {
147 get { return appearance; }
149 if (value == appearance)
157 bool autosize = true;
159 [DefaultValue (true)]
161 public bool AutoSize {
162 get { return autosize; }
164 if (value == autosize)
173 [EditorBrowsable (EditorBrowsableState.Never)]
174 public override Color BackColor {
175 get { return background_color; }
177 if (value == background_color)
180 background_color = value;
181 OnBackColorChanged (EventArgs.Empty);
187 [EditorBrowsable (EditorBrowsableState.Never)]
188 public override Image BackgroundImage {
189 get { return background_image; }
191 if (value == background_image)
194 background_image = value;
195 OnBackgroundImageChanged (EventArgs.Empty);
200 [DefaultValue (BorderStyle.None)]
201 [DispIdAttribute (-504)]
202 public BorderStyle BorderStyle {
203 get { return InternalBorderStyle; }
204 set { InternalBorderStyle = value; }
207 ToolBarButtonCollection buttons;
209 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
211 [MergableProperty (false)]
212 public ToolBarButtonCollection Buttons {
213 get { return buttons; }
219 [RefreshProperties (RefreshProperties.All)]
220 public Size ButtonSize {
222 if (button_size.IsEmpty) {
223 if (buttons.Count == 0)
224 return new Size (24, 22);
225 Size result = CalcButtonSize ();
227 return new Size (24, 22);
234 size_specified = value != Size.Empty;
235 if (button_size == value)
245 [DefaultValue (true)]
246 public bool Divider {
247 get { return divider; }
249 if (value == divider)
257 [DefaultValue (DockStyle.Top)]
259 public override DockStyle Dock {
260 get { return base.Dock; }
261 set { base.Dock = value; }
264 bool drop_down_arrows = false;
266 [DefaultValue (false)]
268 public bool DropDownArrows {
269 get { return drop_down_arrows; }
271 if (value == drop_down_arrows)
274 drop_down_arrows = value;
280 [EditorBrowsable (EditorBrowsableState.Never)]
281 public override Color ForeColor {
282 get { return foreground_color; }
284 if (value == foreground_color)
287 foreground_color = value;
288 OnForeColorChanged (EventArgs.Empty);
293 ImageList image_list;
295 [DefaultValue (null)]
296 public ImageList ImageList {
297 get { return image_list; }
299 if (image_list == value)
307 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
308 [EditorBrowsable (EditorBrowsableState.Advanced)]
309 public Size ImageSize {
311 if (ImageList == null)
314 return ImageList.ImageSize;
321 [EditorBrowsable (EditorBrowsableState.Never)]
322 public new ImeMode ImeMode {
323 get { return ime_mode; }
325 if (value == ime_mode)
329 OnImeModeChanged (EventArgs.Empty);
334 [EditorBrowsable (EditorBrowsableState.Never)]
335 public override RightToLeft RightToLeft {
336 get { return base.RightToLeft; }
338 if (value == base.RightToLeft)
341 base.RightToLeft = value;
342 OnRightToLeftChanged (EventArgs.Empty);
346 bool show_tooltips = false;
348 [DefaultValue (false)]
350 public bool ShowToolTips {
351 get { return show_tooltips; }
352 set { show_tooltips = value; }
355 [DefaultValue (false)]
356 public new bool TabStop {
357 get { return base.TabStop; }
358 set { base.TabStop = value; }
363 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
364 [EditorBrowsable (EditorBrowsableState.Never)]
365 public override string Text {
373 OnTextChanged (EventArgs.Empty);
377 ToolBarTextAlign text_alignment = ToolBarTextAlign.Underneath;
379 [DefaultValue (ToolBarTextAlign.Underneath)]
381 public ToolBarTextAlign TextAlign {
382 get { return text_alignment; }
384 if (value == text_alignment)
387 text_alignment = value;
392 bool wrappable = true;
394 [DefaultValue (true)]
396 public bool Wrappable {
397 get { return wrappable; }
399 if (value == wrappable)
406 #endregion Public Properties
408 #region Public Methods
409 public override string ToString ()
411 int count = this.Buttons.Count;
414 return string.Format ("System.Windows.Forms.ToolBar, Button.Count: 0");
416 return string.Format ("System.Windows.Forms.ToolBar, Button.Count: {0}, Buttons[0]: {1}",
417 count, this.Buttons [0].ToString ());
419 #endregion Public Methods
421 #region Protected Methods
422 protected override void CreateHandle ()
424 base.CreateHandle ();
427 protected override void Dispose (bool disposing)
432 base.Dispose (disposing);
435 protected virtual void OnButtonClick (ToolBarButtonClickEventArgs e)
437 if (e.Button.Style == ToolBarButtonStyle.ToggleButton) {
438 if (! e.Button.Pushed)
439 e.Button.Pushed = true;
441 e.Button.Pushed = false;
443 e.Button.pressed = false;
445 Invalidate (e.Button.Rectangle);
448 if (ButtonClick != null)
449 ButtonClick (this, e);
452 protected virtual void OnButtonDropDown (ToolBarButtonClickEventArgs e)
454 if (ButtonDropDown != null)
455 ButtonDropDown (this, e);
457 if (e.Button.DropDownMenu == null)
460 Point loc = new Point (e.Button.Rectangle.X + 1, e.Button.Rectangle.Bottom + 1);
461 ((ContextMenu) e.Button.DropDownMenu).Show (this, loc);
463 e.Button.dd_pressed = false;
464 Invalidate (e.Button.Rectangle);
467 protected override void OnFontChanged (EventArgs e)
469 base.OnFontChanged (e);
473 protected override void OnHandleCreated (EventArgs e)
475 base.OnHandleCreated (e);
478 protected override void OnResize (EventArgs e)
482 if (Width <= 0 || Height <= 0 || !Visible)
488 bool height_specified = false;
489 int requested_height = -1;
491 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
493 if ((specified & BoundsSpecified.Height) != 0) {
494 requested_height = height;
495 height_specified = true;
497 base.SetBoundsCore (x, y, width, height, specified);
500 protected override void WndProc (ref Message m)
502 base.WndProc (ref m);
505 #endregion Protected Methods
507 #region Private Methods
508 private void ToolBar_MouseDown (object sender, MouseEventArgs me)
513 Point loc = new Point (me.X, me.Y);
515 // draw the pushed button
516 foreach (ToolBarButton button in buttons) {
517 if (button.Enabled && button.Rectangle.Contains (loc)) {
518 // Mark the DropDown rect as pressed.
519 // We don't redraw the dropdown rect.
520 if (button.Style == ToolBarButtonStyle.DropDownButton) {
521 Rectangle rect = button.Rectangle;
522 rect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
523 rect.X = button.Rectangle.Right - rect.Width;
524 if (rect.Contains (loc)) {
525 if (button.DropDownMenu != null) {
526 button.dd_pressed = true;
532 button.pressed = true;
533 button.inside = true;
534 Invalidate (button.Rectangle);
540 private void ToolBar_MouseUp (object sender, MouseEventArgs me)
545 Point loc = new Point (me.X, me.Y);
547 // draw the normal button
548 // Make a copy in case the list is modified during enumeration
549 ArrayList buttons = new ArrayList (this.buttons);
550 foreach (ToolBarButton button in buttons) {
551 if (button.Enabled && button.Rectangle.Contains (loc)) {
552 if (button.Style == ToolBarButtonStyle.DropDownButton) {
553 Rectangle ddRect = button.Rectangle;
554 ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
555 ddRect.X = button.Rectangle.Right - ddRect.Width;
556 if (ddRect.Contains (loc)) {
557 if (button.dd_pressed)
558 OnButtonDropDown (new ToolBarButtonClickEventArgs (button));
562 // Fire a ButtonClick
564 OnButtonClick (new ToolBarButtonClickEventArgs (button));
565 } else if (button.pressed) {
566 button.pressed = false;
567 Invalidate (button.Rectangle);
572 private void ToolBar_MouseLeave (object sender, EventArgs e)
574 if (!Enabled || appearance != ToolBarAppearance.Flat || current_button == null)
577 if (current_button.Hilight) {
578 current_button.Hilight = false;
579 Invalidate (current_button.Rectangle);
582 current_button = null;
585 private void ToolBar_MouseMove (object sender, MouseEventArgs me)
590 Point loc = new Point (me.X, me.Y);
593 // If the button was pressed and we leave, release the
594 // button press and vice versa
595 foreach (ToolBarButton button in buttons) {
596 if (button.pressed &&
597 (button.inside != button.Rectangle.Contains (loc))) {
598 button.inside = button.Rectangle.Contains (loc);
599 button.Hilight = false;
600 Invalidate (button.Rectangle);
606 // following is only for flat style toolbar
607 else if (appearance == ToolBarAppearance.Flat) {
608 if (current_button != null && current_button.Rectangle.Contains (loc)) {
609 if (current_button.Hilight || current_button.Pushed)
611 current_button.Hilight = true;
612 Invalidate (current_button.Rectangle);
616 foreach (ToolBarButton button in buttons) {
617 if (button.Rectangle.Contains (loc) && button.Enabled) {
618 current_button = button;
619 if (current_button.Hilight || current_button.Pushed)
621 current_button.Hilight = true;
622 Invalidate (current_button.Rectangle);
625 else if (button.Hilight) {
626 button.Hilight = false;
627 Invalidate (button.Rectangle);
635 internal override void OnPaintInternal (PaintEventArgs pevent)
637 ThemeEngine.Current.DrawToolBar (pevent.Graphics, pevent.ClipRectangle, this);
640 internal void Redraw (bool recalculate)
648 internal bool SizeSpecified {
649 get { return size_specified; }
652 const int text_padding = 3;
654 private Size CalcButtonSize ()
656 if (Buttons.Count == 0)
659 string longest_text = Buttons [0].Text;
660 for (int i = 1; i < Buttons.Count; i++) {
661 if (Buttons[i].Text.Length > longest_text.Length)
662 longest_text = Buttons[i].Text;
665 Size size = Size.Empty;
666 if (longest_text != null && longest_text.Length > 0) {
667 SizeF sz = DeviceContext.MeasureString (longest_text, Font);
668 if (sz != SizeF.Empty)
669 size = new Size ((int) Math.Ceiling (sz.Width) + 2 * text_padding, (int) Math.Ceiling (sz.Height));
672 Size img_size = ImageList == null ? new Size (16, 16) : ImageSize;
674 Theme theme = ThemeEngine.Current;
675 int imgWidth = img_size.Width + 2 * theme.ToolBarImageGripWidth;
676 int imgHeight = img_size.Height + 2 * theme.ToolBarImageGripWidth;
678 if (text_alignment == ToolBarTextAlign.Right) {
679 size.Width = imgWidth + size.Width;
680 size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
682 size.Height = imgHeight + size.Height;
683 size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
686 size.Width += theme.ToolBarImageGripWidth;
687 size.Height += theme.ToolBarImageGripWidth;
691 // Flat toolbars disregard specified sizes. Normal toolbars grow the
692 // button size to be at least large enough to show the image.
693 Size AdjustedButtonSize {
695 Size size = ButtonSize;
696 if (size_specified) {
697 if (Appearance == ToolBarAppearance.Flat)
698 size = CalcButtonSize ();
700 int grip = ThemeEngine.Current.ToolBarImageGripWidth;
701 if (size.Width < ImageSize.Width + 2 * grip )
702 size.Width = ImageSize.Width + 2 * grip;
703 if (size.Height < ImageSize.Height + 2 * grip)
704 size.Height = ImageSize.Height + 2 * grip;
713 Theme theme = ThemeEngine.Current;
714 int x = theme.ToolBarGripWidth;
715 int y = theme.ToolBarGripWidth;
717 Size button_size = AdjustedButtonSize;
719 int ht = button_size.Height + theme.ToolBarGripWidth;
721 if (Wrappable && Parent != null) {
722 int separator_index = -1;
724 for (int i = 0; i < buttons.Count; i++) {
725 ToolBarButton button = buttons [i];
731 button.Layout (button_size);
735 bool is_separator = button.Style == ToolBarButtonStyle.Separator;
737 if (x + button.Rectangle.Width < Width || is_separator) {
738 button.Location = new Point (x, y);
739 x += button.Rectangle.Width;
742 } else if (separator_index > 0) {
744 separator_index = -1;
745 x = theme.ToolBarGripWidth;
748 x = theme.ToolBarGripWidth;
750 button.Location = new Point (x, y);
751 x += button.Rectangle.Width;
759 else if (!height_specified)
760 Height = DefaultSize.Height;
761 foreach (ToolBarButton button in buttons) {
763 button.Layout (button_size);
766 button.Location = new Point (x, y);
767 x += button.Rectangle.Width;
771 #endregion Private Methods
774 public class ToolBarButtonCollection : IList, ICollection, IEnumerable
776 #region instance variables
777 private ArrayList list;
778 private ToolBar owner;
782 public ToolBarButtonCollection (ToolBar owner)
785 list = new ArrayList ();
792 get { return list.Count; }
795 public bool IsReadOnly {
796 get { return list.IsReadOnly; }
799 public virtual ToolBarButton this [int index] {
800 get { return (ToolBarButton) list [index]; }
802 value.SetParent (owner);
803 list [index] = value;
808 bool ICollection.IsSynchronized {
809 get { return list.IsSynchronized; }
812 object ICollection.SyncRoot {
813 get { return list.SyncRoot; }
816 bool IList.IsFixedSize {
817 get { return list.IsFixedSize; }
820 object IList.this [int index] {
821 get { return this [index]; }
823 if (! (value is ToolBarButton))
824 throw new ArgumentException("Not of type ToolBarButton", "value");
825 this [index] = (ToolBarButton) value;
831 public int Add (string text)
833 ToolBarButton button = new ToolBarButton (text);
834 return this.Add (button);
837 public int Add (ToolBarButton button)
840 button.SetParent (owner);
841 result = list.Add (button);
846 public void AddRange (ToolBarButton [] buttons)
848 foreach (ToolBarButton button in buttons)
855 owner.Redraw (false);
858 public bool Contains (ToolBarButton button)
860 return list.Contains (button);
863 public IEnumerator GetEnumerator ()
865 return list.GetEnumerator ();
868 void ICollection.CopyTo (Array dest, int index)
870 list.CopyTo (dest, index);
873 int IList.Add (object button)
875 if (! (button is ToolBarButton)) {
876 throw new ArgumentException("Not of type ToolBarButton", "button");
879 return this.Add ((ToolBarButton) button);
882 bool IList.Contains (object button)
884 if (! (button is ToolBarButton)) {
885 throw new ArgumentException("Not of type ToolBarButton", "button");
888 return this.Contains ((ToolBarButton) button);
891 int IList.IndexOf (object button)
893 if (! (button is ToolBarButton)) {
894 throw new ArgumentException("Not of type ToolBarButton", "button");
897 return this.IndexOf ((ToolBarButton) button);
900 void IList.Insert (int index, object button)
902 if (! (button is ToolBarButton)) {
903 throw new ArgumentException("Not of type ToolBarButton", "button");
906 this.Insert (index, (ToolBarButton) button);
909 void IList.Remove (object button)
911 if (! (button is ToolBarButton)) {
912 throw new ArgumentException("Not of type ToolBarButton", "button");
915 this.Remove ((ToolBarButton) button);
918 public int IndexOf (ToolBarButton button)
920 return list.IndexOf (button);
923 public void Insert (int index, ToolBarButton button)
925 list.Insert (index, button);
929 public void Remove (ToolBarButton button)
931 list.Remove (button);
935 public void RemoveAt (int index)
937 list.RemoveAt (index);