|
@@ -1,40 +1,16 @@
|
|
|
#include "BsGUISceneTreeView.h"
|
|
#include "BsGUISceneTreeView.h"
|
|
|
-#include "BsGUIArea.h"
|
|
|
|
|
-#include "BsGUILayout.h"
|
|
|
|
|
-#include "BsGUITexture.h"
|
|
|
|
|
-#include "BsGUIButton.h"
|
|
|
|
|
-#include "BsGUILabel.h"
|
|
|
|
|
-#include "BsGUISpace.h"
|
|
|
|
|
-#include "BsGUIWidget.h"
|
|
|
|
|
-#include "BsGUIToggle.h"
|
|
|
|
|
-#include "BsGUITreeViewEditBox.h"
|
|
|
|
|
-#include "BsGUIMouseEvent.h"
|
|
|
|
|
-#include "BsGUISkin.h"
|
|
|
|
|
-#include "BsGUICommandEvent.h"
|
|
|
|
|
-#include "BsGUIVirtualButtonEvent.h"
|
|
|
|
|
#include "CmSceneObject.h"
|
|
#include "CmSceneObject.h"
|
|
|
#include "CmSceneManager.h"
|
|
#include "CmSceneManager.h"
|
|
|
|
|
+#include "BsGUISkin.h"
|
|
|
#include "BsCmdEditPlainFieldGO.h"
|
|
#include "BsCmdEditPlainFieldGO.h"
|
|
|
#include "BsDragAndDropManager.h"
|
|
#include "BsDragAndDropManager.h"
|
|
|
#include "BsCmdReparentSO.h"
|
|
#include "BsCmdReparentSO.h"
|
|
|
-#include "CmTime.h"
|
|
|
|
|
-#include "BsGUIScrollArea.h"
|
|
|
|
|
|
|
|
|
|
using namespace CamelotFramework;
|
|
using namespace CamelotFramework;
|
|
|
using namespace BansheeEngine;
|
|
using namespace BansheeEngine;
|
|
|
|
|
|
|
|
namespace BansheeEditor
|
|
namespace BansheeEditor
|
|
|
{
|
|
{
|
|
|
- const UINT32 GUISceneTreeView::ELEMENT_EXTRA_SPACING = 3;
|
|
|
|
|
- const UINT32 GUISceneTreeView::INDENT_SIZE = 10;
|
|
|
|
|
- const UINT32 GUISceneTreeView::INITIAL_INDENT_OFFSET = 16;
|
|
|
|
|
- const UINT32 GUISceneTreeView::DRAG_MIN_DISTANCE = 3;
|
|
|
|
|
- const float GUISceneTreeView::AUTO_EXPAND_DELAY_SEC = 0.5f;
|
|
|
|
|
- const float GUISceneTreeView::SCROLL_AREA_HEIGHT_PCT = 0.1f;
|
|
|
|
|
- const UINT32 GUISceneTreeView::SCROLL_SPEED_PX_PER_SEC = 25;
|
|
|
|
|
-
|
|
|
|
|
- VirtualButton GUISceneTreeView::mRenameVB = VirtualButton("Rename");
|
|
|
|
|
-
|
|
|
|
|
GUISceneTreeView::DraggedSceneObjects::DraggedSceneObjects(UINT32 numObjects)
|
|
GUISceneTreeView::DraggedSceneObjects::DraggedSceneObjects(UINT32 numObjects)
|
|
|
:numObjects(numObjects)
|
|
:numObjects(numObjects)
|
|
|
{
|
|
{
|
|
@@ -47,107 +23,18 @@ namespace BansheeEditor
|
|
|
objects = nullptr;
|
|
objects = nullptr;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- GUISceneTreeView::TreeElement::TreeElement()
|
|
|
|
|
- :mParent(nullptr), mFoldoutBtn(nullptr), mElement(nullptr), mIsSelected(false),
|
|
|
|
|
- mId(0), mIsExpanded(false), mSortedIdx(0), mIsDirty(false), mIsVisible(true)
|
|
|
|
|
- { }
|
|
|
|
|
-
|
|
|
|
|
- GUISceneTreeView::TreeElement::~TreeElement()
|
|
|
|
|
- {
|
|
|
|
|
- for(auto& child : mChildren)
|
|
|
|
|
- cm_delete(child);
|
|
|
|
|
-
|
|
|
|
|
- if(mFoldoutBtn != nullptr)
|
|
|
|
|
- GUIElement::destroy(mFoldoutBtn);
|
|
|
|
|
-
|
|
|
|
|
- if(mElement != nullptr)
|
|
|
|
|
- GUIElement::destroy(mElement);
|
|
|
|
|
-
|
|
|
|
|
- mChildren.clear();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- bool GUISceneTreeView::TreeElement::isParentRec(TreeElement* element) const
|
|
|
|
|
- {
|
|
|
|
|
- TreeElement* curParent = mParent;
|
|
|
|
|
- while(curParent != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- if(curParent == element)
|
|
|
|
|
- return true;
|
|
|
|
|
-
|
|
|
|
|
- curParent = curParent->mParent;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- GUISceneTreeView::TreeElement* GUISceneTreeView::InteractableElement::getTreeElement() const
|
|
|
|
|
- {
|
|
|
|
|
- if(!isTreeElement())
|
|
|
|
|
- return nullptr;
|
|
|
|
|
-
|
|
|
|
|
- UINT32 sortedIdx = (index - 1) / 2;
|
|
|
|
|
-
|
|
|
|
|
- auto findIter = std::find_if(parent->mChildren.begin(), parent->mChildren.end(),
|
|
|
|
|
- [&](const TreeElement* x) { return x->mSortedIdx == sortedIdx; });
|
|
|
|
|
-
|
|
|
|
|
- if(findIter != parent->mChildren.end())
|
|
|
|
|
- return *findIter;
|
|
|
|
|
-
|
|
|
|
|
- return nullptr;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
GUISceneTreeView::GUISceneTreeView(GUIWidget& parent, GUIElementStyle* backgroundStyle, GUIElementStyle* elementBtnStyle,
|
|
GUISceneTreeView::GUISceneTreeView(GUIWidget& parent, GUIElementStyle* backgroundStyle, GUIElementStyle* elementBtnStyle,
|
|
|
GUIElementStyle* foldoutBtnStyle, GUIElementStyle* selectionBackgroundStyle, GUIElementStyle* editBoxStyle,
|
|
GUIElementStyle* foldoutBtnStyle, GUIElementStyle* selectionBackgroundStyle, GUIElementStyle* editBoxStyle,
|
|
|
BS::GUIElementStyle* dragHighlightStyle, BS::GUIElementStyle* dragSepHighlightStyle, const GUILayoutOptions& layoutOptions)
|
|
BS::GUIElementStyle* dragHighlightStyle, BS::GUIElementStyle* dragSepHighlightStyle, const GUILayoutOptions& layoutOptions)
|
|
|
- :GUIElementContainer(parent, layoutOptions), mBackgroundStyle(backgroundStyle),
|
|
|
|
|
- mElementBtnStyle(elementBtnStyle), mFoldoutBtnStyle(foldoutBtnStyle), mEditBoxStyle(editBoxStyle), mEditElement(nullptr), mIsElementSelected(false),
|
|
|
|
|
- mNameEditBox(nullptr), mSelectionBackgroundStyle(selectionBackgroundStyle), mDragInProgress(nullptr), mDragHighlightStyle(dragHighlightStyle),
|
|
|
|
|
- mDragSepHighlightStyle(dragSepHighlightStyle), mDragHighlight(nullptr), mDragSepHighlight(nullptr), mMouseOverDragElement(nullptr), mMouseOverDragElementTime(0.0f),
|
|
|
|
|
- mScrollState(ScrollState::None), mLastScrollTime(0.0f)
|
|
|
|
|
|
|
+ :GUITreeView(parent, backgroundStyle, elementBtnStyle, foldoutBtnStyle, selectionBackgroundStyle, editBoxStyle, dragHighlightStyle,
|
|
|
|
|
+ dragSepHighlightStyle, layoutOptions)
|
|
|
{
|
|
{
|
|
|
- if(mBackgroundStyle == nullptr)
|
|
|
|
|
- mBackgroundStyle = parent.getSkin().getStyle("TreeViewBackground");
|
|
|
|
|
-
|
|
|
|
|
- if(mElementBtnStyle == nullptr)
|
|
|
|
|
- mElementBtnStyle = parent.getSkin().getStyle("TreeViewElementBtn");
|
|
|
|
|
-
|
|
|
|
|
- if(mFoldoutBtnStyle == nullptr)
|
|
|
|
|
- mFoldoutBtnStyle = parent.getSkin().getStyle("TreeViewFoldoutBtn");
|
|
|
|
|
-
|
|
|
|
|
- if(mSelectionBackgroundStyle == nullptr)
|
|
|
|
|
- mSelectionBackgroundStyle = parent.getSkin().getStyle("TreeViewSelectionBackground");
|
|
|
|
|
-
|
|
|
|
|
- if(mEditBoxStyle == nullptr)
|
|
|
|
|
- mEditBoxStyle = parent.getSkin().getStyle("TreeViewEditBox");
|
|
|
|
|
-
|
|
|
|
|
- if(mDragHighlightStyle == nullptr)
|
|
|
|
|
- mDragHighlightStyle = parent.getSkin().getStyle("TreeViewElementHighlight");
|
|
|
|
|
-
|
|
|
|
|
- if(mDragSepHighlightStyle == nullptr)
|
|
|
|
|
- mDragSepHighlightStyle = parent.getSkin().getStyle("TreeViewElementSepHighlight");
|
|
|
|
|
-
|
|
|
|
|
- mBackgroundImage = GUITexture::create(parent, mBackgroundStyle);
|
|
|
|
|
- mNameEditBox = GUITreeViewEditBox::create(parent, mEditBoxStyle);
|
|
|
|
|
- mNameEditBox->disableRecursively();
|
|
|
|
|
-
|
|
|
|
|
- mNameEditBox->onInputConfirmed.connect(boost::bind(&GUISceneTreeView::onEditAccepted, this));
|
|
|
|
|
- mNameEditBox->onInputCanceled.connect(boost::bind(&GUISceneTreeView::onEditCanceled, this));
|
|
|
|
|
-
|
|
|
|
|
- mDragHighlight = GUITexture::create(parent, mDragHighlightStyle);
|
|
|
|
|
- mDragSepHighlight = GUITexture::create(parent, mDragSepHighlightStyle);
|
|
|
|
|
-
|
|
|
|
|
- mDragHighlight->disableRecursively();
|
|
|
|
|
- mDragSepHighlight->disableRecursively();
|
|
|
|
|
-
|
|
|
|
|
- _registerChildElement(mBackgroundImage);
|
|
|
|
|
- _registerChildElement(mNameEditBox);
|
|
|
|
|
- _registerChildElement(mDragHighlight);
|
|
|
|
|
- _registerChildElement(mDragSepHighlight);
|
|
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
GUISceneTreeView::~GUISceneTreeView()
|
|
GUISceneTreeView::~GUISceneTreeView()
|
|
|
{
|
|
{
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
GUISceneTreeView* GUISceneTreeView::create(GUIWidget& parent, GUIElementStyle* backgroundStyle, GUIElementStyle* elementBtnStyle,
|
|
GUISceneTreeView* GUISceneTreeView::create(GUIWidget& parent, GUIElementStyle* backgroundStyle, GUIElementStyle* elementBtnStyle,
|
|
@@ -166,1148 +53,200 @@ namespace BansheeEditor
|
|
|
foldoutBtnStyle, selectionBackgroundStyle, editBoxStyle, dragHighlightStyle, dragSepHighlightStyle, GUILayoutOptions::create(options, &GUISkin::DefaultStyle));
|
|
foldoutBtnStyle, selectionBackgroundStyle, editBoxStyle, dragHighlightStyle, dragSepHighlightStyle, GUILayoutOptions::create(options, &GUISkin::DefaultStyle));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void GUISceneTreeView::update()
|
|
|
|
|
|
|
+ void GUISceneTreeView::updateTreeElement(SceneTreeElement* element, bool visible)
|
|
|
{
|
|
{
|
|
|
- // Attempt to auto-expand elements we are dragging over
|
|
|
|
|
- if(DragAndDropManager::instance().isDragInProgress() && DragAndDropManager::instance().getDragTypeId() == (UINT32)DragAndDropType::SceneObject)
|
|
|
|
|
- {
|
|
|
|
|
- const GUISceneTreeView::InteractableElement* element = findElementUnderCoord(mDragPosition);
|
|
|
|
|
- temporarilyExpandElement(element);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ HSceneObject currentSO = element->mSceneObject;
|
|
|
|
|
|
|
|
- // NOTE - Instead of iterating through every visible element and comparing it with internal values,
|
|
|
|
|
- // I might just want to add callbacks to SceneManager that notify me of any changes and then only perform
|
|
|
|
|
- // update if anything is actually dirty
|
|
|
|
|
-
|
|
|
|
|
- struct UpdateTreeElement
|
|
|
|
|
|
|
+ // Check if SceneObject has changed in any way and update the tree element
|
|
|
|
|
+ if(visible)
|
|
|
{
|
|
{
|
|
|
- UpdateTreeElement(TreeElement* element, UINT32 seqIdx, bool visible)
|
|
|
|
|
- :element(element), seqIdx(seqIdx), visible(visible)
|
|
|
|
|
- { }
|
|
|
|
|
-
|
|
|
|
|
- TreeElement* element;
|
|
|
|
|
- UINT32 seqIdx;
|
|
|
|
|
- bool visible;
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ bool completeMatch = (UINT32)element->mChildren.size() == currentSO->getNumChildren();
|
|
|
|
|
|
|
|
- HSceneObject root = CM::gSceneManager().getRootNode();
|
|
|
|
|
- mRootElement.mSceneObject = root;
|
|
|
|
|
- mRootElement.mId = root->getId();
|
|
|
|
|
- mRootElement.mSortedIdx = 0;
|
|
|
|
|
- mRootElement.mIsExpanded = true;
|
|
|
|
|
-
|
|
|
|
|
- Stack<UpdateTreeElement>::type todo;
|
|
|
|
|
- todo.push(UpdateTreeElement(&mRootElement, 0, true));
|
|
|
|
|
-
|
|
|
|
|
- while(!todo.empty())
|
|
|
|
|
- {
|
|
|
|
|
- UpdateTreeElement updateElement = todo.top();
|
|
|
|
|
- TreeElement* current = updateElement.element;
|
|
|
|
|
- HSceneObject currentSO = current->mSceneObject;
|
|
|
|
|
- todo.pop();
|
|
|
|
|
-
|
|
|
|
|
- // Check if SceneObject has changed in any way and update the tree element
|
|
|
|
|
- if(updateElement.visible)
|
|
|
|
|
|
|
+ // Early exit case - Most commonly there will be no changes between active and cached data so
|
|
|
|
|
+ // we first do a quick check in order to avoid expensive comparison later
|
|
|
|
|
+ if(completeMatch)
|
|
|
{
|
|
{
|
|
|
- bool completeMatch = (UINT32)current->mChildren.size() == currentSO->getNumChildren();
|
|
|
|
|
-
|
|
|
|
|
- // Early exit case - Most commonly there will be no changes between active and cached data so
|
|
|
|
|
- // we first do a quick check in order to avoid expensive comparison later
|
|
|
|
|
- if(completeMatch)
|
|
|
|
|
|
|
+ for(UINT32 i = 0; i < currentSO->getNumChildren(); i++)
|
|
|
{
|
|
{
|
|
|
- for(UINT32 i = 0; i < currentSO->getNumChildren(); i++)
|
|
|
|
|
|
|
+ UINT32 curId = currentSO->getChild(i)->getId();
|
|
|
|
|
+ if(curId != element->mChildren[i]->mId)
|
|
|
{
|
|
{
|
|
|
- UINT32 curId = currentSO->getChild(i)->getId();
|
|
|
|
|
- if(curId != current->mChildren[i]->mId)
|
|
|
|
|
- {
|
|
|
|
|
- completeMatch = false;
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Not a complete match, compare everything and insert/delete elements as needed
|
|
|
|
|
- if(!completeMatch)
|
|
|
|
|
- {
|
|
|
|
|
- Vector<TreeElement*>::type newChildren;
|
|
|
|
|
-
|
|
|
|
|
- mTempToDelete.resize(current->mChildren.size());
|
|
|
|
|
- for(UINT32 i = 0; i < (UINT32)current->mChildren.size(); i++)
|
|
|
|
|
- mTempToDelete[i] = true;
|
|
|
|
|
-
|
|
|
|
|
- for(UINT32 i = 0; i < currentSO->getNumChildren(); i++)
|
|
|
|
|
- {
|
|
|
|
|
- HSceneObject currentSOChild = currentSO->getChild(i);
|
|
|
|
|
- UINT32 curId = currentSOChild->getId();
|
|
|
|
|
- bool found = false;
|
|
|
|
|
- for(UINT32 j = 0; j < current->mChildren.size(); j++)
|
|
|
|
|
- {
|
|
|
|
|
- TreeElement* currentChild = current->mChildren[j];
|
|
|
|
|
-
|
|
|
|
|
- if(curId == currentChild->mId)
|
|
|
|
|
- {
|
|
|
|
|
- mTempToDelete[j] = false;
|
|
|
|
|
- currentChild->mIsDirty = true;
|
|
|
|
|
- currentChild->mSortedIdx = (UINT32)newChildren.size();
|
|
|
|
|
- newChildren.push_back(currentChild);
|
|
|
|
|
-
|
|
|
|
|
- found = true;
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(!found)
|
|
|
|
|
- {
|
|
|
|
|
- TreeElement* newChild = cm_new<TreeElement>();
|
|
|
|
|
- newChild->mParent = current;
|
|
|
|
|
- newChild->mSceneObject = currentSOChild;
|
|
|
|
|
- newChild->mId = currentSOChild->getId();
|
|
|
|
|
- newChild->mName = currentSOChild->getName();
|
|
|
|
|
- newChild->mSortedIdx = (UINT32)newChildren.size();
|
|
|
|
|
- newChild->mIsDirty = true;
|
|
|
|
|
-
|
|
|
|
|
- newChildren.push_back(newChild);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- for(UINT32 i = 0; i < current->mChildren.size(); i++)
|
|
|
|
|
- {
|
|
|
|
|
- if(!mTempToDelete[i])
|
|
|
|
|
- continue;
|
|
|
|
|
-
|
|
|
|
|
- deleteTreeElement(current->mChildren[i]);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- current->mChildren = newChildren;
|
|
|
|
|
- current->mIsDirty = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Check if name needs updating
|
|
|
|
|
- const String& name = current->mSceneObject->getName();
|
|
|
|
|
- if(current->mName != name)
|
|
|
|
|
- {
|
|
|
|
|
- current->mName = name;
|
|
|
|
|
- current->mIsDirty = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Calculate the sorted index of the element based on its name
|
|
|
|
|
- TreeElement* parent = current->mParent;
|
|
|
|
|
- if(current->mIsDirty && parent != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- for(UINT32 i = 0; i < (UINT32)parent->mChildren.size(); i++)
|
|
|
|
|
- {
|
|
|
|
|
- INT32 stringCompare = current->mName.compare(parent->mChildren[i]->mName);
|
|
|
|
|
- if(stringCompare > 0)
|
|
|
|
|
- {
|
|
|
|
|
- if(current->mSortedIdx < parent->mChildren[i]->mSortedIdx)
|
|
|
|
|
- std::swap(current->mSortedIdx, parent->mChildren[i]->mSortedIdx);
|
|
|
|
|
- }
|
|
|
|
|
- else if(stringCompare < 0)
|
|
|
|
|
- {
|
|
|
|
|
- if(current->mSortedIdx > parent->mChildren[i]->mSortedIdx)
|
|
|
|
|
- std::swap(current->mSortedIdx, parent->mChildren[i]->mSortedIdx);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ completeMatch = false;
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- bool visibilityChanged = false;
|
|
|
|
|
- if(current->mIsVisible != updateElement.visible)
|
|
|
|
|
- {
|
|
|
|
|
- visibilityChanged = true;
|
|
|
|
|
- current->mIsVisible = updateElement.visible;
|
|
|
|
|
- current->mIsDirty = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(current->mIsDirty && current != &mRootElement)
|
|
|
|
|
|
|
+ // Not a complete match, compare everything and insert/delete elements as needed
|
|
|
|
|
+ if(!completeMatch)
|
|
|
{
|
|
{
|
|
|
- if(updateElement.visible)
|
|
|
|
|
|
|
+ Vector<TreeElement*>::type newChildren;
|
|
|
|
|
+
|
|
|
|
|
+ bool* tempToDelete = (bool*)stackAlloc(sizeof(bool) * (UINT32)element->mChildren.size());
|
|
|
|
|
+ for(UINT32 i = 0; i < (UINT32)element->mChildren.size(); i++)
|
|
|
|
|
+ tempToDelete[i] = true;
|
|
|
|
|
+
|
|
|
|
|
+ for(UINT32 i = 0; i < currentSO->getNumChildren(); i++)
|
|
|
{
|
|
{
|
|
|
- HString name(toWString(current->mName));
|
|
|
|
|
- if(current->mElement == nullptr)
|
|
|
|
|
|
|
+ HSceneObject currentSOChild = currentSO->getChild(i);
|
|
|
|
|
+ UINT32 curId = currentSOChild->getId();
|
|
|
|
|
+ bool found = false;
|
|
|
|
|
+ for(UINT32 j = 0; j < element->mChildren.size(); j++)
|
|
|
{
|
|
{
|
|
|
- current->mElement = GUILabel::create(_getParentWidget(), name, mElementBtnStyle);
|
|
|
|
|
- _registerChildElement(current->mElement);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ TreeElement* currentChild = element->mChildren[j];
|
|
|
|
|
|
|
|
- if(current->mChildren.size() > 0)
|
|
|
|
|
- {
|
|
|
|
|
- if(current->mFoldoutBtn == nullptr)
|
|
|
|
|
|
|
+ if(curId == currentChild->mId)
|
|
|
{
|
|
{
|
|
|
- current->mFoldoutBtn = GUIToggle::create(_getParentWidget(), GUIContent(HString(L"")), mFoldoutBtnStyle);
|
|
|
|
|
- _registerChildElement(current->mFoldoutBtn);
|
|
|
|
|
-
|
|
|
|
|
- current->mFoldoutBtn->onToggled.connect(boost::bind(&GUISceneTreeView::elementToggled, this, current, _1));
|
|
|
|
|
|
|
+ tempToDelete[j] = false;
|
|
|
|
|
+ currentChild->mIsDirty = true;
|
|
|
|
|
+ currentChild->mSortedIdx = (UINT32)newChildren.size();
|
|
|
|
|
+ newChildren.push_back(currentChild);
|
|
|
|
|
|
|
|
- if(current->mIsExpanded)
|
|
|
|
|
- current->mFoldoutBtn->toggleOn();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- if(current->mFoldoutBtn != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- GUIElement::destroy(current->mFoldoutBtn);
|
|
|
|
|
- current->mFoldoutBtn = nullptr;
|
|
|
|
|
|
|
+ found = true;
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- current->mElement->setContent(GUIContent(name));
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- if(current->mElement != nullptr)
|
|
|
|
|
|
|
+ if(!found)
|
|
|
{
|
|
{
|
|
|
- GUIElement::destroy(current->mElement);
|
|
|
|
|
- current->mElement = nullptr;
|
|
|
|
|
|
|
+ SceneTreeElement* newChild = cm_new<SceneTreeElement>();
|
|
|
|
|
+ newChild->mParent = element;
|
|
|
|
|
+ newChild->mSceneObject = currentSOChild;
|
|
|
|
|
+ newChild->mId = currentSOChild->getId();
|
|
|
|
|
+ newChild->mName = currentSOChild->getName();
|
|
|
|
|
+ newChild->mSortedIdx = (UINT32)newChildren.size();
|
|
|
|
|
+ newChild->mIsDirty = true;
|
|
|
|
|
+
|
|
|
|
|
+ newChildren.push_back(newChild);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- if(current->mFoldoutBtn != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- GUIElement::destroy(current->mFoldoutBtn);
|
|
|
|
|
- current->mFoldoutBtn = nullptr;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(visibilityChanged && current->mIsSelected)
|
|
|
|
|
- unselectElement(current);
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- markContentAsDirty();
|
|
|
|
|
- current->mIsDirty = false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Queue children for next iteration
|
|
|
|
|
- if(visibilityChanged || current->mIsVisible)
|
|
|
|
|
- {
|
|
|
|
|
- for(UINT32 i = 0; i < (UINT32)current->mChildren.size(); i++)
|
|
|
|
|
|
|
+ for(UINT32 i = 0; i < element->mChildren.size(); i++)
|
|
|
{
|
|
{
|
|
|
- todo.push(UpdateTreeElement(current->mChildren[i], i, current->mIsVisible && current->mIsExpanded));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Attempt to scroll if needed
|
|
|
|
|
- if(mScrollState != ScrollState::None)
|
|
|
|
|
- {
|
|
|
|
|
- GUIScrollArea* scrollArea = findParentScrollArea();
|
|
|
|
|
- if(scrollArea != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- float curTime = gTime().getTime();
|
|
|
|
|
- float timeDiff = curTime - mLastScrollTime;
|
|
|
|
|
- float secondsPerPixel = 1.0f / SCROLL_SPEED_PX_PER_SEC;
|
|
|
|
|
-
|
|
|
|
|
- switch(mScrollState)
|
|
|
|
|
- {
|
|
|
|
|
- case ScrollState::TransitioningUp:
|
|
|
|
|
- mScrollState = ScrollState::Up;
|
|
|
|
|
- mLastScrollTime = curTime;
|
|
|
|
|
- break;
|
|
|
|
|
- case ScrollState::TransitioningDown:
|
|
|
|
|
- mScrollState = ScrollState::Down;
|
|
|
|
|
- mLastScrollTime = curTime;
|
|
|
|
|
- break;
|
|
|
|
|
- case ScrollState::Up:
|
|
|
|
|
- {
|
|
|
|
|
- UINT32 scrollAmount = (UINT32)Math::floorToInt(timeDiff / secondsPerPixel);
|
|
|
|
|
- mLastScrollTime += scrollAmount * secondsPerPixel;
|
|
|
|
|
-
|
|
|
|
|
- scrollArea->scrollUpPx(scrollAmount);
|
|
|
|
|
- }
|
|
|
|
|
- break;
|
|
|
|
|
- case ScrollState::Down:
|
|
|
|
|
- {
|
|
|
|
|
- UINT32 scrollAmount = (UINT32)Math::floorToInt(timeDiff / secondsPerPixel);
|
|
|
|
|
- mLastScrollTime += scrollAmount * secondsPerPixel;
|
|
|
|
|
|
|
+ if(!tempToDelete[i])
|
|
|
|
|
+ continue;
|
|
|
|
|
|
|
|
- scrollArea->scrollDownPx(scrollAmount);
|
|
|
|
|
- }
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ deleteTreeElement(element->mChildren[i]);
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- bool GUISceneTreeView::mouseEvent(const GUIMouseEvent& event)
|
|
|
|
|
- {
|
|
|
|
|
- if(event.getType() == GUIMouseEventType::MouseUp)
|
|
|
|
|
- {
|
|
|
|
|
- if(DragAndDropManager::instance().isDragInProgress())
|
|
|
|
|
- return false;
|
|
|
|
|
|
|
|
|
|
- const GUISceneTreeView::InteractableElement* element = findElementUnderCoord(event.getPosition());
|
|
|
|
|
- TreeElement* treeElement = nullptr;
|
|
|
|
|
|
|
+ stackDeallocLast(tempToDelete);
|
|
|
|
|
|
|
|
- if(element != nullptr && element->isTreeElement())
|
|
|
|
|
- {
|
|
|
|
|
- treeElement = element->getTreeElement();
|
|
|
|
|
|
|
+ element->mChildren = newChildren;
|
|
|
|
|
+ element->mIsDirty = true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if(treeElement != nullptr && event.getPosition().x >= treeElement->mElement->getBounds().x)
|
|
|
|
|
|
|
+ // Check if name needs updating
|
|
|
|
|
+ const String& name = element->mSceneObject->getName();
|
|
|
|
|
+ if(element->mName != name)
|
|
|
{
|
|
{
|
|
|
- if(event.isCtrlDown())
|
|
|
|
|
- {
|
|
|
|
|
- selectElement(treeElement);
|
|
|
|
|
- }
|
|
|
|
|
- else if(event.isShiftDown())
|
|
|
|
|
- {
|
|
|
|
|
- if(isSelectionActive())
|
|
|
|
|
- {
|
|
|
|
|
- TreeElement* selectionRoot = mSelectedElements[0].element;
|
|
|
|
|
- unselectAll();
|
|
|
|
|
-
|
|
|
|
|
- auto iterStartFind = std::find_if(mVisibleElements.begin(), mVisibleElements.end(),
|
|
|
|
|
- [&] (const InteractableElement& x) { return x.parent == selectionRoot->mParent; } );
|
|
|
|
|
-
|
|
|
|
|
- bool foundStart = false;
|
|
|
|
|
- bool foundEnd = false;
|
|
|
|
|
- for(; iterStartFind != mVisibleElements.end(); ++iterStartFind)
|
|
|
|
|
- {
|
|
|
|
|
- if(!iterStartFind->isTreeElement())
|
|
|
|
|
- continue;
|
|
|
|
|
-
|
|
|
|
|
- TreeElement* curElem = iterStartFind->getTreeElement();
|
|
|
|
|
- if(curElem == selectionRoot)
|
|
|
|
|
- {
|
|
|
|
|
- foundStart = true;
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- auto iterEndFind = std::find_if(mVisibleElements.begin(), mVisibleElements.end(),
|
|
|
|
|
- [&] (const InteractableElement& x) { return &x == element; } );
|
|
|
|
|
-
|
|
|
|
|
- if(iterEndFind != mVisibleElements.end())
|
|
|
|
|
- foundEnd = true;
|
|
|
|
|
-
|
|
|
|
|
- if(foundStart && foundEnd)
|
|
|
|
|
- {
|
|
|
|
|
- if(iterStartFind < iterEndFind)
|
|
|
|
|
- {
|
|
|
|
|
- for(;iterStartFind != (iterEndFind + 1); ++iterStartFind)
|
|
|
|
|
- {
|
|
|
|
|
- if(iterStartFind->isTreeElement())
|
|
|
|
|
- selectElement(iterStartFind->getTreeElement());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else if(iterEndFind < iterStartFind)
|
|
|
|
|
- {
|
|
|
|
|
- for(;iterEndFind != (iterStartFind + 1); ++iterEndFind)
|
|
|
|
|
- {
|
|
|
|
|
- if(iterEndFind->isTreeElement())
|
|
|
|
|
- selectElement(iterEndFind->getTreeElement());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- selectElement(treeElement);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(!foundStart || !foundEnd)
|
|
|
|
|
- selectElement(treeElement);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- selectElement(treeElement);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- unselectAll();
|
|
|
|
|
- selectElement(treeElement);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- markContentAsDirty();
|
|
|
|
|
-
|
|
|
|
|
- return true;
|
|
|
|
|
|
|
+ element->mName = name;
|
|
|
|
|
+ element->mIsDirty = true;
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- else if(event.getType() == GUIMouseEventType::MouseDragStart)
|
|
|
|
|
- {
|
|
|
|
|
- mDragStartPosition = event.getPosition();
|
|
|
|
|
- }
|
|
|
|
|
- else if(event.getType() == GUIMouseEventType::MouseDrag)
|
|
|
|
|
- {
|
|
|
|
|
- UINT32 dist = mDragStartPosition.manhattanDist(event.getPosition());
|
|
|
|
|
|
|
|
|
|
- if(!DragAndDropManager::instance().isDragInProgress())
|
|
|
|
|
|
|
+ // Calculate the sorted index of the element based on its name
|
|
|
|
|
+ TreeElement* parent = element->mParent;
|
|
|
|
|
+ if(element->mIsDirty && parent != nullptr)
|
|
|
{
|
|
{
|
|
|
- if(dist > DRAG_MIN_DISTANCE)
|
|
|
|
|
|
|
+ for(UINT32 i = 0; i < (UINT32)parent->mChildren.size(); i++)
|
|
|
{
|
|
{
|
|
|
- const GUISceneTreeView::InteractableElement* element = findElementUnderCoord(mDragStartPosition);
|
|
|
|
|
- TreeElement* treeElement = nullptr;
|
|
|
|
|
-
|
|
|
|
|
- if(element != nullptr && element->isTreeElement())
|
|
|
|
|
- {
|
|
|
|
|
- // If element we are trying to drag isn't selected, select it
|
|
|
|
|
- TreeElement* treeElement = element->getTreeElement();
|
|
|
|
|
- auto iterFind = std::find_if(mSelectedElements.begin(), mSelectedElements.end(),
|
|
|
|
|
- [&] (const SelectedElement& x) { return x.element == treeElement; });
|
|
|
|
|
-
|
|
|
|
|
- if(iterFind == mSelectedElements.end())
|
|
|
|
|
- {
|
|
|
|
|
- unselectAll();
|
|
|
|
|
- selectElement(element->getTreeElement());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- DraggedSceneObjects* draggedSceneObjects = cm_new<DraggedSceneObjects>((UINT32)mSelectedElements.size());
|
|
|
|
|
-
|
|
|
|
|
- UINT32 cnt = 0;
|
|
|
|
|
- for(auto& selectedElement : mSelectedElements)
|
|
|
|
|
|
|
+ INT32 stringCompare = element->mName.compare(parent->mChildren[i]->mName);
|
|
|
|
|
+ if(stringCompare > 0)
|
|
|
{
|
|
{
|
|
|
- draggedSceneObjects->objects[cnt] = selectedElement.element->mSceneObject;
|
|
|
|
|
- cnt++;
|
|
|
|
|
|
|
+ if(element->mSortedIdx < parent->mChildren[i]->mSortedIdx)
|
|
|
|
|
+ std::swap(element->mSortedIdx, parent->mChildren[i]->mSortedIdx);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- DragAndDropManager::instance().startDrag(HTexture(), (UINT32)DragAndDropType::SceneObject, (void*)draggedSceneObjects,
|
|
|
|
|
- boost::bind(&GUISceneTreeView::dragAndDropEnded, this));
|
|
|
|
|
-
|
|
|
|
|
- mDragPosition = event.getPosition();
|
|
|
|
|
- mDragInProgress = true;
|
|
|
|
|
- mScrollState = ScrollState::None;
|
|
|
|
|
- markContentAsDirty();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else if(event.getType() == GUIMouseEventType::MouseDragAndDropDragged)
|
|
|
|
|
- {
|
|
|
|
|
- if(DragAndDropManager::instance().isDragInProgress() && DragAndDropManager::instance().getDragTypeId() == (UINT32)DragAndDropType::SceneObject)
|
|
|
|
|
- {
|
|
|
|
|
- mDragPosition = event.getPosition();
|
|
|
|
|
- mDragInProgress = true;
|
|
|
|
|
- markContentAsDirty();
|
|
|
|
|
-
|
|
|
|
|
- if(mBottomScrollBounds.contains(mDragPosition))
|
|
|
|
|
- {
|
|
|
|
|
- if(mScrollState != ScrollState::Down)
|
|
|
|
|
- mScrollState = ScrollState::TransitioningDown;
|
|
|
|
|
- }
|
|
|
|
|
- else if(mTopScrollBounds.contains(mDragPosition))
|
|
|
|
|
- {
|
|
|
|
|
- if(mScrollState != ScrollState::Up)
|
|
|
|
|
- mScrollState = ScrollState::TransitioningUp;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- mScrollState = ScrollState::None;
|
|
|
|
|
-
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else if(event.getType() == GUIMouseEventType::MouseDragAndDropDropped)
|
|
|
|
|
- {
|
|
|
|
|
- if(DragAndDropManager::instance().isDragInProgress() && DragAndDropManager::instance().getDragTypeId() == (UINT32)DragAndDropType::SceneObject)
|
|
|
|
|
- {
|
|
|
|
|
- DraggedSceneObjects* draggedSceneObjects = reinterpret_cast<DraggedSceneObjects*>(DragAndDropManager::instance().getDragData());
|
|
|
|
|
- const GUISceneTreeView::InteractableElement* element = findElementUnderCoord(event.getPosition());
|
|
|
|
|
-
|
|
|
|
|
- TreeElement* treeElement = nullptr;
|
|
|
|
|
- if(element != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- if(element->isTreeElement())
|
|
|
|
|
- treeElement = element->getTreeElement();
|
|
|
|
|
- else
|
|
|
|
|
- treeElement = element->parent;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(treeElement != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- Vector<HSceneObject>::type sceneObjects;
|
|
|
|
|
- HSceneObject newParent = treeElement->mSceneObject;
|
|
|
|
|
-
|
|
|
|
|
- for(UINT32 i = 0; i < draggedSceneObjects->numObjects; i++)
|
|
|
|
|
|
|
+ else if(stringCompare < 0)
|
|
|
{
|
|
{
|
|
|
- if(draggedSceneObjects->objects[i] != newParent)
|
|
|
|
|
- sceneObjects.push_back(draggedSceneObjects->objects[i]);
|
|
|
|
|
|
|
+ if(element->mSortedIdx > parent->mChildren[i]->mSortedIdx)
|
|
|
|
|
+ std::swap(element->mSortedIdx, parent->mChildren[i]->mSortedIdx);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- CmdReparentSO::execute(sceneObjects, newParent);
|
|
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- unselectAll();
|
|
|
|
|
-
|
|
|
|
|
- return true;
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- else if(event.getType() == GUIMouseEventType::MouseOut)
|
|
|
|
|
- {
|
|
|
|
|
- mDragInProgress = false;
|
|
|
|
|
- markContentAsDirty();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- bool GUISceneTreeView::commandEvent(const GUICommandEvent& ev)
|
|
|
|
|
- {
|
|
|
|
|
- if(ev.getType() == GUICommandEventType::CursorMoveUp || ev.getType() == GUICommandEventType::SelectUp)
|
|
|
|
|
- {
|
|
|
|
|
- TreeElement* topMostElement = getTopMostSelectedElement();
|
|
|
|
|
- auto topMostIter = std::find_if(mVisibleElements.begin(), mVisibleElements.end(),
|
|
|
|
|
- [&] (const InteractableElement& x) { return x.getTreeElement() == topMostElement; });
|
|
|
|
|
-
|
|
|
|
|
- if(topMostIter != mVisibleElements.end() && topMostIter != mVisibleElements.begin())
|
|
|
|
|
- {
|
|
|
|
|
- do
|
|
|
|
|
- {
|
|
|
|
|
- topMostIter--;
|
|
|
|
|
- } while (!topMostIter->isTreeElement() && topMostIter != mVisibleElements.begin());
|
|
|
|
|
-
|
|
|
|
|
- if(topMostIter->isTreeElement())
|
|
|
|
|
- {
|
|
|
|
|
- if(ev.getType() == GUICommandEventType::CursorMoveUp)
|
|
|
|
|
- unselectAll();
|
|
|
|
|
-
|
|
|
|
|
- TreeElement* treeElement = topMostIter->getTreeElement();
|
|
|
|
|
- selectElement(treeElement);
|
|
|
|
|
- scrollToElement(treeElement, false);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else if(ev.getType() == GUICommandEventType::CursorMoveDown || ev.getType() == GUICommandEventType::SelectDown)
|
|
|
|
|
- {
|
|
|
|
|
- TreeElement* bottoMostElement = getBottomMostSelectedElement();
|
|
|
|
|
- auto bottomMostIter = std::find_if(mVisibleElements.begin(), mVisibleElements.end(),
|
|
|
|
|
- [&] (const InteractableElement& x) { return x.getTreeElement() == bottoMostElement; });
|
|
|
|
|
-
|
|
|
|
|
- if(bottomMostIter != mVisibleElements.end())
|
|
|
|
|
- {
|
|
|
|
|
- do
|
|
|
|
|
- {
|
|
|
|
|
- bottomMostIter++;
|
|
|
|
|
- } while (bottomMostIter != mVisibleElements.end() && !bottomMostIter->isTreeElement());
|
|
|
|
|
-
|
|
|
|
|
- if(bottomMostIter != mVisibleElements.end() && bottomMostIter->isTreeElement())
|
|
|
|
|
- {
|
|
|
|
|
- if(ev.getType() == GUICommandEventType::CursorMoveDown)
|
|
|
|
|
- unselectAll();
|
|
|
|
|
-
|
|
|
|
|
- TreeElement* treeElement = bottomMostIter->getTreeElement();
|
|
|
|
|
- selectElement(treeElement);
|
|
|
|
|
- scrollToElement(treeElement, false);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- bool GUISceneTreeView::virtualButtonEvent(const BS::GUIVirtualButtonEvent& ev)
|
|
|
|
|
- {
|
|
|
|
|
- if(ev.getButton() == mRenameVB)
|
|
|
|
|
- {
|
|
|
|
|
- if(isSelectionActive() && mEditElement == nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- enableEdit(mSelectedElements[0].element);
|
|
|
|
|
- unselectAll();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void GUISceneTreeView::dragAndDropEnded()
|
|
|
|
|
- {
|
|
|
|
|
- mDragInProgress = false;
|
|
|
|
|
- markContentAsDirty();
|
|
|
|
|
-
|
|
|
|
|
- DraggedSceneObjects* draggedSceneObjects = reinterpret_cast<DraggedSceneObjects*>(DragAndDropManager::instance().getDragData());
|
|
|
|
|
- cm_delete(draggedSceneObjects);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- bool GUISceneTreeView::isSelectionActive() const
|
|
|
|
|
- {
|
|
|
|
|
- return mIsElementSelected && mSelectedElements.size() > 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void GUISceneTreeView::selectElement(TreeElement* element)
|
|
|
|
|
- {
|
|
|
|
|
- auto iterFind = std::find_if(mSelectedElements.begin(), mSelectedElements.end(),
|
|
|
|
|
- [&] (const SelectedElement& x) { return x.element == element; });
|
|
|
|
|
-
|
|
|
|
|
- if(iterFind == mSelectedElements.end())
|
|
|
|
|
- {
|
|
|
|
|
- GUITexture* background = GUITexture::create(_getParentWidget(), mSelectionBackgroundStyle);
|
|
|
|
|
- _registerChildElement(background);
|
|
|
|
|
-
|
|
|
|
|
- element->mIsSelected = true;
|
|
|
|
|
-
|
|
|
|
|
- mSelectedElements.push_back(SelectedElement(element, background));
|
|
|
|
|
- mIsElementSelected = true;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void GUISceneTreeView::unselectElement(TreeElement* element)
|
|
|
|
|
- {
|
|
|
|
|
- auto iterFind = std::find_if(mSelectedElements.begin(), mSelectedElements.end(),
|
|
|
|
|
- [&] (const SelectedElement& x) { return x.element == element; });
|
|
|
|
|
-
|
|
|
|
|
- if(iterFind != mSelectedElements.end())
|
|
|
|
|
- {
|
|
|
|
|
- iterFind->element->mIsSelected = false;
|
|
|
|
|
- GUIElement::destroy(iterFind->background);
|
|
|
|
|
-
|
|
|
|
|
- mSelectedElements.erase(iterFind);
|
|
|
|
|
- markContentAsDirty();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- mIsElementSelected = mSelectedElements.size() > 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void GUISceneTreeView::unselectAll()
|
|
|
|
|
- {
|
|
|
|
|
- for(auto& selectedElem : mSelectedElements)
|
|
|
|
|
- {
|
|
|
|
|
- selectedElem.element->mIsSelected = false;
|
|
|
|
|
- GUIElement::destroy(selectedElem.background);
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- mSelectedElements.clear();
|
|
|
|
|
- mIsElementSelected = false;
|
|
|
|
|
-
|
|
|
|
|
- markContentAsDirty();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void GUISceneTreeView::elementToggled(TreeElement* element, bool toggled)
|
|
|
|
|
- {
|
|
|
|
|
- element->mIsExpanded = toggled;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void GUISceneTreeView::onEditAccepted()
|
|
|
|
|
- {
|
|
|
|
|
- disableEdit(true);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void GUISceneTreeView::onEditCanceled()
|
|
|
|
|
- {
|
|
|
|
|
- if(mEditElement != nullptr)
|
|
|
|
|
- disableEdit(false);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void GUISceneTreeView::enableEdit(TreeElement* element)
|
|
|
|
|
- {
|
|
|
|
|
- assert(mEditElement == nullptr);
|
|
|
|
|
-
|
|
|
|
|
- mEditElement = element;
|
|
|
|
|
- mNameEditBox->enableRecursively();
|
|
|
|
|
- mNameEditBox->setFocus(true);
|
|
|
|
|
-
|
|
|
|
|
- if(element->mElement != nullptr)
|
|
|
|
|
- element->mElement->disableRecursively();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void GUISceneTreeView::deleteTreeElement(TreeElement* element)
|
|
|
|
|
- {
|
|
|
|
|
- closeTemporarilyExpandedElements(); // In case this element is one of them
|
|
|
|
|
-
|
|
|
|
|
- if(element->mIsSelected)
|
|
|
|
|
- unselectElement(element);
|
|
|
|
|
-
|
|
|
|
|
- cm_delete(element);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void GUISceneTreeView::disableEdit(bool applyChanges)
|
|
|
|
|
- {
|
|
|
|
|
- assert(mEditElement != nullptr);
|
|
|
|
|
-
|
|
|
|
|
- if(mEditElement->mElement != nullptr)
|
|
|
|
|
- mEditElement->mElement->enableRecursively();
|
|
|
|
|
-
|
|
|
|
|
- if(applyChanges)
|
|
|
|
|
|
|
+ bool visibilityChanged = false;
|
|
|
|
|
+ if(element->mIsVisible != visible)
|
|
|
{
|
|
{
|
|
|
- String newName = toString(mNameEditBox->getText());
|
|
|
|
|
- CmdEditPlainFieldGO<String>::execute(mEditElement->mSceneObject, "mName", newName);
|
|
|
|
|
|
|
+ visibilityChanged = true;
|
|
|
|
|
+ element->mIsVisible = visible;
|
|
|
|
|
+ element->mIsDirty = true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- mNameEditBox->disableRecursively();
|
|
|
|
|
- mEditElement = nullptr;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- Vector2I GUISceneTreeView::_getOptimalSize() const
|
|
|
|
|
- {
|
|
|
|
|
- struct UpdateTreeElement
|
|
|
|
|
|
|
+ if(visibilityChanged || element->mIsVisible)
|
|
|
{
|
|
{
|
|
|
- UpdateTreeElement(const TreeElement* element, UINT32 indent)
|
|
|
|
|
- :element(element), indent(indent)
|
|
|
|
|
- { }
|
|
|
|
|
-
|
|
|
|
|
- const TreeElement* element;
|
|
|
|
|
- UINT32 indent;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- Vector2I optimalSize;
|
|
|
|
|
-
|
|
|
|
|
- if(_getLayoutOptions().fixedWidth && _getLayoutOptions().fixedHeight)
|
|
|
|
|
- {
|
|
|
|
|
- optimalSize.x = _getLayoutOptions().width;
|
|
|
|
|
- optimalSize.y = _getLayoutOptions().height;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- Stack<UpdateTreeElement>::type todo;
|
|
|
|
|
- todo.push(UpdateTreeElement(&mRootElement, 0));
|
|
|
|
|
-
|
|
|
|
|
- while(!todo.empty())
|
|
|
|
|
|
|
+ for(UINT32 i = 0; i < (UINT32)element->mChildren.size(); i++)
|
|
|
{
|
|
{
|
|
|
- UpdateTreeElement currentUpdateElement = todo.top();
|
|
|
|
|
- const TreeElement* current = currentUpdateElement.element;
|
|
|
|
|
- todo.pop();
|
|
|
|
|
-
|
|
|
|
|
- INT32 yOffset = 0;
|
|
|
|
|
- if(current->mElement != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- Vector2I curOptimalSize = current->mElement->_getOptimalSize();
|
|
|
|
|
- optimalSize.x = std::max(optimalSize.x,
|
|
|
|
|
- (INT32)(INITIAL_INDENT_OFFSET + curOptimalSize.x + currentUpdateElement.indent * INDENT_SIZE));
|
|
|
|
|
- yOffset = curOptimalSize.y + ELEMENT_EXTRA_SPACING;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- optimalSize.y += yOffset;
|
|
|
|
|
-
|
|
|
|
|
- for(auto& child : current->mChildren)
|
|
|
|
|
- {
|
|
|
|
|
- if(!child->mIsVisible)
|
|
|
|
|
- continue;
|
|
|
|
|
-
|
|
|
|
|
- todo.push(UpdateTreeElement(child, currentUpdateElement.indent + 1));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(_getLayoutOptions().fixedWidth)
|
|
|
|
|
- optimalSize.x = _getLayoutOptions().width;
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- if(_getLayoutOptions().minWidth > 0)
|
|
|
|
|
- optimalSize.x = std::max((INT32)_getLayoutOptions().minWidth, optimalSize.x);
|
|
|
|
|
-
|
|
|
|
|
- if(_getLayoutOptions().maxWidth > 0)
|
|
|
|
|
- optimalSize.x = std::min((INT32)_getLayoutOptions().maxWidth, optimalSize.x);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(_getLayoutOptions().fixedHeight)
|
|
|
|
|
- optimalSize.y = _getLayoutOptions().height;
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- if(_getLayoutOptions().minHeight > 0)
|
|
|
|
|
- optimalSize.y = std::max((INT32)_getLayoutOptions().minHeight, optimalSize.y);
|
|
|
|
|
-
|
|
|
|
|
- if(_getLayoutOptions().maxHeight > 0)
|
|
|
|
|
- optimalSize.y = std::min((INT32)_getLayoutOptions().maxHeight, optimalSize.y);
|
|
|
|
|
|
|
+ SceneTreeElement* sceneElement = static_cast<SceneTreeElement*>(element->mChildren[i]);
|
|
|
|
|
+ updateTreeElement(sceneElement, element->mIsVisible && element->mIsExpanded);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return optimalSize;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void GUISceneTreeView::updateClippedBounds()
|
|
|
|
|
- {
|
|
|
|
|
- Vector2I offset = _getOffset();
|
|
|
|
|
- mClippedBounds = RectI(offset.x, offset.y, _getWidth(), _getHeight());
|
|
|
|
|
-
|
|
|
|
|
- RectI localClipRect(mClipRect.x + mOffset.x, mClipRect.y + mOffset.y, mClipRect.width, mClipRect.height);
|
|
|
|
|
- mClippedBounds.clip(localClipRect);
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void GUISceneTreeView::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
|
|
|
|
|
- RectI clipRect, UINT8 widgetDepth, UINT16 areaDepth)
|
|
|
|
|
|
|
+ void GUISceneTreeView::updateTreeElementHierarchy()
|
|
|
{
|
|
{
|
|
|
- struct UpdateTreeElement
|
|
|
|
|
- {
|
|
|
|
|
- UpdateTreeElement(TreeElement* element, UINT32 indent)
|
|
|
|
|
- :element(element), indent(indent)
|
|
|
|
|
- { }
|
|
|
|
|
-
|
|
|
|
|
- TreeElement* element;
|
|
|
|
|
- UINT32 indent;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- mVisibleElements.clear();
|
|
|
|
|
-
|
|
|
|
|
- Stack<UpdateTreeElement>::type todo;
|
|
|
|
|
- todo.push(UpdateTreeElement(&mRootElement, 0));
|
|
|
|
|
-
|
|
|
|
|
- // NOTE - Instead of iterating through all elements, try to find those within the clip rect
|
|
|
|
|
- // and only iterate through those. Others should somehow be marked in-active (similar to GUIElement::isDisabled()?)
|
|
|
|
|
-
|
|
|
|
|
- Vector<TreeElement*>::type tempOrderedElements;
|
|
|
|
|
-
|
|
|
|
|
- Vector2I offset(x, y);
|
|
|
|
|
-
|
|
|
|
|
- while(!todo.empty())
|
|
|
|
|
- {
|
|
|
|
|
- UpdateTreeElement currentUpdateElement = todo.top();
|
|
|
|
|
- TreeElement* current = currentUpdateElement.element;
|
|
|
|
|
- UINT32 indent = currentUpdateElement.indent;
|
|
|
|
|
- todo.pop();
|
|
|
|
|
-
|
|
|
|
|
- INT32 btnHeight = 0;
|
|
|
|
|
- INT32 yOffset = 0;
|
|
|
|
|
- if(current->mElement != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- Vector2I elementSize = current->mElement->_getOptimalSize();
|
|
|
|
|
- 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 = x + INITIAL_INDENT_OFFSET + indent * INDENT_SIZE;
|
|
|
|
|
- offset.y += ELEMENT_EXTRA_SPACING;
|
|
|
|
|
-
|
|
|
|
|
- current->mElement->_setOffset(offset);
|
|
|
|
|
- current->mElement->_setWidth(elementSize.x);
|
|
|
|
|
- current->mElement->_setHeight(elementSize.y);
|
|
|
|
|
- current->mElement->_setAreaDepth(areaDepth);
|
|
|
|
|
- current->mElement->_setWidgetDepth(widgetDepth);
|
|
|
|
|
-
|
|
|
|
|
- RectI elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
|
|
|
|
|
- current->mElement->_setClipRect(elemClipRect);
|
|
|
|
|
-
|
|
|
|
|
- yOffset = btnHeight;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(current->mFoldoutBtn != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- Vector2I elementSize = current->mFoldoutBtn->_getOptimalSize();
|
|
|
|
|
-
|
|
|
|
|
- offset.x -= std::min((INT32)INITIAL_INDENT_OFFSET, elementSize.x);
|
|
|
|
|
-
|
|
|
|
|
- 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)
|
|
|
|
|
- {
|
|
|
|
|
- UINT32 diff = elementSize.y - btnHeight;
|
|
|
|
|
- float half = diff * 0.5f;
|
|
|
|
|
- myOffset.y -= Math::floorToInt(half);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- current->mFoldoutBtn->_setOffset(myOffset);
|
|
|
|
|
- current->mFoldoutBtn->_setWidth(elementSize.x);
|
|
|
|
|
- current->mFoldoutBtn->_setHeight(elementSize.y);
|
|
|
|
|
- current->mFoldoutBtn->_setAreaDepth(areaDepth);
|
|
|
|
|
- current->mFoldoutBtn->_setWidgetDepth(widgetDepth);
|
|
|
|
|
-
|
|
|
|
|
- RectI elemClipRect(clipRect.x - myOffset.x, clipRect.y - myOffset.y, clipRect.width, clipRect.height);
|
|
|
|
|
- current->mFoldoutBtn->_setClipRect(elemClipRect);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- offset.y += yOffset;
|
|
|
|
|
-
|
|
|
|
|
- tempOrderedElements.resize(current->mChildren.size(), nullptr);
|
|
|
|
|
- for(auto& child : current->mChildren)
|
|
|
|
|
- {
|
|
|
|
|
- tempOrderedElements[child->mSortedIdx] = child;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- for(auto iter = tempOrderedElements.rbegin(); iter != tempOrderedElements.rend(); ++iter)
|
|
|
|
|
- {
|
|
|
|
|
- TreeElement* child = *iter;
|
|
|
|
|
-
|
|
|
|
|
- if(!child->mIsVisible)
|
|
|
|
|
- continue;
|
|
|
|
|
-
|
|
|
|
|
- todo.push(UpdateTreeElement(child, indent + 1));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- 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)
|
|
|
|
|
- {
|
|
|
|
|
- GUILabel* targetElement = selectedElem.element->mElement;
|
|
|
|
|
-
|
|
|
|
|
- Vector2I offset = targetElement->_getOffset();
|
|
|
|
|
- offset.x = x;
|
|
|
|
|
-
|
|
|
|
|
- selectedElem.background->_setOffset(offset);
|
|
|
|
|
- selectedElem.background->_setWidth(width);
|
|
|
|
|
- selectedElem.background->_setHeight(targetElement->_getHeight());
|
|
|
|
|
- selectedElem.background->_setAreaDepth(areaDepth + 1);
|
|
|
|
|
- selectedElem.background->_setWidgetDepth(widgetDepth);
|
|
|
|
|
-
|
|
|
|
|
- RectI elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
|
|
|
|
|
- selectedElem.background->_setClipRect(elemClipRect);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(mEditElement != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- GUILabel* targetElement = mEditElement->mElement;
|
|
|
|
|
-
|
|
|
|
|
- Vector2I offset = targetElement->_getOffset();
|
|
|
|
|
- UINT32 remainingWidth = (UINT32)std::max(0, (((INT32)width) - (offset.x - x)));
|
|
|
|
|
-
|
|
|
|
|
- mNameEditBox->_setOffset(offset);
|
|
|
|
|
- mNameEditBox->_setWidth(remainingWidth);
|
|
|
|
|
- mNameEditBox->_setHeight(targetElement->_getHeight());
|
|
|
|
|
- mNameEditBox->_setAreaDepth(areaDepth);
|
|
|
|
|
- mNameEditBox->_setWidgetDepth(widgetDepth);
|
|
|
|
|
-
|
|
|
|
|
- RectI elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
|
|
|
|
|
- mNameEditBox->_setClipRect(elemClipRect);
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(mDragInProgress)
|
|
|
|
|
- {
|
|
|
|
|
- const InteractableElement* interactableElement = findElementUnderCoord(mDragPosition);
|
|
|
|
|
-
|
|
|
|
|
- if(interactableElement == nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- if(!mDragHighlight->_isDisabled())
|
|
|
|
|
- mDragHighlight->disableRecursively();
|
|
|
|
|
-
|
|
|
|
|
- if(!mDragSepHighlight->_isDisabled())
|
|
|
|
|
- mDragSepHighlight->disableRecursively();
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- if(interactableElement->isTreeElement())
|
|
|
|
|
- {
|
|
|
|
|
- if(!mDragSepHighlight->_isDisabled())
|
|
|
|
|
- mDragSepHighlight->disableRecursively();
|
|
|
|
|
-
|
|
|
|
|
- if(mDragHighlight->_isDisabled())
|
|
|
|
|
- mDragHighlight->enableRecursively();
|
|
|
|
|
-
|
|
|
|
|
- Vector2I offset(interactableElement->bounds.x, interactableElement->bounds.y);
|
|
|
|
|
- mDragHighlight->_setOffset(offset);
|
|
|
|
|
- mDragHighlight->_setWidth(interactableElement->bounds.width);
|
|
|
|
|
- mDragHighlight->_setHeight(interactableElement->bounds.height);
|
|
|
|
|
- mDragHighlight->_setAreaDepth(areaDepth + 1);
|
|
|
|
|
- mDragHighlight->_setWidgetDepth(widgetDepth);
|
|
|
|
|
-
|
|
|
|
|
- RectI elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
|
|
|
|
|
- mDragHighlight->_setClipRect(elemClipRect);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- if(!mDragHighlight->_isDisabled())
|
|
|
|
|
- mDragHighlight->disableRecursively();
|
|
|
|
|
-
|
|
|
|
|
- if(mDragSepHighlight->_isDisabled())
|
|
|
|
|
- mDragSepHighlight->enableRecursively();
|
|
|
|
|
-
|
|
|
|
|
- Vector2I offset(interactableElement->bounds.x, interactableElement->bounds.y);
|
|
|
|
|
- mDragSepHighlight->_setOffset(offset);
|
|
|
|
|
- mDragSepHighlight->_setWidth(interactableElement->bounds.width);
|
|
|
|
|
- mDragSepHighlight->_setHeight(interactableElement->bounds.height);
|
|
|
|
|
- mDragSepHighlight->_setAreaDepth(areaDepth + 1);
|
|
|
|
|
- mDragSepHighlight->_setWidgetDepth(widgetDepth);
|
|
|
|
|
-
|
|
|
|
|
- RectI elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
|
|
|
|
|
- mDragSepHighlight->_setClipRect(elemClipRect);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- if(!mDragHighlight->_isDisabled())
|
|
|
|
|
- mDragHighlight->disableRecursively();
|
|
|
|
|
-
|
|
|
|
|
- if(!mDragSepHighlight->_isDisabled())
|
|
|
|
|
- mDragSepHighlight->disableRecursively();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Update scroll bounds
|
|
|
|
|
- UINT32 scrollHeight = (UINT32)Math::roundToInt(clipRect.height * SCROLL_AREA_HEIGHT_PCT);
|
|
|
|
|
-
|
|
|
|
|
- mTopScrollBounds.x = clipRect.x;
|
|
|
|
|
- mTopScrollBounds.y = clipRect.y;
|
|
|
|
|
- mTopScrollBounds.width = clipRect.width;
|
|
|
|
|
- mTopScrollBounds.height = scrollHeight;
|
|
|
|
|
|
|
+ HSceneObject root = CM::gSceneManager().getRootNode();
|
|
|
|
|
+ mRootElement.mSceneObject = root;
|
|
|
|
|
+ mRootElement.mId = root->getId();
|
|
|
|
|
+ mRootElement.mSortedIdx = 0;
|
|
|
|
|
+ mRootElement.mIsExpanded = true;
|
|
|
|
|
|
|
|
- mBottomScrollBounds.x = clipRect.x;
|
|
|
|
|
- mBottomScrollBounds.y = clipRect.y + clipRect.height - scrollHeight;
|
|
|
|
|
- mBottomScrollBounds.width = clipRect.width;
|
|
|
|
|
- mBottomScrollBounds.height = scrollHeight;
|
|
|
|
|
|
|
+ updateTreeElement(&mRootElement, true);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const GUISceneTreeView::InteractableElement* GUISceneTreeView::findElementUnderCoord(const CM::Vector2I& coord) const
|
|
|
|
|
|
|
+ void GUISceneTreeView::renameTreeElement(GUITreeView::TreeElement* element, const CM::WString& name)
|
|
|
{
|
|
{
|
|
|
- for(auto& element : mVisibleElements)
|
|
|
|
|
- {
|
|
|
|
|
- if(element.bounds.contains(coord))
|
|
|
|
|
- {
|
|
|
|
|
- return &element;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return nullptr;
|
|
|
|
|
|
|
+ SceneTreeElement* sceneTreeElement = static_cast<SceneTreeElement*>(element);
|
|
|
|
|
+ CmdEditPlainFieldGO<String>::execute(sceneTreeElement->mSceneObject, "mName", toString(name));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- GUISceneTreeView::TreeElement* GUISceneTreeView::getTopMostSelectedElement() const
|
|
|
|
|
|
|
+ bool GUISceneTreeView::acceptDragAndDrop() const
|
|
|
{
|
|
{
|
|
|
- auto topMostElement = mVisibleElements.end();
|
|
|
|
|
-
|
|
|
|
|
- for(auto& selectedElement : mSelectedElements)
|
|
|
|
|
- {
|
|
|
|
|
- auto iterFind = std::find_if(mVisibleElements.begin(), mVisibleElements.end(),
|
|
|
|
|
- [&] (const InteractableElement& x) { return x.getTreeElement() == selectedElement.element; });
|
|
|
|
|
-
|
|
|
|
|
- if(iterFind != mVisibleElements.end())
|
|
|
|
|
- {
|
|
|
|
|
- if(topMostElement == mVisibleElements.end())
|
|
|
|
|
- topMostElement = iterFind;
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- if(iterFind->bounds.y < topMostElement->bounds.y)
|
|
|
|
|
- topMostElement = iterFind;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(topMostElement != mVisibleElements.end())
|
|
|
|
|
- return topMostElement->getTreeElement();
|
|
|
|
|
- else
|
|
|
|
|
- return nullptr;
|
|
|
|
|
|
|
+ return DragAndDropManager::instance().isDragInProgress() && DragAndDropManager::instance().getDragTypeId() == (UINT32)DragAndDropType::SceneObject;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- GUISceneTreeView::TreeElement* GUISceneTreeView::getBottomMostSelectedElement() const
|
|
|
|
|
|
|
+ void GUISceneTreeView::dragAndDropStart()
|
|
|
{
|
|
{
|
|
|
- auto& botMostElement = mVisibleElements.end();
|
|
|
|
|
|
|
+ DraggedSceneObjects* draggedSceneObjects = cm_new<DraggedSceneObjects>((UINT32)mSelectedElements.size());
|
|
|
|
|
|
|
|
|
|
+ UINT32 cnt = 0;
|
|
|
for(auto& selectedElement : mSelectedElements)
|
|
for(auto& selectedElement : mSelectedElements)
|
|
|
{
|
|
{
|
|
|
- auto iterFind = std::find_if(mVisibleElements.begin(), mVisibleElements.end(),
|
|
|
|
|
- [&] (const InteractableElement& x) { return x.getTreeElement() == selectedElement.element; });
|
|
|
|
|
-
|
|
|
|
|
- if(iterFind != mVisibleElements.end())
|
|
|
|
|
- {
|
|
|
|
|
- if(botMostElement == mVisibleElements.end())
|
|
|
|
|
- botMostElement = iterFind;
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- if((iterFind->bounds.y + iterFind->bounds.height) > (botMostElement->bounds.y + botMostElement->bounds.height))
|
|
|
|
|
- botMostElement = iterFind;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ SceneTreeElement* sceneTreeElement = static_cast<SceneTreeElement*>(selectedElement.element);
|
|
|
|
|
+ draggedSceneObjects->objects[cnt] = sceneTreeElement->mSceneObject;
|
|
|
|
|
+ cnt++;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if(botMostElement != mVisibleElements.end())
|
|
|
|
|
- return botMostElement->getTreeElement();
|
|
|
|
|
- else
|
|
|
|
|
- return nullptr;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void GUISceneTreeView::closeTemporarilyExpandedElements()
|
|
|
|
|
- {
|
|
|
|
|
- temporarilyExpandElement(nullptr);
|
|
|
|
|
|
|
+ DragAndDropManager::instance().startDrag(HTexture(), (UINT32)DragAndDropType::SceneObject, (void*)draggedSceneObjects,
|
|
|
|
|
+ boost::bind(&GUISceneTreeView::dragAndDropFinalize, this));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void GUISceneTreeView::temporarilyExpandElement(const GUISceneTreeView::InteractableElement* mouseOverElement)
|
|
|
|
|
|
|
+ void GUISceneTreeView::dragAndDropEnded(TreeElement* overTreeElement)
|
|
|
{
|
|
{
|
|
|
- TreeElement* treeElement = nullptr;
|
|
|
|
|
- if(mouseOverElement != nullptr && mouseOverElement->isTreeElement())
|
|
|
|
|
- treeElement = mouseOverElement->getTreeElement();
|
|
|
|
|
-
|
|
|
|
|
- if(treeElement == nullptr || treeElement != mMouseOverDragElement)
|
|
|
|
|
|
|
+ if(overTreeElement != nullptr)
|
|
|
{
|
|
{
|
|
|
- while(!mAutoExpandedElements.empty())
|
|
|
|
|
- {
|
|
|
|
|
- TreeElement* autoExpandedElement = mAutoExpandedElements.top();
|
|
|
|
|
-
|
|
|
|
|
- bool unexpandElement = false;
|
|
|
|
|
- if(mouseOverElement != nullptr && mouseOverElement->parent != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- if(mouseOverElement->parent != autoExpandedElement && !mouseOverElement->parent->isParentRec(autoExpandedElement))
|
|
|
|
|
- unexpandElement = true;
|
|
|
|
|
- else
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- unexpandElement = true;
|
|
|
|
|
|
|
+ DraggedSceneObjects* draggedSceneObjects = reinterpret_cast<DraggedSceneObjects*>(DragAndDropManager::instance().getDragData());
|
|
|
|
|
|
|
|
- if(unexpandElement)
|
|
|
|
|
- {
|
|
|
|
|
- autoExpandedElement->mIsExpanded = false;
|
|
|
|
|
- if(autoExpandedElement->mFoldoutBtn != nullptr)
|
|
|
|
|
- autoExpandedElement->mFoldoutBtn->toggleOff();
|
|
|
|
|
-
|
|
|
|
|
- mAutoExpandedElements.pop();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ Vector<HSceneObject>::type sceneObjects;
|
|
|
|
|
+ SceneTreeElement* sceneTreeElement = static_cast<SceneTreeElement*>(overTreeElement);
|
|
|
|
|
+ HSceneObject newParent = sceneTreeElement->mSceneObject;
|
|
|
|
|
|
|
|
- mMouseOverDragElement = treeElement;
|
|
|
|
|
- mMouseOverDragElementTime = gTime().getTime();
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- if(mMouseOverDragElement != nullptr && !mMouseOverDragElement->mIsExpanded)
|
|
|
|
|
|
|
+ for(UINT32 i = 0; i < draggedSceneObjects->numObjects; i++)
|
|
|
{
|
|
{
|
|
|
- float timeDiff = gTime().getTime() - mMouseOverDragElementTime;
|
|
|
|
|
- if(timeDiff >= AUTO_EXPAND_DELAY_SEC)
|
|
|
|
|
- {
|
|
|
|
|
- mAutoExpandedElements.push(mMouseOverDragElement);
|
|
|
|
|
- mMouseOverDragElement->mIsExpanded = true;
|
|
|
|
|
-
|
|
|
|
|
- if(mMouseOverDragElement->mFoldoutBtn != nullptr)
|
|
|
|
|
- mMouseOverDragElement->mFoldoutBtn->toggleOn();
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if(draggedSceneObjects->objects[i] != newParent)
|
|
|
|
|
+ sceneObjects.push_back(draggedSceneObjects->objects[i]);
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void GUISceneTreeView::scrollToElement(TreeElement* element, bool center)
|
|
|
|
|
- {
|
|
|
|
|
- if(element->mElement == nullptr)
|
|
|
|
|
- return;
|
|
|
|
|
-
|
|
|
|
|
- GUIScrollArea* scrollArea = findParentScrollArea();
|
|
|
|
|
- if(scrollArea == nullptr)
|
|
|
|
|
- return;
|
|
|
|
|
-
|
|
|
|
|
- if(center)
|
|
|
|
|
- {
|
|
|
|
|
- RectI myBounds = _getClippedBounds();
|
|
|
|
|
- INT32 clipVertCenter = myBounds.y + (INT32)Math::roundToInt(myBounds.height * 0.5f);
|
|
|
|
|
- INT32 elemVertCenter = element->mElement->_getOffset().y + (INT32)Math::roundToInt(element->mElement->_getHeight() * 0.5f);
|
|
|
|
|
-
|
|
|
|
|
- if(elemVertCenter > clipVertCenter)
|
|
|
|
|
- scrollArea->scrollUpPx(elemVertCenter - clipVertCenter);
|
|
|
|
|
- else
|
|
|
|
|
- scrollArea->scrollDownPx(clipVertCenter - elemVertCenter);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- RectI myBounds = _getClippedBounds();
|
|
|
|
|
- INT32 elemVertTop = element->mElement->_getOffset().y;
|
|
|
|
|
- INT32 elemVertBottom = element->mElement->_getOffset().y + element->mElement->_getHeight();
|
|
|
|
|
-
|
|
|
|
|
- INT32 top = myBounds.y;
|
|
|
|
|
- INT32 bottom = myBounds.y + myBounds.height;
|
|
|
|
|
|
|
|
|
|
- INT32 offset = 0;
|
|
|
|
|
- if(elemVertTop < top)
|
|
|
|
|
- scrollArea->scrollUpPx(top - elemVertTop);
|
|
|
|
|
- else if(elemVertBottom > bottom)
|
|
|
|
|
- scrollArea->scrollDownPx(elemVertBottom - bottom);
|
|
|
|
|
|
|
+ CmdReparentSO::execute(sceneObjects, newParent);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- GUIScrollArea* GUISceneTreeView::findParentScrollArea() const
|
|
|
|
|
|
|
+ void GUISceneTreeView::dragAndDropFinalize()
|
|
|
{
|
|
{
|
|
|
- GUIElementBase* parent = _getParent();
|
|
|
|
|
- while(parent != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- if(parent->_getType() == GUIElementBase::Type::Element)
|
|
|
|
|
- {
|
|
|
|
|
- GUIElement* parentElement = static_cast<GUIElement*>(parent);
|
|
|
|
|
-
|
|
|
|
|
- if(parentElement->getElementType() == GUIElement::ElementType::ScrollArea)
|
|
|
|
|
- {
|
|
|
|
|
- GUIScrollArea* scrollArea = static_cast<GUIScrollArea*>(parentElement);
|
|
|
|
|
- return scrollArea;
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- parent = parent->_getParent();
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ mDragInProgress = false;
|
|
|
|
|
+ markContentAsDirty();
|
|
|
|
|
|
|
|
- return nullptr;
|
|
|
|
|
|
|
+ DraggedSceneObjects* draggedSceneObjects = reinterpret_cast<DraggedSceneObjects*>(DragAndDropManager::instance().getDragData());
|
|
|
|
|
+ cm_delete(draggedSceneObjects);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const String& GUISceneTreeView::getGUITypeName()
|
|
const String& GUISceneTreeView::getGUITypeName()
|