Просмотр исходного кода

Animation clip splitting functional
Fixed issue where certain GUI element didn't report focus loss events
Modified GUI so that focus loss event is reported before mouse press event, to make form confirm logic more intuitive

BearishSun 9 лет назад
Родитель
Сommit
dd32259b26

+ 4 - 0
Source/BansheeEditor/Source/BsGUIFloatField.cpp

@@ -212,14 +212,18 @@ namespace BansheeEngine
 		if (focus)
 		{
 			UndoRedo::instance().pushGroup("InputBox");
+
 			mHasInputFocus = true;
+			onFocusChanged(true);
 		}
 		else
 		{
 			UndoRedo::instance().popGroup("InputBox");
 
 			setText(applyRangeAndStep(mValue));
+
 			mHasInputFocus = false;
+			onFocusChanged(false);
 		}
 	}
 

+ 4 - 0
Source/BansheeEditor/Source/BsGUIIntField.cpp

@@ -230,14 +230,18 @@ namespace BansheeEngine
 		if (focus)
 		{
 			UndoRedo::instance().pushGroup("InputBox");
+
 			mHasInputFocus = true;
+			onFocusChanged(true);
 		}
 		else
 		{
 			UndoRedo::instance().popGroup("InputBox");
 
 			setText(applyRangeAndStep(mValue));
+
 			mHasInputFocus = false;
+			onFocusChanged(false);
 		}
 	}
 

+ 4 - 0
Source/BansheeEditor/Source/BsGUISliderField.cpp

@@ -148,13 +148,17 @@ namespace BansheeEngine
 		if (focus)
 		{
 			UndoRedo::instance().pushGroup("InputBox");
+
 			mHasInputFocus = true;
+			onFocusChanged(true);
 		}
 		else
 		{
 			UndoRedo::instance().popGroup("InputBox");
 			inputBoxValueChanged();
+
 			mHasInputFocus = false;
+			onFocusChanged(false);
 		}
 	}
 

+ 4 - 0
Source/BansheeEditor/Source/BsGUITextField.cpp

@@ -198,12 +198,16 @@ namespace BansheeEngine
 		if (focus)
 		{
 			UndoRedo::instance().pushGroup("InputBox");
+
 			mHasInputFocus = true;
+			onFocusChanged(true);
 		}
 		else
 		{
 			UndoRedo::instance().popGroup("InputBox");
+
 			mHasInputFocus = false;
+			onFocusChanged(false);
 		}
 	}
 

+ 1 - 0
Source/BansheeEngine/Include/BsGUIInputBox.h

@@ -251,6 +251,7 @@ namespace BansheeEngine
 		bool mIsMultiline;
 		Vector2I mTextOffset;
 		bool mHasFocus;
+		UINT64 mFocusGainedFrame;
 		bool mIsMouseOver;
 		State mState;
 

+ 10 - 3
Source/BansheeEngine/Source/BsGUIInputBox.cpp

@@ -14,6 +14,7 @@
 #include "BsGUIInputSelection.h"
 #include "BsGUIContextMenu.h"
 #include "BsGUIHelper.h"
+#include "BsTime.h"
 
 namespace BansheeEngine
 {
@@ -29,8 +30,8 @@ namespace BansheeEngine
 	}
 
 	GUIInputBox::GUIInputBox(const String& styleName, const GUIDimensions& dimensions, bool multiline)
-		: GUIElement(styleName, dimensions), mIsMultiline(multiline), mHasFocus(false), mIsMouseOver(false)
-		, mState(State::Normal), mCaretShown(false), mSelectionShown(false), mDragInProgress(false)
+		: GUIElement(styleName, dimensions), mIsMultiline(multiline), mHasFocus(false), mFocusGainedFrame((UINT64)-1)
+		, mIsMouseOver(false), mState(State::Normal), mCaretShown(false), mSelectionShown(false), mDragInProgress(false)
 	{
 		mImageSprite = bs_new<ImageSprite>();
 		mTextSprite = bs_new<TextSprite>();
@@ -470,7 +471,12 @@ namespace BansheeEngine
 				}
 				else
 				{
-					clearSelection();
+					bool focusGainedThisFrame = mHasFocus && mFocusGainedFrame == gTime().getFrameIdx();
+
+					// We want to select all on focus gain, so don't override that
+					if(!focusGainedThisFrame)
+						clearSelection();
+
 					showCaret();
 				}
 
@@ -605,6 +611,7 @@ namespace BansheeEngine
 			gGUIManager().getInputSelectionTool()->selectAll();
 
 			mHasFocus = true;
+			mFocusGainedFrame = gTime().getFrameIdx();
 
 			Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 			if (origSize != newSize)

+ 47 - 44
Source/BansheeEngine/Source/BsGUIManager.cpp

@@ -1016,52 +1016,18 @@ namespace BansheeEngine
 		if(findElementUnderPointer(event.screenPos, buttonStates, event.shift, event.control, event.alt))
 			event.markAsUsed();
 
