EGPropertyGridList.cpp
Upload User: kairuinn
Upload Date: 2009-02-07
Package Size: 2922k
Code Size: 13k
Category:

Graph program

Development Platform:

Visual C++

  1. // PropTreeList.cpp : implementation file
  2. //
  3. //  Copyright (C) 1998-2001 Scott Ramsay
  4. // sramsay@gonavi.com
  5. // http://www.gonavi.com
  6. //
  7. //  This material is provided "as is", with absolutely no warranty expressed
  8. //  or implied. Any use is at your own risk.
  9. // 
  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.
  15. // 
  16. // If you use this code, drop me an email.  I'd like to know if you find the code
  17. // useful.
  18. #include "stdafx.h"
  19. #include "EGPropertyGrid.h"
  20. //#include "Resource.h"
  21. #include "EGPropertyGridList.h"
  22. #ifdef _DEBUG
  23. #define new DEBUG_NEW
  24. #undef THIS_FILE
  25. static char THIS_FILE[] = __FILE__;
  26. #endif
  27. #define PROPTREEITEM_EXPANDCOLUMN 16 // width of the expand column
  28. #define PROPTREEITEM_COLRNG 5 // width of splitter
  29. #define PROPTREEITEM_DEFHEIGHT 21 // default heigt of an item
  30. extern HINSTANCE ghInst;
  31. /////////////////////////////////////////////////////////////////////////////
  32. // CEGPropertyGridList
  33. CEGPropertyGridList::CEGPropertyGridList() :
  34. m_pProp(NULL),
  35. m_BackBufferSize(0,0),
  36. m_bColDrag(FALSE),
  37. m_nPrevCol(0)
  38. {
  39. }
  40. CEGPropertyGridList::~CEGPropertyGridList()
  41. {
  42. }
  43. BEGIN_MESSAGE_MAP(CEGPropertyGridList, CWnd)
  44. //{{AFX_MSG_MAP(CEGPropertyGridList)
  45. ON_WM_SIZE()
  46. ON_WM_PAINT()
  47. ON_WM_SETCURSOR()
  48. ON_WM_LBUTTONDOWN()
  49. ON_WM_LBUTTONUP()
  50. ON_WM_LBUTTONDBLCLK()
  51. ON_WM_MOUSEMOVE()
  52. ON_WM_MOUSEWHEEL()
  53. ON_WM_KEYDOWN()
  54. ON_WM_GETDLGCODE()
  55. ON_WM_VSCROLL()
  56. //}}AFX_MSG_MAP
  57. END_MESSAGE_MAP()
  58. /////////////////////////////////////////////////////////////////////////////
  59. // CEGPropertyGridList message handlers
  60. void CEGPropertyGridList::SetPropOwner(CEGPropertyGrid* pProp)
  61. {
  62. m_pProp = pProp;
  63. }
  64. BOOL CEGPropertyGridList::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
  65. {
  66. CWnd* pWnd = this;
  67. LPCTSTR pszCreateClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, ::LoadCursor(NULL, IDC_ARROW));
  68. return pWnd->Create(pszCreateClass, _T(""), dwStyle, rect, pParentWnd, nID);
  69. }
  70. void CEGPropertyGridList::OnSize(UINT nType, int cx, int cy) 
  71. {
  72. CWnd::OnSize(nType, cx, cy);
  73. RecreateBackBuffer(cx, cy);
  74. if (m_pProp)
  75. {
  76. UpdateResize();
  77. Invalidate();
  78. UpdateWindow();
  79. // inform all items that a resize has been made
  80. m_pProp->UpdateMoveAllItems();
  81. }
  82. }
  83. void CEGPropertyGridList::RecreateBackBuffer(int cx, int cy)
  84. {
  85. if (m_BackBufferSize.cx<cx || m_BackBufferSize.cy<cy)
  86. {
  87. m_BackBufferSize = CSize(cx, cy);
  88. CWindowDC dc(NULL);
  89. int nPlanes = dc.GetDeviceCaps(PLANES);
  90. int nBitCount = dc.GetDeviceCaps(BITSPIXEL);
  91. m_BackBuffer.DeleteObject();
  92. m_BackBuffer.CreateBitmap(cx, cy, nPlanes, nBitCount, NULL);
  93. }
  94. }
  95. void CEGPropertyGridList::UpdateResize()
  96. {
  97. SCROLLINFO si;
  98. LONG nHeight;
  99. CRect rc;
  100. ASSERT(m_pProp!=NULL);
  101. GetClientRect(rc);
  102. nHeight = rc.Height() + 1;
  103. ZeroMemory(&si, sizeof(SCROLLINFO));
  104. si.cbSize = sizeof(SCROLLINFO);
  105. si.fMask = SIF_RANGE|SIF_PAGE;
  106. si.nMin = 0;
  107. si.nMax = m_pProp->GetRootItem()->GetTotalHeight();
  108. si.nPage = nHeight;
  109. if ((int)si.nPage>si.nMax)
  110. m_pProp->SetOriginOffset(0);
  111. SetScrollInfo(SB_VERT, &si, TRUE);
  112. // force set column for clipping
  113. m_pProp->SetColumn(m_pProp->GetColumn());
  114. }
  115. void CEGPropertyGridList::OnPaint() 
  116. {
  117. CPaintDC dc(this);
  118. CDC memdc;
  119. CBitmap* pOldBitmap;
  120. ASSERT(m_pProp!=NULL);
  121. m_pProp->ClearVisibleList();
  122. memdc.CreateCompatibleDC(&dc);
  123. pOldBitmap = memdc.SelectObject(&m_BackBuffer);
  124. CRect rc;
  125. GetClientRect(rc);
  126. // draw control background
  127. memdc.SelectObject(GetSysColorBrush(COLOR_BTNFACE));
  128. memdc.PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATCOPY);
  129. // draw control inside fill color
  130. rc.DeflateRect(2,2);
  131. memdc.PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), m_pProp->IsWindowEnabled() ? WHITENESS : PATCOPY);
  132. rc.InflateRect(2,2);
  133. // draw expand column
  134. memdc.SelectObject(GetSysColorBrush(COLOR_BTNFACE));
  135. memdc.PatBlt(0, 0, PROPTREEITEM_EXPANDCOLUMN, rc.Height(), PATCOPY);
  136. // draw edge
  137. memdc.DrawEdge(&rc, BDR_SUNKENOUTER, BF_RECT);
  138. CEGPropertyGridItem* pItem;
  139. LONG nTotal = 0;
  140. ASSERT(m_pProp->GetRootItem()!=NULL);
  141. rc.DeflateRect(2,2);
  142. // create clip region
  143. HRGN hRgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
  144. SelectClipRgn(memdc.m_hDC, hRgn);
  145. // draw all items
  146. for (pItem = m_pProp->GetRootItem()->GetChild(); pItem; pItem = pItem->GetSibling())
  147. {
  148. LONG nHeight = pItem->DrawItem(&memdc, rc, 0, nTotal);
  149. nTotal += nHeight;
  150. }
  151. // remove clip region
  152. SelectClipRgn(memdc.m_hDC, NULL);
  153. DeleteObject(hRgn);
  154. // copy back buffer to the display
  155. dc.GetClipBox(&rc);
  156. dc.BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &memdc, rc.left, rc.top, SRCCOPY);
  157. memdc.DeleteDC();
  158. }
  159. BOOL CEGPropertyGridList::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
  160. {
  161. if (nHitTest==HTCLIENT)
  162. {
  163. CPoint pt;
  164. ASSERT(m_pProp!=NULL);
  165. GetCursorPos(&pt);
  166. ScreenToClient(&pt);
  167. switch (m_pProp->HitTest(pt))
  168. {
  169. case HTCOLUMN:
  170. SetCursor( ::LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZEWE) ) );
  171. return TRUE;
  172. case HTCHECKBOX:
  173. case HTEXPAND:
  174. SetCursor( ::LoadCursor(NULL, MAKEINTRESOURCE(IDC_HAND) ) );
  175. return TRUE;
  176. }
  177. }
  178. return CWnd::OnSetCursor(pWnd, nHitTest, message);
  179. }
  180. void CEGPropertyGridList::OnLButtonDown(UINT, CPoint point) 
  181. {
  182. ASSERT(m_pProp!=NULL);
  183. if (m_pProp->IsDisableInput())
  184. return;
  185. m_pProp->SendNotify(NM_CLICK);
  186. if (!m_pProp->IsWindowEnabled())
  187. return;
  188. SetFocus();
  189. LONG nHit = m_pProp->HitTest(point);
  190. CEGPropertyGridItem* pItem;
  191. CRect rc;
  192. CDC* pDC;
  193. switch (nHit)
  194. {
  195. case HTCOLUMN:
  196. if (m_pProp->SendNotify(PTN_COLUMNCLICK))
  197. break;
  198. m_bColDrag = TRUE;
  199. SetCapture();
  200. m_nPrevCol = m_pProp->GetOrigin().x;
  201. // paint drag line
  202. pDC = GetDC();
  203. GetClientRect(rc);
  204. pDC->PatBlt(m_nPrevCol - PROPTREEITEM_COLRNG/2, 0, PROPTREEITEM_COLRNG, rc.bottom, PATINVERT);
  205. ReleaseDC(pDC);
  206. break;
  207. case HTCHECKBOX:
  208. if ((pItem = m_pProp->FindItem(point))!=NULL)
  209. {
  210. pItem->Check(!pItem->IsChecked());
  211. m_pProp->SendNotify(PTN_CHECKCLICK, pItem);
  212. Invalidate();
  213. }
  214. break;
  215. case HTEXPAND:
  216. if ((pItem = m_pProp->FindItem(point))!=NULL)
  217. {
  218. if (pItem->GetChild() && !m_pProp->SendNotify(PTN_ITEMEXPANDING, pItem))
  219. {
  220. pItem->Expand(!pItem->IsExpanded());
  221. UpdateResize();
  222. Invalidate();
  223. UpdateWindow();
  224. CheckVisibleFocus();
  225. }
  226. }
  227. break;
  228. default:
  229. if ((pItem = m_pProp->FindItem(point))!=NULL)
  230. {
  231. CEGPropertyGridItem* pOldFocus = m_pProp->GetFocusedItem();
  232. m_pProp->SelectItems(NULL, FALSE);
  233. m_pProp->SetFocusedItem(pItem);
  234. pItem->Select();
  235. Invalidate();
  236. if (pItem!=pOldFocus)
  237. m_pProp->SendNotify(PTN_SELCHANGE, pItem);
  238. if (nHit==HTATTRIBUTE && !pItem->IsRootLevel())
  239. {
  240. if (!m_pProp->SendNotify(PTN_PROPCLICK, pItem) && !pItem->IsReadOnly())
  241. pItem->Activate();
  242. }
  243. }
  244. else
  245. {
  246. m_pProp->SelectItems(NULL, FALSE);
  247. m_pProp->SetFocusedItem(NULL);
  248. m_pProp->SendNotify(PTN_SELCHANGE);
  249. Invalidate();
  250. }
  251. break;
  252. }
  253. }
  254. void CEGPropertyGridList::OnLButtonUp(UINT, CPoint point) 
  255. {
  256. if (m_bColDrag)
  257. {
  258. CDC* pDC = GetDC();
  259. CRect rc;
  260. GetClientRect(rc);
  261. pDC->PatBlt(m_nPrevCol - PROPTREEITEM_COLRNG/2, 0, PROPTREEITEM_COLRNG, rc.bottom, PATINVERT);
  262. ReleaseDC(pDC);
  263. m_bColDrag = FALSE;
  264. ReleaseCapture();
  265. m_pProp->SetColumn(point.x);
  266. m_pProp->UpdateMoveAllItems();
  267. Invalidate();
  268. }
  269. }
  270. void CEGPropertyGridList::OnLButtonDblClk(UINT, CPoint point)
  271. {
  272. ASSERT(m_pProp!=NULL);
  273. m_pProp->SendNotify(NM_DBLCLK);
  274. CEGPropertyGridItem* pItem;
  275. CEGPropertyGridItem* pOldFocus;
  276. if ((pItem = m_pProp->FindItem(point))!=NULL && pItem->GetChild())
  277. {
  278. switch (m_pProp->HitTest(point))
  279. {
  280. case HTCOLUMN:
  281. break;
  282. case HTCHECKBOX:
  283. pItem->Check(!pItem->IsChecked());
  284. m_pProp->SendNotify(PTN_CHECKCLICK, pItem);
  285. Invalidate();
  286. break;
  287. case HTATTRIBUTE:
  288. if (!pItem->IsRootLevel())
  289. break;
  290. // pass thru to default
  291. default:
  292. pOldFocus = m_pProp->GetFocusedItem();
  293. m_pProp->SelectItems(NULL, FALSE);
  294. m_pProp->SetFocusedItem(pItem);
  295. pItem->Select();
  296. if (pItem!=pOldFocus)
  297. m_pProp->SendNotify(PTN_SELCHANGE, pItem);
  298. // pass thru to HTEXPAND
  299. case HTEXPAND:
  300. if (!m_pProp->SendNotify(PTN_ITEMEXPANDING, pItem))
  301. {
  302. pItem->Expand(!pItem->IsExpanded());
  303. UpdateResize();
  304. Invalidate();
  305. UpdateWindow();
  306. CheckVisibleFocus();
  307. }
  308. break;
  309. }
  310. }
  311. }
  312. void CEGPropertyGridList::OnMouseMove(UINT, CPoint point)
  313. {
  314. if (m_bColDrag)
  315. {
  316. CDC* pDC = GetDC();
  317. CRect rc;
  318. GetClientRect(rc);
  319. pDC->PatBlt(m_nPrevCol - PROPTREEITEM_COLRNG/2, 0, PROPTREEITEM_COLRNG, rc.bottom, PATINVERT);
  320. pDC->PatBlt(point.x - PROPTREEITEM_COLRNG/2, 0, PROPTREEITEM_COLRNG, rc.bottom, PATINVERT);
  321. m_nPrevCol = point.x;
  322. ReleaseDC(pDC);
  323. }
  324. }
  325. BOOL CEGPropertyGridList::OnMouseWheel(UINT, short zDelta, CPoint) 
  326. {
  327. SCROLLINFO si;
  328. ZeroMemory(&si, sizeof(SCROLLINFO));
  329. si.cbSize = sizeof(SCROLLINFO);
  330. si.fMask = SIF_RANGE;
  331. GetScrollInfo(SB_VERT, &si);
  332. CRect rc;
  333. GetClientRect(rc);
  334. if (si.nMax - si.nMin < rc.Height())
  335. return TRUE;
  336. SetFocus();
  337. OnVScroll(zDelta < 0 ? SB_LINEDOWN : SB_LINEUP, 0, NULL);
  338. return TRUE;
  339. }
  340. void CEGPropertyGridList::OnKeyDown(UINT nChar, UINT, UINT) 
  341. {
  342. CEGPropertyGridItem* pItem;
  343. ASSERT(m_pProp!=NULL);
  344. if (m_pProp->IsDisableInput() || !m_pProp->IsWindowEnabled())
  345. return;
  346. switch (nChar)
  347. {
  348. case VK_RETURN:
  349. if ((pItem = m_pProp->GetFocusedItem())!=NULL && !pItem->IsRootLevel() && !pItem->IsReadOnly())
  350. {
  351. pItem->Activate();
  352. }
  353. break;
  354. case VK_HOME:
  355. if (m_pProp->FocusFirst())
  356. Invalidate();
  357. break;
  358. case VK_END:
  359. if (m_pProp->FocusLast())
  360. Invalidate();
  361. break;
  362. case VK_LEFT:
  363. if ((pItem = m_pProp->GetFocusedItem())!=NULL)
  364. {
  365. if (!m_pProp->SendNotify(PTN_ITEMEXPANDING, pItem))
  366. {
  367. if (pItem->GetChild() && pItem->IsExpanded())
  368. {
  369. pItem->Expand(FALSE);
  370. UpdateResize();
  371. Invalidate();
  372. UpdateWindow();
  373. CheckVisibleFocus();
  374. break;
  375. }
  376. }
  377. }
  378. else
  379. break;
  380. // pass thru to next case VK_UP
  381. case VK_UP:
  382. if (m_pProp->FocusPrev())
  383. Invalidate();
  384. break;
  385. case VK_RIGHT:
  386. if ((pItem = m_pProp->GetFocusedItem())!=NULL)
  387. {
  388. if (!m_pProp->SendNotify(PTN_ITEMEXPANDING, pItem))
  389. {
  390. if (pItem->GetChild() && !pItem->IsExpanded())
  391. {
  392. pItem->Expand();
  393. UpdateResize();
  394. Invalidate();
  395. UpdateWindow();
  396. CheckVisibleFocus();
  397. break;
  398. }
  399. }
  400. }
  401. else
  402. break;
  403. // pass thru to next case VK_DOWN
  404. case VK_DOWN:
  405. if (m_pProp->FocusNext())
  406. Invalidate();
  407. break;
  408. }
  409. }
  410. UINT CEGPropertyGridList::OnGetDlgCode() 
  411. {
  412. return DLGC_WANTARROWS|DLGC_WANTCHARS|DLGC_WANTALLKEYS;
  413. }
  414. void CEGPropertyGridList::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*) 
  415. {
  416. SCROLLINFO si;
  417. CRect rc;
  418. LONG nHeight;
  419. SetFocus();
  420. GetClientRect(rc);
  421. nHeight = rc.Height() + 1;
  422. ZeroMemory(&si, sizeof(SCROLLINFO));
  423. si.cbSize = sizeof(SCROLLINFO);
  424. si.fMask = SIF_RANGE;
  425. GetScrollInfo(SB_VERT, &si);
  426. LONG ny = m_pProp->GetOrigin().y;
  427. switch (nSBCode)
  428. {
  429. case SB_LINEDOWN:
  430. ny += PROPTREEITEM_DEFHEIGHT;
  431. break;
  432. case SB_LINEUP:
  433. ny -= PROPTREEITEM_DEFHEIGHT;
  434. break;
  435. case SB_PAGEDOWN:
  436. ny += nHeight;
  437. break;
  438. case SB_PAGEUP:
  439. ny -= nHeight;
  440. break;
  441. case SB_THUMBTRACK:
  442. ny = nPos;
  443. break;
  444. }
  445. ny = __min(__max(ny, si.nMin), si.nMax - nHeight);
  446. m_pProp->SetOriginOffset(ny);
  447. si.fMask = SIF_POS;
  448. si.nPos = ny;
  449. SetScrollInfo(SB_VERT, &si, TRUE);
  450. Invalidate();
  451. }
  452. void CEGPropertyGridList::CheckVisibleFocus()
  453. {
  454. ASSERT(m_pProp!=NULL);
  455. CEGPropertyGridItem* pItem;
  456. if ((pItem = m_pProp->GetFocusedItem())==NULL)
  457. return;
  458. if (!m_pProp->IsItemVisible(pItem))
  459. {
  460. if (m_pProp->IsSingleSelection())
  461. pItem->Select(FALSE);
  462. m_pProp->SetFocusedItem(NULL);
  463. m_pProp->SendNotify(PTN_SELCHANGE, NULL);
  464. Invalidate();
  465. }
  466. }