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>
25 // Everaldo Canuto <ecanuto@novell.com>
27 // Copyright (C) 2004-2006 Novell, Inc. (http://www.novell.com)
30 using System
.Collections
;
31 using System
.ComponentModel
;
32 using System
.ComponentModel
.Design
;
34 using System
.Drawing
.Text
;
35 using System
.Drawing
.Imaging
;
36 using System
.Runtime
.InteropServices
;
38 namespace System
.Windows
.Forms
41 [ClassInterface (ClassInterfaceType
.AutoDispatch
)]
42 [DefaultEvent ("ButtonClick")]
43 [DefaultProperty ("Buttons")]
44 [Designer ("System.Windows.Forms.Design.ToolBarDesigner, " + Consts
.AssemblySystem_Design
, "System.ComponentModel.Design.IDesigner")]
45 public class ToolBar
: Control
47 #region Instance Variables
48 private bool size_specified
= false;
49 private ToolBarItem current_item
;
50 internal ToolBarItem
[] items
;
51 internal Size default_size
;
52 #endregion Instance Variables
55 static object ButtonClickEvent
= new object ();
56 static object ButtonDropDownEvent
= new object ();
59 [EditorBrowsable (EditorBrowsableState
.Always
)]
60 public new event EventHandler AutoSizeChanged
{
61 add { base.AutoSizeChanged += value; }
62 remove { base.AutoSizeChanged -= value; }
66 [EditorBrowsable (EditorBrowsableState
.Never
)]
67 public new event EventHandler BackColorChanged
{
68 add { base.BackColorChanged += value; }
69 remove { base.BackColorChanged -= value; }
73 [EditorBrowsable (EditorBrowsableState
.Never
)]
74 public new event EventHandler BackgroundImageChanged
{
75 add { base.BackgroundImageChanged += value; }
76 remove { base.BackgroundImageChanged -= value; }
80 [EditorBrowsable (EditorBrowsableState
.Never
)]
81 public new event EventHandler BackgroundImageLayoutChanged
{
82 add { base.BackgroundImageLayoutChanged += value; }
83 remove { base.BackgroundImageLayoutChanged -= value; }
86 public event ToolBarButtonClickEventHandler ButtonClick
{
87 add { Events.AddHandler (ButtonClickEvent, value); }
88 remove {Events.RemoveHandler (ButtonClickEvent, value); }
91 public event ToolBarButtonClickEventHandler ButtonDropDown
{
92 add { Events.AddHandler (ButtonDropDownEvent, value); }
93 remove {Events.RemoveHandler (ButtonDropDownEvent, value); }
97 [EditorBrowsable (EditorBrowsableState
.Never
)]
98 public new event EventHandler ForeColorChanged
{
99 add { base.ForeColorChanged += value; }
100 remove { base.ForeColorChanged -= value; }
104 [EditorBrowsable (EditorBrowsableState
.Never
)]
105 public new event EventHandler ImeModeChanged
{
106 add { base.ImeModeChanged += value; }
107 remove { base.ImeModeChanged -= value; }
111 [EditorBrowsable (EditorBrowsableState
.Never
)]
112 public new event PaintEventHandler Paint
{
113 add { base.Paint += value; }
114 remove { base.Paint -= value; }
118 [EditorBrowsable (EditorBrowsableState
.Never
)]
119 public new event EventHandler RightToLeftChanged
{
120 add { base.RightToLeftChanged += value; }
121 remove { base.RightToLeftChanged -= value; }
125 [EditorBrowsable (EditorBrowsableState
.Never
)]
126 public new event EventHandler TextChanged
{
127 add { base.TextChanged += value; }
128 remove { base.TextChanged -= value; }
135 background_color
= ThemeEngine
.Current
.DefaultControlBackColor
;
136 foreground_color
= ThemeEngine
.Current
.DefaultControlForeColor
;
137 buttons
= new ToolBarButtonCollection (this);
138 Dock
= DockStyle
.Top
;
140 GotFocus
+= new EventHandler (FocusChanged
);
141 LostFocus
+= new EventHandler (FocusChanged
);
142 MouseDown
+= new MouseEventHandler (ToolBar_MouseDown
);
143 MouseHover
+= new EventHandler (ToolBar_MouseHover
);
144 MouseLeave
+= new EventHandler (ToolBar_MouseLeave
);
145 MouseMove
+= new MouseEventHandler (ToolBar_MouseMove
);
146 MouseUp
+= new MouseEventHandler (ToolBar_MouseUp
);
147 BackgroundImageChanged
+= new EventHandler (ToolBar_BackgroundImageChanged
);
151 SetStyle (ControlStyles
.UserPaint
, false);
152 SetStyle (ControlStyles
.FixedHeight
, true);
153 SetStyle (ControlStyles
.FixedWidth
, false);
155 #endregion Constructor
157 #region protected Properties
158 protected override CreateParams CreateParams
{
160 CreateParams create_params
= base.CreateParams
;
162 if (appearance
== ToolBarAppearance
.Flat
) {
163 create_params
.Style
|= (int) ToolBarStyles
.TBSTYLE_FLAT
;
166 return create_params
;
170 protected override ImeMode DefaultImeMode
{
171 get { return ImeMode.Disable; }
174 protected override Size DefaultSize
{
175 get { return ThemeEngine.Current.ToolBarDefaultSize; }
178 [EditorBrowsable (EditorBrowsableState
.Never
)]
179 protected override bool DoubleBuffered
{
180 get { return base.DoubleBuffered; }
181 set { base.DoubleBuffered = value; }
185 ToolBarAppearance appearance
= ToolBarAppearance
.Normal
;
187 #region Public Properties
188 [DefaultValue (ToolBarAppearance
.Normal
)]
190 public ToolBarAppearance Appearance
{
191 get { return appearance; }
193 if (value == appearance
)
201 bool autosize
= true;
204 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Visible
)]
205 [EditorBrowsable (EditorBrowsableState
.Always
)]
206 [DefaultValue (true)]
208 public override bool AutoSize
{
209 get { return autosize; }
211 if (value == autosize
)
222 [EditorBrowsable (EditorBrowsableState
.Never
)]
223 public override Color BackColor
{
224 get { return background_color; }
226 if (value == background_color
)
229 background_color
= value;
230 OnBackColorChanged (EventArgs
.Empty
);
236 [EditorBrowsable (EditorBrowsableState
.Never
)]
237 public override Image BackgroundImage
{
238 get { return base.BackgroundImage; }
239 set { base.BackgroundImage = value; }
243 [EditorBrowsable (EditorBrowsableState
.Never
)]
244 public override ImageLayout BackgroundImageLayout
{
245 get { return base.BackgroundImageLayout; }
246 set { base.BackgroundImageLayout = value; }
249 [DefaultValue (BorderStyle
.None
)]
250 [DispIdAttribute (-504)]
251 public BorderStyle BorderStyle
{
252 get { return InternalBorderStyle; }
253 set { InternalBorderStyle = value; }
256 ToolBarButtonCollection buttons
;
258 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Content
)]
260 [MergableProperty (false)]
261 public ToolBarButtonCollection Buttons
{
262 get { return buttons; }
268 [RefreshProperties (RefreshProperties
.All
)]
269 public Size ButtonSize
{
271 if (!button_size
.IsEmpty
)
274 if (buttons
.Count
== 0)
275 return new Size (39, 36);
277 Size result
= CalcButtonSize ();
279 return new Size (24, 22);
284 size_specified
= value != Size
.Empty
;
285 if (button_size
== value)
295 [DefaultValue (true)]
296 public bool Divider
{
297 get { return divider; }
299 if (value == divider
)
307 [DefaultValue (DockStyle
.Top
)]
309 public override DockStyle Dock
{
310 get { return base.Dock; }
312 if (base.Dock
== value) {
313 // Call base anyways so layout_type gets set correctly
314 if (value != DockStyle
.None
)
320 SetStyle (ControlStyles
.FixedWidth
, AutoSize
);
321 SetStyle (ControlStyles
.FixedHeight
, false);
323 SetStyle (ControlStyles
.FixedHeight
, AutoSize
);
324 SetStyle (ControlStyles
.FixedWidth
, false);
333 bool drop_down_arrows
= true;
335 [DefaultValue (false)]
337 public bool DropDownArrows
{
338 get { return drop_down_arrows; }
340 if (value == drop_down_arrows
)
343 drop_down_arrows
= value;
349 [EditorBrowsable (EditorBrowsableState
.Never
)]
350 public override Color ForeColor
{
351 get { return foreground_color; }
353 if (value == foreground_color
)
356 foreground_color
= value;
357 OnForeColorChanged (EventArgs
.Empty
);
362 ImageList image_list
;
364 [DefaultValue (null)]
365 public ImageList ImageList
{
366 get { return image_list; }
368 if (image_list
== value)
376 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
377 [EditorBrowsable (EditorBrowsableState
.Advanced
)]
378 public Size ImageSize
{
380 if (ImageList
== null)
383 return ImageList
.ImageSize
;
387 // XXX this should probably go away and it should call
388 // into Control.ImeMode instead.
389 ImeMode ime_mode
= ImeMode
.Disable
;
392 [EditorBrowsable (EditorBrowsableState
.Never
)]
393 public new ImeMode ImeMode
{
394 get { return ime_mode; }
396 if (value == ime_mode
)
400 OnImeModeChanged (EventArgs
.Empty
);
405 [EditorBrowsable (EditorBrowsableState
.Never
)]
406 public override RightToLeft RightToLeft
{
407 get { return base.RightToLeft; }
409 if (value == base.RightToLeft
)
412 base.RightToLeft
= value;
413 OnRightToLeftChanged (EventArgs
.Empty
);
417 // Default value is "false" but after make a test in .NET we get "true" result as default.
418 bool show_tooltips
= true;
420 [DefaultValue (false)]
422 public bool ShowToolTips
{
423 get { return show_tooltips; }
424 set { show_tooltips = value; }
427 [DefaultValue (false)]
428 public new bool TabStop
{
429 get { return base.TabStop; }
430 set { base.TabStop = value; }
435 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
436 [EditorBrowsable (EditorBrowsableState
.Never
)]
437 public override string Text
{
438 get { return base.Text; }
440 if (value == base.Text
)
448 ToolBarTextAlign text_alignment
= ToolBarTextAlign
.Underneath
;
450 [DefaultValue (ToolBarTextAlign
.Underneath
)]
452 public ToolBarTextAlign TextAlign
{
453 get { return text_alignment; }
455 if (value == text_alignment
)
458 text_alignment
= value;
463 bool wrappable
= true;
465 [DefaultValue (true)]
467 public bool Wrappable
{
468 get { return wrappable; }
470 if (value == wrappable
)
477 #endregion Public Properties
479 #region Public Methods
480 public override string ToString ()
482 int count
= this.Buttons
.Count
;
485 return string.Format ("System.Windows.Forms.ToolBar, Buttons.Count: 0");
487 return string.Format ("System.Windows.Forms.ToolBar, Buttons.Count: {0}, Buttons[0]: {1}",
488 count
, this.Buttons
[0].ToString ());
490 #endregion Public Methods
492 #region Protected Methods
493 protected override void CreateHandle ()
495 base.CreateHandle ();
496 default_size
= CalcButtonSize ();
498 // In win32 the recalculate size only happens for not flat style
499 if (appearance
!= ToolBarAppearance
.Flat
)
503 protected override void Dispose (bool disposing
)
509 if (tipdown_timer
!= null)
510 tipdown_timer
.Dispose();
512 if (tip_window
!= null)
513 tip_window
.Dispose();
516 base.Dispose (disposing
);
519 private ToolBarButton button_for_focus
= null;
521 internal void UIAPerformClick (ToolBarButton button
)
523 ToolBarItem previous_item
= current_item
;
526 foreach (ToolBarItem item
in items
)
527 if (item
.Button
== button
) {
533 if (current_item
== null)
534 throw new ArgumentException ("button", "The button specified is not part of this toolbar");
535 PerformButtonClick (new ToolBarButtonClickEventArgs (button
));
537 current_item
= previous_item
;
541 void PerformButtonClick (ToolBarButtonClickEventArgs e
)
543 // Only change pushed for ToogleButton
544 if (e
.Button
.Style
== ToolBarButtonStyle
.ToggleButton
) {
545 if (! e
.Button
.Pushed
)
546 e
.Button
.Pushed
= true;
548 e
.Button
.Pushed
= false;
551 current_item
.Pressed
= false;
552 current_item
.Invalidate ();
554 button_for_focus
= current_item
.Button
;
555 button_for_focus
.UIAHasFocus
= true;
560 protected virtual void OnButtonClick (ToolBarButtonClickEventArgs e
)
562 ToolBarButtonClickEventHandler eh
= (ToolBarButtonClickEventHandler
)(Events
[ButtonClickEvent
]);
567 protected virtual void OnButtonDropDown (ToolBarButtonClickEventArgs e
)
569 ToolBarButtonClickEventHandler eh
= (ToolBarButtonClickEventHandler
)(Events
[ButtonDropDownEvent
]);
573 if (e
.Button
.DropDownMenu
== null)
576 ShowDropDownMenu (current_item
);
579 internal void ShowDropDownMenu (ToolBarItem item
)
581 Point loc
= new Point (item
.Rectangle
.X
+ 1, item
.Rectangle
.Bottom
+ 1);
582 ((ContextMenu
) item
.Button
.DropDownMenu
).Show (this, loc
);
584 item
.DDPressed
= false;
585 item
.Hilight
= false;
589 protected override void OnFontChanged (EventArgs e
)
591 base.OnFontChanged (e
);
595 protected override void OnHandleCreated (EventArgs e
)
597 base.OnHandleCreated (e
);
600 protected override void OnResize (EventArgs e
)
606 protected override void ScaleControl (SizeF factor
, BoundsSpecified specified
)
608 specified
&= ~BoundsSpecified
.Height
;
610 base.ScaleControl (factor
, specified
);
613 [EditorBrowsable (EditorBrowsableState
.Never
)]
614 protected override void ScaleCore (float dx
, float dy
)
618 base.ScaleCore (dx
, dy
);
621 private int requested_size
= -1;
623 protected override void SetBoundsCore (int x
, int y
, int width
, int height
, BoundsSpecified specified
)
626 if (!AutoSize
&& (requested_size
!= width
) && ((specified
& BoundsSpecified
.Width
) != BoundsSpecified
.None
))
627 requested_size
= width
;
629 if (!AutoSize
&& (requested_size
!= height
) && ((specified
& BoundsSpecified
.Height
) != BoundsSpecified
.None
))
630 requested_size
= height
;
633 base.SetBoundsCore (x
, y
, width
, height
, specified
);
636 protected override void WndProc (ref Message m
)
638 base.WndProc (ref m
);
641 internal override bool InternalPreProcessMessage (ref Message msg
)
643 if (msg
.Msg
== (int)Msg
.WM_KEYDOWN
) {
644 Keys key_data
= (Keys
)msg
.WParam
.ToInt32();
645 if (HandleKeyDown (ref msg
, key_data
))
648 return base.InternalPreProcessMessage (ref msg
);
651 #endregion Protected Methods
653 #region Private Methods
654 internal int CurrentItem
{
656 return Array
.IndexOf (items
, current_item
);
659 if (current_item
!= null)
660 current_item
.Hilight
= false;
662 current_item
= value == -1 ? null : items
[value];
664 if (current_item
!= null)
665 current_item
.Hilight
= true;
670 private void FocusChanged (object sender
, EventArgs args
)
672 if (!Focused
&& button_for_focus
!= null)
673 button_for_focus
.UIAHasFocus
= false;
674 button_for_focus
= null;
676 if (Appearance
!= ToolBarAppearance
.Flat
|| Buttons
.Count
== 0)
679 ToolBarItem prelit
= null;
680 foreach (ToolBarItem item
in items
) {
687 if (Focused
&& prelit
== null) {
688 foreach (ToolBarItem item
in items
) {
689 if (item
.Button
.Enabled
) {
694 } else if (prelit
!= null) {
695 prelit
.Hilight
= false;
699 private bool HandleKeyDown (ref Message msg
, Keys key_data
)
701 if (Appearance
!= ToolBarAppearance
.Flat
|| Buttons
.Count
== 0)
704 // Handle the key as needed if the current item is a dropdownbutton.
705 if (HandleKeyOnDropDown (ref msg
, key_data
))
711 HighlightButton (-1);
719 if (current_item
!= null) {
720 OnButtonClick (new ToolBarButtonClickEventArgs (current_item
.Button
));
729 bool HandleKeyOnDropDown (ref Message msg
, Keys key_data
)
731 if (current_item
== null || current_item
.Button
.Style
!= ToolBarButtonStyle
.DropDownButton
||
732 current_item
.Button
.DropDownMenu
== null)
735 Menu dropdown_menu
= current_item
.Button
.DropDownMenu
;
737 if (dropdown_menu
.Tracker
.active
) {
738 dropdown_menu
.ProcessCmdKey (ref msg
, key_data
);
739 return true; // always true if the menu is active
742 if (key_data
== Keys
.Up
|| key_data
== Keys
.Down
) {
743 current_item
.DDPressed
= true;
744 current_item
.Invalidate ();
745 OnButtonDropDown (new ToolBarButtonClickEventArgs (current_item
.Button
));
752 void HighlightButton (int offset
)
754 ArrayList enabled
= new ArrayList ();
757 ToolBarItem curr_item
= null;
758 foreach (ToolBarItem item
in items
) {
764 if (item
.Button
.Enabled
) {
770 int next
= (start
+ offset
) % count
;
777 if (curr_item
!= null)
778 curr_item
.Hilight
= false;
780 current_item
= enabled
[next
] as ToolBarItem
;
781 current_item
.Hilight
= true;
784 private void ToolBar_BackgroundImageChanged (object sender
, EventArgs args
)
786 Redraw (false, true);
789 private void ToolBar_MouseDown (object sender
, MouseEventArgs me
)
791 if ((!Enabled
) || ((me
.Button
& MouseButtons
.Left
) == 0))
794 Point loc
= new Point (me
.X
, me
.Y
);
796 if (ItemAtPoint (loc
) == null)
799 // Hide tooltip when left mouse button
800 if ((tip_window
!= null) && (tip_window
.Visible
) && ((me
.Button
& MouseButtons
.Left
) == MouseButtons
.Left
)) {
801 TipDownTimer
.Stop ();
802 tip_window
.Hide (this);
805 // draw the pushed button
806 foreach (ToolBarItem item
in items
) {
807 if (item
.Button
.Enabled
&& item
.Rectangle
.Contains (loc
)) {
808 // Mark the DropDown rect as pressed.
809 // We don't redraw the dropdown rect.
810 if (item
.Button
.Style
== ToolBarButtonStyle
.DropDownButton
) {
811 Rectangle rect
= item
.Rectangle
;
812 if (DropDownArrows
) {
813 rect
.Width
= ThemeEngine
.Current
.ToolBarDropDownWidth
;
814 rect
.X
= item
.Rectangle
.Right
- rect
.Width
;
817 if (rect
.Contains (loc
)) {
818 if (item
.Button
.DropDownMenu
!= null) {
819 item
.DDPressed
= true;
833 private void ToolBar_MouseUp (object sender
, MouseEventArgs me
)
835 if ((!Enabled
) || ((me
.Button
& MouseButtons
.Left
) == 0))
838 Point loc
= new Point (me
.X
, me
.Y
);
840 // draw the normal button
841 // Make a copy in case the list is modified during enumeration
842 ArrayList items
= new ArrayList (this.items
);
843 foreach (ToolBarItem item
in items
) {
844 if (item
.Button
.Enabled
&& item
.Rectangle
.Contains (loc
)) {
845 if (item
.Button
.Style
== ToolBarButtonStyle
.DropDownButton
) {
846 Rectangle ddRect
= item
.Rectangle
;
847 ddRect
.Width
= ThemeEngine
.Current
.ToolBarDropDownWidth
;
848 ddRect
.X
= item
.Rectangle
.Right
- ddRect
.Width
;
849 if (ddRect
.Contains (loc
)) {
852 OnButtonDropDown (new ToolBarButtonClickEventArgs (item
.Button
));
856 // Fire a ButtonClick
858 if ((item
.Pressed
) && ((me
.Button
& MouseButtons
.Left
) == MouseButtons
.Left
))
859 PerformButtonClick (new ToolBarButtonClickEventArgs (item
.Button
));
860 } else if (item
.Pressed
) {
861 item
.Pressed
= false;
867 private ToolBarItem
ItemAtPoint (Point pt
)
869 foreach (ToolBarItem item
in items
)
870 if (item
.Rectangle
.Contains (pt
))
876 ToolTip tip_window
= null;
877 Timer tipdown_timer
= null;
879 private void PopDownTip (object o
, EventArgs args
)
881 tip_window
.Hide (this);
884 private Timer TipDownTimer
{
886 if (tipdown_timer
== null) {
887 tipdown_timer
= new Timer ();
888 tipdown_timer
.Enabled
= false;
889 tipdown_timer
.Interval
= 5000;
890 tipdown_timer
.Tick
+= new EventHandler (PopDownTip
);
892 return tipdown_timer
;
896 private void ToolBar_MouseHover (object sender
, EventArgs e
)
901 if (tip_window
== null)
902 tip_window
= new ToolTip ();
904 ToolBarItem item
= ItemAtPoint (PointToClient (Control
.MousePosition
));
907 if (item
== null || item
.Button
.ToolTipText
.Length
== 0)
910 tip_window
.Present (this, item
.Button
.ToolTipText
);
911 TipDownTimer
.Start ();
914 private void ToolBar_MouseLeave (object sender
, EventArgs e
)
916 if (tipdown_timer
!= null)
917 tipdown_timer
.Dispose ();
918 tipdown_timer
= null;
919 if (tip_window
!= null)
920 tip_window
.Dispose ();
923 if (!Enabled
|| current_item
== null)
926 current_item
.Hilight
= false;
930 private void ToolBar_MouseMove (object sender
, MouseEventArgs me
)
935 if (tip_window
!= null && tip_window
.Visible
) {
936 TipDownTimer
.Stop ();
937 TipDownTimer
.Start ();
940 Point loc
= new Point (me
.X
, me
.Y
);
943 // If the button was pressed and we leave, release the
944 // button press and vice versa
945 foreach (ToolBarItem item
in items
) {
947 (item
.Inside
!= item
.Rectangle
.Contains (loc
))) {
948 item
.Inside
= item
.Rectangle
.Contains (loc
);
949 item
.Hilight
= false;
956 if (current_item
!= null && current_item
.Rectangle
.Contains (loc
)) {
957 if (ThemeEngine
.Current
.ToolBarHasHotElementStyles (this)) {
958 if (current_item
.Hilight
|| (!ThemeEngine
.Current
.ToolBarHasHotCheckedElementStyles
&& current_item
.Button
.Pushed
) || !current_item
.Button
.Enabled
)
960 current_item
.Hilight
= true;
963 if (tip_window
!= null) {
964 if (tip_window
.Visible
) {
965 tip_window
.Hide (this);
966 TipDownTimer
.Stop ();
968 current_item
= ItemAtPoint (loc
);
969 if (current_item
!= null && current_item
.Button
.ToolTipText
.Length
> 0) {
970 tip_window
.Present (this, current_item
.Button
.ToolTipText
);
971 TipDownTimer
.Start ();
975 if (ThemeEngine
.Current
.ToolBarHasHotElementStyles (this)) {
976 foreach (ToolBarItem item
in items
) {
977 if (item
.Rectangle
.Contains (loc
) && item
.Button
.Enabled
) {
979 if (current_item
.Hilight
|| (!ThemeEngine
.Current
.ToolBarHasHotCheckedElementStyles
&& current_item
.Button
.Pushed
))
981 current_item
.Hilight
= true;
983 else if (item
.Hilight
) {
984 item
.Hilight
= false;
991 internal override void OnPaintInternal (PaintEventArgs pevent
)
993 if (GetStyle (ControlStyles
.UserPaint
))
996 ThemeEngine
.Current
.DrawToolBar (pevent
.Graphics
, pevent
.ClipRectangle
, this);
998 // Toolbars do not raise OnPaint unless UserPaint is set
999 pevent
.Handled
= true;
1002 internal void Redraw (bool recalculate
)
1004 Redraw (recalculate
, true);
1007 internal void Redraw (bool recalculate
, bool force
)
1009 bool invalidate
= true;
1012 invalidate
= LayoutToolBar ();
1014 if (force
|| invalidate
)
1018 internal bool SizeSpecified
{
1019 get { return size_specified; }
1022 internal bool Vertical
{
1023 get { return (Dock == DockStyle.Left) || (Dock == DockStyle.Right); }
1026 internal const int text_padding
= 3;
1028 private Size
CalcButtonSize ()
1030 if (Buttons
.Count
== 0)
1033 string longest_text
= Buttons
[0].Text
;
1034 for (int i
= 1; i
< Buttons
.Count
; i
++) {
1035 if (Buttons
[i
].Text
.Length
> longest_text
.Length
)
1036 longest_text
= Buttons
[i
].Text
;
1039 Size size
= Size
.Empty
;
1040 if (longest_text
!= null && longest_text
.Length
> 0) {
1041 SizeF sz
= TextRenderer
.MeasureString (longest_text
, Font
);
1042 if (sz
!= SizeF
.Empty
)
1043 size
= new Size ((int) Math
.Ceiling (sz
.Width
) + 2 * text_padding
, (int) Math
.Ceiling (sz
.Height
));
1046 Size img_size
= ImageList
== null ? new Size (16, 16) : ImageSize
;
1048 Theme theme
= ThemeEngine
.Current
;
1049 int imgWidth
= img_size
.Width
+ 2 * theme
.ToolBarImageGripWidth
;
1050 int imgHeight
= img_size
.Height
+ 2 * theme
.ToolBarImageGripWidth
;
1052 if (text_alignment
== ToolBarTextAlign
.Right
) {
1053 size
.Width
= imgWidth
+ size
.Width
;
1054 size
.Height
= (size
.Height
> imgHeight
) ? size
.Height
: imgHeight
;
1056 size
.Height
= imgHeight
+ size
.Height
;
1057 size
.Width
= (size
.Width
> imgWidth
) ? size
.Width
: imgWidth
;
1060 size
.Width
+= theme
.ToolBarImageGripWidth
;
1061 size
.Height
+= theme
.ToolBarImageGripWidth
;
1065 // Flat toolbars disregard specified sizes. Normal toolbars grow the
1066 // button size to be at least large enough to show the image.
1067 private Size AdjustedButtonSize
{
1071 if (default_size
.IsEmpty
|| Appearance
== ToolBarAppearance
.Normal
)
1074 size
= default_size
;
1076 if (size_specified
) {
1077 if (Appearance
== ToolBarAppearance
.Flat
)
1078 size
= CalcButtonSize ();
1080 int grip
= ThemeEngine
.Current
.ToolBarImageGripWidth
;
1081 if (size
.Width
< ImageSize
.Width
+ 2 * grip
)
1082 size
.Width
= ImageSize
.Width
+ 2 * grip
;
1083 if (size
.Height
< ImageSize
.Height
+ 2 * grip
)
1084 size
.Height
= ImageSize
.Height
+ 2 * grip
;
1091 private bool LayoutToolBar ()
1093 bool changed
= false;
1094 Theme theme
= ThemeEngine
.Current
;
1095 int x
= theme
.ToolBarGripWidth
;
1096 int y
= theme
.ToolBarGripWidth
;
1098 Size adjusted_size
= AdjustedButtonSize
;
1100 int calculated_size
= (Vertical
? adjusted_size
.Width
: adjusted_size
.Height
) + theme
.ToolBarGripWidth
;
1102 int separator_index
= -1;
1104 items
= new ToolBarItem
[buttons
.Count
];
1106 for (int i
= 0; i
< buttons
.Count
; i
++) {
1107 ToolBarButton button
= buttons
[i
];
1109 ToolBarItem item
= new ToolBarItem (button
);
1112 if (!button
.Visible
)
1115 if (size_specified
&& (button
.Style
!= ToolBarButtonStyle
.Separator
))
1116 changed
= item
.Layout (adjusted_size
);
1118 changed
= item
.Layout (Vertical
, calculated_size
);
1120 bool is_separator
= button
.Style
== ToolBarButtonStyle
.Separator
;
1123 if (y
+ item
.Rectangle
.Height
< Height
|| is_separator
|| !Wrappable
) {
1124 if (item
.Location
.X
!= x
|| item
.Location
.Y
!= y
)
1126 item
.Location
= new Point (x
, y
);
1127 y
+= item
.Rectangle
.Height
;
1129 separator_index
= i
;
1130 } else if (separator_index
> 0) {
1131 i
= separator_index
;
1132 separator_index
= -1;
1133 y
= theme
.ToolBarGripWidth
;
1134 x
+= calculated_size
;
1136 y
= theme
.ToolBarGripWidth
;
1137 x
+= calculated_size
;
1138 if (item
.Location
.X
!= x
|| item
.Location
.Y
!= y
)
1140 item
.Location
= new Point (x
, y
);
1141 y
+= item
.Rectangle
.Height
;
1144 if (x
+ item
.Rectangle
.Width
< Width
|| is_separator
|| !Wrappable
) {
1145 if (item
.Location
.X
!= x
|| item
.Location
.Y
!= y
)
1147 item
.Location
= new Point (x
, y
);
1148 x
+= item
.Rectangle
.Width
;
1150 separator_index
= i
;
1151 } else if (separator_index
> 0) {
1152 i
= separator_index
;
1153 separator_index
= -1;
1154 x
= theme
.ToolBarGripWidth
;
1155 y
+= calculated_size
;
1157 x
= theme
.ToolBarGripWidth
;
1158 y
+= calculated_size
;
1159 if (item
.Location
.X
!= x
|| item
.Location
.Y
!= y
)
1161 item
.Location
= new Point (x
, y
);
1162 x
+= item
.Rectangle
.Width
;
1171 calculated_size
+= Vertical
? x
: y
;
1173 if (IsHandleCreated
) {
1175 Width
= calculated_size
;
1177 Height
= calculated_size
;
1182 #endregion Private Methods
1185 public class ToolBarButtonCollection
: IList
, ICollection
, IEnumerable
1187 #region instance variables
1188 private ArrayList list
; // ToolBarButton list
1189 private ToolBar owner
; // ToolBar associated to Collection
1190 private bool redraw
; // Flag if needs to redraw after add/remove operations
1193 #region UIA Framework Events
1194 static object UIACollectionChangedEvent
= new object ();
1196 internal event CollectionChangeEventHandler UIACollectionChanged
{
1197 add { owner.Events.AddHandler (UIACollectionChangedEvent, value); }
1198 remove { owner.Events.RemoveHandler (UIACollectionChangedEvent, value); }
1201 internal void OnUIACollectionChanged (CollectionChangeEventArgs e
)
1203 CollectionChangeEventHandler eh
1204 = (CollectionChangeEventHandler
) owner
.Events
[UIACollectionChangedEvent
];
1210 #region constructors
1211 public ToolBarButtonCollection (ToolBar owner
)
1213 this.list
= new ArrayList ();
1222 get { return list.Count; }
1225 public bool IsReadOnly
{
1226 get { return list.IsReadOnly; }
1229 public virtual ToolBarButton
this [int index
] {
1230 get { return (ToolBarButton) list [index]; }
1232 // UIA Framework Event: Button Removed
1233 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction
.Remove
, index
));
1235 value.SetParent (owner
);
1236 list
[index
] = value;
1237 owner
.Redraw (true);
1239 // UIA Framework Event: Button Added
1240 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction
.Add
, index
));
1244 public virtual ToolBarButton
this[string key
] {
1246 if (string.IsNullOrEmpty (key
))
1249 foreach (ToolBarButton b
in list
)
1250 if (string.Compare (b
.Name
, key
, true) == 0)
1257 bool ICollection
.IsSynchronized
{
1258 get { return list.IsSynchronized; }
1261 object ICollection
.SyncRoot
{
1262 get { return list.SyncRoot; }
1265 bool IList
.IsFixedSize
{
1266 get { return list.IsFixedSize; }
1269 object IList
.this [int index
] {
1270 get { return this [index]; }
1272 if (! (value is ToolBarButton
))
1273 throw new ArgumentException("Not of type ToolBarButton", "value");
1274 this [index
] = (ToolBarButton
) value;
1280 public int Add (string text
)
1282 ToolBarButton button
= new ToolBarButton (text
);
1283 return this.Add (button
);
1286 public int Add (ToolBarButton button
)
1289 button
.SetParent (owner
);
1290 result
= list
.Add (button
);
1292 owner
.Redraw (true);
1294 // UIA Framework Event: Button Added
1295 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction
.Add
, result
));
1300 public void AddRange (ToolBarButton
[] buttons
)
1304 foreach (ToolBarButton button
in buttons
)
1309 owner
.Redraw (true);
1313 public void Clear ()
1316 owner
.Redraw (false);
1318 // UIA Framework Event: Button Cleared
1319 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction
.Refresh
, -1));
1322 public bool Contains (ToolBarButton button
)
1324 return list
.Contains (button
);
1327 public virtual bool ContainsKey (string key
)
1329 return !(this[key
] == null);
1332 public IEnumerator
GetEnumerator ()
1334 return list
.GetEnumerator ();
1337 void ICollection
.CopyTo (Array dest
, int index
)
1339 list
.CopyTo (dest
, index
);
1342 int IList
.Add (object button
)
1344 if (! (button
is ToolBarButton
)) {
1345 throw new ArgumentException("Not of type ToolBarButton", "button");
1348 return this.Add ((ToolBarButton
) button
);
1351 bool IList
.Contains (object button
)
1353 if (! (button
is ToolBarButton
)) {
1354 throw new ArgumentException("Not of type ToolBarButton", "button");
1357 return this.Contains ((ToolBarButton
) button
);
1360 int IList
.IndexOf (object button
)
1362 if (! (button
is ToolBarButton
)) {
1363 throw new ArgumentException("Not of type ToolBarButton", "button");
1366 return this.IndexOf ((ToolBarButton
) button
);
1369 void IList
.Insert (int index
, object button
)
1371 if (! (button
is ToolBarButton
)) {
1372 throw new ArgumentException("Not of type ToolBarButton", "button");
1375 this.Insert (index
, (ToolBarButton
) button
);
1378 void IList
.Remove (object button
)
1380 if (! (button
is ToolBarButton
)) {
1381 throw new ArgumentException("Not of type ToolBarButton", "button");
1384 this.Remove ((ToolBarButton
) button
);
1387 public int IndexOf (ToolBarButton button
)
1389 return list
.IndexOf (button
);
1392 public virtual int IndexOfKey (string key
)
1394 return IndexOf (this[key
]);
1397 public void Insert (int index
, ToolBarButton button
)
1399 list
.Insert (index
, button
);
1400 owner
.Redraw (true);
1402 // UIA Framework Event: Button Added
1403 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction
.Add
, index
));
1406 public void Remove (ToolBarButton button
)
1408 list
.Remove (button
);
1409 owner
.Redraw (true);
1412 public void RemoveAt (int index
)
1414 list
.RemoveAt (index
);
1415 owner
.Redraw (true);
1417 // UIA Framework Event: Button Removed
1418 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction
.Remove
, index
));
1421 public virtual void RemoveByKey (string key
)
1432 // Because same button can be added to toolbar multiple times, we need to maintain
1433 // a list of button information for each positions.
1434 internal class ToolBarItem
: Component
1436 #region Instance variables
1438 private ToolBar toolbar
; // Parent toolbar
1439 private ToolBarButton button
; // Associated toolBar button
1440 private Rectangle bounds
; // Toolbar button bounds
1441 private Rectangle image_rect
; // Image button bounds
1442 private Rectangle text_rect
; // Text button bounds
1444 private bool dd_pressed
= false; // to check for a mouse down on dropdown rect
1445 private bool inside
= false; // to handle the mouse move event with mouse pressed
1446 private bool hilight
= false; // to hilight buttons in flat style
1447 private bool pressed
= false; // this is to check for mouse down on a button
1451 #region Constructors
1453 public ToolBarItem (ToolBarButton button
)
1455 this.toolbar
= button
.Parent
;
1456 this.button
= button
;
1459 #endregion Constructors
1463 public ToolBarButton Button
{
1464 get { return this.button; }
1467 public Rectangle Rectangle
{
1469 if (!button
.Visible
|| toolbar
== null)
1470 return Rectangle
.Empty
;
1472 if (button
.Style
== ToolBarButtonStyle
.DropDownButton
&& toolbar
.DropDownArrows
) {
1473 Rectangle result
= bounds
;
1474 result
.Width
+= ThemeEngine
.Current
.ToolBarDropDownWidth
;
1480 set { this.bounds = value; }
1483 public Point Location
{
1484 get { return bounds.Location; }
1485 set { bounds.Location = value; }
1488 public Rectangle ImageRectangle
{
1490 Rectangle result
= image_rect
;
1491 result
.X
+= bounds
.X
;
1492 result
.Y
+= bounds
.Y
;
1497 public Rectangle TextRectangle
{
1499 Rectangle result
= text_rect
;
1500 result
.X
+= bounds
.X
;
1501 result
.Y
+= bounds
.Y
;
1506 private Size TextSize
{
1508 StringFormat text_format
= new StringFormat ();
1509 text_format
.HotkeyPrefix
= HotkeyPrefix
.Hide
;
1511 SizeF sz
= TextRenderer
.MeasureString (button
.Text
, toolbar
.Font
, SizeF
.Empty
, text_format
);
1512 if (sz
== SizeF
.Empty
)
1514 return new Size ((int) Math
.Ceiling (sz
.Width
) + 2 * ToolBar
.text_padding
, (int) Math
.Ceiling (sz
.Height
));
1518 public bool Pressed
{
1519 get { return (pressed && inside); }
1520 set { pressed = value; }
1523 public bool DDPressed
{
1524 get { return dd_pressed; }
1525 set { dd_pressed = value; }
1528 public bool Inside
{
1529 get { return inside; }
1530 set { inside = value; }
1533 public bool Hilight
{
1534 get { return hilight; }
1536 if (hilight
== value)
1544 #endregion Properties
1548 public Size
CalculateSize ()
1550 Theme theme
= ThemeEngine
.Current
;
1552 int ht
= toolbar
.ButtonSize
.Height
+ 2 * theme
.ToolBarGripWidth
;
1554 if (button
.Style
== ToolBarButtonStyle
.Separator
)
1555 return new Size (theme
.ToolBarSeparatorWidth
, ht
);
1558 if (TextSize
.IsEmpty
&& (button
.Image
== null))
1559 size
= toolbar
.default_size
;
1563 Size image_size
= (toolbar
.ImageSize
== Size
.Empty
) ? new Size (16, 16) : toolbar
.ImageSize
;
1565 int image_width
= image_size
.Width
+ 2 * theme
.ToolBarImageGripWidth
;
1566 int image_height
= image_size
.Height
+ 2 * theme
.ToolBarImageGripWidth
;
1568 if (toolbar
.TextAlign
== ToolBarTextAlign
.Right
) {
1569 size
.Width
= image_width
+ size
.Width
;
1570 size
.Height
= (size
.Height
> image_height
) ? size
.Height
: image_height
;
1572 size
.Height
= image_height
+ size
.Height
;
1573 size
.Width
= (size
.Width
> image_width
) ? size
.Width
: image_width
;
1576 size
.Width
+= theme
.ToolBarGripWidth
;
1577 size
.Height
+= theme
.ToolBarGripWidth
;
1582 public bool Layout (bool vertical
, int calculated_size
)
1584 if (toolbar
== null || !button
.Visible
)
1587 Size psize
= toolbar
.ButtonSize
;
1589 if ((!toolbar
.SizeSpecified
) || (button
.Style
== ToolBarButtonStyle
.Separator
)) {
1590 size
= CalculateSize ();
1592 if (size
.Width
== 0 || size
.Height
== 0)
1596 size
.Width
= calculated_size
;
1598 size
.Height
= calculated_size
;
1600 return Layout (size
);
1603 public bool Layout (Size size
)
1605 if (toolbar
== null || !button
.Visible
)
1610 Size image_size
= (toolbar
.ImageSize
== Size
.Empty
) ? new Size (16, 16) : toolbar
.ImageSize
;
1611 int grip
= ThemeEngine
.Current
.ToolBarImageGripWidth
;
1613 Rectangle new_image_rect
, new_text_rect
;
1615 if (toolbar
.TextAlign
== ToolBarTextAlign
.Underneath
) {
1616 new_image_rect
= new Rectangle ((bounds
.Size
.Width
- image_size
.Width
) / 2 - grip
, 0, image_size
.Width
+ 2 + grip
, image_size
.Height
+ 2 * grip
);
1617 new_text_rect
= new Rectangle (0, new_image_rect
.Height
, bounds
.Size
.Width
, bounds
.Size
.Height
- new_image_rect
.Height
- 2 * grip
);
1619 new_image_rect
= new Rectangle (0, 0, image_size
.Width
+ 2 * grip
, image_size
.Height
+ 2 * grip
);
1620 new_text_rect
= new Rectangle (new_image_rect
.Width
, 0, bounds
.Size
.Width
- new_image_rect
.Width
, bounds
.Size
.Height
- 2 * grip
);
1623 bool changed
= false;
1625 if (new_image_rect
!= image_rect
|| new_text_rect
!= text_rect
)
1628 image_rect
= new_image_rect
;
1629 text_rect
= new_text_rect
;
1634 public void Invalidate ()
1636 if (toolbar
!= null)
1637 toolbar
.Invalidate (Rectangle
);