Browse Source

Exposed manual context menu opening to C#
Added context menu for animation

BearishSun 9 years ago
parent
commit
596d46c542

+ 91 - 9
Source/MBansheeEditor/Windows/AnimationWindow.cs

@@ -42,6 +42,10 @@ namespace BansheeEditor
         private int markedFrameIdx;
         private List<KeyframeRef> selectedKeyframes = new List<KeyframeRef>();
 
+        private ContextMenu blankContextMenu;
+        private ContextMenu keyframeContextMenu;
+        private Vector2I contextClickPosition;
+
         // Keyframe drag
         private bool isMousePressedOverKey;
         private KeyFrame[] draggedKeyframes;
@@ -121,11 +125,42 @@ namespace BansheeEditor
             curveDrawing.SetSize(Width, Height - 20 - buttonLayout.Bounds.height);
             curveDrawing.Rebuild();
 
+            blankContextMenu = new ContextMenu();
+            blankContextMenu.AddItem("Add keyframe", AddKeyframeAtPosition);
+            blankContextMenu.AddItem("Add event", AddEventAtPosition);
+
+            keyframeContextMenu = new ContextMenu();
+            keyframeContextMenu.AddItem("Delete", DeleteSelectedKeyframes);
+            keyframeContextMenu.AddItem("Tangents/Auto", () => { ChangeSelectionTangentMode(TangentMode.Auto); });
+            keyframeContextMenu.AddItem("Tangents/Free", () => { ChangeSelectionTangentMode(TangentMode.Free); });
+            keyframeContextMenu.AddItem("Tangents/In/Auto", () => { ChangeSelectionTangentMode(TangentMode.InAuto); });
+            keyframeContextMenu.AddItem("Tangents/In/Free", () => { ChangeSelectionTangentMode(TangentMode.InFree); });
+            keyframeContextMenu.AddItem("Tangents/In/Linear", () => { ChangeSelectionTangentMode(TangentMode.InLinear); });
+            keyframeContextMenu.AddItem("Tangents/In/Step", () => { ChangeSelectionTangentMode(TangentMode.InStep); });
+            keyframeContextMenu.AddItem("Tangents/Out/Auto", () => { ChangeSelectionTangentMode(TangentMode.OutAuto); });
+            keyframeContextMenu.AddItem("Tangents/Out/Free", () => { ChangeSelectionTangentMode(TangentMode.OutFree); });
+            keyframeContextMenu.AddItem("Tangents/Out/Linear", () => { ChangeSelectionTangentMode(TangentMode.OutLinear); });
+            keyframeContextMenu.AddItem("Tangents/Out/Step", () => { ChangeSelectionTangentMode(TangentMode.OutStep); });
 
             // TODO - Calculate min/max Y and range to set as default
             //  - Also recalculate whenever curves change and increase as needed
         }
 
+        private void ChangeSelectionTangentMode(TangentMode mode)
+        {
+            // TODO - When changing just left or right, make sure to persist opposite tangent mode (or switch to equivalent broken mode if it wasn't broken)
+        }
+
+        private void AddKeyframeAtPosition()
+        {
+            // TODO
+        }
+
+        private void AddEventAtPosition()
+        {
+            // TODO
+        }
+
         private void AddKeyframeAtMarker()
         {
             ClearSelection();
@@ -138,6 +173,8 @@ namespace BansheeEditor
                 curve.AddKeyframe(t, value);
             }
 
+            // TODO - UNDOREDO
+
             curveDrawing.Rebuild();
         }
 
@@ -156,6 +193,8 @@ namespace BansheeEditor
             foreach (var keyframe in selectedKeyframes)
                 curves[keyframe.curveIdx].RemoveKeyframe(keyframe.keyIdx);
 
+            // TODO - UNDOREDO
+
             ClearSelection();
 
             curveDrawing.Rebuild();
@@ -190,6 +229,24 @@ namespace BansheeEditor
             isMousePressedOverKey = false;
         }
 
+        private void SelectKeyframe(int curveIdx, int keyIdx)
+        {
+            curveDrawing.SelectKeyframe(curveIdx, keyIdx, true);
+
+            if (!IsSelected(curveIdx, keyIdx))
+                selectedKeyframes.Add(new KeyframeRef(curveIdx, keyIdx));
+        }
+
+        private bool IsSelected(int curveIdx, int keyIdx)
+        {
+            int existingIdx = selectedKeyframes.FindIndex(x =>
+            {
+                return x.curveIdx == curveIdx && x.keyIdx == keyIdx;
+            });
+
+            return (existingIdx != -1);
+        }
+
         private void OnEditorUpdate()
         {
             if (Input.IsPointerButtonDown(PointerButton.Left))
@@ -208,15 +265,7 @@ namespace BansheeEditor
                         if (!Input.IsButtonHeld(ButtonCode.LeftShift) && !Input.IsButtonHeld(ButtonCode.RightShift))
                             ClearSelection();
 
-                        curveDrawing.SelectKeyframe(curveIdx, keyIdx, true);
-
-                        int existingIdx = selectedKeyframes.FindIndex(x =>
-                        {
-                            return x.curveIdx == curveIdx && x.keyIdx == keyIdx;
-                        });
-
-                        if (existingIdx == -1)
-                            selectedKeyframes.Add(new KeyframeRef(curveIdx, keyIdx));
+                        SelectKeyframe(curveIdx, keyIdx);
 
                         isMousePressedOverKey = true;
                         dragStart = curveCoord;
@@ -254,6 +303,39 @@ namespace BansheeEditor
                 isMousePressedOverKey = false;
             }
 
