1 // 2 // MenuStrip.cs 3 // 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: 11 // 12 // The above copyright notice and this permission notice shall be 13 // included in all copies or substantial portions of the Software. 14 // 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. 22 // 23 // Copyright (c) 2006 Jonathan Pobst 24 // 25 // Authors: 26 // Jonathan Pobst (monkey@jpobst.com) 27 // 28 29 using System; 30 using System.Drawing; 31 using System.ComponentModel; 32 using System.Runtime.InteropServices; 33 34 namespace System.Windows.Forms 35 { 36 [ClassInterface (ClassInterfaceType.AutoDispatch)] 37 [ComVisible (true)] 38 public class MenuStrip : ToolStrip 39 { 40 private ToolStripMenuItem mdi_window_list_item; 41 MenuStrip()42 public MenuStrip () : base () 43 { 44 base.CanOverflow = false; 45 this.GripStyle = ToolStripGripStyle.Hidden; 46 this.Stretch = true; 47 this.Dock = DockStyle.Top; 48 } 49 50 #region Public Properties 51 [DefaultValue (false)] 52 [Browsable (false)] 53 public new bool CanOverflow { 54 get { return base.CanOverflow; } 55 set { base.CanOverflow = value; } 56 } 57 58 [DefaultValue (ToolStripGripStyle.Hidden)] 59 public new ToolStripGripStyle GripStyle { 60 get { return base.GripStyle; } 61 set { base.GripStyle = value; } 62 } 63 64 [DefaultValue (null)] 65 [MergableProperty (false)] 66 [TypeConverter (typeof (MdiWindowListItemConverter))] 67 public ToolStripMenuItem MdiWindowListItem { 68 get { return this.mdi_window_list_item; } 69 set { 70 if (this.mdi_window_list_item != value) { 71 this.mdi_window_list_item = value; 72 this.RefreshMdiItems (); 73 } 74 } 75 } 76 77 [DefaultValue (false)] 78 public new bool ShowItemToolTips { 79 get { return base.ShowItemToolTips; } 80 set { base.ShowItemToolTips = value; } 81 } 82 83 [DefaultValue (true)] 84 public new bool Stretch { 85 get { return base.Stretch; } 86 set { base.Stretch = value; } 87 } 88 #endregion 89 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); } } 95 #endregion 96 97 #region Protected Methods CreateAccessibilityInstance()98 protected override AccessibleObject CreateAccessibilityInstance () 99 { 100 return new MenuStripAccessibleObject (); 101 } 102 CreateDefaultItem(string text, Image image, EventHandler onClick)103 protected internal override ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick) 104 { 105 return new ToolStripMenuItem (text, image, onClick); 106 } 107 OnMenuActivate(EventArgs e)108 protected virtual void OnMenuActivate (EventArgs e) 109 { 110 EventHandler eh = (EventHandler)(Events [MenuActivateEvent]); 111 if (eh != null) 112 eh (this, e); 113 } 114 OnMenuDeactivate(EventArgs e)115 protected virtual void OnMenuDeactivate (EventArgs e) 116 { 117 EventHandler eh = (EventHandler)(Events [MenuDeactivateEvent]); 118 if (eh != null) 119 eh (this, e); 120 } 121 ProcessCmdKey(ref Message m, Keys keyData)122 protected override bool ProcessCmdKey (ref Message m, Keys keyData) 123 { 124 return base.ProcessCmdKey (ref m, keyData); 125 } 126 WndProc(ref Message m)127 protected override void WndProc (ref Message m) 128 { 129 base.WndProc (ref m); 130 } 131 #endregion 132 133 #region Public Events 134 static object MenuActivateEvent = new object (); 135 static object MenuDeactivateEvent = new object (); 136 137 public event EventHandler MenuActivate { 138 add { Events.AddHandler (MenuActivateEvent, value); } 139 remove { Events.RemoveHandler (MenuActivateEvent, value); } 140 } 141 142 public event EventHandler MenuDeactivate { 143 add { Events.AddHandler (MenuDeactivateEvent, value); } 144 remove { Events.RemoveHandler (MenuDeactivateEvent, value); } 145 } 146 #endregion 147 148 #region Internal Properties 149 internal override bool KeyboardActive { 150 get { return base.KeyboardActive; } 151 set { 152 if (base.KeyboardActive != value) { 153 base.KeyboardActive = value; 154 155 if (value) 156 this.OnMenuActivate (EventArgs.Empty); 157 else 158 this.OnMenuDeactivate (EventArgs.Empty); 159 } 160 } 161 } 162 163 internal bool MenuDroppedDown { 164 get { return this.menu_selected; } 165 set { this.menu_selected = value; } 166 } 167 #endregion 168 169 #region Internal Methods Dismiss(ToolStripDropDownCloseReason reason)170 internal override void Dismiss (ToolStripDropDownCloseReason reason) 171 { 172 // Make sure we don't auto-dropdown next time we're activated 173 this.MenuDroppedDown = false; 174 175 base.Dismiss (reason); 176 177 this.FireMenuDeactivate (); 178 } 179 FireMenuActivate()180 internal void FireMenuActivate () 181 { 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); 185 186 this.OnMenuActivate (EventArgs.Empty); 187 } 188 FireMenuDeactivate()189 internal void FireMenuDeactivate () 190 { 191 // Detach from the tracker 192 ToolStripManager.AppClicked -= new EventHandler (ToolStripMenuTracker_AppClicked); ; 193 ToolStripManager.AppFocusChange -= new EventHandler (ToolStripMenuTracker_AppFocusChange); 194 195 this.OnMenuDeactivate (EventArgs.Empty); 196 } 197 OnMenuKey()198 internal override bool OnMenuKey () 199 { 200 // Set ourselves active and select our first item 201 ToolStripManager.SetActiveToolStrip (this, true); 202 ToolStripItem tsi = this.SelectNextToolStripItem (null, true); 203 204 if (tsi == null) 205 return false; 206 207 if (tsi is MdiControlStrip.SystemMenuItem) 208 this.SelectNextToolStripItem (tsi, true); 209 210 return true; 211 } 212 ToolStripMenuTracker_AppFocusChange(object sender, EventArgs e)213 private void ToolStripMenuTracker_AppFocusChange (object sender, EventArgs e) 214 { 215 this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppFocusChange); 216 } 217 ToolStripMenuTracker_AppClicked(object sender, EventArgs e)218 private void ToolStripMenuTracker_AppClicked (object sender, EventArgs e) 219 { 220 this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppClicked); 221 } 222 RefreshMdiItems()223 internal void RefreshMdiItems () 224 { 225 if (this.mdi_window_list_item == null) 226 return; 227 228 Form parent_form = this.FindForm (); 229 230 if (parent_form == null || parent_form.MainMenuStrip != this) 231 return; 232 233 MdiClient mdi = parent_form.MdiContainer; 234 235 // If there isn't a MdiContainer, we don't need to worry about MdiItems :) 236 if (mdi == null) 237 return; 238 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); 242 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); 248 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; 253 254 if (!mdichild.Visible) 255 continue; 256 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 ()); 260 261 tsi = new ToolStripMenuItem (); 262 tsi.MdiClientForm = mdichild; 263 this.mdi_window_list_item.DropDownItems.Add (tsi); 264 } 265 266 tsi.Text = string.Format ("&{0} {1}", i + 1, mdichild.Text); 267 tsi.Checked = parent_form.ActiveMdiChild == mdichild; 268 } 269 270 // Check that everything is in the correct order 271 if (NeedToReorderMdi ()) 272 ReorderMdiMenu (); 273 } 274 FindMdiMenuItemOfForm(Form f)275 private ToolStripMenuItem FindMdiMenuItemOfForm (Form f) 276 { 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; 281 282 return null; 283 } 284 CountMdiMenuItems()285 private int CountMdiMenuItems () 286 { 287 int count = 0; 288 289 foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems) 290 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry) 291 count++; 292 293 return count; 294 } 295 NeedToReorderMdi()296 private bool NeedToReorderMdi () 297 { 298 // Mdi menus must be: User Items, Separator, Mdi Items 299 bool seenMdi = false; 300 301 foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems) { 302 if (tsi is ToolStripMenuItem) { 303 if (!(tsi as ToolStripMenuItem).IsMdiWindowListEntry) { 304 if (seenMdi) 305 return true; 306 } else 307 seenMdi = true; 308 } 309 } 310 311 return false; 312 } 313 ReorderMdiMenu()314 private void ReorderMdiMenu () 315 { 316 ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count]; 317 this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0); 318 319 this.mdi_window_list_item.DropDownItems.Clear (); 320 321 foreach (ToolStripItem tsi in loopitems) 322 if (tsi is ToolStripSeparator || !(tsi as ToolStripMenuItem).IsMdiWindowListEntry) 323 this.mdi_window_list_item.DropDownItems.Add (tsi); 324 325 int count = this.mdi_window_list_item.DropDownItems.Count; 326 327 if (count > 0 && !(this.mdi_window_list_item.DropDownItems[count - 1] is ToolStripSeparator)) 328 this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ()); 329 330 foreach (ToolStripItem tsi in loopitems) 331 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry) 332 this.mdi_window_list_item.DropDownItems.Add (tsi); 333 } 334 #endregion 335 336 #region MenuStripAccessibleObject 337 private class MenuStripAccessibleObject : AccessibleObject 338 { 339 } 340 #endregion 341 342 } 343 344 #region MdiWindowListItemConverter 345 internal class MdiWindowListItemConverter : TypeConverter 346 { 347 } 348 #endregion 349 } 350