Browse Source

Merge pull request #619 from stevehalliwell/CommandByName

Command by name
master
Chris Gregan 8 years ago committed by GitHub
parent
commit
00a2c23400
  1. 193
      Assets/Fungus/Scripts/Editor/BlockEditor.cs

193
Assets/Fungus/Scripts/Editor/BlockEditor.cs

@ -26,11 +26,14 @@ namespace Fungus.EditorUtils
protected class AddCommandOperation protected class AddCommandOperation
{ {
public Block block;
public Type commandType; public Type commandType;
public int index;
} }
private static readonly char[] SPLIT_INPUT_ON = new char[] { ' ', '/', '\\' };
private static readonly int MAX_PREVIEW_GRID = 7;
private static readonly string ELIPSIS = "...";
public static List<Action> actionList = new List<Action>(); public static List<Action> actionList = new List<Action>();
protected Texture2D upIcon; protected Texture2D upIcon;
@ -39,6 +42,10 @@ namespace Fungus.EditorUtils
protected Texture2D duplicateIcon; protected Texture2D duplicateIcon;
protected Texture2D deleteIcon; protected Texture2D deleteIcon;
protected string commandTextFieldContents = string.Empty;
protected int filteredCommandPreviewSelectedItem = 0;
protected Type commandSelectedByTextInput;
static List<System.Type> commandTypes; static List<System.Type> commandTypes;
static List<System.Type> eventHandlerTypes; static List<System.Type> eventHandlerTypes;
@ -280,6 +287,33 @@ namespace Fungus.EditorUtils
{ {
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
//handle movement along our selection grid before something else eats our inputs
if (Event.current.type == EventType.keyDown)
{
//up down to change selection / esc to clear field
if (Event.current.keyCode == KeyCode.UpArrow)
{
filteredCommandPreviewSelectedItem--;
}
else if (Event.current.keyCode == KeyCode.DownArrow)
{
filteredCommandPreviewSelectedItem++;
}
if (commandSelectedByTextInput != null &&
Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter)
{
AddCommandCallback(commandSelectedByTextInput);
commandSelectedByTextInput = null;
commandTextFieldContents = String.Empty;
//GUI.FocusControl("dummycontrol");
Event.current.Use();
filteredCommandPreviewSelectedItem = 0;
}
}
// Previous Command // Previous Command
if ((Event.current.type == EventType.keyDown) && (Event.current.keyCode == KeyCode.PageUp)) if ((Event.current.type == EventType.keyDown) && (Event.current.keyCode == KeyCode.PageUp))
{ {
@ -308,6 +342,9 @@ namespace Fungus.EditorUtils
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
//should track if text actually changes and pass that to the ShowPartialMatches so it can cache
commandTextFieldContents = GUILayout.TextField(commandTextFieldContents, GUILayout.MinWidth(20), GUILayout.MaxWidth(200));
// Add Button // Add Button
if (GUILayout.Button(addIcon)) if (GUILayout.Button(addIcon))
{ {
@ -328,6 +365,85 @@ namespace Fungus.EditorUtils
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
if (!string.IsNullOrEmpty(commandTextFieldContents))
ShowPartialMatches();
}
//Handles showing partial matches against the text input next to the AddCommand button
// Splits and matches and can use up down arrows and return/enter/numenter to confirm
// TODO add sorting of results so we get best match at the not just just a match
// e.g. "if" should show Flow/If at the top not Flow/Else If
private void ShowPartialMatches()
{
var block = target as Block;
var flowchart = (Flowchart)block.GetFlowchart();
//TODO this could be cached if input hasn't changed to avoid thrashing
var filteredAttributes = GetFilteredSupportedCommands(flowchart);
var upperCommandText = commandTextFieldContents.ToUpper().Trim();
if (upperCommandText.Length == 0)
return;
var tokens = upperCommandText.Split(SPLIT_INPUT_ON);
//we want commands that have all the elements you have typed
filteredAttributes = filteredAttributes.Where((x) =>
{
bool catAny = tokens.Any(x.Value.Category.ToUpper().Contains);
bool comAny = tokens.Any(x.Value.CommandName.ToUpper().Contains);
bool catAll = tokens.All(x.Value.Category.ToUpper().Contains);
bool comAll = tokens.All(x.Value.CommandName.ToUpper().Contains);
//so if both category and command found something, then there are multiple tokens and they line up with category and command
if (catAny && comAny)
return true;
//or its a single token or a complex token that matches entirely in cat or com
else if (catAll || comAll)
return true;
//this setup avoids multiple bad suggestions due to a complex category name that gives many false matches on complex partials
return false;
}).ToList();
if (filteredAttributes == null || filteredAttributes.Count == 0)
return;
//show results
GUILayout.Space(5);
GUILayout.BeginHorizontal();
filteredCommandPreviewSelectedItem = Mathf.Clamp(filteredCommandPreviewSelectedItem, 0, filteredAttributes.Count - 1);
var toShow = filteredAttributes.Select(x => x.Value.Category + "/" + x.Value.CommandName).ToArray();
//show the first x max that match our filters
if(toShow.Length > MAX_PREVIEW_GRID)
{
toShow = toShow.Take(MAX_PREVIEW_GRID).ToArray();
toShow[MAX_PREVIEW_GRID - 1] = ELIPSIS;
}
filteredCommandPreviewSelectedItem = GUILayout.SelectionGrid(filteredCommandPreviewSelectedItem, toShow, 1);
if (toShow[filteredCommandPreviewSelectedItem] != ELIPSIS)
{
commandSelectedByTextInput = filteredAttributes[filteredCommandPreviewSelectedItem].Key;
}
else
{
commandSelectedByTextInput = null;
}
GUILayout.EndHorizontal();
GUILayout.Space(5);
} }
protected virtual void DrawEventHandlerGUI(Flowchart flowchart) protected virtual void DrawEventHandlerGUI(Flowchart flowchart)
@ -665,40 +781,16 @@ namespace Fungus.EditorUtils
var flowchart = (Flowchart)block.GetFlowchart(); var flowchart = (Flowchart)block.GetFlowchart();
// Use index of last selected command in list, or end of list if nothing selected.
int index = -1;
foreach (var command in flowchart.SelectedCommands)
{
if (command.CommandIndex + 1 > index)
{
index = command.CommandIndex + 1;
}
}
if (index == -1)
{
index = block.CommandList.Count;
}
GenericMenu commandMenu = new GenericMenu(); GenericMenu commandMenu = new GenericMenu();
// Build menu list // Build menu list
List<KeyValuePair<System.Type, CommandInfoAttribute>> filteredAttributes = GetFilteredCommandInfoAttribute(commandTypes); var filteredAttributes = GetFilteredSupportedCommands(flowchart);
filteredAttributes.Sort( CompareCommandAttributes );
foreach (var keyPair in filteredAttributes) foreach (var keyPair in filteredAttributes)
{ {
// Skip command type if the Flowchart doesn't support it
if (!flowchart.IsCommandSupported(keyPair.Value))
{
continue;
}
AddCommandOperation commandOperation = new AddCommandOperation(); AddCommandOperation commandOperation = new AddCommandOperation();
commandOperation.block = block;
commandOperation.commandType = keyPair.Key; commandOperation.commandType = keyPair.Key;
commandOperation.index = index;
GUIContent menuItem; GUIContent menuItem;
if (keyPair.Value.Category == "") if (keyPair.Value.Category == "")
@ -716,6 +808,17 @@ namespace Fungus.EditorUtils
commandMenu.ShowAsContext(); commandMenu.ShowAsContext();
} }
protected static List<KeyValuePair<System.Type, CommandInfoAttribute>> GetFilteredSupportedCommands(Flowchart flowchart)
{
List<KeyValuePair<System.Type, CommandInfoAttribute>> filteredAttributes = GetFilteredCommandInfoAttribute(commandTypes);
filteredAttributes.Sort(CompareCommandAttributes);
filteredAttributes = filteredAttributes.Where(x => flowchart.IsCommandSupported(x.Value)).ToList();
return filteredAttributes;
}
protected static List<KeyValuePair<System.Type, CommandInfoAttribute>> GetFilteredCommandInfoAttribute(List<System.Type> menuTypes) protected static List<KeyValuePair<System.Type, CommandInfoAttribute>> GetFilteredCommandInfoAttribute(List<System.Type> menuTypes)
{ {
Dictionary<string, KeyValuePair<System.Type, CommandInfoAttribute>> filteredAttributes = new Dictionary<string, KeyValuePair<System.Type, CommandInfoAttribute>>(); Dictionary<string, KeyValuePair<System.Type, CommandInfoAttribute>> filteredAttributes = new Dictionary<string, KeyValuePair<System.Type, CommandInfoAttribute>>();
@ -747,11 +850,19 @@ namespace Fungus.EditorUtils
return filteredAttributes.Values.ToList<KeyValuePair<System.Type, CommandInfoAttribute>>(); return filteredAttributes.Values.ToList<KeyValuePair<System.Type, CommandInfoAttribute>>();
} }
protected static void AddCommandCallback(object obj) //Used by GenericMenu Delegate
protected void AddCommandCallback(object obj)
{ {
AddCommandOperation commandOperation = obj as AddCommandOperation; AddCommandOperation commandOperation = obj as AddCommandOperation;
if (commandOperation != null)
{
AddCommandCallback(commandOperation.commandType);
}
}
var block = commandOperation.block; protected void AddCommandCallback(Type commandType)
{
var block = target as Block;
if (block == null) if (block == null)
{ {
return; return;
@ -759,9 +870,21 @@ namespace Fungus.EditorUtils
var flowchart = (Flowchart)block.GetFlowchart(); var flowchart = (Flowchart)block.GetFlowchart();
flowchart.ClearSelectedCommands(); // Use index of last selected command in list, or end of list if nothing selected.
int index = -1;
foreach (var command in flowchart.SelectedCommands)
{
if (command.CommandIndex + 1 > index)
{
index = command.CommandIndex + 1;
}
}
if (index == -1)
{
index = block.CommandList.Count;
}
var newCommand = Undo.AddComponent(block.gameObject, commandOperation.commandType) as Command; var newCommand = Undo.AddComponent(block.gameObject, commandType) as Command;
block.GetFlowchart().AddSelectedCommand(newCommand); block.GetFlowchart().AddSelectedCommand(newCommand);
newCommand.ParentBlock = block; newCommand.ParentBlock = block;
newCommand.ItemId = flowchart.NextItemId(); newCommand.ItemId = flowchart.NextItemId();
@ -770,9 +893,9 @@ namespace Fungus.EditorUtils
newCommand.OnCommandAdded(block); newCommand.OnCommandAdded(block);
Undo.RecordObject(block, "Set command type"); Undo.RecordObject(block, "Set command type");
if (commandOperation.index < block.CommandList.Count - 1) if (index < block.CommandList.Count - 1)
{ {
block.CommandList.Insert(commandOperation.index, newCommand); block.CommandList.Insert(index, newCommand);
} }
else else
{ {
@ -781,6 +904,10 @@ namespace Fungus.EditorUtils
// Because this is an async call, we need to force prefab instances to record changes // Because this is an async call, we need to force prefab instances to record changes
PrefabUtility.RecordPrefabInstancePropertyModifications(block); PrefabUtility.RecordPrefabInstancePropertyModifications(block);
flowchart.ClearSelectedCommands();
commandTextFieldContents = string.Empty;
} }
public virtual void ShowContextMenu() public virtual void ShowContextMenu()

Loading…
Cancel
Save