Browse Source

Refactor popup window content to a common base

CommandMenu has popup selector and fallback to original in double click
master
desktop-maesty/steve 7 years ago
parent
commit
073c8937ed
  1. 241
      Assets/Fungus/Scripts/Editor/BasePopupWindowContent.cs
  2. 11
      Assets/Fungus/Scripts/Editor/BasePopupWindowContent.cs.meta
  3. 14
      Assets/Fungus/Scripts/Editor/BlockEditor.cs
  4. 176
      Assets/Fungus/Scripts/Editor/CommandSelectorPopupWindowContent.cs
  5. 235
      Assets/Fungus/Scripts/Editor/EventSelectorPopupWindowContent.cs

241
Assets/Fungus/Scripts/Editor/BasePopupWindowContent.cs

@ -0,0 +1,241 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Fungus.EditorUtils
{
/// <summary>
/// Common base for PopupWindowContent that is a search filterable list a la AddComponent
///
/// Inspired by https://github.com/roboryantron/UnityEditorJunkie/blob/master/Assets/SearchableEnum/Code/Editor/SearchablePopup.cs
/// </summary>
public abstract class BasePopupWindowContent : PopupWindowContent
{
/// <summary>
/// Called when the user has confirmed an item from the menu.
/// </summary>
/// <param name="index">Index of into the original list of items to show given to the popupcontent</param>
abstract protected void SelectByOrigIndex(int index);
/// <summary>
/// Called during Base Ctor, so that all
/// </summary>
abstract protected void PrepareAllItems();
public class FilteredListItem
{
public FilteredListItem(int index, string str)
{
origIndex = index;
name = str;
lowerName = str.ToLowerInvariant();
}
public int origIndex;
public string name, lowerName;
}
protected Block block;
protected int hoverIndex;
protected readonly string SEARCH_CONTROL_NAME = "PopupSearchControlName";
protected readonly float ROW_HEIGHT = EditorGUIUtility.singleLineHeight;
protected List<FilteredListItem> allItems = new List<FilteredListItem>(), visibleItems = new List<FilteredListItem>();
protected string currentFilter = string.Empty;
protected Vector2 scroll;
protected int scrollToIndex;
protected float scrollOffset;
protected int currentIndex;
protected Vector2 size;
static readonly char[] SEARCH_SPLITS = new char[]{ '/', ' ' };
public BasePopupWindowContent(string currentHandlerName, Block block, int width, int height)
{
this.block = block;
this.size = new Vector2(width, height);
PrepareAllItems();
allItems.Sort((lhs, rhs) => lhs.name.CompareTo(rhs.name));
UpdateFilter();
currentIndex = Mathf.Max(0, visibleItems.FindIndex(x=>x.name.Contains(currentHandlerName)));
}
public override void OnGUI(Rect rect)
{
Rect searchRect = new Rect(0, 0, rect.width, EditorStyles.toolbar.fixedHeight);
Rect scrollRect = Rect.MinMaxRect(0, searchRect.yMax, rect.xMax, rect.yMax);
HandleKeyboard();
DrawSearch(searchRect);
DrawSelectionArea(scrollRect);
}
public override Vector2 GetWindowSize()
{
return size;
}
private void DrawSearch(Rect rect)
{
if (Event.current.type == EventType.Repaint)
EditorStyles.toolbar.Draw(rect, false, false, false, false);
Rect searchRect = new Rect(rect);
searchRect.xMin += 6;
searchRect.xMax -= 6;
searchRect.y += 2;
GUI.FocusControl(SEARCH_CONTROL_NAME);
GUI.SetNextControlName(SEARCH_CONTROL_NAME);
var prevFilter = currentFilter;
currentFilter = GUI.TextField(searchRect, currentFilter);
if (prevFilter != currentFilter)
{
UpdateFilter();
}
}
private void UpdateFilter()
{
var curlower = currentFilter.ToLowerInvariant();
var lowers = curlower.Split(SEARCH_SPLITS);
lowers = lowers.Where(x => x.Length > 0).ToArray();
if (lowers == null || lowers.Length == 0)
{
visibleItems.AddRange(allItems);
}
else
{
visibleItems = allItems.Where(x =>
{
foreach (var item in lowers)
{
if (x.lowerName.Contains(currentFilter))
return true;
}
return false;
}).ToList();
}
hoverIndex = 0;
scroll = Vector2.zero;
visibleItems.Insert(0, new FilteredListItem(-1, "None"));
}
private void DrawSelectionArea(Rect scrollRect)
{
Rect contentRect = new Rect(0, 0,
scrollRect.width - GUI.skin.verticalScrollbar.fixedWidth,
visibleItems.Count * ROW_HEIGHT);
scroll = GUI.BeginScrollView(scrollRect, scroll, contentRect);
Rect rowRect = new Rect(0, 0, scrollRect.width, ROW_HEIGHT);
for (int i = 0; i < visibleItems.Count; i++)
{
if (scrollToIndex == i &&
(Event.current.type == EventType.Repaint
|| Event.current.type == EventType.Layout))
{
Rect r = new Rect(rowRect);
r.y += scrollOffset;
GUI.ScrollTo(r);
scrollToIndex = -1;
scroll.x = 0;
}
if (rowRect.Contains(Event.current.mousePosition))
{
if (Event.current.type == EventType.MouseMove ||
Event.current.type == EventType.ScrollWheel)
hoverIndex = i;
if (Event.current.type == EventType.MouseDown)
{
//onSelectionMade(list.Entries[i].Index);
SelectByOrigIndex(visibleItems[i].origIndex);
EditorWindow.focusedWindow.Close();
}
}
DrawRow(rowRect, i);
rowRect.y = rowRect.yMax;
}
GUI.EndScrollView();
}
private static void DrawBox(Rect rect, Color tint)
{
Color c = GUI.color;
GUI.color = tint;
GUI.Box(rect, "");
GUI.color = c;
}
private void DrawRow(Rect rowRect, int i)
{
if (i == currentIndex)
DrawBox(rowRect, Color.cyan);
else if (i == hoverIndex)
DrawBox(rowRect, Color.white);
Rect labelRect = new Rect(rowRect);
//labelRect.xMin += ROW_INDENT;
GUI.Label(labelRect, visibleItems[i].name);
}
/// <summary>
/// Process keyboard input to navigate the choices or make a selection.
/// </summary>
private void HandleKeyboard()
{
if (Event.current.type == EventType.KeyDown)
{
if (Event.current.keyCode == KeyCode.DownArrow)
{
hoverIndex = Mathf.Min(visibleItems.Count - 1, hoverIndex + 1);
Event.current.Use();
scrollToIndex = hoverIndex;
scrollOffset = ROW_HEIGHT;
}
if (Event.current.keyCode == KeyCode.UpArrow)
{
hoverIndex = Mathf.Max(0, hoverIndex - 1);
Event.current.Use();
scrollToIndex = hoverIndex;
scrollOffset = -ROW_HEIGHT;
}
if (Event.current.keyCode == KeyCode.Return)
{
if (hoverIndex >= 0 && hoverIndex < visibleItems.Count)
{
SelectByOrigIndex(visibleItems[hoverIndex].origIndex);
EditorWindow.focusedWindow.Close();
}
}
if (Event.current.keyCode == KeyCode.Escape)
{
EditorWindow.focusedWindow.Close();
}
}
}
protected void SelectByName(string name)
{
var loc = allItems.FindIndex(x => x.name == name);
SelectByOrigIndex(loc);
}
}
}

