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.Runtime.InteropServices;
34 namespace System.Windows.Forms
36 [ClassInterface (ClassInterfaceType.AutoDispatch)]
38 public class MenuStrip : ToolStrip
40 private ToolStripMenuItem mdi_window_list_item;
42 public MenuStrip () : base ()
44 base.CanOverflow = false;
45 this.GripStyle = ToolStripGripStyle.Hidden;
47 this.Dock = DockStyle.Top;
50 #region Public Properties
51 [DefaultValue (false)]
53 public new bool CanOverflow {
54 get { return base.CanOverflow; }
55 set { base.CanOverflow = value; }
58 [DefaultValue (ToolStripGripStyle.Hidden)]
59 public new ToolStripGripStyle GripStyle {
60 get { return base.GripStyle; }
61 set { base.GripStyle = value; }
65 [MergableProperty (false)]
66 [TypeConverter (typeof (MdiWindowListItemConverter))]
67 public ToolStripMenuItem MdiWindowListItem {
68 get { return this.mdi_window_list_item; }
70 if (this.mdi_window_list_item != value) {
71 this.mdi_window_list_item = value;
72 this.RefreshMdiItems ();
77 [DefaultValue (false)]
78 public new bool ShowItemToolTips {
79 get { return base.ShowItemToolTips; }
80 set { base.ShowItemToolTips = value; }
84 public new bool Stretch {
85 get { return base.Stretch; }
86 set { base.Stretch = value; }
90 #region Protected Properties
91 protected override Padding DefaultGripMargin { get { return new Padding (2, 2, 0, 2); } }
92 protected override Padding DefaultPadding { get { return new Padding (6, 2, 0, 2); } }
93 protected override bool DefaultShowItemToolTips { get { return false; } }
94 protected override Size DefaultSize { get { return new Size (200, 24); } }
97 #region Protected Methods
98 protected override AccessibleObject CreateAccessibilityInstance ()
100 return new MenuStripAccessibleObject ();
103 protected internal override ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick)
105 return new ToolStripMenuItem (text, image, onClick);
108 protected virtual void OnMenuActivate (EventArgs e)
110 EventHandler eh = (EventHandler)(Events [MenuActivateEvent]);
115 protected virtual void OnMenuDeactivate (EventArgs e)
117 EventHandler eh = (EventHandler)(Events [MenuDeactivateEvent]);
122 protected override bool ProcessCmdKey (ref Message m, Keys keyData)
124 return base.ProcessCmdKey (ref m, keyData);
127 protected override void WndProc (ref Message m)
129 base.WndProc (ref m);
133 #region Public Events
134 static object MenuActivateEvent = new object ();
135 static object MenuDeactivateEvent = new object ();
137 public event EventHandler MenuActivate {
138 add { Events.AddHandler (MenuActivateEvent, value); }
139 remove { Events.RemoveHandler (MenuActivateEvent, value); }
142 public event EventHandler MenuDeactivate {
143 add { Events.AddHandler (MenuDeactivateEvent, value); }
144 remove { Events.RemoveHandler (MenuDeactivateEvent, value); }
148 #region Internal Properties
149 internal override bool KeyboardActive {
150 get { return base.KeyboardActive; }
152 if (base.KeyboardActive != value) {
153 base.KeyboardActive = value;
156 this.OnMenuActivate (EventArgs.Empty);
158 this.OnMenuDeactivate (EventArgs.Empty);
163 internal bool MenuDroppedDown {
164 get { return this.menu_selected; }
165 set { this.menu_selected = value; }
169 #region Internal Methods
170 internal override void Dismiss (ToolStripDropDownCloseReason reason)
172 // Make sure we don't auto-dropdown next time we're activated
173 this.MenuDroppedDown = false;
175 base.Dismiss (reason);
178 internal void FireMenuActivate ()
180 // The tracker lets us know when the form is clicked or loses focus
181 ToolStripManager.AppClicked += new EventHandler (ToolStripMenuTracker_AppClicked);
182 ToolStripManager.AppFocusChange += new EventHandler (ToolStripMenuTracker_AppFocusChange);
184 this.OnMenuActivate (EventArgs.Empty);
187 internal void FireMenuDeactivate ()
189 // Detach from the tracker
190 ToolStripManager.AppClicked -= new EventHandler (ToolStripMenuTracker_AppClicked); ;
191 ToolStripManager.AppFocusChange -= new EventHandler (ToolStripMenuTracker_AppFocusChange);
193 this.OnMenuDeactivate (EventArgs.Empty);
196 internal override bool OnMenuKey ()
198 // Set ourselves active and select our first item
199 ToolStripManager.SetActiveToolStrip (this, true);
200 ToolStripItem tsi = this.SelectNextToolStripItem (null, true);
205 if (tsi is MdiControlStrip.SystemMenuItem)
206 this.SelectNextToolStripItem (tsi, true);
211 private void ToolStripMenuTracker_AppFocusChange (object sender, EventArgs e)
213 this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppFocusChange);
216 private void ToolStripMenuTracker_AppClicked (object sender, EventArgs e)
218 this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppClicked);
221 internal void RefreshMdiItems ()
223 if (this.mdi_window_list_item == null)
226 Form parent_form = this.FindForm ();
228 if (parent_form == null || parent_form.MainMenuStrip != this)
231 MdiClient mdi = parent_form.MdiContainer;
233 // If there isn't a MdiContainer, we don't need to worry about MdiItems :)
237 // Make a copy so we can delete from the real one
238 ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count];
239 this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0);
241 // If the mdi child has been removed, remove our menu item
242 foreach (ToolStripItem tsi in loopitems)
243 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
244 if (!mdi.mdi_child_list.Contains ((tsi as ToolStripMenuItem).MdiClientForm) || !(tsi as ToolStripMenuItem).MdiClientForm.Visible)
245 this.mdi_window_list_item.DropDownItems.Remove (tsi);
247 // Add the new forms and update state
248 for (int i = 0; i < mdi.mdi_child_list.Count; i++) {
249 Form mdichild = (Form)mdi.mdi_child_list[i];
250 ToolStripMenuItem tsi;
252 if (!mdichild.Visible)
255 if ((tsi = FindMdiMenuItemOfForm (mdichild)) == null) {
256 if (CountMdiMenuItems () == 0 && this.mdi_window_list_item.DropDownItems.Count > 0 && !(this.mdi_window_list_item.DropDownItems[this.mdi_window_list_item.DropDownItems.Count - 1] is ToolStripSeparator))
257 this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ());
259 tsi = new ToolStripMenuItem ();
260 tsi.MdiClientForm = mdichild;
261 this.mdi_window_list_item.DropDownItems.Add (tsi);
264 tsi.Text = string.Format ("&{0} {1}", i + 1, mdichild.Text);
265 tsi.Checked = parent_form.ActiveMdiChild == mdichild;
268 // Check that everything is in the correct order
269 if (NeedToReorderMdi ())
273 private ToolStripMenuItem FindMdiMenuItemOfForm (Form f)
275 // Not terribly efficient, but Mdi window lists shouldn't get too big
276 foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems)
277 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).MdiClientForm == f)
278 return (ToolStripMenuItem)tsi;
283 private int CountMdiMenuItems ()
287 foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems)
288 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
294 private bool NeedToReorderMdi ()
296 // Mdi menus must be: User Items, Separator, Mdi Items
297 bool seenMdi = false;
299 foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems) {
300 if (tsi is ToolStripMenuItem) {
301 if (!(tsi as ToolStripMenuItem).IsMdiWindowListEntry) {
312 private void ReorderMdiMenu ()
314 ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count];
315 this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0);
317 this.mdi_window_list_item.DropDownItems.Clear ();
319 foreach (ToolStripItem tsi in loopitems)
320 if (tsi is ToolStripSeparator || !(tsi as ToolStripMenuItem).IsMdiWindowListEntry)
321 this.mdi_window_list_item.DropDownItems.Add (tsi);
323 int count = this.mdi_window_list_item.DropDownItems.Count;
325 if (count > 0 && !(this.mdi_window_list_item.DropDownItems[count - 1] is ToolStripSeparator))
326 this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ());
328 foreach (ToolStripItem tsi in loopitems)
329 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
330 this.mdi_window_list_item.DropDownItems.Add (tsi);
334 #region MenuStripAccessibleObject
335 private class MenuStripAccessibleObject : AccessibleObject
342 #region MdiWindowListItemConverter
343 internal class MdiWindowListItemConverter : TypeConverter