-		mMouseEvent = GUIMouseEvent(buttonStates, event.shift, event.control, event.alt);
-
-		GUIMouseButton guiButton = buttonToGUIButton(event.button);
-
-		// We only check for mouse down if mouse isn't already being held down, and we are hovering over an element
-		if(mActiveElements.size() == 0)
-		{
-			mNewActiveElements.clear();
-			for(auto& elementInfo : mElementsUnderPointer)
-			{
-				Vector2I localPos = getWidgetRelativePos(elementInfo.widget, event.screenPos);
-				mMouseEvent.setMouseDownData(localPos, guiButton);
-
-				bool processed = sendMouseEvent(elementInfo.element, mMouseEvent);
-
-				if(guiButton == GUIMouseButton::Left)
-				{
-					mDragState = DragState::HeldWithoutDrag;
-					mLastPointerClickPos = event.screenPos;
-				}
-
-				mNewActiveElements.push_back(ElementInfo(elementInfo.element, elementInfo.widget));
-				mActiveMouseButton = guiButton;
-
-				if(processed)
-				{
-					event.markAsUsed();
-					break;
-				}
-			}
-
-			mActiveElements.swap(mNewActiveElements);
-		}
-
+		// Determine elements that gained focus
 		mNewElementsInFocus.clear();
+
 		mCommandEvent = GUICommandEvent();
-		
-		// Determine elements that gained focus
 		mCommandEvent.setType(GUICommandEventType::FocusGained);
 
