Browse Source

Redesigned Fungus Script window and inspector UI

Sequences are now shown as simple coloured nodes in Fungus Script
window.
Commands for the selected sequence are now shown in the full inspector
window.
FungusScript window now continues to display the most recently selected
script.
Fungus Script window now refreshes every frame.
Can zoom out further on Fungus Script window.
Fungus Script window and Sequence inspectors now have separate context
menus.
master
chrisgregan 10 years ago
parent
commit
7d0491ff5c
  1. 115
      Assets/Examples/TheHunter/TheHunter.unity
  2. 19
      Assets/Fungus/FungusScript/Editor/CommandEditor.cs
  3. 12
      Assets/Fungus/FungusScript/Editor/CommandListAdaptor.cs
  4. 41
      Assets/Fungus/FungusScript/Editor/FungusScriptEditor.cs
  5. 422
      Assets/Fungus/FungusScript/Editor/FungusScriptWindow.cs
  6. 317
      Assets/Fungus/FungusScript/Editor/SequenceEditor.cs
  7. 69
      Assets/Fungus/FungusScript/Editor/SequenceInspector.cs
  8. 8
      Assets/Fungus/FungusScript/Editor/SequenceInspector.cs.meta
  9. 14
      Assets/Fungus/FungusScript/Scripts/FungusState.cs
  10. 8
      Assets/Fungus/FungusScript/Scripts/FungusState.cs.meta
  11. 2
      Assets/Fungus/FungusScript/Scripts/Node.cs

115
Assets/Examples/TheHunter/TheHunter.unity

@ -1690,10 +1690,10 @@ MonoBehaviour:
m_EditorClassIdentifier:
nodeRect:
serializedVersion: 2
x: -244
y: -226.5
width: 240
height: 154
x: 105.654449
y: -378.268433
width: 120
height: 30
sequenceName: Check for fish
commandList:
- {fileID: 541676553}
@ -2704,6 +2704,8 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
scrollPos: {x: 226.013794, y: 380.023193}
variablesScrollPos: {x: 0, y: 0}
variablesExpanded: 1
zoom: 1
scrollViewRect:
serializedVersion: 2
@ -2782,10 +2784,10 @@ MonoBehaviour:
m_EditorClassIdentifier:
nodeRect:
serializedVersion: 2
x: -227.439697
y: 85.5
width: 240
height: 414
x: 108.608582
y: -195.124023
width: 120
height: 30
sequenceName: Bear
commandList:
- {fileID: 899740689}
@ -3490,10 +3492,10 @@ MonoBehaviour:
m_EditorClassIdentifier:
nodeRect:
serializedVersion: 2
x: 57
y: -89
width: 240
height: 174
x: 106.621155
y: -319.003174
width: 120
height: 30
sequenceName: Rescued
commandList:
- {fileID: 1196017816}
@ -3824,6 +3826,8 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
scrollPos: {x: 0, y: 0}
variablesScrollPos: {x: 0, y: 0}
variablesExpanded: 1
zoom: 1
scrollViewRect:
serializedVersion: 2
@ -4488,10 +4492,10 @@ MonoBehaviour:
m_EditorClassIdentifier:
nodeRect:
serializedVersion: 2
x: -204
y: -450
width: 240
height: 134
x: 105.537018
y: -501.022339
width: 120
height: 30
sequenceName: Start
commandList:
- {fileID: 1507034370}
@ -5231,10 +5235,10 @@ MonoBehaviour:
m_EditorClassIdentifier:
nodeRect:
serializedVersion: 2
x: 104
y: -465
width: 240
height: 194
x: 108
y: -439.890259
width: 120
height: 30
sequenceName: Intro
commandList:
- {fileID: 1759345003}
@ -5552,10 +5556,10 @@ MonoBehaviour:
m_EditorClassIdentifier:
nodeRect:
serializedVersion: 2
x: 467
y: -81.5
width: 240
height: 294
x: 257.201355
y: -354.533142
width: 120
height: 30
sequenceName: Shout out
commandList:
- {fileID: 1801800853}
@ -5915,17 +5919,18 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 7a334fe2ffb574b3583ff3b18b4792d3, type: 3}
m_Name:
m_EditorClassIdentifier:
scrollPos: {x: 241.899506, y: 519.510498}
scrollPos: {x: 255.192505, y: 540.002808}
variablesScrollPos: {x: 0, y: 0}
variablesExpanded: 0
zoom: 1
scrollViewRect:
serializedVersion: 2
x: -810.017578
y: -883.033203
y: -904.006714
width: 1939.01758
height: 1972.5332
selectedSequence: {fileID: 1507034365}
selectedCommands:
- {fileID: 1507034370}
height: 1993.50671
selectedSequence: {fileID: 1759344996}
selectedCommands: []
variables:
- {fileID: 1831099569}
startSequence: {fileID: 1507034365}
@ -6038,6 +6043,8 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
scrollPos: {x: 0, y: 0}
variablesScrollPos: {x: 0, y: 0}
variablesExpanded: 1
zoom: 1
scrollViewRect:
serializedVersion: 2
@ -6424,10 +6431,10 @@ MonoBehaviour:
m_EditorClassIdentifier:
nodeRect:
serializedVersion: 2
x: 88
y: 166.5
width: 240
height: 194
x: 105.007446
y: -258.68811
width: 120
height: 30
sequenceName: Exit
commandList:
- {fileID: 2111357060}
@ -6587,3 +6594,43 @@ MonoBehaviour:
errorMessage:
indentLevel: 0
targetSequence: {fileID: 899740677}
--- !u!1 &2142927451
GameObject:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 4
m_Component:
- 4: {fileID: 2142927453}
- 114: {fileID: 2142927452}
m_Layer: 0
m_Name: _FungusState
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &2142927452
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 2142927451}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 61dddfdc5e0e44ca298d8f46f7f5a915, type: 3}
m_Name:
m_EditorClassIdentifier:
selectedFungusScript: {fileID: 1831099568}
--- !u!4 &2142927453
Transform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 2142927451}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0

