Jump to content
  • Advertisement
  • entries
    31
  • comments
    43
  • views
    61916

Roots and "Tree" Hierarchy Control

Sign in to follow this  
RSI

1669 views

[size="3"]e_23a.jpg

Woody3D can create tree roots as shown above. There is a problem however, as it currently uses a very simple hierarchy for branch levels. It does not allow for more than one child per branch. This means you can add roots but not branches. That's a pretty boring tree.

Next version will support a more flexible hierarchy. To manage the various parts of the tree, I'll be using a CtreeCtrl in the Tree Forge. Below is a colored [size="3"]CtreeCtrl [size="3"] (with fancy gradient selection bar).

e_23b.jpg

And here is the source for the control if you're interested in how it works. Feel free to modify it and use it in your own MFC projects.

Color_Tree.h
#ifndef ___COLOR_TREE_CONTROL_H___
#define ___COLOR_TREE_CONTROL_H___


class Color_Tree : public CTreeCtrl
{
private:

COLORREF ___select_background_color;
COLORREF ___select_font_color;
COLORREF ___lost_focus_select_background_color;
COLORREF ___lost_focus_select_font_color;

BOOL ___is_select_full_row;
BOOL ___is_select_full_row_gradient;

protected:

DECLARE_MESSAGE_MAP()

afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult);

public:

// Constructor / Destructor
Color_Tree(void);
~Color_Tree(void);

void enable_select_full_row(BOOL enable, BOOL is_gradient);
void set_select_color(COLORREF select_background_color, COLORREF select_font_color,
COLORREF lost_focus_select_background_color, COLORREF lost_focus_select_font_color);
};


#endif


Color_Tree.cpp
#include "stdafx.h"
#include "Color_Tree.h"



// Local Gradient rectangle function
BOOL draw_gradient_rect(CDC *pDC,
const CRect &draw_rect,
const COLORREF start_color,
const COLORREF end_color,
const bool is_horizontal)
{
// Local data
BYTE red_start, green_start, blue_start,
red_end, green_end, blue_end;
TRIVERTEX vertex_array[2] = { 0 };
GRADIENT_RECT gradient_rect[1] = { 0 };


// Validate DC
if(!pDC || !pDC->GetSafeHdc())
{ return FALSE;
}

// Get RGB bytes from start color
red_start = GetRValue(start_color);
green_start = GetGValue(start_color);
blue_start = GetBValue(start_color);

// Set first vertex
vertex_array[0].x = draw_rect.left;
vertex_array[0].y = draw_rect.top;
vertex_array[0].Red = (static_cast(red_start) << 8);
vertex_array[0].Green = (static_cast(green_start) << 8);
vertex_array[0].Blue = (static_cast(blue_start) << 8);
vertex_array[0].Alpha = 0x0000;

// Get RGB bytes from end color
red_end = GetRValue(end_color);
green_end = GetGValue(end_color);
blue_end = GetBValue(end_color);

// Set second vertex
vertex_array[1].x = draw_rect.right;
vertex_array[1].y = draw_rect.bottom;
vertex_array[1].Red = (static_cast(red_end) << 8 );
vertex_array[1].Green = (static_cast(green_end) << 8 );
vertex_array[1].Blue = (static_cast(blue_end) << 8 );
vertex_array[1].Alpha = 0x0000;

// Gradient vertex index
gradient_rect[0].UpperLeft = 0;
gradient_rect[0].LowerRight = 1;

// Draw gradient rect
return GradientFill( pDC->GetSafeHdc(),
vertex_array,
2,
&gradient_rect,
1,
is_horizontal ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V ) == TRUE;
}

// c()
Color_Tree::Color_Tree(void)
{
___is_select_full_row = FALSE;
___is_select_full_row_gradient = FALSE;
}
// d()
Color_Tree::~Color_Tree(void)
{
}

// Message map
BEGIN_MESSAGE_MAP(Color_Tree, CTreeCtrl)
ON_NOTIFY_REFLECT( NM_CUSTOMDRAW, OnCustomDraw)
END_MESSAGE_MAP()


// Handle color of select
void Color_Tree::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
// Local data
NMTVCUSTOMDRAW* pcd;
RECT rect;
CDC* pDC;
CBrush brush;


// Get custom draw struct
pcd = (NMTVCUSTOMDRAW*)pNMHDR;

