You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1248 lines
24 KiB
C++

// XTPCoreTreeControl.cpp : implementation file
//
// This file is a part of the XTREME CONTROLS MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Common/XTPImageManager.h"
#include "Common/XTPDrawHelpers.h"
#include "Common/XTPMarkupRender.h"
#include "XTPCoreTreeControl.h"
#include "XTPCoreTreeItem.h"
#include "XTPCoreTreePaintManager.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC(CXTPCoreTreeControl, CWnd)
CLIPFORMAT CXTPCoreTreeControl::m_cfItem = (CLIPFORMAT)::RegisterClipboardFormat(_T("CoreTreeItem"));
//////////////////////////////////////////////////////////////////////////
// CTreeDropTarget
class CXTPCoreTreeControl::CTreeDropTarget : public COleDropTarget
{
public:
CTreeDropTarget()
{
m_nHoverTime = 500;
SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &m_nHoverTime, 0);
}
virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
CXTPCoreTreeControl* pTree = DYNAMIC_DOWNCAST(CXTPCoreTreeControl, pWnd);
if (!pTree)
return DROPEFFECT_NONE;
CRect rectClient;
pWnd->GetClientRect(&rectClient);
CRect rect = rectClient;
// hit-test against inset region
UINT nTimerID = MAKEWORD(-1, -1);
rect.InflateRect(0, -nScrollInset);
const int nTimerHover = 10;
if (rectClient.PtInRect(point) && !rect.PtInRect(point))
{
// determine which way to scroll along both X & Y axis
if (point.y < rect.top)
nTimerID = SB_LINEUP;
else if (point.y >= rect.bottom)
nTimerID = SB_LINEDOWN;
}
else if (rectClient.PtInRect(point))
{
nTimerID = nTimerHover;
}
if (nTimerID == nTimerHover)
{
// save tick count when timer ID changes
DWORD dwTick = GetTickCount();
if (point != m_ptLastPoint)
{
m_ptLastPoint = point;
m_dwLastTick = dwTick;
m_nScrollDelay = m_nHoverTime;
}
// scroll if necessary
if (dwTick - m_dwLastTick > m_nScrollDelay)
{
pTree->OnDragHover(pDataObject, dwKeyState, point);
m_dwLastTick = dwTick;
}
}
else if (nTimerID != MAKEWORD(-1, -1))
{
// save tick count when timer ID changes
DWORD dwTick = GetTickCount();
if (nTimerID != m_nTimerID)
{
m_dwLastTick = dwTick;
m_nScrollDelay = nScrollDelay;
}
// scroll if necessary
if (dwTick - m_dwLastTick > m_nScrollDelay)
{
pTree->OnVScroll(nTimerID, 0, NULL);
m_dwLastTick = dwTick;
m_nScrollDelay = nScrollInterval;
}
}
m_nTimerID = nTimerID;
return pTree->OnDragOver(pDataObject, dwKeyState, point);
}
virtual void OnDragLeave(CWnd* pWnd)
{
CXTPCoreTreeControl* pTree = DYNAMIC_DOWNCAST(CXTPCoreTreeControl, pWnd);
if (pTree)
{
pTree->OnDragOver(NULL, 0, CPoint(-1, -1));
}
}
virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
DROPEFFECT dropEffect, CPoint point)
{
CXTPCoreTreeControl* pTree = DYNAMIC_DOWNCAST(CXTPCoreTreeControl, pWnd);
if (pTree)
{
return pTree->OnDrop(pDataObject, dropEffect, point);
}
return FALSE;
}
CPoint m_ptLastPoint;
int m_nHoverTime;
};
/////////////////////////////////////////////////////////////////////////////
// CXTPCoreTreeControl
CXTPCoreTreeControl::CXTPCoreTreeControl()
{
RegisterWindowClass();
m_pItems = new CXTPCoreTreeItems();
m_pItems->m_pControl = this;
m_pPaintManager = new CXTPCoreTreePaintManager();
m_pPaintManager->RefreshMetrics();
m_nClientHeight = 0;
m_rcControl.SetRectEmpty();
m_bPreSubclassWindow = TRUE;
m_bScrollVisible = FALSE;
m_bInUpdateScrollBar = FALSE;
m_pImageManager = new CXTPImageManager();
m_nLockRedraw = 0;
m_ptPressed = CPoint(-1, -1);
m_pFocusedItem = NULL;
m_pDraggingItem = NULL;
m_pPressedItem = NULL;
m_pDragOverItem = NULL;
m_nDropPosition = xtpCoreTreeDropAfter;
m_pDropTarget = new CTreeDropTarget();
m_pMarkupContext = NULL;
}
CXTPCoreTreeControl::~CXTPCoreTreeControl()
{
SAFE_DELETE(m_pItems);
SAFE_DELETE(m_pPaintManager);
CMDTARGET_RELEASE(m_pImageManager);
SAFE_DELETE(m_pDropTarget);
XTPMarkupReleaseContext(m_pMarkupContext);
}
BOOL CXTPCoreTreeControl::RegisterWindowClass(HINSTANCE hInstance /*= NULL*/)
{
return XTPDrawHelpers()->RegisterWndClass(hInstance, _T("XTPCoreTree"), CS_DBLCLKS);
}
void CXTPCoreTreeControl::SetPaintManager(CXTPCoreTreePaintManager* pPaintManager)
{
ASSERT (pPaintManager);
SAFE_DELETE(m_pPaintManager);
m_pPaintManager = pPaintManager;
m_pPaintManager->RefreshMetrics();
}
void CXTPCoreTreeControl::EnableMarkup(BOOL bEnable)
{
XTPMarkupReleaseContext(m_pMarkupContext);
if (bEnable)
{
m_pMarkupContext = XTPMarkupCreateContext();
}
}
void CXTPCoreTreeControl::SetImageManager(CXTPImageManager* pImageManager)
{
CMDTARGET_RELEASE(m_pImageManager);
m_pImageManager = pImageManager;
}
void CXTPCoreTreeControl::SetFocusedItem(CXTPCoreTreeItem* pItem)
{
if (m_pFocusedItem == pItem)
return;
if (pItem && pItem->IsLabel())
return;
m_pFocusedItem = pItem;
EnsureVisible(m_pFocusedItem);
RedrawControl();
SendMessageToParent(TVN_SELCHANGED);
}
LRESULT CXTPCoreTreeControl::SendMessageToParent(int nMessage, NMHDR* pNMHDR)
{
if (!IsWindow(m_hWnd))
return 0;
NMHDR nmhdr;
if (pNMHDR == NULL)
pNMHDR = &nmhdr;
pNMHDR->hwndFrom = GetSafeHwnd();
pNMHDR->idFrom = GetDlgCtrlID();
pNMHDR->code = nMessage;
CWnd *pOwner = GetOwner();
LRESULT res = 0;
if (pOwner && IsWindow(pOwner->m_hWnd))
res = pOwner->SendMessage(WM_NOTIFY, pNMHDR->idFrom, (LPARAM)pNMHDR);
return res;
}
void CXTPCoreTreeControl::RedrawControl(LPCRECT lpcRect)
{
if (m_nLockRedraw > 0)
{
return;
}
if (m_hWnd) InvalidateRect(lpcRect, FALSE);
}
void CXTPCoreTreeControl::SetLockRedraw(BOOL bLockRedraw)
{
m_nLockRedraw += bLockRedraw ? +1 : -1;
ASSERT(m_nLockRedraw >= 0);
if (m_nLockRedraw == 0)
RecalcLayout();
}
void CXTPCoreTreeControl::EnsureVisible(CXTPCoreTreeItem* pItem)
{
if (!pItem || !m_hWnd)
return;
CXTPCoreTreeItem* pParentItem = pItem->GetParentItem();
while (pParentItem != NULL)
{
pParentItem->SetExpanded(TRUE);
pParentItem = pParentItem->GetParentItem();
}
CXTPClientRect rcClient(this);
CRect rc = pItem->GetRect();
if (rc.bottom > rcClient.bottom + GetScrollOffset())
{
OnScrollChanged(min(rc.top, rc.bottom - rcClient.Height()));
}
else if (rc.top < GetScrollOffset())
{
OnScrollChanged(rc.top);
}
}
int CXTPCoreTreeControl::GetScrollOffset() const
{
if (!m_bScrollVisible)
return 0;
return GetScrollPos(SB_VERT);
}
void CXTPCoreTreeControl::OnScrollChanged(int nScrollOffset)
{
SetScrollPos(SB_VERT, nScrollOffset);
RedrawControl();
}
CXTPCoreTreeItem* CXTPCoreTreeControl::HitTestTreeItems(CXTPCoreTreeItems* pItems, CPoint point) const
{
POSITION pos = pItems->GetHeadPosition();
while (pos)
{
CXTPCoreTreeItem* pItem = pItems->GetNext(pos);
if (pItem->GetRect().PtInRect(point))
return pItem;
if (pItem->IsExpanded() && pItem->HasChildren())
{
pItem = HitTestTreeItems(pItem->GetChildren(), point);
if (pItem != NULL)
return pItem;
}
}
return NULL;
}
CXTPCoreTreeItem* CXTPCoreTreeControl::HitTest(CPoint point) const
{
point.y += GetScrollOffset();
return HitTestTreeItems(m_pItems, point);
}
BOOL CXTPCoreTreeControl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
if (!CreateEx(0, _T("XTPCoreTree"), NULL, dwStyle, rect, pParentWnd, nID))
{
return FALSE;
}
m_pDropTarget->Register(this);
return TRUE;
}
void CXTPCoreTreeControl::OnItemRemoved(CXTPCoreTreeItem* pItem)
{
if (pItem == m_pFocusedItem)
{
SetFocusedItem(NULL);
}
if (pItem == m_pPressedItem)
m_pPressedItem = NULL;
}
void CXTPCoreTreeControl::ExpandeTreeItems(CXTPCoreTreeItems* pItems)
{
POSITION pos = pItems->GetHeadPosition();
while (pos)
{
CXTPCoreTreeItem* pItem = pItems->GetNext(pos);
if (pItem->HasChildren())
{
pItem->SetExpanded(TRUE);
ExpandeTreeItems(pItem->GetChildren());
}
}
}
BEGIN_MESSAGE_MAP(CXTPCoreTreeControl, CWnd)
//{{AFX_MSG_MAP(CXTPCoreTreeControl)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_WM_SIZE()
ON_WM_KEYDOWN()
ON_WM_LBUTTONDOWN()
ON_WM_SYSCOLORCHANGE()
ON_WM_GETDLGCODE()
ON_WM_VSCROLL()
ON_WM_MOUSEWHEEL()
ON_WM_LBUTTONDBLCLK()
ON_WM_CHAR()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_CAPTURECHANGED()
ON_WM_NCPAINT()
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
ON_MESSAGE(WM_SETFONT, OnSetFont)
END_MESSAGE_MAP()
int CXTPCoreTreeControl::RecalcTreeItems(CXTPCoreTreeItems* pItems, CDC* pDC, int nLevel, LPCRECT lprcMargin)
{
int nTop = lprcMargin->top;
int nWidth = m_rcControl.Width() - lprcMargin->left - lprcMargin->right;
POSITION pos = pItems->GetHeadPosition();
while (pos)
{
CXTPCoreTreeItem* pItem = pItems->GetNext(pos);
CSize sz = pItem->CalcSize(pDC, nWidth);
pItem->SetRect(CRect(m_rcControl.left + lprcMargin->left, nTop, m_rcControl.right - lprcMargin->right, nTop + sz.cy));
nTop += sz.cy;
if (pItem->IsExpanded() && pItem->HasChildren())
{
CRect rcMargin(lprcMargin);
rcMargin.top = nTop;
rcMargin.left += m_pPaintManager->GetChildrenIndent(pItem);
nTop = RecalcTreeItems(pItem->GetChildren(), pDC, nLevel + 1, rcMargin);
}
}
return nTop;
}
void CXTPCoreTreeControl::RecalcLayout()
{
if (!GetSafeHwnd())
return;
if (m_nLockRedraw > 0)
return;
CXTPClientRect rc(this);
m_rcControl = rc;
CRect rcMargin(0, 0, 0, 0);
{
CClientDC dc(this);
int nPos = RecalcTreeItems(m_pItems, &dc, 0, rcMargin);
m_nClientHeight = nPos;
}
UpdateScrollBar();
RedrawControl();
}
void CXTPCoreTreeControl::UpdateScrollBar()
{
if (m_bInUpdateScrollBar)
return;
m_bInUpdateScrollBar = TRUE;
CXTPClientRect rc(this);
m_bScrollVisible = rc.Height() < m_nClientHeight;
if (m_bScrollVisible)
{
ShowScrollBar(SB_VERT, TRUE);
SCROLLINFO si ;
si.cbSize = sizeof(SCROLLINFO) ;
si.fMask = SIF_PAGE | SIF_RANGE ;
GetScrollInfo(SB_VERT, &si, si.fMask);
UINT nControlHeight = (UINT)rc.Height();
if (si.nPage != nControlHeight || si.nMax != m_nClientHeight - 1 || si.nMin != 0)
{
si.nPage = nControlHeight ;
si.nMax = m_nClientHeight - 1;
si.nMin = 0 ;
si.fMask = SIF_PAGE | SIF_RANGE ;
SetScrollInfo(SB_VERT, &si) ;
}
EnableScrollBarCtrl(SB_VERT, TRUE);
}
else
{
SetScrollPos(SB_VERT, 0);
ShowScrollBar(SB_VERT, FALSE);
}
m_bInUpdateScrollBar = FALSE;
}
void CXTPCoreTreeControl::DrawTreeItems(CXTPCoreTreeItems* pItems, CDC* pDC, CRect rcClipBox)
{
POSITION pos = pItems->GetHeadPosition();
while (pos)
{
CXTPCoreTreeItem* pItem = pItems->GetNext(pos);
if (CRect().IntersectRect(pItem->GetRect(), rcClipBox))
{
pItem->Draw(pDC);
}
if (pItem->IsExpanded() && pItem->HasChildren())
{
DrawTreeItems(pItem->GetChildren(), pDC, rcClipBox);
}
}
}
void CXTPCoreTreeControl::OnDraw(CDC* pDC, CRect rcClipBox)
{
pDC->SetBkMode(TRANSPARENT);
m_pPaintManager->FillTreeControl(pDC, this);
int nScrollOffset = GetScrollOffset();
CPoint pt = pDC->GetViewportOrg();
pDC->SetViewportOrg(pt.x, pt.y - nScrollOffset);
rcClipBox.OffsetRect(0, nScrollOffset);
DrawTreeItems(m_pItems, pDC, rcClipBox);
if (m_pDragOverItem)
{
m_pPaintManager->DrawDropRect(pDC, m_pDragOverItem);
}
pDC->SetViewportOrg(pt);
}
BOOL CXTPCoreTreeControl::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
//
// PreCreateWindow is called when a control is dynamically
// created. We want to set m_bPreSubclassWindow to FALSE
// here so the control is initialized from CWnd::Create and
// not CWnd::PreSubclassWindow.
//
m_bPreSubclassWindow = FALSE;
return TRUE;
}
void CXTPCoreTreeControl::PreSubclassWindow()
{
CWnd::PreSubclassWindow();
if (m_bPreSubclassWindow)
{
m_pDropTarget->Register(this);
}
RecalcLayout();
}
/////////////////////////////////////////////////////////////////////////////
// CXTPCoreTreeControl message handlers
void CXTPCoreTreeControl::OnPaint()
{
CPaintDC dcPaint(this); // device context for painting
CRect rcPaint(dcPaint.m_ps.rcPaint);
CXTPBufferDC dc(dcPaint);
OnDraw(&dc, rcPaint);
}
LRESULT CXTPCoreTreeControl::OnPrintClient(WPARAM wParam, LPARAM /*lParam*/)
{
CDC* pDC = CDC::FromHandle((HDC)wParam);
if (pDC)
{
OnDraw(pDC, CXTPClientRect(this));
}
return TRUE;
}
BOOL CXTPCoreTreeControl::OnEraseBkgnd(CDC* /*pDC*/)
{
return TRUE;
}
void CXTPCoreTreeControl::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
RecalcLayout();
}
CXTPCoreTreeItem* CXTPCoreTreeControl::GetNextFocusableItem(CXTPCoreTreeItem* pFocusedItem) const
{
do
{
if (!pFocusedItem)
{
pFocusedItem = m_pItems->GetFirstItem();
}
else if (pFocusedItem->HasChildren() && pFocusedItem->IsExpanded())
{
pFocusedItem = pFocusedItem->GetFirstChildItem();
}
else
{
while (pFocusedItem && pFocusedItem->GetNextSiblingItem() == NULL)
{
pFocusedItem = pFocusedItem->GetParentItem();
}
if (pFocusedItem)
{
pFocusedItem = pFocusedItem->GetNextSiblingItem();
}
}
if (pFocusedItem && !pFocusedItem->IsLabel())
return pFocusedItem;
if (!pFocusedItem)
return NULL;
}
while (pFocusedItem);
return NULL;
}
CXTPCoreTreeItem* CXTPCoreTreeControl::GetPrevFocusableItem(CXTPCoreTreeItem* pFocusedItem) const
{
do
{
if (!pFocusedItem)
{
pFocusedItem = m_pItems->GetLastItem();
while (pFocusedItem && pFocusedItem->HasChildren() && pFocusedItem->IsExpanded())
{
pFocusedItem = pFocusedItem->GetChildren()->GetLastItem();
}
}
else if (pFocusedItem->GetPrevSiblingItem() != NULL)
{
pFocusedItem = pFocusedItem->GetPrevSiblingItem();
while (pFocusedItem->HasChildren() && pFocusedItem->IsExpanded())
{
pFocusedItem = pFocusedItem->GetChildren()->GetLastItem();
}
}
else
{
pFocusedItem = pFocusedItem->GetParentItem();
}
if (pFocusedItem && !pFocusedItem->IsLabel())
return pFocusedItem;
if (!pFocusedItem)
return NULL;
}
while (pFocusedItem);
return NULL;
}
void CXTPCoreTreeControl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
switch (nChar)
{
case VK_DOWN:
{
CXTPCoreTreeItem* pItem = GetNextFocusableItem(m_pFocusedItem);
if (pItem != NULL)
{
SetFocusedItem(pItem);
}
}
break;
case VK_UP:
{
CXTPCoreTreeItem* pItem = GetPrevFocusableItem(m_pFocusedItem);
if (pItem != NULL)
{
SetFocusedItem(pItem);
}
}
break;
case VK_LEFT:
{
if (m_pFocusedItem && m_pFocusedItem->HasChildren() && m_pFocusedItem->IsExpanded())
{
m_pFocusedItem->SetExpanded(FALSE);
}
else
{
CXTPCoreTreeItem* pItem = m_pFocusedItem ? m_pFocusedItem->GetParentItem() : NULL;
if (pItem != NULL)
{
SetFocusedItem(pItem);
}
}
}
break;
case VK_BACK:
{
CXTPCoreTreeItem* pItem = m_pFocusedItem ? m_pFocusedItem->GetParentItem() : NULL;
if (pItem != NULL)
{
SetFocusedItem(pItem);
}
}
break;
case VK_RIGHT:
{
if (m_pFocusedItem && m_pFocusedItem->HasChildren())
{
if (!m_pFocusedItem->IsExpanded())
{
m_pFocusedItem->SetExpanded(TRUE);
}
else
{
CXTPCoreTreeItem* pItem = GetNextFocusableItem(m_pFocusedItem);
if (pItem != NULL)
{
SetFocusedItem(pItem);
}
}
}
}
break;
case VK_HOME:
{
CXTPCoreTreeItem* pItem = GetNextFocusableItem(NULL);
if (pItem != NULL)
{
SetFocusedItem(pItem);
}
}
break;
case VK_END:
{
CXTPCoreTreeItem* pItem = GetPrevFocusableItem(NULL);
if (pItem != NULL)
{
SetFocusedItem(pItem);
}
}
break;
case VK_NEXT:
{
CXTPClientRect rc(this);
int nItems = (rc.Height() / m_pPaintManager->GetItemHeight()) - 2;
CXTPCoreTreeItem* pItem = m_pFocusedItem;
for (int i = 0; i < nItems; i++)
{
CXTPCoreTreeItem* pNextItem = GetNextFocusableItem(pItem);
if (!pNextItem)
break;
pItem = pNextItem;
}
if (pItem != NULL)
{
SetFocusedItem(pItem);
}
}
break;
case VK_PRIOR:
{
CXTPClientRect rc(this);
int nItems = (rc.Height() / m_pPaintManager->GetItemHeight()) - 2;
CXTPCoreTreeItem* pItem = m_pFocusedItem;
for (int i = 0; i < nItems; i++)
{
CXTPCoreTreeItem* pNextItem = GetPrevFocusableItem(pItem);
if (!pNextItem)
break;
pItem = pNextItem;
}
if (pItem != NULL)
{
SetFocusedItem(pItem);
}
}
break;
case VK_SPACE:
if (m_pFocusedItem && m_pFocusedItem->IsCheckboxVisible())
{
OnCheckClicked(m_pFocusedItem);
}
break;
case VK_ADD:
if (m_pFocusedItem && m_pFocusedItem->HasChildren())
{
m_pFocusedItem->SetExpanded(TRUE);
}
break;
case VK_SUBTRACT:
if (m_pFocusedItem && m_pFocusedItem->HasChildren())
{
m_pFocusedItem->SetExpanded(FALSE);
}
break;
case VK_MULTIPLY:
if (m_pFocusedItem && m_pFocusedItem->HasChildren())
{
SetLockRedraw(TRUE);
m_pFocusedItem->SetExpanded(TRUE);
ExpandeTreeItems(m_pFocusedItem->GetChildren());
SetLockRedraw(FALSE);
}
break;
}
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CXTPCoreTreeControl::StartDragItem(CXTPCoreTreeItem* /*pItem*/)
{
}
BOOL CXTPCoreTreeControl::DragItem(CXTPCoreTreeItem* pItem, DROPEFFECT dropEffectMask)
{
ASSERT(pItem);
if (!pItem)
return FALSE;
COleDataSource ds;
if (!pItem->PrepareDrag(ds))
return FALSE;
m_pDraggingItem = pItem;
DROPEFFECT dropEffect = ds.DoDragDrop(dropEffectMask);
BOOL bRemoved = FALSE;
if ((dropEffect == DROPEFFECT_MOVE) && (dropEffectMask & DROPEFFECT_MOVE))
{
if (m_pDraggingItem)
{
m_pDraggingItem->Remove();
bRemoved = TRUE;
}
}
m_pDraggingItem = NULL;
return bRemoved;
}
void CXTPCoreTreeControl::SetDragOverItem(CXTPCoreTreeItem* pDragOverItem, XTPCoreTreeDropPosition nDropPosition)
{
if (m_pDragOverItem != pDragOverItem || nDropPosition != m_nDropPosition)
{
m_pDragOverItem = pDragOverItem;
m_nDropPosition = nDropPosition;
RedrawControl();
}
};
DROPEFFECT CXTPCoreTreeControl::OnDragOver(COleDataObject* /*pDataObject*/, DWORD /*dwKeyState*/, CPoint /*point*/)
{
return DROPEFFECT_NONE;
}
void CXTPCoreTreeControl::OnDragHover(COleDataObject* /*pDataObject*/, DWORD /*dwKeyState*/, CPoint point)
{
CXTPCoreTreeItem* pItem = HitTest(point);
if (pItem && pItem->HasChildren())
{
pItem->SetExpanded(TRUE);
}
}
BOOL CXTPCoreTreeControl::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint /*point*/)
{
if (!m_pDragOverItem)
return FALSE;
CXTPCoreTreeItem* pDragOverItem = m_pDragOverItem;
m_pDragOverItem = NULL;
RedrawControl();
if (dropEffect != DROPEFFECT_COPY && dropEffect != DROPEFFECT_MOVE)
return FALSE;
if (!pDataObject || !pDataObject->IsDataAvailable(GetClipboardFormat()))
return FALSE;
CXTPCoreTreeItem* pItemDrop = CXTPCoreTreeItem::CreateFromOleData(pDataObject);
if (!pItemDrop)
return FALSE;
if (m_nDropPosition == xtpCoreTreeDropAfter)
{
pDragOverItem->GetParentItems()->AddItemAfter(pItemDrop, pDragOverItem);
}
else if (m_nDropPosition == xtpCoreTreeDropBefore)
{
pDragOverItem->GetParentItems()->AddItemBefore(pItemDrop, pDragOverItem);
}
else if (m_nDropPosition == xtpCoreTreeDropChild)
{
pDragOverItem->GetChildren()->AddItemBefore(pItemDrop, NULL);
pDragOverItem->SetExpanded();
}
else
{
ASSERT(FALSE);
}
SetFocusedItem(pItemDrop);
return TRUE;
}
void CXTPCoreTreeControl::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_pPressedItem && (abs(m_ptPressed.x - point.x) + abs(m_ptPressed.y - point.y) > 4))
{
CXTPCoreTreeItem* pItem = m_pPressedItem;
ReleaseCapture();
StartDragItem(pItem);
return;
}
CWnd::OnMouseMove(nFlags, point);
}
void CXTPCoreTreeControl::OnCheckClicked(CXTPCoreTreeItem* pItem)
{
if (pItem->IsEnabled())
{
pItem->SetChecked(!pItem->IsChecked());
SendMessageToParent(XTP_TVN_CHECKCHANGED);
}
}
void CXTPCoreTreeControl::OnLButtonDown(UINT nFlags, CPoint point)
{
SetFocus();
CXTPCoreTreeItem* pItem = HitTest(point);
if (pItem != NULL)
{
m_ptPressed = point;
point.y += GetScrollOffset();
if (pItem->HasChildren() && pItem->GetButtonRect().PtInRect(point))
{
pItem->SetExpanded(!pItem->IsExpanded());
if (pItem->IsParent(m_pFocusedItem))
{
SetFocusedItem(pItem);
}
}
else if (pItem->GetCheckboxRect().PtInRect(point))
{
SetFocusedItem(pItem);
OnCheckClicked(pItem);
}
else
{
SetFocusedItem(pItem);
SetCapture();
m_pPressedItem = pItem;
}
}
CWnd::OnLButtonDown(nFlags, point);
}
void CXTPCoreTreeControl::OnLButtonUp(UINT nFlags, CPoint point)
{
m_pPressedItem = NULL;
ReleaseCapture();
CWnd::OnLButtonUp(nFlags, point);
}
void CXTPCoreTreeControl::OnCaptureChanged(CWnd* pWnd)
{
m_pPressedItem = NULL;
CWnd::OnCaptureChanged(pWnd);
}
void CXTPCoreTreeControl::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CXTPCoreTreeItem* pItem = HitTest(point);
if (pItem)
{
point.y += GetScrollOffset();
if (pItem->GetCheckboxRect().PtInRect(point))
{
OnCheckClicked(pItem);
}
else if (pItem->HasChildren())
{
pItem->SetExpanded(!pItem->IsExpanded());
}
}
CWnd::OnLButtonDblClk(nFlags, point);
}
void CXTPCoreTreeControl::OnSysColorChange()
{
CWnd::OnSysColorChange();
m_pPaintManager->RefreshMetrics();
RedrawControl();
}
UINT CXTPCoreTreeControl::OnGetDlgCode()
{
return DLGC_WANTARROWS | DLGC_WANTCHARS;
}
void CXTPCoreTreeControl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
if (pScrollBar != NULL)
{
CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
return;
}
// its horizontal scroll bar
int nCurPos = GetScrollPos(SB_VERT);
// decide what to do for each diffrent scroll event
switch (nSBCode)
{
case SB_LEFT: nCurPos = 0; break;
case SB_RIGHT: nCurPos = GetScrollLimit(SB_VERT); break;
case SB_LINELEFT: nCurPos = max(nCurPos - 6, 0); break;
case SB_LINERIGHT: nCurPos = min(nCurPos + 6, GetScrollLimit(SB_VERT)); break;
case SB_PAGELEFT: nCurPos = max(nCurPos - CXTPClientRect(this).Height(), 0); break;
case SB_PAGERIGHT: nCurPos = min(nCurPos + CXTPClientRect(this).Height(), GetScrollLimit(SB_VERT)); break;
case SB_THUMBTRACK:
case SB_THUMBPOSITION:
{
SCROLLINFO si;
ZeroMemory(&si, sizeof(SCROLLINFO));
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_TRACKPOS;
if (!GetScrollInfo(SB_VERT, &si))
return;
nCurPos = si.nTrackPos;
}
break;
}
OnScrollChanged(nCurPos);
}
BOOL CXTPCoreTreeControl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
if (m_bScrollVisible)
{
int nCurPos = GetScrollPos(SB_VERT);
int nDelta = 3 * m_pPaintManager->GetItemHeight();
if (zDelta > 0) nCurPos = max(nCurPos - nDelta, 0);
else nCurPos = min(nCurPos + nDelta, GetScrollLimit(SB_VERT));
OnScrollChanged(nCurPos);
RedrawControl();
return TRUE;
}
return CWnd::OnMouseWheel(nFlags, zDelta, pt);
}
LRESULT CXTPCoreTreeControl::OnSetFont(WPARAM wParam, LPARAM lParam)
{
HFONT hFont = (HFONT)wParam;
LOGFONT lf;
if (GetObject(hFont, sizeof(LOGFONT), &lf))
{
m_pPaintManager->SetFontIndirect(&lf);
}
return CWnd::DefWindowProc(WM_SETFONT, wParam, lParam);
}
void CXTPCoreTreeControl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CWnd::OnChar(nChar, nRepCnt, nFlags);
}
void CXTPCoreTreeControl::OnNcPaint()
{
Default();
if (GetPaintManager()->IsAppThemed() && GetExStyle() & WS_EX_CLIENTEDGE)
{
CWindowDC dc(this);
CXTPWindowRect rc(this);
rc.OffsetRect(-rc.TopLeft());
dc.Draw3dRect(rc, GetSysColor(COLOR_BTNSHADOW), GetSysColor(COLOR_BTNSHADOW));
rc.DeflateRect(1, 1);
dc.Draw3dRect(rc, GetSysColor(COLOR_WINDOW), GetSysColor(COLOR_WINDOW));
}
}
void CXTPCoreTreeControl::OnSetFocus(CWnd* pOldWnd)
{
CWnd::OnSetFocus(pOldWnd);
if (m_pFocusedItem)
{
RedrawControl(m_pFocusedItem->GetScreenRect());
}
}
void CXTPCoreTreeControl::OnKillFocus(CWnd* pNewWnd)
{
CWnd::OnKillFocus(pNewWnd);
if (m_pFocusedItem)
{
RedrawControl(m_pFocusedItem->GetScreenRect());
}
}