11
Assets/Fungus/Scripts/Editor/BasePopupWindowContent.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: be9eead8f19216444b4a87e94fe02ed3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

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

@ -26,7 +26,7 @@ namespace Fungus.EditorUtils
protected Texture2D duplicateIcon;
protected Texture2D deleteIcon;
private Rect lastEventPopupPos;
private Rect lastEventPopupPos, lastCMDpopupPos;
protected virtual void OnEnable()
@ -282,11 +282,19 @@ namespace Fungus.EditorUtils
GUILayout.FlexibleSpace();
var pos = EditorGUILayout.GetControlRect(true, 0, EditorStyles.objectField);
if (pos.x != 0)
{
lastCMDpopupPos = pos;
lastCMDpopupPos.x += EditorGUIUtility.labelWidth;
lastCMDpopupPos.y += EditorGUIUtility.singleLineHeight;
}
// Add Button
if (GUILayout.Button(addIcon))
{
CommandSelectorPopupWindowContent.ShowCommandMenu(target as Block);
CommandSelectorPopupWindowContent.ShowCommandMenu(lastCMDpopupPos, "", target as Block,
(int)(EditorGUIUtility.currentViewWidth),
(int)(EditorWindow.focusedWindow.position.height - lastCMDpopupPos.y - EditorGUIUtility.singleLineHeight*3));
}
// Duplicate Button

176
Assets/Fungus/Scripts/Editor/CommandSelectorPopupWindowContent.cs

