From 05cb02aa0987e901b4bf5b1758bf6a051839b6d7 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 17 Feb 2023 20:44:23 +0100 Subject: [PATCH] Improve #936 for ExternalPopups and preserve odl impl on Windows --- .../Editor/GUI/ContextMenu/ContextMenuBase.cs | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs index 8596ab83b..27d47345d 100644 --- a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs +++ b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs @@ -1,3 +1,7 @@ +#if PLATFORM_WINDOWS +#define USE_IS_FOREGROUND +#else +#endif // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System.Collections.Generic; @@ -196,6 +200,7 @@ namespace FlaxEditor.GUI.ContextMenu desc.HasSizingFrame = false; OnWindowCreating(ref desc); _window = Platform.CreateWindow(ref desc); + _window.GotFocus += OnWindowGotFocus; _window.LostFocus += OnWindowLostFocus; // Attach to the window @@ -325,6 +330,49 @@ namespace FlaxEditor.GUI.ContextMenu // Nothing to do } +#if USE_IS_FOREGROUND + /// + /// Returns true if context menu is in foreground (eg. context window or any child window has user focus or user opened additional popup within this context). + /// + protected virtual bool IsForeground + { + get + { + // Any external popup is focused + foreach (var externalPopup in ExternalPopups) + { + if (externalPopup && externalPopup.IsForegroundWindow) + return true; + } + + // Any context menu window is focused + var anyForeground = false; + var c = this; + while (!anyForeground && c != null) + { + if (c._window != null && c._window.IsForegroundWindow) + anyForeground = true; + c = c._childCM; + } + + return anyForeground; + } + } + + private void OnWindowGotFocus() + { + var child = _childCM; + if (child != null && _window && _window.IsForegroundWindow) + { + // Hide child if user clicked over parent (do it next frame to process other events before - eg. child windows focus loss) + FlaxEngine.Scripting.InvokeOnUpdate(() => + { + if (child == _childCM) + HideChild(); + }); + } + } + private void OnWindowLostFocus() { // Skip for parent menus (child should handle lost of focus) @@ -332,11 +380,39 @@ namespace FlaxEditor.GUI.ContextMenu return; // Check if user stopped using that popup menu + if (_parentCM != null) + { + // Focus parent if user clicked over the parent popup + var mouse = _parentCM.PointFromScreen(FlaxEngine.Input.MouseScreenPosition); + if (_parentCM.ContainsPoint(ref mouse)) + { + _parentCM._window.Focus(); + } + } + } +#else + private void OnWindowGotFocus() + { + } + + private void OnWindowLostFocus() + { + // Skip for parent menus (child should handle lost of focus) + if (_childCM != null) + return; + if (_parentCM != null) { if (IsMouseOver) return; + // Check if any external popup is focused + foreach (var externalPopup in ExternalPopups) + { + if (externalPopup && externalPopup.IsFocused) + return; + } + // Check if mouse is over any of the parents ContextMenuBase focusCM = null; var cm = _parentCM; @@ -360,8 +436,11 @@ namespace FlaxEditor.GUI.ContextMenu } } else if (!IsMouseOver) + { Hide(); + } } +#endif /// public override bool IsMouseOver @@ -382,6 +461,20 @@ namespace FlaxEditor.GUI.ContextMenu } } +#if USE_IS_FOREGROUND + /// + public override void Update(float deltaTime) + { + base.Update(deltaTime); + + // Let root context menu to check if none of the popup windows + if (_parentCM == null && !IsForeground) + { + Hide(); + } + } +#endif + /// public override void Draw() {