2 // ToolStripSplitButton.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.
23 // Copyright (c) 2006 Jonathan Pobst
26 // Jonathan Pobst (monkey@jpobst.com)
31 using System.ComponentModel;
32 using System.Windows.Forms.Design;
34 namespace System.Windows.Forms
36 [DefaultEvent ("ButtonClick")]
37 [ToolStripItemDesignerAvailability (ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)]
38 public class ToolStripSplitButton : ToolStripDropDownItem
40 private bool button_pressed;
41 private ToolStripItem default_item;
42 private bool drop_down_button_selected;
43 private int drop_down_button_width;
45 #region Public Constructors
46 public ToolStripSplitButton()
47 : this (string.Empty, null, null, string.Empty)
51 public ToolStripSplitButton (Image image)
52 : this (string.Empty, image, null, string.Empty)
56 public ToolStripSplitButton (string text)
57 : this (text, null, null, string.Empty)
61 public ToolStripSplitButton (string text, Image image)
62 : this (text, image, null, string.Empty)
66 public ToolStripSplitButton (string text, Image image, EventHandler onClick)
67 : this (text, image, onClick, string.Empty)
71 public ToolStripSplitButton (string text, Image image, params ToolStripItem[] dropDownItems)
72 : base (text, image, dropDownItems)
74 this.ResetDropDownButtonWidth ();
77 public ToolStripSplitButton (string text, Image image, EventHandler onClick, string name)
78 : base (text, image, onClick, name)
80 this.ResetDropDownButtonWidth ();
84 #region Public Properties
86 public new bool AutoToolTip {
87 get { return base.AutoToolTip; }
88 set { base.AutoToolTip = value; }
92 public Rectangle ButtonBounds {
93 get { return new Rectangle (Bounds.Left, Bounds.Top, this.Bounds.Width - this.drop_down_button_width - 1, this.Height); }
97 public bool ButtonPressed {
98 get { return this.button_pressed; }
102 public bool ButtonSelected {
103 get { return base.Selected; }
107 [DefaultValue (null)]
108 public ToolStripItem DefaultItem {
109 get { return this.default_item; }
111 if (this.default_item != value) {
112 this.default_item = value;
113 this.OnDefaultItemChanged (EventArgs.Empty);
119 public Rectangle DropDownButtonBounds {
120 get { return new Rectangle (this.Bounds.Right - this.drop_down_button_width, 0, this.drop_down_button_width, this.Bounds.Height); }
124 public bool DropDownButtonPressed {
125 get { return this.drop_down_button_selected || (this.HasDropDownItems && this.DropDown.Visible); }
129 public bool DropDownButtonSelected {
130 get { return base.Selected; }
133 public int DropDownButtonWidth {
134 get { return this.drop_down_button_width; }
137 throw new ArgumentOutOfRangeException ();
138 if (this.drop_down_button_width != value) {
139 this.drop_down_button_width = value;
140 CalculateAutoSize ();
146 public Rectangle SplitterBounds {
147 get { return new Rectangle (this.Bounds.Width - this.drop_down_button_width - 1, 0, 1, this.Height); }
151 #region Protected Properties
152 protected override bool DefaultAutoToolTip {
156 protected internal override bool DismissWhenClicked {
161 #region Public Methods
162 public override Size GetPreferredSize (Size constrainingSize)
164 // base should calculate the button part for us, add the splitter
165 // and drop down arrow part to that
166 Size s = base.GetPreferredSize (constrainingSize);
171 // If we are a fixed size, we can't add more in for the drop down
172 // button, but we can for autosize
174 s.Width += (this.drop_down_button_width - 2);
179 public virtual void OnButtonDoubleClick (EventArgs e)
181 EventHandler eh = (EventHandler)(Events [ButtonDoubleClickEvent]);
186 public void PerformButtonClick ()
189 this.OnButtonClick (EventArgs.Empty);
192 [EditorBrowsable (EditorBrowsableState.Never)]
193 public virtual void ResetDropDownButtonWidth ()
195 this.DropDownButtonWidth = 11;
199 #region Protected Methods
200 protected override AccessibleObject CreateAccessibilityInstance ()
202 return new ToolStripSplitButtonAccessibleObject (this);
205 protected override ToolStripDropDown CreateDefaultDropDown ()
207 ToolStripDropDownMenu tsddm = new ToolStripDropDownMenu ();
208 tsddm.OwnerItem = this;
212 protected virtual void OnButtonClick (EventArgs e)
214 EventHandler eh = (EventHandler)Events [ButtonClickEvent];
219 protected virtual void OnDefaultItemChanged (EventArgs e)
221 EventHandler eh = (EventHandler)Events [DefaultItemChangedEvent];
226 protected override void OnMouseDown (MouseEventArgs e)
228 if (this.ButtonBounds.Contains (e.Location))
230 this.button_pressed = true;
232 base.OnMouseDown (e);
234 else if (this.DropDownButtonBounds.Contains (e.Location))
236 if (this.DropDown.Visible)
237 this.HideDropDown (ToolStripDropDownCloseReason.ItemClicked);
239 this.ShowDropDown ();
242 base.OnMouseDown (e);
246 protected override void OnMouseLeave (EventArgs e)
248 this.drop_down_button_selected = false;
249 this.button_pressed = false;
253 base.OnMouseLeave (e);
256 protected override void OnMouseUp (MouseEventArgs e)
258 this.button_pressed = false;
264 protected override void OnPaint (PaintEventArgs e)
268 if (this.Owner != null) {
269 Color font_color = this.Enabled ? this.ForeColor : SystemColors.GrayText;
270 Image draw_image = this.Enabled ? this.Image : ToolStripRenderer.CreateDisabledImage (this.Image);
272 this.Owner.Renderer.DrawSplitButton (new System.Windows.Forms.ToolStripItemRenderEventArgs (e.Graphics, this));
274 Rectangle text_layout_rect;
275 Rectangle image_layout_rect;
277 Rectangle r = this.ContentRectangle;
278 r.Width -= (this.drop_down_button_width + 1);
280 this.CalculateTextAndImageRectangles (r, out text_layout_rect, out image_layout_rect);
282 if (text_layout_rect != Rectangle.Empty)
283 this.Owner.Renderer.DrawItemText (new System.Windows.Forms.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, font_color, this.Font, this.TextAlign));
284 if (image_layout_rect != Rectangle.Empty)
285 this.Owner.Renderer.DrawItemImage (new System.Windows.Forms.ToolStripItemImageRenderEventArgs (e.Graphics, this, draw_image, image_layout_rect));
287 this.Owner.Renderer.DrawArrow (new ToolStripArrowRenderEventArgs (e.Graphics, this, new Rectangle (this.Width - 9, 1, 6, this.Height), Color.Black, ArrowDirection.Down));
293 protected override void OnRightToLeftChanged (EventArgs e)
295 base.OnRightToLeftChanged (e);
298 protected internal override bool ProcessDialogKey (Keys keyData)
300 if (this.Selected && keyData == Keys.Enter && this.DefaultItem != null) {
301 this.DefaultItem.FireEvent (EventArgs.Empty, ToolStripItemEventType.Click);
305 return base.ProcessDialogKey (keyData);
308 protected internal override bool ProcessMnemonic (char charCode)
311 this.Parent.ChangeSelection (this);
313 if (this.HasDropDownItems)
314 this.ShowDropDown ();
316 this.PerformClick ();
322 #region Internal Methods
323 internal override void HandleClick (int mouse_clicks, EventArgs e)
325 base.HandleClick (mouse_clicks, e);
327 MouseEventArgs mea = e as MouseEventArgs;
330 if (ButtonBounds.Contains (mea.Location))
331 OnButtonClick (EventArgs.Empty);
335 #region Public Events
336 static object ButtonClickEvent = new object ();
337 static object ButtonDoubleClickEvent = new object ();
338 static object DefaultItemChangedEvent = new object ();
340 public event EventHandler ButtonClick {
341 add { Events.AddHandler (ButtonClickEvent, value); }
342 remove {Events.RemoveHandler (ButtonClickEvent, value); }
344 public event EventHandler ButtonDoubleClick {
345 add { Events.AddHandler (ButtonDoubleClickEvent, value); }
346 remove {Events.RemoveHandler (ButtonDoubleClickEvent, value); }
348 public event EventHandler DefaultItemChanged {
349 add { Events.AddHandler (DefaultItemChangedEvent, value); }
350 remove {Events.RemoveHandler (DefaultItemChangedEvent, value); }
354 #region ToolStripSplitButtonAccessibleObject Class
355 public class ToolStripSplitButtonAccessibleObject : ToolStripItemAccessibleObject
357 #region Public Constructor
358 public ToolStripSplitButtonAccessibleObject (ToolStripSplitButton item) : base (item)
363 #region Public Method
364 public override void DoDefaultAction ()
366 (owner_item as ToolStripSplitButton).PerformButtonClick ();