diff --git a/Projects/Editor/Source/GUI/Controls/CTreeControl.cpp b/Projects/Editor/Source/GUI/Controls/CTreeControl.cpp index d8c22b7d4..ff2c8d91a 100644 --- a/Projects/Editor/Source/GUI/Controls/CTreeControl.cpp +++ b/Projects/Editor/Source/GUI/Controls/CTreeControl.cpp @@ -45,6 +45,7 @@ namespace Skylicht m_expandButton = NULL; m_innerPanel = NULL; m_row = NULL; + m_expand = true; m_scrollControl = new CScrollControl(this); m_scrollControl->dock(EPosition::Fill); @@ -91,11 +92,29 @@ namespace Skylicht bool CTreeControl::onKeyUp(bool down) { + if (down) + { + CTreeNode *child = selectPrevChild(); + if (child != NULL) + { + m_scrollControl->scrollToItem(child->getTextItem()); + } + } + return true; } bool CTreeControl::onKeyDown(bool down) { + if (down) + { + CTreeNode *child = selectNextChild(); + if (child != NULL) + { + m_scrollControl->scrollToItem(child->getTextItem()); + } + } + return true; } @@ -148,6 +167,44 @@ namespace Skylicht } return true; } + + bool CTreeControl::onKeyLeft(bool down) + { + if (down) + { + CTreeNode* node = getChildSelected(); + if (node != NULL) + { + if (node->haveChild() && node->isExpand()) + node->collapse(); + else + { + // select parent + CTreeNode *parent = node->getParentNode(); + if (parent != NULL) + { + deselectAll(); + parent->setSelected(true); + m_scrollControl->scrollToItem(parent->getTextItem()); + } + } + } + } + return true; + } + + bool CTreeControl::onKeyRight(bool down) + { + if (down) + { + CTreeNode* node = getChildSelected(); + if (node != NULL) + { + node->expand(); + } + } + return true; + } } } } \ No newline at end of file diff --git a/Projects/Editor/Source/GUI/Controls/CTreeControl.h b/Projects/Editor/Source/GUI/Controls/CTreeControl.h index 64914ab56..9c19664e6 100644 --- a/Projects/Editor/Source/GUI/Controls/CTreeControl.h +++ b/Projects/Editor/Source/GUI/Controls/CTreeControl.h @@ -64,6 +64,10 @@ namespace Skylicht virtual bool onKeyHome(bool down); virtual bool onKeyEnd(bool down); + + virtual bool onKeyLeft(bool down); + + virtual bool onKeyRight(bool down); }; } } diff --git a/Projects/Editor/Source/GUI/Controls/CTreeNode.cpp b/Projects/Editor/Source/GUI/Controls/CTreeNode.cpp index f865d5848..a0f8eb64a 100644 --- a/Projects/Editor/Source/GUI/Controls/CTreeNode.cpp +++ b/Projects/Editor/Source/GUI/Controls/CTreeNode.cpp @@ -41,6 +41,8 @@ namespace Skylicht m_expand(false), m_selected(false) { + m_parentNode = dynamic_cast(parent); + m_row = new CTreeRowItem(this, root); m_row->OnDown = BIND_LISTENER(&CTreeNode::onDown, this); m_row->OnDoubleLeftMouseClick = BIND_LISTENER(&CTreeNode::onDoubleClick, this); @@ -188,6 +190,28 @@ namespace Skylicht } + CTreeNode* CTreeNode::getChildSelected() + { + if (m_selected) + return this; + + if (m_innerPanel->Children.size() == 0) + return NULL; + + for (CBase *c : m_innerPanel->Children) + { + CTreeNode *node = dynamic_cast(c); + if (node && !node->isDisabled()) + { + CTreeNode* child = node->getChildSelected(); + if (child != NULL) + return child; + } + } + + return NULL; + } + CTreeNode* CTreeNode::selectFirstChild() { if (m_expand == false) @@ -201,18 +225,9 @@ namespace Skylicht CTreeNode *node = dynamic_cast(c); if (node && !node->isDisabled()) { - CTreeNode *child = node->selectFirstChild(); - - if (child == NULL) - { - m_root->deselectAll(); - node->setSelected(true); - return node; - } - else - { - return child; - } + m_root->deselectAll(); + node->setSelected(true); + return node; } } @@ -252,6 +267,93 @@ namespace Skylicht return NULL; } + CTreeNode* CTreeNode::selectPrevChild() + { + std::list priorityQueue; + priorityQueue.push_back(this); + + CTreeNode *lastItem = NULL; + + while (priorityQueue.size() > 0) + { + CTreeNode* visit = priorityQueue.front(); + priorityQueue.pop_front(); + + if (visit->isSelected() == true) + { + if (lastItem == NULL) + return NULL; + + m_root->deselectAll(); + lastItem->setSelected(true); + return lastItem; + } + + if (visit->m_expand && visit->m_innerPanel->Children.size() > 0) + { + std::list::iterator i = priorityQueue.begin(); + + for (CBase *c : visit->m_innerPanel->Children) + { + CTreeNode *node = dynamic_cast(c); + if (node && !node->isDisabled()) + { + i = priorityQueue.insert(i, node); + ++i; + } + } + } + + if (visit != this) + lastItem = visit; + } + + return NULL; + } + + CTreeNode* CTreeNode::selectNextChild() + { + std::list priorityQueue; + priorityQueue.push_back(this); + + bool selectNext = false; + + while (priorityQueue.size() > 0) + { + CTreeNode* visit = priorityQueue.front(); + priorityQueue.pop_front(); + + if (selectNext == true) + { + m_root->deselectAll(); + visit->setSelected(true); + return visit; + } + + if (visit->isSelected() == true) + { + selectNext = true; + } + + if (visit->m_expand && visit->m_innerPanel->Children.size() > 0) + { + std::list::iterator i = priorityQueue.begin(); + + for (CBase *c : visit->m_innerPanel->Children) + { + CTreeNode *node = dynamic_cast(c); + if (node && !node->isDisabled()) + { + i = priorityQueue.insert(i, node); + ++i; + } + } + } + } + + return NULL; + } + void CTreeNode::setSelected(bool b) { if (m_selected == b) diff --git a/Projects/Editor/Source/GUI/Controls/CTreeNode.h b/Projects/Editor/Source/GUI/Controls/CTreeNode.h index fb82680fc..ea6a18368 100644 --- a/Projects/Editor/Source/GUI/Controls/CTreeNode.h +++ b/Projects/Editor/Source/GUI/Controls/CTreeNode.h @@ -43,6 +43,7 @@ namespace Skylicht CTreeRowItem *m_row; CTreeNode *m_root; + CTreeNode *m_parentNode; bool m_expand; bool m_selected; @@ -97,15 +98,31 @@ namespace Skylicht invalidate(); } + inline bool haveChild() + { + return m_innerPanel->Children.size() > 0; + } + inline bool isSelected() { return m_selected; } + inline CTreeNode* getParentNode() + { + return m_parentNode; + } + + CTreeNode* getChildSelected(); + CTreeNode* selectFirstChild(); CTreeNode* selectLastChild(); + CTreeNode* selectNextChild(); + + CTreeNode* selectPrevChild(); + void setSelected(bool b); virtual void deselectAll();