-		for(auto& elementInfo : mElementsUnderPointer)
+		for (auto& elementInfo : mElementsUnderPointer)
 		{
-			auto iterFind = std::find_if(begin(mElementsInFocus), end(mElementsInFocus), 
-				[=] (const ElementFocusInfo& x) { return x.element == elementInfo.element; });
+			auto iterFind = std::find_if(begin(mElementsInFocus), end(mElementsInFocus),
+				[=](const ElementFocusInfo& x) { return x.element == elementInfo.element; });
 
-			if(iterFind == mElementsInFocus.end())
+			if (iterFind == mElementsInFocus.end())
 			{
 				bool processed = sendCommandEvent(elementInfo.element, mCommandEvent);
 				mNewElementsInFocus.push_back(ElementFocusInfo(elementInfo.element, elementInfo.widget, processed));
@@ -1079,14 +1045,17 @@ namespace BansheeEngine
 		}
 
 		// Determine elements that lost focus
+		// Note: Focus loss must trigger before mouse press because things like input boxes often only confirm changes
+		// made to them when focus is lost. So if the user is confirming some input via a press of the button focus loss
+		// must trigger on the input box first to make sure its contents get saved.
 		mCommandEvent.setType(GUICommandEventType::FocusLost);
 
-		for(auto& elementInfo : mElementsInFocus)
+		for (auto& elementInfo : mElementsInFocus)
 		{
-			auto iterFind = std::find_if(begin(mNewElementsInFocus), end(mNewElementsInFocus), 
-				[=] (const ElementFocusInfo& x) { return x.element == elementInfo.element; });
+			auto iterFind = std::find_if(begin(mNewElementsInFocus), end(mNewElementsInFocus),
+				[=](const ElementFocusInfo& x) { return x.element == elementInfo.element; });
 
-			if(iterFind == mNewElementsInFocus.end())
+			if (iterFind == mNewElementsInFocus.end())
 			{
 				sendCommandEvent(elementInfo.element, mCommandEvent);
 			}
@@ -1094,6 +1063,40 @@ namespace BansheeEngine
 
 		mElementsInFocus.swap(mNewElementsInFocus);
 
+		// Send mouse press event
+		mMouseEvent = GUIMouseEvent(buttonStates, event.shift, event.control, event.alt);
+		GUIMouseButton guiButton = buttonToGUIButton(event.button);
+
+		// We only check for mouse down if mouse isn't already being held down, and we are hovering over an element
+		if(mActiveElements.size() == 0)
+		{
+			mNewActiveElements.clear();
+			for(auto& elementInfo : mElementsUnderPointer)
+			{
+				Vector2I localPos = getWidgetRelativePos(elementInfo.widget, event.screenPos);
+				mMouseEvent.setMouseDownData(localPos, guiButton);
+
+				bool processed = sendMouseEvent(elementInfo.element, mMouseEvent);
+
+				if(guiButton == GUIMouseButton::Left)
+				{
+					mDragState = DragState::HeldWithoutDrag;
+					mLastPointerClickPos = event.screenPos;
+				}
+
+				mNewActiveElements.push_back(ElementInfo(elementInfo.element, elementInfo.widget));
+				mActiveMouseButton = guiButton;
+
+				if(processed)
+				{
+					event.markAsUsed();
+					break;
+				}
+			}
+
+			mActiveElements.swap(mNewActiveElements);
+		}
+
 		// If right click try to open context menu
 		if(buttonStates[2] == true) 
 		{

+ 4 - 3
Source/BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -494,6 +494,8 @@ namespace BansheeEngine
 			// user has the ability to split them externally.
 			if(isFirstClip && !splits.empty())
 			{
+				float secondsPerFrame = 1.0f / clip.sampleRate;
+
 				for(auto& split : splits)
 				{
 					SPtr<AnimationCurves> splitClipCurve = bs_shared_ptr_new<AnimationCurves>();
@@ -512,9 +514,8 @@ namespace BansheeEngine
 							if (numFrames == 0)
 								continue;
 
-							UINT32 lastFrame = numFrames - 1;
-							float startTime = animCurve.getKeyFrame(std::min(split.startFrame, lastFrame)).time;
-							float endTime = animCurve.getKeyFrame(std::min(split.endFrame, lastFrame)).time;
+							float startTime = split.startFrame * secondsPerFrame;
+							float endTime = split.endFrame * secondsPerFrame;
 
 							outCurves[i].curve = inCurves[i].curve.split(startTime, endTime);
 

+ 3 - 2
Source/MBansheeEditor/GUI/GUIListField.cs

@@ -572,7 +572,8 @@ namespace BansheeEditor
 
             ElementType[] newArray = new ElementType[size];
 
-            int maxSize = MathEx.Min(size, array.GetLength(0));
+            int oldSize = array.GetLength(0);
+            int maxSize = MathEx.Min(size, oldSize);
             for (int i = 0; i < maxSize; i++)
                 newArray.SetValue(array.GetValue(i), i);
 
@@ -980,7 +981,7 @@ namespace BansheeEditor
         /// Refreshes the GUI for the list row and checks if anything was modified.
         /// </summary>
         /// <returns>State representing was anything modified between two last calls to <see cref="Refresh"/>.</returns>
-        internal protected virtual InspectableState Refresh()
+        protected internal virtual InspectableState Refresh()
         {
             InspectableState oldState = modifiedState;
             if (modifiedState.HasFlag(InspectableState.Modified))

+ 11 - 20
Source/MBansheeEditor/Inspectors/MeshInspector.cs

@@ -45,25 +45,7 @@ namespace BansheeEditor
         {
             MeshImportOptions newImportOptions = GetImportOptions();
 
-            bool rebuildGUI = false;
-
-            AnimationSplitInfo[] splitInfos = newImportOptions.AnimationClipSplits;
-            if (splitInfos == null)
-                rebuildGUI |= animSplitInfoField.Array != null;
-            else
-            {
-                if (animSplitInfoField.Array == null)
-                    rebuildGUI = true;
-                else
-                    rebuildGUI |= splitInfos.Length != animSplitInfoField.Array.GetLength(0);
-            }
-
-            if (rebuildGUI)
-                BuildGUI();
-
-            InspectableState splitInfosModified = animSplitInfoField.Refresh();
-            if (splitInfosModified == InspectableState.Modified)
-                newImportOptions.AnimationClipSplits = splitInfos;
+            animSplitInfoField.Refresh();
 
             normalsField.Value = newImportOptions.ImportNormals;
             tangentsField.Value = newImportOptions.ImportTangents;
@@ -124,7 +106,7 @@ namespace BansheeEditor
 
             animSplitInfoField = GUIArrayField<AnimationSplitInfo, AnimSplitArrayRow>.Create(
                 new LocEdString("Animation splits"), splitInfos, Layout);
-            animSplitInfoField.OnChanged += x => { splitInfos = x; importOptions.AnimationClipSplits = x; };
+            animSplitInfoField.OnChanged += x => { splitInfos = x; };
             animSplitInfoField.IsExpanded = Persistent.GetBool("animSplitInfos_Expanded");
             animSplitInfoField.OnExpand += x => Persistent.SetBool("animSplitInfos_Expanded", x);
 
@@ -173,6 +155,8 @@ namespace BansheeEditor
             Mesh mesh = (Mesh)InspectedObject;
             string resourcePath = ProjectLibrary.GetPath(mesh);
 
+            importOptions.AnimationClipSplits = splitInfos;
+
             ProjectLibrary.Reimport(resourcePath, importOptions, true);
         }
 
@@ -189,6 +173,13 @@ namespace BansheeEditor
             /// <inheritdoc/>
             protected override GUILayoutX CreateGUI(GUILayoutY layout)
             {
+                AnimationSplitInfo rowSplitInfo = GetValue<AnimationSplitInfo>();
+                if (rowSplitInfo == null)
+                {
+                    rowSplitInfo = new AnimationSplitInfo();
+                    SetValue(rowSplitInfo);
+                }
+
                 GUILayoutX titleLayout = layout.AddLayoutX();
                 GUILayoutX contentLayout = layout.AddLayoutX();