orderedtreectrl.cpp

来自「管理项目进度工具的原代码」· C++ 代码 · 共 715 行 · 第 1/2 页

CPP
715
字号
// ToDoCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "orderedtreeCtrl.h"

#include "..\shared\holdredraw.h"
#include "..\shared\themed.h"
#include "..\shared\treectrlhelper.h"
#include "..\shared\misc.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// COrderedTreeCtrl

const UINT MINGUTTER = 16;

static CMap<int, int&, UINT, UINT&> g_mapWidths;

COrderedTreeCtrl::COrderedTreeCtrl(DWORD dwGutterStyles) : 

    // because CTreeCtrlHelper wants a reference passed
    // to its constructor we have to pass '*this'. however
    // the compiler complains because 'this' is not yet
    // fully constructed.
#pragma warning (disable: 4355)
	m_ht(*this),
#pragma warning (default: 4355)
	m_gutter(dwGutterStyles),
	m_bShowingPosColumn(TRUE), 
	m_crGridlines(OTC_GRIDCOLOR),
	m_crAltLines((COLORREF)-1),
	m_bWantInit(FALSE)
{
	AddGutterColumn(OTC_POSCOLUMNID, "Pos"); // for the pos string
	
	EnableGutterColumnHeaderClicking(OTC_POSCOLUMNID, FALSE);
}

COrderedTreeCtrl::~COrderedTreeCtrl()
{
}

BEGIN_MESSAGE_MAP(COrderedTreeCtrl, CTreeCtrl)
//{{AFX_MSG_MAP(COrderedTreeCtrl)
ON_WM_SETTINGCHANGE()
//}}AFX_MSG_MAP
ON_WM_STYLECHANGED()
ON_NOTIFY_REFLECT_EX(TVN_ITEMEXPANDED, OnItemexpanded)
ON_NOTIFY_REFLECT_EX(NM_CUSTOMDRAW, OnCustomDraw)
ON_NOTIFY_REFLECT_EX(NM_CLICK, OnClick)
ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBeginDrag)
ON_REGISTERED_MESSAGE(WM_NCG_GETFIRSTVISIBLETOPLEVELITEM, OnGutterGetFirstVisibleTopLevelItem)
ON_REGISTERED_MESSAGE(WM_NCG_GETNEXTITEM, OnGutterGetNextItem)
ON_REGISTERED_MESSAGE(WM_NCG_DRAWITEM, OnGutterDrawItem)
ON_REGISTERED_MESSAGE(WM_NCG_RECALCCOLWIDTH, OnGutterRecalcColWidth)
ON_REGISTERED_MESSAGE(WM_NCG_POSTNCDRAW, OnGutterPostNcDraw)
ON_REGISTERED_MESSAGE(WM_NCG_GETITEMRECT, OnGutterGetItemRect)
ON_REGISTERED_MESSAGE(WM_NCG_GETFIRSTCHILDITEM, OnGutterGetFirstChildItem)
ON_REGISTERED_MESSAGE(WM_NCG_POSTDRAWITEM, OnGutterPostDrawItem)
ON_REGISTERED_MESSAGE(WM_NCG_HITTEST, OnGutterHitTest)
ON_REGISTERED_MESSAGE(WM_NCG_NOTIFYITEMCLICK, OnGutterNotifyItemClick)
ON_REGISTERED_MESSAGE(WM_NCG_ISITEMSELECTED, OnGutterIsItemSelected)
ON_REGISTERED_MESSAGE(WM_NCG_GETSELECTEDCOUNT, OnGutterGetSelectedCount)
ON_REGISTERED_MESSAGE(WM_NCG_GETPARENTITEM, OnGutterGetParentID)
ON_REGISTERED_MESSAGE(WM_NCG_WANTRECALC, OnGutterWantRecalc)
ON_REGISTERED_MESSAGE(WM_NCG_WANTREDRAW, OnGutterWantRedraw)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// COrderedTreeCtrl message handlers

void COrderedTreeCtrl::PreSubclassWindow() 
{
	m_gutter.AddRecalcMessage(TVM_INSERTITEM);
	m_gutter.AddRecalcMessage(TVM_DELETEITEM);
	m_gutter.AddRecalcMessage(TVM_EXPAND);
	
	m_gutter.AddRedrawMessage(WM_KEYUP); // only way to catch keyboard navigation (at present)
	m_gutter.AddRedrawMessage(WM_SYSKEYUP); // only way to catch ALT+keyboard navigation (at present)
	m_gutter.AddRedrawMessage(WM_KEYDOWN); // only way to catch keyboard navigation (at present)
	m_gutter.AddRedrawMessage(WM_SYSKEYDOWN); // only way to catch ALT+keyboard navigation (at present)
	m_gutter.AddRedrawMessage(TVM_SELECTITEM);
	m_gutter.AddRedrawMessage(TVM_SORTCHILDREN);
	m_gutter.AddRedrawMessage(TVM_SORTCHILDRENCB);
	m_gutter.AddRedrawMessage(WM_COMMAND, EN_KILLFOCUS);
	
	CTreeCtrl::PreSubclassWindow();
	
	// note: its too early to initialize the gutter here because 
	// MFC hasn't done its bit yet, so initilization is done
	// in WindowProc (for now)
	m_bWantInit = TRUE;
}

