From 4e3b65a0e6648fc1a59e06c9b02666bcfccf20a5 Mon Sep 17 00:00:00 2001 From: Zach Vinless Date: Sun, 6 Nov 2016 22:35:10 -0800 Subject: [PATCH 1/4] Added keyboard shortcuts and more context menu options - Added keyboard shortcuts: copy, cut, duplicate, delete, select all - Added context menu when right clicking on empty space: add block, paste - Context menus now appear on mouse up to better support panning --- .../Fungus/Scripts/Editor/FlowchartWindow.cs | 230 +++++++++++++++--- 1 file changed, 200 insertions(+), 30 deletions(-) diff --git a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs index a0df30f9..b943fe9e 100644 --- a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs +++ b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs @@ -36,9 +36,15 @@ namespace Fungus.EditorUtils protected Texture2D addTexture; protected Rect selectionBox; - protected Vector2 startSelectionBoxPosition = new Vector2(-1.0f, -1.0f); + protected Vector2 startSelectionBoxPosition = -Vector2.one; protected List mouseDownSelectionState = new List(); + protected List copyList = new List(); + + // Context Click occurs on MouseDown which interferes with panning + // Track right click positions manually to show menus on MouseUp + protected Vector2 rightClickDown = -Vector2.one; + [MenuItem("Tools/Fungus/Flowchart Window")] static void Init() { @@ -61,6 +67,7 @@ namespace Fungus.EditorUtils nodeStyle.wordWrap = true; addTexture = Resources.Load("Icons/add_small") as Texture2D; + copyList.Clear(); } protected virtual void OnInspectorUpdate() @@ -156,6 +163,9 @@ namespace Fungus.EditorUtils if (isSelected) { + // Deselect + flowchart.SelectedBlocks.Remove(deleteBlock); + // Revert to showing properties for the Flowchart Selection.activeGameObject = flowchart.gameObject; } @@ -168,6 +178,9 @@ namespace Fungus.EditorUtils // Handle selection box events after block and overlay events HandleSelectionBox(flowchart); + ValidateCommands(flowchart); + ExecuteCommands(flowchart); + if (forceRepaintCount > 0) { // Redraw on next frame to get crisp refresh rate @@ -288,6 +301,19 @@ namespace Fungus.EditorUtils // Calc rect for script view Rect scriptViewRect = new Rect(0, 0, this.position.width / flowchart.Zoom, this.position.height / flowchart.Zoom); + // Update right click start outside of EditorZoomArea + if (Event.current.button == 1) + { + if (Event.current.type == EventType.MouseDown) + { + rightClickDown = Event.current.mousePosition; + } + else if (Event.current.type == EventType.MouseDrag) + { + rightClickDown = -Vector2.one; + } + } + EditorZoomArea.Begin(flowchart.Zoom, scriptViewRect); DrawGrid(flowchart); @@ -296,7 +322,10 @@ namespace Fungus.EditorUtils // The center of the Flowchart depends on the block positions and window dimensions, so we calculate it // here in the FlowchartWindow class and store it on the Flowchart object for use later. - CalcFlowchartCenter(flowchart, blocks); + if (flowchart != null && blocks.Length > 0) + { + CalcFlowchartCenter(flowchart, blocks); + } // Draw connections foreach (var block in blocks) @@ -455,15 +484,63 @@ namespace Fungus.EditorUtils GLDraw.EndGroup(); EditorZoomArea.End(); + + // Handle right click up outside of EditorZoomArea to avoid strange offsets + if (Event.current.type == EventType.MouseUp && Event.current.button == 1 && + Event.current.mousePosition == rightClickDown && !mouseOverVariables) + { + var menu = new GenericMenu(); + var mousePosition = rightClickDown; + + Block hitBlock = null; + foreach (var block in blocks) + { + if (block._NodeRect.Contains(rightClickDown / flowchart.Zoom - flowchart.ScrollPos)) + { + hitBlock = block; + break; + } + } + // Clicked on a block + if (hitBlock != null) + { + flowchart.AddSelectedBlock(hitBlock); + + // Use a copy because flowchart.SelectedBlocks gets modified + var blockList = new List(flowchart.SelectedBlocks); + menu.AddItem(new GUIContent ("Copy"), false, () => Copy(flowchart)); + menu.AddItem(new GUIContent ("Cut"), false, () => Cut(flowchart)); + menu.AddItem(new GUIContent ("Duplicate"), false, DuplicateBlocks, blockList); + menu.AddItem(new GUIContent ("Delete"), false, DeleteBlocks, blockList); + } + // Clicked on empty space in grid + else + { + DeselectAll(flowchart); + + menu.AddItem(new GUIContent("Add Block"), false, () => CreateBlock(flowchart, mousePosition / flowchart.Zoom - flowchart.ScrollPos)); + + if (copyList.Count > 0) + { + menu.AddItem(new GUIContent("Paste"), false, () => Paste(flowchart, mousePosition)); + } + else + { + menu.AddDisabledItem(new GUIContent("Paste")); + } + } + + var menuRect = new Rect(); + menuRect.position = new Vector2(mousePosition.x, mousePosition.y - 12f); + menu.DropDown(menuRect); + Event.current.Use(); + } // If event has yet to be used and user isn't multiselecting or panning, clear selection bool validModifier = Event.current.alt || GetAppendModifierDown(); if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && !validModifier) { - Undo.RecordObject(flowchart, "Deselect"); - flowchart.ClearSelectedCommands(); - flowchart.ClearSelectedBlocks(); - Selection.activeGameObject = flowchart.gameObject; + DeselectAll(flowchart); } // Draw selection box @@ -474,12 +551,11 @@ namespace Fungus.EditorUtils } } - public virtual void CalcFlowchartCenter(Flowchart flowchart, Block[] blocks) + public virtual Vector2 GetBlockCenter(Flowchart flowchart, Block[] blocks) { - if (flowchart == null || - blocks.Count() == 0) + if (blocks.Length == 0) { - return; + return Vector2.zero; } Vector2 min = blocks[0]._NodeRect.min; @@ -493,8 +569,12 @@ namespace Fungus.EditorUtils max.y = Mathf.Max(max.y, block._NodeRect.center.y); } - Vector2 center = (min + max) * -0.5f; + return (min + max) * 0.5f; + } + public virtual void CalcFlowchartCenter(Flowchart flowchart, Block[] blocks) + { + var center = -GetBlockCenter(flowchart, blocks); center.x += position.width * 0.5f / flowchart.Zoom; center.y += position.height * 0.5f / flowchart.Zoom; @@ -559,7 +639,7 @@ namespace Fungus.EditorUtils if (Event.current.rawType == EventType.MouseUp) { selectionBox.size = Vector2.zero; - selectionBox.position = Vector2.one * -1; + selectionBox.position = -Vector2.one; startSelectionBoxPosition = selectionBox.position; var tempList = new List(flowchart.SelectedBlocks); @@ -688,6 +768,14 @@ namespace Fungus.EditorUtils flowchart.SelectedBlock = block; SetBlockForInspector(flowchart, block); } + + protected virtual void DeselectAll(Flowchart flowchart) + { + Undo.RecordObject(flowchart, "Deselect"); + flowchart.ClearSelectedCommands(); + flowchart.ClearSelectedBlocks(); + Selection.activeGameObject = flowchart.gameObject; + } public static Block CreateBlock(Flowchart flowchart, Vector2 position) { @@ -854,20 +942,6 @@ namespace Fungus.EditorUtils descriptionStyle.wordWrap = true; GUILayout.Label(block.Description, descriptionStyle); } - - if (Event.current.type == EventType.ContextClick) - { - flowchart.AddSelectedBlock(block); - - GenericMenu menu = new GenericMenu (); - - // Use a copy because flowchart.SelectedBlocks gets modified - var blockList = new List(flowchart.SelectedBlocks); - menu.AddItem(new GUIContent ("Duplicate"), false, DuplicateBlocks, blockList); - menu.AddItem(new GUIContent ("Delete"), false, DeleteBlocks, blockList); - - menu.ShowAsContext(); - } } protected virtual void DrawConnections(Flowchart flowchart, Block block, bool highlightedOnly) @@ -989,6 +1063,11 @@ namespace Fungus.EditorUtils } protected static void DuplicateBlocks(object obj) + { + DuplicateBlocks(obj, new Vector2(20, 0)); + } + + protected static void DuplicateBlocks(object obj, Vector2 offset) { var flowchart = GetFlowchart(); @@ -999,9 +1078,7 @@ namespace Fungus.EditorUtils foreach (var block in blocks) { - Vector2 newPosition = new Vector2(block._NodeRect.position.x + - block._NodeRect.width + 20, - block._NodeRect.y); + Vector2 newPosition = block._NodeRect.position + offset; Block oldBlock = block; @@ -1087,9 +1164,102 @@ namespace Fungus.EditorUtils } } - protected virtual bool GetAppendModifierDown() + protected virtual bool GetAppendModifierDown() { return Event.current.shift || EditorGUI.actionKey; } + + protected virtual void Copy(Flowchart flowchart) + { + copyList.Clear(); + flowchart.SelectedBlocks.ForEach(block => copyList.Add(block)); + } + + protected virtual void Cut(Flowchart flowchart) + { + Copy(flowchart); + Undo.RecordObject(flowchart, "Cut"); + DeleteBlocks(flowchart.SelectedBlocks); + } + + // Center is position in unscaled window space + protected virtual void Paste(Flowchart flowchart, Vector2 center) + { + var copiedCenter = GetBlockCenter(flowchart, copyList.ToArray()) + flowchart.ScrollPos; + var delta = (center / flowchart.Zoom - copiedCenter); + + Undo.RecordObject(flowchart, "Paste"); + DuplicateBlocks(copyList, delta); + } + + protected virtual void ValidateCommands(Flowchart flowchart) + { + if (Event.current.type == EventType.ValidateCommand) + { + var c = Event.current.commandName; + if (c == "Copy" || c == "Cut" || c == "Delete" || c == "Duplicate") + { + if (flowchart.SelectedBlocks.Count > 0) + { + Event.current.Use(); + } + } + else if (c == "Paste") + { + if (copyList.Count > 0) + { + Event.current.Use(); + } + } + else if (c == "SelectAll") + { + Event.current.Use(); + } + } + } + + protected virtual void ExecuteCommands(Flowchart flowchart) + { + if (Event.current.type == EventType.ExecuteCommand) + { + switch (Event.current.commandName) + { + case "Copy": + Copy(flowchart); + Event.current.Use(); + break; + + case "Cut": + Cut(flowchart); + Event.current.Use(); + break; + + case "Paste": + Paste(flowchart, position.center - position.position); + Event.current.Use(); + break; + + case "Delete": + DeleteBlocks(flowchart.SelectedBlocks); + Event.current.Use(); + break; + + case "Duplicate": + DuplicateBlocks(new List(flowchart.SelectedBlocks)); + Event.current.Use(); + break; + + case "SelectAll": + Undo.RecordObject(flowchart, "Selection"); + flowchart.ClearSelectedBlocks(); + foreach (var block in flowchart.GetComponents()) + { + flowchart.AddSelectedBlock(block); + } + Event.current.Use(); + break; + } + } + } } } \ No newline at end of file From 5af37c941544b842dc1d2541c6f2ef449d83ff7f Mon Sep 17 00:00:00 2001 From: Zach Vinless Date: Mon, 7 Nov 2016 07:19:06 -0800 Subject: [PATCH 2/4] Added check for zoom change to avoid constant repaint -forceRepaintCount no longer gets set every time OnGUI is called because of DoZoom function --- Assets/Fungus/Scripts/Editor/FlowchartWindow.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs index b943fe9e..be03da99 100644 --- a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs +++ b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs @@ -210,7 +210,10 @@ namespace Fungus.EditorUtils ); GUILayout.Label(flowchart.Zoom.ToString("0.0#x"), EditorStyles.miniLabel, GUILayout.Width(30)); - DoZoom(flowchart, newZoom - flowchart.Zoom, Vector2.one * 0.5f); + if (newZoom != flowchart.Zoom) + { + DoZoom(flowchart, newZoom - flowchart.Zoom, Vector2.one * 0.5f); + } if (GUILayout.Button("Center", EditorStyles.toolbarButton)) { From 4fb4a2f07b5a0b09bb1a0d1556852b7735977147 Mon Sep 17 00:00:00 2001 From: Zach Vinless Date: Mon, 7 Nov 2016 14:21:31 -0800 Subject: [PATCH 3/4] Removed copy/cut/paste functionality for now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Removed copy/cut/paste functionality so that those commands can be implemented in a future PR -Removed unreferenced “DeleteBlock” function --- .../Fungus/Scripts/Editor/FlowchartWindow.cs | 74 +------------------ 1 file changed, 1 insertion(+), 73 deletions(-) diff --git a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs index be03da99..5de4942c 100644 --- a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs +++ b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs @@ -39,8 +39,6 @@ namespace Fungus.EditorUtils protected Vector2 startSelectionBoxPosition = -Vector2.one; protected List mouseDownSelectionState = new List(); - protected List copyList = new List(); - // Context Click occurs on MouseDown which interferes with panning // Track right click positions manually to show menus on MouseUp protected Vector2 rightClickDown = -Vector2.one; @@ -67,7 +65,6 @@ namespace Fungus.EditorUtils nodeStyle.wordWrap = true; addTexture = Resources.Load("Icons/add_small") as Texture2D; - copyList.Clear(); } protected virtual void OnInspectorUpdate() @@ -511,8 +508,6 @@ namespace Fungus.EditorUtils // Use a copy because flowchart.SelectedBlocks gets modified var blockList = new List(flowchart.SelectedBlocks); - menu.AddItem(new GUIContent ("Copy"), false, () => Copy(flowchart)); - menu.AddItem(new GUIContent ("Cut"), false, () => Cut(flowchart)); menu.AddItem(new GUIContent ("Duplicate"), false, DuplicateBlocks, blockList); menu.AddItem(new GUIContent ("Delete"), false, DeleteBlocks, blockList); } @@ -520,17 +515,7 @@ namespace Fungus.EditorUtils else { DeselectAll(flowchart); - menu.AddItem(new GUIContent("Add Block"), false, () => CreateBlock(flowchart, mousePosition / flowchart.Zoom - flowchart.ScrollPos)); - - if (copyList.Count > 0) - { - menu.AddItem(new GUIContent("Paste"), false, () => Paste(flowchart, mousePosition)); - } - else - { - menu.AddDisabledItem(new GUIContent("Paste")); - } } var menuRect = new Rect(); @@ -792,18 +777,6 @@ namespace Fungus.EditorUtils return newBlock; } - protected virtual void DeleteBlock(Flowchart flowchart, Block block) - { - var commandList = block.CommandList; - foreach (var command in commandList) - { - Undo.DestroyObjectImmediate(command); - } - - Undo.DestroyObjectImmediate((Block)block); - flowchart.ClearSelectedCommands(); - } - protected virtual void DrawWindow(int windowId) { var block = windowBlockMap[windowId]; @@ -1172,48 +1145,18 @@ namespace Fungus.EditorUtils return Event.current.shift || EditorGUI.actionKey; } - protected virtual void Copy(Flowchart flowchart) - { - copyList.Clear(); - flowchart.SelectedBlocks.ForEach(block => copyList.Add(block)); - } - - protected virtual void Cut(Flowchart flowchart) - { - Copy(flowchart); - Undo.RecordObject(flowchart, "Cut"); - DeleteBlocks(flowchart.SelectedBlocks); - } - - // Center is position in unscaled window space - protected virtual void Paste(Flowchart flowchart, Vector2 center) - { - var copiedCenter = GetBlockCenter(flowchart, copyList.ToArray()) + flowchart.ScrollPos; - var delta = (center / flowchart.Zoom - copiedCenter); - - Undo.RecordObject(flowchart, "Paste"); - DuplicateBlocks(copyList, delta); - } - protected virtual void ValidateCommands(Flowchart flowchart) { if (Event.current.type == EventType.ValidateCommand) { var c = Event.current.commandName; - if (c == "Copy" || c == "Cut" || c == "Delete" || c == "Duplicate") + if (c == "Delete" || c == "Duplicate") { if (flowchart.SelectedBlocks.Count > 0) { Event.current.Use(); } } - else if (c == "Paste") - { - if (copyList.Count > 0) - { - Event.current.Use(); - } - } else if (c == "SelectAll") { Event.current.Use(); @@ -1227,21 +1170,6 @@ namespace Fungus.EditorUtils { switch (Event.current.commandName) { - case "Copy": - Copy(flowchart); - Event.current.Use(); - break; - - case "Cut": - Cut(flowchart); - Event.current.Use(); - break; - - case "Paste": - Paste(flowchart, position.center - position.position); - Event.current.Use(); - break; - case "Delete": DeleteBlocks(flowchart.SelectedBlocks); Event.current.Use(); From 60f9bc5fd2e57758c4dd44d5d2ce78aa875adfb2 Mon Sep 17 00:00:00 2001 From: Zach Vinless Date: Tue, 8 Nov 2016 20:54:14 -0800 Subject: [PATCH 4/4] Added tolerance value for right click MouseUp context clicks --- Assets/Fungus/Scripts/Editor/FlowchartWindow.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs index 5de4942c..9c49352f 100644 --- a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs +++ b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs @@ -42,6 +42,7 @@ namespace Fungus.EditorUtils // Context Click occurs on MouseDown which interferes with panning // Track right click positions manually to show menus on MouseUp protected Vector2 rightClickDown = -Vector2.one; + protected readonly float rightClickTolerance = 5f; [MenuItem("Tools/Fungus/Flowchart Window")] static void Init() @@ -310,7 +311,10 @@ namespace Fungus.EditorUtils } else if (Event.current.type == EventType.MouseDrag) { - rightClickDown = -Vector2.one; + if (Vector2.Distance(rightClickDown, Event.current.mousePosition) > rightClickTolerance) + { + rightClickDown = -Vector2.one; + } } } @@ -487,7 +491,7 @@ namespace Fungus.EditorUtils // Handle right click up outside of EditorZoomArea to avoid strange offsets if (Event.current.type == EventType.MouseUp && Event.current.button == 1 && - Event.current.mousePosition == rightClickDown && !mouseOverVariables) + rightClickDown != -Vector2.one && !mouseOverVariables) { var menu = new GenericMenu(); var mousePosition = rightClickDown;