Procházet zdrojové kódy

Multi-select for TreeView working

Marko Pintera před 12 roky
rodič
revize
68aa0ab4f7

+ 3 - 0
CamelotClient/Include/BsEditorGUI.h

@@ -111,6 +111,9 @@ namespace BansheeEditor
 		static const CM::String TreeViewSelectionBackground;
 		static const CM::String TreeViewSelectionBackground;
 		static const CM::String TreeViewEditBox;
 		static const CM::String TreeViewEditBox;
 
 
+		static const CM::String TreeViewElementHighlight;
+		static const CM::String TreeViewElementSepHighlight;
+
 		static BS::HSpriteTexture getTexture(const CM::String& name);
 		static BS::HSpriteTexture getTexture(const CM::String& name);
 	};
 	};
 }
 }

+ 22 - 0
CamelotClient/Source/BsEditorGUI.cpp

@@ -113,6 +113,8 @@ namespace BansheeEditor
 
 
 	const String EditorGUI::TreeViewSelectionBackground = "TreeViewSelectionBackground.psd";
 	const String EditorGUI::TreeViewSelectionBackground = "TreeViewSelectionBackground.psd";
 	const String EditorGUI::TreeViewEditBox = "TreeViewEditBox.psd";
 	const String EditorGUI::TreeViewEditBox = "TreeViewEditBox.psd";
+	const String EditorGUI::TreeViewElementHighlight = "TreeViewElementHighlight.psd";
+	const String EditorGUI::TreeViewElementSepHighlight = "TreeViewElementSepHighlight.psd";
 
 
 	EditorGUI::EditorGUI()
 	EditorGUI::EditorGUI()
 	{
 	{
@@ -702,6 +704,26 @@ namespace BansheeEditor
 		treeViewEditBox.textVertAlign = TVA_Top;
 		treeViewEditBox.textVertAlign = TVA_Top;
 
 
 		mSkin.setStyle(GUITreeViewEditBox::getGUITypeName(), treeViewEditBox);
 		mSkin.setStyle(GUITreeViewEditBox::getGUITypeName(), treeViewEditBox);
+
+		// Element highlight
+		GUIElementStyle treeViewElementHighlight;
+		treeViewElementHighlight.normal.texture = getTexture(TreeViewElementHighlight);
+		treeViewElementHighlight.border.left = 1;
+		treeViewElementHighlight.border.right = 1;
+		treeViewElementHighlight.border.top = 1;
+		treeViewElementHighlight.border.bottom = 1;
+
+		mSkin.setStyle("TreeViewElementHighlight", treeViewElementHighlight);
+
+		// Element separator highlight
+		GUIElementStyle treeViewElementSepHighlight;
+		treeViewElementSepHighlight.normal.texture = getTexture(TreeViewElementSepHighlight);
+		treeViewElementSepHighlight.border.left = 1;
+		treeViewElementSepHighlight.border.right = 1;
+		treeViewElementSepHighlight.border.top = 1;
+		treeViewElementSepHighlight.border.bottom = 1;
+
+		mSkin.setStyle("TreeViewElementSepHighlight", treeViewElementSepHighlight);
 	}
 	}
 
 
 	HSpriteTexture EditorGUI::getTexture(const CM::String& name)
 	HSpriteTexture EditorGUI::getTexture(const CM::String& name)

+ 33 - 24
CamelotClient/Source/BsGUISceneTreeView.cpp

@@ -194,8 +194,8 @@ namespace BansheeEditor
 						if(!mTempToDelete[i])
 						if(!mTempToDelete[i])
 							continue;
 							continue;
 
 
-						if(current->mIsSelected)
-							unselectElement(current);
+						if(current->mChildren[i]->mIsSelected)
+							unselectElement(current->mChildren[i]);
 
 
 						cm_delete(current->mChildren[i]);
 						cm_delete(current->mChildren[i]);
 					}
 					}
@@ -287,7 +287,7 @@ namespace BansheeEditor
 						current->mFoldoutBtn = nullptr;
 						current->mFoldoutBtn = nullptr;
 					}
 					}
 
 
-					if(current->mIsVisible && current->mIsSelected)
+					if(visibilityChanged && current->mIsSelected)
 						unselectElement(current);
 						unselectElement(current);
 				}
 				}
 
 
