Apply clang-format-all.sh using the _clang-format file through all the cpp/.h files. make sure not to apply it to certain serialization structures, since some parser expects the * as part of the name, instead of type. This commit contains no other changes aside from adding and applying clang-format-all.sh
339 lines
6.8 KiB
C++
339 lines
6.8 KiB
C++
/*
|
|
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);
|
|
}
|
|
}
|
|
} |