19
Assets/Fungus/FungusScript/Editor/CommandEditor.cs

@ -47,13 +47,10 @@ namespace Fungus
return;
}
GUILayout.BeginVertical(GUI.skin.box);
EditorGUILayout.PrefixLabel(new GUIContent("Command"));
GUI.backgroundColor = Color.green;
GUILayout.BeginHorizontal(GUI.skin.button);
GUILayout.BeginVertical(GUI.skin.box);
string commandName = commandInfoAttr.CommandName;
GUIStyle commandStyle = new GUIStyle(EditorStyles.miniButton);
if (t.enabled)
{
if (fungusScript.settings.colorCommands)
@ -69,15 +66,15 @@ namespace Fungus
{
GUI.backgroundColor = Color.grey;
}
GUILayout.BeginHorizontal(GUI.skin.button);
bool enabled = t.enabled;
string commandName = commandInfoAttr.CommandName;
GUILayout.Label(commandName, GUILayout.MinWidth(80), GUILayout.ExpandWidth(true));
if (GUILayout.Button(commandName, commandStyle, GUILayout.MinWidth(80), GUILayout.ExpandWidth(true)))
{
enabled = !enabled;
}
GUILayout.FlexibleSpace();
GUI.backgroundColor = Color.white;
bool enabled = t.enabled;
enabled = GUILayout.Toggle(enabled, new GUIContent());
if (t.enabled != enabled)
@ -108,7 +105,7 @@ namespace Fungus
CommandInfoAttribute infoAttr = CommandEditor.GetCommandInfo(t.GetType());
if (infoAttr != null)
{
EditorGUILayout.HelpBox(infoAttr.CommandName + ":\n" + infoAttr.HelpText, MessageType.Info, true);
EditorGUILayout.HelpBox(infoAttr.HelpText, MessageType.Info, true);
}
}

12
Assets/Fungus/FungusScript/Editor/CommandListAdaptor.cs