@@ -311,12 +311,18 @@ namespace BansheeEditor
 		if(event.getType() == GUIMouseEventType::MouseUp)
 		if(event.getType() == GUIMouseEventType::MouseUp)
 		{
 		{
 			const GUISceneTreeView::InteractableElement* element = findElementUnderCoord(event.getPosition());
 			const GUISceneTreeView::InteractableElement* element = findElementUnderCoord(event.getPosition());
+			TreeElement* treeElement = nullptr;
 
 
 			if(element != nullptr && element->isTreeElement())
 			if(element != nullptr && element->isTreeElement())
+			{
+				treeElement = interactableToRealElement(*element);
+			}
+
+			if(treeElement != nullptr && event.getPosition().x >= treeElement->mElement->getBounds().x)
 			{
 			{
 				if(event.isCtrlDown())
 				if(event.isCtrlDown())
 				{
 				{
-					selectElement(interactableToRealElement(*element));
+					selectElement(treeElement);
 				}
 				}
 				else if(event.isShiftDown())
 				else if(event.isShiftDown())
 				{
 				{
@@ -356,7 +362,7 @@ namespace BansheeEditor
 								for(;iterStartFind != (iterEndFind + 1); ++iterStartFind)
 								for(;iterStartFind != (iterEndFind + 1); ++iterStartFind)
 								{
 								{
 									if(iterStartFind->isTreeElement())
 									if(iterStartFind->isTreeElement())
-										selectElement(interactableToRealElement(*element));
+										selectElement(interactableToRealElement(*iterStartFind));
 								}
 								}
 							}
 							}
 							else if(iterEndFind < iterStartFind)
 							else if(iterEndFind < iterStartFind)
@@ -364,31 +370,31 @@ namespace BansheeEditor
 								for(;iterEndFind != (iterStartFind + 1); ++iterEndFind)
 								for(;iterEndFind != (iterStartFind + 1); ++iterEndFind)
 								{
 								{
 									if(iterEndFind->isTreeElement())
 									if(iterEndFind->isTreeElement())
-										selectElement(interactableToRealElement(*element));
+										selectElement(interactableToRealElement(*iterEndFind));
 								}
 								}
 							}
 							}
 							else
 							else
-								selectElement(interactableToRealElement(*element));
+								selectElement(treeElement);
 						}
 						}
 
 
 						if(!foundStart || !foundEnd)
 						if(!foundStart || !foundEnd)
-							selectElement(interactableToRealElement(*element));
+							selectElement(treeElement);
 					}
 					}
 					else
 					else
 					{
 					{
-						selectElement(interactableToRealElement(*element));
+						selectElement(treeElement);
 					}
 					}
 				}
 				}
 				else
 				else
 				{
 				{
 					unselectAll();
 					unselectAll();
-					selectElement(interactableToRealElement(*element));
+					selectElement(treeElement);
 				}
 				}
-			}
 
 
-			markContentAsDirty();
+				markContentAsDirty();
 
 
-			return true;
+				return true;
+			}
 		}
 		}
 
 
 		return false;
 		return false;
