1 // PropTreeList.cpp : implementation file
3 // Copyright (C) 1998-2001 Scott Ramsay
5 // http://www.gonavi.com
7 // This material is provided "as is", with absolutely no warranty expressed
8 // or implied. Any use is at your own risk.
10 // Permission to use or copy this software for any purpose is hereby granted
11 // without fee, provided the above notices are retained on all copies.
12 // Permission to modify the code and to distribute modified code is granted,
13 // provided the above notices are retained, and a notice that the code was
14 // modified is included with the above copyright notice.
16 // If you use this code, drop me an email. I'd like to know if you find the code
20 #include "../../../idlib/precompiled.h"
24 #include "../../../sys/win32/rc/proptree_Resource.h"
25 #include "PropTreeList.h"
30 static char THIS_FILE[] = __FILE__;
33 #define PROPTREEITEM_EXPANDCOLUMN 16 // width of the expand column
34 #define PROPTREEITEM_COLRNG 5 // width of splitter
35 #define PROPTREEITEM_DEFHEIGHT 21 // default heigt of an item
37 extern HINSTANCE ghInst;
39 /////////////////////////////////////////////////////////////////////////////
42 CPropTreeList::CPropTreeList() :
44 m_BackBufferSize(0,0),
50 CPropTreeList::~CPropTreeList()
55 BEGIN_MESSAGE_MAP(CPropTreeList, CWnd)
56 //{{AFX_MSG_MAP(CPropTreeList)
72 /////////////////////////////////////////////////////////////////////////////
73 // CPropTreeList message handlers
75 void CPropTreeList::SetPropOwner(CPropTree* pProp)
81 BOOL CPropTreeList::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
85 LPCTSTR pszCreateClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, ::LoadCursor(NULL, IDC_ARROW));
87 return pWnd->Create(pszCreateClass, _T(""), dwStyle, rect, pParentWnd, nID);
91 void CPropTreeList::OnSize(UINT nType, int cx, int cy)
93 CWnd::OnSize(nType, cx, cy);
95 RecreateBackBuffer(cx, cy);
103 // inform all items that a resize has been made
104 m_pProp->UpdateMoveAllItems();
109 void CPropTreeList::RecreateBackBuffer(int cx, int cy)
111 if (m_BackBufferSize.cx<cx || m_BackBufferSize.cy<cy)
113 m_BackBufferSize = CSize(cx, cy);
117 int nPlanes = dc.GetDeviceCaps(PLANES);
118 int nBitCount = dc.GetDeviceCaps(BITSPIXEL);
120 m_BackBuffer.DeleteObject();
121 m_BackBuffer.CreateBitmap(cx, cy, nPlanes, nBitCount, NULL);
126 void CPropTreeList::UpdateResize()
132 ASSERT(m_pProp!=NULL);
135 nHeight = rc.Height() + 1;
137 ZeroMemory(&si, sizeof(SCROLLINFO));
138 si.cbSize = sizeof(SCROLLINFO);
139 si.fMask = SIF_RANGE|SIF_PAGE;
141 si.nMax = m_pProp->GetRootItem()->GetTotalHeight();
144 if ((int)si.nPage>si.nMax)
145 m_pProp->SetOriginOffset(0);
147 SetScrollInfo(SB_VERT, &si, TRUE);
149 // force set column for clipping
150 m_pProp->SetColumn(m_pProp->GetColumn());
154 void CPropTreeList::OnPaint()
160 ASSERT(m_pProp!=NULL);
162 m_pProp->ClearVisibleList();
164 memdc.CreateCompatibleDC(&dc);
165 pOldBitmap = memdc.SelectObject(&m_BackBuffer);
170 // draw control background
171 memdc.SelectObject(GetSysColorBrush(COLOR_BTNFACE));
172 memdc.PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATCOPY);
174 // draw control inside fill color
176 memdc.PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), m_pProp->IsWindowEnabled() ? WHITENESS : PATCOPY);
179 // draw expand column
180 memdc.SelectObject(GetSysColorBrush(COLOR_BTNFACE));
181 memdc.PatBlt(0, 0, PROPTREEITEM_EXPANDCOLUMN, rc.Height(), PATCOPY);
184 memdc.DrawEdge(&rc, BDR_SUNKENOUTER, BF_RECT);
186 CPropTreeItem* pItem;
189 ASSERT(m_pProp->GetRootItem()!=NULL);
193 // create clip region
194 HRGN hRgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
195 SelectClipRgn(memdc.m_hDC, hRgn);
198 for (pItem = m_pProp->GetRootItem()->GetChild(); pItem; pItem = pItem->GetSibling())
200 LONG nHeight = pItem->DrawItem(&memdc, rc, 0, nTotal);
204 // remove clip region
205 SelectClipRgn(memdc.m_hDC, NULL);
208 // copy back buffer to the display
210 dc.BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &memdc, rc.left, rc.top, SRCCOPY);
215 BOOL CPropTreeList::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
217 if (nHitTest==HTCLIENT)
221 ASSERT(m_pProp!=NULL);
226 switch (m_pProp->HitTest(pt))
229 SetCursor(LoadCursor(ghInst, MAKEINTRESOURCE(IDC_SPLITTER)));
235 SetCursor(LoadCursor(ghInst, MAKEINTRESOURCE(IDC_FPOINT)));
240 return CWnd::OnSetCursor(pWnd, nHitTest, message);
244 void CPropTreeList::OnLButtonDown(UINT, CPoint point)
246 ASSERT(m_pProp!=NULL);
248 if (m_pProp->IsDisableInput())
251 m_pProp->SendNotify(NM_CLICK);
253 if (!m_pProp->IsWindowEnabled())
258 LONG nHit = m_pProp->HitTest(point);
260 CPropTreeItem* pItem;
267 if (m_pProp->SendNotify(PTN_COLUMNCLICK))
273 m_nPrevCol = m_pProp->GetOrigin().x;
278 pDC->PatBlt(m_nPrevCol - PROPTREEITEM_COLRNG/2, 0, PROPTREEITEM_COLRNG, rc.bottom, PATINVERT);
283 if ((pItem = m_pProp->FindItem(point))!=NULL)
285 pItem->Check(!pItem->IsChecked());
286 m_pProp->SendNotify(PTN_CHECKCLICK, pItem);
291 if ((pItem = m_pProp->FindItem(point))!=NULL)
294 m_pProp->SendNotify(PTN_ITEMBUTTONCLICK, pItem);
299 if ((pItem = m_pProp->FindItem(point))!=NULL)
301 if (pItem->GetChild() && !m_pProp->SendNotify(PTN_ITEMEXPANDING, pItem))
303 pItem->Expand(!pItem->IsExpanded());
314 if ((pItem = m_pProp->FindItem(point))!=NULL)
316 CPropTreeItem* pOldFocus = m_pProp->GetFocusedItem();
318 m_pProp->SelectItems(NULL, FALSE);
319 m_pProp->SetFocusedItem(pItem);
325 if (pItem!=pOldFocus)
326 m_pProp->SendNotify(PTN_SELCHANGE, pItem);
328 if (nHit==HTATTRIBUTE && !pItem->IsRootLevel())
330 if (!m_pProp->SendNotify(PTN_PROPCLICK, pItem) && !pItem->IsReadOnly())
331 pItem->Activate(CPropTreeItem::ACTIVATE_TYPE_MOUSE, point);
336 m_pProp->SelectItems(NULL, FALSE);
337 m_pProp->SetFocusedItem(NULL);
338 m_pProp->SendNotify(PTN_SELCHANGE);
346 void CPropTreeList::OnLButtonUp(UINT, CPoint point)
354 pDC->PatBlt(m_nPrevCol - PROPTREEITEM_COLRNG/2, 0, PROPTREEITEM_COLRNG, rc.bottom, PATINVERT);
360 m_pProp->SetColumn(point.x);
361 m_pProp->UpdateMoveAllItems();
364 LONG nHit = m_pProp->HitTest(point);
365 CPropTreeItem* pItem;
370 if ((pItem = m_pProp->FindItem(point))!=NULL)
372 pItem->Check( FALSE );
383 void CPropTreeList::OnLButtonDblClk(UINT, CPoint point)
385 ASSERT(m_pProp!=NULL);
387 m_pProp->SendNotify(NM_DBLCLK);
389 CPropTreeItem* pItem;
390 CPropTreeItem* pOldFocus;
392 if ((pItem = m_pProp->FindItem(point))!=NULL && pItem->GetChild())
394 switch (m_pProp->HitTest(point))
400 pItem->Check(!pItem->IsChecked());
401 m_pProp->SendNotify(PTN_CHECKCLICK, pItem);
406 if (!pItem->IsRootLevel())
409 // pass thru to default
412 pOldFocus = m_pProp->GetFocusedItem();
413 m_pProp->SelectItems(NULL, FALSE);
414 m_pProp->SetFocusedItem(pItem);
417 if (pItem!=pOldFocus)
418 m_pProp->SendNotify(PTN_SELCHANGE, pItem);
420 // pass thru to HTEXPAND
423 if (!m_pProp->SendNotify(PTN_ITEMEXPANDING, pItem))
425 pItem->Expand(!pItem->IsExpanded());
438 void CPropTreeList::OnMouseMove(UINT, CPoint point)
446 pDC->PatBlt(m_nPrevCol - PROPTREEITEM_COLRNG/2, 0, PROPTREEITEM_COLRNG, rc.bottom, PATINVERT);
447 pDC->PatBlt(point.x - PROPTREEITEM_COLRNG/2, 0, PROPTREEITEM_COLRNG, rc.bottom, PATINVERT);
448 m_nPrevCol = point.x;
454 BOOL CPropTreeList::OnMouseWheel(UINT, short zDelta, CPoint)
458 ZeroMemory(&si, sizeof(SCROLLINFO));
459 si.cbSize = sizeof(SCROLLINFO);
460 si.fMask = SIF_RANGE;
462 GetScrollInfo(SB_VERT, &si);
467 if (si.nMax - si.nMin < rc.Height())
471 OnVScroll(zDelta < 0 ? SB_LINEDOWN : SB_LINEUP, 0, NULL);
477 void CPropTreeList::OnKeyDown(UINT nChar, UINT, UINT)
480 CPropTreeItem* pItem;
482 ASSERT(m_pProp!=NULL);
484 if (m_pProp->IsDisableInput() || !m_pProp->IsWindowEnabled())
490 if ((pItem = m_pProp->GetFocusedItem())!=NULL && !pItem->IsRootLevel() && !pItem->IsReadOnly())
492 pItem->Activate(CPropTreeItem::ACTIVATE_TYPE_KEYBOARD, CPoint(0,0));
497 if (m_pProp->FocusFirst())
502 if (m_pProp->FocusLast())
507 if ((pItem = m_pProp->GetFocusedItem())!=NULL)
509 if (!m_pProp->SendNotify(PTN_ITEMEXPANDING, pItem))
511 if (pItem->GetChild() && pItem->IsExpanded())
513 pItem->Expand(FALSE);
524 // pass thru to next case VK_UP
526 if (m_pProp->FocusPrev())
531 if ((pItem = m_pProp->GetFocusedItem())!=NULL)
533 if (!m_pProp->SendNotify(PTN_ITEMEXPANDING, pItem))
535 if (pItem->GetChild() && !pItem->IsExpanded())
548 // pass thru to next case VK_DOWN
550 if (m_pProp->FocusNext())
557 UINT CPropTreeList::OnGetDlgCode()
559 return DLGC_WANTARROWS|DLGC_WANTCHARS|DLGC_WANTALLKEYS;
563 void CPropTreeList::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*)
572 nHeight = rc.Height() + 1;
574 ZeroMemory(&si, sizeof(SCROLLINFO));
575 si.cbSize = sizeof(SCROLLINFO);
576 si.fMask = SIF_RANGE;
578 GetScrollInfo(SB_VERT, &si);
580 LONG ny = m_pProp->GetOrigin().y;
585 ny += PROPTREEITEM_DEFHEIGHT;
589 ny -= PROPTREEITEM_DEFHEIGHT;
605 ny = __min(__max(ny, si.nMin), si.nMax - nHeight);
607 m_pProp->SetOriginOffset(ny);
611 SetScrollInfo(SB_VERT, &si, TRUE);
616 void CPropTreeList::CheckVisibleFocus()
618 ASSERT(m_pProp!=NULL);
620 CPropTreeItem* pItem;
622 if ((pItem = m_pProp->GetFocusedItem())==NULL)
625 if (!m_pProp->IsItemVisible(pItem))
627 if (m_pProp->IsSingleSelection())
628 pItem->Select(FALSE);
630 m_pProp->SetFocusedItem(NULL);
631 m_pProp->SendNotify(PTN_SELCHANGE, NULL);