bullet3/btgui/Gwen/Controls/TreeNode.cpp
Erwin Coumans 68f798a2da Start re-organizing demos so the physics setup can be shared easier (explicit create graphics objects, init/exit physics etc)
Add B3G_RETURN key code, only implemented in Windows so far (todo: Mac, Linux)
Fix Windows key management (use WM_CHAR event instead of WM_KEYUP
Add Return (OnKeyReturn) key support TreeNode, so we can select an item using the return key.
2014-06-24 10:14:06 -07:00

346 lines
6.9 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();
}
void TreeNode::Close()
{
m_InnerPanel->Hide();
if ( m_ToggleButton ) m_ToggleButton->SetToggleState( false );
Invalidate();
}
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);
}
}
}