// Handle by draw stage
switch(pcd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:

*pResult = CDRF_NOTIFYITEMDRAW;

break;
// Pre paint of tree item
case CDDS_ITEMPREPAINT:

// To Get item
HTREEITEM hItem = (HTREEITEM)pcd->nmcd.dwItemSpec;

// Handle control has focus
if(this->GetFocus() == this)
{
// If item is selected
if(pcd->nmcd.uItemState & CDIS_SELECTED)
{
pcd->clrText = ___select_font_color;
pcd->clrTextBk = ___select_background_color;

// Determine if item is in view
// Get text rect
if(___is_select_full_row && this->GetItemRect(hItem, &rect, TRUE))
{
// Adjust rect
pcd->nmcd.rc.left = rect.right;

// Gradient fill
if(___is_select_full_row_gradient)
{
// Get DC and fill
pDC = this->GetDC();
draw_gradient_rect(pDC, pcd->nmcd.rc, ___select_background_color, this->GetBkColor(), true);

// Cleanup
this->ReleaseDC(pDC);
}
// Solid fill
else
{
// Get DC and Create brush
pDC = this->GetDC();
brush.CreateSolidBrush(___select_background_color);

// Solid fill
pDC->FillRect(&pcd->nmcd.rc, &brush);

// Cleanup
brush.DeleteObject();
this->ReleaseDC(pDC);
}
}
}
// If item is hot (mouse over)
else if(pcd->nmcd.uItemState & CDIS_HOT)
{
pcd->clrText = this->GetTextColor();
}
}
else
{
// If item is selected
if(pcd->nmcd.uItemState & CDIS_SELECTED)
{
pcd->clrText = ___lost_focus_select_font_color;
pcd->clrTextBk = ___lost_focus_select_background_color;

// Determine if item is in view
// Get text rect
if(___is_select_full_row && this->GetItemRect(hItem, &rect, TRUE))
{
// Adjust rect
pcd->nmcd.rc.left = rect.right;

// Gradient fill
if(___is_select_full_row_gradient)
{
// Get DC and fill
pDC = this->GetDC();
draw_gradient_rect(pDC, pcd->nmcd.rc, ___lost_focus_select_background_color, this->GetBkColor(), true);

// Cleanup
this->ReleaseDC(pDC);
}
// Solid fill
else
{
// Get DC and Create brush
pDC = this->GetDC();
brush.CreateSolidBrush(___lost_focus_select_background_color);

// Solid fill
pDC->FillRect(&pcd->nmcd.rc, &brush);

// Cleanup
brush.DeleteObject();
this->ReleaseDC(pDC);
}
}
}
// If item is hot (mouse over)
else if(pcd->nmcd.uItemState & CDIS_HOT)
{
pcd->clrText = this->GetTextColor();
}
}

*pResult = CDRF_DODEFAULT;

break;
}
}

// Enable select full row
void Color_Tree::enable_select_full_row(BOOL enable, BOOL is_gradient)
{ ___is_select_full_row = enable;
___is_select_full_row_gradient = is_gradient;
}

// Set the colors for selecting items
void Color_Tree::set_select_color(COLORREF select_background_color, COLORREF select_font_color,
COLORREF lost_focus_select_background_color, COLORREF lost_focus_select_font_color)
{
___select_background_color = select_background_color;
___select_font_color = select_font_color;
___lost_focus_select_background_color = lost_focus_select_background_color;
___lost_focus_select_font_color = lost_focus_select_font_color;
}


Example


CImageList ___tree_image_list;
Color_Tree ___tree_control;


// Local data
CBitmap bitmap;
HTREEITEM o_1, o_2, c_1, c_2;


// Setup tree colors
___tree_control.SetBkColor(RGB(116, 127, 138));
___tree_control.SetTextColor(RGB(255, 255, 255));
___tree_control.SetLineColor(RGB(255, 255, 255));
___tree_control.set_select_color(RGB(196, 210, 224), RGB(0, 0, 0), RGB(102, 114, 124), RGB(255, 255, 255));

// Setup tree images
___tree_image_list.Create(16, 16, ILC_COLOR32, 1, 4);
// Bitmap 1
bitmap.LoadBitmap(IDB_BITMAP1);
___tree_image_list.Add(&bitmap, RGB(0, 0, 0));
bitmap.DeleteObject();
// Bitmap 2
bitmap.LoadBitmap(IDB_BITMAP2);
___tree_image_list.Add(&bitmap, RGB(0, 0, 0));
bitmap.DeleteObject();
// Set image list
___tree_control.SetImageList(&___tree_image_list, TVSIL_NORMAL);

// Set item height
___tree_control.SetItemHeight(20);

// Custom enable select of whole row - do not use 'Full Row Select' property for Control - it disables lines
// Allows for horizontal gradient too.
___tree_control.enable_select_full_row(TRUE, TRUE);

// Add items
o_1 = ___tree_control.InsertItem(_T("Trunk"), 0, 0);
c_1 = ___tree_control.InsertItem(_T("Standard Branch 0"), 1, 1, o_1);
c_2 = ___tree_control.InsertItem(_T("Standard Branch 1"), 1, 1, o_1);
___tree_control.InsertItem(_T("Imposter Branch 0"), 1, 1, c_2);
o_2 = ___tree_control.InsertItem(_T("Leaf Types"), 0, 0);
___tree_control.InsertItem(_T("Mesh Leaf 0"), 1, 1, o_2);
___tree_control.InsertItem(_T("Billboard Leaf 0"), 1, 1, o_2);

Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!