+            if (Input.IsPointerButtonDown(PointerButton.Right))
+            {
+                Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition);
+
+                Vector2 curveCoord;
+                int curveIdx;
+                int keyIdx;
+                if (curveDrawing.GetCoordInfo(windowPos, out curveCoord, out curveIdx, out keyIdx))
+                {
+                    contextClickPosition = windowPos;
+
+                    if (keyIdx == -1)
+                    {
+                        ClearSelection();
+
+                        blankContextMenu.Open(contextClickPosition, GUI);
+                    }
+                    else
+                    {
+                        // If clicked outside of current selection, just select the one keyframe
+                        if (!IsSelected(curveIdx, keyIdx))
+                        {
+                            ClearSelection();
+                            SelectKeyframe(curveIdx, keyIdx);
+
+                            curveDrawing.Rebuild();
+                        }
+
+                        keyframeContextMenu.Open(contextClickPosition, GUI);
+                    }
+                }
+            }
+
             if(Input.IsButtonUp(ButtonCode.Delete))
                 DeleteSelectedKeyframes();
         }

+ 23 - 0
Source/MBansheeEngine/GUI/ContextMenu.cs

@@ -15,6 +15,8 @@ namespace BansheeEngine
     /// a path. Path must be formated in a certain way. All path elements must be separated by /, for example 
     /// "View/Toolbars/Find". "View" would be the top level path element, "Toolbars" a child in its menu that opens up its
     /// own submenu, and "Find" a child in the "Toolbars" sub-menu with an optional callback.
+    /// 
+    /// A context menu can either by provided to GUIElements, or opened manually by calling <see cref="Open"/>.
     /// </summary>
     public class ContextMenu : ScriptObject
     {
@@ -28,6 +30,24 @@ namespace BansheeEngine
             Internal_CreateInstance(this);
         }
 
+        /// <summary>
+        /// Opens the context menu at the specified position.
+        /// </summary>
+        /// <param name="position">Position relative to the <paramref name="parent"/>.</param>
+        /// <param name="parent">GUI layout over which to open the context menu. Context menu can be opened outside of the
+        ///                      area of the layout, as long as the area belongs to the same window.</param>
+        public void Open(Vector2I position, GUILayout parent)
+        {
+            if (parent == null)
+                return;
+
+            Rect2I bounds = GUIUtility.CalculateBounds(parent, null);
+            Vector2I windowPosition = position + new Vector2I(bounds.x, bounds.y);
+
+            IntPtr parentPtr = parent.GetCachedPtr();
+            Internal_Open(mCachedPtr, ref windowPosition, parentPtr);
+        }
+
         /// <summary>
         /// Adds a new item to the menu.
         /// </summary>
@@ -122,6 +142,9 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_CreateInstance(ContextMenu instance);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Open(IntPtr instance, ref Vector2I position, IntPtr layoutPtr);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_AddItem(IntPtr instance, string path, int callbackIdx, ref ShortcutKey shortcut);
 

+ 1 - 0
Source/SBansheeEngine/Include/BsScriptContextMenu.h

@@ -39,6 +39,7 @@ namespace BansheeEngine
 		static OnEntryTriggeredThunkDef onEntryTriggered;
 
 		static void internal_CreateInstance(MonoObject* instance);
+		static void internal_Open(ScriptContextMenu* instance, Vector2I* position, ScriptGUILayout* layoutPtr);
 		static void internal_AddItem(ScriptContextMenu* instance, MonoString* path, UINT32 callbackIdx, ShortcutKey* shortcut);
 		static void internal_AddSeparator(ScriptContextMenu* instance, MonoString* path);
 		static void internal_SetLocalizedName(ScriptContextMenu* instance, MonoString* label, ScriptHString* name);

+ 12 - 0
Source/SBansheeEngine/Source/BsScriptContextMenu.cpp

@@ -9,6 +9,7 @@
 #include "BsMonoUtil.h"
 #include "BsGUIContextMenu.h"
 #include "BsScriptHString.h"
+#include "BsScriptGUILayout.h"
 
 using namespace std::placeholders;
 
@@ -25,6 +26,7 @@ namespace BansheeEngine
 	void ScriptContextMenu::initRuntimeData()
 	{
 		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptContextMenu::internal_CreateInstance);
+		metaData.scriptClass->addInternalCall("Internal_Open", &ScriptContextMenu::internal_Open);
 		metaData.scriptClass->addInternalCall("Internal_AddItem", &ScriptContextMenu::internal_AddItem);
 		metaData.scriptClass->addInternalCall("Internal_AddSeparator", &ScriptContextMenu::internal_AddSeparator);
 		metaData.scriptClass->addInternalCall("Internal_SetLocalizedName", &ScriptContextMenu::internal_SetLocalizedName);
@@ -37,6 +39,16 @@ namespace BansheeEngine
 		new (bs_alloc<ScriptContextMenu>()) ScriptContextMenu(instance);
 	}
 
+	void ScriptContextMenu::internal_Open(ScriptContextMenu* instance, Vector2I* position, ScriptGUILayout* layoutPtr)
+	{
+		GUIWidget* widget = layoutPtr->getGUIElement()->_getParentWidget();
+		if (widget == nullptr)
+			return;
+
+		SPtr<GUIContextMenu> contextMenu = instance->getInternal();
+		contextMenu->open(*position, *widget);
+	}
+
 	void ScriptContextMenu::internal_AddItem(ScriptContextMenu* instance, MonoString* path, UINT32 callbackIdx,
 		ShortcutKey* shortcut)
 	{