aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/ToolStrip/ToolStripManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'source/ShiftUI/ToolStrip/ToolStripManager.cs')
-rw-r--r--source/ShiftUI/ToolStrip/ToolStripManager.cs634
1 files changed, 634 insertions, 0 deletions
diff --git a/source/ShiftUI/ToolStrip/ToolStripManager.cs b/source/ShiftUI/ToolStrip/ToolStripManager.cs
new file mode 100644
index 0000000..f580413
--- /dev/null
+++ b/source/ShiftUI/ToolStrip/ToolStripManager.cs
@@ -0,0 +1,634 @@
+//
+// ToolStripManager.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.Drawing;
+using System.Runtime.InteropServices;
+using System.ComponentModel;
+using System.Collections.Generic;
+using System;
+
+namespace ShiftUI
+{
+ public sealed class ToolStripManager
+ {
+ private static ToolStripRenderer renderer = new ToolStripProfessionalRenderer ();
+ private static ToolStripManagerRenderMode render_mode = ToolStripManagerRenderMode.Professional;
+ private static bool visual_styles_enabled = Application.RenderWithVisualStyles;
+ private static List<WeakReference> toolstrips = new List<WeakReference> ();
+ private static List<ToolStripMenuItem> menu_items = new List<ToolStripMenuItem> ();
+ private static bool activated_by_keyboard;
+
+ #region Private Constructor
+ private ToolStripManager ()
+ {
+ }
+ #endregion
+
+ #region Public Properties
+ public static ToolStripRenderer Renderer {
+ get { return ToolStripManager.renderer; }
+ set {
+ if (ToolStripManager.Renderer != value) {
+ ToolStripManager.renderer = value;
+ ToolStripManager.OnRendererChanged (EventArgs.Empty);
+ }
+ }
+ }
+
+ public static ToolStripManagerRenderMode RenderMode {
+ get { return ToolStripManager.render_mode; }
+ set {
+ if (!Enum.IsDefined (typeof (ToolStripManagerRenderMode), value))
+ throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripManagerRenderMode", value));
+
+ if (ToolStripManager.render_mode != value) {
+ ToolStripManager.render_mode = value;
+
+ switch (value) {
+ case ToolStripManagerRenderMode.Custom:
+ throw new NotSupportedException ();
+ case ToolStripManagerRenderMode.System:
+ ToolStripManager.Renderer = new ToolStripSystemRenderer ();
+ break;
+ case ToolStripManagerRenderMode.Professional:
+ ToolStripManager.Renderer = new ToolStripProfessionalRenderer ();
+ break;
+ }
+ }
+ }
+ }
+
+ public static bool VisualStylesEnabled {
+ get { return ToolStripManager.visual_styles_enabled; }
+ set {
+ if (ToolStripManager.visual_styles_enabled != value) {
+ ToolStripManager.visual_styles_enabled = value;
+
+ if (ToolStripManager.render_mode == ToolStripManagerRenderMode.Professional) {
+ (ToolStripManager.renderer as ToolStripProfessionalRenderer).ColorTable.UseSystemColors = !value;
+ ToolStripManager.OnRendererChanged (EventArgs.Empty);
+ }
+ }
+ }
+ }
+ #endregion
+
+ #region Public Methods
+ public static ToolStrip FindToolStrip (string toolStripName)
+ {
+ lock (toolstrips)
+ foreach (WeakReference wr in toolstrips) {
+ ToolStrip ts = (ToolStrip)wr.Target;
+
+ if (ts == null)
+ continue;
+
+ if (ts.Name == toolStripName)
+ return ts;
+ }
+
+ return null;
+ }
+
+ public static bool IsShortcutDefined (Keys shortcut)
+ {
+ lock (menu_items)
+ foreach (ToolStripMenuItem tsmi in menu_items)
+ if (tsmi.ShortcutKeys == shortcut)
+ return true;
+
+ return false;
+ }
+
+ public static bool IsValidShortcut (Keys shortcut)
+ {
+ // Anything with an F1 - F12 is a shortcut
+ if ((shortcut & Keys.F1) == Keys.F1)
+ return true;
+ else if ((shortcut & Keys.F2) == Keys.F2)
+ return true;
+ else if ((shortcut & Keys.F3) == Keys.F3)
+ return true;
+ else if ((shortcut & Keys.F4) == Keys.F4)
+ return true;
+ else if ((shortcut & Keys.F5) == Keys.F5)
+ return true;
+ else if ((shortcut & Keys.F6) == Keys.F6)
+ return true;
+ else if ((shortcut & Keys.F7) == Keys.F7)
+ return true;
+ else if ((shortcut & Keys.F8) == Keys.F8)
+ return true;
+ else if ((shortcut & Keys.F9) == Keys.F9)
+ return true;
+ else if ((shortcut & Keys.F10) == Keys.F10)
+ return true;
+ else if ((shortcut & Keys.F11) == Keys.F11)
+ return true;
+ else if ((shortcut & Keys.F12) == Keys.F12)
+ return true;
+
+ // Modifier keys alone are not shortcuts
+ switch (shortcut) {
+ case Keys.Alt:
+ case Keys.Widget:
+ case Keys.Shift:
+ case Keys.Alt | Keys.Widget:
+ case Keys.Alt | Keys.Shift:
+ case Keys.Widget | Keys.Shift:
+ case Keys.Alt | Keys.Widget | Keys.Shift:
+ return false;
+ }
+
+ // Anything else with a modifier key is a shortcut
+ if ((shortcut & Keys.Alt) == Keys.Alt)
+ return true;
+ else if ((shortcut & Keys.Widget) == Keys.Widget)
+ return true;
+ else if ((shortcut & Keys.Shift) == Keys.Shift)
+ return true;
+
+ // Anything else is not a shortcut
+ return false;
+ }
+
+ [MonoTODO ("Stub, does nothing")]
+ public static void LoadSettings (Form targetForm)
+ {
+ if (targetForm == null)
+ throw new ArgumentNullException ("targetForm");
+ }
+
+ [MonoTODO ("Stub, does nothing")]
+ public static void LoadSettings (Form targetForm, string key)
+ {
+ if (targetForm == null)
+ throw new ArgumentNullException ("targetForm");
+ if (string.IsNullOrEmpty (key))
+ throw new ArgumentNullException ("key");
+ }
+
+ [MonoLimitation ("Only supports one level of merging, cannot merge the same ToolStrip multiple times")]
+ public static bool Merge (ToolStrip sourceToolStrip, string targetName)
+ {
+ if (string.IsNullOrEmpty (targetName))
+ throw new ArgumentNullException ("targetName");
+
+ return Merge (sourceToolStrip, FindToolStrip (targetName));
+ }
+
+ [MonoLimitation ("Only supports one level of merging, cannot merge the same ToolStrip multiple times")]
+ public static bool Merge (ToolStrip sourceToolStrip, ToolStrip targetToolStrip)
+ {
+ // Check for exceptions
+ if (sourceToolStrip == null)
+ throw new ArgumentNullException ("sourceToolStrip");
+
+ if (targetToolStrip == null)
+ throw new ArgumentNullException ("targetName");
+
+ if (targetToolStrip == sourceToolStrip)
+ throw new ArgumentException ("Source and target ToolStrip must be different.");
+
+ // If the toolstrips don't allow merging, don't merge them
+ if (!sourceToolStrip.AllowMerge || !targetToolStrip.AllowMerge)
+ return false;
+
+ // We currently can't support merging multiple times
+ if (sourceToolStrip.IsCurrentlyMerged || targetToolStrip.IsCurrentlyMerged)
+ return false;
+
+ // What I wouldn't give to be able to modify a collection
+ // while enumerating through it...
+
+ List<ToolStripItem> items_to_move = new List<ToolStripItem> ();
+
+ // Create a list of every ToolStripItem we plan on moving
+ foreach (ToolStripItem tsi in sourceToolStrip.Items) {
+ switch (tsi.MergeAction) {
+ case MergeAction.Append:
+ default:
+ items_to_move.Add (tsi);
+ break;
+ case MergeAction.Insert:
+ if (tsi.MergeIndex >= 0)
+ items_to_move.Add (tsi);
+ break;
+ case MergeAction.Replace:
+ case MergeAction.Remove:
+ case MergeAction.MatchOnly:
+ foreach (ToolStripItem target_tsi in targetToolStrip.Items)
+ if (tsi.Text == target_tsi.Text) {
+ items_to_move.Add (tsi);
+ break;
+ }
+ break;
+ }
+ }
+
+ // If there was nothing valid to merge, return false
+ if (items_to_move.Count == 0)
+ return false;
+
+ // Set some state so we can unmerge later
+ sourceToolStrip.BeginMerge ();
+ targetToolStrip.BeginMerge ();
+
+ sourceToolStrip.SuspendLayout ();
+ targetToolStrip.SuspendLayout ();
+
+ while (items_to_move.Count > 0) {
+ ToolStripItem tsi = items_to_move[0];
+ items_to_move.Remove (tsi);
+
+ switch (tsi.MergeAction) {
+ case MergeAction.Append:
+ default:
+ // Just changing the parent will append it to the target
+ // and remove it from the source
+ ToolStrip.SetItemParent (tsi, targetToolStrip);
+
+ break;
+ case MergeAction.Insert:
+ // Do the same work as Append, except Insert it into the
+ // location specified by the MergeIndex
+ RemoveItemFromParentToolStrip (tsi);
+
+ if (tsi.MergeIndex == -1)
+ continue;
+ else if (tsi.MergeIndex >= CountRealToolStripItems (targetToolStrip))
+ targetToolStrip.Items.AddNoOwnerOrLayout (tsi);
+ else
+ targetToolStrip.Items.InsertNoOwnerOrLayout (AdjustItemMergeIndex (targetToolStrip, tsi), tsi);
+
+ tsi.Parent = targetToolStrip;
+
+ break;
+ case MergeAction.Replace:
+ // Find a target ToolStripItem with the same Text, remove it
+ // and replace it with the source one
+ foreach (ToolStripItem target_tsi in targetToolStrip.Items)
+ if (tsi.Text == target_tsi.Text) {
+ RemoveItemFromParentToolStrip (tsi);
+
+ // Insert where the old one is, then remove the old one
+ targetToolStrip.Items.InsertNoOwnerOrLayout (targetToolStrip.Items.IndexOf (target_tsi), tsi);
+ targetToolStrip.Items.RemoveNoOwnerOrLayout (target_tsi);
+
+ // Store the replaced one so we can get it back in unmerge
+ targetToolStrip.HiddenMergedItems.Add (target_tsi);
+ break;
+ }
+
+ break;
+ case MergeAction.Remove:
+ // Find a target ToolStripItem with the same Text, and remove
+ // it from the target, nothing else
+ foreach (ToolStripItem target_tsi in targetToolStrip.Items)
+ if (tsi.Text == target_tsi.Text) {
+ targetToolStrip.Items.RemoveNoOwnerOrLayout (target_tsi);
+
+ // Store the removed one so we can get it back in unmerge
+ targetToolStrip.HiddenMergedItems.Add (target_tsi);
+ break;
+ }
+
+ break;
+ case MergeAction.MatchOnly:
+ // Ugh, find the target ToolStripItem with the same Text, and take
+ // all the subitems from the source one, and append it to the target one
+ foreach (ToolStripItem target_tsi in targetToolStrip.Items)
+ if (tsi.Text == target_tsi.Text) {
+ if (target_tsi is ToolStripMenuItem && tsi is ToolStripMenuItem) {
+ ToolStripMenuItem source = (ToolStripMenuItem)tsi;
+ ToolStripMenuItem target = (ToolStripMenuItem)target_tsi;
+
+ ToolStripManager.Merge (source.DropDown, target.DropDown);
+ }
+
+ break;
+ }
+
+ break;
+ }
+ }
+
+ sourceToolStrip.ResumeLayout ();
+ targetToolStrip.ResumeLayout ();
+
+ // Store who we merged with, so we can unmerge when only given the target toolstrip
+ sourceToolStrip.CurrentlyMergedWith = targetToolStrip;
+ targetToolStrip.CurrentlyMergedWith = sourceToolStrip;
+
+ return true;
+ }
+
+ public static bool RevertMerge (string targetName)
+ {
+ return RevertMerge (FindToolStrip (targetName));
+ }
+
+ public static bool RevertMerge (ToolStrip targetToolStrip)
+ {
+ if (targetToolStrip == null)
+ return false;
+
+ return RevertMerge (targetToolStrip, targetToolStrip.CurrentlyMergedWith);
+ }
+
+ public static bool RevertMerge (ToolStrip targetToolStrip, ToolStrip sourceToolStrip)
+ {
+ if (sourceToolStrip == null)
+ return false;
+
+ List<ToolStripItem> items_to_move = new List<ToolStripItem> ();
+
+ // Find every ToolStripItem who's Owner is the source toolstrip
+ // - If it's a TSMI, see if any of the subitems need to be moved back
+ foreach (ToolStripItem tsi in targetToolStrip.Items) {
+ if (tsi.Owner == sourceToolStrip)
+ items_to_move.Add (tsi);
+ else if (tsi is ToolStripMenuItem)
+ foreach (ToolStripItem menuitem in (tsi as ToolStripMenuItem).DropDownItems)
+ foreach (ToolStripMenuItem tsmi in sourceToolStrip.Items)
+ if (menuitem.Owner == tsmi.DropDown)
+ items_to_move.Add (menuitem);
+ }
+
+ // If we didn't find anything, return false
+ if (items_to_move.Count == 0 && targetToolStrip.HiddenMergedItems.Count == 0)
+ return false;
+
+ // Put back all the target's items removed in the merge
+ while (targetToolStrip.HiddenMergedItems.Count > 0) {
+ targetToolStrip.RevertMergeItem (targetToolStrip.HiddenMergedItems[0]);
+ targetToolStrip.HiddenMergedItems.RemoveAt (0);
+ }
+
+ sourceToolStrip.SuspendLayout ();
+ targetToolStrip.SuspendLayout ();
+
+ // Revert everything
+ while (items_to_move.Count > 0) {
+ sourceToolStrip.RevertMergeItem (items_to_move[0]);
+ items_to_move.Remove (items_to_move[0]);
+ }
+
+ sourceToolStrip.ResumeLayout ();
+ targetToolStrip.ResumeLayout ();
+
+ sourceToolStrip.IsCurrentlyMerged = false;
+ targetToolStrip.IsCurrentlyMerged = false;
+
+ sourceToolStrip.CurrentlyMergedWith = null;
+ targetToolStrip.CurrentlyMergedWith = null;
+
+ return true;
+ }
+
+ public static void SaveSettings (Form sourceForm)
+ {
+ if (sourceForm == null)
+ throw new ArgumentNullException ("sourceForm");
+ }
+
+ public static void SaveSettings (Form sourceForm, string key)
+ {
+ if (sourceForm == null)
+ throw new ArgumentNullException ("sourceForm");
+ if (string.IsNullOrEmpty (key))
+ throw new ArgumentNullException ("key");
+ }
+ #endregion
+
+ #region Public Events
+ public static event EventHandler RendererChanged;
+ #endregion
+
+ #region Private/Internal Methods
+ internal static bool ActivatedByKeyboard {
+ get { return activated_by_keyboard; }
+ set { activated_by_keyboard = value; }
+ }
+
+ internal static void AddToolStrip (ToolStrip ts)
+ {
+ lock (toolstrips)
+ toolstrips.Add (new WeakReference (ts));
+ }
+
+ // When we have merged in MDI items like the min/max/close buttons, we
+ // can't count them for the sake of menu merging or it will mess up
+ // where people are trying to put them
+ private static int AdjustItemMergeIndex (ToolStrip ts, ToolStripItem tsi)
+ {
+ if (ts.Items[0] is MdiWidgetStrip.SystemMenuItem)
+ return tsi.MergeIndex + 1;
+
+ return tsi.MergeIndex;
+ }
+
+ private static int CountRealToolStripItems (ToolStrip ts)
+ {
+ int count = 0;
+
+ foreach (ToolStripItem tsi in ts.Items)
+ if (!(tsi is MdiWidgetStrip.WidgetBoxMenuItem) && !(tsi is MdiWidgetStrip.SystemMenuItem))
+ count++;
+
+ return count;
+ }
+
+ internal static ToolStrip GetNextToolStrip (ToolStrip ts, bool forward)
+ {
+ lock (toolstrips) {
+ List<ToolStrip> tools = new List<ToolStrip> ();
+
+ foreach (WeakReference wr in toolstrips) {
+ ToolStrip t = (ToolStrip)wr.Target;
+
+ if (t != null)
+ tools.Add (t);
+ }
+
+ int index = tools.IndexOf (ts);
+
+ if (forward) {
+ // Look for any toolstrip after this one in the collection
+ for (int i = index + 1; i < tools.Count; i++)
+ if (tools[i].TopLevelWidget == ts.TopLevelWidget && !(tools[i] is StatusStrip))
+ return tools[i];
+
+ // Look for any toolstrip before this one in the collection
+ for (int i = 0; i < index; i++)
+ if (tools[i].TopLevelWidget == ts.TopLevelWidget && !(tools[i] is StatusStrip))
+ return tools[i];
+ } else {
+ // Look for any toolstrip before this one in the collection
+ for (int i = index - 1; i >= 0; i--)
+ if (tools[i].TopLevelWidget == ts.TopLevelWidget && !(tools[i] is StatusStrip))
+ return tools[i];
+
+ // Look for any toolstrip after this one in the collection
+ for (int i = tools.Count - 1; i > index; i--)
+ if (tools[i].TopLevelWidget == ts.TopLevelWidget && !(tools[i] is StatusStrip))
+ return tools[i];
+ }
+ }
+
+ return null;
+ }
+
+ internal static bool ProcessCmdKey (ref Message m, Keys keyData)
+ {
+ lock (menu_items)
+ foreach (ToolStripMenuItem tsmi in menu_items)
+ if (tsmi.ProcessCmdKey (ref m, keyData) == true)
+ return true;
+
+ return false;
+ }
+
+ internal static bool ProcessMenuKey (ref Message m)
+ {
+ // If we have a currently active menu, deactivate it
+ if (Application.KeyboardCapture != null) {
+ if (Application.KeyboardCapture.OnMenuKey ())
+ return true;
+ }
+
+ // Get the parent form of this message
+ Form f = (Form)Widget.FromHandle (m.HWnd).TopLevelWidget;
+
+ // If there isn't a Form with this, there isn't much we can do
+ if (f == null)
+ return false;
+
+ // Check the MainMenuStrip property first
+ if (f.MainMenuStrip != null)
+ if (f.MainMenuStrip.OnMenuKey ())
+ return true;
+
+ // Look for any MenuStrip in the form
+ lock (toolstrips)
+ foreach (WeakReference wr in toolstrips) {
+ ToolStrip ts = (ToolStrip)wr.Target;
+
+ if (ts == null)
+ continue;
+
+ if (ts.TopLevelWidget == f)
+ if (ts.OnMenuKey ())
+ return true;
+ }
+
+ return false;
+ }
+
+ internal static void SetActiveToolStrip (ToolStrip toolStrip, bool keyboard)
+ {
+ if (Application.KeyboardCapture != null)
+ Application.KeyboardCapture.KeyboardActive = false;
+
+ if (toolStrip == null) {
+ activated_by_keyboard = false;
+ return;
+ }
+
+ activated_by_keyboard = keyboard;
+
+ toolStrip.KeyboardActive = true;
+ }
+
+ internal static void AddToolStripMenuItem (ToolStripMenuItem tsmi)
+ {
+ lock (menu_items)
+ menu_items.Add (tsmi);
+ }
+
+ internal static void RemoveToolStrip (ToolStrip ts)
+ {
+ lock (toolstrips) {
+ foreach (WeakReference wr in toolstrips)
+ if (wr.Target == ts) {
+ toolstrips.Remove (wr);
+ return;
+ }
+ }
+ }
+
+ internal static void RemoveToolStripMenuItem (ToolStripMenuItem tsmi)
+ {
+ lock (menu_items)
+ menu_items.Remove (tsmi);
+ }
+
+ internal static void FireAppClicked ()
+ {
+ if (AppClicked != null) AppClicked (null, EventArgs.Empty);
+
+ if (Application.KeyboardCapture != null)
+ Application.KeyboardCapture.Dismiss (ToolStripDropDownCloseReason.AppClicked);
+ }
+
+ internal static void FireAppFocusChanged (Form form)
+ {
+ if (AppFocusChange != null) AppFocusChange (form, EventArgs.Empty);
+
+ if (Application.KeyboardCapture != null)
+ Application.KeyboardCapture.Dismiss (ToolStripDropDownCloseReason.AppFocusChange);
+ }
+
+ internal static void FireAppFocusChanged (object sender)
+ {
+ if (AppFocusChange != null) AppFocusChange (sender, EventArgs.Empty);
+
+ if (Application.KeyboardCapture != null)
+ Application.KeyboardCapture.Dismiss (ToolStripDropDownCloseReason.AppFocusChange);
+ }
+
+ private static void OnRendererChanged (EventArgs e)
+ {
+ if (RendererChanged != null) RendererChanged (null, e);
+ }
+
+ private static void RemoveItemFromParentToolStrip (ToolStripItem tsi)
+ {
+ if (tsi.Owner != null) {
+ tsi.Owner.Items.RemoveNoOwnerOrLayout (tsi);
+
+ if (tsi.Owner is ToolStripOverflow)
+ (tsi.Owner as ToolStripOverflow).ParentToolStrip.Items.RemoveNoOwnerOrLayout (tsi);
+ }
+ }
+
+ internal static event EventHandler AppClicked;
+ internal static event EventHandler AppFocusChange;
+ #endregion
+ }
+}