@ -18,7 +18,7 @@ namespace Fungus
public float fixedItemHeight;
public Rect nodeRect = new Rect();
public SerializedProperty this[int index] {
get { return _arrayProperty.GetArrayElementAtIndex(index); }
}
@ -222,17 +222,25 @@ namespace Fungus
commandLabelRect.width -= (indentSize * command.indentLevel - 22);
commandLabelRect.height += 5;
// Select command via left click
if (!Application.isPlaying &&
Event.current.type == EventType.MouseDown &&
(Event.current.button == 0 || Event.current.button == 1) &&
Event.current.button == 0 &&
position.Contains(Event.current.mousePosition))
{
if (fungusScript.selectedCommands.Contains(command) && Event.current.button == 0)
{
// Left click on an already selected command
fungusScript.selectedCommands.Remove(command);
}
else
{
// Left click and no command key
if (!EditorGUI.actionKey && Event.current.button == 0)
{
fungusScript.ClearSelectedCommands();
}
fungusScript.AddSelectedCommand(command);
}
GUIUtility.keyboardControl = 0; // Fix for textarea not refeshing (change focus)

41
Assets/Fungus/FungusScript/Editor/FungusScriptEditor.cs

@ -72,31 +72,6 @@ namespace Fungus
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
EditorGUILayout.Separator();
if (fungusScript.selectedSequence != null)
{
SequenceEditor sequenceEditor = Editor.CreateEditor(fungusScript.selectedSequence) as SequenceEditor;
sequenceEditor.DrawInspectorGUI(fungusScript);
DestroyImmediate(sequenceEditor);
}
if (fungusScript.selectedCommands.Count == 1)
{
if (fungusScript.selectedCommands[0] == null)
{
fungusScript.ClearSelectedCommands();
}
else
{
CommandEditor commandEditor = Editor.CreateEditor(fungusScript.selectedCommands[0]) as CommandEditor;
commandEditor.DrawCommandInspectorGUI();
DestroyImmediate(commandEditor);
}
}
EditorGUILayout.Separator();
serializedObject.ApplyModifiedProperties();
}
@ -121,7 +96,14 @@ namespace Fungus
{
ReorderableListGUI.Title("Variables");
VariableListAdaptor adaptor = new VariableListAdaptor(variablesProp, 0);
ReorderableListControl.DrawControlFromState(adaptor, null, ReorderableListFlags.DisableContextMenu | ReorderableListFlags.HideAddButton);
ReorderableListFlags flags = ReorderableListFlags.DisableContextMenu | ReorderableListFlags.HideAddButton;
if (Application.isPlaying)
{
flags |= ReorderableListFlags.HideRemoveButtons;
}
ReorderableListControl.DrawControlFromState(adaptor, null, flags);
listRect = GUILayoutUtility.GetLastRect();
}
else
@ -138,9 +120,12 @@ namespace Fungus
float buttonHeight = 24;
buttonRect.x = 4;
buttonRect.y -= buttonHeight - 1;
buttonRect.width -= 30;
buttonRect.height = buttonHeight;
if (!Application.isPlaying)
{
buttonRect.width -= 30;
}
if (GUI.Button (buttonRect, "Variables"))
{
t.variablesExpanded = false;

422
Assets/Fungus/FungusScript/Editor/FungusScriptWindow.cs

@ -8,9 +8,7 @@ namespace Fungus
{
public class FungusScriptWindow : EditorWindow
{
static bool locked = false;
static GUIStyle lockButtonStyle;
static FungusScript activeFungusScript;
public static List<Sequence> deleteList = new List<Sequence>();
@ -22,12 +20,11 @@ namespace Fungus
protected Vector2 startDragPosition;
protected Sequence selectedSequence;
protected const float minZoomValue = 0.5f;
protected const float minZoomValue = 0.25f;
protected const float maxZoomValue = 1f;
// Set this flag to tell the context menu to appear.
// The context menu is modal, so we need to defer displaying it if the background needs to be repainted
public static bool showContextMenu;
protected static SequenceInspector sequenceInspector;
protected bool followExecution = true;
[MenuItem("Window/Fungus Script")]
static void Init()
@ -35,37 +32,33 @@ namespace Fungus
GetWindow(typeof(FungusScriptWindow), false, "Fungus Script");
}
// Implementing this method causes the padlock image to display on the window
// https://leahayes.wordpress.com/2013/04/30/adding-the-little-padlock-button-to-your-editorwindow/#more-455
protected virtual void ShowButton(Rect position) {
if (lockButtonStyle == null)
{
lockButtonStyle = "IN LockButton";
}
locked = GUI.Toggle(position, locked, GUIContent.none, lockButtonStyle);
}
public virtual void OnInspectorUpdate()
public virtual void OnEnable()
{
Repaint();
followExecution = true;
}
static public FungusScript GetFungusScript()
{
if (locked && activeFungusScript != null)
// Using a temp hidden object to track the active Fungus Script across
// serialization / deserialization when playing the game in the editor.
FungusState fungusState = GameObject.FindObjectOfType<FungusState>();
if (fungusState == null)
{
return activeFungusScript;
GameObject go = new GameObject("_FungusState");
go.hideFlags = HideFlags.HideInHierarchy;
fungusState = go.AddComponent<FungusState>();
}
locked = false;
if (Selection.activeGameObject != null)
{
activeFungusScript = Selection.activeGameObject.GetComponent<FungusScript>();
return activeFungusScript;
FungusScript fs = Selection.activeGameObject.GetComponent<FungusScript>();
if (fs != null)
{
fungusState.selectedFungusScript = fs;
}
}
return null;
return fungusState.selectedFungusScript;
}
protected virtual void OnGUI()
@ -86,7 +79,7 @@ namespace Fungus
}
Undo.DestroyObjectImmediate(deleteSequence);
fungusScript.selectedSequence = null;
SetSelectedSequence(fungusScript, null);
fungusScript.ClearSelectedCommands();
}
deleteList.Clear();
@ -94,12 +87,26 @@ namespace Fungus
DrawScriptView(fungusScript);
DrawOverlay(fungusScript);
if (Event.current.type == EventType.Repaint &&
showContextMenu)
if (Application.isPlaying &&
fungusScript.executingSequence != null &&
followExecution)
{
ShowContextMenu();
showContextMenu = false;
// Set SequenceInspector object as the selected object
if (Selection.activeGameObject == fungusScript.gameObject ||
Selection.activeGameObject == sequenceInspector)
{
SetSelectedSequence(fungusScript, fungusScript.executingSequence);
}
// Make sure SequenceInspector is using the currently executing sequence
if (sequenceInspector != null)
{
sequenceInspector.sequence = fungusScript.executingSequence;
}
}
// Redraw on next frame to get crisp refresh rate
Repaint();
}
protected virtual void DrawOverlay(FungusScript fungusScript)
@ -177,11 +184,13 @@ namespace Fungus
Event.current.type == EventType.MouseDown)
{
selectedSequence = fungusScript.selectedSequence;
fungusScript.selectedSequence = null;
SetSelectedSequence(fungusScript, null);
if (!EditorGUI.actionKey)
{
fungusScript.ClearSelectedCommands();
}
Selection.activeGameObject = fungusScript.gameObject;
followExecution = false;
}
// Draw connections
@ -199,6 +208,8 @@ namespace Fungus
BeginWindows();
GUIStyle nodeStyle = new GUIStyle("flow node 3");
windowSequenceMap.Clear();
for (int i = 0; i < sequences.Length; ++i)
{
@ -207,10 +218,12 @@ namespace Fungus
// Hack to support legacy design where sequences were child gameobjects (will be removed soon)
sequence.UpdateSequenceName();
sequence.nodeRect.height = CalcRectHeight(sequence.commandList.Count);
float nodeWidth = nodeStyle.CalcSize(new GUIContent(sequence.sequenceName)).x;
sequence.nodeRect.width = Mathf.Max(120, nodeWidth);
sequence.nodeRect.height = 30;
if (!Application.isPlaying &&
Event.current.button == 0)
if (Event.current.button == 0)
{
if (Event.current.type == EventType.MouseDrag && dragWindowId == i)
{
@ -303,7 +316,7 @@ namespace Fungus
{
Sequence newSequence = fungusScript.CreateSequence(position);
Undo.RegisterCreatedObjectUndo(newSequence, "New Sequence");
fungusScript.selectedSequence = newSequence;
SetSelectedSequence(fungusScript, newSequence);
fungusScript.ClearSelectedCommands();
return newSequence;
@ -317,7 +330,7 @@ namespace Fungus
}
Undo.DestroyObjectImmediate(sequence);
fungusScript.selectedSequence = null;
SetSelectedSequence(fungusScript, null);
fungusScript.ClearSelectedCommands();
}
@ -327,9 +340,8 @@ namespace Fungus
FungusScript fungusScript = sequence.GetFungusScript();
// Select sequence when node is clicked
if (!Application.isPlaying &&
(Event.current.button == 0 || Event.current.button == 1) &&
(Event.current.type == EventType.MouseDown))
if (Event.current.button == 0 &&
Event.current.type == EventType.MouseDown)
{
// Check if might be start of a window drag
if (Event.current.button == 0 &&
@ -343,54 +355,42 @@ namespace Fungus
if (windowId < windowSequenceMap.Count)
{
Undo.RecordObject(fungusScript, "Select");
if (sequence != selectedSequence || !EditorGUI.actionKey)
{
int commandIndex = CalcCommandIndex(Event.current.mousePosition.y);
if (commandIndex < sequence.commandList.Count &&
fungusScript.selectedCommands.Contains(sequence.commandList[commandIndex]))
{
// Right clicking on an already selected command does not clear the selected list
}
else
{
fungusScript.ClearSelectedCommands();
}
}
if (selectedSequence != sequence &&
Event.current.mousePosition.x > sequence.nodeRect.width - 30f)
SetSelectedSequence(fungusScript, sequence);
GUIUtility.keyboardControl = 0; // Fix for textarea not refeshing (change focus)
if (Application.isPlaying)
{
Event.current.Use();
// If user selected a non-executing sequence then stop following execution
followExecution = (fungusScript.selectedSequence == fungusScript.executingSequence);
}
fungusScript.selectedSequence = sequence;
GUIUtility.keyboardControl = 0; // Fix for textarea not refeshing (change focus)
}
}
GUIStyle nodeStyle = null;
if (fungusScript.selectedSequence == sequence ||
fungusScript.executingSequence == sequence)
{
GUI.backgroundColor = Color.green;
Rect highlightRect = new Rect(0, 0, sequence.nodeRect.width, 24);
GUIStyle highlightStyle = new GUIStyle();
highlightStyle.normal.background = FungusEditorResources.texCommandBackground;
highlightStyle.border.top = 1;
highlightStyle.border.bottom = 1;
highlightStyle.border.left = 1;
highlightStyle.border.right = 1;
GUI.Box(highlightRect, "", highlightStyle);
GUI.backgroundColor = Color.white;
// Green node
nodeStyle = new GUIStyle("flow node 3");
}
else
{
// Yellow node
nodeStyle = new GUIStyle("flow node 4");
}
GUILayout.BeginVertical();
GUILayout.Box(sequence.sequenceName, nodeStyle, GUILayout.Width(sequence.nodeRect.width), GUILayout.Height(sequence.nodeRect.height));
SequenceEditor sequenceEditor = Editor.CreateEditor(sequence) as SequenceEditor;
sequenceEditor.DrawCommandListGUI(sequence.GetFungusScript());
DestroyImmediate(sequenceEditor);
if (Event.current.type == EventType.ContextClick)
{
GenericMenu menu = new GenericMenu ();
menu.AddItem(new GUIContent ("Duplicate"), false, DuplicateSequence, sequence);
menu.AddItem(new GUIContent ("Delete"), false, DeleteSequence, sequence);
GUILayout.EndVertical();
menu.ShowAsContext();
}
}
protected virtual void DrawConnections(FungusScript fungusScript, Sequence sequence, bool highlightedOnly)
@ -441,13 +441,10 @@ namespace Fungus
}
Rect startRect = new Rect(sequence.nodeRect);
startRect.y += CalcRectHeight(sequence.commandList.Count);
startRect.height = 0;
startRect.x += fungusScript.scrollPos.x;
startRect.y += fungusScript.scrollPos.y;
Rect endRect = new Rect(sequenceB.nodeRect);
endRect.height = 22;
endRect.x += fungusScript.scrollPos.x;
endRect.y += fungusScript.scrollPos.y;
@ -460,14 +457,16 @@ namespace Fungus
{
Vector2[] pointsA = new Vector2[] {
new Vector2(rectA.xMin, rectA.center.y),
new Vector2(rectA.xMin + rectA.width / 2, rectA.yMax + 15),
new Vector2(rectA.xMin + rectA.width / 2, rectA.yMin),
new Vector2(rectA.xMin + rectA.width / 2, rectA.yMax),
new Vector2(rectA.xMax, rectA.center.y)
};
Vector2[] pointsB = new Vector2[] {
new Vector2(rectB.xMin, rectB.center.y + 4),
new Vector2(rectB.xMin, rectB.center.y),
new Vector2(rectB.xMin + rectB.width / 2, rectB.yMin),
new Vector2(rectB.xMax, rectB.center.y + 4)
new Vector2(rectB.xMin + rectB.width / 2, rectB.yMax),
new Vector2(rectB.xMax, rectB.center.y)
};
Vector2 pointA = Vector2.zero;
@ -503,270 +502,59 @@ namespace Fungus
GUI.Label(dotBRect, "", new GUIStyle("U2D.dragDotActive"));
}
protected virtual float CalcRectHeight(int numCommands)
{
return (numCommands * 20) + 34;
}
protected virtual int CalcCommandIndex(float mouseY)
{
return Math.Max(0, (int)(mouseY - 34 + 7) / 20);
}
public static void ShowContextMenu()
{
FungusScript fungusScript = GetFungusScript();
if (fungusScript == null)
{
return;
}
bool showCut = false;
bool showCopy = false;
bool showDelete = false;
bool showPaste = false;
if (fungusScript.selectedCommands.Count > 0)
{
showCut = true;
showCopy = true;
showDelete = true;
}
CommandCopyBuffer commandCopyBuffer = CommandCopyBuffer.GetInstance();
if (commandCopyBuffer.HasCommands())
{
showPaste = true;
}
GenericMenu commandMenu = new GenericMenu();
if (showCut)
{
commandMenu.AddItem (new GUIContent ("Cut"), false, Cut);
}
else
{
commandMenu.AddDisabledItem(new GUIContent ("Cut"));
}
if (showCopy)
{
commandMenu.AddItem (new GUIContent ("Copy"), false, Copy);
}
else
{
commandMenu.AddDisabledItem(new GUIContent ("Copy"));
}
if (showPaste)
{
commandMenu.AddItem (new GUIContent ("Paste"), false, Paste);
}
else
{
commandMenu.AddDisabledItem(new GUIContent ("Paste"));
}
if (showDelete)
{
commandMenu.AddItem (new GUIContent ("Delete"), false, Delete);
}
else
{
commandMenu.AddDisabledItem(new GUIContent ("Delete"));
}
commandMenu.AddSeparator("");
commandMenu.AddItem (new GUIContent ("Select All"), false, SelectAll);
commandMenu.AddItem (new GUIContent ("Select None"), false, SelectNone);
commandMenu.AddSeparator("");
commandMenu.AddItem (new GUIContent ("Delete Sequence"), false, DeleteSequence);
commandMenu.AddItem (new GUIContent ("Duplicate Sequence"), false, DuplicateSequence);
commandMenu.ShowAsContext();
}
protected static void SelectAll()
{
FungusScript fungusScript = GetFungusScript();
if (fungusScript == null ||
fungusScript.selectedSequence == null)
{
return;
}
fungusScript.ClearSelectedCommands();
Undo.RecordObject(fungusScript, "Select All");
foreach (Command command in fungusScript.selectedSequence.commandList)
{
fungusScript.AddSelectedCommand(command);
}
}
protected static void SelectNone()
{
FungusScript fungusScript = GetFungusScript();
if (fungusScript == null ||
fungusScript.selectedSequence == null)
{
return;
}
Undo.RecordObject(fungusScript, "Select None");
fungusScript.ClearSelectedCommands();
}
protected static void Cut()
public static void DeleteSequence(object obj)
{
Copy();
Delete();
Sequence sequence = obj as Sequence;
FungusScriptWindow.deleteList.Add(sequence);
}
protected static void Copy()
protected static void DuplicateSequence(object obj)
{
FungusScript fungusScript = GetFungusScript();
if (fungusScript == null ||
fungusScript.selectedSequence == null)
{
return;
}
Sequence sequence = obj as Sequence;
CommandCopyBuffer commandCopyBuffer = CommandCopyBuffer.GetInstance();
commandCopyBuffer.Clear();
Vector2 newPosition = new Vector2(sequence.nodeRect.position.x +
sequence.nodeRect.width + 20,
sequence.nodeRect.y);
foreach (Command command in fungusScript.selectedCommands)
{
System.Type type = command.GetType();
Command newCommand = Undo.AddComponent(commandCopyBuffer.gameObject, type) as Command;
System.Reflection.FieldInfo[] fields = type.GetFields();
foreach (System.Reflection.FieldInfo field in fields)
{
field.SetValue(newCommand, field.GetValue(command));
}
}
}
protected static void Paste()
{
FungusScript fungusScript = GetFungusScript();
if (fungusScript == null ||
fungusScript.selectedSequence == null)
{
return;
}
Sequence oldSequence = sequence;
CommandCopyBuffer commandCopyBuffer = CommandCopyBuffer.GetInstance();
Sequence newSequence = FungusScriptWindow.CreateSequence(fungusScript, newPosition);
newSequence.sequenceName = oldSequence.sequenceName + " (Copy)";
// Find where to paste commands in sequence (either at end or after last selected command)
int pasteIndex = fungusScript.selectedSequence.commandList.Count;
if (fungusScript.selectedCommands.Count > 0)
{
for (int i = 0; i < fungusScript.selectedSequence.commandList.Count; ++i)
{
Command command = fungusScript.selectedSequence.commandList[i];
foreach (Command selectedCommand in fungusScript.selectedCommands)
{
if (command == selectedCommand)
{
pasteIndex = i + 1;
}
}
}
}
foreach (Command command in commandCopyBuffer.GetCommands())
foreach (Command command in oldSequence.commandList)
{
System.Type type = command.GetType();
Command newCommand = Undo.AddComponent(fungusScript.selectedSequence.gameObject, type) as Command;
Command newCommand = Undo.AddComponent(fungusScript.gameObject, type) as Command;
System.Reflection.FieldInfo[] fields = type.GetFields();
foreach (System.Reflection.FieldInfo field in fields)
{
field.SetValue(newCommand, field.GetValue(command));
}
Undo.RecordObject(fungusScript.selectedSequence, "Paste");
fungusScript.selectedSequence.commandList.Insert(pasteIndex++, newCommand);
newSequence.commandList.Add(newCommand);
}
}
protected static void Delete()
{
FungusScript fungusScript = GetFungusScript();
if (fungusScript == null ||
fungusScript.selectedSequence == null)
{
return;
}
for (int i = fungusScript.selectedSequence.commandList.Count - 1; i >= 0; --i)
{
Command command = fungusScript.selectedSequence.commandList[i];
foreach (Command selectedCommand in fungusScript.selectedCommands)
{
if (command == selectedCommand)
{
Undo.RecordObject(fungusScript.selectedSequence, "Delete");
fungusScript.selectedSequence.commandList.RemoveAt(i);
Undo.DestroyObjectImmediate(command);
break;
}
}
}
Undo.RecordObject(fungusScript, "Delete");
fungusScript.ClearSelectedCommands();
fungusScript.selectedSequence = null;
}
public static void DeleteSequence()
protected static void SetSelectedSequence(FungusScript fungusScript, Sequence sequence)
{
FungusScript fungusScript = GetFungusScript();
if (fungusScript == null ||
fungusScript.selectedSequence == null)
{
return;
}
fungusScript.selectedSequence = sequence;
FungusScriptWindow.deleteList.Add(fungusScript.selectedSequence);
}
protected static void DuplicateSequence()
{
FungusScript fungusScript = GetFungusScript();
if (fungusScript == null ||
fungusScript.selectedSequence == null)
if (sequenceInspector == null)
{
return;
// Create a Scriptable Object with a custom editor which we can use to inspect the selected sequence.
// Editors for Scriptable Objects display using the full height of the inspector window.
sequenceInspector = ScriptableObject.CreateInstance<SequenceInspector>() as SequenceInspector;
sequenceInspector.hideFlags = HideFlags.DontSave;
}
Vector2 newPosition = new Vector2(fungusScript.selectedSequence.nodeRect.position.x +
fungusScript.selectedSequence.nodeRect.width + 20,
fungusScript.selectedSequence.nodeRect.y);
Sequence oldSequence = fungusScript.selectedSequence;
Sequence newSequence = FungusScriptWindow.CreateSequence(fungusScript, newPosition);
newSequence.sequenceName = oldSequence.sequenceName + " (Copy)";
sequenceInspector.sequence = sequence;
foreach (Command command in oldSequence.commandList)
if (sequence != null)
{
System.Type type = command.GetType();
Command newCommand = Undo.AddComponent(fungusScript.gameObject, type) as Command;
System.Reflection.FieldInfo[] fields = type.GetFields();
foreach (System.Reflection.FieldInfo field in fields)
{
field.SetValue(newCommand, field.GetValue(command));
}
newSequence.commandList.Add(newCommand);
Selection.activeObject = sequenceInspector;
}
}
EditorUtility.SetDirty(sequenceInspector);
}
}
}

