PropertyGridView.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. #include "stdafx.h"
  2. #include "PropertyGrid_Resource.h"
  3. #include "PropertyGridInplaceEdit.h"
  4. #include "PropertyGridInplaceButton.h"
  5. #include "PropertyGridInplaceList.h"
  6. #include "PropertyGrid_DrawHelpers.h"
  7. #include "PropertyGridItem.h"
  8. #include "PropertyGrid.h"
  9. const UINT PGV_HIT_SPLITTER = 0x100;
  10. /////////////////////////////////////////////////////////////////////////////
  11. // CPropertyGridView
  12. CPropertyGridView::CPropertyGridView()
  13. {
  14. m_properetySort = pgsortCategorized;
  15. m_dDivider = .5;
  16. m_bTracking = FALSE;
  17. LOGFONT lfIcon;
  18. VERIFY( ::SystemParametersInfo( SPI_GETICONTITLELOGFONT, sizeof( lfIcon ), &lfIcon, 0 ) );
  19. lfIcon.lfWeight = FW_NORMAL;
  20. lfIcon.lfItalic = FALSE;
  21. VERIFY( m_fontNormal.CreateFontIndirect(&lfIcon ) );
  22. lfIcon.lfWeight = FW_BOLD;
  23. VERIFY( m_fontBold.CreateFontIndirect(&lfIcon ) );
  24. m_pSelected = NULL;
  25. }
  26. CPropertyGridView::~CPropertyGridView()
  27. {
  28. while (!m_lstCategories.IsEmpty())
  29. {
  30. delete m_lstCategories.RemoveTail();
  31. }
  32. }
  33. IMPLEMENT_DYNAMIC(CPropertyGridView, CListBox)
  34. BEGIN_MESSAGE_MAP(CPropertyGridView, CListBox)
  35. //{{AFX_MSG_MAP(CPropertyGridView)
  36. ON_WM_ERASEBKGND()
  37. ON_WM_PAINT()
  38. ON_WM_NCPAINT()
  39. ON_WM_LBUTTONDOWN()
  40. ON_WM_LBUTTONDBLCLK()
  41. ON_CONTROL_REFLECT(LBN_SELCHANGE, OnSelectionChanged)
  42. ON_WM_SETCURSOR()
  43. ON_WM_LBUTTONUP()
  44. ON_WM_CAPTURECHANGED()
  45. ON_WM_MOUSEMOVE()
  46. ON_WM_SIZE()
  47. ON_WM_VSCROLL()
  48. ON_WM_MOUSEWHEEL()
  49. //}}AFX_MSG_MAP
  50. END_MESSAGE_MAP()
  51. /////////////////////////////////////////////////////////////////////////////
  52. // CPropertyGridView message handlers
  53. void CPropertyGridView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
  54. {
  55. if (GetScrollBarCtrl(SB_VERT) == pScrollBar)
  56. {
  57. CListBox::OnVScroll(nSBCode, nPos, pScrollBar);
  58. Invalidate(FALSE);
  59. CWnd* pWnd = GetWindow(GW_CHILD);
  60. while (pWnd)
  61. {
  62. if (pWnd->IsWindowVisible())
  63. pWnd->Invalidate(FALSE);
  64. pWnd = pWnd->GetWindow(GW_HWNDNEXT);
  65. }
  66. }
  67. else
  68. {
  69. CListBox::OnVScroll(nSBCode, nPos, pScrollBar);
  70. }
  71. }
  72. BOOL CPropertyGridView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
  73. {
  74. BOOL bResult = CWnd::OnMouseWheel(nFlags, zDelta, pt);
  75. Invalidate(FALSE);
  76. CWnd* pWnd = GetWindow(GW_CHILD);
  77. while (pWnd)
  78. {
  79. if (pWnd->IsWindowVisible())
  80. pWnd->Invalidate(FALSE);
  81. pWnd = pWnd->GetWindow(GW_HWNDNEXT);
  82. }
  83. return bResult;
  84. }
  85. void CPropertyGridView::PreSubclassWindow()
  86. {
  87. CListBox::PreSubclassWindow();
  88. ASSERT((GetStyle() & (LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT)) == (LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT));
  89. ASSERT((GetStyle() & WS_BORDER) == 0);
  90. ASSERT((GetExStyle() & WS_EX_STATICEDGE) == WS_EX_STATICEDGE);
  91. }
  92. void CPropertyGridView::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  93. {
  94. ASSERT(lpDrawItemStruct->CtlType == ODT_LISTBOX);
  95. CPropertyGridItem* pItem = (CPropertyGridItem*)lpDrawItemStruct->itemData;
  96. COLORREF clrWindow = m_clrBack;
  97. if (pItem == NULL)
  98. return;
  99. CPGWindowRect rcWindow(this);
  100. CRect rc = lpDrawItemStruct->rcItem;
  101. CPGBufferDC dc(lpDrawItemStruct->hDC, rc);
  102. CPGFontDC font(&dc, &m_fontNormal);
  103. dc.FillSolidRect(rc, clrWindow);
  104. dc.SetBkMode(TRANSPARENT);
  105. CRect rcCaption(rc.left, rc.top, rc.left + int(m_dDivider * rcWindow.Width()), rc.bottom);
  106. if (pItem->IsCategory())
  107. {
  108. dc.FillSolidRect(rc, m_clrLine);
  109. CPGFontDC font(&dc, &m_fontBold);
  110. dc.SetTextColor(::GetSysColor(COLOR_GRAYTEXT));
  111. CPGEmptyRect rcDrawText;
  112. dc.DrawText( pItem->GetCaption(), rcDrawText, DT_SINGLELINE|DT_VCENTER|DT_CALCRECT);
  113. CRect rcText(CPoint(PGI_EXPAND_BORDER - 1, rc.top + 1) , CSize(rcDrawText.Width() + 4, rc.Height() - 2));
  114. dc.DrawText( pItem->GetCaption(), rcText, DT_SINGLELINE|DT_VCENTER|DT_RIGHT);
  115. if ((lpDrawItemStruct->itemAction | ODA_FOCUS) && (lpDrawItemStruct->itemState & ODS_FOCUS))
  116. {
  117. dc.SetTextColor(0);
  118. dc.DrawFocusRect(rcText);
  119. }
  120. }
  121. else
  122. {
  123. dc.SetTextColor(pItem->m_bReadOnly? GetSysColor(COLOR_GRAYTEXT): m_clrFore);
  124. CRect rcValue(rc);
  125. rcValue.left = rcCaption.right + 4;
  126. rcValue.bottom -= 1;
  127. if (!pItem->OnDrawItemValue(dc, rcValue))
  128. {
  129. dc.DrawText( pItem->m_strValue, rcValue, DT_SINGLELINE|DT_VCENTER);
  130. }
  131. BOOL bSelected = ((lpDrawItemStruct->itemAction | ODA_SELECT) && (lpDrawItemStruct->itemState & ODS_SELECTED));
  132. BOOL bFocused = bSelected && GetFocus() && ((GetFocus() == this) || (GetFocus()->GetParent() == this) || (GetFocus()->GetOwner() == this));
  133. if (bFocused)
  134. {
  135. dc.SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
  136. dc.FillSolidRect(rcCaption, ::GetSysColor(COLOR_HIGHLIGHT));
  137. }
  138. else if (bSelected)
  139. {
  140. dc.FillSolidRect(rcCaption, m_clrLine);
  141. }
  142. dc.FillSolidRect(rc.left, rc.top, PGI_EXPAND_BORDER, rc.Height(), m_clrLine);
  143. CPGPenDC pen(dc, m_clrLine);
  144. dc.MoveTo(0, rc.bottom - 1); dc.LineTo(rc.right, rc.bottom - 1);
  145. dc.MoveTo(rcCaption.right, rc.top); dc.LineTo(rcCaption.right, rc.bottom - 1);
  146. CRect rcText(rc);
  147. rcText.left = pItem->m_nIndent * PGI_EXPAND_BORDER + 3;
  148. rcText.right = rcCaption.right - 1;
  149. rcText.bottom -= 1;
  150. dc.DrawText( pItem->GetCaption(), rcText, DT_SINGLELINE|DT_VCENTER);
  151. }
  152. if (pItem->HasChilds())
  153. {
  154. CRgn rgn;
  155. rgn.CreateRectRgnIndirect(&rcCaption);
  156. dc.SelectClipRgn(&rgn);
  157. CRect rcSign(CPoint(PGI_EXPAND_BORDER / 2 - 5, rc.CenterPoint().y - 4), CSize(9, 9));
  158. if (pItem->m_nIndent > 1)
  159. rcSign.OffsetRect((pItem->m_nIndent - 1) * PGI_EXPAND_BORDER, 0);
  160. CPoint pt = rcSign.CenterPoint();
  161. CPGBrushDC brush (dc, pItem->IsCategory()? m_clrLine: clrWindow);
  162. CPGPenDC pen (dc, m_clrFore);
  163. dc.Rectangle(rcSign);
  164. dc.MoveTo(pt.x - 2, pt.y);
  165. dc.LineTo(pt.x + 3, pt.y);
  166. if(!pItem->m_bExpanded)
  167. {
  168. dc.MoveTo(pt.x, pt.y - 2);
  169. dc.LineTo(pt.x, pt.y + 3);
  170. }
  171. dc.SelectClipRgn(NULL);
  172. }
  173. }
  174. BOOL CPropertyGridView::OnEraseBkgnd(CDC*)
  175. {
  176. return TRUE;
  177. }
  178. void CPropertyGridView::OnPaint()
  179. {
  180. CPaintDC dc(this);
  181. CPGClientRect rc(this);
  182. CPGBufferDC buffer(dc, rc);
  183. buffer.FillSolidRect(rc, m_clrBack);
  184. CWnd::DefWindowProc(WM_PAINT, (WPARAM)buffer.m_hDC, 0);
  185. }
  186. void CPropertyGridView::OnNcPaint()
  187. {
  188. CWindowDC dc(this);
  189. CPGWindowRect rc(this);
  190. rc.OffsetRect(-rc.TopLeft());
  191. // 当窗口大小发生改变,使得列表项消失时,下面这段代码会产生异常。
  192. // 由于这段代码看上去无关紧要,因此予以注释。
  193. // #ifdef _DEBUG
  194. // CPGClientRect rcClient(this);
  195. // ASSERT(rcClient.Height() == rc.Height() - 2);
  196. // #endif
  197. CWnd::DefWindowProc(WM_PRINT, (WPARAM)dc.m_hDC, PRF_NONCLIENT);
  198. dc.Draw3dRect(rc, GetSysColor(COLOR_3DSHADOW), GetSysColor(COLOR_3DSHADOW) );
  199. }
  200. CPropertyGridItem* CPropertyGridView::AddCategory(CString strCaption)
  201. {
  202. CPropertyGridItem* pCategory = new CPropertyGridItem(strCaption);
  203. pCategory->m_pGrid = this;
  204. pCategory->m_bCategory = TRUE;
  205. pCategory->m_nFlags = 0;
  206. m_lstCategories.AddTail(pCategory);
  207. SetPropertySort(m_properetySort, TRUE);
  208. return pCategory;
  209. }
  210. void CPropertyGridView::ResetContent()
  211. {
  212. // 在删除属性项对象之前,强制触发内置编辑框的EN_KILLFOCUS消息
  213. if (m_pSelected)
  214. {
  215. m_pSelected->OnDeselect();
  216. m_pSelected = NULL;
  217. }
  218. for (int i = 0; i < GetCount(); i++)
  219. {
  220. CPropertyGridItem* pItem = (CPropertyGridItem*)GetItemDataPtr(i);
  221. ASSERT(pItem);
  222. ASSERT(pItem->m_nIndex == i);
  223. pItem->m_bVisible = FALSE;
  224. }
  225. CListBox::ResetContent();
  226. SetFont(&m_fontNormal, FALSE);
  227. CWindowDC dc(this);
  228. CPGFontDC font(&dc, &m_fontNormal);
  229. SetItemHeight(0, dc.GetTextExtent(_T(" ")).cy + 3);
  230. }
  231. void CPropertyGridView::SetPropertySort(PG_PROPERTYSORT sort, BOOL bRrefresh)
  232. {
  233. if (sort == m_properetySort && !bRrefresh)
  234. return;
  235. SetRedraw(FALSE); // 禁止窗口重画
  236. CPropertyGridItem* pSelected = GetSelectedItem();
  237. ResetContent();
  238. if (sort == pgsortCategorized)
  239. {
  240. POSITION pos = m_lstCategories.GetHeadPosition();
  241. while (pos)
  242. {
  243. CPropertyGridItem* pCategory = m_lstCategories.GetNext(pos);
  244. InsertItem(pCategory, GetCount());
  245. }
  246. }
  247. else if (sort == pgsortAlphabetical || sort == pgsortNoSort)
  248. {
  249. CPGListItems lstItems;
  250. POSITION pos = m_lstCategories.GetHeadPosition();
  251. while (pos)
  252. {
  253. CPropertyGridItem* pCategory = m_lstCategories.GetNext(pos);
  254. lstItems.AddTail(&pCategory->m_lstChilds);
  255. }
  256. if (sort != pgsortNoSort)
  257. lstItems.Sort();
  258. pos = lstItems.GetHeadPosition();
  259. while (pos)
  260. {
  261. CPropertyGridItem* pItem = lstItems.GetNext(pos);
  262. InsertItem(pItem, GetCount());
  263. }
  264. }
  265. else
  266. {
  267. ASSERT(FALSE);
  268. }
  269. _RefreshIndexes();
  270. if (pSelected)
  271. {
  272. pSelected->Select();
  273. }
  274. SetRedraw(TRUE); // 允许窗口重画
  275. // 下面这行代码会导致第31号Bug,需要去掉
  276. // OnSelectionChanged();
  277. if (sort != m_properetySort)
  278. {
  279. m_properetySort = sort;
  280. ((CPropertyGrid*)GetParent())->OnSortChanged();
  281. }
  282. }
  283. int CPropertyGridView::GetDividerPos()
  284. {
  285. CPGWindowRect rcWindow(this);
  286. return int(m_dDivider * rcWindow.Width());
  287. }
  288. int CPropertyGridView::InsertItem(CPropertyGridItem* pItem, int nIndex)
  289. {
  290. nIndex = InsertString(nIndex, _T(""));
  291. ASSERT(nIndex != -1);
  292. SetItemDataPtr(nIndex, pItem);
  293. pItem->m_bVisible = TRUE;
  294. int nItemsInserted = 1;
  295. if (pItem->m_bExpanded)
  296. {
  297. nItemsInserted += _DoExpand(pItem, nIndex);
  298. }
  299. return nItemsInserted;
  300. }
  301. int CPropertyGridView::_DoExpand(CPropertyGridItem* pItem, int nIndex)
  302. {
  303. int nStart = nIndex;
  304. POSITION pos = pItem->GetFirstChild();
  305. while(pos != NULL)
  306. {
  307. CPropertyGridItem* pChild = pItem->GetNextChild(pos);
  308. nIndex += InsertItem(pChild, nIndex + 1);
  309. }
  310. return nIndex - nStart;
  311. }
  312. void CPropertyGridView::_RefreshIndexes()
  313. {
  314. int i;
  315. for (i = 0; i < GetCount(); i++)
  316. {
  317. CPropertyGridItem* pItem = (CPropertyGridItem*)GetItemDataPtr(i);
  318. ASSERT(pItem);
  319. pItem->m_nIndex = i;
  320. }
  321. }
  322. void CPropertyGridView::_DoCollapse(CPropertyGridItem* pItem)
  323. {
  324. ASSERT(pItem);
  325. ASSERT(pItem->m_bExpanded);
  326. int nIndex = pItem->m_nIndex + 1;
  327. while(nIndex < GetCount())
  328. {
  329. CPropertyGridItem* pChild = (CPropertyGridItem*)GetItemDataPtr(nIndex);
  330. ASSERT(pChild);
  331. if (!pChild || !pChild->HasParent(pItem))
  332. break;
  333. pChild->m_bVisible = FALSE;
  334. DeleteString(nIndex);
  335. }
  336. _RefreshIndexes();
  337. }
  338. CPropertyGridItem* CPropertyGridView::GetItem(int nIndex)
  339. {
  340. if (nIndex < 0 || nIndex >= GetCount())
  341. return 0;
  342. CPropertyGridItem* pItem = (CPropertyGridItem*)GetItemDataPtr(nIndex);
  343. ASSERT(pItem);
  344. // 下面这行代码会导致第29号Bug,需要去掉
  345. // ASSERT(pItem->m_nIndex == nIndex);
  346. return pItem;
  347. }
  348. void CPropertyGridView::SwitchExpandState(int nItem)
  349. {
  350. CPropertyGridItem* pItem = GetItem(nItem);
  351. if (!pItem) return;
  352. if(pItem->m_bExpanded) pItem->Collapse(); else pItem->Expand();
  353. }
  354. void CPropertyGridView::OnLButtonDown(UINT nFlags, CPoint point)
  355. {
  356. if (HitTest(point) == PGV_HIT_SPLITTER)
  357. {
  358. SetFocus();
  359. SetCapture();
  360. if (m_pSelected) m_pSelected->OnValidateEdit();
  361. m_bTracking = TRUE;
  362. return;
  363. }
  364. CPropertyGridItem* pItem = ItemFromPoint(point);
  365. if (pItem && pItem->OnLButtonDown(nFlags, point))
  366. return;
  367. CListBox::OnLButtonDown(nFlags, point);
  368. }
  369. CPropertyGridItem* CPropertyGridView::ItemFromPoint(CPoint point)
  370. {
  371. BOOL bOutside = FALSE;
  372. int nIndex = CListBox::ItemFromPoint(point, bOutside);
  373. if (nIndex != -1 && !bOutside)
  374. {
  375. return GetItem(nIndex);
  376. }
  377. return NULL;
  378. }
  379. void CPropertyGridView::OnMouseMove(UINT nFlags, CPoint point)
  380. {
  381. if (m_bTracking)
  382. {
  383. CPGWindowRect rcWindow(this);
  384. m_dDivider = (double)point.x / rcWindow.Width();
  385. m_dDivider = __max(m_dDivider, .1);
  386. m_dDivider = __min(m_dDivider, .85);
  387. Invalidate(FALSE);
  388. }
  389. else
  390. {
  391. ShowToolTip(point);
  392. }
  393. CListBox::OnMouseMove(nFlags, point);
  394. }
  395. void CPropertyGridView::OnLButtonUp(UINT nFlags, CPoint point)
  396. {
  397. if (m_bTracking)
  398. {
  399. ReleaseCapture();
  400. m_bTracking = FALSE;
  401. }
  402. CListBox::OnLButtonUp(nFlags, point);
  403. }
  404. void CPropertyGridView::OnCaptureChanged(CWnd *pWnd)
  405. {
  406. m_bTracking = FALSE;
  407. CListBox::OnCaptureChanged(pWnd);
  408. }
  409. void CPropertyGridView::OnLButtonDblClk(UINT nFlags, CPoint point)
  410. {
  411. CListBox::OnLButtonDblClk(nFlags, point);
  412. CPropertyGridItem* pItem = ItemFromPoint(point);
  413. if (pItem)
  414. {
  415. pItem->OnLButtonDblClk();
  416. }
  417. }
  418. CPropertyGridItem* CPropertyGridView::GetSelectedItem()
  419. {
  420. return GetItem(GetCurSel());
  421. }
  422. BOOL CPropertyGridView::PreTranslateMessage(MSG* pMsg)
  423. {
  424. if (GetFocus() == this && (pMsg->message == WM_KEYDOWN))
  425. {
  426. if (pMsg->wParam == VK_RETURN )
  427. {
  428. SwitchExpandState(GetCurSel());
  429. return TRUE;
  430. }
  431. else if (pMsg->wParam == VK_RIGHT || pMsg->wParam == VK_ADD)
  432. {
  433. CPropertyGridItem* pItem = GetSelectedItem();
  434. if (pItem && pItem->HasChilds())
  435. {
  436. if (!pItem->m_bExpanded)
  437. {
  438. pItem->Expand();
  439. return TRUE;
  440. }
  441. if (pMsg->wParam == VK_ADD) return TRUE;
  442. }
  443. }
  444. else if (pMsg->wParam == VK_LEFT || pMsg->wParam == VK_SUBTRACT)
  445. {
  446. CPropertyGridItem* pItem = GetSelectedItem();
  447. if (pItem && pItem->HasChilds())
  448. {
  449. if (pItem->m_bExpanded)
  450. {
  451. pItem->Collapse();
  452. return TRUE;
  453. }
  454. if (pMsg->wParam == VK_SUBTRACT) return TRUE;
  455. }
  456. }
  457. }
  458. if (GetFocus() == this && ((pMsg->message == WM_CHAR) ||
  459. (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_TAB )))
  460. {
  461. CPropertyGridItem* pItem = GetSelectedItem();
  462. if (pItem)
  463. {
  464. if (pItem->OnChar((UINT)pMsg->wParam))
  465. return TRUE;
  466. }
  467. }
  468. if (m_wndTip.GetSafeHwnd() && m_wndTip.IsWindowVisible())
  469. {
  470. RelayToolTipEvent(pMsg);
  471. }
  472. return CListBox::PreTranslateMessage(pMsg);
  473. }
  474. void CPropertyGridView::OnSelectionChanged()
  475. {
  476. CPropertyGridItem* pItem = GetSelectedItem();
  477. if (m_pSelected) m_pSelected->OnDeselect();
  478. if (pItem) pItem->OnSelect();
  479. m_pSelected = pItem;
  480. ((CPropertyGrid*)GetParent())->OnSelectionChanged(m_pSelected);
  481. Invalidate(FALSE);
  482. }
  483. int CPropertyGridView::HitTest(CPoint point)
  484. {
  485. CPGWindowRect rcWindow(this);
  486. int nWidth = int(m_dDivider * rcWindow.Width());
  487. if (point.x > nWidth - 4 && point.x <= nWidth + 2 && GetCount() > 0)
  488. return PGV_HIT_SPLITTER;
  489. return -1;
  490. }
  491. BOOL CPropertyGridView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  492. {
  493. if (nHitTest == HTCLIENT)
  494. {
  495. CPoint point;
  496. GetCursorPos(&point);
  497. ScreenToClient(&point);
  498. if (HitTest(point) == PGV_HIT_SPLITTER)
  499. {
  500. static HCURSOR hcurHSplitBar = ::LoadCursor( AfxGetInstanceHandle(), MAKEINTRESOURCE(PG_IDC_HSPLITBAR) );
  501. ASSERT(hcurHSplitBar);
  502. SetCursor(hcurHSplitBar);
  503. return TRUE;
  504. }
  505. }
  506. return CListBox::OnSetCursor(pWnd, nHitTest, message);
  507. }
  508. void CPropertyGridView::OnSize(UINT nType, int cx, int cy)
  509. {
  510. CListBox::OnSize(nType, cx, cy);
  511. // OnSelectionChanged();
  512. // 原来的代码会导致第32号Bug,替换成下列代码
  513. CPropertyGridItem* pItem = GetSelectedItem();
  514. if (m_pSelected) m_pSelected->OnDeselect();
  515. if (pItem) pItem->OnSelect();
  516. m_pSelected = pItem;
  517. }
  518. // ToolTips routings
  519. void CPropertyGridView::_ShowToolTip(CRect rcBound, CRect rcText)
  520. {
  521. TOOLINFO ti = { sizeof (TOOLINFO), TTF_ABSOLUTE|TTF_TRACK|TTF_TRANSPARENT, m_hWnd, 1};
  522. ti.lpszText = (LPTSTR)(LPCTSTR)m_strTipText;
  523. m_wndTip.SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti);
  524. m_wndTip.SetToolInfo(&ti);
  525. m_wndTip.Activate(TRUE);
  526. m_wndTip.SendMessage(TTM_TRACKPOSITION, 0, MAKELONG(rcText.left, rcText.top));
  527. m_wndTip.SendMessage(TTM_TRACKACTIVATE,(WPARAM)TRUE,(LPARAM)&ti);
  528. m_rcToolTip = rcBound;
  529. TRACKMOUSEEVENT tme = {sizeof(TRACKMOUSEEVENT), TME_LEAVE, m_hWnd, 0};
  530. _TrackMouseEvent (&tme);
  531. }
  532. CSize CPropertyGridView::_GetTextExtent(CString str)
  533. {
  534. CWindowDC dc(this);
  535. CPGFontDC font(&dc, GetFont());
  536. return dc.GetTextExtent(str);
  537. }
  538. void CPropertyGridView::ShowToolTip(CPoint pt)
  539. {
  540. if (!m_wndTip.GetSafeHwnd())
  541. {
  542. m_wndTip.Create(this);
  543. m_wndTip.SetFont(GetFont(), FALSE);
  544. }
  545. CPropertyGridItem* pItem = ItemFromPoint(pt);
  546. if (!pItem || pItem->IsCategory())
  547. return;
  548. CPGWindowRect rcWindow(this);
  549. CRect rc = pItem->GetItemRect();
  550. CRect rcCaption(rc.left, rc.top, rc.left + int(m_dDivider * rcWindow.Width()), rc.bottom);
  551. if (rcCaption.PtInRect(pt))
  552. {
  553. // if (m_strTipText == pItem->GetCaption())
  554. // 原来的判断条件有问题,改进如下
  555. if (m_strTipText == pItem->GetCaption() && m_wndTip.IsWindowVisible())
  556. return;
  557. m_strTipText = pItem->GetCaption();
  558. ClientToScreen(&rcCaption);
  559. CRect rcCaptionText(rcCaption);
  560. rcCaptionText.left += pItem->m_nIndent * PGI_EXPAND_BORDER + 3 - 3;
  561. rcCaptionText.top--;
  562. if (_GetTextExtent(m_strTipText).cx + 3 > rcCaptionText.Width())
  563. {
  564. _ShowToolTip(rcCaption, rcCaptionText);
  565. }
  566. }
  567. else
  568. {
  569. // if (m_strTipText == pItem->GetValue())
  570. // 原来的判断条件有问题,改进如下
  571. if (m_strTipText == pItem->GetValue() && m_wndTip.IsWindowVisible())
  572. return;
  573. m_strTipText = pItem->GetValue();
  574. /* if (GetFocus() && GetFocus()->IsKindOf(RUNTIME_CLASS(CPropertyGridInplaceEdit)))
  575. {
  576. if (((CPropertyGridInplaceEdit*)(GetFocus()))->GetItem() == pItem)
  577. return;
  578. } */
  579. // 上述代码判断如果属性项正处于编辑状态,则不显示工具提示。
  580. // 由于自定义的扩展属性项使用了自定义内置编辑控件,上述代码
  581. // 不起作用,改进如下:
  582. CWnd* pWnd = GetFocus();
  583. if (pWnd && pWnd->IsKindOf(RUNTIME_CLASS(CEdit)) && IsChild(pWnd) && pItem == m_pSelected)
  584. return;
  585. CRect rcValue(rc.left + int(m_dDivider * rcWindow.Width()), rc.top, rc.right, rc.bottom);
  586. ClientToScreen(&rcValue);
  587. CRect rcValueText = pItem->GetValueRect();
  588. rcValueText.top -= 2;
  589. ClientToScreen(&rcValueText);
  590. if (_GetTextExtent(m_strTipText).cx + 3 > rcValueText.Width())
  591. {
  592. _ShowToolTip(rcValue, rcValueText);
  593. }
  594. }
  595. }
  596. void CPropertyGridView::RelayToolTipEvent(MSG* pMsg)
  597. {
  598. if (m_wndTip.GetSafeHwnd() && m_wndTip.IsWindowVisible())
  599. {
  600. CPoint pt;
  601. GetCursorPos(&pt);
  602. if (!m_rcToolTip.PtInRect(pt))
  603. {
  604. m_strTipText = _T("");
  605. m_wndTip.Activate(FALSE);
  606. }
  607. switch (pMsg->message)
  608. {
  609. case WM_MOUSEWHEEL:
  610. m_strTipText = _T("");
  611. case WM_KEYDOWN:
  612. case WM_SYSKEYDOWN:
  613. case WM_LBUTTONDOWN:
  614. case WM_RBUTTONDOWN:
  615. case WM_MBUTTONDOWN:
  616. case WM_LBUTTONUP:
  617. case WM_RBUTTONUP:
  618. case WM_MBUTTONUP:
  619. m_wndTip.Activate(FALSE);
  620. }
  621. }
  622. }