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);
177 this.FireMenuDeactivate ();
180 internal void FireMenuActivate ()
182 // The tracker lets us know when the form is clicked or loses focus
183 ToolStripManager.AppClicked += new EventHandler (ToolStripMenuTracker_AppClicked);
184 ToolStripManager.AppFocusChange += new EventHandler (ToolStripMenuTracker_AppFocusChange);
186 this.OnMenuActivate (EventArgs.Empty);
189 internal void FireMenuDeactivate ()
191 // Detach from the tracker
192 ToolStripManager.AppClicked -= new EventHandler (ToolStripMenuTracker_AppClicked); ;
193 ToolStripManager.AppFocusChange -= new EventHandler (ToolStripMenuTracker_AppFocusChange);
195 this.OnMenuDeactivate (EventArgs.Empty);
198 internal override bool OnMenuKey ()
200 // Set ourselves active and select our first item
201 ToolStripManager.SetActiveToolStrip (this, true);
202 ToolStripItem tsi = this.SelectNextToolStripItem (null, true);
207 if (tsi is MdiControlStrip.SystemMenuItem)
208 this.SelectNextToolStripItem (tsi, true);
213 private void ToolStripMenuTracker_AppFocusChange (object sender, EventArgs e)
215 this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppFocusChange);
218 private void ToolStripMenuTracker_AppClicked (object sender, EventArgs e)
220 this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppClicked);
223 internal void RefreshMdiItems ()
225 if (this.mdi_window_list_item == null)
228 Form parent_form = this.FindForm ();
230 if (parent_form == null || parent_form.MainMenuStrip != this)
233 MdiClient mdi = parent_form.MdiContainer;
235 // If there isn't a MdiContainer, we don't need to worry about MdiItems :)
239 // Make a copy so we can delete from the real one
240 ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count];
241 this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0);
243 // If the mdi child has been removed, remove our menu item
244 foreach (ToolStripItem tsi in loopitems)
245 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
246 if (!mdi.mdi_child_list.Contains ((tsi as ToolStripMenuItem).MdiClientForm) || !(tsi as ToolStripMenuItem).MdiClientForm.Visible)
247 this.mdi_window_list_item.DropDownItems.Remove (tsi);
249 // Add the new forms and update state
250 for (int i = 0; i < mdi.mdi_child_list.Count; i++) {
251 Form mdichild = (Form)mdi.mdi_child_list[i];
252 ToolStripMenuItem tsi;
254 if (!mdichild.Visible)
257 if ((tsi = FindMdiMenuItemOfForm (mdichild)) == null) {
258 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))
259 this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ());
261 tsi = new ToolStripMenuItem ();
262 tsi.MdiClientForm = mdichild;
263 this.mdi_window_list_item.DropDownItems.Add (tsi);
266 tsi.Text = string.Format ("&{0} {1}", i + 1, mdichild.Text);
267 tsi.Checked = parent_form.ActiveMdiChild == mdichild;
270 // Check that everything is in the correct order
271 if (NeedToReorderMdi ())
275 private ToolStripMenuItem FindMdiMenuItemOfForm (Form f)
277 // Not terribly efficient, but Mdi window lists shouldn't get too big
278 foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems)
279 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).MdiClientForm == f)
280 return (ToolStripMenuItem)tsi;
285 private int CountMdiMenuItems ()
289 foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems)
290 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
296 private bool NeedToReorderMdi ()
298 // Mdi menus must be: User Items, Separator, Mdi Items
299 bool seenMdi = false;
301 foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems) {
302 if (tsi is ToolStripMenuItem) {
303 if (!(tsi as ToolStripMenuItem).IsMdiWindowListEntry) {
314 private void ReorderMdiMenu ()
316 ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count];
317 this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0);
319 this.mdi_window_list_item.DropDownItems.Clear ();
321 foreach (ToolStripItem tsi in loopitems)
322 if (tsi is ToolStripSeparator || !(tsi as ToolStripMenuItem).IsMdiWindowListEntry)
323 this.mdi_window_list_item.DropDownItems.Add (tsi);
325 int count = this.mdi_window_list_item.DropDownItems.Count;
327 if (count > 0 && !(this.mdi_window_list_item.DropDownItems[count - 1] is ToolStripSeparator))
328 this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ());
330 foreach (ToolStripItem tsi in loopitems)
331 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
332 this.mdi_window_list_item.DropDownItems.Add (tsi);
336 #region MenuStripAccessibleObject
337 private class MenuStripAccessibleObject : AccessibleObject
344 #region MdiWindowListItemConverter
345 internal class MdiWindowListItemConverter : TypeConverter