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, "System.ComponentModel.Design.IDesigner")]
47 public class ToolBar : Control
49 #region Instance Variables
50 internal ToolBarAppearance appearance;
51 internal bool autosize;
52 internal ToolBarButtonCollection buttons;
53 internal Size buttonSize;
54 internal bool divider;
55 internal bool dropDownArrows;
56 internal ImageList imageList;
57 internal ImeMode imeMode;
58 internal bool showToolTips;
59 internal ToolBarTextAlign textAlignment;
60 internal bool wrappable; // flag to make the toolbar wrappable
61 internal bool redraw; // flag to force redrawing the control
62 private bool size_specified; // flag to know if button size is fixed.
63 internal ToolBarButton currentButton; // the highlighted button
64 #endregion Instance Variables
68 [EditorBrowsable (EditorBrowsableState.Never)]
69 public new event EventHandler BackColorChanged;
72 [EditorBrowsable (EditorBrowsableState.Never)]
73 public new event EventHandler BackgroundImageChanged;
75 public event ToolBarButtonClickEventHandler ButtonClick;
76 public event ToolBarButtonClickEventHandler ButtonDropDown;
79 [EditorBrowsable (EditorBrowsableState.Never)]
80 public new event EventHandler ForeColorChanged;
83 [EditorBrowsable (EditorBrowsableState.Never)]
84 public new event EventHandler ImeModeChanged;
87 [EditorBrowsable (EditorBrowsableState.Never)]
88 public new event PaintEventHandler Paint;
91 [EditorBrowsable (EditorBrowsableState.Never)]
92 public new event EventHandler RightToLeftChanged;
95 [EditorBrowsable (EditorBrowsableState.Never)]
96 public new event EventHandler TextChanged;
102 appearance = ToolBarAppearance.Normal;
104 background_color = ThemeEngine.Current.DefaultControlBackColor;
105 border_style = BorderStyle.None;
106 buttons = new ToolBarButtonCollection (this);
107 buttonSize = Size.Empty;
109 dropDownArrows = false;
110 foreground_color = ThemeEngine.Current.DefaultControlForeColor;
111 showToolTips = false;
112 textAlignment = ToolBarTextAlign.Underneath;
114 dock_style = DockStyle.Top;
116 size_specified = false;
119 this.MouseDown += new MouseEventHandler (ToolBar_MouseDown);
120 this.MouseLeave += new EventHandler (ToolBar_MouseLeave);
121 this.MouseMove += new MouseEventHandler (ToolBar_MouseMove);
122 this.MouseUp += new MouseEventHandler (ToolBar_MouseUp);
123 base.Paint += new PaintEventHandler (ToolBar_Paint);
125 SetStyle (ControlStyles.UserPaint, false);
126 SetStyle (ControlStyles.FixedHeight, true);
128 #endregion Constructor
130 #region protected Properties
131 protected override CreateParams CreateParams
133 get { return base.CreateParams; }
136 protected override ImeMode DefaultImeMode {
137 get { return ImeMode.Disable; }
140 protected override Size DefaultSize {
141 get { return ThemeEngine.Current.ToolBarDefaultSize; }
145 #region Public Properties
146 [DefaultValue (ToolBarAppearance.Normal)]
148 public ToolBarAppearance Appearance {
149 get { return appearance; }
151 if (value == appearance)
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 if (BackColorChanged != null)
182 BackColorChanged (this, new EventArgs ());
188 [EditorBrowsable (EditorBrowsableState.Never)]
189 public override Image BackgroundImage {
190 get { return background_image; }
192 if (value == background_image)
195 background_image = value;
196 if (BackgroundImageChanged != null)
197 BackgroundImageChanged (this, new EventArgs ());
202 [DefaultValue (BorderStyle.None)]
203 [DispIdAttribute (-504)]
204 public BorderStyle BorderStyle {
205 get { return InternalBorderStyle; }
206 set { InternalBorderStyle = value; }
209 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
211 [MergableProperty (false)]
212 public ToolBarButtonCollection Buttons {
213 get { return buttons; }
217 [RefreshProperties (RefreshProperties.All)]
218 public Size ButtonSize {
220 if (buttonSize.IsEmpty) {
221 if (buttons.Count == 0)
222 return new Size (39, 36);
224 return CalcButtonSize ();
229 if (buttonSize.Width == value.Width && buttonSize.Height == value.Height)
233 size_specified = true;
238 [DefaultValue (true)]
239 public bool Divider {
240 get { return divider; }
242 if (value == divider)
250 [DefaultValue (DockStyle.Top)]
252 public override DockStyle Dock {
253 get { return base.Dock; }
254 set { base.Dock = value; }
257 [DefaultValue (false)]
259 public bool DropDownArrows {
260 get { return dropDownArrows; }
262 if (value == dropDownArrows)
265 dropDownArrows = value;
271 [EditorBrowsable (EditorBrowsableState.Never)]
272 public override Color ForeColor {
273 get { return foreground_color; }
275 if (value == foreground_color)
278 foreground_color = value;
279 if (ForeColorChanged != null)
280 ForeColorChanged (this, new EventArgs ());
285 [DefaultValue (null)]
286 public ImageList ImageList {
287 get { return imageList; }
288 set { imageList = value; }
292 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
293 [EditorBrowsable (EditorBrowsableState.Advanced)]
294 public Size ImageSize {
296 if (imageList == null)
299 return imageList.ImageSize;
304 [EditorBrowsable (EditorBrowsableState.Never)]
305 public new ImeMode ImeMode {
306 get { return imeMode; }
308 if (value == imeMode)
312 if (ImeModeChanged != null)
313 ImeModeChanged (this, new EventArgs ());
318 [EditorBrowsable (EditorBrowsableState.Never)]
319 public override RightToLeft RightToLeft {
320 get { return base.RightToLeft; }
322 if (value == base.RightToLeft)
325 base.RightToLeft = value;
326 if (RightToLeftChanged != null)
327 RightToLeftChanged (this, new EventArgs ());
331 [DefaultValue (false)]
333 public bool ShowToolTips {
334 get { return showToolTips; }
335 set { showToolTips = value; }
338 [DefaultValue (false)]
339 public new bool TabStop {
340 get { return base.TabStop; }
341 set { base.TabStop = value; }
346 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
347 [EditorBrowsable (EditorBrowsableState.Never)]
348 public override string Text {
356 if (TextChanged != null)
357 TextChanged (this, new EventArgs ());
361 [DefaultValue (ToolBarTextAlign.Underneath)]
363 public ToolBarTextAlign TextAlign {
364 get { return textAlignment; }
366 if (value == textAlignment)
369 textAlignment = value;
374 [DefaultValue (true)]
376 public bool Wrappable {
377 get { return wrappable; }
379 if (value == wrappable)
386 #endregion Public Properties
388 #region Public Methods
389 public override string ToString ()
391 int count = this.Buttons.Count;
394 return string.Format ("System.Windows.Forms.ToolBar, Button.Count: 0");
396 return string.Format ("System.Windows.Forms.ToolBar, Button.Count: {0}, Buttons[0]: {1}",
397 count, this.Buttons [0].ToString ());
399 #endregion Public Methods
401 #region Internal Methods
402 internal Rectangle GetChildBounds (ToolBarButton button)
404 if (button.Style == ToolBarButtonStyle.Separator)
405 return new Rectangle (button.Location.X, button.Location.Y,
406 ThemeEngine.Current.ToolBarSeparatorWidth, this.ButtonSize.Height);
409 return new Rectangle (button.Location, this.ButtonSize);
411 SizeF sz = this.DeviceContext.MeasureString (button.Text, this.Font);
412 Size size = new Size ((int) Math.Ceiling (sz.Width), (int) Math.Ceiling (sz.Height));
414 if (imageList != null) {
415 // adjustment for the image grip
416 int imgWidth = this.ImageSize.Width + 2 * ThemeEngine.Current.ToolBarImageGripWidth;
417 int imgHeight = this.ImageSize.Height + 2 * ThemeEngine.Current.ToolBarImageGripWidth;
419 if (textAlignment == ToolBarTextAlign.Right) {
420 size.Width = imgWidth + size.Width;
421 size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
424 size.Height = imgHeight + size.Height;
425 size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
428 if (button.Style == ToolBarButtonStyle.DropDownButton && this.dropDownArrows)
429 size.Width += ThemeEngine.Current.ToolBarDropDownWidth;
431 return new Rectangle (button.Location, size);
433 #endregion Internal Methods
435 #region Protected Methods
436 protected override void CreateHandle ()
438 base.CreateHandle ();
441 protected override void Dispose (bool disposing)
446 base.Dispose (disposing);
449 protected virtual void OnButtonClick (ToolBarButtonClickEventArgs e)
451 if (e.Button.Style == ToolBarButtonStyle.ToggleButton) {
452 if (! e.Button.Pushed)
453 e.Button.Pushed = true;
455 e.Button.Pushed = false;
457 e.Button.pressed = false;
459 Invalidate (e.Button.Rectangle);
462 if (ButtonClick != null)
463 ButtonClick (this, e);
468 protected virtual void OnButtonDropDown (ToolBarButtonClickEventArgs e)
470 // Reset the flag set on DropDown
471 e.Button.dd_pressed = false;
473 if (ButtonDropDown != null)
474 ButtonDropDown (this, e);
476 if (e.Button.DropDownMenu == null)
479 Point loc = new Point (e.Button.Location.X + 1,
480 e.Button.Rectangle.Bottom + 2);
481 ((ContextMenu) e.Button.DropDownMenu).Show (this, loc);
484 protected override void OnFontChanged (EventArgs e)
486 base.OnFontChanged (e);
490 protected override void OnHandleCreated (EventArgs e)
492 base.OnHandleCreated (e);
495 protected override void OnResize (EventArgs e)
499 if (this.Width <= 0 || this.Height <= 0 || this.Visible == false)
505 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
507 base.SetBoundsCore (x, y, width, height, specified);
510 protected override void WndProc (ref Message m)
512 base.WndProc (ref m);
515 #endregion Protected Methods
517 #region Private Methods
518 private void ToolBar_MouseDown (object sender, MouseEventArgs me)
520 if (! this.Enabled) return;
522 Point hit = new Point (me.X, me.Y);
525 // draw the pushed button
526 foreach (ToolBarButton button in buttons) {
527 if (button.Enabled && button.Rectangle.Contains (hit)) {
528 // Mark the DropDown rect as pressed.
529 // We don't redraw the dropdown rect.
530 if (button.Style == ToolBarButtonStyle.DropDownButton) {
531 Rectangle ddRect = Rectangle.Empty;
532 Rectangle rect = button.Rectangle;
533 ddRect.Height = rect.Height;
534 ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
535 ddRect.X = rect.X + rect.Width - ddRect.Width;
537 if (ddRect.Contains (hit)) {
538 button.dd_pressed = true;
542 // If it is not dropdown then we treat it as a normal
544 button.pressed = true;
545 button.inside = true;
546 Invalidate (button.Rectangle);
553 private void ToolBar_MouseUp (object sender, MouseEventArgs me)
555 if (! this.Enabled) return;
557 Point hit = new Point (me.X, me.Y);
558 this.Capture = false;
560 // draw the normal button
561 foreach (ToolBarButton button in buttons) {
562 if (button.Enabled && button.Rectangle.Contains (hit)) {
563 if (button.Style == ToolBarButtonStyle.DropDownButton) {
564 Rectangle ddRect = Rectangle.Empty;
565 Rectangle rect = button.Rectangle;
566 ddRect.Height = rect.Height;
567 ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
568 ddRect.X = rect.X + rect.Width - ddRect.Width;
570 // Fire a ButtonDropDown event
571 if (ddRect.Contains (hit)) {
572 if (button.dd_pressed)
573 this.OnButtonDropDown (new ToolBarButtonClickEventArgs (button));
577 // Fire a ButtonClick
579 this.OnButtonClick (new ToolBarButtonClickEventArgs (button));
581 // Clear the button press flags, if any
582 else if (button.pressed) {
583 button.pressed = false;
584 Invalidate (button.Rectangle);
590 private void ToolBar_MouseLeave (object sender, EventArgs e)
592 if (! this.Enabled || appearance != ToolBarAppearance.Flat) return;
594 if (currentButton != null && currentButton.Hilight) {
595 currentButton.Hilight = false;
596 Invalidate (currentButton.Rectangle);
599 currentButton = null;
602 private void ToolBar_MouseMove (object sender, MouseEventArgs me)
604 if (! this.Enabled) return;
606 Point hit = new Point (me.X, me.Y);
609 // If the button was pressed and we leave, release the
610 // button press and vice versa
611 foreach (ToolBarButton button in buttons) {
612 if (button.pressed &&
613 (button.inside != button.Rectangle.Contains (hit))) {
614 button.inside = button.Rectangle.Contains (hit);
615 button.Hilight = false;
616 Invalidate (button.Rectangle);
622 // following is only for flat style toolbar
623 else if (appearance == ToolBarAppearance.Flat) {
624 if (currentButton != null && currentButton.Rectangle.Contains (hit)) {
625 if (currentButton.Hilight || currentButton.Pushed)
627 currentButton.Hilight = true;
628 Invalidate (currentButton.Rectangle);
632 foreach (ToolBarButton button in buttons) {
633 if (button.Rectangle.Contains (hit) && button.Enabled) {
634 currentButton = button;
635 if (currentButton.Hilight || currentButton.Pushed)
637 currentButton.Hilight = true;
638 Invalidate (currentButton.Rectangle);
641 else if (button.Hilight) {
642 button.Hilight = false;
643 Invalidate (button.Rectangle);
651 private void ToolBar_Paint (object sender, PaintEventArgs pevent)
653 if (this.Width <= 0 || this.Height <= 0 || this.Visible == false)
657 ThemeEngine.Current.DrawToolBar (pevent.Graphics, pevent.ClipRectangle, this);
662 Paint (this, pevent);
666 internal void Redraw (bool recalculate)
676 private Size CalcButtonSize ()
678 String longestText = buttons [0].Text;
679 for (int i = 1; i < buttons.Count; i++) {
680 if (buttons[i].Text.Length > longestText.Length)
681 longestText = buttons[i].Text;
684 SizeF sz = this.DeviceContext.MeasureString (longestText, this.Font);
685 Size size = new Size ((int) Math.Ceiling (sz.Width), (int) Math.Ceiling (sz.Height));
687 if (imageList != null) {
688 // adjustment for the image grip
689 int imgWidth = this.ImageSize.Width + 2 * ThemeEngine.Current.ToolBarImageGripWidth;
690 int imgHeight = this.ImageSize.Height + 2 * ThemeEngine.Current.ToolBarImageGripWidth;
692 if (textAlignment == ToolBarTextAlign.Right) {
693 size.Width = imgWidth + size.Width;
694 size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
697 size.Height = imgHeight + size.Height;
698 size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
704 /* Checks for the separators and sets the location of a button and its wrapper flag */
705 private void CalcToolBar ()
707 int wd = this.Width; // the amount of space we have for rest of the buttons
708 int ht = this.ButtonSize.Height; // all buttons are displayed with the same height
709 Point loc; // the location to place the next button, leave the space for border
710 loc = new Point (ThemeEngine.Current.ToolBarGripWidth, ThemeEngine.Current.ToolBarGripWidth);
712 // clear all the wrappers if toolbar is not wrappable
713 if (! wrappable && ! autosize) {
714 if (this.Height != this.DefaultSize.Height)
715 this.Height = this.DefaultSize.Height;
716 foreach (ToolBarButton button in buttons) {
717 button.Location = loc;
718 button.Wrapper = false;
719 loc.X = loc.X + button.Rectangle.Width;
722 else if (! wrappable) { // autosizeable
723 if (ht != this.Height)
725 foreach (ToolBarButton button in buttons) {
726 button.Location = loc;
727 button.Wrapper = false;
728 loc.X = loc.X + button.Rectangle.Width;
732 bool seenSeparator = false;
733 int separatorIndex = -1;
734 ToolBarButton button;
736 for (int i = 0; i < buttons.Count; i++) {
737 button = buttons [i];
738 if (button.Visible) {
739 if (button.Style == ToolBarButtonStyle.Separator) {
740 wd -= ThemeEngine.Current.ToolBarSeparatorWidth;
742 button.Wrapper = false; // clear the old flag in case it was set
743 button.Location = loc;
744 loc.X = loc.X + ThemeEngine.Current.ToolBarSeparatorWidth;
747 button.Wrapper = true;
748 button.Location = loc;
749 loc.X = ThemeEngine.Current.ToolBarGripWidth;
751 // we need space to draw horizontal separator
752 loc.Y = loc.Y + ThemeEngine.Current.ToolBarSeparatorWidth + ht;
754 seenSeparator = true;
758 Rectangle rect = button.Rectangle;
761 button.Wrapper = false;
762 button.Location = loc;
763 loc.X = loc.X + rect.Width;
765 else if (seenSeparator) {
766 // wrap at the separator and reassign the locations
767 i = separatorIndex; // for loop is going to increment it
768 buttons [separatorIndex].Wrapper = true;
769 seenSeparator = false;
771 loc.X = ThemeEngine.Current.ToolBarGripWidth;
772 // we need space to draw horizontal separator
773 loc.Y = loc.Y + ht + ThemeEngine.Current.ToolBarSeparatorWidth;
778 button.Wrapper = true;
782 button.Location = loc;
783 loc.X = loc.X + rect.Width;
787 else // don't consider invisible buttons
790 /* adjust the control height, if we are autosizeable */
791 if (autosize) // wrappable
792 if (this.Height != (loc.Y + ht + ThemeEngine.Current.ToolBarGripWidth))
793 this.Height = loc.Y + ht + ThemeEngine.Current.ToolBarGripWidth;
797 private void DumpToolBar (string msg)
799 Console.WriteLine (msg);
800 Console.WriteLine ("ToolBar: name: " + this.Text);
801 Console.WriteLine ("ToolBar: wd, ht: " + this.Size);
802 Console.WriteLine ("ToolBar: img size: " + this.ImageSize);
803 Console.WriteLine ("ToolBar: button sz: " + this.buttonSize);
804 Console.WriteLine ("ToolBar: textalignment: "+ this.TextAlign);
805 Console.WriteLine ("ToolBar: appearance: "+ this.Appearance);
806 Console.WriteLine ("ToolBar: wrappable: "+ this.Wrappable);
807 Console.WriteLine ("ToolBar: buttons count: " + this.Buttons.Count);
810 foreach (ToolBarButton b in buttons) {
811 Console.WriteLine ("ToolBar: button [{0}]:",i++);
815 #endregion Private Methods
818 public class ToolBarButtonCollection : IList, ICollection, IEnumerable
820 #region instance variables
821 private ArrayList buttonsList;
822 private ToolBar owner;
826 public ToolBarButtonCollection (ToolBar owner)
829 this.buttonsList = new ArrayList ();
835 public virtual int Count {
836 get { return buttonsList.Count; }
839 public virtual bool IsReadOnly {
840 get { return buttonsList.IsReadOnly; }
843 public virtual ToolBarButton this [int index] {
844 get { return (ToolBarButton) buttonsList [index]; }
846 value.SetParent (owner);
847 buttonsList [index] = value;
852 bool ICollection.IsSynchronized {
853 get { return buttonsList.IsSynchronized; }
856 object ICollection.SyncRoot {
857 get { return buttonsList.SyncRoot; }
860 bool IList.IsFixedSize {
861 get { return buttonsList.IsFixedSize; }
864 object IList.this [int index] {
865 get { return this [index]; }
867 if (! (value is ToolBarButton))
868 throw new ArgumentException("Not of type ToolBarButton", "value");
869 this [index] = (ToolBarButton) value;
875 public int Add (string text)
877 ToolBarButton button = new ToolBarButton (text);
878 return this.Add (button);
881 public int Add (ToolBarButton button)
884 button.SetParent (owner);
885 result = buttonsList.Add (button);
890 public void AddRange (ToolBarButton [] buttons)
892 foreach (ToolBarButton button in buttons)
896 public virtual void Clear ()
898 buttonsList.Clear ();
899 owner.Redraw (false);
902 public bool Contains (ToolBarButton button)
904 return buttonsList.Contains (button);
907 public virtual IEnumerator GetEnumerator ()
909 return buttonsList.GetEnumerator ();
912 void ICollection.CopyTo (Array dest, int index)
914 buttonsList.CopyTo (dest, index);
917 int IList.Add (object button)
919 if (! (button is ToolBarButton)) {
920 throw new ArgumentException("Not of type ToolBarButton", "button");
923 return this.Add ((ToolBarButton) button);
926 bool IList.Contains (object button)
928 if (! (button is ToolBarButton)) {
929 throw new ArgumentException("Not of type ToolBarButton", "button");
932 return this.Contains ((ToolBarButton) button);
935 int IList.IndexOf (object button)
937 if (! (button is ToolBarButton)) {
938 throw new ArgumentException("Not of type ToolBarButton", "button");
941 return this.IndexOf ((ToolBarButton) button);
944 void IList.Insert (int index, object button)
946 if (! (button is ToolBarButton)) {
947 throw new ArgumentException("Not of type ToolBarButton", "button");
950 this.Insert (index, (ToolBarButton) button);
953 void IList.Remove (object button)
955 if (! (button is ToolBarButton)) {
956 throw new ArgumentException("Not of type ToolBarButton", "button");
959 this.Remove ((ToolBarButton) button);
962 public int IndexOf (ToolBarButton button)
964 return buttonsList.IndexOf (button);
967 public void Insert (int index, ToolBarButton button)
969 buttonsList.Insert (index, button);
973 public void Remove (ToolBarButton button)
975 buttonsList.Remove (button);
979 public virtual void RemoveAt (int index)
981 buttonsList.RemoveAt (index);