diff --git a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs index 11050ce3..bfe96357 100644 --- a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs +++ b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs @@ -11,7 +11,7 @@ using Object = UnityEngine.Object; namespace Fungus.EditorUtils { - public class FlowchartWindow : EditorWindow + public class FlowchartWindow : EventWindow { protected class ClipboardObject { @@ -148,7 +148,7 @@ namespace Fungus.EditorUtils protected int blockPopupSelection = -1; protected Vector2 popupScroll; protected bool mouseOverPopup; - + [MenuItem("Tools/Fungus/Flowchart Window")] static void Init() { @@ -247,6 +247,93 @@ namespace Fungus.EditorUtils return fungusState.SelectedFlowchart; } + protected virtual void HandleEarlyEvents(Flowchart flowchart, Event e) + { + switch (e.type) + { + case EventType.MouseDown: + // Clear search filter focus + if (!searchRect.Contains(e.mousePosition) && !popupRect.Contains(e.mousePosition)) + { + CloseBlockPopup(); + } + + if (e.button == 0 && searchRect.Contains(e.mousePosition)) + { + blockPopupSelection = 0; + popupScroll = Vector2.zero; + } + + rightClickDown = -Vector2.one; + break; + + case EventType.KeyDown: + if (GUI.GetNameOfFocusedControl() == searchFieldName) + { + var centerBlock = false; + var selectBlock = false; + var closePopup = false; + var useEvent = false; + + switch (e.keyCode) + { + case KeyCode.DownArrow: + ++blockPopupSelection; + centerBlock = true; + useEvent = true; + break; + + case KeyCode.UpArrow: + --blockPopupSelection; + centerBlock = true; + useEvent = true; + break; + + case KeyCode.Return: + centerBlock = true; + selectBlock = true; + closePopup = true; + useEvent = true; + break; + + case KeyCode.Escape: + closePopup = true; + useEvent = true; + break; + } + + blockPopupSelection = Mathf.Clamp(blockPopupSelection, 0, filteredBlocks.Length - 1); + + if (centerBlock && filteredBlocks.Length > 0) + { + var block = filteredBlocks[blockPopupSelection]; + CenterBlock(flowchart, block); + + if (selectBlock) + { + SelectBlock(flowchart, block); + } + } + + if (closePopup) + { + CloseBlockPopup(); + } + + if (useEvent) + { + e.Use(); + } + } + else if (e.keyCode == KeyCode.Escape && flowchart.SelectedBlocks.Count > 0) + { + DeselectAll(flowchart); + e.Use(); + } + break; + } + } + protected virtual void OnGUI() { var flowchart = GetFlowchart(); @@ -286,6 +373,8 @@ namespace Fungus.EditorUtils } deleteList.Clear(); + HandleEarlyEvents(flowchart, Event.current); + // Clear search filter focus if (Event.current.type == EventType.MouseDown && !searchRect.Contains(Event.current.mousePosition) && !popupRect.Contains(Event.current.mousePosition)) @@ -311,6 +400,8 @@ namespace Fungus.EditorUtils ValidateCommands(flowchart); ExecuteCommands(flowchart); + base.HandleEvents(Event.current); + if (forceRepaintCount > 0) { // Redraw on next frame to get crisp refresh rate @@ -319,191 +410,139 @@ namespace Fungus.EditorUtils } protected virtual void DrawOverlay(Flowchart flowchart) - { + { + // Main toolbar group GUILayout.BeginHorizontal(EditorStyles.toolbar); - - GUILayout.Space(2); - - if (GUILayout.Button(new GUIContent(addTexture, "Add a new block"), EditorStyles.toolbarButton)) - { - Vector2 newNodePosition = new Vector2(50 / flowchart.Zoom - flowchart.ScrollPos.x, - 50 / flowchart.Zoom - flowchart.ScrollPos.y); - CreateBlock(flowchart, newNodePosition); - } - - // Separator - GUILayout.Label("", EditorStyles.toolbarButton, GUILayout.Width(8)); - - GUILayout.Label("Scale", EditorStyles.miniLabel); - var newZoom = GUILayout.HorizontalSlider( - flowchart.Zoom, minZoomValue, maxZoomValue, GUILayout.MinWidth(40), GUILayout.MaxWidth(100) - ); - GUILayout.Label(flowchart.Zoom.ToString("0.0#x"), EditorStyles.miniLabel, GUILayout.Width(30)); - - if (newZoom != flowchart.Zoom) - { - DoZoom(flowchart, newZoom - flowchart.Zoom, Vector2.one * 0.5f); - } - - if (GUILayout.Button("Center", EditorStyles.toolbarButton)) { - flowchart.ScrollPos = flowchart.CenterPosition; - } + GUILayout.Space(2); - GUILayout.FlexibleSpace(); + // Draw add block button + if (GUILayout.Button(new GUIContent(addTexture, "Add a new block"), EditorStyles.toolbarButton)) + { + DeselectAll(flowchart); + Vector2 newNodePosition = new Vector2( + 50 / flowchart.Zoom - flowchart.ScrollPos.x, 50 / flowchart.Zoom - flowchart.ScrollPos.y + ); + CreateBlock(flowchart, newNodePosition); + } + + GUILayout.Label("", EditorStyles.toolbarButton, GUILayout.Width(8)); // Separator - var blocks = flowchart.GetComponents(); + // Draw scale bar and labels + GUILayout.Label("Scale", EditorStyles.miniLabel); + var newZoom = GUILayout.HorizontalSlider( + flowchart.Zoom, minZoomValue, maxZoomValue, GUILayout.MinWidth(40), GUILayout.MaxWidth(100) + ); + GUILayout.Label(flowchart.Zoom.ToString("0.0#x"), EditorStyles.miniLabel, GUILayout.Width(30)); - // Intercept mouse and keyboard events before search field uses them - if (GUI.GetNameOfFocusedControl() == searchFieldName) - { - if (Event.current.type == EventType.KeyDown) + if (newZoom != flowchart.Zoom) { - var centerBlock = false; - var selectBlock = false; - var closePopup = false; - var useEvent = false; + DoZoom(flowchart, newZoom - flowchart.Zoom, Vector2.one * 0.5f); + } - switch (Event.current.keyCode) - { - case KeyCode.DownArrow: - ++blockPopupSelection; - centerBlock = true; - useEvent = true; - break; + // Draw center button + if (GUILayout.Button("Center", EditorStyles.toolbarButton)) + { + flowchart.ScrollPos = flowchart.CenterPosition; + } - case KeyCode.UpArrow: - --blockPopupSelection; - centerBlock = true; - useEvent = true; - break; + GUILayout.FlexibleSpace(); - case KeyCode.Return: - centerBlock = true; - selectBlock = true; - closePopup = true; - useEvent = true; - break; - - case KeyCode.Escape: - closePopup = true; - useEvent = true; - break; - } + // Draw search bar + GUI.SetNextControlName(searchFieldName); + var newString = EditorGUILayout.TextField(searchString, GUI.skin.FindStyle("ToolbarSeachTextField"), GUILayout.Width(150)); + if (newString != searchString) + { + searchString = newString; + filteredBlocks = flowchart.GetComponents().Where(block => { + return block.BlockName.ToLower().Contains(searchString.ToLower()); + }).ToArray(); blockPopupSelection = Mathf.Clamp(blockPopupSelection, 0, filteredBlocks.Length - 1); + } - if (centerBlock && filteredBlocks.Length > 0) - { - var block = filteredBlocks[blockPopupSelection]; - CenterBlock(flowchart, block); - - if (selectBlock) - { - SelectBlock(flowchart, block); - } - } + if (Event.current.type == EventType.Repaint) + { + searchRect = GUILayoutUtility.GetLastRect(); + popupRect = searchRect; + popupRect.width += 12; + popupRect.y += popupRect.height; + popupRect.height = Mathf.Min(filteredBlocks.Length * 16, position.height - 22); + } - if (closePopup) - { - CloseBlockPopup(); - } + if (GUILayout.Button("", GUI.skin.FindStyle("ToolbarSeachCancelButton"))) + { + CloseBlockPopup(); + } - if (useEvent) + // Eat all click events on toolbar + if (Event.current.type == EventType.MouseDown) + { + if (Event.current.mousePosition.y < searchRect.height) { Event.current.Use(); } } } - else if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && - searchRect.Contains(Event.current.mousePosition)) - { - blockPopupSelection = 0; - } - - GUI.SetNextControlName(searchFieldName); - var newString = EditorGUILayout.TextField(searchString, GUI.skin.FindStyle("ToolbarSeachTextField"), GUILayout.Width(150)); - if (newString != searchString) - { - searchString = newString; - } - - // Update this every frame in case of redo/undo while popup is open - filteredBlocks = blocks.Where(block => block.BlockName.ToLower().Contains(searchString.ToLower())).ToArray(); - blockPopupSelection = Mathf.Clamp(blockPopupSelection, 0, filteredBlocks.Length - 1); - - if (Event.current.type == EventType.Repaint) - { - searchRect = GUILayoutUtility.GetLastRect(); - popupRect = searchRect; - popupRect.width += 12; - popupRect.y += popupRect.height; - popupRect.height = Mathf.Min(filteredBlocks.Length * 16, position.height - 22); - } - - if (GUILayout.Button("", GUI.skin.FindStyle("ToolbarSeachCancelButton"))) - { - CloseBlockPopup(); - } - GUILayout.EndHorizontal(); + // Name and description group GUILayout.BeginHorizontal(); - - GUILayout.FlexibleSpace(); - - GUILayout.BeginVertical(); - GUILayout.Label(flowchart.name, EditorStyles.whiteBoldLabel); - - GUILayout.Space(2); - - if (flowchart.Description.Length > 0) { - GUILayout.Label(flowchart.Description, EditorStyles.helpBox); - } - GUILayout.EndVertical(); + GUILayout.FlexibleSpace(); + GUILayout.BeginVertical(); + { + GUILayout.Label(flowchart.name, EditorStyles.whiteBoldLabel); + + GUILayout.Space(2); + + if (flowchart.Description.Length > 0) + { + GUILayout.Label(flowchart.Description, EditorStyles.helpBox); + } + } + GUILayout.EndVertical(); + } GUILayout.EndHorizontal(); + // Variables group GUILayout.BeginHorizontal(); + { + GUILayout.BeginVertical(GUILayout.Width(440)); + { + GUILayout.FlexibleSpace(); - GUILayout.BeginVertical(GUILayout.Width(440)); - - GUILayout.FlexibleSpace(); - - var rawMousePosition = Event.current.mousePosition; // mouse position outside of scrollview to test against toolbar rect - - flowchart.VariablesScrollPos = GUILayout.BeginScrollView(flowchart.VariablesScrollPos, GUILayout.MaxHeight(position.height * 0.75f)); + flowchart.VariablesScrollPos = GUILayout.BeginScrollView(flowchart.VariablesScrollPos); + { + GUILayout.Space(8); - GUILayout.FlexibleSpace(); + FlowchartEditor flowchartEditor = Editor.CreateEditor (flowchart) as FlowchartEditor; + flowchartEditor.DrawVariablesGUI(); - GUILayout.Space(8); + Rect variableWindowRect = GUILayoutUtility.GetLastRect(); + if (flowchart.VariablesExpanded && flowchart.Variables.Count > 0) + { + variableWindowRect.y -= 20; + variableWindowRect.height += 20; + } - FlowchartEditor flowchartEditor = Editor.CreateEditor (flowchart) as FlowchartEditor; - flowchartEditor.DrawVariablesGUI(); - DestroyImmediate(flowchartEditor); + // Eat mouse events + if (Event.current.type == EventType.MouseDown) + { + if (Event.current.mousePosition.x <= variableWindowRect.width && + Event.current.mousePosition.y <= variableWindowRect.height) + { + Event.current.Use(); + } + } + } + GUILayout.EndScrollView(); + } + GUILayout.EndVertical(); - Rect variableWindowRect = GUILayoutUtility.GetLastRect(); - if (flowchart.VariablesExpanded && - flowchart.Variables.Count > 0) - { - variableWindowRect.y -= 20; - variableWindowRect.height += 20; - } - if (Event.current.type == EventType.Repaint) - { - Rect toolbarRect = new Rect(0, 0, position.width, 18); - mouseOverPopup = (GUI.GetNameOfFocusedControl() == searchFieldName && popupRect.Contains(rawMousePosition)); - mouseOverVariables = variableWindowRect.Contains(Event.current.mousePosition) || - toolbarRect.Contains(rawMousePosition) || mouseOverPopup; + GUILayout.FlexibleSpace(); } - - GUILayout.EndScrollView(); - - GUILayout.EndVertical(); - - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); // Draw block search popup on top of other controls