diff --git a/Assets/Fungus/Scripts/Editor/EventWindow.cs b/Assets/Fungus/Scripts/Editor/EventWindow.cs new file mode 100644 index 00000000..774670d7 --- /dev/null +++ b/Assets/Fungus/Scripts/Editor/EventWindow.cs @@ -0,0 +1,76 @@ +// This code is part of the Fungus library (http://fungusgames.com) maintained by Chris Gregan (http://twitter.com/gofungus). +// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE) + +// Adapted from: https://github.com/thecodejunkie/unity.resources/blob/master/scripts/editor/ExtendedEditorWindow.cs + +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; + +namespace Fungus.EditorUtils +{ + internal static class MouseButton + { + public const int Left = 0; + public const int Right = 1; + public const int Middle = 2; + } + + public class EventWindow : EditorWindow + { + protected delegate void EventAction(Event e); + protected Dictionary eventTable; + protected Dictionary rawEventTable; + + public EventWindow() + { + eventTable = new Dictionary { + { EventType.MouseDown, e => OnMouseDown(e) }, + { EventType.MouseUp, e => OnMouseUp(e) }, + { EventType.MouseDrag, e => OnMouseDrag(e) }, + { EventType.MouseMove, e => OnMouseMove(e) }, + { EventType.ScrollWheel, e => OnScrollWheel(e) }, + { EventType.ContextClick, e => OnContextClick(e) }, + { EventType.KeyDown, e => OnKeyDown(e) }, + { EventType.KeyUp, e => OnKeyUp(e) }, + { EventType.ValidateCommand, e => OnValidateCommand(e) }, + { EventType.ExecuteCommand, e => OnExecuteCommand(e) }, + }; + rawEventTable = new Dictionary { + { EventType.MouseDown, e => OnRawMouseDown(e) }, + { EventType.MouseUp, e => OnRawMouseUp(e) }, + { EventType.MouseDrag, e => OnRawMouseDrag(e) }, + { EventType.MouseMove, e => OnRawMouseMove(e) }, + }; + } + + protected virtual void OnMouseDown(Event e) { } + protected virtual void OnMouseUp(Event e) { } + protected virtual void OnMouseDrag(Event e) { } + protected virtual void OnMouseMove(Event e) { } + protected virtual void OnScrollWheel(Event e) { } + protected virtual void OnContextClick(Event e) { } + protected virtual void OnKeyDown(Event e) { } + protected virtual void OnKeyUp(Event e) { } + protected virtual void OnValidateCommand(Event e) { } + protected virtual void OnExecuteCommand(Event e) { } + + protected virtual void OnRawMouseDown(Event e) { } + protected virtual void OnRawMouseUp(Event e) { } + protected virtual void OnRawMouseDrag(Event e) { } + protected virtual void OnRawMouseMove(Event e) { } + + protected virtual void HandleEvents(Event e) + { + EventAction handler; + if (rawEventTable.TryGetValue(e.rawType, out handler)) + { + handler.Invoke(e); + } + if (eventTable.TryGetValue(e.type, out handler)) + { + handler.Invoke(e); + } + } + } +} diff --git a/Assets/Fungus/Scripts/Editor/EventWindow.cs.meta b/Assets/Fungus/Scripts/Editor/EventWindow.cs.meta new file mode 100644 index 00000000..a0c1a0de --- /dev/null +++ b/Assets/Fungus/Scripts/Editor/EventWindow.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: cf9fe33ec7c10409398e58f1ede7e850 +timeCreated: 1485118482 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs index 11050ce3..46c0bfac 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 { @@ -106,40 +106,23 @@ namespace Fungus.EditorUtils protected List copyList = new List(); public static List deleteList = new List(); - - protected List windowBlockMap = new List(); - - // The ReorderableList control doesn't drag properly when used with GUI.DragWindow(), - // so we just implement dragging ourselves. - protected int dragWindowId = -1; protected Vector2 startDragPosition; - public const float minZoomValue = 0.25f; public const float maxZoomValue = 1f; - protected GUIStyle nodeStyle = new GUIStyle(); - protected static BlockInspector blockInspector; - - protected bool mouseOverVariables = false; - protected int forceRepaintCount; - protected Texture2D addTexture; protected Texture2D connectionPointTexture; - protected Rect selectionBox; protected Vector2 startSelectionBoxPosition = -Vector2.one; protected List mouseDownSelectionState = new List(); - protected Color gridLineColor = Color.black; protected readonly Color connectionColor = new Color(0.65f, 0.65f, 0.65f, 1.0f); - // 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 const float rightClickTolerance = 5f; - protected const string searchFieldName = "search"; private string searchString = string.Empty; protected Rect searchRect; @@ -147,8 +130,10 @@ namespace Fungus.EditorUtils protected Block[] filteredBlocks; protected int blockPopupSelection = -1; protected Vector2 popupScroll; - protected bool mouseOverPopup; - + protected Flowchart flowchart; + protected Block[] blocks; + protected Block dragBlock; + [MenuItem("Tools/Fungus/Flowchart Window")] static void Init() { @@ -158,14 +143,8 @@ namespace Fungus.EditorUtils protected virtual void OnEnable() { // All block nodes use the same GUIStyle, but with a different background - nodeStyle.border.left = 20; - nodeStyle.border.right = 20; - nodeStyle.border.top = 5; - nodeStyle.border.bottom = 5; - nodeStyle.padding.left = 20; - nodeStyle.padding.right = 20; - nodeStyle.padding.top = 5; - nodeStyle.padding.bottom = 5; + nodeStyle.border = new RectOffset(20, 20, 5, 5); + nodeStyle.padding = nodeStyle.border; nodeStyle.contentOffset = Vector2.zero; nodeStyle.alignment = TextAnchor.MiddleCenter; nodeStyle.wordWrap = true; @@ -247,124 +226,41 @@ namespace Fungus.EditorUtils return fungusState.SelectedFlowchart; } - protected virtual void OnGUI() + protected void UpdateFilteredBlocks() { - var flowchart = GetFlowchart(); - if (flowchart == null) - { - GUILayout.Label("No Flowchart scene object selected"); - return; - } + filteredBlocks = blocks.Where(block => block.BlockName.ToLower().Contains(searchString.ToLower())).ToArray(); + blockPopupSelection = Mathf.Clamp(blockPopupSelection, 0, filteredBlocks.Length - 1); + } - // Delete any scheduled objects - foreach (var deleteBlock in deleteList) + protected virtual void HandleEarlyEvents(Event e) + { + switch (e.type) { - bool isSelected = (flowchart.SelectedBlocks.Contains(deleteBlock)); - - var commandList = deleteBlock.CommandList; - foreach (var command in commandList) - { - Undo.DestroyObjectImmediate(command); - } - - if (deleteBlock._EventHandler != null) - { - Undo.DestroyObjectImmediate(deleteBlock._EventHandler); - } - - Undo.DestroyObjectImmediate((Block)deleteBlock); - flowchart.ClearSelectedCommands(); - - if (isSelected) + case EventType.MouseDown: + // Clear search filter focus + if (!searchRect.Contains(e.mousePosition) && !popupRect.Contains(e.mousePosition)) { - // Deselect - flowchart.SelectedBlocks.Remove(deleteBlock); - - // Revert to showing properties for the Flowchart - Selection.activeGameObject = flowchart.gameObject; + CloseBlockPopup(); } - } - deleteList.Clear(); - // Clear search filter focus - if (Event.current.type == EventType.MouseDown && !searchRect.Contains(Event.current.mousePosition) && - !popupRect.Contains(Event.current.mousePosition)) - { - CloseBlockPopup(); - } - - if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape) - { - if (GUI.GetNameOfFocusedControl() != searchFieldName && flowchart.SelectedBlocks.Count > 0) + if (e.button == 0 && searchRect.Contains(e.mousePosition)) { - DeselectAll(flowchart); - Event.current.Use(); + blockPopupSelection = 0; + popupScroll = Vector2.zero; } - } - - DrawFlowchartView(flowchart); - DrawOverlay(flowchart); - - // 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 - Repaint(); - } - } - - protected virtual void DrawOverlay(Flowchart flowchart) - { - 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.FlexibleSpace(); + rightClickDown = -Vector2.one; + break; - var blocks = flowchart.GetComponents(); - - // Intercept mouse and keyboard events before search field uses them - if (GUI.GetNameOfFocusedControl() == searchFieldName) - { - if (Event.current.type == EventType.KeyDown) + case EventType.KeyDown: + if (GUI.GetNameOfFocusedControl() == searchFieldName) { var centerBlock = false; var selectBlock = false; var closePopup = false; var useEvent = false; - switch (Event.current.keyCode) + switch (e.keyCode) { case KeyCode.DownArrow: ++blockPopupSelection; @@ -396,11 +292,11 @@ namespace Fungus.EditorUtils if (centerBlock && filteredBlocks.Length > 0) { var block = filteredBlocks[blockPopupSelection]; - CenterBlock(flowchart, block); + CenterBlock(block); if (selectBlock) { - SelectBlock(flowchart, block); + SelectBlock(block); } } @@ -411,249 +307,580 @@ namespace Fungus.EditorUtils if (useEvent) { - Event.current.Use(); + e.Use(); } } + else if (e.keyCode == KeyCode.Escape && flowchart.SelectedBlocks.Count > 0) + { + DeselectAll(); + e.Use(); + } + break; } - 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) + protected virtual void OnGUI() + { + // TODO: avoid calling some of these methods in OnGUI because it should be possible + // to only call them when the window is initialized or a new flowchart is selected, etc. + flowchart = GetFlowchart(); + + if (flowchart == null) { - searchString = newString; + GUILayout.Label("No Flowchart scene object selected"); + return; } - // 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); + DeleteBlocks(); + + blocks = flowchart.GetComponents(); + UpdateFilteredBlocks(); + BringSelectedBlockToFront(); + HandleEarlyEvents(Event.current); + + // Draw background color / drop shadow 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); + UnityEditor.Graphs.Styles.graphBackground.Draw( + new Rect(0, 17, position.width, position.height - 17), false, false, false, false + ); } - if (GUILayout.Button("", GUI.skin.FindStyle("ToolbarSeachCancelButton"))) + // Draw blocks and connections + DrawFlowchartView(Event.current); + + // Draw selection box + if (Event.current.type == EventType.Repaint) { - CloseBlockPopup(); + if (startSelectionBoxPosition.x >= 0 && startSelectionBoxPosition.y >= 0) + { + GUI.Box(selectionBox, "", GUI.skin.FindStyle("SelectionRect")); + } } - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); + // Draw toolbar, search popup, and variables window + DrawOverlay(Event.current); - GUILayout.FlexibleSpace(); + // Handle events for custom GUI + base.HandleEvents(Event.current); - GUILayout.BeginVertical(); - GUILayout.Label(flowchart.name, EditorStyles.whiteBoldLabel); - - GUILayout.Space(2); - - if (flowchart.Description.Length > 0) + if (forceRepaintCount > 0) { - GUILayout.Label(flowchart.Description, EditorStyles.helpBox); + // Redraw on next frame to get crisp refresh rate + Repaint(); } - GUILayout.EndVertical(); + } - GUILayout.EndHorizontal(); + protected virtual void DrawOverlay(Event e) + { + // Main toolbar group + GUILayout.BeginHorizontal(EditorStyles.toolbar); + { + GUILayout.Space(2); - GUILayout.BeginHorizontal(); + // Draw add block button + if (GUILayout.Button(new GUIContent(addTexture, "Add a new block"), EditorStyles.toolbarButton)) + { + DeselectAll(); + 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 - GUILayout.BeginVertical(GUILayout.Width(440)); - - GUILayout.FlexibleSpace(); + // 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)); - var rawMousePosition = Event.current.mousePosition; // mouse position outside of scrollview to test against toolbar rect + if (newZoom != flowchart.Zoom) + { + DoZoom(newZoom - flowchart.Zoom, Vector2.one * 0.5f); + } - flowchart.VariablesScrollPos = GUILayout.BeginScrollView(flowchart.VariablesScrollPos, GUILayout.MaxHeight(position.height * 0.75f)); + // Draw center button + if (GUILayout.Button("Center", EditorStyles.toolbarButton)) + { + CenterFlowchart(); + } - GUILayout.FlexibleSpace(); + GUILayout.FlexibleSpace(); - GUILayout.Space(8); + // Draw search bar + GUI.SetNextControlName(searchFieldName); + var newString = EditorGUILayout.TextField(searchString, GUI.skin.FindStyle("ToolbarSeachTextField"), GUILayout.Width(150)); + if (newString != searchString) + { + searchString = newString; + } - FlowchartEditor flowchartEditor = Editor.CreateEditor (flowchart) as FlowchartEditor; - flowchartEditor.DrawVariablesGUI(); - DestroyImmediate(flowchartEditor); + if (e.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); + } - Rect variableWindowRect = GUILayoutUtility.GetLastRect(); - if (flowchart.VariablesExpanded && - flowchart.Variables.Count > 0) - { - variableWindowRect.y -= 20; - variableWindowRect.height += 20; + if (GUILayout.Button("", GUI.skin.FindStyle("ToolbarSeachCancelButton"))) + { + CloseBlockPopup(); + } + + // Eat all click events on toolbar + if (e.type == EventType.MouseDown) + { + if (e.mousePosition.y < searchRect.height) + { + e.Use(); + } + } } - if (Event.current.type == EventType.Repaint) + GUILayout.EndHorizontal(); + + // Name and description group + GUILayout.BeginHorizontal(); { - 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.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.EndScrollView(); + flowchart.VariablesScrollPos = GUILayout.BeginScrollView(flowchart.VariablesScrollPos); + { + GUILayout.Space(8); - GUILayout.EndVertical(); + FlowchartEditor flowchartEditor = Editor.CreateEditor (flowchart) as FlowchartEditor; + flowchartEditor.DrawVariablesGUI(); + DestroyImmediate(flowchartEditor); + + Rect variableWindowRect = GUILayoutUtility.GetLastRect(); + if (flowchart.VariablesExpanded && flowchart.Variables.Count > 0) + { + variableWindowRect.y -= 20; + variableWindowRect.height += 20; + } - GUILayout.FlexibleSpace(); + // Eat mouse events + if (e.type == EventType.MouseDown) + { + if (e.mousePosition.x <= variableWindowRect.width && + e.mousePosition.y <= variableWindowRect.height) + { + e.Use(); + } + } + } + GUILayout.EndScrollView(); + } + GUILayout.EndVertical(); + GUILayout.FlexibleSpace(); + } GUILayout.EndHorizontal(); // Draw block search popup on top of other controls if (GUI.GetNameOfFocusedControl() == searchFieldName && filteredBlocks.Length > 0) { - DrawBlockPopup(flowchart); + DrawBlockPopup(e); } } - protected virtual void DrawBlockPopup(Flowchart flowchart) + protected virtual void DrawBlockPopup(Event e) { blockPopupSelection = Mathf.Clamp(blockPopupSelection, 0, filteredBlocks.Length - 1); GUI.Box(popupRect, "", GUI.skin.FindStyle("sv_iconselector_back")); - if (Event.current.type == EventType.MouseMove) + if (e.type == EventType.MouseMove) { - if (popupRect.Contains(Event.current.mousePosition)) + if (popupRect.Contains(e.mousePosition)) { - var relativeY = Event.current.mousePosition.y - popupRect.yMin + popupScroll.y; + var relativeY = e.mousePosition.y - popupRect.yMin + popupScroll.y; blockPopupSelection = (int) (relativeY / 16); } - Event.current.Use(); + e.Use(); } GUILayout.BeginArea(popupRect); - popupScroll = EditorGUILayout.BeginScrollView(popupScroll, GUIStyle.none, GUI.skin.verticalScrollbar); + { + popupScroll = EditorGUILayout.BeginScrollView(popupScroll, GUIStyle.none, GUI.skin.verticalScrollbar); + { + var normalStyle = new GUIStyle(GUI.skin.FindStyle("MenuItem")); + normalStyle.padding = new RectOffset(8, 0, 0, 0); + normalStyle.imagePosition = ImagePosition.ImageLeft; + var selectedStyle = new GUIStyle(normalStyle); + selectedStyle.normal = selectedStyle.hover; + normalStyle.hover = normalStyle.normal; + + for (int i = 0; i < filteredBlocks.Length; ++i) + { + EditorGUILayout.BeginHorizontal(GUILayout.Height(16)); + + var block = filteredBlocks[i]; + var style = i == blockPopupSelection ? selectedStyle : normalStyle; + + GUI.contentColor = GetBlockGraphics(block).tint; - var normalStyle = new GUIStyle(GUI.skin.FindStyle("MenuItem")); - normalStyle.padding = new RectOffset(8, 0, 0, 0); - normalStyle.imagePosition = ImagePosition.ImageLeft; - var selectedStyle = new GUIStyle(normalStyle); - selectedStyle.normal = selectedStyle.hover; - normalStyle.hover = normalStyle.normal; + var buttonPressed = false; + if (GUILayout.Button(FungusEditorResources.BulletPoint, style, GUILayout.Width(16))) + { + buttonPressed = true; + } - for (int i = 0; i < filteredBlocks.Length; ++i) + GUI.contentColor = Color.white; + + if (GUILayout.Button(block.BlockName, style)) + { + buttonPressed = true; + } + + if (buttonPressed) + { + CenterBlock(block); + SelectBlock(block); + CloseBlockPopup(); + } + + EditorGUILayout.EndHorizontal(); + } + } + EditorGUILayout.EndScrollView(); + } + GUILayout.EndArea(); + } + + protected Block GetBlockAtPoint(Vector2 point) + { + for (int i = blocks.Length - 1; i > -1; --i) { - EditorGUILayout.BeginHorizontal(GUILayout.Height(16)); + var block = blocks[i]; + var rect = block._NodeRect; + rect.position += flowchart.ScrollPos; - var block = filteredBlocks[i]; - var style = i == blockPopupSelection ? selectedStyle : normalStyle; + if (rect.Contains(point / flowchart.Zoom)) + { + return block; + } + } - GUI.contentColor = GetBlockGraphics(block).tint; + return null; + } - var buttonPressed = false; - if (GUILayout.Button(FungusEditorResources.BulletPoint, style, GUILayout.Width(16))) + protected void BringSelectedBlockToFront() + { + var block = flowchart.SelectedBlock; + if (block != null) + { + var index = Array.IndexOf(blocks, block); + for (int i = index; i < blocks.Length - 1; ++i) { - buttonPressed = true; + blocks[i] = blocks[i + 1]; } + blocks[blocks.Length - 1] = block; + } + } - GUI.contentColor = Color.white; + protected override void OnMouseDown(Event e) + { + var hitBlock = GetBlockAtPoint(e.mousePosition); - if (GUILayout.Button(block.BlockName, style)) + switch(e.button) + { + case MouseButton.Left: + if (!e.alt) { - buttonPressed = true; + if (hitBlock != null) + { + startDragPosition = e.mousePosition / flowchart.Zoom - flowchart.ScrollPos; + Undo.RecordObject(flowchart, "Select"); + + if (GetAppendModifierDown()) + { + if (flowchart.SelectedBlocks.Contains(hitBlock)) + { + flowchart.SelectedBlocks.Remove(hitBlock); + } + else + { + flowchart.AddSelectedBlock(hitBlock); + } + } + else + { + if (flowchart.SelectedBlocks.Contains(hitBlock)) + { + SetBlockForInspector(flowchart, hitBlock); + } + else + { + SelectBlock(hitBlock); + } + + dragBlock = hitBlock; + } + + e.Use(); + GUIUtility.keyboardControl = 0; // Fix for textarea not refeshing (change focus) + } + else if (!(UnityEditor.Tools.current == Tool.View && UnityEditor.Tools.viewTool == ViewTool.Zoom)) + { + if (!GetAppendModifierDown()) + { + DeselectAll(); + } + + startSelectionBoxPosition = e.mousePosition; + mouseDownSelectionState = new List(flowchart.SelectedBlocks); + e.Use(); + } } + break; - if (buttonPressed) + case MouseButton.Right: + rightClickDown = e.mousePosition; + e.Use(); + break; + } + } + + protected override void OnMouseDrag(Event e) + { + var drag = false; + switch (e.button) + { + case MouseButton.Left: + // Block dragging + if (dragBlock != null) { - CenterBlock(flowchart, block); - SelectBlock(flowchart, block); - CloseBlockPopup(); + for (int i = 0; i < flowchart.SelectedBlocks.Count; ++i) + { + var block = flowchart.SelectedBlocks[i]; + var tempRect = block._NodeRect; + tempRect.position += e.delta / flowchart.Zoom; + block._NodeRect = tempRect; + } + e.Use(); + } + // Pan tool or alt + left click + else if (UnityEditor.Tools.current == Tool.View && UnityEditor.Tools.viewTool == ViewTool.Pan || e.alt) + { + drag = true; + } + else if (UnityEditor.Tools.current == Tool.View && UnityEditor.Tools.viewTool == ViewTool.Zoom) + { + DoZoom(-e.delta.y * 0.01f, Vector2.one * 0.5f); + e.Use(); } + // Selection box + else if (startSelectionBoxPosition.x >= 0 && startSelectionBoxPosition.y >= 0) + { + var topLeft = Vector2.Min(startSelectionBoxPosition, e.mousePosition); + var bottomRight = Vector2.Max(startSelectionBoxPosition, e.mousePosition); + selectionBox = Rect.MinMaxRect(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); + + Rect zoomSelectionBox = selectionBox; + zoomSelectionBox.position -= flowchart.ScrollPos * flowchart.Zoom; + zoomSelectionBox.position /= flowchart.Zoom; + zoomSelectionBox.size /= flowchart.Zoom; - EditorGUILayout.EndHorizontal(); + for (int i = 0; i < blocks.Length; ++i) + { + var block = blocks[i]; + if (zoomSelectionBox.Overlaps(block._NodeRect)) + { + if (mouseDownSelectionState.Contains(block)) + { + flowchart.SelectedBlocks.Remove(block); + } + else + { + flowchart.AddSelectedBlock(block); + } + } + else if (mouseDownSelectionState.Contains(block)) + { + flowchart.AddSelectedBlock(block); + } + else + { + flowchart.SelectedBlocks.Remove(block); + } + } + e.Use(); + } + break; + + case MouseButton.Right: + if (Vector2.Distance(rightClickDown, e.mousePosition) > rightClickTolerance) + { + rightClickDown = -Vector2.one; + } + drag = true; + break; + + case MouseButton.Middle: + drag = true; + break; } - EditorGUILayout.EndScrollView(); - GUILayout.EndArea(); + if (drag) + { + flowchart.ScrollPos += e.delta / flowchart.Zoom; + e.Use(); + } } - - protected virtual void DrawFlowchartView(Flowchart flowchart) + + protected override void OnRawMouseUp(Event e) { - Block[] blocks = flowchart.GetComponents(); + var hitBlock = GetBlockAtPoint(e.mousePosition); - foreach (var block in blocks) + switch (e.button) { - var node = block as Node; - if (node == null) + case MouseButton.Left: + + if (dragBlock != null) { - continue; + for (int i = 0; i < flowchart.SelectedBlocks.Count; ++i) + { + var block = flowchart.SelectedBlocks[i]; + var tempRect = block._NodeRect; + var distance = e.mousePosition / flowchart.Zoom - flowchart.ScrollPos - startDragPosition; + tempRect.position -= distance; + block._NodeRect = tempRect; + Undo.RecordObject(block, "Block Position"); + tempRect.position += distance; + block._NodeRect = tempRect; + } + + dragBlock = null; } - var newRect = new Rect(); - newRect.xMin = Mathf.Min(flowchart.ScrollViewRect.xMin, node._NodeRect.xMin - 400); - newRect.xMax = Mathf.Max(flowchart.ScrollViewRect.xMax, node._NodeRect.xMax + 400); - newRect.yMin = Mathf.Min(flowchart.ScrollViewRect.yMin, node._NodeRect.yMin - 400); - newRect.yMax = Mathf.Max(flowchart.ScrollViewRect.yMax, node._NodeRect.yMax + 400); - flowchart.ScrollViewRect = newRect; + // Check to see if selection actually changed? + if (selectionBox.size.x > 0 && selectionBox.size.y > 0) + { + var tempList = new List(flowchart.SelectedBlocks); + flowchart.SelectedBlocks = mouseDownSelectionState; + Undo.RecordObject(flowchart, "Select"); + flowchart.SelectedBlocks = tempList; + + if (flowchart.SelectedBlock != null) + { + SetBlockForInspector(flowchart, flowchart.SelectedBlock); + } + } + break; + + case MouseButton.Right: + if (rightClickDown != -Vector2.one) + { + var menu = new GenericMenu(); + var mousePosition = rightClickDown; + + // 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()); + menu.AddItem(new GUIContent ("Cut"), false, () => Cut()); + menu.AddItem(new GUIContent ("Duplicate"), false, () => Duplicate()); + menu.AddItem(new GUIContent ("Delete"), false, () => AddToDeleteList(blockList)); + } + else + { + DeselectAll(); + + 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(mousePosition)); + } + else + { + menu.AddDisabledItem(new GUIContent("Paste")); + } + } + + var menuRect = new Rect(); + menuRect.position = new Vector2(mousePosition.x, mousePosition.y - 12f); + menu.DropDown(menuRect); + e.Use(); + } + break; } - // Draw background color / drop shadow - if (Event.current.type == EventType.Repaint) + // Selection box + selectionBox.size = Vector2.zero; + selectionBox.position = -Vector2.one; + startSelectionBoxPosition = selectionBox.position; + } + + protected override void OnScrollWheel(Event e) + { + if (selectionBox.size == Vector2.zero) { - UnityEditor.Graphs.Styles.graphBackground.Draw( - new Rect(0, 17, position.width, position.height - 17), false, false, false, false - ); + Vector2 zoomCenter; + zoomCenter.x = e.mousePosition.x / flowchart.Zoom / position.width; + zoomCenter.y = e.mousePosition.y / flowchart.Zoom / position.height; + zoomCenter *= flowchart.Zoom; + + DoZoom(-e.delta.y * 0.01f, zoomCenter); + e.Use(); } + } + + protected virtual void DrawFlowchartView(Event e) + { // 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) + EditorZoomArea.Begin(flowchart.Zoom, scriptViewRect); + + if (e.type == EventType.Repaint) { - if (Event.current.type == EventType.MouseDown) + DrawGrid(); + + // Draw connections + foreach (var block in blocks) { - rightClickDown = Event.current.mousePosition; + DrawConnections(block, false); } - else if (Event.current.type == EventType.MouseDrag) + foreach (var block in blocks) { - if (Vector2.Distance(rightClickDown, Event.current.mousePosition) > rightClickTolerance) - { - rightClickDown = -Vector2.one; - } + DrawConnections(block, true); } } - EditorZoomArea.Begin(flowchart.Zoom, scriptViewRect); - - if (Event.current.type == EventType.Repaint) - { - DrawGrid(flowchart); - } - - // 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. - if (flowchart != null && blocks.Length > 0) - { - CalcFlowchartCenter(flowchart, blocks); - } - - // Draw connections - foreach (var block in blocks) - { - DrawConnections(flowchart, block, false); - } - foreach (var block in blocks) - { - DrawConnections(flowchart, block, true); - } - - GUIStyle windowStyle = new GUIStyle(); - windowStyle.stretchHeight = true; - - BeginWindows(); - - windowBlockMap.Clear(); - bool useEvent = false; - bool endDrag = false; for (int i = 0; i < blocks.Length; ++i) { var block = blocks[i]; @@ -665,67 +892,62 @@ namespace Fungus.EditorUtils nodeWidthB = nodeStyle.CalcSize(new GUIContent(block._EventHandler.GetSummary())).x + 10; } - if (Event.current.button == 0) - { - Rect tempRect = block._NodeRect; - tempRect.width = Mathf.Max(Mathf.Max(nodeWidthA, nodeWidthB), 120); - tempRect.height = 40; + Rect tempRect = block._NodeRect; + tempRect.width = Mathf.Max(Mathf.Max(nodeWidthA, nodeWidthB), 120); + tempRect.height = 40; + block._NodeRect = tempRect; - if (dragWindowId > -1 && flowchart.SelectedBlocks.Contains(block)) - { - if (Event.current.type == EventType.MouseDrag) - { - tempRect.x += Event.current.delta.x; - tempRect.y += Event.current.delta.y; + Rect windowRect = new Rect(block._NodeRect); + windowRect.position += flowchart.ScrollPos; - forceRepaintCount = 6; - useEvent = true; - } - else if (Event.current.rawType == EventType.MouseUp) - { - Vector2 newPos = new Vector2(tempRect.x, tempRect.y); - tempRect.x = startDragPosition.x + (newPos.x - blocks[dragWindowId]._NodeRect.position.x); - tempRect.y = startDragPosition.y + (newPos.y - blocks[dragWindowId]._NodeRect.position.y); - - block._NodeRect = tempRect; - - Undo.RecordObject(block, "Node Position"); - - tempRect.x = newPos.x; - tempRect.y = newPos.y; - - forceRepaintCount = 6; - useEvent = true; - endDrag = true; - } - } + // Draw blocks + bool selected = flowchart.SelectedBlocks.Contains(block); - block._NodeRect = tempRect; - } + GUIStyle nodeStyleCopy = new GUIStyle(nodeStyle); + var graphics = GetBlockGraphics(block); - Rect windowRect = new Rect(block._NodeRect); - windowRect.x += flowchart.ScrollPos.x; - windowRect.y += flowchart.ScrollPos.y; + // Make sure node is wide enough to fit the node name text + float width = nodeStyleCopy.CalcSize(new GUIContent(block.BlockName)).x; + tempRect = block._NodeRect; + tempRect.width = Mathf.Max(block._NodeRect.width, width); + block._NodeRect = tempRect; - GUILayout.Window(i, windowRect, DrawWindow, "", windowStyle); + // Draw untinted highlight + if (selected) + { + GUI.backgroundColor = Color.white; + nodeStyleCopy.normal.background = graphics.onTexture; + GUI.Box(windowRect, "", nodeStyleCopy); + } - GUI.backgroundColor = Color.white; + // Draw tinted block; ensure text is readable + var brightness = graphics.tint.r * 0.3 + graphics.tint.g * 0.59 + graphics.tint.b * 0.11; + nodeStyleCopy.normal.textColor = brightness >= 0.5 ? Color.black : Color.white; - windowBlockMap.Add(block); - } + if (GUI.GetNameOfFocusedControl() == searchFieldName && !filteredBlocks.Contains(block)) + { + graphics.tint.a *= 0.2f; + } - dragWindowId = endDrag ? -1 : dragWindowId; + nodeStyleCopy.normal.background = graphics.offTexture; + GUI.backgroundColor = graphics.tint; + GUI.Box(windowRect, block.BlockName, nodeStyleCopy); - if (useEvent) - { - Event.current.Use(); - } + GUI.backgroundColor = Color.white; + + if (block.Description.Length > 0) + { + GUIStyle descriptionStyle = new GUIStyle(EditorStyles.helpBox); + descriptionStyle.wordWrap = true; + var content = new GUIContent(block.Description); + windowRect.y += windowRect.height; + windowRect.height = descriptionStyle.CalcHeight(content, windowRect.width); + GUI.Label(windowRect, content, descriptionStyle); + } - EndWindows(); + GUI.backgroundColor = Color.white; - // Draw Event Handler labels - foreach (var block in blocks) - { + // Draw Event Handler labels if (block._EventHandler != null) { string handlerLabel = ""; @@ -753,13 +975,14 @@ namespace Fungus.EditorUtils // Draw play icons beside all executing blocks if (Application.isPlaying) { - foreach (var b in blocks) + for (int i = 0; i < blocks.Length; ++i) { + var b = blocks[i]; if (b.IsExecuting()) { b.ExecutingIconTimer = Time.realtimeSinceStartup + FungusConstants.ExecutingIconFadeTime; b.ActiveCommand.ExecutingIconTimer = Time.realtimeSinceStartup + FungusConstants.ExecutingIconFadeTime; - forceRepaintCount = 6; + forceRepaintCount = 1; } if (b.ExecutingIconTimer > Time.realtimeSinceStartup) @@ -780,7 +1003,7 @@ namespace Fungus.EditorUtils if (GUI.Button(rect, FungusEditorResources.PlayBig, new GUIStyle())) { - SelectBlock(flowchart, b); + SelectBlock(b); } GUI.color = Color.white; @@ -788,77 +1011,10 @@ namespace Fungus.EditorUtils } } - PanAndZoom(flowchart); - EditorZoomArea.End(); - - // Handle right click up outside of EditorZoomArea to avoid strange offsets - if (Event.current.type == EventType.MouseUp && Event.current.button == 1 && - rightClickDown != -Vector2.one && !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, () => Duplicate(flowchart)); - 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) - { - DeselectAll(flowchart); - } - - // Draw selection box - if (startSelectionBoxPosition.x >= 0 && startSelectionBoxPosition.y >= 0) - { - GUI.Box(selectionBox, "", (GUIStyle) "SelectionRect"); - forceRepaintCount = 6; - } } - public virtual Vector2 GetBlockCenter(Flowchart flowchart, Block[] blocks) + public virtual Vector2 GetBlockCenter(Block[] blocks) { if (blocks.Length == 0) { @@ -868,8 +1024,9 @@ namespace Fungus.EditorUtils Vector2 min = blocks[0]._NodeRect.min; Vector2 max = blocks[0]._NodeRect.max; - foreach (var block in blocks) + for (int i = 0; i < blocks.Length; ++i) { + var block = blocks[i]; min.x = Mathf.Min(min.x, block._NodeRect.center.x); min.y = Mathf.Min(min.y, block._NodeRect.center.y); max.x = Mathf.Max(max.x, block._NodeRect.center.x); @@ -879,147 +1036,20 @@ namespace Fungus.EditorUtils 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; - - flowchart.CenterPosition = center; - } - - protected virtual void HandleSelectionBox(Flowchart flowchart) - { - if (Event.current.button == 0 && Event.current.modifiers != EventModifiers.Alt && - !(UnityEditor.Tools.current == Tool.View && UnityEditor.Tools.viewTool == ViewTool.Pan)) - { - switch (Event.current.type) - { - case EventType.MouseDown: - if (!mouseOverVariables) - { - startSelectionBoxPosition = Event.current.mousePosition; - mouseDownSelectionState = new List(flowchart.SelectedBlocks); - Event.current.Use(); - } - break; - - case EventType.MouseDrag: - if (startSelectionBoxPosition.x >= 0 && startSelectionBoxPosition.y >= 0) - { - var topLeft = Vector2.Min(startSelectionBoxPosition, Event.current.mousePosition); - var bottomRight = Vector2.Max(startSelectionBoxPosition, Event.current.mousePosition); - selectionBox = Rect.MinMaxRect(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); - - Rect zoomSelectionBox = selectionBox; - zoomSelectionBox.position -= flowchart.ScrollPos * flowchart.Zoom; - zoomSelectionBox.position /= flowchart.Zoom; - zoomSelectionBox.size /= flowchart.Zoom; - - foreach (var block in flowchart.GetComponents()) - { - if (zoomSelectionBox.Overlaps(block._NodeRect)) - { - if (mouseDownSelectionState.Contains(block)) - { - flowchart.SelectedBlocks.Remove(block); - } - else - { - flowchart.AddSelectedBlock(block); - } - } - else if (mouseDownSelectionState.Contains(block)) - { - flowchart.AddSelectedBlock(block); - } - else - { - flowchart.SelectedBlocks.Remove(block); - } - } - } - Event.current.Use(); - break; - } - - if (Event.current.rawType == EventType.MouseUp) - { - selectionBox.size = Vector2.zero; - selectionBox.position = -Vector2.one; - startSelectionBoxPosition = selectionBox.position; - - var tempList = new List(flowchart.SelectedBlocks); - flowchart.SelectedBlocks = mouseDownSelectionState; - Undo.RecordObject(flowchart, "Select"); - flowchart.SelectedBlocks = tempList; - - if (flowchart.SelectedBlock != null) - { - SetBlockForInspector(flowchart, flowchart.SelectedBlock); - } - } - } - } - - protected virtual void PanAndZoom(Flowchart flowchart) + protected virtual void CenterFlowchart() { - // Right click to drag view - bool drag = false; - - // Pan tool - if (UnityEditor.Tools.current == Tool.View && UnityEditor.Tools.viewTool == ViewTool.Pan && - Event.current.button == 0 && Event.current.type == EventType.MouseDrag) - { - drag = true; - } - - // Right or middle button drag - if (Event.current.button > 0 && Event.current.type == EventType.MouseDrag) - { - drag = true; - } - - // Alt + left mouse drag - if (Event.current.alt && - Event.current.button == 0 && Event.current.type == EventType.MouseDrag) - { - drag = true; - } - - if (drag) - { - flowchart.ScrollPos += Event.current.delta; - forceRepaintCount = 6; - } - - bool zoom = false; - - // Scroll wheel - if (Event.current.type == EventType.ScrollWheel && !mouseOverPopup) - { - zoom = true; - } - - // Zoom tool - if (UnityEditor.Tools.current == Tool.View && UnityEditor.Tools.viewTool == ViewTool.Zoom && - Event.current.button == 0 && Event.current.type == EventType.MouseDrag) - { - zoom = true; - } - - if (zoom && selectionBox.size == Vector2.zero) + if (blocks.Length > 0) { - Vector2 zoomCenter; - zoomCenter.x = Event.current.mousePosition.x / position.width; - zoomCenter.y = Event.current.mousePosition.y / position.height; - zoomCenter *= flowchart.Zoom; + var center = -GetBlockCenter(blocks); + center.x += position.width * 0.5f / flowchart.Zoom; + center.y += position.height * 0.5f / flowchart.Zoom; - DoZoom(flowchart, -Event.current.delta.y * 0.01f, zoomCenter); + flowchart.CenterPosition = center; + flowchart.ScrollPos = flowchart.CenterPosition; } } - protected virtual void DoZoom(Flowchart flowchart, float delta, Vector2 center) + protected virtual void DoZoom(float delta, Vector2 center) { var prevZoom = flowchart.Zoom; flowchart.Zoom += delta; @@ -1027,10 +1057,10 @@ namespace Fungus.EditorUtils var deltaSize = position.size / prevZoom - position.size / flowchart.Zoom; var offset = -Vector2.Scale(deltaSize, center); flowchart.ScrollPos += offset; - forceRepaintCount = 6; + forceRepaintCount = 1; } - protected virtual void DrawGrid(Flowchart flowchart) + protected virtual void DrawGrid() { float width = this.position.width / flowchart.Zoom; float height = this.position.height / flowchart.Zoom; @@ -1059,14 +1089,14 @@ namespace Fungus.EditorUtils Handles.color = Color.white; } - protected virtual void SelectBlock(Flowchart flowchart, Block block) + protected virtual void SelectBlock(Block block) { // Select the block and also select currently executing command flowchart.SelectedBlock = block; SetBlockForInspector(flowchart, block); } - protected virtual void DeselectAll(Flowchart flowchart) + protected virtual void DeselectAll() { Undo.RecordObject(flowchart, "Deselect"); flowchart.ClearSelectedCommands(); @@ -1086,117 +1116,7 @@ namespace Fungus.EditorUtils return newBlock; } - protected virtual void DrawWindow(int windowId) - { - var block = windowBlockMap[windowId]; - var flowchart = (Flowchart)block.GetFlowchart(); - - if (flowchart == null) - { - return; - } - - // Select block when node is clicked - if (Event.current.button == 0 && - Event.current.type == EventType.MouseDown && - !mouseOverVariables) - { - // Check if might be start of a window drag - if (Event.current.button == 0 && - Event.current.alt == false) - { - if (!GetAppendModifierDown()) - { - dragWindowId = windowId; - - startDragPosition.x = block._NodeRect.x; - startDragPosition.y = block._NodeRect.y; - } - - Event.current.Use(); - } - - if (windowId < windowBlockMap.Count) - { - Undo.RecordObject(flowchart, "Select"); - - if (GetAppendModifierDown()) - { - if (flowchart.SelectedBlocks.Contains(block)) - { - flowchart.SelectedBlocks.Remove(block); - } - else - { - flowchart.AddSelectedBlock(block); - } - } - else - { - if (flowchart.SelectedBlocks.Contains(block)) - { - SetBlockForInspector(flowchart, block); - } - else - { - SelectBlock(flowchart, block); - } - } - - GUIUtility.keyboardControl = 0; // Fix for textarea not refeshing (change focus) - } - } - - bool selected = false; - if (flowchart.SelectedBlocks.Contains(block)) - { - selected = true; - } - - GUIStyle nodeStyleCopy = new GUIStyle(nodeStyle); - var graphics = GetBlockGraphics(block); - - // Make sure node is wide enough to fit the node name text - var n = block as Node; - float width = nodeStyleCopy.CalcSize(new GUIContent(block.BlockName)).x; - Rect tempRect = n._NodeRect; - tempRect.width = Mathf.Max (n._NodeRect.width, width); - n._NodeRect = tempRect; - - Rect boxRect = GUILayoutUtility.GetRect(n._NodeRect.width, n._NodeRect.height); - - // Draw untinted highlight - if (selected) - { - GUI.backgroundColor = Color.white; - nodeStyleCopy.normal.background = graphics.onTexture; - GUI.Box(boxRect, "", nodeStyleCopy); - } - - // Draw tinted block; ensure text is readable - var brightness = graphics.tint.r * 0.3 + graphics.tint.g * 0.59 + graphics.tint.b * 0.11; - nodeStyleCopy.normal.textColor = brightness >= 0.5 ? Color.black : Color.white; - - if (GUI.GetNameOfFocusedControl() == searchFieldName && !filteredBlocks.Contains(block)) - { - graphics.tint.a *= 0.2f; - } - - nodeStyleCopy.normal.background = graphics.offTexture; - GUI.backgroundColor = graphics.tint; - GUI.Box(boxRect, block.BlockName, nodeStyleCopy); - - GUI.backgroundColor = Color.white; - - if (block.Description.Length > 0) - { - GUIStyle descriptionStyle = new GUIStyle(EditorStyles.helpBox); - descriptionStyle.wordWrap = true; - GUILayout.Label(block.Description, descriptionStyle); - } - } - - protected virtual void DrawConnections(Flowchart flowchart, Block block, bool highlightedOnly) + protected virtual void DrawConnections(Block block, bool highlightedOnly) { if (block == null) { @@ -1205,7 +1125,7 @@ namespace Fungus.EditorUtils var connectedBlocks = new List(); - bool blockIsSelected = (flowchart.SelectedBlock != block); + bool blockIsSelected = flowchart.SelectedBlock == block; var commandList = block.CommandList; foreach (var command in commandList) @@ -1343,10 +1263,47 @@ namespace Fungus.EditorUtils return rt * rt * rt * s + 3 * rt * rtt * st + 3 * rtt * t * et + t * t * t * e; } - public static void DeleteBlocks(object obj) + protected void AddToDeleteList(List blocks) + { + for (int i = 0; i < blocks.Count; ++i) + { + FlowchartWindow.deleteList.Add(blocks[i]); + } + } + + public void DeleteBlocks() { - var blocks = obj as List; - blocks.ForEach(block => FlowchartWindow.deleteList.Add(block)); + // Delete any scheduled objects + for (int i = 0; i < deleteList.Count; ++i) + { + var deleteBlock = deleteList[i]; + bool isSelected = (flowchart.SelectedBlocks.Contains(deleteBlock)); + + var commandList = deleteBlock.CommandList; + for (int j = 0; j < commandList.Count; ++j) + { + Undo.DestroyObjectImmediate(commandList[j]); + } + + if (deleteBlock._EventHandler != null) + { + Undo.DestroyObjectImmediate(deleteBlock._EventHandler); + } + + Undo.DestroyObjectImmediate(deleteBlock); + flowchart.ClearSelectedCommands(); + + if (isSelected) + { + // Deselect + flowchart.SelectedBlocks.Remove(deleteBlock); + + // Revert to showing properties for the Flowchart + Selection.activeGameObject = flowchart.gameObject; + } + } + + deleteList.Clear(); } protected static void ShowBlockInspector(Flowchart flowchart) @@ -1391,7 +1348,7 @@ namespace Fungus.EditorUtils return Event.current.shift || EditorGUI.actionKey; } - protected virtual void Copy(Flowchart flowchart) + protected virtual void Copy() { copyList.Clear(); @@ -1401,18 +1358,18 @@ namespace Fungus.EditorUtils } } - protected virtual void Cut(Flowchart flowchart) + protected virtual void Cut() { - Copy(flowchart); + Copy(); Undo.RecordObject(flowchart, "Cut"); - DeleteBlocks(flowchart.SelectedBlocks); + AddToDeleteList(flowchart.SelectedBlocks); } // Center is position in unscaled window space - protected virtual void Paste(Flowchart flowchart, Vector2 center, bool relative = false) + protected virtual void Paste(Vector2 center, bool relative = false) { Undo.RecordObject(flowchart, "Deselect"); - DeselectAll(flowchart); + DeselectAll(); var pasteList = new List(); @@ -1421,7 +1378,7 @@ namespace Fungus.EditorUtils pasteList.Add(copy.PasteBlock(flowchart)); } - var copiedCenter = GetBlockCenter(flowchart, pasteList.ToArray()) + flowchart.ScrollPos; + var copiedCenter = GetBlockCenter(pasteList.ToArray()) + flowchart.ScrollPos; var delta = relative ? center : (center / flowchart.Zoom - copiedCenter); foreach (var block in pasteList) @@ -1432,95 +1389,93 @@ namespace Fungus.EditorUtils } } - protected virtual void Duplicate(Flowchart flowchart) + protected virtual void Duplicate() { var tempCopyList = new List(copyList); - Copy(flowchart); - Paste(flowchart, new Vector2(20, 0), true); + Copy(); + Paste(new Vector2(20, 0), true); copyList = tempCopyList; } - protected virtual void ValidateCommands(Flowchart flowchart) + protected override void OnValidateCommand(Event e) { - if (Event.current.type == EventType.ValidateCommand) + if (e.type == EventType.ValidateCommand) { - var c = Event.current.commandName; + var c = e.commandName; if (c == "Copy" || c == "Cut" || c == "Delete" || c == "Duplicate") { if (flowchart.SelectedBlocks.Count > 0) { - Event.current.Use(); + e.Use(); } } else if (c == "Paste") { if (copyList.Count > 0) { - Event.current.Use(); + e.Use(); } } else if (c == "SelectAll" || c == "Find") { - Event.current.Use(); + e.Use(); } } } - protected virtual void ExecuteCommands(Flowchart flowchart) + protected override void OnExecuteCommand(Event e) { - if (Event.current.type == EventType.ExecuteCommand) + switch (e.commandName) { - switch (Event.current.commandName) + case "Copy": + Copy(); + e.Use(); + break; + + case "Cut": + Cut(); + e.Use(); + break; + + case "Paste": + Paste(position.center - position.position); + e.Use(); + break; + + case "Delete": + AddToDeleteList(flowchart.SelectedBlocks); + e.Use(); + break; + + case "Duplicate": + Duplicate(); + e.Use(); + break; + + case "SelectAll": + Undo.RecordObject(flowchart, "Selection"); + flowchart.ClearSelectedBlocks(); + for (int i = 0; i < blocks.Length; ++i) { - 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": - Duplicate(flowchart); - 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; - - case "Find": - blockPopupSelection = 0; - EditorGUI.FocusTextInControl(searchFieldName); - Event.current.Use(); - break; + flowchart.AddSelectedBlock(blocks[i]); } + e.Use(); + break; + + case "Find": + blockPopupSelection = 0; + popupScroll = Vector2.zero; + EditorGUI.FocusTextInControl(searchFieldName); + e.Use(); + break; } } - protected virtual void CenterBlock(Flowchart flowchart, Block block) + protected virtual void CenterBlock(Block block) { if (flowchart.Zoom < 1) { - DoZoom(flowchart, 1 - flowchart.Zoom, Vector2.one * 0.5f); + DoZoom(1 - flowchart.Zoom, Vector2.one * 0.5f); } flowchart.ScrollPos = -block._NodeRect.center + position.size * 0.5f / flowchart.Zoom; diff --git a/Assets/Materials.meta b/Assets/Materials.meta new file mode 100644 index 00000000..1e2f3ee6 --- /dev/null +++ b/Assets/Materials.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1c50c0c57f3a4493fac16abcf3e567a1 +folderAsset: yes +timeCreated: 1484499349 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: