using System.Collections.Generic; using System.Windows.Forms.RibbonHelpers; namespace System.Windows.Forms { /// /// Manages opened popups /// public static class RibbonPopupManager { #region Subclasses /// /// Specifies reasons why pop-ups can be dismissed /// public enum DismissReason { /// /// An item has been clicked /// ItemClicked, /// /// The app has been clicked /// AppClicked, /// /// A new popup is showing and will hide sibling's popups /// NewPopup, /// /// The aplication window has been deactivated /// AppFocusChanged, /// /// User has pressed escape on the keyboard /// EscapePressed } #endregion #region Events public static event EventHandler PopupRegistered; public static event EventHandler PopupUnRegistered; #endregion #region Fields private static readonly List pops; #endregion #region Ctor static RibbonPopupManager() { pops = new List(); } #endregion #region Props /// /// Gets the last pop-up of the collection /// internal static RibbonPopup LastPopup { get { if (pops.Count > 0) { return pops[pops.Count - 1]; } return null; } } internal static int PopupCount => pops.Count; #endregion #region Methods /// /// Registers a popup existance /// /// internal static void Register(RibbonPopup p) { if (!pops.Contains(p)) { pops.Add(p); PopupRegistered(p, EventArgs.Empty); } } /// /// Unregisters a popup from existance /// /// internal static void Unregister(RibbonPopup p) { if (pops.Contains(p)) { pops.Remove(p); PopupUnRegistered(p, EventArgs.Empty); } } /// /// Feeds a click generated on the mouse hook /// /// internal static bool FeedHookClick(MouseEventArgs e) { //Al-74 fix (see GitHub issue #10): //Starting from Windows 10 April 2018 Update (version 1803) with display scaling above 100%, e.Location is the physical mouse location, //not scaled according to display scaling, so the Contains function fails check and no events fires when clicking RibbonButtons dropdown items. //Use GetCursorPos api instead of e.Location seems to solve the problem. WinApi.POINT pos; if (WinApi.GetCursorPos(out pos)) { foreach (RibbonPopup p in pops) { if (p.WrappedDropDown.Bounds.Contains(pos.x, pos.y)) //if (p.WrappedDropDown.Bounds.Contains(e.Location)) { return true; } } } //If click was in no dropdown, let's go everyone Dismiss(DismissReason.AppClicked); return false; } /// /// Feeds mouse Wheel. If applied on a IScrollableItem it's sended to it /// /// /// True if handled. False otherwise internal static bool FeedMouseWheel(MouseEventArgs e) { RibbonDropDown dd = LastPopup as RibbonDropDown; if (dd != null) { WinApi.POINT pos; if (WinApi.GetCursorPos(out pos)) { foreach (RibbonItem item in dd.Items) { if (dd.RectangleToScreen(item.Bounds).Contains(pos.x, pos.y)) //if (dd.RectangleToScreen(item.Bounds).Contains(e.Location)) { IScrollableRibbonItem sc = item as IScrollableRibbonItem; if (sc != null) { if (e.Delta < 0) { sc.ScrollDown(); } else { sc.ScrollUp(); } return true; } } } } } //kevin carbis - added scrollbar support to dropdowns so we need to feed the mouse wheel to the //actual dropdown item if it was not intended for a child item. if (dd != null) { if (e.Delta < 0) { dd.ScrollDown(); } else { dd.ScrollUp(); } return true; } return false; } /// /// Closes all children of specified pop-up /// /// Pop-up of which children will be closed /// Reason for dismissing public static void DismissChildren(RibbonPopup parent, DismissReason reason) { int index = pops.IndexOf(parent); if (index >= 0) { Dismiss(index + 1, reason); } } /// /// Closes all currently registered pop-ups /// /// public static void Dismiss(DismissReason reason) { Dismiss(0, reason); } /// /// Closes specified pop-up and all its descendants /// /// Pop-up to close (and its descendants) /// Reason for closing public static void Dismiss(RibbonPopup startPopup, DismissReason reason) { int index = pops.IndexOf(startPopup); if (index >= 0) { Dismiss(index, reason); } } /// /// Closes pop-up of the specified index and all its descendants /// /// Index of the pop-up to close /// Reason for closing private static void Dismiss(int startPopup, DismissReason reason) { for (int i = pops.Count - 1; i >= startPopup; i--) { pops[i].Close(); } } #endregion } }