PropertyGrid.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. #include "stdafx.h"
  2. #include "PropertyGrid_Defines.h"
  3. #include "PropertyGrid_Resource.h"
  4. #include "PropertyGridInplaceEdit.h"
  5. #include "PropertyGridInplaceButton.h"
  6. #include "PropertyGridInplaceList.h"
  7. #include "PropertyGridItem.h"
  8. #include "PropertyGrid.h"
  9. #include "PropertyGrid_DrawHelpers.h"
  10. const UINT SPLITTER_HEIGHT = 3;
  11. const UINT HIT_SPLITTER = 1;
  12. const UINT TOOLBAR_HEIGHT = 25;
  13. /////////////////////////////////////////////////////////////////////////////
  14. // CPropertyGrid
  15. CPropertyGrid::CPropertyGrid()
  16. : m_bHelpVisible(TRUE)
  17. , m_bToolBarVisible(FALSE)
  18. , m_nHelpHeight(58)
  19. {
  20. }
  21. CPropertyGrid::~CPropertyGrid()
  22. {
  23. }
  24. IMPLEMENT_DYNAMIC(CPropertyGrid, CWnd)
  25. BEGIN_MESSAGE_MAP(CPropertyGrid, CWnd)
  26. //{{AFX_MSG_MAP(CPropertyGrid)
  27. ON_WM_ERASEBKGND()
  28. ON_WM_PAINT()
  29. ON_WM_SETFOCUS()
  30. ON_WM_SIZE()
  31. ON_WM_SETCURSOR()
  32. ON_WM_LBUTTONDOWN()
  33. ON_COMMAND(PG_IDC_SORT_ALPHABETIC, OnSortAlphabetic)
  34. ON_COMMAND(PG_IDC_SORT_CATEGORIZED, OnSortCategorized)
  35. ON_NOTIFY_EX( TTN_NEEDTEXT, 0, OnToolTipNotify )
  36. ON_WM_CONTEXTMENU()
  37. //}}AFX_MSG_MAP
  38. END_MESSAGE_MAP()
  39. BOOL CPropertyGrid::Create(const RECT& rect, CWnd* pParentWnd, UINT nID)
  40. {
  41. LPCTSTR pszCreateClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW, ::LoadCursor(NULL, IDC_ARROW));
  42. CPGEmptyRect rc;
  43. if (!CreateEx(0, pszCreateClass, _T(""), WS_TABSTOP|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_CHILD|WS_GROUP, rc, pParentWnd, nID))
  44. return FALSE;
  45. if (!m_wndView.CreateEx(WS_EX_STATICEDGE, _T("LISTBOX"), NULL, WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_CHILD|WS_VISIBLE|LBS_NOTIFY|LBS_OWNERDRAWFIXED| LBS_NOINTEGRALHEIGHT| WS_VSCROLL|WS_TABSTOP, rc, this, 0))
  46. return FALSE;
  47. m_wndView.ResetContent();
  48. SetWindowPos(0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_SHOWWINDOW | SWP_NOZORDER);
  49. SetStandardColors();
  50. return TRUE;
  51. }
  52. /////////////////////////////////////////////////////////////////////////////
  53. // CPropertyGrid message handlers
  54. BOOL CPropertyGrid::OnEraseBkgnd(CDC*)
  55. {
  56. return TRUE;
  57. }
  58. void CPropertyGrid::OnPaint()
  59. {
  60. CPaintDC dcPaint(this);
  61. CPGClientRect rc(this);
  62. CPGBufferDC dc(dcPaint, rc);
  63. dc.FillSolidRect(rc, GetSysColor(COLOR_3DFACE));
  64. if (m_bHelpVisible)
  65. {
  66. CPGPenDC pen(dc, GetSysColor(COLOR_3DSHADOW));
  67. CPGBrushDC brush(dc, m_clrHelpBack);
  68. CRect rcHelp(rc);
  69. rcHelp.top = rc.bottom - m_nHelpHeight;
  70. dc.Rectangle(rcHelp);
  71. CPGFontDC font(&dc, &m_wndView.m_fontBold);
  72. CPropertyGridItem* pItem = m_wndView.GetSelectedItem();
  73. if (pItem)
  74. {
  75. dc.SetTextColor(m_clrHelpFore);
  76. dc.SetBkColor(m_clrHelpBack);
  77. CRect rcCaption(rcHelp);
  78. rcCaption.DeflateRect(6, 3);
  79. dc.DrawText(pItem->GetCaption(), rcCaption, DT_SINGLELINE);
  80. CString strDesc = pItem->GetDescription();
  81. if (!strDesc.IsEmpty())
  82. {
  83. CPGFontDC font(&dc, &m_wndView.m_fontNormal);
  84. CPGEmptyRect rcCaption;
  85. dc.DrawText(pItem->GetCaption(), rcCaption, DT_SINGLELINE|DT_CALCRECT);
  86. CRect rcDesc(rcHelp);
  87. rcDesc.DeflateRect(6, 3 + rcCaption.Height() + 3, 6, 3);
  88. dc.DrawText(strDesc, rcDesc, DT_WORDBREAK);
  89. }
  90. }
  91. }
  92. }
  93. void CPropertyGrid::OnSetFocus(CWnd*)
  94. {
  95. m_wndView.SetFocus();
  96. }
  97. void CPropertyGrid::OnSize(UINT nType, int cx, int cy)
  98. {
  99. CWnd::OnSize(nType, cx, cy);
  100. if (!m_wndView.GetSafeHwnd())
  101. return;
  102. Reposition(cx, cy);
  103. }
  104. int CPropertyGrid::HitTest(CPoint pt)
  105. {
  106. if (!m_bHelpVisible)
  107. return -1;
  108. CPGClientRect rc(this);
  109. CRect rcSplitter(CPoint(rc.left, rc.bottom - SPLITTER_HEIGHT - m_nHelpHeight), CSize(rc.Width(), SPLITTER_HEIGHT));
  110. if (rcSplitter.PtInRect(pt))
  111. return HIT_SPLITTER;
  112. return -1;
  113. }
  114. BOOL CPropertyGrid::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  115. {
  116. if (nHitTest == HTCLIENT)
  117. {
  118. CPoint point;
  119. GetCursorPos(&point);
  120. ScreenToClient(&point);
  121. if (HitTest(point) == HIT_SPLITTER)
  122. {
  123. static HCURSOR hcurVSplitBar = ::LoadCursor( AfxGetInstanceHandle(), MAKEINTRESOURCE(PG_IDC_VSPLITBAR) );
  124. ASSERT(hcurVSplitBar);
  125. SetCursor(hcurVSplitBar);
  126. return TRUE;
  127. }
  128. }
  129. return CWnd::OnSetCursor(pWnd, nHitTest, message);
  130. }
  131. void CPropertyGrid::OnInvertTracker(CRect rect)
  132. {
  133. ASSERT_VALID(this);
  134. ASSERT(!rect.IsRectEmpty());
  135. ASSERT((GetStyle() & WS_CLIPCHILDREN) == 0);
  136. // pat-blt without clip children on
  137. CDC* pDC = GetDC();
  138. CBrush brush(GetSysColor(COLOR_3DFACE));
  139. CBrush* pBrush = (CBrush*)pDC->SelectObject(&brush);
  140. pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATINVERT);
  141. pDC->SelectObject(pBrush);
  142. ReleaseDC(pDC);
  143. }
  144. void CPropertyGrid::OnSelectionChanged(CPropertyGridItem* pItem)
  145. {
  146. CPGClientRect rc(this);
  147. CRect rcHelp(rc);
  148. rcHelp.top = rc.bottom - m_nHelpHeight;
  149. InvalidateRect(rcHelp, FALSE);
  150. if (pItem)
  151. {
  152. // 发送属性项选中的通知消息
  153. int nID = GetDlgCtrlID();
  154. WPARAM wParam = MAKEWPARAM(nID, PGN_SELECTION_CHANGED);
  155. GetOwner()->SendMessage(PGWM_PROPERTYGRID_NOTIFY, wParam, (LPARAM)pItem);
  156. }
  157. }
  158. void CPropertyGrid::OnLButtonDown(UINT nFlags, CPoint point)
  159. {
  160. if (HitTest(point) == HIT_SPLITTER)
  161. {
  162. SetCapture();
  163. CPGClientRect rc(this);
  164. ModifyStyle(WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 0, FALSE);
  165. m_rectTracker.SetRect(0, point.y, rc.Width(), point.y + 3);
  166. OnInvertTracker(m_rectTracker);
  167. BOOL bAccept = FALSE;
  168. while (GetCapture() == this)
  169. {
  170. MSG msg;
  171. if (!GetMessage(&msg, NULL, 0, 0))
  172. break;
  173. if (msg.message == WM_MOUSEMOVE)
  174. {
  175. point = CPoint(msg.lParam);
  176. point.y = __min(point.y, rc.Height() - 20);
  177. point.y = __max(point.y, 20 + TOOLBAR_HEIGHT);
  178. if (m_rectTracker.top != point.y)
  179. {
  180. OnInvertTracker(m_rectTracker);
  181. m_rectTracker.OffsetRect(0, point.y - m_rectTracker.top);
  182. OnInvertTracker(m_rectTracker);
  183. }
  184. }
  185. else if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) break;
  186. else if (msg.message ==WM_LBUTTONUP)
  187. {
  188. bAccept = TRUE;
  189. break;
  190. }
  191. else ::DispatchMessage(&msg);
  192. }
  193. ReleaseCapture();
  194. if (bAccept)
  195. {
  196. m_nHelpHeight = rc.bottom - m_rectTracker.top -2;
  197. Reposition(rc.Width(), rc.Height());
  198. }
  199. Invalidate(FALSE);
  200. ModifyStyle(0, WS_CLIPCHILDREN|WS_CLIPSIBLINGS, FALSE);
  201. return;
  202. }
  203. CWnd::OnLButtonDown(nFlags, point);
  204. }
  205. void CPropertyGrid::Reposition(int cx, int cy)
  206. {
  207. CRect rcView(0, 0, cx, cy);
  208. if (m_bHelpVisible)
  209. {
  210. rcView.bottom -= m_nHelpHeight + SPLITTER_HEIGHT;
  211. }
  212. if (m_bToolBarVisible)
  213. {
  214. ASSERT(m_wndToolbar.GetSafeHwnd());
  215. CRect rcToolBar(1, 1, cx - 1, TOOLBAR_HEIGHT - 1);
  216. m_wndToolbar.MoveWindow(rcToolBar);
  217. rcView.top += TOOLBAR_HEIGHT;
  218. }
  219. m_wndView.MoveWindow(rcView);
  220. }
  221. void CPropertyGrid::CreateToolbar()
  222. {
  223. m_wndToolbar.CreateEx(this, TBSTYLE_FLAT, WS_BORDER|WS_CHILD|WS_VISIBLE|CBRS_ALIGN_TOP|CBRS_TOOLTIPS);
  224. m_wndToolbar.LoadToolBar(PG_IDR_PROPGRID_TBAR);
  225. }
  226. void CPropertyGrid::ShowToolBar(BOOL bShow)
  227. {
  228. if (bShow && !m_wndToolbar.GetSafeHwnd()) CreateToolbar();
  229. else
  230. {
  231. if (m_wndToolbar.GetSafeHwnd())
  232. m_wndToolbar.ShowWindow(bShow? SW_SHOW: SW_HIDE);
  233. }
  234. m_bToolBarVisible = bShow;
  235. CPGClientRect rc(this);
  236. Reposition(rc.Width(), rc.Height());
  237. RefreshToolBarButtons();
  238. }
  239. void CPropertyGrid::RefreshToolBarButtons()
  240. {
  241. if (m_bToolBarVisible)
  242. {
  243. m_wndToolbar.GetToolBarCtrl().SetState(PG_IDC_SORT_CATEGORIZED, TBSTATE_ENABLED | (m_wndView.m_properetySort == pgsortCategorized? TBSTATE_CHECKED: 0));
  244. m_wndToolbar.GetToolBarCtrl().SetState(PG_IDC_SORT_ALPHABETIC, TBSTATE_ENABLED | (m_wndView.m_properetySort == pgsortAlphabetical? TBSTATE_CHECKED: 0));
  245. }
  246. }
  247. void CPropertyGrid::ShowHelp(BOOL bShow)
  248. {
  249. m_bHelpVisible = bShow;
  250. CPGClientRect rc(this);
  251. Reposition(rc.Width(), rc.Height());
  252. }
  253. void CPropertyGrid::OnSortAlphabetic()
  254. {
  255. SetPropertySort(pgsortAlphabetical);
  256. }
  257. void CPropertyGrid::OnSortCategorized()
  258. {
  259. SetPropertySort(pgsortCategorized);
  260. }
  261. void CPropertyGrid::OnSortChanged()
  262. {
  263. RefreshToolBarButtons();
  264. OnSelectionChanged(NULL);
  265. // 发送属性项排序改变的通知消息
  266. int nID = GetDlgCtrlID();
  267. WPARAM wParam = MAKEWPARAM(nID, PGN_SORTORDER_CHANGED);
  268. GetOwner()->SendMessage(PGWM_PROPERTYGRID_NOTIFY, wParam, (LPARAM)0);
  269. }
  270. void CPropertyGrid::SetStandardColors()
  271. {
  272. m_clrHelpBack = ::GetSysColor( COLOR_3DFACE );
  273. m_clrHelpFore = ::GetSysColor( COLOR_BTNTEXT );
  274. m_wndView.m_clrLine = ::GetSysColor( COLOR_SCROLLBAR );
  275. m_wndView.m_clrBack = ::GetSysColor( COLOR_WINDOW );
  276. m_wndView.m_clrFore = ::GetSysColor( COLOR_WINDOWTEXT );
  277. RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW| RDW_INVALIDATE | RDW_ERASE);
  278. }
  279. void CPropertyGrid::SetCustomColors(
  280. COLORREF clrHelpBack, COLORREF clrHelpFore, COLORREF clrViewLine,
  281. COLORREF clrViewBack, COLORREF clrViewFore )
  282. {
  283. m_clrHelpBack = clrHelpBack;
  284. m_clrHelpFore = clrHelpFore;
  285. m_wndView.m_clrLine = clrViewLine;
  286. m_wndView.m_clrBack = clrViewBack;
  287. m_wndView.m_clrFore = clrViewFore;
  288. RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW| RDW_INVALIDATE | RDW_ERASE);
  289. }
  290. void CPropertyGrid::ResetContent()
  291. {
  292. m_wndView.ResetContent();
  293. m_wndView.m_pSelected = NULL;
  294. while ( !m_wndView.m_lstCategories.IsEmpty( ) )
  295. {
  296. CPropertyGridItem* pGridItem =
  297. m_wndView.m_lstCategories.RemoveTail( );
  298. if(pGridItem) { delete pGridItem; pGridItem = NULL; }
  299. }
  300. CPGClientRect rc(this);
  301. CRect rcHelp(rc);
  302. rcHelp.top = rc.bottom - m_nHelpHeight;
  303. InvalidateRect(rcHelp, FALSE);
  304. }
  305. void CPropertyGrid::ExpandAllCategories()
  306. {
  307. CPGListItems* pList = &GetGridView().m_lstCategories;
  308. POSITION pos = pList->GetHeadPosition();
  309. while (pos)
  310. {
  311. CPropertyGridItem* pCategory = pList->GetNext(pos);
  312. pCategory->Expand();
  313. }
  314. }
  315. void CPropertyGrid::CollapseAllCategories()
  316. {
  317. CPGListItems* pList = &GetGridView().m_lstCategories;
  318. POSITION pos = pList->GetHeadPosition();
  319. while (pos)
  320. {
  321. CPropertyGridItem* pCategory = pList->GetNext(pos);
  322. pCategory->Collapse();
  323. }
  324. }
  325. BOOL CPropertyGrid::OnToolTipNotify( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
  326. {
  327. TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
  328. UINT nID = (UINT)pNMHDR->idFrom;
  329. if (pTTT->uFlags & TTF_IDISHWND)
  330. return FALSE;
  331. // nID是工具栏按钮的ID值
  332. pTTT->lpszText = MAKEINTRESOURCE(nID);
  333. pTTT->hinst = AfxGetInstanceHandle();
  334. return TRUE;
  335. }
  336. void CPropertyGrid::OnContextMenu(CWnd* pWnd, CPoint point)
  337. {
  338. CMenu menu;
  339. menu.CreatePopupMenu();
  340. menu.AppendMenu( MF_STRING, 101, _T("关于属性表") );
  341. int result = menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON, point.x, point.y, this);
  342. if (result == 101)
  343. MessageBox( _T("原著: Codejock 2003\n扩展&除错: 祝晓鹰 2009\n版本: 1.03"), _T("关于属性表"), MB_ICONINFORMATION | MB_OK);
  344. }