|
|
|
@ -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<Block>(); |
|
|
|
|
// 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<Block>().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 |
|
|
|
|