Exemplo n.º 1
0
        private void ShowSidebar()
        {
            ResizeScrollView();

            if (def && showSide)
            {
                float padding = 20;
                EditorGUI.DrawRect(new Rect(position.width - _sidePanelWidth, 0, _sidePanelWidth, position.height), panelColor);
                GUILayout.BeginArea(new Rect(position.width - _sidePanelWidth + padding, padding, _sidePanelWidth - padding * 2, position.height - padding * 2));
                EditorGUILayout.BeginVertical();
                float w = EditorGUIUtility.labelWidth;
                EditorGUIUtility.labelWidth = 1;

                if (GUILayout.Button(dirty ? "Save *" : "Save"))
                {
                    AssetDatabase.SaveAssets();
                    dirty = false;
                    StateMachineClassGenerator.GenerateAbstractClass(def);
                }

                if (GUILayout.Button("New Impl Class..."))
                {
                    var path = EditorUtility.SaveFilePanelInProject("Save new class", def.name + "Impl.cs", "cs", "Enter a name for the new impl class");
                    if (path.Length > 0)
                    {
                        StateMachineClassGenerator.GenerateImplClass(def, path);
                    }
                }

                if (types == null)
                {
                    types = typeof(StateMachine).Assembly.GetTypes()
                            .Where(p => !p.IsGenericType && typeof(StateMachine).IsAssignableFrom(p))
                            .Select(t => t.FullName).ToArray();
                }

                int index = Array.IndexOf(types, def.baseClass);
                if (index < 0)
                {
                    index = Array.IndexOf(types, typeof(StateMachine).FullName);
                }
                int prev = index;

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Base Class");
                index = EditorGUILayout.Popup(index, types);

                if (prev != index)
                {
                    dirty = true;
                }

                EditorGUILayout.EndHorizontal();
                def.baseClass = types[index];

                if (editingState != null)
                {
                    EditorGUILayout.LabelField("State " + editingState.name);
                    EditorGUILayout.LabelField("State Events", EditorStyles.boldLabel);

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Enter: ");
                    bool enter = EditorGUILayout.Toggle(editingState.hasEnter);
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("During: ");
                    bool during = EditorGUILayout.Toggle(editingState.hasDuring);
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Exit: ");
                    bool exit = EditorGUILayout.Toggle(editingState.hasExit);
                    EditorGUILayout.EndHorizontal();


                    if (enter != editingState.hasEnter || during != editingState.hasDuring || exit != editingState.hasExit)
                    {
                        editingState.hasEnter  = enter;
                        editingState.hasDuring = during;
                        editingState.hasExit   = exit;

                        dirty = true;
                        EditorUtility.SetDirty(def);
                    }
                }
                else if (editingTransition.t1 != null)
                {
                    EditorGUILayout.LabelField("Transition From " + editingTransition.t1.name + " To " + editingTransition.t2.to);
                    EditorGUILayout.LabelField("Transition Events", EditorStyles.boldLabel);

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Notify: ");
                    bool notify = EditorGUILayout.Toggle("Notify: ", editingTransition.t2.hasNotify);
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.LabelField("Conditions", EditorStyles.boldLabel);

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Exit Time: ");
                    float exitTime = EditorGUILayout.FloatField(editingTransition.t2.exitTime);
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Mode: ");
                    var mode = (StateMachineDefinition.TransitionMode)EditorGUILayout.EnumPopup(editingTransition.t2.mode);
                    EditorGUILayout.EndHorizontal();

                    if (notify != editingTransition.t2.hasNotify || exitTime != editingTransition.t2.exitTime || mode != editingTransition.t2.mode)
                    {
                        editingTransition.t2.hasNotify = notify;
                        editingTransition.t2.exitTime  = exitTime;
                        editingTransition.t2.mode      = mode;

                        dirty = true;
                        EditorUtility.SetDirty(def);
                    }
                }

                EditorGUILayout.EndVertical();
                EditorGUIUtility.labelWidth = w;

                GUILayout.EndArea();
            }
        }
        void OnGUI()
        {
            ResizeScrollView();
            Rect viewportRect = new Rect(0, 0, position.width - sidePanelWidth, position.height);

            EditorGUI.DrawRect(viewportRect, bgColor);
            bool repaint = false;

            foreach (var obj in Selection.objects)
            {
                if (obj is StateMachineDefinition)
                {
                    def = (StateMachineDefinition)obj;
                    break;
                }
            }

            if (def != null)
            {
                bool showSide = true;

                Event cur = Event.current;

                if (op != null)
                {
                    if (def != op.definition)
                    {
                        op.Cancel();
                        op = null;
                    }
                    else
                    {
                        op.Update();

                        if (op.done)
                        {
                            op      = null;
                            repaint = true;
                            EditorUtility.SetDirty(def);
                            dirty = true;
                        }
                    }
                }
                else
                {
                    var selected   = def.SelectState(cur.mousePosition + scrollPos);
                    var selectedTr = def.SelectTransition(cur.mousePosition + scrollPos);

                    if (selected == null)
                    {
                        if (selectedTr.t2 != lastSelectedTr)
                        {
                            repaint        = true;
                            lastSelectedTr = selectedTr.t2;
                        }

                        if (lastSelectedState != null)
                        {
                            lastSelectedState = null;
                            repaint           = true;
                        }
                    }
                    else
                    {
                        if (selected != lastSelectedState)
                        {
                            repaint           = true;
                            lastSelectedState = selected;
                        }

                        if (lastSelectedTr != null)
                        {
                            lastSelectedTr = null;
                            repaint        = true;
                        }
                    }

                    if (viewportRect.Contains(cur.mousePosition))
                    {
                        if (cur.type == EventType.MouseDown)
                        {
                            if (cur.button == 0)
                            {
                                if (selected != null)
                                {
                                    editingState         = selected;
                                    editingTransition.t1 = null;
                                    editingTransition.t2 = null;
                                    repaint  = true;
                                    showSide = false;


                                    if (cur.clickCount == 1)
                                    {
                                        op = new MoveStateOperation(def, this, selected);
                                    }
                                    else if (cur.clickCount == 2)
                                    {
                                        op = new RenameStateOperation(def, this, selected);
                                    }
                                }
                                else if (selectedTr.t1 != null)
                                {
                                    editingTransition = selectedTr;
                                    editingState      = null;
                                    repaint           = true;
                                    showSide          = false;
                                }
                                else
                                {
                                    editingState         = null;
                                    editingTransition.t1 = null;
                                    editingTransition.t2 = null;
                                    repaint  = true;
                                    showSide = false;
                                }
                            }
                            else if (cur.button == 1)
                            {
                                if (selected == null && lastSelectedTr == null)
                                {
                                    GenericMenu menu = new GenericMenu();

                                    menu.AddItem(new GUIContent("Create State"), false, () => {
                                        var s      = def.AddState();
                                        s.position = cur.mousePosition + scrollPos;
                                        MoveStateOperation.Snap(ref s.position);
                                        op = new RenameStateOperation(def, this, s);
                                        EditorUtility.SetDirty(def);
                                        dirty = true;
                                    });

                                    menu.ShowAsContext();
                                }
                                else if (selected != null)
                                {
                                    GenericMenu menu = new GenericMenu();

                                    menu.AddItem(new GUIContent("Delete State"), false, () => {
                                        def.RemoveState(selected);
                                        EditorUtility.SetDirty(def);
                                        dirty   = true;
                                        repaint = true;
                                    });

                                    menu.AddItem(new GUIContent("Add Transition"), false, () => {
                                        op = new MakeTransitionOperation(def, this, selected);
                                    });

                                    if (selected.name != def.defaultState)
                                    {
                                        menu.AddItem(new GUIContent("Make Default State"), false, () => {
                                            def.defaultState = selected.name;
                                            dirty            = true;
                                            repaint          = true;
                                        });
                                    }

                                    menu.ShowAsContext();
                                }
                                else if (selectedTr.t1 != null)
                                {
                                    GenericMenu menu = new GenericMenu();

                                    menu.AddItem(new GUIContent("Remove Transition"), false, () => {
                                        selectedTr.t1.RemoveTransition(selectedTr.t2);
                                        EditorUtility.SetDirty(def);
                                        dirty   = true;
                                        repaint = true;
                                    });

                                    menu.ShowAsContext();
                                }
                            }
                        }
                        else if (cur.type == EventType.MouseDrag && cur.button == 2)
                        {
                            scrollPos -= cur.delta;
                            repaint    = true;
                        }
                        else if (cur.type == EventType.KeyDown && cur.keyCode == KeyCode.F)
                        {
                            var state = def.GetState(def.defaultState);
                            if (state == null && def.states.Count > 0)
                            {
                                state = def.states[0];
                            }

                            if (state != null)
                            {
                                scrollPos = state.position - viewportRect.size / 2;
                                repaint   = true;
                            }
                        }
                    }
                }

                if (Event.current.type != EventType.Repaint && (repaint || (op != null && op.repaint)))
                {
                    Repaint();
                }

                Handles.BeginGUI();

                Handles.color = lineColor;
                for (float x = -scrollPos.x % MoveStateOperation.snap; x < viewportRect.width; x += MoveStateOperation.snap)
                {
                    Handles.DrawLine(new Vector3(x, 0), new Vector3(x, viewportRect.height));
                }

                for (float y = -scrollPos.y % MoveStateOperation.snap; y < viewportRect.height; y += MoveStateOperation.snap)
                {
                    Handles.DrawLine(new Vector3(0, y), new Vector3(viewportRect.width, y));
                }

                if (def.states != null)
                {
                    foreach (var from in def.states)
                    {
                        if (from.transitions != null)
                        {
                            foreach (var tr in from.transitions)
                            {
                                if (tr != lastSelectedTr && tr != editingTransition.t2)
                                {
                                    Handles.color = Color.black;
                                }
                                else
                                {
                                    Handles.color = Color.blue;
                                }

                                if (def.GetState(tr.to) != null)
                                {
                                    var     line = def.GetTransitionPoints(from, tr);
                                    Vector2 src  = line.t1 - scrollPos;
                                    Vector2 dest = line.t2 - scrollPos;

                                    Vector2 v     = (dest - src).normalized;
                                    Vector2 ortho = new Vector2(v.y, -v.x);

                                    Vector2 arrow = ortho - v;
                                    Vector2 mid   = (src + dest) / 2;

                                    Handles.DrawAAPolyLine(3, src, dest);
                                    Handles.DrawAAPolyLine(3, mid + v * 5, mid + arrow * 10);
                                }
                            }
                        }
                    }

                    foreach (var state in def.states)
                    {
                        if (op == null || op.state != state || op.showBaseGUI)
                        {
                            string s = state.name;
                            if (def.defaultState == s)
                            {
                                s += "\n<default state>";
                            }

                            Rect rect = state.rect;
                            rect.position -= scrollPos;

                            if (state != lastSelectedState && state != editingState)
                            {
                                GUI.Button(rect, s);
                            }
                            else
                            {
                                GUI.Button(rect, "");

                                var centeredStyle = new GUIStyle(GUI.skin.label);
                                centeredStyle.alignment        = TextAnchor.MiddleCenter;
                                centeredStyle.normal.textColor = Color.blue;
                                centeredStyle.fontStyle        = FontStyle.Bold;

                                GUI.Label(rect, s, centeredStyle);
                            }
                        }

                        if (op != null && op.state == state)
                        {
                            op.OnGUI();
                        }
                    }
                }

                Handles.EndGUI();

                if (showSide)
                {
                    EditorGUI.DrawRect(new Rect(position.width - sidePanelWidth, 0, sidePanelWidth, position.height), panelColor);


                    float padding = 20;
                    GUILayout.BeginArea(new Rect(position.width - sidePanelWidth + padding, padding, sidePanelWidth - padding * 2, position.height - padding * 2));
                    EditorGUILayout.BeginVertical();
                    float w = EditorGUIUtility.labelWidth;
                    EditorGUIUtility.labelWidth = 1;

                    if (GUILayout.Button(dirty ? "Save *" : "Save"))
                    {
                        AssetDatabase.SaveAssets();
                        dirty = false;
                        StateMachineClassGenerator.GenerateAbstractClass(def);
                    }

                    if (GUILayout.Button("New Impl Class..."))
                    {
                        var path = EditorUtility.SaveFilePanelInProject("Save new class", def.name + "Impl.cs", "cs", "Enter a name for the new impl class");
                        if (path.Length > 0)
                        {
                            StateMachineClassGenerator.GenerateImplClass(def, path);
                        }
                    }

                    if (types == null)
                    {
                        types = typeof(StateMachine).Assembly.GetTypes()
                                .Where(p => !p.IsGenericType && typeof(StateMachine).IsAssignableFrom(p))
                                .Select(t => t.FullName).ToArray();
                    }

                    int index = Array.IndexOf(types, def.baseClass);
                    if (index < 0)
                    {
                        index = Array.IndexOf(types, typeof(StateMachine).FullName);
                    }
                    int prev = index;

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Base Class");
                    index = EditorGUILayout.Popup(index, types);

                    if (prev != index)
                    {
                        dirty = true;
                    }

                    EditorGUILayout.EndHorizontal();
                    def.baseClass = types[index];

                    if (editingState != null)
                    {
                        EditorGUILayout.LabelField("State " + editingState.name);
                        EditorGUILayout.LabelField("State Events", EditorStyles.boldLabel);

                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("Enter: ");
                        bool enter = EditorGUILayout.Toggle(editingState.hasEnter);
                        EditorGUILayout.EndHorizontal();

                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("During: ");
                        bool during = EditorGUILayout.Toggle(editingState.hasDuring);
                        EditorGUILayout.EndHorizontal();

                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("Exit: ");
                        bool exit = EditorGUILayout.Toggle(editingState.hasExit);
                        EditorGUILayout.EndHorizontal();


                        if (enter != editingState.hasEnter || during != editingState.hasDuring || exit != editingState.hasExit)
                        {
                            editingState.hasEnter  = enter;
                            editingState.hasDuring = during;
                            editingState.hasExit   = exit;

                            dirty = true;
                            EditorUtility.SetDirty(def);
                        }
                    }
                    else if (editingTransition.t1 != null)
                    {
                        EditorGUILayout.LabelField("Transition From " + editingTransition.t1.name + " To " + editingTransition.t2.to);
                        EditorGUILayout.LabelField("Transition Events", EditorStyles.boldLabel);

                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("Notify: ");
                        bool notify = EditorGUILayout.Toggle(editingTransition.t2.hasNotify);
                        EditorGUILayout.EndHorizontal();

                        if (notify != editingTransition.t2.hasNotify)
                        {
                            editingTransition.t2.hasNotify = notify;

                            dirty = true;
                            EditorUtility.SetDirty(def);
                        }
                    }

                    EditorGUILayout.EndVertical();
                    EditorGUIUtility.labelWidth = w;

                    GUILayout.EndArea();
                }
            }
            else if (op != null)
            {
                op.Cancel();
                op = null;
            }
        }