@ -11,7 +11,7 @@ namespace Fungus.EditorUtils
///
/// Inspired by https://github.com/roboryantron/UnityEditorJunkie/blob/master/Assets/SearchableEnum/Code/Editor/SearchablePopup.cs
/// </summary>
public class CommandSelectorPopupWindowContent //: PopupWindowContent
public class CommandSelectorPopupWindowContent : BasePopupWindowContent
{
private static readonly char[] SPLIT_INPUT_ON = new char[] { ' ', '/', '\\' };
private static readonly int MAX_PREVIEW_GRID = 7;
@ -20,7 +20,7 @@ namespace Fungus.EditorUtils
static List<System.Type> commandTypes;
static void CacheEventHandlerTypes()
static void CacheCommandTypes()
{
commandTypes = EditorExtensions.FindDerivedTypes(typeof(Command)).Where(x => !x.IsAbstract).ToList();
}
@ -28,42 +28,52 @@ namespace Fungus.EditorUtils
[UnityEditor.Callbacks.DidReloadScripts]
private static void OnScriptsReloaded()
{
CacheEventHandlerTypes();
CacheCommandTypes();
}
static Block curBlock;
static protected List<KeyValuePair<System.Type, CommandInfoAttribute>> filteredAttributes;
static public void ShowCommandMenu(Block block)
public CommandSelectorPopupWindowContent(string currentHandlerName, Block block, int width, int height)
: base(currentHandlerName, block, width, height)
{
curBlock = block;
}
var flowchart = (Flowchart)block.GetFlowchart();
protected override void SelectByOrigIndex(int index)
{
var commandType = (index >= 0 && index < commandTypes.Count) ? commandTypes[index] : null;
AddCommandCallback(commandType);
}
GenericMenu commandMenu = new GenericMenu();
protected override void PrepareAllItems()
{
if (commandTypes == null || commandTypes.Count == 0)
{
CacheCommandTypes();
}
// Build menu list
var filteredAttributes = GetFilteredSupportedCommands(flowchart);
foreach (var keyPair in filteredAttributes)
filteredAttributes = GetFilteredSupportedCommands(block.GetFlowchart());
int i = 0;
foreach (var item in filteredAttributes)
{
AddCommandOperation commandOperation = new AddCommandOperation();
allItems.Add(new FilteredListItem(i, (item.Value.Category.Length > 0 ? item.Value.Category + "/" : "") + item.Value.CommandName));
commandOperation.commandType = keyPair.Key;
i++;
}
}
GUIContent menuItem;
if (keyPair.Value.Category == "")
{
menuItem = new GUIContent(keyPair.Value.CommandName);
}
else
{
menuItem = new GUIContent(keyPair.Value.Category + "/" + keyPair.Value.CommandName);
}
static public void ShowCommandMenu(Rect position, string currentHandlerName, Block block, int width, int height)
{
curBlock = block;
commandMenu.AddItem(menuItem, false, AddCommandCallback, commandOperation);
}
var win = new CommandSelectorPopupWindowContent(currentHandlerName, block, width, height);
PopupWindow.Show(position, win);
commandMenu.ShowAsContext();
//old method
DoOlderMenu();
}
protected static List<KeyValuePair<System.Type, CommandInfoAttribute>> GetFilteredSupportedCommands(Flowchart flowchart)
@ -79,13 +89,40 @@ namespace Fungus.EditorUtils
static protected void DoOlderMenu()
{
var flowchart = (Flowchart)curBlock.GetFlowchart();
GenericMenu commandMenu = new GenericMenu();
// Build menu list
foreach (var keyPair in filteredAttributes)
{
GUIContent menuItem;
if (keyPair.Value.Category == "")
{
menuItem = new GUIContent(keyPair.Value.CommandName);
}
else
{
menuItem = new GUIContent(keyPair.Value.Category + "/" + keyPair.Value.CommandName);
}
commandMenu.AddItem(menuItem, false, AddCommandCallback, keyPair.Key);
}
commandMenu.ShowAsContext();
}
//Used by GenericMenu Delegate
static protected void AddCommandCallback(object obj)
{
AddCommandOperation commandOperation = obj as AddCommandOperation;
if (commandOperation != null)
Type command = obj as Type;
if (command != null)
{
AddCommandCallback(commandOperation.commandType);
AddCommandCallback(command);
}
}
@ -93,7 +130,7 @@ namespace Fungus.EditorUtils
static protected void AddCommandCallback(Type commandType)
{
var block = curBlock;
if (block == null)
if (block == null || commandType == null)
{
return;
}
@ -137,89 +174,6 @@ namespace Fungus.EditorUtils
flowchart.ClearSelectedCommands();
//commandTextFieldContents = string.Empty;
}
protected class AddCommandOperation
{
public Type commandType;
}
//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 = curBlock;
// 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);
//}
}
}

