/*****************************************************************************
* CColumnTreeCtrl
* Version: 1.1
* Date: February 18, 2008
* Author: Oleg A. Krivtsov
* E-mail: olegkrivtsov@mail.ru
* Based on ideas implemented in Michal Mecinski's CColumnTreeCtrl class
* (see copyright note below).
*
*****************************************************************************/
/*********************************************************
* Multi-Column Tree View
* Version: 1.1
* Date: October 22, 2003
* Author: Michal Mecinski
* E-mail: mimec@mimec.w.pl
* WWW: http://www.mimec.w.pl
*
* You may freely use and modify this code, but don't remove
* this copyright note.
*
* There is no warranty of any kind, express or implied, for this class.
* The author does not take the responsibility for any damage
* resulting from the use of it.
*
* Let me know if you find this code useful, and
* send me any modifications and bug reports.
*
* Copyright (C) 2003 by Michal Mecinski
*********************************************************/
#include "stdafx.h"
#include "ColumnTreeCtrl.h"
#include <shlwapi.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// IE 5.0 or higher required
#ifndef TVS_NOHSCROLL
#error CColumnTreeCtrl requires IE 5.0 or higher; _WIN32_IE should be greater than 0x500.
#endif
//-------------------------------------------------------------------------------
// Helper drawing funtions.
// I tried standard GDI fucntion LineTo with PS_DOT pen style,
// but that didn't have the effect I wanted, so I had to use these ones.
//-------------------------------------------------------------------------------
// draws a dotted horizontal line
static void _DotHLine(HDC hdc, LONG x, LONG y, LONG w, COLORREF cr)
{
for (; w>0; w-=2, x+=2)
SetPixel(hdc, x, y, cr);
}
// draws a dotted vertical line
static void _DotVLine(HDC hdc, LONG x, LONG y, LONG w, COLORREF cr)
{
for (; w>0; w-=2, y+=2)
SetPixel(hdc, x, y, cr);
}
//--------------------------------------------------------------------------------
// CCustomTreeChildCtrl Implementation
//--------------------------------------------------------------------------------
IMPLEMENT_DYNAMIC(CCustomTreeChildCtrl, CTreeCtrl)
//--------------------------------------------------------------------------------
// Construction/Destruction
//--------------------------------------------------------------------------------
CCustomTreeChildCtrl::CCustomTreeChildCtrl()
{
#ifdef _OWNER_DRAWN_TREE // only if owner-drawn
// init bitmap image structure
m_bkImage.hbm=NULL;
m_bkImage.xOffsetPercent = 0;
m_bkImage.yOffsetPercent = 0;
// create imagelist for tree buttons
m_imgBtns.Create (9, 9, ILC_COLOR32|ILC_MASK,2,1);
CBitmap* pBmpBtns = CBitmap::FromHandle(LoadBitmap(AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDB_TREEBTNS)));
ASSERT(pBmpBtns);
m_imgBtns.Add(pBmpBtns,RGB(255,0,255));
#endif //_OWNER_DRAWN_TREE
}
CCustomTreeChildCtrl::~CCustomTreeChildCtrl()
{
}
BEGIN_MESSAGE_MAP(CCustomTreeChildCtrl, CTreeCtrl)
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONDBLCLK()
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_WM_VSCROLL()
ON_WM_MOUSEWHEEL()
ON_WM_TIMER()
ON_WM_KEYDOWN()
//ON_NOTIFY( TTN_NEEDTEXT, OnToolTipNeedText )
//ON_WM_STYLECHANGED()
END_MESSAGE_MAP()
//---------------------------------------------------------------------------
// Operations
//---------------------------------------------------------------------------
// gets control's background image
BOOL CCustomTreeChildCtrl::GetBkImage(LVBKIMAGE* plvbkImage) const
{
memcpy(plvbkImage, &m_bkImage, sizeof(LVBKIMAGE));
return TRUE;
}
// sets background image for control
BOOL CCustomTreeChildCtrl::SetBkImage(LVBKIMAGE* plvbkImage)
{
memcpy(&m_bkImage, plvbkImage, sizeof(LVBKIMAGE));
Invalidate();
return TRUE;
}
//---------------------------------------------------------------------------
// Message Handlers
//---------------------------------------------------------------------------
void CCustomTreeChildCtrl::OnTimer(UINT_PTR nIDEvent)
{
// Do nothing.
// CTreeCtrl sends this message to scroll the bitmap in client area
// which also causes background bitmap scrolling,
// so we don't pass this message to the base class.
}
void CCustomTreeChildCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// CTreeCtrl may scroll the bitmap up or down in several cases,
// so we need to invalidate entire client area
Invalidate();
//... and pass to the base class
CTreeCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CCustomTreeChildCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
// mask left click if outside the real item's label
if (CheckHit(point))
{
HTREEITEM hItem = HitTest(point);
if(hItem)
{
#ifdef _OWNER_DRAWN_TREE
// if the clicked item is partially visible we won't process
// the message to avoid background bitmap scrolling
// TODO: need to avoid scrolling and process the message
CRect rcItem, rcClient;
GetClientRect(&rcClient);
GetItemRect(hItem,&rcItem,FALSE);
if(rcItem.bottom>rcClient.bottom)
{
Invalidate();
EnsureVisible(hItem);
SelectItem(hItem);
//CTreeCtrl::OnLButtonDown(nFlags, point);
return;
}
#endif //_OWNER_DRAWN_TREE
// select the clicked item
SelectItem(hItem);
}
// call standard handler
CTreeCtrl::OnLButtonDown(nFlags, point);
}
else
{
// if clicked outside the item's label
// than set focus to contol window
SetFocus();
}
}
void CCustomTreeChildCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// process this message only if double-clicked the real item's label
// mask double click if outside the real item's label
if (CheckHit(point))
{
HTREEITEM hItem = HitTest(point);
if(hItem)
{
#ifdef _OWNER_DRAWN_TREE
// if the clicked item is partially visible we should invalidate
// entire client area to avoid background bitmap scrolling
CRect rcItem, rcClient;
GetClientRect(&rcClient);
GetItemRect(hItem,&rcItem,FALSE);
if(rcItem.bottom>rcClient.bottom)
{
Invalidate();
CTreeCtrl::OnLButtonDown(nFlags, point);
return;
}
#endif //_OWNER_DRAWN_TREE
SelectItem(hItem);
}
// call standard message handler
CTreeCtrl::OnLButtonDblClk(nFlags, point);
}
else
{
// if clicked outside the item's label
// than set focus to contol window
SetFocus();
}
}
void CCustomTreeChildCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
// mask mouse move if outside the real item's label
if (CheckHit(point))
{
// call standard handler
CTreeCtrl::OnMouseMove(nFlags, point);
}
}
#ifdef _OWNER_DRAWN_TREE // this code is only for owner-drawn contol
//----------------------------------------------------------------------
// Sends NM_CUSTOMDRAW notification to the parent (CColumnTreeCtrl)
// The idea is to use one custom drawing code for both custom-drawn and
// owner-drawn controls
//----------------------------------------------------------------------
LRESULT CCustomTreeChildCtrl::CustomDrawNotify(LPNMTVCUSTOMDRAW lpnm)
{
lpnm->nmcd.hdr.hwndFrom = GetSafeHwnd();
lpnm->nmcd.hdr.code = NM_CUSTOMDRAW;
lpnm->nmcd.hdr.idFrom = GetWindowLong(m_hWnd, GWL_ID);
return GetParent()->SendMessage(WM_NOTIFY,(WPARAM)0,(LPARAM)lpnm);
}
//---------------------------------------------------------------------------
// Performs painting in the client's area.
// The pDC parameter is the memory device context created in OnPaint handler.
//---------------------------------------------------------------------------
LRESULT CCustomTreeChildCtrl::OwnerDraw(CDC* pDC)
{
NMTVCUSTOMDRAW nm; // this structure is used by NM_CUSTOMDRAW message
DWORD dwFlags; // custom-drawing flags
DWORD dwRet; // current custom-drawing operation'