317
Assets/Fungus/FungusScript/Editor/SequenceEditor.cs

@ -19,30 +19,6 @@ namespace Fungus
public int index;
}
public virtual void DrawInspectorGUI(FungusScript fungusScript)
{
serializedObject.Update();
// We acquire the serialized properties in the draw methods instead of in OnEnable as otherwise
// deleting or renaming a command class would generate a bunch of null reference exceptions.
SerializedProperty sequenceNameProp = serializedObject.FindProperty("sequenceName");
EditorGUILayout.PropertyField(sequenceNameProp);
SerializedProperty nodeRectProp = serializedObject.FindProperty("nodeRect");
EditorGUI.BeginChangeCheck();
float width = EditorGUILayout.FloatField(new GUIContent("Node Width"), nodeRectProp.rectValue.width);
if (EditorGUI.EndChangeCheck())
{
Rect nodeRect = nodeRectProp.rectValue;
nodeRect.width = Mathf.Max(width, 100);
nodeRectProp.rectValue = nodeRect;
}
EditorGUILayout.Separator();
serializedObject.ApplyModifiedProperties();
}
public virtual void DrawCommandListGUI(FungusScript fungusScript)
{
serializedObject.Update();
@ -50,65 +26,45 @@ namespace Fungus
Sequence sequence = target as Sequence;
UpdateIndentLevels(sequence);
SerializedProperty sequenceNameProperty = serializedObject.FindProperty("sequenceName");
Rect sequenceLabelRect = new Rect(40, 5, 120, 16);
EditorGUI.LabelField(sequenceLabelRect, new GUIContent("Sequence Name"));
Rect sequenceNameRect = new Rect(40, 21, 180, 16);
EditorGUI.PropertyField(sequenceNameRect, sequenceNameProperty, new GUIContent(""));
SerializedProperty commandListProperty = serializedObject.FindProperty("commandList");
ReorderableListGUI.Title(sequence.sequenceName);
ReorderableListGUI.Title("Commands");
CommandListAdaptor adaptor = new CommandListAdaptor(commandListProperty, 0);
adaptor.nodeRect = sequence.nodeRect;
ReorderableListFlags flags = ReorderableListFlags.HideAddButton | ReorderableListFlags.HideRemoveButtons | ReorderableListFlags.DisableContextMenu;
ReorderableListControl.DrawControlFromState(adaptor, null, flags);
Rect bottomBoxRect = GUILayoutUtility.GetRect(sequence.nodeRect.width, 20);
bottomBoxRect.y -= 7;
bottomBoxRect.x += 5;
bottomBoxRect.width -= 10;
if (sequence.commandList.Count == 0)
if (!Application.isPlaying)
{
bottomBoxRect.y -= 16;
if (Event.current.type == EventType.ContextClick)
{
ShowContextMenu();
}
}
GUIStyle boxStyle = new GUIStyle();
boxStyle.border = new RectOffset(2, 2, 2, 1);
boxStyle.margin = new RectOffset(5, 5, 5, 0);
boxStyle.padding = new RectOffset(5, 5, 0, 0);
boxStyle.alignment = TextAnchor.MiddleLeft;
boxStyle.normal.background = FungusEditorResources.texTitleBackground;
boxStyle.normal.textColor = EditorGUIUtility.isProSkin
? new Color(0.8f, 0.8f, 0.8f)
: new Color(0.2f, 0.2f, 0.2f);
GUI.Box(bottomBoxRect, "", boxStyle);
if (!Application.isPlaying &&
sequence == fungusScript.selectedSequence)
{
// Show add command button
{
Rect plusRect = bottomBoxRect;
plusRect.x = plusRect.width - 19;
plusRect.y += 2;
plusRect.width = 16;
plusRect.height = 16;
GUILayout.BeginHorizontal();
if (GUI.Button(plusRect, FungusEditorResources.texAddButton, new GUIStyle()))
GUILayout.FlexibleSpace();
if (GUILayout.Button(FungusEditorResources.texAddButton))
{
ShowCommandMenu();
}
}
// Show delete sequence button
{
Rect deleteRect = new Rect();
deleteRect.x = sequence.nodeRect.width - 28;
deleteRect.y = 7;
deleteRect.width = 16;
deleteRect.height = 16;
if (GUI.Button(deleteRect, "", new GUIStyle("WinBtnCloseWin")))
{
FungusScriptWindow.DeleteSequence();
}
GUILayout.EndHorizontal();
}
}
@ -124,18 +80,6 @@ namespace Fungus
}
serializedObject.ApplyModifiedProperties();
if (!Application.isPlaying)
{
if (Event.current.button == 1 &&
Event.current.type == EventType.MouseDown)
{
// Set a flag to show the context menu on the new display frame
// This gives the sequence list display a chance to update
FungusScriptWindow.showContextMenu = true;
Event.current.Use();
}
}
}
protected virtual void UpdateIndentLevels(Sequence sequence)
@ -338,6 +282,231 @@ namespace Fungus
}
}
public void ShowContextMenu()
{
Sequence sequence = target as Sequence;
FungusScript fungusScript = sequence.GetFungusScript();
if (fungusScript == null)
{
return;
}
bool showCut = false;
bool showCopy = false;
bool showDelete = false;
bool showPaste = false;
if (fungusScript.selectedCommands.Count > 0)
{
showCut = true;
showCopy = true;
showDelete = true;
}
CommandCopyBuffer commandCopyBuffer = CommandCopyBuffer.GetInstance();
if (commandCopyBuffer.HasCommands())
{
showPaste = true;
}
GenericMenu commandMenu = new GenericMenu();
if (showCut)
{
commandMenu.AddItem (new GUIContent ("Cut"), false, Cut);
}
else
{
commandMenu.AddDisabledItem(new GUIContent ("Cut"));
}
if (showCopy)
{
commandMenu.AddItem (new GUIContent ("Copy"), false, Copy);
}
else
{
commandMenu.AddDisabledItem(new GUIContent ("Copy"));
}
if (showPaste)
{
commandMenu.AddItem (new GUIContent ("Paste"), false, Paste);
}
else
{
commandMenu.AddDisabledItem(new GUIContent ("Paste"));
}
if (showDelete)
{
commandMenu.AddItem (new GUIContent ("Delete"), false, Delete);
}
else
{
commandMenu.AddDisabledItem(new GUIContent ("Delete"));
}
commandMenu.AddSeparator("");
commandMenu.AddItem (new GUIContent ("Select All"), false, SelectAll);
commandMenu.AddItem (new GUIContent ("Select None"), false, SelectNone);
commandMenu.ShowAsContext();
}
protected void SelectAll()
{
Sequence sequence = target as Sequence;
FungusScript fungusScript = sequence.GetFungusScript();
if (fungusScript == null ||
fungusScript.selectedSequence == null)
{
return;
}
fungusScript.ClearSelectedCommands();
Undo.RecordObject(fungusScript, "Select All");
foreach (Command command in fungusScript.selectedSequence.commandList)
{
fungusScript.AddSelectedCommand(command);
}
Repaint();
}
protected void SelectNone()
{
Sequence sequence = target as Sequence;
FungusScript fungusScript = sequence.GetFungusScript();
if (fungusScript == null ||
fungusScript.selectedSequence == null)
{
return;
}
Undo.RecordObject(fungusScript, "Select None");
fungusScript.ClearSelectedCommands();
Repaint();
}
protected void Cut()
{
Copy();
Delete();
}
protected void Copy()
{
Sequence sequence = target as Sequence;
FungusScript fungusScript = sequence.GetFungusScript();
if (fungusScript == null ||
fungusScript.selectedSequence == null)
{
return;
}
CommandCopyBuffer commandCopyBuffer = CommandCopyBuffer.GetInstance();
commandCopyBuffer.Clear();
foreach (Command command in fungusScript.selectedCommands)
{
System.Type type = command.GetType();
Command newCommand = Undo.AddComponent(commandCopyBuffer.gameObject, type) as Command;
System.Reflection.FieldInfo[] fields = type.GetFields();
foreach (System.Reflection.FieldInfo field in fields)
{
field.SetValue(newCommand, field.GetValue(command));
}
}
}
protected void Paste()
{
Sequence sequence = target as Sequence;
FungusScript fungusScript = sequence.GetFungusScript();
if (fungusScript == null ||
fungusScript.selectedSequence == null)
{
return;
}
CommandCopyBuffer commandCopyBuffer = CommandCopyBuffer.GetInstance();
// Find where to paste commands in sequence (either at end or after last selected command)
int pasteIndex = fungusScript.selectedSequence.commandList.Count;
if (fungusScript.selectedCommands.Count > 0)
{
for (int i = 0; i < fungusScript.selectedSequence.commandList.Count; ++i)
{
Command command = fungusScript.selectedSequence.commandList[i];
foreach (Command selectedCommand in fungusScript.selectedCommands)
{
if (command == selectedCommand)
{
pasteIndex = i + 1;
}
}
}
}
foreach (Command command in commandCopyBuffer.GetCommands())
{
System.Type type = command.GetType();
Command newCommand = Undo.AddComponent(fungusScript.selectedSequence.gameObject, type) as Command;
System.Reflection.FieldInfo[] fields = type.GetFields();
foreach (System.Reflection.FieldInfo field in fields)
{
field.SetValue(newCommand, field.GetValue(command));
}
Undo.RecordObject(fungusScript.selectedSequence, "Paste");
fungusScript.selectedSequence.commandList.Insert(pasteIndex++, newCommand);
}
Repaint();
}
protected void Delete()
{
Sequence sequence = target as Sequence;
FungusScript fungusScript = sequence.GetFungusScript();
if (fungusScript == null ||
fungusScript.selectedSequence == null)
{
return;
}
for (int i = fungusScript.selectedSequence.commandList.Count - 1; i >= 0; --i)
{
Command command = fungusScript.selectedSequence.commandList[i];
foreach (Command selectedCommand in fungusScript.selectedCommands)
{
if (command == selectedCommand)
{
Undo.RecordObject(fungusScript.selectedSequence, "Delete");
fungusScript.selectedSequence.commandList.RemoveAt(i);
Undo.DestroyObjectImmediate(command);
break;
}
}
}
Undo.RecordObject(fungusScript, "Delete");
fungusScript.ClearSelectedCommands();
Repaint();
}
}
}

