Procházet zdrojové kódy

Refactored how GUI elements gain and lose focus
Removed keyboard focus related stuff
Added better skin for TreeViewEditBox
Fixed a bug where object wouldn't be marked dirty if re-enabled after being disabled

Marko Pintera před 12 roky
rodič
revize
7b9d01ccaf

+ 1 - 1
BansheeEngine/Include/BsGUICommandEvent.h

@@ -6,7 +6,7 @@ namespace BansheeEngine
 {
 	enum class GUICommandEventType
 	{
-		Redraw, CursorMoveLeft, CursorMoveRight, CursorMoveUp, CursorMoveDown, 
+		Redraw, FocusLost, FocusGained, CursorMoveLeft, CursorMoveRight, CursorMoveUp, CursorMoveDown, 
 		SelectLeft, SelectRight, SelectUp, SelectDown, Undo, Redo, Rename,
 		Escape, Delete, Backspace, Return, SelectAll, Copy, Cut, Paste, Tab
 	};

+ 0 - 1
BansheeEngine/Include/BsGUIElement.h

@@ -95,7 +95,6 @@ namespace BansheeEngine
 		void _setWidth(CM::UINT32 width);
 		void _setHeight(CM::UINT32 height);
 		void _setClipRect(const CM::RectI& clipRect);
-		virtual void _setFocus(bool focus) {}
 		virtual void _changeParentWidget(GUIWidget* widget);
 
 		CM::UINT32 _getWidth() const { return mWidth; }

+ 0 - 1
BansheeEngine/Include/BsGUIElementBase.h

@@ -53,7 +53,6 @@ namespace BansheeEngine
 		GUIElementBase* _getParent() const { return mParentElement; }
 
 		void _markAsClean() { mIsDirty = 0; }
-		virtual void _setFocus(bool focus) {}
 
 		bool _isContentDirty() const;
 		bool _isMeshDirty() const; 

+ 0 - 1
BansheeEngine/Include/BsGUIInputBox.h

@@ -63,7 +63,6 @@ namespace BansheeEngine
 		virtual CM::RectI _getTextInputRect() const;
 
 		virtual CM::UINT32 _getRenderElementDepth(CM::UINT32 renderElementIdx) const;
-		virtual void _setFocus(bool focus);
 
 		virtual GUIContextMenu* getContextMenu() const;
 	private:

+ 1 - 1
BansheeEngine/Source/BsGUIElementBase.cpp

@@ -68,8 +68,8 @@ namespace BansheeEngine
 	void GUIElementBase::enableRecursively()
 	{
 		// Make sure to mark everything as dirty, as we didn't track any dirty flags while the element was disabled
-		markContentAsDirty();
 		mIsDisabled = false;
+		markContentAsDirty();
 
 		for(auto& elem : mChildren)
 		{

+ 20 - 18
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -533,6 +533,26 @@ namespace BansheeEngine
 			return true;
 		}
 
+		if(ev.getType() == GUICommandEventType::FocusGained)
+		{
+			mActiveTexture = mStyle->focused.texture;
+			markContentAsDirty();
+
+			mHasFocus = true;
+			return true;
+		}
+		
+		if(ev.getType() == GUICommandEventType::FocusLost)
+		{
+			mActiveTexture = mStyle->normal.texture;
+			hideCaret();
+			clearSelection();
+			markContentAsDirty();
+
+			mHasFocus = false;
+			return true;
+		}
+		
 		if(ev.getType() == GUICommandEventType::Backspace)
 		{
 			if(mText.size() > 0)
@@ -958,24 +978,6 @@ namespace BansheeEngine
 		return textDesc;
 	}
 
-	void GUIInputBox::_setFocus(bool focus)
-	{
-		if(focus)
-		{
-			mActiveTexture = mStyle->focused.texture;
-			markContentAsDirty();
-		}
-		else
-		{
-			mActiveTexture = mStyle->normal.texture;
-			hideCaret();
-			clearSelection();
-			markContentAsDirty();
-		}
-
-		mHasFocus = focus;
-	}
-
 	GUIContextMenu* GUIInputBox::getContextMenu() const
 	{
 		static bool initialized = false;

+ 8 - 5
BansheeEngine/Source/BsGUIManager.cpp

@@ -829,8 +829,11 @@ namespace BansheeEngine
 		}
 
 		mNewElementsInFocus.clear();
-
+		mCommandEvent = GUICommandEvent();
+		
 		// Determine elements that gained focus
+		mCommandEvent.setType(GUICommandEventType::FocusGained);
+
 		for(auto& elementInfo : mElementsUnderCursor)
 		{
 			mNewElementsInFocus.push_back(elementInfo);
@@ -840,12 +843,13 @@ namespace BansheeEngine
 
 			if(iterFind == mElementsInFocus.end())
 			{
-				// TODO - Send FocusGained event
-				elementInfo.element->_setFocus(true);
+				sendCommandEvent(elementInfo.widget, elementInfo.element, mCommandEvent);
 			}
 		}
 
 		// Determine elements that lost focus
+		mCommandEvent.setType(GUICommandEventType::FocusLost);
+
 		for(auto& elementInfo : mElementsInFocus)
 		{
 			auto iterFind = std::find_if(begin(mNewElementsInFocus), end(mNewElementsInFocus), 
@@ -853,8 +857,7 @@ namespace BansheeEngine
 
 			if(iterFind == mNewElementsInFocus.end())
 			{
-				// TODO - Send FocusLost event
-				elementInfo.element->_setFocus(false);
+				sendCommandEvent(elementInfo.widget, elementInfo.element, mCommandEvent);
 			}
 		}
 

+ 1 - 0
CamelotClient/Include/BsEditorGUI.h

@@ -109,6 +109,7 @@ namespace BansheeEditor
 		static const CM::String TreeViewExpandButtonOnHover;
 
 		static const CM::String TreeViewSelectionBackground;
+		static const CM::String TreeViewEditBox;
 
 		static BS::HSpriteTexture getTexture(const CM::String& name);
 	};

+ 23 - 1
CamelotClient/Source/BsEditorGUI.cpp

@@ -112,6 +112,7 @@ namespace BansheeEditor
 	const String EditorGUI::TreeViewExpandButtonOnHover = "TreeViewExpandButtonOnHover.psd";
 
 	const String EditorGUI::TreeViewSelectionBackground = "TreeViewSelectionBackground.psd";
+	const String EditorGUI::TreeViewEditBox = "TreeViewEditBox.psd";
 
 	EditorGUI::EditorGUI()
 	{
@@ -679,7 +680,28 @@ namespace BansheeEditor
 		mSkin.setStyle("TreeViewSelectionBackground", treeViewSelBackgroundStyle);
 
 		// Edit box
-		mSkin.setStyle(GUITreeViewEditBox::getGUITypeName(), inputBoxStyle);
+		GUIElementStyle treeViewEditBox;
+		treeViewEditBox.normal.texture = getTexture(TreeViewEditBox);
+		treeViewEditBox.hover.texture = treeViewEditBox.normal.texture;
+		treeViewEditBox.focused.texture = treeViewEditBox.normal.texture;
+		treeViewEditBox.active.texture = treeViewEditBox.normal.texture;
+		treeViewEditBox.border.left = 1;
+		treeViewEditBox.border.right = 1;
+		treeViewEditBox.border.top = 1;
+		treeViewEditBox.border.bottom = 1;
+		treeViewEditBox.margins.left = 1;
+		treeViewEditBox.margins.right = 1;
+		treeViewEditBox.margins.top = 1;
+		treeViewEditBox.margins.bottom = 1;
+		treeViewEditBox.fixedHeight = true;
+		treeViewEditBox.height = 13;
+		treeViewEditBox.minWidth = 10;
+		treeViewEditBox.font = font;
+		treeViewEditBox.fontSize = DefaultFontSize;
+		treeViewEditBox.textHorzAlign = THA_Left;
+		treeViewEditBox.textVertAlign = TVA_Top;
+
+		mSkin.setStyle(GUITreeViewEditBox::getGUITypeName(), treeViewEditBox);
 	}
 
 	HSpriteTexture EditorGUI::getTexture(const CM::String& name)

+ 12 - 52
TreeView.txt

@@ -1,16 +1,6 @@
-TreeView
-  - Name editing
-     - Detect mouse input in TreeView and if I double click over a GUILabel start rename
-     - Or if I select it and hit F2 also start rename
-     - Has callbacks with which it notifies TreeView of actual changes
-  - Selecting
-     - Clicking on a row of TreeView sets a flag that item is selected, and a GUIElement is created. 
-     - Element is positioned in updateLayoutInternal and it shows a different colored background
-  - Deleting
-      - Simply track currently selected element and Delete event
-
 TODO:
  - Add better TreeViewEditBox texture
+ - Callback on tree item select
  - In disableEdit make sure I actually apply name change
    - Use Undo/Redo system (TODO: Not implemented yet)
  - Clicking on an already selectecd element starts rename 
@@ -20,16 +10,6 @@ TODO:
  - Detect when I click outside of input box and disable edit (TODO: Need a way to easily detect this)
  - Delete
     - Needs Undo/Redo support
-
-
-Implementation steps:
- - Selection
-   - Clicking on element selects it, delete removes it, F2 renames is. Slow double click renames it.
-   - Rename implementation to follow, just set up an empty method for now
-   - Callback on selection
- - Rename implementation
-   - When rename is initiated hide the objects label and replace it with an input-box with the same text as a label
-   - Rename ends when user hits enter or click anywhere else but the rename box
  - Drag and drop
    - If a mouse drag is detected DragAndDropManager is activated
    - Element is not removed from its original position until drag is complete
@@ -39,13 +19,9 @@ Implementation steps:
  - Auto scroll
     - Sliding over top or bottom of the tree view while dragging an element will search GUIElement parents to find a ScrollArea. If it finds one it will attempt to scroll up or down.
 
-Detecting external clicks:
- - LostFocus event?
-   - Triggered when I click on another control within my own windows, or when controls parent window loses the focus himself
-   - Each GUIElement can implement acceptsMouseFocus event. If it does, then mouse click will cause a ReceivedFocus event.
-     - Mouse click on any other element, or window losing focus will trigger LostFocus events
- - I can replace clumsy Selective Input with this approach
- - DropDownBox can also use the same approach although I will likely need to convert DropDownBox to a GUIElement - DO THIS AFTER TreeView implementation is working
+Gained/Lost focus refactor:
+ - Add Window mouse hooks for detecting a mouse press outside of a window: http://www.codeproject.com/Articles/187869/Your-Desktop-and-Microsoft-s-SetWindowsHookEx
+ - Remove Selective input and port DropDownBox so it uses the focus system
 
  Other:
  - When dragging in tree view automatically expand mouse over elements
@@ -57,28 +33,12 @@ Detecting external clicks:
    - This is more of a problem with actual copying of SceneObjects (It's not implemented). I should be able to serialize, and then de-serialize with a new parent as a form of copy.
 
 
- ---------------------
-
- SHORTCUT BRAINSTORM:
-
- Remove pre-defined GUICommandEvents and InputCommandType. They cannot be easily extended and I will need their functionality when I add support for shortcuts! 
-INSTEAD:
- - Add GUIShortcutManager to BansheeEngine
- - Platform forwards all input commands to ShortcutManager instead of gInput (via a callback)
- - ShortcutManager checks if it has any registered shortcuts and if any are triggered it notifies GUIManager
- - Shortcuts change depending on active GUIElement
-   - Each GUIELement can provide a list of shortcuts it listens to
-   - OnFocusGained/OnFocusLost adds/removes items from the list
-   - If multiple elements are in focus, all of their shortcuts are registered but the callbacks just don't get triggered on those elements that don't have the triggered shortcut
-     - If two elements have the same shortcut, only one of them will trigger (undefined which)
- - (Obviously this functionality will need focusGained/focusLost functionality first)
-
-
-TODO: Can I integrate this with the input manager somehow?
- - NO - Shortcut system should be GUI only, while in-game input and in-game shortcuts will be handled manually.
+--------------------------------------------------
+LOW PRIORITY:
 
-When I implement focus gained/lost system, send keyboard input to all elements with focus. Remove "acceptsKeyboardFocus". Elements can choose to ignore keyboard focus by ignoring keyboard events.
-Remove Cut/Copy/Paste/Undo/Redo/Rename/SelectAll and similar shortcuts from InputCommands. Instead send generic shortcut commands whenever user presses some key (together with shift/ctrl/alt state).
-  - Some shift/ctrl combinations might not be general shortcuts, like shift + arrows for selection, in which case we send them as specific shortcuts instead of generic ones
-  - I should also add a GUIShortcutManager, as a centralized place for dealing with shortcuts (so that I my edit them at a later date)
-   - TODO - Figure out how would this work
+Shoutcuts ideas:
+Remove Cut/Copy/Paste/Undo/Redo/Rename/SelectAll and similar shortcuts from InputCommands. Instead send generic shortcut commands whenever user presses some key (with shift/ctrl/alt state).
+ - I will need some kind of generic shortcuts at some point so there is no point that Rename is hardcoded to F2
+ - I should also add a GUIShortcutManager, as a centralized place for dealing with shortcuts (so that I my edit them at a later date)
+  - TODO - Figure out how would this work. How would the centralized system know all of the UI shortcuts? Probably register them somehow on program start?
+ - This shortcut system would be separate from the input manager, and would not be meant for in-game use