@@ -423,6 +429,8 @@ namespace BansheeEditor
 		if(iterFind == mSelectedElements.end())
 		if(iterFind == mSelectedElements.end())
 		{
 		{
 			GUITexture* background = GUITexture::create(_getParentWidget(), mSelectionBackgroundStyle);
 			GUITexture* background = GUITexture::create(_getParentWidget(), mSelectionBackgroundStyle);
+			_registerChildElement(background);
+
 			element->mIsSelected = true;
 			element->mIsSelected = true;
 
 
 			mSelectedElements.push_back(SelectedElement(element, background));
 			mSelectedElements.push_back(SelectedElement(element, background));
@@ -530,8 +538,6 @@ namespace BansheeEditor
 			Stack<UpdateTreeElement>::type todo;
 			Stack<UpdateTreeElement>::type todo;
 			todo.push(UpdateTreeElement(&mRootElement, 0));
 			todo.push(UpdateTreeElement(&mRootElement, 0));
 
 
-			optimalSize.y += ELEMENT_EXTRA_SPACING;
-
 			while(!todo.empty())
 			while(!todo.empty())
 			{
 			{
 				UpdateTreeElement currentUpdateElement = todo.top();
 				UpdateTreeElement currentUpdateElement = todo.top();
@@ -622,11 +628,6 @@ namespace BansheeEditor
 			UINT32 indent = currentUpdateElement.indent;
 			UINT32 indent = currentUpdateElement.indent;
 			todo.pop();
 			todo.pop();
 
 
-			if(current->mParent != nullptr && current->mSortedIdx == 0)
-			{
-				mVisibleElements.push_back(InteractableElement(current->mParent, 0, RectI(x, offset.y, width, ELEMENT_EXTRA_SPACING)));
-			}
-
 			INT32 btnHeight = 0;
 			INT32 btnHeight = 0;
 			INT32 yOffset = 0;
 			INT32 yOffset = 0;
 			if(current->mElement != nullptr)
 			if(current->mElement != nullptr)
@@ -634,7 +635,11 @@ namespace BansheeEditor
 				Vector2I elementSize = current->mElement->_getOptimalSize();
 				Vector2I elementSize = current->mElement->_getOptimalSize();
 				btnHeight = elementSize.y;
 				btnHeight = elementSize.y;
 
 
+				mVisibleElements.push_back(InteractableElement(current->mParent, current->mSortedIdx * 2 + 0, RectI(x, offset.y, width, ELEMENT_EXTRA_SPACING)));
+				mVisibleElements.push_back(InteractableElement(current->mParent, current->mSortedIdx * 2 + 1, RectI(x, offset.y + ELEMENT_EXTRA_SPACING, width, btnHeight)));
+
 				offset.x = INITIAL_INDENT_OFFSET + indent * INDENT_SIZE;
 				offset.x = INITIAL_INDENT_OFFSET + indent * INDENT_SIZE;
+				offset.y += ELEMENT_EXTRA_SPACING;
 
 
 				current->mElement->_setOffset(offset);
 				current->mElement->_setOffset(offset);
 				current->mElement->_setWidth(elementSize.x);
 				current->mElement->_setWidth(elementSize.x);
@@ -645,10 +650,7 @@ namespace BansheeEditor
 				RectI elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
 				RectI elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
 				current->mElement->_setClipRect(elemClipRect);
 				current->mElement->_setClipRect(elemClipRect);
 
 
-				mVisibleElements.push_back(InteractableElement(current->mParent, current->mSortedIdx * 2 + 1, RectI(x, offset.y, width, btnHeight)));
-				mVisibleElements.push_back(InteractableElement(current->mParent, current->mSortedIdx * 2 + 2, RectI(x, offset.y + btnHeight, width, ELEMENT_EXTRA_SPACING)));
-
-				yOffset = btnHeight + ELEMENT_EXTRA_SPACING;
+				yOffset = btnHeight;
 			}
 			}
 
 
 			if(current->mFoldoutBtn != nullptr)
 			if(current->mFoldoutBtn != nullptr)
@@ -658,6 +660,8 @@ namespace BansheeEditor
 				offset.x -= std::min((INT32)INITIAL_INDENT_OFFSET, elementSize.y);
 				offset.x -= std::min((INT32)INITIAL_INDENT_OFFSET, elementSize.y);
 
 
 				Vector2I myOffset = offset;
 				Vector2I myOffset = offset;
+				myOffset.y -= 2; // TODO: Arbitrary offset, I should adjust it based on font baseline so that the button is nicely centered on text
+
 				if(elementSize.y > btnHeight)
 				if(elementSize.y > btnHeight)
 				{
 				{
 					UINT32 diff = elementSize.y - btnHeight;
 					UINT32 diff = elementSize.y - btnHeight;
@@ -694,6 +698,11 @@ namespace BansheeEditor
 			}
 			}
 		}
 		}
 
 
+		UINT32 remainingHeight = (UINT32)std::max(0, (INT32)height - (offset.y - y));
+
+		if(remainingHeight > 0)
+			mVisibleElements.push_back(InteractableElement(&mRootElement, (UINT32)mRootElement.mChildren.size() * 2, RectI(x, offset.y, width, remainingHeight)));
+
 		for(auto selectedElem : mSelectedElements)
 		for(auto selectedElem : mSelectedElements)
 		{
 		{
 			GUILabel* targetElement = selectedElem.element->mElement;
 			GUILabel* targetElement = selectedElem.element->mElement;