69
Assets/Fungus/FungusScript/Editor/SequenceInspector.cs

@ -0,0 +1,69 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace Fungus
{
/**
* Temp hidden object which lets us use the entire inspector window to inspect
* the sequence command list.
*/
public class SequenceInspector : ScriptableObject
{
public Sequence sequence;
}
/**
* Custom editor for the temp hidden object.
*/
[CustomEditor (typeof(SequenceInspector), true)]
public class SequenceInspectorEditor : Editor
{
public override void OnInspectorGUI ()
{
SequenceInspector t = target as SequenceInspector;
Sequence s = t.sequence;
if (s == null)
{
return;
}
FungusScript fungusScript = s.GetFungusScript();
SequenceEditor sequenceEditor = Editor.CreateEditor(s) as SequenceEditor;
sequenceEditor.DrawCommandListGUI(fungusScript);
DestroyImmediate(sequenceEditor);
Command inspectCommand = null;
if (Application.isPlaying &&
fungusScript.executingSequence != null)
{
inspectCommand = fungusScript.executingSequence.activeCommand;
}
else if (fungusScript.selectedCommands.Count == 1)
{
inspectCommand = fungusScript.selectedCommands[0];
}
if (Application.isPlaying &&
inspectCommand != null &&
inspectCommand.parentSequence != s)
{
Repaint();
return;
}
if (inspectCommand != null)
{
CommandEditor commandEditor = Editor.CreateEditor(inspectCommand) as CommandEditor;
commandEditor.DrawCommandInspectorGUI();
DestroyImmediate(commandEditor);
}
Repaint();
}
}
}

8
Assets/Fungus/FungusScript/Editor/SequenceInspector.cs.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 002913b6a2655480eb46221d14457062
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

14
Assets/Fungus/FungusScript/Scripts/FungusState.cs

@ -0,0 +1,14 @@
using UnityEngine;
using System.Collections;
namespace Fungus
{
// Used by the Fungus Script window to serialize the currently active Fungus Script object
// so that the same Fungus Script can be displayed while editing & playing.
public class FungusState : MonoBehaviour
{
public FungusScript selectedFungusScript;
}
}

8
Assets/Fungus/FungusScript/Scripts/FungusState.cs.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 61dddfdc5e0e44ca298d8f46f7f5a915
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

2
Assets/Fungus/FungusScript/Scripts/Node.cs

@ -6,7 +6,7 @@ namespace Fungus
public class Node : MonoBehaviour
{
public Rect nodeRect = new Rect(0, 0, 240, 20);
public Rect nodeRect = new Rect(0, 0, 120, 30);
}
}
Loading…
Cancel
Save