Browse Source

Merge branch 'snozbot/master'

master
Zach Vinless 8 years ago
parent
commit
bc898d978f
  1. 39
      Assets/Fungus/Scripts/Components/Flowchart.cs
  2. 6
      Assets/Fungus/Scripts/Editor/BlockInspector.cs
  3. 245
      Assets/Fungus/Scripts/Editor/FlowchartWindow.cs
  4. 32
      Docs/fungus_docs/coding_standard.md

39
Assets/Fungus/Scripts/Components/Flowchart.cs

@ -41,8 +41,7 @@ namespace Fungus
[SerializeField] protected Rect scrollViewRect; [SerializeField] protected Rect scrollViewRect;
[HideInInspector] [HideInInspector]
[FormerlySerializedAs("selectedSequence")] [SerializeField] protected List<Block> selectedBlocks = new List<Block>();
[SerializeField] protected Block selectedBlock;
[HideInInspector] [HideInInspector]
[SerializeField] protected List<Command> selectedCommands = new List<Command>(); [SerializeField] protected List<Command> selectedCommands = new List<Command>();
@ -325,9 +324,22 @@ namespace Fungus
public virtual Rect ScrollViewRect { get { return scrollViewRect; } set { scrollViewRect = value; } } public virtual Rect ScrollViewRect { get { return scrollViewRect; } set { scrollViewRect = value; } }
/// <summary> /// <summary>
/// Currently selected block in the Flowchart editor. /// Current actively selected block in the Flowchart editor.
/// </summary> /// </summary>
public virtual Block SelectedBlock { get { return selectedBlock; } set { selectedBlock = value; } } public virtual Block SelectedBlock
{
get
{
return selectedBlocks.FirstOrDefault();
}
set
{
selectedBlocks.Clear();
selectedBlocks.Add(value);
}
}
public virtual List<Block> SelectedBlocks { get { return selectedBlocks; } set { selectedBlocks = value; } }
/// <summary> /// <summary>
/// Currently selected command in the Flowchart editor. /// Currently selected command in the Flowchart editor.
@ -1040,6 +1052,25 @@ namespace Fungus
} }
} }
/// <summary>
/// Clears the list of selected blocks.
/// </summary>
public virtual void ClearSelectedBlocks()
{
selectedBlocks.Clear();
}
/// <summary>
/// Adds a block to the list of selected blocks.
/// </summary>
public virtual void AddSelectedBlock(Block block)
{
if (!selectedBlocks.Contains(block))
{
selectedBlocks.Add(block);
}
}
/// <summary> /// <summary>
/// Reset the commands and variables in the Flowchart. /// Reset the commands and variables in the Flowchart.
/// </summary> /// </summary>

6
Assets/Fungus/Scripts/Editor/BlockInspector.cs

