aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/Menu/Menu.cs
diff options
context:
space:
mode:
authorMichael VanOverbeek <[email protected]>2016-07-25 12:57:52 -0400
committerGitHub <[email protected]>2016-07-25 12:57:52 -0400
commit46c1c31302f111a1f3ec23a70e6f3986a9aa2a27 (patch)
treef00af7ea3f6ad2641fb26fa1d310fd8b7179b39c /source/ShiftUI/Menu/Menu.cs
parentaf48e774189596b8d7a058c564a7d6d75205ca03 (diff)
parent6fa16209519896de09949a27425dff00ebf2970a (diff)
downloadshiftos-c--46c1c31302f111a1f3ec23a70e6f3986a9aa2a27.tar.gz
shiftos-c--46c1c31302f111a1f3ec23a70e6f3986a9aa2a27.tar.bz2
shiftos-c--46c1c31302f111a1f3ec23a70e6f3986a9aa2a27.zip
Merge pull request #17 from MichaelTheShifter/shiftui_integration
Shiftui integration
Diffstat (limited to 'source/ShiftUI/Menu/Menu.cs')
-rw-r--r--source/ShiftUI/Menu/Menu.cs621
1 files changed, 621 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
+ }
+ }
+}
+
+