Search Unity

Question Modal Window in editor mode

Discussion in 'UI Toolkit' started by Tom-Atom, Apr 16, 2021.

  1. Tom-Atom

    Tom-Atom

    Joined:
    Jun 29, 2014
    Posts:
    153
    Hi, I have main level editor window (EditorWindow) (encircled with blue on image) and when I click on any board cell, it opens second editor window (also EditorWindow - in red) with available items.

    Unfortunately, I can't find a way how to make this red window modal. While red window is open, I want to block all input into blue window. Currently, if clicking blue window it also brings it into front over red one. I want classic modal window, which exclusively takes all input until it is closed.

    - I tried to consume all mouse events (MouseMoveEvent) in red window, but it gets them only if mouse moves over it.
    - I tried to set picking mode to ignore on top visual element of blue window, but it looks, like picking is only set on single element and not on whole sub-tree.
    - HTML5 has "pointer-events: none;" which disables input on element and all descendands, but I can't find something similar to this in Unity.

    What I have to do to make red window modal in editor?

    LevelEditor.jpg
     
    eses likes this.
  2. sebastiend-unity

    sebastiend-unity

    Unity Technologies

    Joined:
    Nov 9, 2015
    Posts:
    184
  3. uMathieu

    uMathieu

    Unity Technologies

    Joined:
    Jun 6, 2017
    Posts:
    398
  4. sebastiend-unity

    sebastiend-unity

    Unity Technologies

    Joined:
    Nov 9, 2015
    Posts:
    184
    Hey let's back up. I skipped over the fact that you are in editor mode. You should be able to use Editor.ShowModalUtility for your case.
     
  5. Tom-Atom

    Tom-Atom

    Joined:
    Jun 29, 2014
    Posts:
    153
    @uMathieu ,@sebastiend-unity - thanks for answer! Yes it works... with some flaws:
    - scheduler tasks are not executed (one time nor periodic),
    - EditorWindow.Update callback is not called,
    - asynchronous tasks are not executed.

    Currently, I am happy as I achieved what I needed. But above problems prevent me to make editor better. In my modal window I am also doing some changes to main board and I am calling my custom repaint function on main window. But as long as modal window is open, it is ignored. When modal window is closed, all repaints run at once.

    I thought, that modal window will be mainly "input block", forcing user to interact with it. But it looks to be heavy blocker, blocking above mentioned tasks as well as other calls into other windows. On the other hand registered callbacks from keys, mouse or other elements work.
     
  6. uMathieu

    uMathieu

    Unity Technologies

    Joined:
    Jun 6, 2017
    Posts:
    398
    @Tom-Atom Can you Report the issues you encountered with Help-> Report a bug... ? If you can provide us with a sample script that will help greatly
     
  7. Tom-Atom

    Tom-Atom

    Joined:
    Jun 29, 2014
    Posts:
    153
    @uMathieu I submitted report (Case 1333331) with minimal example. In fact, it consist of two scripts for two windows - main and modal (code is below). Open Main Window with menu Test -> Main Window. Opening modal window starts in background:
    • UI Toolkit scheduler,
    • loop of 5 async tasks,
    • implements Update() method
    None of above is called if modal window was started with EditorWindow.ShowModalUtility()

    If you comment line with EditorWindow.ShowModalUtility(). Then all above runs well, but window is not modal.

    Regarding repaints: changes into UI tree are displayed immediately. But if change is made from modal window into parent, then parent is not changed until modal is closed (then all changes appear). I found, that I can force parent window to repait by calling Repaint() explicitlly. This is not needed if child window is not displayed as modal.


    MainWindow.cs
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using UnityEngine.UIElements;
    4.  
    5. public class MainWindow : EditorWindow {
    6.  
    7.     [MenuItem("Test/Main Window")]
    8.     public static void CreateMainWindow() {
    9.  
    10.         MainWindow window = GetWindow<MainWindow>("Main Window");
    11.         window.minSize = new Vector2(200, 200);
    12.     }
    13.  
    14.     public void CreateGUI() {
    15.  
    16.         VisualTreeAsset visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/MainWindowTemplate.uxml");
    17.  
    18.         rootVisualElement.Clear();
    19.         visualTree.CloneTree(rootVisualElement);
    20.  
    21.         Button button = rootVisualElement.Q<Button>("button");
    22.         button.clicked += HandleShowModal;
    23.     }
    24.  
    25.     private void HandleShowModal() {
    26.  
    27.         ModalWindow.CreateModalWindow();
    28.     }
    29. }
    30.  
    MainWindowTemplate.uxml

    <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
    <ui:VisualElement style="align-items: center;">
    <ui:Button text="Show Modal" display-tooltip-when-elided="true" name="button" style="width: 200px; align-items: auto; margin-top: 20px; margin-bottom: 20px;" />
    </ui:VisualElement>
    </ui:UXML>


    ModalWindow.cs
    Code (CSharp):
    1. using System.Threading.Tasks;
    2. using UnityEditor;
    3. using UnityEngine;
    4. using UnityEngine.UIElements;
    5.  
    6. public class ModalWindow : EditorWindow {
    7.  
    8.     private double _time = 0;
    9.  
    10.     public static void CreateModalWindow() {
    11.  
    12.         ModalWindow window = GetWindow<ModalWindow>("Modal Window");
    13.         window.minSize = new Vector2(200, 200);
    14.  
    15.         window.ShowModalUtility();
    16.     }
    17.  
    18.     public void CreateGUI() {
    19.  
    20.         VisualTreeAsset visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/ModalWindowTemplate.uxml");
    21.  
    22.         rootVisualElement.Clear();
    23.         visualTree.CloneTree(rootVisualElement);
    24.  
    25.         Button closeButton = rootVisualElement.Q<Button>("closeButton");
    26.         closeButton.clicked += () => {
    27.             Close();
    28.         };
    29.  
    30.         SetPeriodicEvent();     // UI Toolkit scheduled item
    31.         AsyncTask();            // C# async task
    32.     }
    33.  
    34.     private void SetPeriodicEvent() {
    35.  
    36.         int count = 0;
    37.         var scheduledItem = rootVisualElement.schedule.Execute(() => {
    38.             Debug.Log($"Modal Window scheduled task - count = {count++}");
    39.         });
    40.         scheduledItem.Every(1000);
    41.     }
    42.  
    43.     private async void AsyncTask() {
    44.  
    45.         int count = 0;
    46.  
    47.         for (int i = 0; i < 5; i++) {
    48.  
    49.             await Task.Delay(1000);
    50.             Debug.Log($"AsyncTask - (count = {count})");
    51.  
    52.             ++count;
    53.         }
    54.     }
    55.  
    56.     private void Update() {
    57.  
    58.         if (EditorApplication.timeSinceStartup - _time > 1) {
    59.             _time = EditorApplication.timeSinceStartup;
    60.             Debug.Log($"Unity Update() tick.");
    61.         }
    62.     }
    63. }
    64.  

    ModalWindowTemplate.uxml
    <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
    <ui:VisualElement style="align-items: stretch; flex-grow: 0;">
    <ui:Label text="When modal window opens it starts three types of periodic tasks:&#10; - UI Toolkit scheduled item&#10; - C# async task (5 times)&#10; - EditorWindow.Update()&#10;&#10;None of these tasks is executed if modal window was open with EditorWindow.ShowModalUtility(). C# tasks start to execute after modal is closed." display-tooltip-when-elided="true" style="margin-left: 10px; margin-right: 10px; margin-top: 20px; margin-bottom: 0; align-items: auto; flex-grow: 1; border-left-color: rgb(128, 128, 128); border-right-color: rgb(128, 128, 128); border-top-color: rgb(128, 128, 128); border-bottom-color: rgb(128, 128, 128); border-left-width: 1px; border-right-width: 1px; border-top-width: 1px; border-bottom-width: 1px; white-space: normal;" />
    <ui:VisualElement style="width: auto; flex-grow: 1; flex-shrink: 0; align-items: center;">
    <ui:Button text="Close" display-tooltip-when-elided="true" name="closeButton" style="width: 200px; margin-top: 20px;" />
    </ui:VisualElement>
    </ui:VisualElement>
    </ui:UXML>
     
  8. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    I'm trying to use this as a starting point, but the model window appears way off in the corner of the screen.

    How do I get the position of the current editor and open the modal window centered over the current editor?

    I've tried these to no avail:
    Code (CSharp):
    1.             TimelineEditorModalWindow window = ScriptableObject.CreateInstance(typeof(TimelineEditorModalWindow)) as TimelineEditorModalWindow;
    2.             Log.Info($"Mouse: {UnityEngine.Input.mousePosition.x}, {UnityEngine.Input.mousePosition.y}");
    3.             Log.Info($"Window: {window.position}");
    4.             Log.Info($"WorldPos: {m_parentContainer}");
    5.             var screenRect = GUIUtility.GUIToScreenRect(worldBound);
    6.             Log.Info($"screenRect: {screenRect}");
    7.             window.PreloadGUI();
    8.  
    9.             window.position = screenRect;