@ -83,6 +83,12 @@ namespace Fungus.EditorUtils
var flowchart = (Flowchart)block.GetFlowchart(); var flowchart = (Flowchart)block.GetFlowchart();
if (flowchart.SelectedBlocks.Count > 1)
{
GUILayout.Label("Multiple blocks selected");
return;
}
if (activeBlockEditor == null || if (activeBlockEditor == null ||
!block.Equals(activeBlockEditor.target)) !block.Equals(activeBlockEditor.target))
{ {

245
Assets/Fungus/Scripts/Editor/FlowchartWindow.cs

@ -34,6 +34,10 @@ namespace Fungus.EditorUtils
protected Texture2D addTexture; protected Texture2D addTexture;
protected Rect selectionBox;
protected Vector2 startSelectionBoxPosition = new Vector2(-1.0f, -1.0f);
protected List<Block> mouseDownSelectionState = new List<Block>();
[MenuItem("Tools/Fungus/Flowchart Window")] [MenuItem("Tools/Fungus/Flowchart Window")]
static void Init() static void Init()
{ {
@ -120,7 +124,7 @@ namespace Fungus.EditorUtils
// Delete any scheduled objects // Delete any scheduled objects
foreach (var deleteBlock in deleteList) foreach (var deleteBlock in deleteList)
{ {
bool isSelected = (flowchart.SelectedBlock == deleteBlock); bool isSelected = (flowchart.SelectedBlocks.Contains(deleteBlock));
var commandList = deleteBlock.CommandList; var commandList = deleteBlock.CommandList;
foreach (var command in commandList) foreach (var command in commandList)
@ -142,6 +146,9 @@ namespace Fungus.EditorUtils
DrawFlowchartView(flowchart); DrawFlowchartView(flowchart);
DrawOverlay(flowchart); DrawOverlay(flowchart);
// Handle selection box events after block and overlay events
HandleSelectionBox(flowchart);
if (forceRepaintCount > 0) if (forceRepaintCount > 0)
{ {
// Redraw on next frame to get crisp refresh rate // Redraw on next frame to get crisp refresh rate
@ -166,7 +173,8 @@ namespace Fungus.EditorUtils
GUILayout.Space(8); GUILayout.Space(8);
flowchart.Zoom = GUILayout.HorizontalSlider(flowchart.Zoom, minZoomValue, maxZoomValue, GUILayout.Width(100)); var newZoom = GUILayout.HorizontalSlider(flowchart.Zoom, minZoomValue, maxZoomValue, GUILayout.Width(100));
DoZoom(flowchart, newZoom - flowchart.Zoom, Vector2.one * 0.5f);
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
@ -248,18 +256,6 @@ namespace Fungus.EditorUtils
GLDraw.BeginGroup(scriptViewRect); GLDraw.BeginGroup(scriptViewRect);
if (Event.current.button == 0 &&
Event.current.type == EventType.MouseDown &&
!mouseOverVariables)
{
flowchart.SelectedBlock = null;
if (!EditorGUI.actionKey)
{
flowchart.ClearSelectedCommands();
}
Selection.activeGameObject = flowchart.gameObject;
}
// The center of the Flowchart depends on the block positions and window dimensions, so we calculate it // 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. // here in the FlowchartWindow class and store it on the Flowchart object for use later.
CalcFlowchartCenter(flowchart, blocks); CalcFlowchartCenter(flowchart, blocks);
@ -280,6 +276,8 @@ namespace Fungus.EditorUtils
BeginWindows(); BeginWindows();
windowBlockMap.Clear(); windowBlockMap.Clear();
bool useEvent = false;
bool endDrag = false;
for (int i = 0; i < blocks.Length; ++i) for (int i = 0; i < blocks.Length; ++i)
{ {
var block = blocks[i]; var block = blocks[i];
@ -297,28 +295,33 @@ namespace Fungus.EditorUtils
tempRect.width = Mathf.Max(Mathf.Max(nodeWidthA, nodeWidthB), 120); tempRect.width = Mathf.Max(Mathf.Max(nodeWidthA, nodeWidthB), 120);
tempRect.height = 40; tempRect.height = 40;
if (Event.current.type == EventType.MouseDrag && dragWindowId == i) if (dragWindowId > -1 && flowchart.SelectedBlocks.Contains(block))
{
if (Event.current.type == EventType.MouseDrag)
{ {
tempRect.x += Event.current.delta.x; tempRect.x += Event.current.delta.x;
tempRect.y += Event.current.delta.y; tempRect.y += Event.current.delta.y;
forceRepaintCount = 6; forceRepaintCount = 6;
useEvent = true;
} }
else if (Event.current.type == EventType.MouseUp && else if (Event.current.rawType == EventType.MouseUp)
dragWindowId == i)
{ {
Vector2 newPos = new Vector2(tempRect.x, tempRect.y); 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);
tempRect.x = startDragPosition.x; block._NodeRect = tempRect;
tempRect.y = startDragPosition.y;
Undo.RecordObject((Block)block, "Node Position"); Undo.RecordObject(block, "Node Position");
tempRect.x = newPos.x; tempRect.x = newPos.x;
tempRect.y = newPos.y; tempRect.y = newPos.y;
dragWindowId = -1;
forceRepaintCount = 6; forceRepaintCount = 6;
useEvent = true;
endDrag = true;
}
} }
block._NodeRect = tempRect; block._NodeRect = tempRect;
@ -335,6 +338,13 @@ namespace Fungus.EditorUtils
windowBlockMap.Add(block); windowBlockMap.Add(block);
} }
dragWindowId = endDrag ? -1 : dragWindowId;
if (useEvent)
{
Event.current.Use();
}
EndWindows(); EndWindows();
// Draw Event Handler labels // Draw Event Handler labels
@ -407,6 +417,23 @@ namespace Fungus.EditorUtils
GLDraw.EndGroup(); GLDraw.EndGroup();
EditorZoomArea.End(); EditorZoomArea.End();
// If event has yet to be used and user isn't multiselecting or panning, clear selection
bool validModifier = Event.current.alt || GetAppendModifierDown();
if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && !validModifier)
{
Undo.RecordObject(flowchart, "Deselect");
flowchart.ClearSelectedCommands();
flowchart.ClearSelectedBlocks();
Selection.activeGameObject = flowchart.gameObject;
}
// Draw selection box
if (startSelectionBoxPosition.x >= 0 && startSelectionBoxPosition.y >= 0)
{
GUI.Box(selectionBox, "", (GUIStyle) "SelectionRect");
forceRepaintCount = 6;
}
} }
public virtual void CalcFlowchartCenter(Flowchart flowchart, Block[] blocks) public virtual void CalcFlowchartCenter(Flowchart flowchart, Block[] blocks)
@ -436,6 +463,77 @@ namespace Fungus.EditorUtils
flowchart.CenterPosition = center; 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:
startSelectionBoxPosition = Event.current.mousePosition;
mouseDownSelectionState = new List<Block>(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<Block>())
{
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 * -1;
startSelectionBoxPosition = selectionBox.position;
var tempList = new List<Block>(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 PanAndZoom(Flowchart flowchart)
{ {
// Right click to drag view // Right click to drag view
@ -482,13 +580,27 @@ namespace Fungus.EditorUtils
zoom = true; zoom = true;
} }
if (zoom) if (zoom && selectionBox.size == Vector2.zero)
{ {
flowchart.Zoom -= Event.current.delta.y * 0.01f; Vector2 zoomCenter;
zoomCenter.x = Event.current.mousePosition.x / position.width;
zoomCenter.y = Event.current.mousePosition.y / position.height;
zoomCenter *= flowchart.Zoom;
DoZoom(flowchart, -Event.current.delta.y * 0.01f, zoomCenter);
}
}
protected virtual void DoZoom(Flowchart flowchart, float delta, Vector2 center)
{
var prevZoom = flowchart.Zoom;
flowchart.Zoom += delta;
flowchart.Zoom = Mathf.Clamp(flowchart.Zoom, minZoomValue, maxZoomValue); flowchart.Zoom = Mathf.Clamp(flowchart.Zoom, minZoomValue, maxZoomValue);
var deltaSize = position.size / prevZoom - position.size / flowchart.Zoom;
var offset = -Vector2.Scale(deltaSize, center);
flowchart.ScrollPos += offset;
forceRepaintCount = 6; forceRepaintCount = 6;
} }
}
protected virtual void DrawGrid(Flowchart flowchart) protected virtual void DrawGrid(Flowchart flowchart)
{ {
@ -532,22 +644,18 @@ namespace Fungus.EditorUtils
protected virtual void SelectBlock(Flowchart flowchart, Block block) protected virtual void SelectBlock(Flowchart flowchart, Block block)
{ {
// Select the block and also select currently executing command // Select the block and also select currently executing command
ShowBlockInspector(flowchart);
flowchart.SelectedBlock = block; flowchart.SelectedBlock = block;
flowchart.ClearSelectedCommands(); SetBlockForInspector(flowchart, block);
if (block.ActiveCommand != null)
{
flowchart.AddSelectedCommand(block.ActiveCommand);
}
} }
public static Block CreateBlock(Flowchart flowchart, Vector2 position) public static Block CreateBlock(Flowchart flowchart, Vector2 position)
{ {
Block newBlock = flowchart.CreateBlock(position); Block newBlock = flowchart.CreateBlock(position);
Undo.RegisterCreatedObjectUndo(newBlock, "New Block"); Undo.RegisterCreatedObjectUndo(newBlock, "New Block");
ShowBlockInspector(flowchart);
flowchart.SelectedBlock = newBlock; // Use AddSelected instead of Select for when multiple blocks are duplicated
flowchart.ClearSelectedCommands(); flowchart.AddSelectedBlock(newBlock);
SetBlockForInspector(flowchart, newBlock);
return newBlock; return newBlock;
} }
@ -582,6 +690,8 @@ namespace Fungus.EditorUtils
// Check if might be start of a window drag // Check if might be start of a window drag
if (Event.current.button == 0 && if (Event.current.button == 0 &&
Event.current.alt == false) Event.current.alt == false)
{
if (!GetAppendModifierDown())
{ {
dragWindowId = windowId; dragWindowId = windowId;
@ -589,19 +699,42 @@ namespace Fungus.EditorUtils
startDragPosition.y = block._NodeRect.y; startDragPosition.y = block._NodeRect.y;
} }
Event.current.Use();
}
if (windowId < windowBlockMap.Count) if (windowId < windowBlockMap.Count)
{ {
Undo.RecordObject(flowchart, "Select"); 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); SelectBlock(flowchart, block);
}
}
GUIUtility.keyboardControl = 0; // Fix for textarea not refeshing (change focus) GUIUtility.keyboardControl = 0; // Fix for textarea not refeshing (change focus)
} }
} }
bool selected = false; bool selected = false;
if (flowchart.SelectedBlock != null && if (flowchart.SelectedBlocks.Contains(block))
flowchart.SelectedBlock.Equals(block))
{ {
selected = true; selected = true;
} }
@ -670,7 +803,7 @@ namespace Fungus.EditorUtils
nodeStyleCopy.normal.background = offTex; nodeStyleCopy.normal.background = offTex;
GUI.backgroundColor = tintColor; GUI.backgroundColor = tintColor;
GUI.Box(GUILayoutUtility.GetLastRect(), block.BlockName, nodeStyleCopy); GUI.Box(boxRect, block.BlockName, nodeStyleCopy);
GUI.backgroundColor = Color.white; GUI.backgroundColor = Color.white;
@ -683,10 +816,14 @@ namespace Fungus.EditorUtils
if (Event.current.type == EventType.ContextClick) if (Event.current.type == EventType.ContextClick)
{ {
flowchart.AddSelectedBlock(block);
GenericMenu menu = new GenericMenu (); GenericMenu menu = new GenericMenu ();
menu.AddItem(new GUIContent ("Duplicate"), false, DuplicateBlock, block); // Use a copy because flowchart.SelectedBlocks gets modified
menu.AddItem(new GUIContent ("Delete"), false, DeleteBlock, block); var blockList = new List<Block>(flowchart.SelectedBlocks);
menu.AddItem(new GUIContent ("Duplicate"), false, DuplicateBlocks, blockList);
menu.AddItem(new GUIContent ("Delete"), false, DeleteBlocks, blockList);
menu.ShowAsContext(); menu.ShowAsContext();
} }
@ -804,17 +941,23 @@ namespace Fungus.EditorUtils
GUI.Label(dotBRect, "", new GUIStyle("U2D.dragDotActive")); GUI.Label(dotBRect, "", new GUIStyle("U2D.dragDotActive"));
} }
public static void DeleteBlock(object obj) public static void DeleteBlocks(object obj)
{ {
var block = obj as Block; var blocks = obj as List<Block>;
FlowchartWindow.deleteList.Add(block); blocks.ForEach(block => FlowchartWindow.deleteList.Add(block));
} }
protected static void DuplicateBlock(object obj) protected static void DuplicateBlocks(object obj)
{ {
var flowchart = GetFlowchart(); var flowchart = GetFlowchart();
Block block = obj as Block;
Undo.RecordObject(flowchart, "Select");
flowchart.ClearSelectedBlocks();
var blocks = obj as List<Block>;
foreach (var block in blocks)
{
Vector2 newPosition = new Vector2(block._NodeRect.position.x + Vector2 newPosition = new Vector2(block._NodeRect.position.x +
block._NodeRect.width + 20, block._NodeRect.width + 20,
block._NodeRect.y); block._NodeRect.y);
@ -864,6 +1007,7 @@ namespace Fungus.EditorUtils
} }
} }
} }
}
protected static void ShowBlockInspector(Flowchart flowchart) protected static void ShowBlockInspector(Flowchart flowchart)
{ {
@ -880,6 +1024,16 @@ namespace Fungus.EditorUtils
EditorUtility.SetDirty(blockInspector); EditorUtility.SetDirty(blockInspector);
} }
protected static void SetBlockForInspector(Flowchart flowchart, Block block)
{
ShowBlockInspector(flowchart);
flowchart.ClearSelectedCommands();
if (block.ActiveCommand != null)
{
flowchart.AddSelectedCommand(block.ActiveCommand);
}
}
/// <summary> /// <summary>
/// Displays a temporary text alert in the center of the Flowchart window. /// Displays a temporary text alert in the center of the Flowchart window.
/// </summary> /// </summary>
@ -891,5 +1045,10 @@ namespace Fungus.EditorUtils
window.ShowNotification(new GUIContent(notificationText)); window.ShowNotification(new GUIContent(notificationText));
} }
} }
protected virtual bool GetAppendModifierDown()
{
return Event.current.shift || EditorGUI.actionKey;
}
} }
} }

