aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/Menu
diff options
context:
space:
mode:
Diffstat (limited to 'source/ShiftUI/Menu')
-rw-r--r--source/ShiftUI/Menu/Menu.cs621
-rw-r--r--source/ShiftUI/Menu/MenuAPI.cs836
-rw-r--r--source/ShiftUI/Menu/MenuGlyph.cs36
-rw-r--r--source/ShiftUI/Menu/MenuItem.cs912
-rw-r--r--source/ShiftUI/Menu/MenuMerge.cs38
-rw-r--r--source/ShiftUI/Menu/MenuStrip.cs349
6 files changed, 2792 insertions, 0 deletions
diff --git a/source/ShiftUI/Menu/Menu.cs b/source/ShiftUI/Menu/Menu.cs
new file mode 100644
index 0000000..0e04d70
--- /dev/null
+++ b/source/ShiftUI/Menu/Menu.cs
@@ -0,0 +1,621 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2004-2005 Novell, Inc.
+//
+// Authors:
+// Jordi Mas i Hernandez, [email protected]
+//
+// TODO:
+// - FindMenuItem
+// - MdiListItem
+//
+
+using System.Collections;
+using System.ComponentModel;
+using System.ComponentModel.Design;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Drawing;
+using System;
+
+namespace ShiftUI
+{
+ [ToolboxItemFilter("ShiftUI", ToolboxItemFilterType.Allow)]
+ [ListBindable(false)]
+ public abstract class Menu : Component
+ {
+ internal MenuItemCollection menu_items;
+ internal IntPtr menu_handle = IntPtr.Zero;
+ internal Menu parent_menu = null;
+ System.Drawing.Rectangle rect = new Rectangle ();
+ // UIA Framework Note: Used to keep track of expanded menus
+ internal Widget Wnd;
+ internal MenuTracker tracker;
+ private string control_name;
+ private object control_tag;
+ public const int FindHandle = 0;
+ public const int FindShortcut = 1;
+
+ protected Menu (MenuItem[] items)
+ {
+ menu_items = new MenuItemCollection (this);
+
+ if (items != null)
+ menu_items.AddRange (items);
+ }
+
+ #region Public Properties
+
+ [BrowsableAttribute(false)]
+ //[EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
+ //[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
+ public IntPtr Handle {
+ get { return menu_handle; }
+ }
+
+ internal virtual void OnMenuChanged (EventArgs e)
+ {
+ EventHandler eh = (EventHandler)(Events [MenuChangedEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+ [BrowsableAttribute(false)]
+ //[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
+ public virtual bool IsParent {
+ get {
+ if (menu_items != null && menu_items.Count > 0)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ [BrowsableAttribute(false)]
+ //[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
+ public MenuItem MdiListItem {
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
+ [BrowsableAttribute(false)]
+ //[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content)]
+ [MergableProperty(false)]
+ public MenuItemCollection MenuItems {
+ get { return menu_items; }
+ }
+
+ [BrowsableAttribute(false)]
+ //[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
+ public string Name {
+ get { return control_name; }
+ set { control_name = value; }
+ }
+
+ [Localizable(false)]
+ [Bindable(true)]
+ [TypeConverter(typeof(StringConverter))]
+ [DefaultValue(null)]
+ [MWFCategory("Data")]
+ public object Tag {
+ get { return control_tag; }
+ set { control_tag = value; }
+ }
+
+ #endregion Public Properties
+
+ #region Private Properties
+
+ // UIA Framework Note: Used to obtain menu bounds
+ internal Rectangle Rect {
+ get { return rect; }
+ }
+
+ internal MenuItem SelectedItem {
+ get {
+ foreach (MenuItem item in MenuItems)
+ if (item.Selected)
+ return item;
+
+ return null;
+ }
+ }
+
+ internal int Height {
+ get { return rect.Height; }
+ set { rect.Height = value; }
+ }
+
+ internal int Width {
+ get { return rect.Width; }
+ set { rect.Width = value; }
+ }
+
+ internal int X {
+ get { return rect.X; }
+ set { rect.X = value; }
+ }
+
+ internal int Y {
+ get { return rect.Y; }
+ set { rect.Y = value; }
+ }
+
+ internal MenuTracker Tracker {
+ get {
+ Menu top = this;
+ while (top.parent_menu != null)
+ top = top.parent_menu;
+
+ return top.tracker;
+ }
+ }
+ #endregion Private Properties
+
+ #region Public Methods
+
+ protected void CloneMenu (Menu menuSrc)
+ {
+ Dispose (true);
+
+ menu_items = new MenuItemCollection (this);
+
+ for (int i = 0; i < menuSrc.MenuItems.Count ; i++)
+ menu_items.Add (menuSrc.MenuItems [i].CloneMenu ());
+ }
+
+ protected virtual IntPtr CreateMenuHandle ()
+ {
+ return IntPtr.Zero;
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (disposing) {
+ if (menu_items != null) {
+ // MenuItem.Dispose removes the item from the list
+ while (menu_items.Count > 0) {
+ menu_items [0].Dispose ();
+ }
+ }
+ if (menu_handle != IntPtr.Zero) {
+ menu_handle = IntPtr.Zero;
+ }
+ }
+ }
+
+ // From Microsoft documentation is impossible to guess that
+ // this method is supossed to do
+ //
+ // update: according to MS documentation, first parameter is on of this
+ // constant values FindHandle or FindShortcut, value depends from what
+ // you what to search, by shortcut or handle. FindHandle and FindShortcut
+ // is a constant fields and was defined for this class.
+ public MenuItem FindMenuItem (int type, IntPtr value)
+ {
+ return null;
+ }
+
+ protected int FindMergePosition (int mergeOrder)
+ {
+ int cnt = MenuItems.Count, cur, pos;
+
+ for (pos = 0; pos < cnt; ) {
+ cur = (pos + cnt) /2;
+ if (MenuItems[cur].MergeOrder > mergeOrder) {
+ cnt = cur;
+ } else {
+ pos = cur +1;
+ }
+ }
+
+ return pos;
+ }
+
+ public MainMenu GetMainMenu ()
+ {
+ for (Menu item = this; item != null; item = item.parent_menu) {
+ if (item is MainMenu) {
+ return (MainMenu) item;
+ }
+ }
+
+ return null;
+ }
+
+ internal virtual void InvalidateItem (MenuItem item)
+ {
+ if (Wnd != null)
+ Wnd.Invalidate (item.bounds);
+ }
+
+ public virtual void MergeMenu (Menu menuSrc)
+ {
+ if (menuSrc == this)
+ throw new ArgumentException ("The menu cannot be merged with itself");
+
+ if (menuSrc == null)
+ return;
+
+ for (int i = 0; i < menuSrc.MenuItems.Count; i++) {
+
+ MenuItem sourceitem = menuSrc.MenuItems[i];
+
+ switch (sourceitem.MergeType) {
+ case MenuMerge.Remove: // Item not included
+ break;
+
+ case MenuMerge.Add:
+ {
+ int pos = FindMergePosition (sourceitem.MergeOrder);
+ MenuItems.Add (pos, sourceitem.CloneMenu ());
+ break;
+ }
+
+ case MenuMerge.Replace:
+ case MenuMerge.MergeItems:
+ {
+ for (int pos = FindMergePosition (sourceitem.MergeOrder-1); pos <= MenuItems.Count; pos++) {
+
+ if ((pos >= MenuItems.Count) || (MenuItems[pos].MergeOrder != sourceitem.MergeOrder)) {
+ MenuItems.Add (pos, sourceitem.CloneMenu ());
+ break;
+ }
+
+ MenuItem mergeitem = MenuItems[pos];
+
+ if (mergeitem.MergeType != MenuMerge.Add) {
+ if ((sourceitem.MergeType == MenuMerge.MergeItems) && (mergeitem.MergeType == MenuMerge.MergeItems)) {
+ mergeitem.MergeMenu (sourceitem);
+ } else {
+ MenuItems.Remove (sourceitem);
+ MenuItems.Add (pos, sourceitem.CloneMenu ());
+ }
+ break;
+ }
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ }
+
+ protected internal virtual bool ProcessCmdKey (ref Message msg, Keys keyData)
+ {
+ if (tracker == null)
+ return false;
+ return tracker.ProcessKeys (ref msg, keyData);
+ }
+
+ public override string ToString ()
+ {
+ return base.ToString () + ", Items.Count: " + MenuItems.Count;
+ }
+
+ #endregion Public Methods
+ static object MenuChangedEvent = new object ();
+
+ // UIA Framework Note: Used to track changes in MenuItemCollection
+ internal event EventHandler MenuChanged {
+ add { Events.AddHandler (MenuChangedEvent, value); }
+ remove { Events.RemoveHandler (MenuChangedEvent, value); }
+ }
+
+ [ListBindable(false)]
+ public class MenuItemCollection : IList, ICollection, IEnumerable
+ {
+ private Menu owner;
+ private ArrayList items = new ArrayList ();
+
+ public MenuItemCollection (Menu owner)
+ {
+ this.owner = owner;
+ }
+
+ #region Public Properties
+
+ public int Count {
+ get { return items.Count;}
+ }
+
+ public bool IsReadOnly {
+ get { return false; }
+ }
+
+ bool ICollection.IsSynchronized {
+ get { return false;}
+ }
+
+ object ICollection.SyncRoot {
+ get { return this;}
+ }
+
+ bool IList.IsFixedSize {
+ get { return false;}
+ }
+
+ public virtual MenuItem this [int index] {
+ get {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException ("Index of out range");
+
+ return (MenuItem) items[index];
+ }
+ }
+
+ public virtual MenuItem this [string key] {
+ get {
+ if (string.IsNullOrEmpty (key))
+ return null;
+
+ foreach (MenuItem m in items)
+ if (string.Compare (m.Name, key, true) == 0)
+ return m;
+
+ return null;
+ }
+ }
+
+ object IList.this[int index] {
+ get { return items[index]; }
+ set { throw new NotSupportedException (); }
+ }
+
+ #endregion Public Properties
+
+ #region Public Methods
+
+ public virtual int Add (MenuItem item)
+ {
+ if (item.Parent != null)
+ item.Parent.MenuItems.Remove (item);
+
+ items.Add (item);
+ item.Index = items.Count - 1;
+ UpdateItem (item);
+
+ owner.OnMenuChanged (EventArgs.Empty);
+ if (owner.parent_menu != null)
+ owner.parent_menu.OnMenuChanged (EventArgs.Empty);
+ return items.Count - 1;
+ }
+
+ internal void AddNoEvents (MenuItem mi)
+ {
+ if (mi.Parent != null)
+ mi.Parent.MenuItems.Remove (mi);
+
+ items.Add (mi);
+ mi.Index = items.Count - 1;
+ mi.parent_menu = owner;
+ }
+
+ public virtual MenuItem Add (string caption)
+ {
+ MenuItem item = new MenuItem (caption);
+ Add (item);
+ return item;
+ }
+
+ public virtual int Add (int index, MenuItem item)
+ {
+ if (index < 0 || index > Count)
+ throw new ArgumentOutOfRangeException ("Index of out range");
+
+ ArrayList new_items = new ArrayList (Count + 1);
+
+ for (int i = 0; i < index; i++)
+ new_items.Add (items[i]);
+
+ new_items.Add (item);
+
+ for (int i = index; i < Count; i++)
+ new_items.Add (items[i]);
+
+ items = new_items;
+ UpdateItemsIndices ();
+ UpdateItem (item);
+
+ return index;
+ }
+
+ private void UpdateItem (MenuItem mi)
+ {
+ mi.parent_menu = owner;
+ owner.OnMenuChanged (EventArgs.Empty);
+ if (owner.parent_menu != null)
+ owner.parent_menu.OnMenuChanged (EventArgs.Empty);
+ if (owner.Tracker != null)
+ owner.Tracker.AddShortcuts (mi);
+ }
+
+ internal void Insert (int index, MenuItem mi)
+ {
+ if (index < 0 || index > Count)
+ throw new ArgumentOutOfRangeException ("Index of out range");
+
+ items.Insert (index, mi);
+
+ UpdateItemsIndices ();
+ UpdateItem (mi);
+ }
+
+ public virtual MenuItem Add (string caption, EventHandler onClick)
+ {
+ MenuItem item = new MenuItem (caption, onClick);
+ Add (item);
+
+ return item;
+ }
+
+ public virtual MenuItem Add (string caption, MenuItem[] items)
+ {
+ MenuItem item = new MenuItem (caption, items);
+ Add (item);
+
+ return item;
+ }
+
+ public virtual void AddRange (MenuItem[] items)
+ {
+ if (items == null)
+ throw new ArgumentNullException ("items");
+
+ foreach (MenuItem mi in items)
+ Add (mi);
+ }
+
+ public virtual void Clear ()
+ {
+ MenuTracker tracker = owner.Tracker;
+ foreach (MenuItem item in items) {
+ if (tracker != null)
+ tracker.RemoveShortcuts (item);
+ item.parent_menu = null;
+ }
+ items.Clear ();
+ owner.OnMenuChanged (EventArgs.Empty);
+ }
+
+ public bool Contains (MenuItem value)
+ {
+ return items.Contains (value);
+ }
+
+ public virtual bool ContainsKey (string key)
+ {
+ return !(this[key] == null);
+ }
+
+ public void CopyTo (Array dest, int index)
+ {
+ items.CopyTo (dest, index);
+ }
+
+ public MenuItem[] Find (string key, bool searchAllChildren)
+ {
+ if (string.IsNullOrEmpty (key))
+ throw new ArgumentNullException ("key");
+
+ List<MenuItem> list = new List<MenuItem> ();
+
+ foreach (MenuItem m in items)
+ if (string.Compare (m.Name, key, true) == 0)
+ list.Add (m);
+
+ if (searchAllChildren)
+ foreach (MenuItem m in items)
+ list.AddRange (m.MenuItems.Find (key, true));
+
+ return list.ToArray ();
+ }
+
+ public IEnumerator GetEnumerator ()
+ {
+ return items.GetEnumerator ();
+ }
+
+ int IList.Add (object value)
+ {
+ return Add ((MenuItem)value);
+ }
+
+ bool IList.Contains (object value)
+ {
+ return Contains ((MenuItem)value);
+ }
+
+ int IList.IndexOf (object value)
+ {
+ return IndexOf ((MenuItem)value);
+ }
+
+ void IList.Insert (int index, object value)
+ {
+ Insert (index, (MenuItem) value);
+ }
+
+ void IList.Remove (object value)
+ {
+ Remove ((MenuItem) value);
+ }
+
+ public int IndexOf (MenuItem value)
+ {
+ return items.IndexOf (value);
+ }
+
+ public virtual int IndexOfKey (string key)
+ {
+ if (string.IsNullOrEmpty (key))
+ return -1;
+
+ return IndexOf (this[key]);
+ }
+
+ public virtual void Remove (MenuItem item)
+ {
+ RemoveAt (item.Index);
+ }
+
+ public virtual void RemoveAt (int index)
+ {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException ("Index of out range");
+
+ MenuItem item = (MenuItem) items [index];
+ MenuTracker tracker = owner.Tracker;
+ if (tracker != null)
+ tracker.RemoveShortcuts (item);
+ item.parent_menu = null;
+
+ items.RemoveAt (index);
+
+ UpdateItemsIndices ();
+ owner.OnMenuChanged (EventArgs.Empty);
+ }
+
+ public virtual void RemoveByKey (string key)
+ {
+ Remove (this[key]);
+ }
+
+ #endregion Public Methods
+
+ #region Private Methods
+
+ private void UpdateItemsIndices ()
+ {
+ for (int i = 0; i < Count; i++) // Recalculate indeces
+ ((MenuItem)items[i]).Index = i;
+ }
+
+ #endregion Private Methods
+ }
+ }
+}
+
+
diff --git a/source/ShiftUI/Menu/MenuAPI.cs b/source/ShiftUI/Menu/MenuAPI.cs
new file mode 100644
index 0000000..79a7a1d
--- /dev/null
+++ b/source/ShiftUI/Menu/MenuAPI.cs
@@ -0,0 +1,836 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2004-2005 Novell, Inc.
+//
+// Authors:
+// Jordi Mas i Hernandez, [email protected]
+// Mike Kestner <[email protected]>
+// Everaldo Canuto <[email protected]>
+//
+
+using System.Collections;
+using System.Drawing;
+using System.Threading;
+using System;
+
+namespace ShiftUI {
+
+ /*
+ When writing this code the Wine project was of great help to
+ understand the logic behind some Win32 issues. Thanks to them. Jordi,
+ */
+ // UIA Framework Note: This class used by UIA for its mouse action methods.
+ internal class MenuTracker {
+
+ internal bool active;
+ internal bool popup_active;
+ internal bool popdown_menu;
+ internal bool hotkey_active;
+ private bool mouse_down = false;
+ public Menu CurrentMenu;
+ public Menu TopMenu;
+ public Widget GrabControl;
+ Point last_motion = Point.Empty;
+
+ public MenuTracker (Menu top_menu)
+ {
+ TopMenu = CurrentMenu = top_menu;
+ foreach (MenuItem item in TopMenu.MenuItems)
+ AddShortcuts (item);
+ }
+
+ enum KeyNavState {
+ Idle,
+ Startup,
+ NoPopups,
+ Navigating
+ }
+
+ KeyNavState keynav_state = KeyNavState.Idle;
+
+ public bool Navigating {
+ get { return keynav_state != KeyNavState.Idle || active; }
+ }
+
+ internal static Point ScreenToMenu (Menu menu, Point pnt)
+ {
+ int x = pnt.X;
+ int y = pnt.Y;
+ XplatUI.ScreenToMenu (menu.Wnd.window.Handle, ref x, ref y);
+ return new Point (x, y);
+ }
+
+ private void UpdateCursor ()
+ {
+ Widget child_control = GrabControl.GetRealChildAtPoint (Cursor.Position);
+ if (child_control != null) {
+ if (active)
+ XplatUI.SetCursor (child_control.Handle, Cursors.Default.handle);
+ else
+ XplatUI.SetCursor (child_control.Handle, child_control.Cursor.handle);
+ }
+ }
+
+ internal void Deactivate ()
+ {
+ bool redrawbar = (keynav_state != KeyNavState.Idle) && (TopMenu is MainMenu);
+
+ active = false;
+ popup_active = false;
+ hotkey_active = false;
+ if (GrabControl != null)
+ GrabControl.ActiveTracker = null;
+ keynav_state = KeyNavState.Idle;
+ CurrentMenu = TopMenu;
+
+ if (redrawbar)
+ (TopMenu as MainMenu).Draw ();
+ }
+
+ MenuItem FindItemByCoords (Menu menu, Point pt)
+ {
+ if (menu is MainMenu)
+ pt = ScreenToMenu (menu, pt);
+ else {
+ if (menu.Wnd == null) {
+ return null;
+ }
+ pt = menu.Wnd.PointToClient (pt);
+ }
+ foreach (MenuItem item in menu.MenuItems) {
+ Rectangle rect = item.bounds;
+ if (rect.Contains (pt))
+ return item;
+ }
+
+ return null;
+ }
+
+ MenuItem GetItemAtXY (int x, int y)
+ {
+ Point pnt = new Point (x, y);
+ MenuItem item = null;
+ return item;
+ }
+
+ // UIA Framework Note: Used to expand/collapse MenuItems
+ public bool OnMouseDown (MouseEventArgs args)
+ {
+ MenuItem item = GetItemAtXY (args.X, args.Y);
+
+ mouse_down = true;
+
+ if (item == null) {
+ Deactivate ();
+ return false;
+ }
+
+ if ((args.Button & MouseButtons.Left) == 0)
+ return true;
+
+ if (!item.Enabled)
+ return true;
+
+ popdown_menu = active && item.VisibleItems;
+
+ if (item.IsPopup || (item.Parent is MainMenu)) {
+ active = true;
+ item.Parent.InvalidateItem (item);
+ }
+
+ if ((CurrentMenu == TopMenu) && !popdown_menu)
+ SelectItem (item.Parent, item, item.IsPopup);
+
+ GrabControl.ActiveTracker = this;
+ return true;
+ }
+
+ // UIA Framework Note: Used to select MenuItems
+ public void OnMotion (MouseEventArgs args)
+ {
+ // Windows helpfully sends us MOUSEMOVE messages when any key is pressed.
+ // So if the mouse hasn't actually moved since the last MOUSEMOVE, ignore it.
+ if (args.Location == last_motion)
+ return;
+
+ last_motion = args.Location;
+
+ MenuItem item = GetItemAtXY (args.X, args.Y);
+
+ UpdateCursor ();
+
+ if (CurrentMenu.SelectedItem == item)
+ return;
+
+ GrabControl.ActiveTracker = (active || item != null) ? this : null;
+
+ if (item == null) {
+ MenuItem old_item = CurrentMenu.SelectedItem;
+
+ // Return when is a popup with visible subitems for MainMenu
+ if ((active && old_item.VisibleItems && old_item.IsPopup && (CurrentMenu is MainMenu)))
+ return;
+
+ // Also returns when keyboard navigating
+ if (keynav_state == KeyNavState.Navigating)
+ return;
+
+ // Select parent menu when move outside of menu item
+ if (old_item.Parent is MenuItem) {
+ MenuItem new_item = (old_item.Parent as MenuItem);
+ if (new_item.IsPopup) {
+ SelectItem (new_item.Parent, new_item, false);
+ return;
+ }
+ }
+ if (CurrentMenu != TopMenu)
+ CurrentMenu = CurrentMenu.parent_menu;
+
+ DeselectItem (old_item);
+ } else {
+ keynav_state = KeyNavState.Idle;
+ SelectItem (item.Parent, item, active && item.IsPopup && popup_active && (CurrentMenu.SelectedItem != item));
+ }
+ }
+
+ // UIA Framework Note: Used to expand/collapse MenuItems
+ public void OnMouseUp (MouseEventArgs args)
+ {
+ /* mouse down dont comes from menu */
+ if (!mouse_down)
+ return;
+
+ mouse_down = false;
+
+ /* is not left button */
+ if ((args.Button & MouseButtons.Left) == 0)
+ return;
+
+ MenuItem item = GetItemAtXY (args.X, args.Y);
+
+ /* the user released the mouse button outside the menu */
+ if (item == null) {
+ Deactivate ();
+ return;
+ }
+
+ if (!item.Enabled)
+ return;
+
+ /* Perform click when is not a popup */
+ if (!item.IsPopup) {
+ DeselectItem (item);
+
+ // Raise the form's MenuComplete event
+ if (TopMenu != null && TopMenu.Wnd != null) {
+ Form f = TopMenu.Wnd.FindForm ();
+
+ if (f != null)
+ f.OnMenuComplete (EventArgs.Empty);
+ }
+
+ item.PerformClick ();
+ }
+ }
+
+ static public bool TrackPopupMenu (Menu menu, Point pnt)
+ {
+ return true;
+ }
+
+ void DeselectItem (MenuItem item)
+ {
+ if (item == null)
+ return;
+
+ item.Selected = false;
+
+ /* When popup item then close all sub popups and unselect all sub items */
+ if (item.IsPopup) {
+ HideSubPopups (item, TopMenu);
+
+ /* Unselect all selected sub itens */
+ foreach (MenuItem subitem in item.MenuItems)
+ if (subitem.Selected)
+ DeselectItem (subitem);
+ }
+
+ Menu menu = item.Parent;
+ menu.InvalidateItem (item);
+ }
+
+ void SelectItem (Menu menu, MenuItem item, bool execute)
+ {
+ MenuItem prev_item = CurrentMenu.SelectedItem;
+
+ if (prev_item != item.Parent) {
+ DeselectItem (prev_item);
+ if ((CurrentMenu != menu) && (prev_item.Parent != item) && (prev_item.Parent is MenuItem)) {
+ DeselectItem (prev_item.Parent as MenuItem);
+ }
+ }
+
+ if (CurrentMenu != menu)
+ CurrentMenu = menu;
+
+ item.Selected = true;
+ menu.InvalidateItem (item);
+
+ if (((CurrentMenu == TopMenu) && execute) || ((CurrentMenu != TopMenu) && popup_active))
+ item.PerformSelect ();
+
+ if ((execute) && ((prev_item == null) || (item != prev_item.Parent)))
+ ExecFocusedItem (menu, item);
+ }
+
+ // Used when the user executes the action of an item (press enter, shortcut)
+ // or a sub-popup menu has to be shown
+ void ExecFocusedItem (Menu menu, MenuItem item)
+ {
+ if (item == null)
+ return;
+
+ if (!item.Enabled)
+ return;
+
+ if (item.IsPopup) {
+ ShowSubPopup (menu, item);
+ } else {
+ Deactivate ();
+ item.PerformClick ();
+ }
+ }
+
+ // Create a popup window and show it or only show it if it is already created
+ void ShowSubPopup (Menu menu, MenuItem item)
+ {
+ if (item.Enabled == false)
+ return;
+
+ if (!popdown_menu || !item.VisibleItems)
+ item.PerformPopup ();
+
+ if (item.VisibleItems == false)
+ return;
+
+ if (item.Wnd != null) {
+ item.Wnd.Dispose ();
+ }
+
+ popup_active = true;
+ PopUpWindow puw = new PopUpWindow (GrabControl, item);
+
+ Point pnt;
+ if (menu is MainMenu)
+ pnt = new Point (item.X, item.Y + item.Height - 2 - menu.Height);
+ else
+ pnt = new Point (item.X + item.Width - 3, item.Y - 3);
+ pnt = menu.Wnd.PointToScreen (pnt);
+ puw.Location = pnt;
+ item.Wnd = puw;
+
+ puw.ShowWindow ();
+ }
+
+ static public void HideSubPopups (Menu menu, Menu topmenu)
+ {
+ foreach (MenuItem item in menu.MenuItems)
+ if (item.IsPopup)
+ HideSubPopups (item, null);
+
+ if (menu.Wnd == null)
+ return;
+
+ PopUpWindow puw = menu.Wnd as PopUpWindow;
+ if (puw != null) {
+ puw.Hide ();
+ puw.Dispose ();
+ }
+ menu.Wnd = null;
+
+ if ((topmenu != null) && (topmenu is MainMenu))
+ ((MainMenu) topmenu).OnCollapse (EventArgs.Empty);
+ }
+
+ MenuItem FindSubItemByCoord (Menu menu, Point pnt)
+ {
+ foreach (MenuItem item in menu.MenuItems) {
+
+ if (item.IsPopup && item.Wnd != null && item.Wnd.Visible && item == menu.SelectedItem) {
+ MenuItem result = FindSubItemByCoord (item, pnt);
+ if (result != null)
+ return result;
+ }
+
+ if (menu.Wnd == null || !menu.Wnd.Visible)
+ continue;
+
+ Rectangle rect = item.bounds;
+ Point pnt_client = menu.Wnd.PointToScreen (new Point (item.X, item.Y));
+ rect.X = pnt_client.X;
+ rect.Y = pnt_client.Y;
+
+ if (rect.Contains (pnt) == true)
+ return item;
+ }
+
+ return null;
+ }
+
+ static MenuItem FindItemByKey (Menu menu, IntPtr key)
+ {
+ char key_char = Char.ToUpper ((char) (key.ToInt32() & 0xff));
+ foreach (MenuItem item in menu.MenuItems) {
+ if (item.Mnemonic == key_char)
+ return item;
+ }
+
+ string key_str = key_char.ToString ();
+ foreach (MenuItem item in menu.MenuItems) {
+ //if (item.Mnemonic == key_char)
+ if (item.Text.StartsWith (key_str))
+ return item;
+ }
+
+ return null;
+ }
+
+ enum ItemNavigation {
+ First,
+ Last,
+ Next,
+ Previous,
+ }
+
+ static MenuItem GetNextItem (Menu menu, ItemNavigation navigation)
+ {
+ int pos = 0;
+ bool selectable_items = false;
+ MenuItem item;
+
+ // Check if there is at least a selectable item
+ for (int i = 0; i < menu.MenuItems.Count; i++) {
+ item = menu.MenuItems [i];
+ if (item.Separator == false && item.Visible == true) {
+ selectable_items = true;
+ break;
+ }
+ }
+
+ if (selectable_items == false)
+ return null;
+
+ switch (navigation) {
+ case ItemNavigation.First:
+
+ /* First item that is not separator and it is visible*/
+ for (pos = 0; pos < menu.MenuItems.Count; pos++) {
+ item = menu.MenuItems [pos];
+ if (item.Separator == false && item.Visible == true)
+ break;
+ }
+
+ break;
+
+ case ItemNavigation.Last: // Not used
+ break;
+
+ case ItemNavigation.Next:
+
+ pos = menu.SelectedItem == null ? - 1 : menu.SelectedItem.Index;
+
+ /* Next item that is not separator and it is visible*/
+ for (pos++; pos < menu.MenuItems.Count; pos++) {
+ item = menu.MenuItems [pos];
+ if (item.Separator == false && item.Visible == true)
+ break;
+ }
+
+ if (pos >= menu.MenuItems.Count) { /* Jump at the start of the menu */
+ pos = 0;
+ /* Next item that is not separator and it is visible*/
+ for (; pos < menu.MenuItems.Count; pos++) {
+ item = menu.MenuItems [pos];
+ if (item.Separator == false && item.Visible == true)
+ break;
+ }
+ }
+ break;
+
+ case ItemNavigation.Previous:
+
+ if (menu.SelectedItem != null)
+ pos = menu.SelectedItem.Index;
+
+ /* Previous item that is not separator and it is visible*/
+ for (pos--; pos >= 0; pos--) {
+ item = menu.MenuItems [pos];
+ if (item.Separator == false && item.Visible == true)
+ break;
+ }
+
+ if (pos < 0 ) { /* Jump at the end of the menu*/
+ pos = menu.MenuItems.Count - 1;
+ /* Previous item that is not separator and it is visible*/
+ for (; pos >= 0; pos--) {
+ item = menu.MenuItems [pos];
+ if (item.Separator == false && item.Visible == true)
+ break;
+ }
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return menu.MenuItems [pos];
+ }
+
+ void ProcessMenuKey (Msg msg_type)
+ {
+ if (TopMenu.MenuItems.Count == 0)
+ return;
+
+ MainMenu main_menu = TopMenu as MainMenu;
+
+ switch (msg_type) {
+ case Msg.WM_SYSKEYDOWN:
+ switch (keynav_state) {
+ case KeyNavState.Idle:
+ keynav_state = KeyNavState.Startup;
+ hotkey_active = true;
+ GrabControl.ActiveTracker = this;
+ CurrentMenu = TopMenu;
+ main_menu.Draw ();
+ break;
+ case KeyNavState.Startup:
+ break;
+ default:
+ Deactivate ();
+ main_menu.Draw ();
+ break;
+ }
+ break;
+
+ case Msg.WM_SYSKEYUP:
+ switch (keynav_state) {
+ case KeyNavState.Idle:
+ case KeyNavState.Navigating:
+ break;
+ case KeyNavState.Startup:
+ keynav_state = KeyNavState.NoPopups;
+ SelectItem (TopMenu, TopMenu.MenuItems [0], false);
+ break;
+ default:
+ Deactivate ();
+ main_menu.Draw ();
+ break;
+ }
+ break;
+ }
+ }
+
+ bool ProcessMnemonic (Message msg, Keys key_data)
+ {
+ keynav_state = KeyNavState.Navigating;
+ MenuItem item = FindItemByKey (CurrentMenu, msg.WParam);
+ if ((item == null) || (GrabControl == null) || (GrabControl.ActiveTracker == null))
+ return false;
+
+ active = true;
+ GrabControl.ActiveTracker = this;
+
+ SelectItem (CurrentMenu, item, true);
+ if (item.IsPopup) {
+ CurrentMenu = item;
+ SelectItem (item, item.MenuItems [0], false);
+ }
+ return true;
+ }
+
+ Hashtable shortcuts = new Hashtable ();
+
+ public void AddShortcuts (MenuItem item)
+ {
+ foreach (MenuItem child in item.MenuItems) {
+ AddShortcuts (child);
+ if (child.Shortcut != Shortcut.None)
+ shortcuts [(int)child.Shortcut] = child;
+ }
+
+ if (item.Shortcut != Shortcut.None)
+ shortcuts [(int)item.Shortcut] = item;
+ }
+
+ public void RemoveShortcuts (MenuItem item)
+ {
+ foreach (MenuItem child in item.MenuItems) {
+ RemoveShortcuts (child);
+ if (child.Shortcut != Shortcut.None)
+ shortcuts.Remove ((int)child.Shortcut);
+ }
+
+ if (item.Shortcut != Shortcut.None)
+ shortcuts.Remove ((int)item.Shortcut);
+ }
+
+ bool ProcessShortcut (Keys keyData)
+ {
+ MenuItem item = shortcuts [(int)keyData] as MenuItem;
+ if (item == null || !item.Enabled)
+ return false;
+
+ if (active)
+ Deactivate ();
+ item.PerformClick ();
+ return true;
+ }
+
+ public bool ProcessKeys (ref Message msg, Keys keyData)
+ {
+ // We should process Alt+key only if we don't have an active menu,
+ // and hide it otherwise.
+ if ((keyData & Keys.Alt) == Keys.Alt && active) {
+ Deactivate ();
+ return false;
+ }
+
+ // If we get Alt-F4, Windows will ignore it because we have a capture,
+ // release the capture and the program will exit. (X11 doesn't care.)
+ if ((keyData & Keys.Alt) == Keys.Alt && (keyData & Keys.F4) == Keys.F4) {
+ if (GrabControl != null)
+ GrabControl.ActiveTracker = null;
+
+ return false;
+ }
+
+ if ((Msg)msg.Msg != Msg.WM_SYSKEYUP && ProcessShortcut (keyData))
+ return true;
+ else if ((keyData & Keys.KeyCode) == Keys.Menu && TopMenu is MainMenu) {
+ ProcessMenuKey ((Msg) msg.Msg);
+ return true;
+ } else if ((keyData & Keys.Alt) == Keys.Alt)
+ return ProcessMnemonic (msg, keyData);
+ else if ((Msg)msg.Msg == Msg.WM_SYSKEYUP)
+ return false;
+ else if (!Navigating)
+ return false;
+
+ MenuItem item;
+
+ switch (keyData) {
+ case Keys.Up:
+ if (CurrentMenu is MainMenu)
+ return true;
+ else if (CurrentMenu.MenuItems.Count == 1 && CurrentMenu.parent_menu == TopMenu) {
+ DeselectItem (CurrentMenu.SelectedItem);
+ CurrentMenu = TopMenu;
+ return true;
+ }
+ item = GetNextItem (CurrentMenu, ItemNavigation.Previous);
+ if (item != null)
+ SelectItem (CurrentMenu, item, false);
+ break;
+
+ case Keys.Down:
+ if (CurrentMenu is MainMenu) {
+ if (CurrentMenu.SelectedItem != null && CurrentMenu.SelectedItem.IsPopup) {
+ keynav_state = KeyNavState.Navigating;
+ item = CurrentMenu.SelectedItem;
+ ShowSubPopup (CurrentMenu, item);
+ SelectItem (item, item.MenuItems [0], false);
+ CurrentMenu = item;
+ active = true;
+ GrabControl.ActiveTracker = this;
+ }
+ return true;
+ }
+ item = GetNextItem (CurrentMenu, ItemNavigation.Next);
+ if (item != null)
+ SelectItem (CurrentMenu, item, false);
+ break;
+
+ case Keys.Right:
+ if (CurrentMenu is MainMenu) {
+ item = GetNextItem (CurrentMenu, ItemNavigation.Next);
+ bool popup = item.IsPopup && keynav_state != KeyNavState.NoPopups;
+ SelectItem (CurrentMenu, item, popup);
+ if (popup) {
+ SelectItem (item, item.MenuItems [0], false);
+ CurrentMenu = item;
+ }
+ } else if (CurrentMenu.SelectedItem != null && CurrentMenu.SelectedItem.IsPopup) {
+ item = CurrentMenu.SelectedItem;
+ ShowSubPopup (CurrentMenu, item);
+ SelectItem (item, item.MenuItems [0], false);
+ CurrentMenu = item;
+ } else {
+ //Search up for a main menu
+ Menu Prnt = CurrentMenu.parent_menu;
+ while (Prnt != null && !(Prnt is MainMenu)) {
+ Prnt = Prnt.parent_menu;
+ }
+ if (Prnt is MainMenu)
+ {
+ item = GetNextItem(Prnt, ItemNavigation.Next);
+ SelectItem(Prnt, item, item.IsPopup);
+ if (item.IsPopup)
+ {
+ SelectItem(item, item.MenuItems[0], false);
+ CurrentMenu = item;
+ }
+ }
+ }
+ break;
+
+ case Keys.Left:
+ if (CurrentMenu is MainMenu) {
+ item = GetNextItem (CurrentMenu, ItemNavigation.Previous);
+ bool popup = item.IsPopup && keynav_state != KeyNavState.NoPopups;
+ SelectItem (CurrentMenu, item, popup);
+ if (popup) {
+ SelectItem (item, item.MenuItems [0], false);
+ CurrentMenu = item;
+ }
+ } else if (CurrentMenu.parent_menu is MainMenu) {
+ item = GetNextItem (CurrentMenu.parent_menu, ItemNavigation.Previous);
+ SelectItem (CurrentMenu.parent_menu, item, item.IsPopup);
+ if (item.IsPopup) {
+ SelectItem (item, item.MenuItems [0], false);
+ CurrentMenu = item;
+ }
+ }
+ break;
+
+ case Keys.Return:
+ if (CurrentMenu.SelectedItem != null && CurrentMenu.SelectedItem.IsPopup) {
+ keynav_state = KeyNavState.Navigating;
+ item = CurrentMenu.SelectedItem;
+ ShowSubPopup (CurrentMenu, item);
+ SelectItem (item, item.MenuItems [0], false);
+ CurrentMenu = item;
+ active = true;
+ GrabControl.ActiveTracker = this;
+ } else {
+ ExecFocusedItem (CurrentMenu, CurrentMenu.SelectedItem);
+ }
+ break;
+
+ case Keys.Escape:
+ Deactivate ();
+ break;
+
+ default:
+ ProcessMnemonic (msg, keyData);
+ break;
+ }
+
+ return active;
+ }
+ }
+
+ internal class PopUpWindow : Widget
+ {
+ private Menu menu;
+ private Widget form;
+
+ public PopUpWindow (Widget form, Menu menu): base ()
+ {
+ this.menu = menu;
+ this.form = form;
+ SetStyle (Widgetstyles.UserPaint | Widgetstyles.AllPaintingInWmPaint, true);
+ SetStyle (Widgetstyles.ResizeRedraw | Widgetstyles.Opaque, true);
+ is_visible = false;
+ }
+
+ protected override CreateParams CreateParams
+ {
+ get {
+ CreateParams cp = base.CreateParams;
+ cp.Caption = "Menu PopUp";
+ cp.Style = unchecked ((int)(WindowStyles.WS_POPUP));
+ cp.ExStyle |= (int)(WindowExStyles.WS_EX_TOOLWINDOW | WindowExStyles.WS_EX_TOPMOST);
+ return cp;
+ }
+ }
+
+ public void ShowWindow ()
+ {
+ XplatUI.SetCursor(form.Handle, Cursors.Default.handle);
+ RefreshItems ();
+ Show ();
+ }
+
+ internal override void OnPaintInternal (PaintEventArgs args)
+ {
+ ThemeEngine.Current.DrawPopupMenu (args.Graphics, menu, args.ClipRectangle, ClientRectangle);
+ }
+
+ public void HideWindow ()
+ {
+ XplatUI.SetCursor (form.Handle, form.Cursor.handle);
+ MenuTracker.HideSubPopups (menu, null);
+ Hide ();
+ }
+
+ protected override void CreateHandle ()
+ {
+ base.CreateHandle ();
+ RefreshItems ();
+ }
+
+ // Called when the number of items has changed
+ internal void RefreshItems ()
+ {
+ Point pt = new Point (Location.X, Location.Y);
+
+ ThemeEngine.Current.CalcPopupMenuSize (DeviceContext, menu);
+
+ if ((pt.X + menu.Rect.Width) > SystemInformation.VirtualScreen.Width) {
+ if (((pt.X - menu.Rect.Width) > 0) && !(menu.parent_menu is MainMenu))
+ pt.X = pt.X - menu.Rect.Width;
+ else
+ pt.X = SystemInformation.VirtualScreen.Width - menu.Rect.Width;
+
+ if (pt.X < 0)
+ pt.X = 0;
+ }
+ if ((pt.Y + menu.Rect.Height) > SystemInformation.VirtualScreen.Height) {
+ if ((pt.Y - menu.Rect.Height) > 0)
+ pt.Y = pt.Y - menu.Rect.Height;
+ else
+ pt.Y = SystemInformation.VirtualScreen.Height - menu.Rect.Height;
+
+ if (pt.Y < 0)
+ pt.Y = 0;
+ }
+
+ Location = pt;
+ Width = menu.Rect.Width;
+ Height = menu.Rect.Height;
+ }
+
+ internal override bool ActivateOnShow { get { return false; } }
+ }
+}
+
+
diff --git a/source/ShiftUI/Menu/MenuGlyph.cs b/source/ShiftUI/Menu/MenuGlyph.cs
new file mode 100644
index 0000000..92aa7f7
--- /dev/null
+++ b/source/ShiftUI/Menu/MenuGlyph.cs
@@ -0,0 +1,36 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2004 Novell, Inc.
+//
+// Authors:
+// Peter Bartok [email protected]
+
+
+// COMPLETE
+
+namespace ShiftUI {
+ public enum MenuGlyph {
+ Arrow = 0,
+ Min = 0,
+ Checkmark = 1,
+ Bullet = 2,
+ Max = 2
+ }
+}
diff --git a/source/ShiftUI/Menu/MenuItem.cs b/source/ShiftUI/Menu/MenuItem.cs
new file mode 100644
index 0000000..a893106
--- /dev/null
+++ b/source/ShiftUI/Menu/MenuItem.cs
@@ -0,0 +1,912 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2004-2005 Novell, Inc.
+//
+// Authors:
+// Jordi Mas i Hernandez, [email protected]
+//
+//
+
+// NOT COMPLETE
+
+using System.Collections;
+using System.ComponentModel;
+using System.ComponentModel.Design;
+using System.Drawing;
+using System.Drawing.Text;
+using System;
+
+namespace ShiftUI
+{
+ [DefaultProperty("Text")]
+ [DefaultEvent("Click")]
+ [DesignTimeVisible(false)]
+ [ToolboxItem(false)]
+ public class MenuItem : Menu
+ {
+ internal bool separator;
+ internal bool break_;
+ internal bool bar_break;
+ private Shortcut shortcut;
+ private string text;
+ private bool checked_;
+ private bool radiocheck;
+ private bool enabled;
+ private char mnemonic;
+ private bool showshortcut;
+ private int index;
+ private bool mdilist;
+ private Hashtable mdilist_items;
+ private Hashtable mdilist_forms;
+ private MdiClient mdicontainer;
+ private bool is_window_menu_item;
+ private bool defaut_item;
+ private bool visible;
+ private bool ownerdraw;
+ private int menuid;
+ private int mergeorder;
+ private int xtab;
+ private int menuheight;
+ private bool menubar;
+ private MenuMerge mergetype;
+ // UIA Framework Note: Used to obtain item bounds
+ internal Rectangle bounds;
+
+ public MenuItem (): base (null)
+ {
+ CommonConstructor (string.Empty);
+ shortcut = Shortcut.None;
+ }
+
+ public MenuItem (string text) : base (null)
+ {
+ CommonConstructor (text);
+ shortcut = Shortcut.None;
+ }
+
+ public MenuItem (string text, EventHandler onClick) : base (null)
+ {
+ CommonConstructor (text);
+ shortcut = Shortcut.None;
+ Click += onClick;
+ }
+
+ public MenuItem (string text, MenuItem[] items) : base (items)
+ {
+ CommonConstructor (text);
+ shortcut = Shortcut.None;
+ }
+
+ public MenuItem (string text, EventHandler onClick, Shortcut shortcut) : base (null)
+ {
+ CommonConstructor (text);
+ Click += onClick;
+ this.shortcut = shortcut;
+ }
+
+ public MenuItem (MenuMerge mergeType, int mergeOrder, Shortcut shortcut, string text,
+ EventHandler onClick, EventHandler onPopup, EventHandler onSelect, MenuItem[] items)
+ : base (items)
+ {
+ CommonConstructor (text);
+ this.shortcut = shortcut;
+ mergeorder = mergeOrder;
+ mergetype = mergeType;
+
+ Click += onClick;
+ Popup += onPopup;
+ Select += onSelect;
+ }
+
+ private void CommonConstructor (string text)
+ {
+ defaut_item = false;
+ separator = false;
+ break_ = false;
+ bar_break = false;
+ checked_ = false;
+ radiocheck = false;
+ enabled = true;
+ showshortcut = true;
+ visible = true;
+ ownerdraw = false;
+ menubar = false;
+ menuheight = 0;
+ xtab = 0;
+ index = -1;
+ mnemonic = '\0';
+ menuid = -1;
+ mergeorder = 0;
+ mergetype = MenuMerge.Add;
+ Text = text; // Text can change separator status
+ }
+
+ #region Events
+ static object ClickEvent = new object ();
+ static object DrawItemEvent = new object ();
+ static object MeasureItemEvent = new object ();
+ static object PopupEvent = new object ();
+ static object SelectEvent = new object ();
+
+ public event EventHandler Click {
+ add { Events.AddHandler (ClickEvent, value); }
+ remove { Events.RemoveHandler (ClickEvent, value); }
+ }
+
+ public event DrawItemEventHandler DrawItem {
+ add { Events.AddHandler (DrawItemEvent, value); }
+ remove { Events.RemoveHandler (DrawItemEvent, value); }
+ }
+
+ public event MeasureItemEventHandler MeasureItem {
+ add { Events.AddHandler (MeasureItemEvent, value); }
+ remove { Events.RemoveHandler (MeasureItemEvent, value); }
+ }
+
+ public event EventHandler Popup {
+ add { Events.AddHandler (PopupEvent, value); }
+ remove { Events.RemoveHandler (PopupEvent, value); }
+ }
+
+ public event EventHandler Select {
+ add { Events.AddHandler (SelectEvent, value); }
+ remove { Events.RemoveHandler (SelectEvent, value); }
+ }
+
+ #region UIA Framework Events
+
+ static object UIACheckedChangedEvent = new object ();
+
+ internal event EventHandler UIACheckedChanged {
+ add { Events.AddHandler (UIACheckedChangedEvent, value); }
+ remove { Events.RemoveHandler (UIACheckedChangedEvent, value); }
+ }
+
+ internal void OnUIACheckedChanged (EventArgs e)
+ {
+ EventHandler eh = (EventHandler) Events [UIACheckedChangedEvent];
+ if (eh != null)
+ eh (this, e);
+ }
+
+ static object UIARadioCheckChangedEvent = new object ();
+
+ internal event EventHandler UIARadioCheckChanged {
+ add { Events.AddHandler (UIARadioCheckChangedEvent, value); }
+ remove { Events.RemoveHandler (UIARadioCheckChangedEvent, value); }
+ }
+
+ internal void OnUIARadioCheckChanged (EventArgs e)
+ {
+ EventHandler eh = (EventHandler) Events [UIARadioCheckChangedEvent];
+ if (eh != null)
+ eh (this, e);
+ }
+
+ static object UIAEnabledChangedEvent = new object ();
+
+ internal event EventHandler UIAEnabledChanged {
+ add { Events.AddHandler (UIAEnabledChangedEvent, value); }
+ remove { Events.RemoveHandler (UIAEnabledChangedEvent, value); }
+ }
+
+ internal void OnUIAEnabledChanged (EventArgs e)
+ {
+ EventHandler eh = (EventHandler) Events [UIAEnabledChangedEvent];
+ if (eh != null)
+ eh (this, e);
+ }
+
+ static object UIATextChangedEvent = new object ();
+
+ internal event EventHandler UIATextChanged {
+ add { Events.AddHandler (UIATextChangedEvent, value); }
+ remove { Events.RemoveHandler (UIATextChangedEvent, value); }
+ }
+
+ internal void OnUIATextChanged (EventArgs e)
+ {
+ EventHandler eh = (EventHandler) Events [UIATextChangedEvent];
+ if (eh != null)
+ eh (this, e);
+ }
+
+ #endregion
+ #endregion // Events
+
+ #region Public Properties
+
+ [Browsable(false)]
+ [DefaultValue(false)]
+ public bool BarBreak {
+ get { return break_; }
+ set { break_ = value; }
+ }
+
+ [Browsable(false)]
+ [DefaultValue(false)]
+ public bool Break {
+ get { return bar_break; }
+ set { bar_break = value; }
+ }
+
+ [DefaultValue(false)]
+ public bool Checked {
+ get { return checked_; }
+ set {
+ if (checked_ == value)
+ return;
+
+ checked_ = value;
+
+ // UIA Framework Event: Checked Changed
+ OnUIACheckedChanged (EventArgs.Empty);
+ }
+ }
+
+ [DefaultValue(false)]
+ public bool DefaultItem {
+ get { return defaut_item; }
+ set { defaut_item = value; }
+ }
+
+ [DefaultValue(true)]
+ [Localizable(true)]
+ public bool Enabled {
+ get { return enabled; }
+ set {
+ if (enabled == value)
+ return;
+
+ enabled = value;
+
+ // UIA Framework Event: Enabled Changed
+ OnUIAEnabledChanged (EventArgs.Empty);
+
+ Invalidate ();
+ }
+ }
+
+ [Browsable(false)]
+ public int Index {
+ get { return index; }
+ set {
+ if (Parent != null && Parent.MenuItems != null && (value < 0 || value >= Parent.MenuItems.Count))
+ throw new ArgumentException ("'" + value + "' is not a valid value for 'value'");
+ index = value;
+ }
+ }
+
+ [Browsable(false)]
+ public override bool IsParent {
+ get { return IsPopup; }
+ }
+
+ [DefaultValue(false)]
+ public bool MdiList {
+ get { return mdilist; }
+ set {
+ if (mdilist == value)
+ return;
+ mdilist = value;
+
+ if (mdilist || mdilist_items == null)
+ return;
+
+ foreach (MenuItem item in mdilist_items.Keys)
+ MenuItems.Remove (item);
+ mdilist_items.Clear ();
+ mdilist_items = null;
+ }
+ }
+
+ protected int MenuID {
+ get { return menuid; }
+ }
+
+ [DefaultValue(0)]
+ public int MergeOrder {
+ get { return mergeorder; }
+ set { mergeorder = value; }
+ }
+
+ [DefaultValue(MenuMerge.Add)]
+ public MenuMerge MergeType {
+ get { return mergetype; }
+ set {
+ if (!Enum.IsDefined (typeof (MenuMerge), value))
+ throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for MenuMerge", value));
+
+ mergetype = value;
+ }
+ }
+
+ [Browsable(false)]
+ public char Mnemonic {
+ get { return mnemonic; }
+ }
+
+ [DefaultValue(false)]
+ public bool OwnerDraw {
+ get { return ownerdraw; }
+ set { ownerdraw = value; }
+ }
+
+ [Browsable(false)]
+ public Menu Parent {
+ get { return parent_menu;}
+ }
+
+ [DefaultValue(false)]
+ public bool RadioCheck {
+ get { return radiocheck; }
+ set {
+ if (radiocheck == value)
+ return;
+
+ radiocheck = value;
+
+ // UIA Framework Event: Checked Changed
+ OnUIARadioCheckChanged (EventArgs.Empty);
+ }
+ }
+
+ [DefaultValue(Shortcut.None)]
+ [Localizable(true)]
+ public Shortcut Shortcut {
+ get { return shortcut;}
+ set {
+ if (!Enum.IsDefined (typeof (Shortcut), value))
+ throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for Shortcut", value));
+
+ shortcut = value;
+ UpdateMenuItem ();
+ }
+ }
+
+ [DefaultValue(true)]
+ [Localizable(true)]
+ public bool ShowShortcut {
+ get { return showshortcut;}
+ set { showshortcut = value; }
+ }
+
+ [Localizable(true)]
+ public string Text {
+ get { return text; }
+ set {
+ text = value;
+
+ if (text == "-")
+ separator = true;
+ else
+ separator = false;
+
+ // UIA Framework Event: Text Changed
+ OnUIATextChanged (EventArgs.Empty);
+
+ ProcessMnemonic ();
+ Invalidate ();
+ }
+ }
+
+ [DefaultValue(true)]
+ [Localizable(true)]
+ public bool Visible {
+ get { return visible;}
+ set {
+ if (value == visible)
+ return;
+
+ visible = value;
+
+ if (menu_items != null) {
+ foreach (MenuItem mi in menu_items)
+ mi.Visible = value;
+ }
+
+ if (parent_menu != null)
+ parent_menu.OnMenuChanged (EventArgs.Empty);
+ }
+ }
+
+ #endregion Public Properties
+
+ #region Private Properties
+
+ internal new int Height {
+ get { return bounds.Height; }
+ set { bounds.Height = value; }
+ }
+
+ internal bool IsPopup {
+ get {
+ if (menu_items.Count > 0)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ internal bool MeasureEventDefined {
+ get {
+ if (ownerdraw == true && Events [MeasureItemEvent] != null) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ internal bool MenuBar {
+ get { return menubar; }
+ set { menubar = value; }
+ }
+
+ internal int MenuHeight {
+ get { return menuheight; }
+ set { menuheight = value; }
+ }
+
+ bool selected;
+ internal bool Selected {
+ get { return selected; }
+ set { selected = value; }
+ }
+
+ internal bool Separator {
+ get { return separator; }
+ set { separator = value; }
+ }
+
+ internal DrawItemState Status {
+ get {
+ DrawItemState status = DrawItemState.None;
+ MenuTracker tracker = Parent.Tracker;
+ if (Selected)
+ status |= (tracker.active || tracker.Navigating ? DrawItemState.Selected : DrawItemState.HotLight);
+ if (!Enabled)
+ status |= DrawItemState.Grayed | DrawItemState.Disabled;
+ if (Checked)
+ status |= DrawItemState.Checked;
+ if (!tracker.Navigating)
+ status |= DrawItemState.NoAccelerator;
+ return status;
+ }
+ }
+
+ internal bool VisibleItems {
+ get {
+ if (menu_items != null) {
+ foreach (MenuItem mi in menu_items)
+ if (mi.Visible)
+ return true;
+ }
+ return false;
+ }
+ }
+
+ internal new int Width {
+ get { return bounds.Width; }
+ set { bounds.Width = value; }
+ }
+
+ internal new int X {
+ get { return bounds.X; }
+ set { bounds.X = value; }
+ }
+
+ internal int XTab {
+ get { return xtab; }
+ set { xtab = value; }
+ }
+
+ internal new int Y {
+ get { return bounds.Y; }
+ set { bounds.Y = value; }
+ }
+
+ #endregion Private Properties
+
+ #region Public Methods
+
+ public virtual MenuItem CloneMenu ()
+ {
+ MenuItem item = new MenuItem ();
+ item.CloneMenu (this);
+ return item;
+ }
+
+ protected void CloneMenu (MenuItem itemSrc)
+ {
+ base.CloneMenu (itemSrc); // Copy subitems
+
+ // Window list
+ MdiList = itemSrc.MdiList;
+ is_window_menu_item = itemSrc.is_window_menu_item;
+ // Remove items corresponding to window menu items, and add new items
+ // (Otherwise window menu items would show up twice, since the PopulateWindowMenu doesn't
+ // now them)
+ bool populated = false;
+ for (int i = MenuItems.Count - 1; i >= 0; i--) {
+ if (MenuItems [i].is_window_menu_item) {
+ MenuItems.RemoveAt (i);
+ populated = true;
+ }
+ }
+ if (populated)
+ PopulateWindowMenu ();
+
+ // Properties
+ BarBreak = itemSrc.BarBreak;
+ Break = itemSrc.Break;
+ Checked = itemSrc.Checked;
+ DefaultItem = itemSrc.DefaultItem;
+ Enabled = itemSrc.Enabled;
+ MergeOrder = itemSrc.MergeOrder;
+ MergeType = itemSrc.MergeType;
+ OwnerDraw = itemSrc.OwnerDraw;
+ //Parent = menuitem.Parent;
+ RadioCheck = itemSrc.RadioCheck;
+ Shortcut = itemSrc.Shortcut;
+ ShowShortcut = itemSrc.ShowShortcut;
+ Text = itemSrc.Text;
+ Visible = itemSrc.Visible;
+ Name = itemSrc.Name;
+ Tag = itemSrc.Tag;
+
+ // Events
+ Events[ClickEvent] = itemSrc.Events[ClickEvent];
+ Events[DrawItemEvent] = itemSrc.Events[DrawItemEvent];
+ Events[MeasureItemEvent] = itemSrc.Events[MeasureItemEvent];
+ Events[PopupEvent] = itemSrc.Events[PopupEvent];
+ Events[SelectEvent] = itemSrc.Events[SelectEvent];
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (disposing && parent_menu != null)
+ parent_menu.MenuItems.Remove (this);
+
+ base.Dispose (disposing);
+ }
+
+ // This really clones the item
+ public virtual MenuItem MergeMenu ()
+ {
+ MenuItem item = new MenuItem ();
+ item.CloneMenu (this);
+ return item;
+ }
+
+ public void MergeMenu (MenuItem itemSrc)
+ {
+ base.MergeMenu (itemSrc);
+ }
+
+ protected virtual void OnClick (EventArgs e)
+ {
+ EventHandler eh = (EventHandler)(Events [ClickEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+ protected virtual void OnDrawItem (DrawItemEventArgs e)
+ {
+ DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+
+ protected virtual void OnInitMenuPopup (EventArgs e)
+ {
+ OnPopup (e);
+ }
+
+ protected virtual void OnMeasureItem (MeasureItemEventArgs e)
+ {
+ if (!OwnerDraw)
+ return;
+
+ MeasureItemEventHandler eh = (MeasureItemEventHandler)(Events [MeasureItemEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+ protected virtual void OnPopup (EventArgs e)
+ {
+ EventHandler eh = (EventHandler)(Events [PopupEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+ protected virtual void OnSelect (EventArgs e)
+ {
+ EventHandler eh = (EventHandler)(Events [SelectEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+ public void PerformClick ()
+ {
+ OnClick (EventArgs.Empty);
+ }
+
+ public virtual void PerformSelect ()
+ {
+ OnSelect (EventArgs.Empty);
+ }
+
+ public override string ToString ()
+ {
+ return base.ToString () + ", Items.Count: " + MenuItems.Count + ", Text: " + text;
+ }
+
+ #endregion Public Methods
+
+ #region Private Methods
+
+ internal virtual void Invalidate ()
+ {
+ if ((Parent == null) || !(Parent is MainMenu) || (Parent.Wnd == null))
+ return;
+
+ Form form = Parent.Wnd.FindForm ();
+ if ((form == null) || (!form.IsHandleCreated))
+ return;
+
+ XplatUI.RequestNCRecalc (form.Handle);
+ }
+
+ internal void PerformPopup ()
+ {
+ OnPopup (EventArgs.Empty);
+ }
+
+ internal void PerformDrawItem (DrawItemEventArgs e)
+ {
+ PopulateWindowMenu ();
+ if (OwnerDraw)
+ OnDrawItem (e);
+ else
+ ThemeEngine.Current.DrawMenuItem (this, e);
+ }
+
+ private void PopulateWindowMenu ()
+ {
+ if (mdilist) {
+ if (mdilist_items == null) {
+ mdilist_items = new Hashtable ();
+ mdilist_forms = new Hashtable ();
+ }
+
+ do {
+ MainMenu main = GetMainMenu ();
+ if (main == null || main.GetForm () == null)
+ break;
+
+ Form form = main.GetForm ();
+ mdicontainer = form.MdiContainer;
+ if (mdicontainer == null)
+ break;
+
+
+ // Remove closed forms
+ MenuItem[] items = new MenuItem[mdilist_items.Count];
+ mdilist_items.Keys.CopyTo (items, 0);
+ foreach (MenuItem item in items) {
+ Form mdichild = (Form) mdilist_items [item];
+ if (!mdicontainer.mdi_child_list.Contains(mdichild)) {
+ mdilist_items.Remove (item);
+ mdilist_forms.Remove (mdichild);
+ MenuItems.Remove (item);
+ }
+ }
+
+ // Add new forms and update state for existing forms.
+ for (int i = 0; i < mdicontainer.mdi_child_list.Count; i++) {
+ Form mdichild = (Form)mdicontainer.mdi_child_list[i];
+ MenuItem item;
+ if (mdilist_forms.Contains (mdichild)) {
+ item = (MenuItem) mdilist_forms [mdichild];
+ } else {
+ item = new MenuItem ();
+ item.is_window_menu_item = true;
+ item.Click += new EventHandler (MdiWindowClickHandler);
+ mdilist_items [item] = mdichild;
+ mdilist_forms [mdichild] = item;
+ MenuItems.AddNoEvents (item);
+ }
+ item.Visible = mdichild.Visible;
+ item.Text = "&" + (i + 1).ToString () + " " + mdichild.Text;
+ item.Checked = form.ActiveMdiChild == mdichild;
+ }
+ } while (false);
+ } else {
+ // Remove all forms
+ if (mdilist_items != null) {
+ foreach (MenuItem item in mdilist_items.Values) {
+ MenuItems.Remove (item);
+ }
+
+ mdilist_forms.Clear ();
+ mdilist_items.Clear ();
+ }
+ }
+ }
+
+ internal void PerformMeasureItem (MeasureItemEventArgs e)
+ {
+ OnMeasureItem (e);
+ }
+
+ private void ProcessMnemonic ()
+ {
+ if (text == null || text.Length < 2) {
+ mnemonic = '\0';
+ return;
+ }
+
+ bool bPrevAmp = false;
+ for (int i = 0; i < text.Length -1 ; i++) {
+ if (text[i] == '&') {
+ if (bPrevAmp == false && (text[i+1] != '&')) {
+ mnemonic = Char.ToUpper (text[i+1]);
+ return;
+ }
+
+ bPrevAmp = true;
+ }
+ else
+ bPrevAmp = false;
+ }
+
+ mnemonic = '\0';
+ }
+
+ private string GetShortCutTextCtrl () { return "Ctrl"; }
+ private string GetShortCutTextAlt () { return "Alt"; }
+ private string GetShortCutTextShift () { return "Shift"; }
+
+ internal string GetShortCutText ()
+ {
+ /* Ctrl+A - Ctrl+Z */
+ if (Shortcut >= Shortcut.CtrlA && Shortcut <= Shortcut.CtrlZ)
+ return GetShortCutTextCtrl () + "+" + (char)((int) 'A' + (int)(Shortcut - Shortcut.CtrlA));
+
+ /* Alt+0 - Alt+9 */
+ if (Shortcut >= Shortcut.Alt0 && Shortcut <= Shortcut.Alt9)
+ return GetShortCutTextAlt () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.Alt0));
+
+ /* Alt+F1 - Alt+F2 */
+ if (Shortcut >= Shortcut.AltF1 && Shortcut <= Shortcut.AltF9)
+ return GetShortCutTextAlt () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.AltF1));
+
+ /* Ctrl+0 - Ctrl+9 */
+ if (Shortcut >= Shortcut.Ctrl0 && Shortcut <= Shortcut.Ctrl9)
+ return GetShortCutTextCtrl () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.Ctrl0));
+
+ /* Ctrl+F0 - Ctrl+F9 */
+ if (Shortcut >= Shortcut.CtrlF1 && Shortcut <= Shortcut.CtrlF9)
+ return GetShortCutTextCtrl () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.CtrlF1));
+
+ /* Ctrl+Shift+0 - Ctrl+Shift+9 */
+ if (Shortcut >= Shortcut.CtrlShift0 && Shortcut <= Shortcut.CtrlShift9)
+ return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.CtrlShift0));
+
+ /* Ctrl+Shift+A - Ctrl+Shift+Z */
+ if (Shortcut >= Shortcut.CtrlShiftA && Shortcut <= Shortcut.CtrlShiftZ)
+ return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+" + (char)((int) 'A' + (int)(Shortcut - Shortcut.CtrlShiftA));
+
+ /* Ctrl+Shift+F1 - Ctrl+Shift+F9 */
+ if (Shortcut >= Shortcut.CtrlShiftF1 && Shortcut <= Shortcut.CtrlShiftF9)
+ return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.CtrlShiftF1));
+
+ /* F1 - F9 */
+ if (Shortcut >= Shortcut.F1 && Shortcut <= Shortcut.F9)
+ return "F" + (char)((int) '1' + (int)(Shortcut - Shortcut.F1));
+
+ /* Shift+F1 - Shift+F9 */
+ if (Shortcut >= Shortcut.ShiftF1 && Shortcut <= Shortcut.ShiftF9)
+ return GetShortCutTextShift () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.ShiftF1));
+
+ /* Special cases */
+ switch (Shortcut) {
+ case Shortcut.AltBksp:
+ return "AltBksp";
+ case Shortcut.AltF10:
+ return GetShortCutTextAlt () + "+F10";
+ case Shortcut.AltF11:
+ return GetShortCutTextAlt () + "+F11";
+ case Shortcut.AltF12:
+ return GetShortCutTextAlt () + "+F12";
+ case Shortcut.CtrlDel:
+ return GetShortCutTextCtrl () + "+Del";
+ case Shortcut.CtrlF10:
+ return GetShortCutTextCtrl () + "+F10";
+ case Shortcut.CtrlF11:
+ return GetShortCutTextCtrl () + "+F11";
+ case Shortcut.CtrlF12:
+ return GetShortCutTextCtrl () + "+F12";
+ case Shortcut.CtrlIns:
+ return GetShortCutTextCtrl () + "+Ins";
+ case Shortcut.CtrlShiftF10:
+ return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F10";
+ case Shortcut.CtrlShiftF11:
+ return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F11";
+ case Shortcut.CtrlShiftF12:
+ return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F12";
+ case Shortcut.Del:
+ return "Del";
+ case Shortcut.F10:
+ return "F10";
+ case Shortcut.F11:
+ return "F11";
+ case Shortcut.F12:
+ return "F12";
+ case Shortcut.Ins:
+ return "Ins";
+ case Shortcut.None:
+ return "None";
+ case Shortcut.ShiftDel:
+ return GetShortCutTextShift () + "+Del";
+ case Shortcut.ShiftF10:
+ return GetShortCutTextShift () + "+F10";
+ case Shortcut.ShiftF11:
+ return GetShortCutTextShift () + "+F11";
+ case Shortcut.ShiftF12:
+ return GetShortCutTextShift () + "+F12";
+ case Shortcut.ShiftIns:
+ return GetShortCutTextShift () + "+Ins";
+ default:
+ break;
+ }
+
+ return "";
+ }
+
+ private void MdiWindowClickHandler (object sender, EventArgs e)
+ {
+ Form mdichild = (Form) mdilist_items [sender];
+
+ // people could add weird items to the Window menu
+ // so we can't assume its just us
+ if (mdichild == null)
+ return;
+
+ mdicontainer.ActivateChild (mdichild);
+ }
+
+ private void UpdateMenuItem ()
+ {
+ if ((parent_menu == null) || (parent_menu.Tracker == null))
+ return;
+
+ parent_menu.Tracker.RemoveShortcuts (this);
+ parent_menu.Tracker.AddShortcuts (this);
+ }
+
+ #endregion Private Methods
+
+ }
+}
+
+
diff --git a/source/ShiftUI/Menu/MenuMerge.cs b/source/ShiftUI/Menu/MenuMerge.cs
new file mode 100644
index 0000000..8731f64
--- /dev/null
+++ b/source/ShiftUI/Menu/MenuMerge.cs
@@ -0,0 +1,38 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2004 Novell, Inc.
+//
+// Authors:
+// Jordi Mas i Hernandez, [email protected]
+//
+//
+
+namespace ShiftUI
+{
+ public enum MenuMerge
+ {
+ Add = 0,
+ Replace = 1,
+ MergeItems = 2,
+ Remove = 3,
+ }
+}
+
+
diff --git a/source/ShiftUI/Menu/MenuStrip.cs b/source/ShiftUI/Menu/MenuStrip.cs
new file mode 100644
index 0000000..85e585e
--- /dev/null
+++ b/source/ShiftUI/Menu/MenuStrip.cs
@@ -0,0 +1,349 @@
+//
+// MenuStrip.cs
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2006 Jonathan Pobst
+//
+// Authors:
+// Jonathan Pobst ([email protected])
+//
+
+using System;
+using System.Drawing;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+
+namespace ShiftUI
+{
+ [ClassInterface (ClassInterfaceType.AutoDispatch)]
+ [ComVisible (true)]
+ public class MenuStrip : ToolStrip
+ {
+ private ToolStripMenuItem mdi_window_list_item;
+
+ public MenuStrip () : base ()
+ {
+ base.CanOverflow = false;
+ this.GripStyle = ToolStripGripStyle.Hidden;
+ this.Stretch = true;
+ this.Dock = DockStyle.Top;
+ }
+
+ #region Public Properties
+ [DefaultValue (false)]
+ [Browsable (false)]
+ public new bool CanOverflow {
+ get { return base.CanOverflow; }
+ set { base.CanOverflow = value; }
+ }
+
+ [DefaultValue (ToolStripGripStyle.Hidden)]
+ public new ToolStripGripStyle GripStyle {
+ get { return base.GripStyle; }
+ set { base.GripStyle = value; }
+ }
+
+ [DefaultValue (null)]
+ [MergableProperty (false)]
+ [TypeConverter (typeof (MdiWindowListItemConverter))]
+ public ToolStripMenuItem MdiWindowListItem {
+ get { return this.mdi_window_list_item; }
+ set {
+ if (this.mdi_window_list_item != value) {
+ this.mdi_window_list_item = value;
+ this.RefreshMdiItems ();
+ }
+ }
+ }
+
+ [DefaultValue (false)]
+ public new bool ShowItemToolTips {
+ get { return base.ShowItemToolTips; }
+ set { base.ShowItemToolTips = value; }
+ }
+
+ [DefaultValue (true)]
+ public new bool Stretch {
+ get { return base.Stretch; }
+ set { base.Stretch = value; }
+ }
+ #endregion
+
+ #region Protected Properties
+ protected override Padding DefaultGripMargin { get { return new Padding (2, 2, 0, 2); } }
+ protected override Padding DefaultPadding { get { return new Padding (6, 2, 0, 2); } }
+ protected override bool DefaultShowItemToolTips { get { return false; } }
+ protected override Size DefaultSize { get { return new Size (200, 24); } }
+ #endregion
+
+ #region Protected Methods
+ protected override AccessibleObject CreateAccessibilityInstance ()
+ {
+ return new MenuStripAccessibleObject ();
+ }
+
+ protected internal override ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick)
+ {
+ return new ToolStripMenuItem (text, image, onClick);
+ }
+
+ protected virtual void OnMenuActivate (EventArgs e)
+ {
+ EventHandler eh = (EventHandler)(Events [MenuActivateEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+ protected virtual void OnMenuDeactivate (EventArgs e)
+ {
+ EventHandler eh = (EventHandler)(Events [MenuDeactivateEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+ protected override bool ProcessCmdKey (ref Message m, Keys keyData)
+ {
+ return base.ProcessCmdKey (ref m, keyData);
+ }
+
+ protected override void WndProc (ref Message m)
+ {
+ base.WndProc (ref m);
+ }
+ #endregion
+
+ #region Public Events
+ static object MenuActivateEvent = new object ();
+ static object MenuDeactivateEvent = new object ();
+
+ public event EventHandler MenuActivate {
+ add { Events.AddHandler (MenuActivateEvent, value); }
+ remove { Events.RemoveHandler (MenuActivateEvent, value); }
+ }
+
+ public event EventHandler MenuDeactivate {
+ add { Events.AddHandler (MenuDeactivateEvent, value); }
+ remove { Events.RemoveHandler (MenuDeactivateEvent, value); }
+ }
+ #endregion
+
+ #region Internal Properties
+ internal override bool KeyboardActive {
+ get { return base.KeyboardActive; }
+ set {
+ if (base.KeyboardActive != value) {
+ base.KeyboardActive = value;
+
+ if (value)
+ this.OnMenuActivate (EventArgs.Empty);
+ else
+ this.OnMenuDeactivate (EventArgs.Empty);
+ }
+ }
+ }
+
+ internal bool MenuDroppedDown {
+ get { return this.menu_selected; }
+ set { this.menu_selected = value; }
+ }
+ #endregion
+
+ #region Internal Methods
+ internal override void Dismiss (ToolStripDropDownCloseReason reason)
+ {
+ // Make sure we don't auto-dropdown next time we're activated
+ this.MenuDroppedDown = false;
+
+ base.Dismiss (reason);
+
+ this.FireMenuDeactivate ();
+ }
+
+ internal void FireMenuActivate ()
+ {
+ // The tracker lets us know when the form is clicked or loses focus
+ ToolStripManager.AppClicked += new EventHandler (ToolStripMenuTracker_AppClicked);
+ ToolStripManager.AppFocusChange += new EventHandler (ToolStripMenuTracker_AppFocusChange);
+
+ this.OnMenuActivate (EventArgs.Empty);
+ }
+
+ internal void FireMenuDeactivate ()
+ {
+ // Detach from the tracker
+ ToolStripManager.AppClicked -= new EventHandler (ToolStripMenuTracker_AppClicked); ;
+ ToolStripManager.AppFocusChange -= new EventHandler (ToolStripMenuTracker_AppFocusChange);
+
+ this.OnMenuDeactivate (EventArgs.Empty);
+ }
+
+ internal override bool OnMenuKey ()
+ {
+ // Set ourselves active and select our first item
+ ToolStripManager.SetActiveToolStrip (this, true);
+ ToolStripItem tsi = this.SelectNextToolStripItem (null, true);
+
+ if (tsi == null)
+ return false;
+
+ if (tsi is MdiWidgetStrip.SystemMenuItem)
+ this.SelectNextToolStripItem (tsi, true);
+
+ return true;
+ }
+
+ private void ToolStripMenuTracker_AppFocusChange (object sender, EventArgs e)
+ {
+ this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppFocusChange);
+ }
+
+ private void ToolStripMenuTracker_AppClicked (object sender, EventArgs e)
+ {
+ this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppClicked);
+ }
+
+ internal void RefreshMdiItems ()
+ {
+ if (this.mdi_window_list_item == null)
+ return;
+
+ Form parent_form = this.FindForm ();
+
+ if (parent_form == null || parent_form.MainMenuStrip != this)
+ return;
+
+ MdiClient mdi = parent_form.MdiContainer;
+
+ // If there isn't a MdiContainer, we don't need to worry about MdiItems :)
+ if (mdi == null)
+ return;
+
+ // Make a copy so we can delete from the real one
+ ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count];
+ this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0);
+
+ // If the mdi child has been removed, remove our menu item
+ foreach (ToolStripItem tsi in loopitems)
+ if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
+ if (!mdi.mdi_child_list.Contains ((tsi as ToolStripMenuItem).MdiClientForm) || !(tsi as ToolStripMenuItem).MdiClientForm.Visible)
+ this.mdi_window_list_item.DropDownItems.Remove (tsi);
+
+ // Add the new forms and update state
+ for (int i = 0; i < mdi.mdi_child_list.Count; i++) {
+ Form mdichild = (Form)mdi.mdi_child_list[i];
+ ToolStripMenuItem tsi;
+
+ if (!mdichild.Visible)
+ continue;
+
+ if ((tsi = FindMdiMenuItemOfForm (mdichild)) == null) {
+ 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))
+ this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ());
+
+ tsi = new ToolStripMenuItem ();
+ tsi.MdiClientForm = mdichild;
+ this.mdi_window_list_item.DropDownItems.Add (tsi);
+ }
+
+ tsi.Text = string.Format ("&{0} {1}", i + 1, mdichild.Text);
+ tsi.Checked = parent_form.ActiveMdiChild == mdichild;
+ }
+
+ // Check that everything is in the correct order
+ if (NeedToReorderMdi ())
+ ReorderMdiMenu ();
+ }
+
+ private ToolStripMenuItem FindMdiMenuItemOfForm (Form f)
+ {
+ // Not terribly efficient, but Mdi window lists shouldn't get too big
+ foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems)
+ if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).MdiClientForm == f)
+ return (ToolStripMenuItem)tsi;
+
+ return null;
+ }
+
+ private int CountMdiMenuItems ()
+ {
+ int count = 0;
+
+ foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems)
+ if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
+ count++;
+
+ return count;
+ }
+
+ private bool NeedToReorderMdi ()
+ {
+ // Mdi menus must be: User Items, Separator, Mdi Items
+ bool seenMdi = false;
+
+ foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems) {
+ if (tsi is ToolStripMenuItem) {
+ if (!(tsi as ToolStripMenuItem).IsMdiWindowListEntry) {
+ if (seenMdi)
+ return true;
+ } else
+ seenMdi = true;
+ }
+ }
+
+ return false;
+ }
+
+ private void ReorderMdiMenu ()
+ {
+ ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count];
+ this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0);
+
+ this.mdi_window_list_item.DropDownItems.Clear ();
+
+ foreach (ToolStripItem tsi in loopitems)
+ if (tsi is ToolStripSeparator || !(tsi as ToolStripMenuItem).IsMdiWindowListEntry)
+ this.mdi_window_list_item.DropDownItems.Add (tsi);
+
+ int count = this.mdi_window_list_item.DropDownItems.Count;
+
+ if (count > 0 && !(this.mdi_window_list_item.DropDownItems[count - 1] is ToolStripSeparator))
+ this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ());
+
+ foreach (ToolStripItem tsi in loopitems)
+ if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
+ this.mdi_window_list_item.DropDownItems.Add (tsi);
+ }
+ #endregion
+
+ #region MenuStripAccessibleObject
+ private class MenuStripAccessibleObject : AccessibleObject
+ {
+ }
+ #endregion
+
+ }
+
+ #region MdiWindowListItemConverter
+ internal class MdiWindowListItemConverter : TypeConverter
+ {
+ }
+ #endregion
+}