LRESULT COrderedTreeCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	if (m_bWantInit && !m_gutter.IsInitialized())
	{
		m_bWantInit = FALSE;
		m_gutter.Initialize(GetSafeHwnd());
	}
	
	return CTreeCtrl::WindowProc(message, wParam, lParam);
}

void COrderedTreeCtrl::SetAlternateLineColor(COLORREF color)
{
	if (m_crAltLines != color)
	{
		m_crAltLines = color;
		Invalidate();
		RedrawGutter();
	}
}

BOOL COrderedTreeCtrl::PtInHeader(CPoint ptScreen) const
{
	return m_gutter.PtInHeader(ptScreen);
}

COLORREF COrderedTreeCtrl::GetItemLineColor(HTREEITEM hti)
{
	if (m_crAltLines != -1 && TCH().ItemLineIsOdd(hti))
		return m_crAltLines;
	
	// else
	return GetSysColor(COLOR_WINDOW);
}

BOOL COrderedTreeCtrl::ShowGutterPosColumn(BOOL bShow)
{
	if (m_bShowingPosColumn != bShow)
	{
		m_bShowingPosColumn = bShow;
		m_gutter.RecalcGutter();

		return TRUE;
	}

	// else no change
	return FALSE;

}

void COrderedTreeCtrl::SetGridlineColor(COLORREF color)
{
	if (m_crGridlines != color)
	{
		m_crGridlines = color;
		
		if (GetSafeHwnd())
		{
			m_gutter.Redraw();
			Invalidate();
		}
	}
}

int COrderedTreeCtrl::AddGutterColumn(UINT nColID, LPCTSTR szTitle, UINT nWidth, UINT nTextAlign)
{
	return m_gutter.AddColumn(nColID, szTitle, nWidth, nTextAlign);
}

void COrderedTreeCtrl::PressGutterColumnHeader(UINT nColID, BOOL bPress)
{
	m_gutter.PressHeader(nColID, bPress);
}

void COrderedTreeCtrl::SetGutterColumnHeaderTitle(UINT nColID, LPCTSTR szTitle, LPCTSTR szFont)
{
	m_gutter.SetHeaderTitle(nColID, szTitle, szFont, FALSE);
}

void COrderedTreeCtrl::SetGutterColumnHeaderTitle(UINT nColID, UINT nSymbol, LPCTSTR szFont)
{
	// Valik - cast to TCHAR is necessary or the compiler complains under VC 7.1
	m_gutter.SetHeaderTitle(nColID, CString(static_cast<TCHAR>(nSymbol)), szFont, TRUE);
}

void COrderedTreeCtrl::SetGutterColumnSort(UINT nColID, NCGSORT nSortDir)
{
	m_gutter.SetColumnSort(nColID, nSortDir);
}

void COrderedTreeCtrl::EnableGutterColumnHeaderClicking(UINT nColID, BOOL bEnable)
{
	m_gutter.EnableHeaderClicking(nColID, bEnable);
}

LRESULT COrderedTreeCtrl::OnGutterGetFirstVisibleTopLevelItem(WPARAM /*wParam*/, LPARAM lParam)
{
	ASSERT (lParam);
	return (LRESULT)TCH().GetFirstVisibleTopLevelItem(*((LPINT)lParam));
}

LRESULT COrderedTreeCtrl::OnGutterGetNextItem(WPARAM /*wParam*/, LPARAM lParam)
{
	return (LRESULT)CTreeCtrl::GetNextItem((HTREEITEM)lParam, TVGN_NEXT);
}

LRESULT COrderedTreeCtrl::OnGutterWantRecalc(WPARAM /*wParam*/, LPARAM /*lParam*/)
{
	TCH().BuildVisibleIndexMap();

	// do not recalc if editing a label
	if (GetEditControl() != NULL)
		return 1L; // cancel recalc

	// else
	return 0L;
}

LRESULT COrderedTreeCtrl::OnGutterWantRedraw(WPARAM /*wParam*/, LPARAM lParam)
{
	MSG* pMsg = (MSG*)lParam;

	switch (pMsg->message)
	{
	case WM_KEYDOWN:
	case WM_KEYUP:
	case WM_SYSKEYDOWN:
	case WM_SYSKEYUP:
		{
			switch (pMsg->wParam) // what key
			{
			// ignore modifiers
			case VK_CONTROL:
			case VK_SHIFT:
			case VK_MENU:
				return TRUE; // prevent redraw
			}
		}
		break;
	}

	return FALSE; // allow redraw
}