32
Docs/fungus_docs/coding_standard.md

@ -51,7 +51,7 @@ namespace Fungus
Things to note: Things to note:
- using declarations all go together at the top of the file. - using declarations all go together at the top of the file.
- You should remove any unused using declarations (can spot these easily with static code analysis - see below). - Remove any unused using declarations (can spot these easily with static code analysis - see below).
- Runtime code goes in the Fungus namespace. - Runtime code goes in the Fungus namespace.
- Editor code goes in the Fungus.EditorUtils namespace. - Editor code goes in the Fungus.EditorUtils namespace.
- All public classes, structs, enums and class members should be documented using xml comments. - All public classes, structs, enums and class members should be documented using xml comments.
@ -78,4 +78,32 @@ These are some general best practices when writing code for %Fungus. Where these
- Use Mathf.Approximately when comparing float variables to constants. - Use Mathf.Approximately when comparing float variables to constants.
- Treat compiler warnings as errors. There should be zero warnings at build or runtime in normal operation. - Treat compiler warnings as errors. There should be zero warnings at build or runtime in normal operation.
- Add global constants to FungusConstants.cs - Add global constants to FungusConstants.cs
- Always try to maintain backwards compatibility when introducing changes. We support Unity 5.0+ so beware of API differences in newer versions.
# Backwards compatibility # {#backwards_compatibility}
We aim to maintain backwards compatibility with each new release (to a reasonable extent).
- Projects should work correctly after upgrading to a newer %Fungus version. Minor behavior changes are acceptable.
- Custom code which uses the %Fungus API should compile without error after upgrading. Minor compile errors that are trivial to fix are sometimes acceptable.
- There are loads of %Fungus tutorial videos and articles on the Internet, so avoid changing the UI too dramatically. Small UI tweaks and adding new controls is acceptable.
- We support Unity 5.0+ so beware of API differences in newer versions. If in doubt, install Unity 5.0 and test your changes.
# Contributing # {#contributing}
We welcome pull requests from everyone. By contributing to this project, you agree to abide by the @ref code_of_conduct. You also agree that by submitting a pull request for this project, your contribution will be licensed under the [Open Source license] for this project.
- Fork and clone the %Fungus repo.
- Make sure the tests pass locally (see the project readme for instructions).
- Make your change. Add tests for your change. Make the tests pass locally.
- Push to your fork and submit a pull request.
Your pull request will have a better chance of being accepted if you do the following:
- Send one pull request for each new feature / bug fix. It's time consuming to review multi-feature changes and we won't merge a change unless we know exactly what it does.
- Write tests for each change / new feature (not always possible)
- Follow our coding standard (see above)
- Write a [good commit message][commit].
[commit]: http://chris.beams.io/posts/git-commit/
[fork a repo]: https://help.github.com/articles/fork-a-repo/
[Open Source license]: https://github.com/snozbot/Fungus/blob/master/LICENSE

Loading…
Cancel
Save