2 // System.Windows.Forms.ToolBar.cs
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.
24 // Ravindra (rkumar@novell.com)
29 // Copyright (C) Novell, Inc. 2004 (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)]
47 public class ToolBar : Control
49 #region Instance Variables
50 internal ToolBarAppearance appearance;
51 internal bool autosize;
52 internal BorderStyle borderStyle;
53 internal ToolBarButtonCollection buttons;
54 internal Size buttonSize;
55 internal bool divider;
56 internal bool dropDownArrows;
57 internal ImageList imageList;
58 internal ImeMode imeMode;
59 internal bool showToolTips;
60 internal ToolBarTextAlign textAlignment;
61 internal bool wrappable; // flag to make the toolbar wrappable
62 internal bool redraw; // flag to force redrawing the control
63 private bool size_specified; // flag to know if button size is fixed.
64 internal ToolBarButton currentButton; // the highlighted button
65 #endregion Instance Variables
69 [EditorBrowsable (EditorBrowsableState.Never)]
70 public new event EventHandler BackColorChanged;
73 [EditorBrowsable (EditorBrowsableState.Never)]
74 public new event EventHandler BackgroundImageChanged;
76 public event ToolBarButtonClickEventHandler ButtonClick;
77 public event ToolBarButtonClickEventHandler ButtonDropDown;
80 [EditorBrowsable (EditorBrowsableState.Never)]
81 public new event EventHandler ForeColorChanged;
84 [EditorBrowsable (EditorBrowsableState.Never)]
85 public new event EventHandler ImeModeChanged;
88 [EditorBrowsable (EditorBrowsableState.Never)]
89 public new event PaintEventHandler Paint;
92 [EditorBrowsable (EditorBrowsableState.Never)]
93 public new event EventHandler RightToLeftChanged;
96 [EditorBrowsable (EditorBrowsableState.Never)]
97 public new event EventHandler TextChanged;
103 appearance = ToolBarAppearance.Normal;
105 background_color = ThemeEngine.Current.DefaultControlBackColor;
106 borderStyle = BorderStyle.None;
107 buttons = new ToolBarButtonCollection (this);
108 buttonSize = Size.Empty;
110 dropDownArrows = false;
111 foreground_color = ThemeEngine.Current.DefaultControlForeColor;
112 showToolTips = false;
113 textAlignment = ToolBarTextAlign.Underneath;
115 dock_style = DockStyle.Top;
117 size_specified = false;
120 this.MouseDown += new MouseEventHandler (ToolBar_MouseDown);
121 this.MouseLeave += new EventHandler (ToolBar_MouseLeave);
122 this.MouseMove += new MouseEventHandler (ToolBar_MouseMove);
123 this.MouseUp += new MouseEventHandler (ToolBar_MouseUp);
124 base.Paint += new PaintEventHandler (ToolBar_Paint);
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 #region Public Properties
144 [DefaultValue (ToolBarAppearance.Normal)]
146 public ToolBarAppearance Appearance {
147 get { return appearance; }
149 if (value == appearance)
157 [DefaultValue (true)]
159 public bool AutoSize {
160 get { return autosize; }
162 if (value == autosize)
171 [EditorBrowsable (EditorBrowsableState.Never)]
172 public override Color BackColor {
173 get { return background_color; }
175 if (value == background_color)
178 background_color = value;
179 if (BackColorChanged != null)
180 BackColorChanged (this, new EventArgs ());
186 [EditorBrowsable (EditorBrowsableState.Never)]
187 public override Image BackgroundImage {
188 get { return background_image; }
190 if (value == background_image)
193 background_image = value;
194 if (BackgroundImageChanged != null)
195 BackgroundImageChanged (this, new EventArgs ());
200 [DefaultValue (BorderStyle.None)]
201 [DispIdAttribute (-504)]
202 public BorderStyle BorderStyle {
203 get { return borderStyle; }
205 if (value == borderStyle)
213 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
215 [MergableProperty (false)]
216 public ToolBarButtonCollection Buttons {
217 get { return buttons; }
221 [RefreshProperties (RefreshProperties.All)]
222 public Size ButtonSize {
224 if (buttonSize.IsEmpty) {
225 if (buttons.Count == 0)
226 return new Size (39, 36);
228 return CalcButtonSize ();
233 if (buttonSize.Width == value.Width && buttonSize.Height == value.Height)
237 size_specified = true;
242 [DefaultValue (true)]
243 public bool Divider {
244 get { return divider; }
246 if (value == divider)
254 [DefaultValue (DockStyle.Top)]
256 public override DockStyle Dock {
257 get { return base.Dock; }
258 set { base.Dock = value; }
261 [DefaultValue (false)]
263 public bool DropDownArrows {
264 get { return dropDownArrows; }
266 if (value == dropDownArrows)
269 dropDownArrows = value;
275 [EditorBrowsable (EditorBrowsableState.Never)]
276 public override Color ForeColor {
277 get { return foreground_color; }
279 if (value == foreground_color)
282 foreground_color = value;
283 if (ForeColorChanged != null)
284 ForeColorChanged (this, new EventArgs ());
289 [DefaultValue (null)]
290 public ImageList ImageList {
291 get { return imageList; }
292 set { imageList = value; }
296 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
297 [EditorBrowsable (EditorBrowsableState.Advanced)]
298 public Size ImageSize {
300 if (imageList == null)
303 return imageList.ImageSize;
308 [EditorBrowsable (EditorBrowsableState.Never)]
309 public new ImeMode ImeMode {
310 get { return imeMode; }
312 if (value == imeMode)
316 if (ImeModeChanged != null)
317 ImeModeChanged (this, new EventArgs ());
322 [EditorBrowsable (EditorBrowsableState.Never)]
323 public override RightToLeft RightToLeft {
324 get { return base.RightToLeft; }
326 if (value == base.RightToLeft)
329 base.RightToLeft = value;
330 if (RightToLeftChanged != null)
331 RightToLeftChanged (this, new EventArgs ());
335 [DefaultValue (false)]
337 public bool ShowToolTips {
338 get { return showToolTips; }
339 set { showToolTips = value; }
342 [DefaultValue (false)]
343 public new bool TabStop {
344 get { return base.TabStop; }
345 set { base.TabStop = value; }
350 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
351 [EditorBrowsable (EditorBrowsableState.Never)]
352 public override string Text {
360 if (TextChanged != null)
361 TextChanged (this, new EventArgs ());
365 [DefaultValue (ToolBarTextAlign.Underneath)]
367 public ToolBarTextAlign TextAlign {
368 get { return textAlignment; }
370 if (value == textAlignment)
373 textAlignment = value;
378 [DefaultValue (true)]
380 public bool Wrappable {
381 get { return wrappable; }
383 if (value == wrappable)
390 #endregion Public Properties
392 #region Public Methods
393 public override string ToString ()
395 int count = this.Buttons.Count;
398 return string.Format ("System.Windows.Forms.ToolBar, Button.Count: 0");
400 return string.Format ("System.Windows.Forms.ToolBar, Button.Count: {0}, Buttons[0]: {1}",
401 count, this.Buttons [0].ToString ());
403 #endregion Public Methods
405 #region Internal Methods
406 internal Rectangle GetChildBounds (ToolBarButton button)
408 if (button.Style == ToolBarButtonStyle.Separator)
409 return new Rectangle (button.Location.X, button.Location.Y,
410 ThemeEngine.Current.ToolBarSeparatorWidth, this.ButtonSize.Height);
413 return new Rectangle (button.Location, this.ButtonSize);
415 SizeF sz = this.DeviceContext.MeasureString (button.Text, this.Font);
416 Size size = new Size ((int) Math.Ceiling (sz.Width), (int) Math.Ceiling (sz.Height));
418 if (imageList != null) {
419 // adjustment for the image grip
420 int imgWidth = this.ImageSize.Width + 2 * ThemeEngine.Current.ToolBarImageGripWidth;
421 int imgHeight = this.ImageSize.Height + 2 * ThemeEngine.Current.ToolBarImageGripWidth;
423 if (textAlignment == ToolBarTextAlign.Right) {
424 size.Width = imgWidth + size.Width;
425 size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
428 size.Height = imgHeight + size.Height;
429 size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
432 if (button.Style == ToolBarButtonStyle.DropDownButton && this.dropDownArrows)
433 size.Width += ThemeEngine.Current.ToolBarDropDownWidth;
435 return new Rectangle (button.Location, size);
437 #endregion Internal Methods
439 #region Protected Methods
440 protected override void CreateHandle ()
442 base.CreateHandle ();
445 protected override void Dispose (bool disposing)
448 if (imageList != null)
449 imageList.Dispose ();
452 base.Dispose (disposing);
455 protected virtual void OnButtonClick (ToolBarButtonClickEventArgs e)
457 if (e.Button.Style == ToolBarButtonStyle.ToggleButton) {
458 if (! e.Button.Pushed)
459 e.Button.Pushed = true;
461 e.Button.Pushed = false;
463 e.Button.pressed = false;
465 Invalidate (e.Button.Rectangle);
468 if (ButtonClick != null)
469 ButtonClick (this, e);
474 protected virtual void OnButtonDropDown (ToolBarButtonClickEventArgs e)
476 // Reset the flag set on DropDown
477 e.Button.dd_pressed = false;
479 if (ButtonDropDown != null)
480 ButtonDropDown (this, e);
482 if (e.Button.DropDownMenu == null)
485 Point loc = new Point (e.Button.Location.X + 1,
486 e.Button.Rectangle.Bottom + 2);
487 ((ContextMenu) e.Button.DropDownMenu).Show (this, loc);
490 protected override void OnFontChanged (EventArgs e)
492 base.OnFontChanged (e);
496 protected override void OnHandleCreated (EventArgs e)
498 base.OnHandleCreated (e);
501 protected override void OnResize (EventArgs e)
505 if (this.Width <= 0 || this.Height <= 0 || this.Visible == false)
511 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
513 base.SetBoundsCore (x, y, width, height, specified);
516 protected override void WndProc (ref Message m)
518 base.WndProc (ref m);
521 #endregion Protected Methods
523 #region Private Methods
524 private void ToolBar_MouseDown (object sender, MouseEventArgs me)
526 if (! this.Enabled) return;
528 Point hit = new Point (me.X, me.Y);
531 // draw the pushed button
532 foreach (ToolBarButton button in buttons) {
533 if (button.Enabled && button.Rectangle.Contains (hit)) {
534 // Mark the DropDown rect as pressed.
535 // We don't redraw the dropdown rect.
536 if (button.Style == ToolBarButtonStyle.DropDownButton) {
537 Rectangle ddRect = Rectangle.Empty;
538 Rectangle rect = button.Rectangle;
539 ddRect.Height = rect.Height;
540 ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
541 ddRect.X = rect.X + rect.Width - ddRect.Width;
543 if (ddRect.Contains (hit)) {
544 button.dd_pressed = true;
548 // If it is not dropdown then we treat it as a normal
550 button.pressed = true;
551 button.inside = true;
552 Invalidate (button.Rectangle);
559 private void ToolBar_MouseUp (object sender, MouseEventArgs me)
561 if (! this.Enabled) return;
563 Point hit = new Point (me.X, me.Y);
564 this.Capture = false;
566 // draw the normal button
567 foreach (ToolBarButton button in buttons) {
568 if (button.Enabled && button.Rectangle.Contains (hit)) {
569 if (button.Style == ToolBarButtonStyle.DropDownButton) {
570 Rectangle ddRect = Rectangle.Empty;
571 Rectangle rect = button.Rectangle;
572 ddRect.Height = rect.Height;
573 ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
574 ddRect.X = rect.X + rect.Width - ddRect.Width;
576 // Fire a ButtonDropDown event
577 if (ddRect.Contains (hit)) {
578 if (button.dd_pressed)
579 this.OnButtonDropDown (new ToolBarButtonClickEventArgs (button));
583 // Fire a ButtonClick
585 this.OnButtonClick (new ToolBarButtonClickEventArgs (button));
587 // Clear the button press flags, if any
588 else if (button.pressed) {
589 button.pressed = false;
590 Invalidate (button.Rectangle);
596 private void ToolBar_MouseLeave (object sender, EventArgs e)
598 if (! this.Enabled || appearance != ToolBarAppearance.Flat) return;
600 if (currentButton != null && currentButton.Hilight) {
601 currentButton.Hilight = false;
602 Invalidate (currentButton.Rectangle);
605 currentButton = null;
608 private void ToolBar_MouseMove (object sender, MouseEventArgs me)
610 if (! this.Enabled) return;
612 Point hit = new Point (me.X, me.Y);
615 // If the button was pressed and we leave, release the
616 // button press and vice versa
617 foreach (ToolBarButton button in buttons) {
618 if (button.pressed &&
619 (button.inside != button.Rectangle.Contains (hit))) {
620 button.inside = button.Rectangle.Contains (hit);
621 button.Hilight = false;
622 Invalidate (button.Rectangle);
628 // following is only for flat style toolbar
629 else if (appearance == ToolBarAppearance.Flat) {
630 if (currentButton != null && currentButton.Rectangle.Contains (hit)) {
631 if (currentButton.Hilight || currentButton.Pushed)
633 currentButton.Hilight = true;
634 Invalidate (currentButton.Rectangle);
638 foreach (ToolBarButton button in buttons) {
639 if (button.Rectangle.Contains (hit) && button.Enabled) {
640 currentButton = button;
641 if (currentButton.Hilight || currentButton.Pushed)
643 currentButton.Hilight = true;
644 Invalidate (currentButton.Rectangle);
647 else if (button.Hilight) {
648 button.Hilight = false;
649 Invalidate (button.Rectangle);
657 private void ToolBar_Paint (object sender, PaintEventArgs pevent)
659 if (this.Width <= 0 || this.Height <= 0 || this.Visible == false)
663 ThemeEngine.Current.DrawToolBar (this.DeviceContext, pevent.ClipRectangle, this);
667 pevent.Graphics.DrawImage(this.ImageBuffer, pevent.ClipRectangle, pevent.ClipRectangle, GraphicsUnit.Pixel);
670 Paint (this, pevent);
674 internal void Redraw (bool recalculate)
684 private Size CalcButtonSize ()
686 String longestText = buttons [0].Text;
687 for (int i = 1; i < buttons.Count; i++) {
688 if (buttons[i].Text.Length > longestText.Length)
689 longestText = buttons[i].Text;
692 SizeF sz = this.DeviceContext.MeasureString (longestText, this.Font);
693 Size size = new Size ((int) Math.Ceiling (sz.Width), (int) Math.Ceiling (sz.Height));
695 if (imageList != null) {
696 // adjustment for the image grip
697 int imgWidth = this.ImageSize.Width + 2 * ThemeEngine.Current.ToolBarImageGripWidth;
698 int imgHeight = this.ImageSize.Height + 2 * ThemeEngine.Current.ToolBarImageGripWidth;
700 if (textAlignment == ToolBarTextAlign.Right) {
701 size.Width = imgWidth + size.Width;
702 size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
705 size.Height = imgHeight + size.Height;
706 size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
712 /* Checks for the separators and sets the location of a button and its wrapper flag */
713 private void CalcToolBar ()
715 int wd = this.Width; // the amount of space we have for rest of the buttons
716 int ht = this.ButtonSize.Height; // all buttons are displayed with the same height
717 Point loc; // the location to place the next button, leave the space for border
718 loc = new Point (ThemeEngine.Current.ToolBarGripWidth, ThemeEngine.Current.ToolBarGripWidth);
720 // clear all the wrappers if toolbar is not wrappable
721 if (! wrappable && ! autosize) {
722 if (this.Height != this.DefaultSize.Height)
723 this.Height = this.DefaultSize.Height;
724 foreach (ToolBarButton button in buttons) {
725 button.Location = loc;
726 button.Wrapper = false;
727 loc.X = loc.X + button.Rectangle.Width;
730 else if (! wrappable) { // autosizeable
731 if (ht != this.Height)
733 foreach (ToolBarButton button in buttons) {
734 button.Location = loc;
735 button.Wrapper = false;
736 loc.X = loc.X + button.Rectangle.Width;
740 bool seenSeparator = false;
741 int separatorIndex = -1;
742 ToolBarButton button;
744 for (int i = 0; i < buttons.Count; i++) {
745 button = buttons [i];
746 if (button.Visible) {
747 if (button.Style == ToolBarButtonStyle.Separator) {
748 wd -= ThemeEngine.Current.ToolBarSeparatorWidth;
750 button.Wrapper = false; // clear the old flag in case it was set
751 button.Location = loc;
752 loc.X = loc.X + ThemeEngine.Current.ToolBarSeparatorWidth;
755 button.Wrapper = true;
756 button.Location = loc;
757 loc.X = ThemeEngine.Current.ToolBarGripWidth;
759 // we need space to draw horizontal separator
760 loc.Y = loc.Y + ThemeEngine.Current.ToolBarSeparatorWidth + ht;
762 seenSeparator = true;
766 Rectangle rect = button.Rectangle;
769 button.Wrapper = false;
770 button.Location = loc;
771 loc.X = loc.X + rect.Width;
773 else if (seenSeparator) {
774 // wrap at the separator and reassign the locations
775 i = separatorIndex; // for loop is going to increment it
776 buttons [separatorIndex].Wrapper = true;
777 seenSeparator = false;
779 loc.X = ThemeEngine.Current.ToolBarGripWidth;
780 // we need space to draw horizontal separator
781 loc.Y = loc.Y + ht + ThemeEngine.Current.ToolBarSeparatorWidth;
786 button.Wrapper = true;
790 button.Location = loc;
791 loc.X = loc.X + rect.Width;
795 else // don't consider invisible buttons
798 /* adjust the control height, if we are autosizeable */
799 if (autosize) // wrappable
800 if (this.Height != (loc.Y + ht + ThemeEngine.Current.ToolBarGripWidth))
801 this.Height = loc.Y + ht + ThemeEngine.Current.ToolBarGripWidth;
805 private void DumpToolBar (string msg)
807 Console.WriteLine (msg);
808 Console.WriteLine ("ToolBar: name: " + this.Text);
809 Console.WriteLine ("ToolBar: wd, ht: " + this.Size);
810 Console.WriteLine ("ToolBar: img size: " + this.ImageSize);
811 Console.WriteLine ("ToolBar: button sz: " + this.buttonSize);
812 Console.WriteLine ("ToolBar: textalignment: "+ this.TextAlign);
813 Console.WriteLine ("ToolBar: appearance: "+ this.Appearance);
814 Console.WriteLine ("ToolBar: wrappable: "+ this.Wrappable);
815 Console.WriteLine ("ToolBar: buttons count: " + this.Buttons.Count);
818 foreach (ToolBarButton b in buttons) {
819 Console.WriteLine ("ToolBar: button [{0}]:",i++);
823 #endregion Private Methods
826 public class ToolBarButtonCollection : IList, ICollection, IEnumerable
828 #region instance variables
829 private ArrayList buttonsList;
830 private ToolBar owner;
834 public ToolBarButtonCollection (ToolBar owner)
837 this.buttonsList = new ArrayList ();
843 public virtual int Count {
844 get { return buttonsList.Count; }
847 public virtual bool IsReadOnly {
848 get { return buttonsList.IsReadOnly; }
851 public virtual ToolBarButton this [int index] {
852 get { return (ToolBarButton) buttonsList [index]; }
854 value.SetParent (owner);
855 buttonsList [index] = value;
860 bool ICollection.IsSynchronized {
861 get { return buttonsList.IsSynchronized; }
864 object ICollection.SyncRoot {
865 get { return buttonsList.SyncRoot; }
868 bool IList.IsFixedSize {
869 get { return buttonsList.IsFixedSize; }
872 object IList.this [int index] {
873 get { return this [index]; }
875 if (! (value is ToolBarButton))
876 throw new ArgumentException("Not of type ToolBarButton", "value");
877 this [index] = (ToolBarButton) value;
883 public int Add (string text)
885 ToolBarButton button = new ToolBarButton (text);
886 return this.Add (button);
889 public int Add (ToolBarButton button)
892 button.SetParent (owner);
893 result = buttonsList.Add (button);
898 public void AddRange (ToolBarButton [] buttons)
900 foreach (ToolBarButton button in buttons)
904 public virtual void Clear ()
906 buttonsList.Clear ();
907 owner.Redraw (false);
910 public bool Contains (ToolBarButton button)
912 return buttonsList.Contains (button);
915 public virtual IEnumerator GetEnumerator ()
917 return buttonsList.GetEnumerator ();
920 void ICollection.CopyTo (Array dest, int index)
922 buttonsList.CopyTo (dest, index);
925 int IList.Add (object button)
927 if (! (button is ToolBarButton)) {
928 throw new ArgumentException("Not of type ToolBarButton", "button");
931 return this.Add ((ToolBarButton) button);
934 bool IList.Contains (object button)
936 if (! (button is ToolBarButton)) {
937 throw new ArgumentException("Not of type ToolBarButton", "button");
940 return this.Contains ((ToolBarButton) button);
943 int IList.IndexOf (object button)
945 if (! (button is ToolBarButton)) {
946 throw new ArgumentException("Not of type ToolBarButton", "button");
949 return this.IndexOf ((ToolBarButton) button);
952 void IList.Insert (int index, object button)
954 if (! (button is ToolBarButton)) {
955 throw new ArgumentException("Not of type ToolBarButton", "button");
958 this.Insert (index, (ToolBarButton) button);
961 void IList.Remove (object button)
963 if (! (button is ToolBarButton)) {
964 throw new ArgumentException("Not of type ToolBarButton", "button");
967 this.Remove ((ToolBarButton) button);
970 public int IndexOf (ToolBarButton button)
972 return buttonsList.IndexOf (button);
975 public void Insert (int index, ToolBarButton button)
977 buttonsList.Insert (index, button);
981 public void Remove (ToolBarButton button)
983 buttonsList.Remove (button);
987 public virtual void RemoveAt (int index)
989 buttonsList.RemoveAt (index);