235
Assets/Fungus/Scripts/Editor/EventSelectorPopupWindowContent.cs

@ -11,7 +11,7 @@ namespace Fungus.EditorUtils
///
/// Inspired by https://github.com/roboryantron/UnityEditorJunkie/blob/master/Assets/SearchableEnum/Code/Editor/SearchablePopup.cs
/// </summary>
public class EventSelectorPopupWindowContent : PopupWindowContent
public class EventSelectorPopupWindowContent : BasePopupWindowContent
{
static List<System.Type> eventHandlerTypes;
@ -32,36 +32,18 @@ namespace Fungus.EditorUtils
public Type eventHandlerType;
}
public class FilteredListItem
public EventSelectorPopupWindowContent(string currentHandlerName, Block block, int width, int height)
:base(currentHandlerName, block, width, height)
{
public FilteredListItem(int index, string str)
{
origIndex = index;
name = str;
lowerName = str.ToLowerInvariant();
}
public int origIndex;
public string name, lowerName;
}
private Block block;
private int hoverIndex;
private readonly string SEARCH_CONTROL_NAME = "PopupSearchControlName";
private readonly float ROW_HEIGHT = EditorGUIUtility.singleLineHeight;
private List<FilteredListItem> allItems = new List<FilteredListItem>(), visibleItems = new List<FilteredListItem>();
private string currentFilter = string.Empty;
private Vector2 scroll;
private int scrollToIndex;
private float scrollOffset;
private int currentIndex;
private Vector2 size;
static readonly char[] SEARCH_SPLITS = new char[]{ '/', ' ' };
public EventSelectorPopupWindowContent(string currentHandlerName, Block block, int width, int height)
protected override void PrepareAllItems()
{
this.block = block;
this.size = new Vector2(width, height);
if (eventHandlerTypes == null || eventHandlerTypes.Count == 0)
{
CacheEventHandlerTypes();
}
int i = 0;
foreach (System.Type type in eventHandlerTypes)
@ -78,180 +60,16 @@ namespace Fungus.EditorUtils
i++;
}
allItems.Sort((lhs, rhs) => lhs.name.CompareTo(rhs.name));
UpdateFilter();
currentIndex = Mathf.Max(0, visibleItems.FindIndex(x=>x.name.Contains(currentHandlerName)));
}
public override void OnGUI(Rect rect)
override protected void SelectByOrigIndex(int index)
{
Rect searchRect = new Rect(0, 0, rect.width, EditorStyles.toolbar.fixedHeight);
Rect scrollRect = Rect.MinMaxRect(0, searchRect.yMax, rect.xMax, rect.yMax);
HandleKeyboard();
DrawSearch(searchRect);
DrawSelectionArea(scrollRect);
}
public override Vector2 GetWindowSize()
{
return size;
}
private void DrawSearch(Rect rect)
{
if (Event.current.type == EventType.Repaint)
EditorStyles.toolbar.Draw(rect, false, false, false, false);
Rect searchRect = new Rect(rect);
searchRect.xMin += 6;
searchRect.xMax -= 6;
searchRect.y += 2;
//searchRect.width -= CancelButton.fixedWidth;
GUI.FocusControl(SEARCH_CONTROL_NAME);
GUI.SetNextControlName(SEARCH_CONTROL_NAME);
var prevFilter = currentFilter;
currentFilter = GUI.TextField(searchRect, currentFilter);
if (prevFilter != currentFilter)
{
UpdateFilter();
}
}
private void UpdateFilter()
{
var curlower = currentFilter.ToLowerInvariant();
var lowers = curlower.Split(SEARCH_SPLITS);
lowers = lowers.Where(x => x.Length > 0).ToArray();
if (lowers == null || lowers.Length == 0)
{
visibleItems.AddRange(allItems);
}
else
{
visibleItems = allItems.Where(x =>
{
foreach (var item in lowers)
{
if (x.lowerName.Contains(currentFilter))
return true;
}
return false;
}).ToList();
}
hoverIndex = 0;
scroll = Vector2.zero;
visibleItems.Insert(0, new FilteredListItem(-1, "None"));
}
private void DrawSelectionArea(Rect scrollRect)
{
Rect contentRect = new Rect(0, 0,
scrollRect.width - GUI.skin.verticalScrollbar.fixedWidth,
visibleItems.Count * ROW_HEIGHT);
scroll = GUI.BeginScrollView(scrollRect, scroll, contentRect);
Rect rowRect = new Rect(0, 0, scrollRect.width, ROW_HEIGHT);
for (int i = 0; i < visibleItems.Count; i++)
{
if (scrollToIndex == i &&
(Event.current.type == EventType.Repaint
|| Event.current.type == EventType.Layout))
{
Rect r = new Rect(rowRect);
r.y += scrollOffset;
GUI.ScrollTo(r);
scrollToIndex = -1;
scroll.x = 0;
}
if (rowRect.Contains(Event.current.mousePosition))
{
if (Event.current.type == EventType.MouseMove ||
Event.current.type == EventType.ScrollWheel)
hoverIndex = i;
if (Event.current.type == EventType.MouseDown)
{
//onSelectionMade(list.Entries[i].Index);
SelectByOrigIndex(visibleItems[i].origIndex);
EditorWindow.focusedWindow.Close();
}
}
DrawRow(rowRect, i);
rowRect.y = rowRect.yMax;
}
GUI.EndScrollView();
}
private static void DrawBox(Rect rect, Color tint)
{
Color c = GUI.color;
GUI.color = tint;
GUI.Box(rect, "");
GUI.color = c;
}
private void DrawRow(Rect rowRect, int i)
{
if (i == currentIndex)
DrawBox(rowRect, Color.cyan);
else if (i == hoverIndex)
DrawBox(rowRect, Color.white);
Rect labelRect = new Rect(rowRect);
//labelRect.xMin += ROW_INDENT;
GUI.Label(labelRect, visibleItems[i].name);
SetEventHandlerOperation operation = new SetEventHandlerOperation();
operation.block = block;
operation.eventHandlerType = (index >= 0 && index < eventHandlerTypes.Count) ? eventHandlerTypes[index] : null;
OnSelectEventHandler(operation);
}
/// <summary>
/// Process keyboard input to navigate the choices or make a selection.
/// </summary>
private void HandleKeyboard()
{
if (Event.current.type == EventType.KeyDown)
{
if (Event.current.keyCode == KeyCode.DownArrow)
{
hoverIndex = Mathf.Min(visibleItems.Count - 1, hoverIndex + 1);
Event.current.Use();
scrollToIndex = hoverIndex;
scrollOffset = ROW_HEIGHT;
}
if (Event.current.keyCode == KeyCode.UpArrow)
{
hoverIndex = Mathf.Max(0, hoverIndex - 1);
Event.current.Use();
scrollToIndex = hoverIndex;
scrollOffset = -ROW_HEIGHT;
}
if (Event.current.keyCode == KeyCode.Return)
{
if (hoverIndex >= 0 && hoverIndex < visibleItems.Count)
{
SelectByOrigIndex(visibleItems[hoverIndex].origIndex);
//onSelectionMade(list.Entries[hoverIndex].Index);
EditorWindow.focusedWindow.Close();
}
}
if (Event.current.keyCode == KeyCode.Escape)
{
EditorWindow.focusedWindow.Close();
}
}
}
static public void DoEventHandlerPopUp(Rect position, string currentHandlerName, Block block, int width, int height)
{
@ -260,6 +78,11 @@ namespace Fungus.EditorUtils
PopupWindow.Show(position, win);
//old method
DoOlderMenu(block);
}
static protected void DoOlderMenu(Block block)
{
SetEventHandlerOperation noneOperation = new SetEventHandlerOperation();
noneOperation.block = block;
@ -301,7 +124,6 @@ namespace Fungus.EditorUtils
eventHandlerMenu.ShowAsContext();
}
static protected void OnSelectEventHandler(object obj)
{
SetEventHandlerOperation operation = obj as SetEventHandlerOperation;
@ -329,22 +151,5 @@ namespace Fungus.EditorUtils
// Because this is an async call, we need to force prefab instances to record changes
PrefabUtility.RecordPrefabInstancePropertyModifications(block);
}
protected void SelectByName(string name)
{
var loc = allItems.First(x => x.name == name);
SetEventHandlerOperation operation = new SetEventHandlerOperation();
operation.block = block;
operation.eventHandlerType = eventHandlerTypes[loc.origIndex];
OnSelectEventHandler(operation);
}
protected void SelectByOrigIndex(int index)
{
SetEventHandlerOperation operation = new SetEventHandlerOperation();
operation.block = block;
operation.eventHandlerType = (index >= 0 && index<eventHandlerTypes.Count) ? eventHandlerTypes[index] : null;
OnSelectEventHandler(operation);
}
}
}
Loading…
Cancel
Save