Jump to content

  • Log In with Google      Sign In   
  • Create Account

Rendering Systems



Roots and "Tree" Hierarchy Control

Posted by RSI3D, in MFC, Woody3D 03 June 2011 - - - - - - · 933 views

Posted Image

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
CtreeCtrl (with fancy gradient selection bar).

Posted Image

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<USHORT>(red_start)   << 8);
	vertex_array[0].Green	= (static_cast<USHORT>(green_start) << 8);
	vertex_array[0].Blue	= (static_cast<USHORT>(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<USHORT>(red_end) 	<< 8 );
	vertex_array[1].Green	= (static_cast<USHORT>(green_end)   << 8 );
	vertex_array[1].Blue	= (static_cast<USHORT>(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);






Twitter

Posted Image

Google GameDev.Net Search Bar

Posted Image

Recent Comments

PARTNERS