/* GWEN Copyright (c) 2010 Facepunch Studios See license in Gwen.h */ #include "Gwen/Controls/TreeNode.h" #include "Gwen/Controls/TreeControl.h" #include "Gwen/Utility.h" using namespace Gwen; using namespace Gwen::Controls; class OpenToggleButton : public Button { GWEN_CONTROL_INLINE(OpenToggleButton, Button) { SetIsToggle(true); SetTabable(false); } virtual void RenderFocus(Skin::Base* /*skin*/) {} virtual void Render(Skin::Base* skin) { skin->DrawTreeButton(this, GetToggleState()); } }; const int TreeIndentation = 14; const int BranchLength = 16; GWEN_CONTROL_CONSTRUCTOR(TreeNode) { m_TreeControl = NULL; m_ToggleButton = new OpenToggleButton(this); m_ToggleButton->SetBounds(2, 2, 13, 13); m_ToggleButton->onToggle.Add(this, &TreeNode::OnToggleButtonPress); m_Title = new Button(this); m_Title->Dock(Pos::Top); m_Title->SetMargin(Margin(BranchLength, 0, 0, 0)); m_Title->SetAlignment(Pos::Left | Pos::CenterV); m_Title->SetShouldDrawBackground(false); m_Title->onDoubleClick.Add(this, &TreeNode::OnDoubleClickName); m_Title->onDown.Add(this, &TreeNode::OnClickName); m_Title->SetHeight(16); m_InnerPanel = new Base(this); m_InnerPanel->Dock(Pos::Top); m_InnerPanel->SetHeight(100); m_InnerPanel->SetMargin(Margin(TreeIndentation, 1, 0, 0)); m_InnerPanel->Hide(); m_bRoot = false; m_bSelected = false; m_bSelectable = true; } void TreeNode::Render(Skin::Base* skin) { int iBottom = 0; if (m_InnerPanel->Children.size() > 0) { iBottom = m_InnerPanel->Children.back()->Y() + m_InnerPanel->Y(); } skin->DrawTreeNode(this, m_InnerPanel->Visible(), IsSelected(), m_Title->Height(), m_Title->TextRight(), m_ToggleButton->Y() + m_ToggleButton->Height() * 0.5, iBottom, GetParent() == m_TreeControl); } TreeNode* TreeNode::AddNode(const UnicodeString& strLabel) { // int sz = sizeof(TreeNode); TreeNode* node = new TreeNode(this); node->SetText(strLabel); node->Dock(Pos::Top); node->SetRoot(this->DynamicCastTreeControl() != NULL); node->SetTreeControl(m_TreeControl); if (m_TreeControl) { m_TreeControl->OnNodeAdded(node); } return node; } TreeNode* TreeNode::AddNode(const String& strLabel) { return AddNode(Utility::StringToUnicode(strLabel)); } void TreeNode::Layout(Skin::Base* skin) { if (m_ToggleButton) { if (m_InnerPanel->NumChildren() == 0) { m_ToggleButton->Hide(); m_ToggleButton->SetToggleState(false); m_InnerPanel->Hide(); } else { m_ToggleButton->Show(); m_InnerPanel->SizeToChildren(false, true); } } BaseClass::Layout(skin); } //too many calls to PostLayout... //int numCalls = 0xfd; void TreeNode::PostLayout(Skin::Base* /*skin*/) { //int bla = numCalls&0xffff; //if (bla==0) // printf("TreeNode::PostLayout numCalls = %d\n", numCalls); //numCalls++; if (SizeToChildren(false, true)) { InvalidateParent(); } } void TreeNode::SetText(const UnicodeString& text) { m_Title->SetText(text); }; void TreeNode::SetText(const String& text) { m_Title->SetText(text); }; UnicodeString TreeNode::GetText() const { UnicodeString bla = m_Title->GetText(); return bla; } void TreeNode::Open() { m_InnerPanel->Show(); if (m_ToggleButton) m_ToggleButton->SetToggleState(true); Invalidate(); if (m_TreeControl) m_TreeControl->ForceUpdateScrollBars(); } void TreeNode::Close() { m_InnerPanel->Hide(); if (m_ToggleButton) m_ToggleButton->SetToggleState(false); Invalidate(); if (m_TreeControl) m_TreeControl->ForceUpdateScrollBars(); } void TreeNode::ExpandAll() { Open(); Base::List& children = m_InnerPanel->GetChildren(); for (Base::List::iterator iter = children.begin(); iter != children.end(); ++iter) { TreeNode* pChild = (*iter)->DynamicCastTreeNode(); if (!pChild) continue; pChild->ExpandAll(); } } Button* TreeNode::GetButton() { return m_Title; } void TreeNode::OnToggleButtonPress(Base* /*control*/) { if (m_ToggleButton->GetToggleState()) { Open(); } else { Close(); } } void TreeNode::OnDoubleClickName(Base* /*control*/) { if (!m_ToggleButton->Visible()) return; m_ToggleButton->Toggle(); } void TreeNode::OnClickName(Base* /*control*/) { onNamePress.Call(this); SetSelected(!IsSelected()); } void TreeNode::SetSelected(bool b) { if (!m_bSelectable) return; if (m_bSelected == b) return; m_bSelected = b; onSelectChange.Call(this); if (m_bSelected) onSelect.Call(this); else onUnselect.Call(this); } void TreeNode::DeselectAll() { m_bSelected = false; Base::List& children = m_InnerPanel->GetChildren(); for (Base::List::iterator iter = children.begin(); iter != children.end(); ++iter) { TreeNode* pChild = (*iter)->DynamicCastTreeNode(); if (!pChild) continue; pChild->DeselectAll(); } } void TreeNode::iterate(int action, int* curIndex, int* targetIndex) { Gwen::String name = Gwen::Utility::UnicodeToString(m_Title->GetText()); // int actualIndex = curIndex? *curIndex : -1; //printf("iterated over item %d with name = %s\n", actualIndex, name.c_str()); if (action == ITERATE_ACTION_SELECT) { if (curIndex && targetIndex) { if ((*curIndex) == (*targetIndex)) { SetSelected(true); *targetIndex = -1; } } } if (IsSelected()) { //printf("current selected: name = %s\n", name.c_str()); switch (action) { case ITERATE_ACTION_DESELECT_INDEX: { if (targetIndex && curIndex) { if (*targetIndex == *curIndex) SetSelected(false); } break; } case ITERATE_ACTION_FIND_SELECTED_INDEX: { if (targetIndex && curIndex) { *targetIndex = *curIndex; } break; } case ITERATE_ACTION_OPEN: { Open(); break; } case ITERATE_ACTION_CLOSE: { //either close or select parent if (this->GetChildren().size()) { if (m_ToggleButton && m_ToggleButton->GetToggleState()) { Close(); } else { TreeNode* pChild = (GetParent())->DynamicCastTreeNode(); TreeControl* pChild2 = (GetParent())->DynamicCastTreeControl(); if (pChild && !pChild2) { SetSelected(false); pChild->SetSelected(true); } } } else { TreeNode* pChild = (GetParent())->DynamicCastTreeNode(); TreeControl* pChild2 = (GetParent())->DynamicCastTreeControl(); if (pChild && !pChild2) { SetSelected(false); pChild->SetSelected(true); } } break; } default: { } }; } if (curIndex) (*curIndex)++; bool needsRecursion = true; if (action == ITERATE_ACTION_FIND_SELECTED_INDEX || action == ITERATE_ACTION_SELECT || action == ITERATE_ACTION_DESELECT_INDEX) { if (m_ToggleButton && !m_ToggleButton->GetToggleState()) { needsRecursion = false; } } if (needsRecursion) { Base::List& children = m_InnerPanel->GetChildren(); for (Base::List::iterator iter = children.begin(); iter != children.end(); ++iter) { TreeNode* pChild = (*iter)->DynamicCastTreeNode(); if (!pChild) continue; pChild->iterate(action, curIndex, targetIndex); } } }