LRESULT COrderedTreeCtrl::OnGutterGetFirstChildItem(WPARAM /*wParam*/, LPARAM lParam)
{
	HTREEITEM hti = (HTREEITEM)lParam;
	
	if (ItemHasChildren(hti) && (GetItemState(hti, TVIS_EXPANDED) & TVIS_EXPANDED))
		return (LRESULT)GetChildItem(hti);
	
	return 0;
}

LRESULT COrderedTreeCtrl::OnGutterDrawItem(WPARAM /*wParam*/, LPARAM lParam)
{
	NCGDRAWITEM* pNCGDI = (NCGDRAWITEM*)lParam;
	
	if (pNCGDI->nColID == OTC_POSCOLUMNID)
	{
		CRect rItem(pNCGDI->rItem);

		NcDrawItem(pNCGDI->pDC, pNCGDI->dwItem, pNCGDI->dwParentItem, 
					pNCGDI->nColID, rItem, pNCGDI->nLevel, 
					pNCGDI->nItemPos, pNCGDI->bSelected, pNCGDI->rWindow);
		
		return TRUE; // we handled it
	}
	
	// else
	return FALSE;
}

LRESULT COrderedTreeCtrl::OnGutterPostDrawItem(WPARAM /*wParam*/, LPARAM lParam)
{
	NCGDRAWITEM* pNCGDI = (NCGDRAWITEM*)lParam;

	if (pNCGDI->dwParentItem)
		PostNcDrawItem(pNCGDI->pDC, pNCGDI->dwParentItem, pNCGDI->rItem, pNCGDI->nLevel);
	
	return FALSE; // to let our parent handle it too
}

LRESULT COrderedTreeCtrl::OnGutterPostNcDraw(WPARAM /*wParam*/, LPARAM lParam)
{
	NCGDRAWITEM* pNCGDI = (NCGDRAWITEM*)lParam;
	
	PostNcDraw(pNCGDI->pDC, pNCGDI->rWindow);
	
	return FALSE; // to let our parent handle it too
}

LRESULT COrderedTreeCtrl::OnGutterRecalcColWidth(WPARAM /*wParam*/, LPARAM lParam)
{
	NCGRECALCCOLUMN* pNCRC = (NCGRECALCCOLUMN*)lParam;
	
	return RecalcColumnWidth(pNCRC->pDC, pNCRC->nColID, pNCRC->nWidth);
}

LRESULT COrderedTreeCtrl::OnGutterGetItemRect(WPARAM /*wParam*/, LPARAM lParam)
{
	NCGITEMRECT* pNCGGI = (NCGITEMRECT*)lParam;
	
	return GetItemRect((HTREEITEM)pNCGGI->dwItem, &pNCGGI->rItem, TRUE);
}

LRESULT COrderedTreeCtrl::OnGutterGetParentID(WPARAM /*wParam*/, LPARAM lParam)
{
	return (DWORD)GetParentItem((HTREEITEM)lParam);
}

LRESULT COrderedTreeCtrl::OnGutterIsItemSelected(WPARAM /*wParam*/, LPARAM lParam)
{
	NCGITEMSELECTION* pNCGIS = (NCGITEMSELECTION*)lParam;
	
	HTREEITEM hti = (HTREEITEM)pNCGIS->dwItem;
	pNCGIS->bSelected = (GetItemState(hti, TVIF_STATE) & TVIS_SELECTED);
	
	return TRUE;
}

LRESULT COrderedTreeCtrl::OnGutterGetSelectedCount(WPARAM /*wParam*/, LPARAM lParam)
{
	int* pCount = (int*)lParam;
	*pCount = GetSelectedItem() ? 1 : 0;
	
	return TRUE;
}

LRESULT COrderedTreeCtrl::OnGutterHitTest(WPARAM /*wParam*/, LPARAM lParam)
{
	CPoint point(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
	
	UINT nFlags = 0;
	HTREEITEM hti = HitTest(point, &nFlags);
	
	return (LRESULT)hti;
}

void COrderedTreeCtrl::PostNcDraw(CDC* pDC, const CRect& rWindow)
{
	// vertical divider
	if (m_crGridlines != -1 && GutterHasStyle(NCGS_RIGHTCOLUMNS) && !(GetStyle() & WS_VSCROLL))
	{
		pDC->FillSolidRect(rWindow.left, rWindow.top, 1, rWindow.Height(), m_crGridlines);
	}
}

void COrderedTreeCtrl::NcDrawItem(CDC* pDC, DWORD dwItem, DWORD dwParentItem, UINT nColID, CRect& rItem, 
								  int nLevel, int nPos, BOOL bSelected, const CRect& rWindow)
{
	HTREEITEM hti = (HTREEITEM)dwItem;
	
	if (nColID == OTC_POSCOLUMNID) // this is all we deal with
	{
		// extract the parent pos
		CString sPos, sParentPos; 
		static CMap<DWORD, DWORD, CString, LPCTSTR> mapParentPos;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?