1669 lines
37 KiB
C++
1669 lines
37 KiB
C++
/*
|
|
** Command & Conquer Renegade(tm)
|
|
** Copyright 2025 Electronic Arts Inc.
|
|
**
|
|
** This program is free software: you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation, either version 3 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
|
|
***********************************************************************************************
|
|
* *
|
|
* Project Name : wwui *
|
|
* *
|
|
* $Archive:: /Commando/Code/wwui/treectrl.cpp $*
|
|
* *
|
|
* Author:: Patrick Smith *
|
|
* *
|
|
* $Modtime:: 11/08/01 5:56p $*
|
|
* *
|
|
* $Revision:: 2 $*
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
#include "treectrl.h"
|
|
#include "assetmgr.h"
|
|
#include "refcount.h"
|
|
#include "font3d.h"
|
|
#include "mousemgr.h"
|
|
#include "ww3d.h"
|
|
#include "dialogmgr.h"
|
|
#include "dialogbase.h"
|
|
#include "stylemgr.h"
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Local constants
|
|
////////////////////////////////////////////////////////////////
|
|
static const char *PLUS_IMAGE = "if_treeplus.tga";
|
|
|
|
static const RectClass PLUS_RECT = RectClass (0, 0, 16, 16);
|
|
static const RectClass MINUS_RECT = RectClass (16, 0, 32, 16);
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Static member initialization
|
|
////////////////////////////////////////////////////////////////
|
|
TREECTRL_SORT_CALLBACK TreeCtrlClass::CurrentSortCallback = NULL;
|
|
TreeCtrlClass * TreeCtrlClass::CurrentSorter = NULL;
|
|
uint32 TreeCtrlClass::CurrentSortUserData = 0;
|
|
const char * TreeCtrlClass::ICON_FOLDER = "if_treefld.tga";
|
|
const char * TreeCtrlClass::ICON_FOLDER_OPEN = "if_treefld_open.tga";
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// TreeCtrlClass
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeCtrlClass::TreeCtrlClass (void) :
|
|
SelectedItem (NULL),
|
|
ScrollPos (0),
|
|
RowHeight (0),
|
|
RowsPerPage (0),
|
|
IsScrollBarDisplayed (false)
|
|
{
|
|
//
|
|
// Set the font for the text renderers
|
|
//
|
|
StyleMgrClass::Assign_Font (&TextRenderer, StyleMgrClass::FONT_LISTS);
|
|
StyleMgrClass::Configure_Renderer (&ControlRenderer);
|
|
StyleMgrClass::Configure_Renderer (&PlusRenderer);
|
|
StyleMgrClass::Configure_Renderer (&IconRenderer);
|
|
HilightRenderer.Set_Coordinate_Range (Render2DClass::Get_Screen_Resolution());
|
|
StyleMgrClass::Configure_Hilighter (&HilightRenderer);
|
|
|
|
//
|
|
// Load the "plus" texture
|
|
//
|
|
TextureClass *texture = WW3DAssetManager::Get_Instance ()->Get_Texture (PLUS_IMAGE, TextureClass::MIP_LEVELS_1);
|
|
if (texture != NULL) {
|
|
PlusRenderer.Set_Texture (texture);
|
|
REF_PTR_RELEASE (texture);
|
|
}
|
|
|
|
TextRenderer.Set_Texture_Size_Hint (256);
|
|
|
|
//
|
|
// We don't want the scroll bar getting focus
|
|
//
|
|
ScrollBarCtrl.Set_Wants_Focus (false);
|
|
ScrollBarCtrl.Set_Advise_Sink (this);
|
|
ScrollBarCtrl.Set_Is_Embedded (true);
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// ~TreeCtrlClass
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeCtrlClass::~TreeCtrlClass (void)
|
|
{
|
|
ScrollBarCtrl.Set_Advise_Sink (NULL);
|
|
|
|
if (Parent != NULL) {
|
|
Parent->Remove_Control (&ScrollBarCtrl);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Create_Text_Renderers
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::Create_Text_Renderers (void)
|
|
{
|
|
//
|
|
// Configure the renderers
|
|
//
|
|
HilightRenderer.Reset ();
|
|
TextRenderer.Reset ();
|
|
IconRenderer.Reset ();
|
|
PlusRenderer.Reset ();
|
|
IconMgr.Reset_Renderers ();
|
|
|
|
float x_pos = ClientRect.Left;
|
|
float y_pos = ClientRect.Top;
|
|
|
|
int row_index = 0;
|
|
int level = 0;
|
|
|
|
//
|
|
// Render each row...
|
|
//
|
|
for (int index = 0; index < ItemList.Count (); index ++) {
|
|
TreeItemClass *item = ItemList[index];
|
|
if (Render_Item (item, x_pos, y_pos, row_index, level) == false) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Render_Item
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
bool
|
|
TreeCtrlClass::Render_Item (TreeItemClass *item, float x_pos, float &y_pos, int &row_index, int level)
|
|
{
|
|
bool retval = true;
|
|
if (item == NULL) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Determine which color to draw the outline in
|
|
//
|
|
int color = StyleMgrClass::Get_Line_Color ();
|
|
if (IsEnabled == false) {
|
|
color = StyleMgrClass::Get_Disabled_Line_Color ();
|
|
}
|
|
|
|
const float LINE_START = 16.0F * StyleMgrClass::Get_X_Scale ();
|
|
const float LINE_SPACING = 16.0F * StyleMgrClass::Get_X_Scale ();
|
|
const float TEXT_SPACING = 4.0F * StyleMgrClass::Get_X_Scale ();
|
|
|
|
//
|
|
// Build the display rectangles
|
|
//
|
|
RectClass rect;
|
|
rect.Left = ClientRect.Left + LINE_START + int(level * LINE_SPACING);
|
|
rect.Top = y_pos;
|
|
rect.Right = ClientRect.Right;
|
|
rect.Bottom = y_pos + RowHeight;
|
|
|
|
RectClass plus_rect;
|
|
plus_rect.Left = int(rect.Left - LINE_SPACING);
|
|
plus_rect.Top = int(rect.Center ().Y - (LINE_SPACING * 0.5F));
|
|
plus_rect.Right = int((plus_rect.Left + LINE_SPACING));
|
|
plus_rect.Bottom = int(rect.Center ().Y + (LINE_SPACING * 0.5F));
|
|
|
|
RectClass icon_rect;
|
|
icon_rect.Left = rect.Left;
|
|
icon_rect.Top = rect.Top;
|
|
icon_rect.Right = icon_rect.Left + LINE_SPACING;
|
|
icon_rect.Bottom = rect.Bottom;
|
|
|
|
RectClass text_rect;
|
|
text_rect.Left = icon_rect.Right + TEXT_SPACING;
|
|
text_rect.Top = rect.Top;
|
|
text_rect.Right = rect.Right;
|
|
text_rect.Bottom = rect.Bottom;
|
|
|
|
//
|
|
// Only draw the entry if its inside the view
|
|
//
|
|
if (row_index >= ScrollPos && ((y_pos + RowHeight) <= ClientRect.Bottom)) {
|
|
|
|
//
|
|
// Draw the tick to the left of the entry
|
|
//
|
|
if (level > 0) {
|
|
float half_rect = rect.Height () / 2;
|
|
Vector2 line_start (icon_rect.Left - (LINE_SPACING * 0.5F), rect.Top + half_rect);
|
|
Vector2 line_end (icon_rect.Left, rect.Top + half_rect);
|
|
ControlRenderer.Add_Line (line_start, line_end, 1.0F, color);
|
|
}
|
|
|
|
//
|
|
// Draw the plus (if necessary)
|
|
//
|
|
if ((item->Get_Child_Count () > 0 || item->Needs_Children ())) {
|
|
|
|
RectClass plus_uv_rect = PLUS_RECT;
|
|
if (item->Is_Expanded ()) {
|
|
plus_uv_rect = MINUS_RECT;
|
|
}
|
|
|
|
plus_uv_rect.Inverse_Scale (Vector2 (32.0F, 32.0F));
|
|
PlusRenderer.Add_Quad (plus_rect, plus_uv_rect);
|
|
}
|
|
|
|
//
|
|
// Render the icon
|
|
//
|
|
const char *icon_name = item->Get_Icon ();
|
|
if (SelectedItem == item) {
|
|
icon_name = item->Get_Selected_Icon ();
|
|
}
|
|
if (icon_name != NULL && icon_name[0] != 0) {
|
|
IconMgr.Render_Icon (icon_rect, icon_name);
|
|
}
|
|
|
|
//
|
|
// Draw the text
|
|
//
|
|
StyleMgrClass::Render_Text (item->Get_Name (), &TextRenderer, text_rect, true, true,
|
|
StyleMgrClass::LEFT_JUSTIFY, IsEnabled);
|
|
|
|
|
|
//
|
|
// Adjust the width of the rectangle so its the approximate size
|
|
// of the text
|
|
//
|
|
float width = TextRenderer.Get_Text_Extents (item->Get_Name ()).X;
|
|
text_rect.Right = text_rect.Left + width + TEXT_SPACING;
|
|
|
|
//
|
|
// Is this the selected item?
|
|
//
|
|
if (SelectedItem == item) {
|
|
|
|
if (HasFocus) {
|
|
RectClass hilight_rect = text_rect;
|
|
hilight_rect.Right -= 1.0F;
|
|
hilight_rect.Bottom -= 1.0F;
|
|
StyleMgrClass::Render_Hilight (&HilightRenderer, hilight_rect);
|
|
}
|
|
ControlRenderer.Add_Outline (text_rect, 1.0F, color);
|
|
}
|
|
|
|
//
|
|
// Move down one row
|
|
//
|
|
y_pos += RowHeight;
|
|
}
|
|
|
|
row_index ++;
|
|
retval = ((y_pos + RowHeight) <= ClientRect.Bottom);
|
|
|
|
//
|
|
// Should we render the children?
|
|
//
|
|
if (item->Is_Expanded ()) {
|
|
|
|
float start_y_pos = y_pos;
|
|
int start_row_index = max (row_index, ScrollPos);
|
|
int end_row_index = start_row_index;
|
|
|
|
//
|
|
// Render each child item
|
|
//
|
|
int child_count = item->Get_Child_Count ();
|
|
for (int index = 0; index < child_count; index ++) {
|
|
end_row_index = row_index + 1;
|
|
retval = Render_Item (item->Get_Child (index), x_pos, y_pos, row_index, level + 1);
|
|
}
|
|
|
|
//
|
|
// Render the line connecting this item to all its children
|
|
//
|
|
if ( end_row_index != start_row_index &&
|
|
end_row_index >= ScrollPos &&
|
|
start_row_index <= (ScrollPos + RowsPerPage))
|
|
{
|
|
float end_y_pos = start_y_pos + (end_row_index - start_row_index) * RowHeight;
|
|
|
|
//
|
|
// Clip the line start and end to the window
|
|
//
|
|
end_y_pos = min (end_y_pos, ClientRect.Top + (RowsPerPage * RowHeight));
|
|
start_y_pos = max (start_y_pos, ClientRect.Top);
|
|
|
|
//
|
|
// Render the line
|
|
//
|
|
if (start_y_pos < end_y_pos) {
|
|
float icon_x_pos = icon_rect.Center ().X;
|
|
Vector2 line_start (icon_x_pos, start_y_pos);
|
|
Vector2 line_end (icon_x_pos, end_y_pos - (RowHeight * 0.5F));
|
|
ControlRenderer.Add_Line (line_start, line_end, 1.0F, color);
|
|
}
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Set_Scroll_Pos
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::Set_Scroll_Pos (int new_pos)
|
|
{
|
|
//
|
|
// Ensure this scroll position doesn't extend out of bounds
|
|
//
|
|
int visible_rows = Count_Visible_Rows ();
|
|
new_pos = min (visible_rows - RowsPerPage, new_pos);
|
|
new_pos = max (new_pos, 0);
|
|
|
|
//
|
|
// Did anything change?
|
|
//
|
|
if (ScrollPos != new_pos) {
|
|
ScrollPos = new_pos;
|
|
ScrollBarCtrl.Set_Pos (ScrollPos, false);
|
|
Set_Dirty ();
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Count_Visible_Rows
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
int
|
|
TreeCtrlClass::Count_Visible_Rows (void)
|
|
{
|
|
int total = 0;
|
|
|
|
//
|
|
// Count each row
|
|
//
|
|
for (int index = 0; index < ItemList.Count (); index ++) {
|
|
TreeItemClass *item = ItemList[index];
|
|
|
|
//
|
|
// Count this item and it's children
|
|
//
|
|
total += Count_Visible_Rows (item);
|
|
}
|
|
|
|
return total;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Count_Visible_Rows
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
int
|
|
TreeCtrlClass::Count_Visible_Rows (TreeItemClass *item)
|
|
{
|
|
if (item == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
int total = 1;
|
|
|
|
//
|
|
// Should we count the children?
|
|
//
|
|
if (item->Is_Expanded ()) {
|
|
|
|
//
|
|
// Count each child
|
|
//
|
|
int child_count = item->Get_Child_Count ();
|
|
for (int index = 0; index < child_count; index ++) {
|
|
total += Count_Visible_Rows (item->Get_Child (index));
|
|
}
|
|
}
|
|
|
|
return total;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Create_Control_Renderers
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::Create_Control_Renderers (void)
|
|
{
|
|
Render2DClass &renderer = ControlRenderer;
|
|
|
|
//
|
|
// Configure this renderer
|
|
//
|
|
renderer.Reset ();
|
|
renderer.Enable_Texturing (false);
|
|
|
|
//
|
|
// Determine which color to draw the outline in
|
|
//
|
|
int color = StyleMgrClass::Get_Line_Color ();
|
|
int bkcolor = StyleMgrClass::Get_Bk_Color ();
|
|
if (IsEnabled == false) {
|
|
color = StyleMgrClass::Get_Disabled_Line_Color ();
|
|
bkcolor = StyleMgrClass::Get_Disabled_Bk_Color ();
|
|
}
|
|
|
|
//
|
|
// Draw the outline
|
|
//
|
|
renderer.Add_Rect (Rect, 1.0F, color, bkcolor);
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// On_Set_Cursor
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::On_Set_Cursor (const Vector2 &mouse_pos)
|
|
{
|
|
//
|
|
// Change the mouse cursor
|
|
//
|
|
MouseMgrClass::Set_Cursor (MouseMgrClass::CURSOR_ACTION);
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Update_Client_Rect
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::Update_Client_Rect (void)
|
|
{
|
|
const float BORDER_SIZE_X = 4.0F * StyleMgrClass::Get_X_Scale ();
|
|
const float BORDER_SIZE_Y = 4.0F * StyleMgrClass::Get_Y_Scale ();
|
|
|
|
//
|
|
// Set the client area
|
|
//
|
|
ClientRect = Rect;
|
|
ClientRect.Inflate (Vector2 (-BORDER_SIZE_X, -BORDER_SIZE_Y));
|
|
|
|
//
|
|
// Calculate how tall each row should be...
|
|
//
|
|
const float ROW_SPACING = 4.0F;
|
|
float border_height = (ROW_SPACING * StyleMgrClass::Get_Y_Scale ());
|
|
RowHeight = (TextRenderer.Get_Text_Extents (L"W").Y + border_height);
|
|
|
|
//
|
|
// Determine how many rows we can fit on a page
|
|
//
|
|
RowsPerPage = ClientRect.Height () / RowHeight;
|
|
ClientRect.Top = int(Rect.Center ().Y - (RowsPerPage * RowHeight * 0.5F));
|
|
ClientRect.Bottom = int(Rect.Center ().Y + (RowsPerPage * RowHeight * 0.5F));
|
|
|
|
//
|
|
// Choose an arbitrary width, the scroll bar
|
|
// will snap to the only width it supports
|
|
//
|
|
float width = 10;
|
|
|
|
//
|
|
// Calculate the scroll bar's rectangle
|
|
//
|
|
RectClass scroll_rect;
|
|
scroll_rect.Left = Rect.Right - width;
|
|
scroll_rect.Top = Rect.Top;
|
|
scroll_rect.Right = Rect.Right;
|
|
scroll_rect.Bottom = Rect.Bottom;
|
|
|
|
//
|
|
// Size the scroll bar
|
|
//
|
|
ScrollBarCtrl.Set_Window_Rect (scroll_rect);
|
|
|
|
Update_Scroll_Bar_Visibility ();
|
|
Set_Dirty ();
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// On_VScroll
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::On_VScroll (ScrollBarCtrlClass *, int , int new_position)
|
|
{
|
|
Set_Scroll_Pos (new_position);
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Render
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::Render (void)
|
|
{
|
|
//
|
|
// Recreate the renderers (if necessary)
|
|
//
|
|
if (IsDirty) {
|
|
Create_Control_Renderers ();
|
|
Create_Text_Renderers ();
|
|
}
|
|
|
|
//
|
|
// Render the background and text for the current state
|
|
//
|
|
IconMgr.Render_Icons ();
|
|
TextRenderer.Render ();
|
|
ControlRenderer.Render ();
|
|
PlusRenderer.Render ();
|
|
HilightRenderer.Render ();
|
|
|
|
DialogControlClass::Render ();
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Sort_Children_Alphabetically
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::Sort_Children_Alphabetically (TreeItemClass *parent)
|
|
{
|
|
Sort_Children (parent, Alphabetic_Sort_Callback, 0);
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Sort_Children
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::Sort_Children (TreeItemClass *parent, TREECTRL_SORT_CALLBACK sort_callback, uint32 user_data)
|
|
{
|
|
CurrentSortCallback = sort_callback;
|
|
CurrentSorter = this;
|
|
CurrentSortUserData = user_data;
|
|
|
|
if (parent == NULL) {
|
|
|
|
//
|
|
// Sort the root-level entries
|
|
//
|
|
if (ItemList.Count () != 0) {
|
|
::qsort (&ItemList[0], ItemList.Count (), sizeof (ItemList[0]), Sort_Callback);
|
|
}
|
|
|
|
} else {
|
|
|
|
TREE_ITEM_LIST &child_list = parent->Get_Child_List ();
|
|
|
|
//
|
|
// Sort the immediate children of this item
|
|
//
|
|
if (child_list.Count () != 0) {
|
|
::qsort (&child_list[0], child_list.Count (), sizeof (child_list[0]), Sort_Callback);
|
|
}
|
|
}
|
|
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Sort_Callback
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
int __cdecl
|
|
TreeCtrlClass::Sort_Callback (const void *elem1, const void *elem2)
|
|
{
|
|
WWASSERT (elem1 != NULL);
|
|
WWASSERT (elem2 != NULL);
|
|
TreeItemClass *item1 = *((TreeItemClass **)elem1);
|
|
TreeItemClass *item2 = *((TreeItemClass **)elem2);
|
|
|
|
//
|
|
// Pass the sorting off to the user... (NOT THREAD SAFE)
|
|
//
|
|
return CurrentSortCallback (CurrentSorter, item1, item2, CurrentSortUserData);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Alphabetic_Sort_Callback
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
int CALLBACK
|
|
TreeCtrlClass::Alphabetic_Sort_Callback
|
|
(
|
|
TreeCtrlClass * tree_ctrl,
|
|
TreeItemClass * item1,
|
|
TreeItemClass * item2,
|
|
uint32 user_param
|
|
)
|
|
{
|
|
//
|
|
// Sort by name
|
|
//
|
|
const WCHAR *name1 = item1->Get_Name ();
|
|
const WCHAR *name2 = item2->Get_Name ();
|
|
int result = ::CompareStringW (LOCALE_USER_DEFAULT, NORM_IGNORECASE, name1, -1, name2, -1);
|
|
|
|
int retval = 0;
|
|
if (result == CSTR_LESS_THAN) {
|
|
retval = -1;
|
|
} else if (result == CSTR_GREATER_THAN) {
|
|
retval = 1;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Find_Top_Item
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeItemClass *
|
|
TreeCtrlClass::Find_Top_Item (void)
|
|
{
|
|
TreeItemClass *retval = NULL;
|
|
|
|
//
|
|
// Count visible items until we've hit the current scroll position
|
|
//
|
|
retval = ItemList.Count () > 0 ? ItemList[0] : NULL;
|
|
for (int index = 0; retval != NULL && index < ScrollPos; index ++) {
|
|
retval = Find_Next_Visible (retval);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Find_Last_Visible_Item
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeItemClass *
|
|
TreeCtrlClass::Find_Last_Visible_Item (void)
|
|
{
|
|
//
|
|
// Determine where to start...
|
|
//
|
|
TreeItemClass *curr_item = NULL;
|
|
if (ItemList.Count () > 0) {
|
|
curr_item = ItemList[ItemList.Count () - 1];
|
|
}
|
|
|
|
//
|
|
// Keep searching until we stop finding new visible items...
|
|
//
|
|
while (curr_item != NULL) {
|
|
TreeItemClass *next_item = Find_Next_Visible (curr_item);
|
|
if (next_item == curr_item) {
|
|
break;
|
|
}
|
|
curr_item = next_item;
|
|
}
|
|
|
|
return curr_item;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Hit_Test
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeItemClass *
|
|
TreeCtrlClass::Hit_Test (const Vector2 &mouse_pos, HITTYPE &type)
|
|
{
|
|
TreeItemClass *retval = NULL;
|
|
|
|
//
|
|
// Attempt to locate the first visible item
|
|
//
|
|
TreeItemClass *hit_item = Find_Top_Item ();
|
|
if (hit_item != NULL) {
|
|
|
|
//
|
|
// Determine on which row of the screen the user clicked
|
|
//
|
|
int row_index = (mouse_pos.Y - ClientRect.Top) / RowHeight;
|
|
|
|
//
|
|
// Now move down that number of items...
|
|
//
|
|
for (int index = 0; hit_item != NULL && index < row_index; index ++) {
|
|
hit_item = Find_Next_Visible (hit_item);
|
|
}
|
|
|
|
const float LINE_START = 16.0F * StyleMgrClass::Get_X_Scale ();
|
|
const float LINE_SPACING = 16.0F * StyleMgrClass::Get_X_Scale ();
|
|
const float TEXT_SPACING = 4.0F * StyleMgrClass::Get_X_Scale ();
|
|
|
|
//
|
|
// Now determine on what part of the item the user clicked...
|
|
//
|
|
if (hit_item != NULL) {
|
|
int level = hit_item->Get_Indent_Level ();
|
|
float icon_left = ClientRect.Left + LINE_START + int(level * LINE_SPACING);
|
|
float plus_left = icon_left - LINE_SPACING;
|
|
float text_left = icon_left + LINE_SPACING + TEXT_SPACING;
|
|
|
|
//
|
|
// Return the hit type and hit item to the caller
|
|
//
|
|
if (mouse_pos.X >= plus_left && mouse_pos.X < icon_left) {
|
|
type = HIT_PLUS;
|
|
retval = hit_item;
|
|
} else if (mouse_pos.X >= icon_left && mouse_pos.X < text_left) {
|
|
type = HIT_ICON;
|
|
retval = hit_item;
|
|
} else if (mouse_pos.X >= text_left) {
|
|
type = HIT_TEXT;
|
|
retval = hit_item;
|
|
}
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// On_LButton_Down
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::On_LButton_Down (const Vector2 &mouse_pos)
|
|
{
|
|
//
|
|
// Find which item hit clicked on
|
|
//
|
|
HITTYPE type;
|
|
TreeItemClass *tree_item = Hit_Test (mouse_pos, type);
|
|
if (tree_item != NULL) {
|
|
SelectedItem = tree_item;
|
|
|
|
//
|
|
// Toggle the expanded state if the user clicked on the
|
|
// plus
|
|
//
|
|
if (type == HIT_PLUS) {
|
|
tree_item->Expand (!tree_item->Is_Expanded ());
|
|
}
|
|
Set_Dirty ();
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// On_LButton_DblClk
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::On_LButton_DblClk (const Vector2 &mouse_pos)
|
|
{
|
|
//
|
|
// Find which item hit clicked on
|
|
//
|
|
HITTYPE type;
|
|
TreeItemClass *tree_item = Hit_Test (mouse_pos, type);
|
|
if (tree_item != NULL) {
|
|
SelectedItem = tree_item;
|
|
|
|
//
|
|
// Toggle the expanded state if the user clicked on the
|
|
// plus
|
|
//
|
|
tree_item->Expand (!tree_item->Is_Expanded ());
|
|
Set_Dirty ();
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// On_LButton_Up
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::On_LButton_Up (const Vector2 &mouse_pos)
|
|
{
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// On_Set_Focus
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::On_Set_Focus (void)
|
|
{
|
|
Set_Dirty ();
|
|
|
|
DialogControlClass::On_Set_Focus ();
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// On_Kill_Focus
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::On_Kill_Focus (DialogControlClass *focus)
|
|
{
|
|
Set_Dirty ();
|
|
|
|
DialogControlClass::On_Kill_Focus (focus);
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// On_Mouse_Wheel
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::On_Mouse_Wheel (int direction)
|
|
{
|
|
if (direction < 0) {
|
|
Set_Scroll_Pos (ScrollPos - 1);
|
|
} else {
|
|
Set_Scroll_Pos (ScrollPos + 1);
|
|
}
|
|
|
|
Set_Dirty ();
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// On_Key_Down
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
bool
|
|
TreeCtrlClass::On_Key_Down (uint32 key_id, uint32 key_data)
|
|
{
|
|
bool handled = false;
|
|
bool is_dirty = true;
|
|
|
|
switch (key_id)
|
|
{
|
|
case VK_HOME:
|
|
if (ItemList.Count () > 0) {
|
|
SelectedItem = ItemList[0];
|
|
Set_Scroll_Pos (0);
|
|
}
|
|
break;
|
|
|
|
case VK_END:
|
|
if (ItemList.Count () > 0) {
|
|
SelectedItem = Find_Last_Visible_Item ();
|
|
Ensure_Visible (SelectedItem);
|
|
}
|
|
break;
|
|
|
|
case VK_UP:
|
|
SelectedItem = Find_Prev_Visible (SelectedItem);
|
|
Ensure_Visible (SelectedItem);
|
|
Set_Dirty ();
|
|
break;
|
|
|
|
case VK_DOWN:
|
|
SelectedItem = Find_Next_Visible (SelectedItem);
|
|
Ensure_Visible (SelectedItem);
|
|
Set_Dirty ();
|
|
break;
|
|
|
|
case VK_RIGHT:
|
|
if (SelectedItem != NULL) {
|
|
SelectedItem->Expand (true);
|
|
}
|
|
break;
|
|
|
|
case VK_LEFT:
|
|
if (SelectedItem != NULL) {
|
|
SelectedItem->Expand (false);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
is_dirty = false;
|
|
break;
|
|
}
|
|
|
|
if (is_dirty) {
|
|
Set_Dirty ();
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// On_Create
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::On_Create (void)
|
|
{
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Ensure_Visible
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::Ensure_Visible (TreeItemClass *item_to_find)
|
|
{
|
|
if (item_to_find == NULL) {
|
|
Set_Scroll_Pos (0);
|
|
Set_Dirty ();
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Start at the first visible item and keep going until we've found the
|
|
// item we're looking for
|
|
//
|
|
TreeItemClass *item = ItemList.Count () > 0 ? ItemList[0] : NULL;
|
|
for (int row_index = 0; item != NULL; row_index ++) {
|
|
|
|
if (item == item_to_find) {
|
|
|
|
//
|
|
// Determine if this row is outside the visible window
|
|
//
|
|
if (row_index < ScrollPos) {
|
|
Set_Scroll_Pos (row_index);
|
|
Set_Dirty ();
|
|
} else if (row_index >= ScrollPos + RowsPerPage) {
|
|
Set_Scroll_Pos (row_index - (RowsPerPage-1));
|
|
Set_Dirty ();
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Advance to the next visible item
|
|
//
|
|
item = Find_Next_Visible (item);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Insert_Item
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeItemClass *
|
|
TreeCtrlClass::Insert_Item
|
|
(
|
|
const WCHAR * name,
|
|
const char * icon_name,
|
|
const char * selected_icon_name,
|
|
TreeItemClass * parent
|
|
)
|
|
{
|
|
//
|
|
// Allocate a new tree item
|
|
//
|
|
TreeItemClass *retval = new TreeItemClass (this);
|
|
retval->Set_Name (name);
|
|
retval->Set_Icon (icon_name);
|
|
retval->Set_Selected_Icon (selected_icon_name);
|
|
|
|
//
|
|
// Now insert this item into the tree
|
|
//
|
|
if (parent != NULL) {
|
|
parent->Add_Child (retval);
|
|
retval->Set_Parent (parent);
|
|
} else {
|
|
ItemList.Add (retval);
|
|
|
|
//
|
|
// Select the first item by default
|
|
//
|
|
if (ItemList.Count () == 1) {
|
|
SelectedItem = retval;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check to see if we need a scroll bar or not
|
|
//
|
|
Update_Scroll_Bar_Visibility ();
|
|
Set_Dirty ();
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Delete_Item
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::Delete_Item (TreeItemClass *item)
|
|
{
|
|
if (item == NULL) {
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Remove the selected item if necessary
|
|
//
|
|
if (SelectedItem == item) {
|
|
SelectedItem = NULL;
|
|
}
|
|
|
|
//
|
|
// Notify any advise sinks
|
|
//
|
|
ADVISE_NOTIFY (On_TreeCtrl_Delete_Item (this, Get_ID (), item));
|
|
|
|
//
|
|
// Recursively delete all this item's children
|
|
//
|
|
int child_count = item->Get_Child_Count ();
|
|
for (int index = 0; index < child_count; index ++) {
|
|
TreeItemClass *child = item->Get_Child (index);
|
|
Delete_Item (child);
|
|
}
|
|
|
|
//
|
|
// Now unlink this child from its parent (or the root list)
|
|
//
|
|
TreeItemClass *parent = item->Get_Parent ();
|
|
if (parent != NULL) {
|
|
parent->Remove_Child (item);
|
|
} else {
|
|
|
|
//
|
|
// Remove this item from the root list
|
|
//
|
|
index = ItemList.ID (item);
|
|
if (index != -1) {
|
|
ItemList.Delete (index);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free this item
|
|
//
|
|
delete item;
|
|
item = NULL;
|
|
|
|
//
|
|
// Ensure the scroll bar is correctly displayed
|
|
//
|
|
Update_Scroll_Bar_Visibility ();
|
|
|
|
Set_Dirty ();
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Delete_All_Items
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::Delete_All_Items (void)
|
|
{
|
|
//
|
|
// Note: We count down because the Delete_Item () call will
|
|
// delete the entry from the list...
|
|
//
|
|
int index = ItemList.Count ();
|
|
while (index --) {
|
|
Delete_Item (ItemList[index]);
|
|
}
|
|
|
|
//
|
|
// Ensure the scroll bar is correctly displayed
|
|
//
|
|
ScrollPos = 0;
|
|
SelectedItem = NULL;
|
|
Update_Scroll_Bar_Visibility ();
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Select_Item
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::Select_Item (TreeItemClass *item)
|
|
{
|
|
//
|
|
// Notify any advise sinks
|
|
//
|
|
ADVISE_NOTIFY (On_TreeCtrl_Sel_Change (this, Get_ID (), SelectedItem, item));
|
|
|
|
SelectedItem = item;
|
|
Set_Dirty ();
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Selected_Item
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeItemClass *
|
|
TreeCtrlClass::Get_Selected_Item (void)
|
|
{
|
|
return SelectedItem;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Next_Sibling
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeItemClass *
|
|
TreeCtrlClass::Get_Next_Sibling (TreeItemClass *item)
|
|
{
|
|
TreeItemClass *retval = NULL;
|
|
if (item == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// If this item has a parent, then ask it for the sibling...
|
|
//
|
|
TreeItemClass *parent = item->Get_Parent ();
|
|
if (parent != NULL) {
|
|
retval = parent->Get_Next_Child (item);
|
|
} else {
|
|
|
|
//
|
|
// Return the next entry in the root item list...
|
|
//
|
|
int index = ItemList.ID (item);
|
|
if (index != -1 && (index + 1) < ItemList.Count ()) {
|
|
retval = ItemList[index + 1];
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Prev_Sibling
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeItemClass *
|
|
TreeCtrlClass::Get_Prev_Sibling (TreeItemClass *item)
|
|
{
|
|
TreeItemClass *retval = NULL;
|
|
if (item == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// If this item has a parent, then ask it for the sibling...
|
|
//
|
|
TreeItemClass *parent = item->Get_Parent ();
|
|
if (parent != NULL) {
|
|
retval = parent->Get_Prev_Child (item);
|
|
} else {
|
|
|
|
//
|
|
// Return the previous entry in the root item list...
|
|
//
|
|
int index = ItemList.ID (item);
|
|
if (index > 0) {
|
|
retval = ItemList[index - 1];
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Find_Prev_Visible
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeItemClass *
|
|
TreeCtrlClass::Find_Prev_Visible (TreeItemClass *item)
|
|
{
|
|
TreeItemClass *retval = NULL;
|
|
if (item == NULL) {
|
|
if (ItemList.Count () > 0) {
|
|
return ItemList[0];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Simply find the previous sibling of this item.
|
|
// If you can't find the sibling, then return its parent
|
|
//
|
|
retval = Get_Prev_Sibling (item);
|
|
if (retval == NULL) {
|
|
retval = item->Get_Parent ();
|
|
} else {
|
|
|
|
while (retval->Is_Expanded ()) {
|
|
|
|
//
|
|
// Find the last child for this given item
|
|
//
|
|
TreeItemClass *curr_item = retval->Get_Last_Child ();
|
|
if (curr_item != NULL) {
|
|
retval = curr_item;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we didn't find a previous visible entry, then
|
|
// simply return the item we were given
|
|
//
|
|
if (retval == NULL) {
|
|
retval = item;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Find_Next_Visible
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeItemClass *
|
|
TreeCtrlClass::Find_Next_Visible (TreeItemClass *item)
|
|
{
|
|
TreeItemClass *retval = NULL;
|
|
if (item == NULL) {
|
|
if (ItemList.Count () > 0) {
|
|
return ItemList[0];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// First try to get this item's first child...
|
|
//
|
|
if (item->Is_Expanded () && item->Get_Child_Count () > 0) {
|
|
retval = item->Get_Child (0);
|
|
}
|
|
|
|
if (retval == NULL) {
|
|
|
|
//
|
|
// Try to find this item's next sibling...
|
|
//
|
|
retval = Get_Next_Sibling (item);
|
|
if (retval == NULL) {
|
|
|
|
//
|
|
// Loop outwards through each parent until
|
|
// we can find the next sibling of any parent...
|
|
//
|
|
TreeItemClass *curr_item = item;
|
|
while (curr_item != NULL && retval == NULL) {
|
|
|
|
curr_item = curr_item->Get_Parent ();
|
|
if (curr_item != NULL) {
|
|
retval = Get_Next_Sibling (curr_item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we didn't find a previous visible entry, then
|
|
// simply return the item we were given
|
|
//
|
|
if (retval == NULL) {
|
|
retval = item;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Update_Scroll_Bar_Visibility
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::Update_Scroll_Bar_Visibility (void)
|
|
{
|
|
int visible_rows = Count_Visible_Rows ();
|
|
|
|
//
|
|
// Determine if we have more entries then we can
|
|
// display on one page
|
|
//
|
|
bool needs_scrollbar = (visible_rows > RowsPerPage);
|
|
float new_right = 0;
|
|
|
|
if (needs_scrollbar != IsScrollBarDisplayed) {
|
|
|
|
//
|
|
// Do we need to show a scroll bar?
|
|
//
|
|
if (needs_scrollbar) {
|
|
new_right = ScrollBarCtrl.Get_Window_Rect ().Left;
|
|
IsScrollBarDisplayed = true;
|
|
} else if (Parent != NULL) {
|
|
new_right = ScrollBarCtrl.Get_Window_Rect ().Right;
|
|
IsScrollBarDisplayed = false;
|
|
}
|
|
|
|
const float BORDER_SIZE_X = 4.0F * StyleMgrClass::Get_X_Scale ();
|
|
|
|
//
|
|
// Reset our window size (as necessary)
|
|
//
|
|
Rect.Right = new_right;
|
|
ClientRect.Left = Rect.Left + BORDER_SIZE_X;
|
|
ClientRect.Right = Rect.Right - BORDER_SIZE_X;
|
|
|
|
//
|
|
// Add or remove the scrollbar (as necessary)
|
|
//
|
|
if (IsScrollBarDisplayed) {
|
|
Parent->Add_Control (&ScrollBarCtrl);
|
|
} else {
|
|
Parent->Remove_Control (&ScrollBarCtrl);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Configure the scroll-bar's ranges
|
|
//
|
|
ScrollBarCtrl.Set_Page_Size (RowsPerPage);
|
|
ScrollBarCtrl.Set_Range (0, visible_rows - RowsPerPage);
|
|
ScrollBarCtrl.Set_Pos (ScrollPos);
|
|
ScrollPos = ScrollBarCtrl.Get_Pos ();
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// On_Expanded
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeCtrlClass::On_Expanded (TreeItemClass *item)
|
|
{
|
|
//
|
|
// Notify any advise sinks
|
|
//
|
|
ADVISE_NOTIFY (On_TreeCtrl_Expand_Item (this, Get_ID (), item));
|
|
|
|
//
|
|
// Check to see if this item needs its children filled in. If so,
|
|
// then notify the advise sinks
|
|
//
|
|
if (item != NULL && item->Is_Expanded () && item->Needs_Children ()) {
|
|
ADVISE_NOTIFY (On_TreeCtrl_Needs_Children (this, Get_ID (), item));
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
//********************************************************************************//
|
|
//
|
|
// Start of TreeItemClass
|
|
//
|
|
//********************************************************************************//
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Remove_Child
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeItemClass::Remove_Child (TreeItemClass *child)
|
|
{
|
|
int index = ChildList.ID (child);
|
|
if (index != -1) {
|
|
ChildList.Delete (index);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Expand
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeItemClass::Expand (bool onoff)
|
|
{
|
|
IsExpanded = onoff;
|
|
TreeCtrl->On_Expanded (this);
|
|
TreeCtrl->Select_Item (this);
|
|
TreeCtrl->Update_Scroll_Bar_Visibility ();
|
|
TreeCtrl->Set_Dirty ();
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Set_Name
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeItemClass::Set_Name (const WCHAR *name)
|
|
{
|
|
Name = name;
|
|
TreeCtrl->Set_Dirty ();
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Set_Icon
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeItemClass::Set_Icon (const char *texture_name)
|
|
{
|
|
IconName = texture_name;
|
|
|
|
//
|
|
// Add this icon to our manager
|
|
//
|
|
if (texture_name != NULL) {
|
|
TreeCtrl->IconMgr.Add_Icon (texture_name);
|
|
}
|
|
|
|
TreeCtrl->Set_Dirty ();
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Set_Selected_Icon
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeItemClass::Set_Selected_Icon (const char *texture_name)
|
|
{
|
|
SelectedIconName = texture_name;
|
|
|
|
//
|
|
// Add this icon to our manager
|
|
//
|
|
if (texture_name != NULL) {
|
|
TreeCtrl->IconMgr.Add_Icon (texture_name);
|
|
}
|
|
|
|
TreeCtrl->Set_Dirty ();
|
|
return ;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Prev_Child
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeItemClass *
|
|
TreeItemClass::Get_Prev_Child (TreeItemClass *child)
|
|
{
|
|
TreeItemClass *retval = NULL;
|
|
if (child == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Return the previous entry in our list...
|
|
//
|
|
int index = ChildList.ID (child);
|
|
if (index > 0) {
|
|
retval = ChildList[index - 1];
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Prev_Child
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeItemClass *
|
|
TreeItemClass::Get_Next_Child (TreeItemClass *child)
|
|
{
|
|
TreeItemClass *retval = NULL;
|
|
if (child == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Return the next entry in our list...
|
|
//
|
|
int index = ChildList.ID (child);
|
|
if (index != -1 && (index + 1) < ChildList.Count ()) {
|
|
retval = ChildList[index + 1];
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Indent_Level
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
int
|
|
TreeItemClass::Get_Indent_Level (void)
|
|
{
|
|
int retval = 0;
|
|
|
|
//
|
|
// Count the number of parents this item has
|
|
//
|
|
TreeItemClass *curr_item = this;
|
|
while ((curr_item = curr_item->Get_Parent ()) != NULL) {
|
|
retval ++;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get_Last_Child
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
TreeItemClass *
|
|
TreeItemClass::Get_Last_Child (void)
|
|
{
|
|
TreeItemClass *retval = NULL;
|
|
|
|
if (ChildList.Count () > 0) {
|
|
retval = ChildList[ChildList.Count () - 1];
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Set_Needs_Children
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
void
|
|
TreeItemClass::Set_Needs_Children (bool onoff)
|
|
{
|
|
NeedsChildren = onoff;
|
|
TreeCtrl->Set_Dirty ();
|
|
return ;
|
|
}
|