DrawerCtrl.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. #include "pch.h"
  2. #include "resource.h"
  3. #include "DrawerCtrl.h"
  4. #ifdef _DEBUG
  5. #define new DEBUG_NEW
  6. #undef THIS_FILE
  7. static char THIS_FILE[] = __FILE__;
  8. #endif
  9. IMPLEMENT_DYNCREATE(CDrawerCtrl, CWnd)
  10. CDrawerCtrl::CDrawerCtrl()
  11. {
  12. //背景色
  13. m_crBackground = RGB(255, 255, 255);
  14. //字体颜色
  15. m_crText = RGB(27, 79, 116);
  16. //字体
  17. m_pFont = NULL;
  18. //目录高度
  19. m_nFolderHeight = 20;
  20. //当前选中目录索引
  21. m_nCurSelFolder = 1;
  22. //最后高亮的目录索引
  23. iLastFolderHighlighted = -1;
  24. //当前鼠标滑过的目录
  25. iHoverFolder = -1;
  26. //hHandCursor = AfxGetApp()->LoadCursor(IDC_CURSOR_HAND);
  27. hHandCursor = AfxGetApp()->LoadCursor(1);
  28. iSelcon = NULL;
  29. }
  30. CDrawerCtrl::~CDrawerCtrl()
  31. {
  32. for (int t = 0; t < m_arFolder.GetSize(); t++)
  33. {
  34. if (m_arFolder.GetAt(t)) delete (CBm_arFolder*)m_arFolder.GetAt(t);
  35. }
  36. m_arFolder.RemoveAll();
  37. }
  38. BEGIN_MESSAGE_MAP(CDrawerCtrl, CWnd)
  39. //{{AFX_MSG_MAP(CDrawerCtrl)
  40. ON_WM_CREATE()
  41. ON_WM_PAINT()
  42. ON_WM_ERASEBKGND()
  43. ON_WM_LBUTTONDOWN()
  44. ON_WM_SETCURSOR()
  45. ON_WM_SIZE()
  46. //}}AFX_MSG_MAP
  47. ON_WM_MOUSEMOVE()
  48. ON_WM_TIMER()
  49. ON_WM_MOUSEWHEEL()
  50. END_MESSAGE_MAP()
  51. void CDrawerCtrl::SetFolderImage(LPCTSTR lpszPath)
  52. {
  53. ASSERT(lpszPath || PathFileExists(lpszPath));
  54. CEnBitmap bmpTemp;
  55. bmpTemp.LoadImage(lpszPath);
  56. bmpTemp.DrawImage(m_bmpNormalFolder, 1, 1, 1, 2);
  57. bmpTemp.DrawImage(m_bmpHoverFolder, 1, 2, 1, 2);
  58. bmpTemp.DeleteObject();
  59. };
  60. void CDrawerCtrl::SetSelIcon(LPCTSTR lpszIconPath)
  61. {
  62. iSelcon = (HICON)::LoadImage(AfxGetApp()->m_hInstance, lpszIconPath, IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
  63. }
  64. void CDrawerCtrl::SetFolderText(const int index, const char* text)
  65. {
  66. ASSERT(index >= 0 && index < GetFolderCount());
  67. CBm_arFolder* pbf = (CBm_arFolder*)m_arFolder.GetAt(index);
  68. if (pbf->cName)
  69. {
  70. delete[] pbf->cName;
  71. pbf->cName = NULL;
  72. }
  73. pbf->cName = new char[lstrlen(text) + 1];
  74. lstrcpy(pbf->cName, text);
  75. }
  76. BOOL CDrawerCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
  77. {
  78. return CWnd::CreateEx(0, NULL, NULL, dwStyle | WS_CHILD, rect, pParentWnd, nID);
  79. }
  80. int CDrawerCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
  81. {
  82. if (CWnd::OnCreate(lpCreateStruct) == -1)
  83. return -1;
  84. return 0;
  85. }
  86. void CDrawerCtrl::OnPaint()
  87. {
  88. CRect rc;
  89. GetClientRect(&rc);
  90. _dprintf(_T("CDrawerCtrl::OnPaint,%d,客户区域[%d,%d,%d,%d]"), m_arFolder.GetSize(), rc.left, rc.top, rc.right, rc.bottom);
  91. CDC memDC;
  92. CPaintDC dc(this);
  93. memDC.CreateCompatibleDC(&dc);
  94. CBitmap bmp;
  95. bmp.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height());
  96. CBitmap* oldbmp = memDC.SelectObject(&bmp);
  97. memDC.FillSolidRect(rc, m_crBackground);
  98. int nFolders = m_arFolder.GetSize();
  99. for (int i = 0;i < nFolders;i++)
  100. {
  101. CRect rcFolder;
  102. GetFolderRect(i, rcFolder);
  103. _dprintf(_T("\t\tCDrawerCtrl::OnPaint,folder=%d【%d,%d,%d,%d】"),i, rcFolder.left, rcFolder.top, rcFolder.right, rcFolder.bottom);
  104. DrawFolder(&memDC, i, &rcFolder);
  105. }
  106. dc.BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY);//Copy
  107. memDC.DeleteDC();
  108. }
  109. BOOL CDrawerCtrl::OnEraseBkgnd(CDC* pDC)
  110. {
  111. return true;
  112. }
  113. bool CDrawerCtrl::GetFolderRect(const int iIndex, CRect& rect) const
  114. {
  115. int max = m_arFolder.GetSize();
  116. if (iIndex < 0 || iIndex >= max)
  117. return false;
  118. CRect rc;
  119. GetClientRect(rc);
  120. if (iIndex > m_nCurSelFolder)
  121. rect.SetRect(rc.left, rc.bottom - ((max - iIndex)) * m_nFolderHeight, rc.right, rc.bottom - (max - iIndex - 1) * m_nFolderHeight);
  122. else
  123. rect.SetRect(rc.left, rc.top + iIndex * m_nFolderHeight, rc.right, rc.top + (1 + iIndex) * m_nFolderHeight);
  124. return true;
  125. }
  126. bool CDrawerCtrl::PtInFolderHeadRect(CPoint pt) const
  127. {
  128. int max = m_arFolder.GetSize();
  129. ASSERT(m_nCurSelFolder >= 0 && m_nCurSelFolder < max);
  130. CRect rcClient;
  131. GetClientRect(rcClient);
  132. CRect rcTop, rcBottom;
  133. rcTop.SetRect(rcClient.left, rcClient.top, rcClient.right, rcClient.top + (m_nCurSelFolder + 1) * m_nFolderHeight);
  134. rcBottom.SetRect(rcClient.left, rcClient.bottom - (max - m_nCurSelFolder) * m_nFolderHeight, rcClient.right, rcClient.bottom);
  135. if (rcTop.PtInRect(pt) || rcBottom.PtInRect(pt))
  136. return true;
  137. return false;
  138. }
  139. int CDrawerCtrl::AddFolder(const char* cFolderName, const DWORD exData)
  140. {
  141. CBm_arFolder* pbf = new CBm_arFolder(cFolderName, exData);
  142. ASSERT(pbf);
  143. m_arFolder.Add((void*)pbf);
  144. return m_arFolder.GetSize() - 1;
  145. }
  146. int CDrawerCtrl::AddFolderBar(const char* pFolder, CWnd* pSon, const DWORD exData)
  147. {
  148. CBm_arFolder* pbf = new CBm_arFolder(pFolder, exData);
  149. ASSERT(pbf);
  150. pbf->pChild = pSon;
  151. m_arFolder.Add((void*)pbf);
  152. return m_arFolder.GetSize() - 1;
  153. }
  154. CDrawerCtrl::CBm_arFolder::CBm_arFolder(const char* name, DWORD exData)
  155. {
  156. cName = NULL;
  157. dwData = exData;
  158. if (name)
  159. {
  160. cName = new char[lstrlen(name) + 1];
  161. ASSERT(cName);
  162. lstrcpy(cName, name);
  163. }
  164. pChild = NULL;
  165. }
  166. CDrawerCtrl::CBm_arFolder::~CBm_arFolder()
  167. {
  168. if (cName) delete[] cName;
  169. }
  170. void CDrawerCtrl::GetInsideRect(CRect& rect) const
  171. {
  172. GetClientRect(rect);
  173. if (m_arFolder.GetSize() > 0)
  174. {
  175. int max = m_arFolder.GetSize();
  176. rect.top += m_nFolderHeight * (m_nCurSelFolder + 1);//+ 2;
  177. rect.bottom -= (max - m_nCurSelFolder - 1) * m_nFolderHeight + 1;
  178. return;
  179. }
  180. }
  181. int CDrawerCtrl::HitTestEx(const CPoint& point, int& index)
  182. {
  183. int max = m_arFolder.GetSize(), t;
  184. CRect rc;
  185. for (t = 0; t < max; t++)
  186. {
  187. GetFolderRect(t, rc);
  188. if (rc.PtInRect(point))
  189. {
  190. index = t;
  191. return htFolder;
  192. }
  193. }
  194. index = -1;
  195. return htNothing;
  196. }
  197. void CDrawerCtrl::OnLButtonDown(UINT nFlags, CPoint point)
  198. {
  199. if (GetFocus() != this) SetFocus();
  200. int index, ht = HitTestEx(point, index);
  201. if (ht == htFolder)
  202. {
  203. bool bHigh = true;
  204. if (::GetCapture() == NULL)
  205. {
  206. SetCapture();
  207. ASSERT(this == GetCapture());
  208. AfxLockTempMaps();
  209. while (TRUE)
  210. {
  211. MSG msg;
  212. VERIFY(::GetMessage(&msg, NULL, 0, 0));
  213. if (CWnd::GetCapture() != this) break;
  214. switch (msg.message)
  215. {
  216. case WM_LBUTTONUP:
  217. {
  218. CPoint pt(msg.lParam);
  219. int idx, ht1 = HitTestEx(pt, idx);
  220. if (ht1 == htFolder && idx != m_nCurSelFolder)
  221. {
  222. //idx = (idx == m_nCurSelFolder)?(idx+1):idx;
  223. if (idx < GetFolderCount())
  224. SetSelFolder(idx);
  225. }
  226. }
  227. goto ExitLoop;
  228. default:
  229. DispatchMessage(&msg);
  230. break;
  231. }
  232. }
  233. ExitLoop:
  234. ReleaseCapture();
  235. AfxUnlockTempMaps(FALSE);
  236. }
  237. }
  238. CWnd::OnLButtonDown(nFlags, point);
  239. }
  240. void CDrawerCtrl::SetSelFolder(const int index)
  241. {
  242. ASSERT(index >= 0 && index < GetFolderCount());
  243. if (index == m_nCurSelFolder) return;
  244. CWnd* pc = GetFolderChild();
  245. if (pc) pc->ShowWindow(SW_HIDE);
  246. m_nCurSelFolder = index;
  247. pc = GetFolderChild();
  248. if (pc)
  249. {
  250. CRect rc;
  251. GetInsideRect(rc);
  252. _dprintf(_T("\t\t\t内部大小:%d,%d,%d,%d"), rc.left, rc.top, rc.right, rc.bottom);
  253. pc->MoveWindow(rc);
  254. pc->ShowWindow(SW_SHOW);
  255. }
  256. Invalidate();
  257. }
  258. int CDrawerCtrl::GetFolderCount() const
  259. {
  260. return m_arFolder.GetSize();
  261. }
  262. int CDrawerCtrl::GetSelFolder() const
  263. {
  264. return m_nCurSelFolder;
  265. }
  266. void CDrawerCtrl::RemoveFolder(const int index)
  267. {
  268. ASSERT(index >= 0 && index < GetFolderCount());
  269. CBm_arFolder* pbf = (CBm_arFolder*)m_arFolder.GetAt(index);
  270. delete pbf;
  271. m_arFolder.RemoveAt(index);
  272. if (m_nCurSelFolder >= index) m_nCurSelFolder = index - 1;
  273. if (m_nCurSelFolder < 0 && GetFolderCount() > 0) m_nCurSelFolder = 0;
  274. Invalidate();
  275. }
  276. BOOL CDrawerCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  277. {
  278. CPoint pt(GetMessagePos());
  279. ScreenToClient(&pt);
  280. int index, ht = HitTestEx(pt, index);
  281. if (ht == htFolder)
  282. {
  283. //SetCursor(hHandCursor);
  284. return true;
  285. }
  286. return CWnd::OnSetCursor(pWnd, nHitTest, message);
  287. }
  288. void CDrawerCtrl::OnSize(UINT nType, int cx, int cy)
  289. {
  290. CWnd::OnSize(nType, cx, cy);
  291. int t, max = GetFolderCount();
  292. CRect rc;
  293. GetInsideRect(rc);
  294. for (t = 0; t < max; t++)
  295. {
  296. CBm_arFolder* pbf = (CBm_arFolder*)m_arFolder.GetAt(t);
  297. CWnd* pc = GetFolderChild(t);
  298. if (pc) pc->SetWindowPos(0, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOZORDER);
  299. }
  300. }
  301. CWnd* CDrawerCtrl::GetFolderChild(int iFolder)
  302. {
  303. if (GetFolderCount())
  304. {
  305. if (iFolder < 0)
  306. iFolder = m_nCurSelFolder == -1 ? 0 : m_nCurSelFolder;
  307. CBm_arFolder* pbf = (CBm_arFolder*)m_arFolder.GetAt(iFolder);
  308. return pbf->pChild;
  309. }
  310. return NULL;
  311. }
  312. void CDrawerCtrl::SetAutoFolder(IN const DWORD& dwTime)
  313. {
  314. SetTimer(2, dwTime, NULL);
  315. }
  316. DWORD CDrawerCtrl::GetFolderData(int iFolder)
  317. {
  318. if (iFolder < 0) iFolder = m_nCurSelFolder;
  319. CBm_arFolder* pbf = (CBm_arFolder*)m_arFolder.GetAt(iFolder);
  320. return pbf->dwData;
  321. }
  322. void CDrawerCtrl::OnMouseMove(UINT nFlags, CPoint point)
  323. {
  324. if (GetFocus() != this && PtInFolderHeadRect(point))
  325. SetFocus();
  326. //_dprintf(_T("CDrawerCtrl::OnMouseMove"));
  327. int ht = HitTestEx(point, iHoverFolder);
  328. if (ht == htFolder)
  329. {
  330. HighlightFolder(iHoverFolder);
  331. SetTimer(1, 100, NULL);
  332. }
  333. m_curpoint = point;
  334. CWnd::OnMouseMove(nFlags, point);
  335. }
  336. void CDrawerCtrl::DrawFolder(CDC* pDC, const int iIdx, CRect rect)
  337. {
  338. _dprintf(_T("\t\tCDrawerCtrl::DrawFolder %d, %d = %d"), m_nCurSelFolder, iHoverFolder, iIdx);
  339. if (iIdx < 0) return;
  340. CBm_arFolder* pBf = (CBm_arFolder*)m_arFolder.GetAt(iIdx);
  341. if (iHoverFolder == iIdx)
  342. {
  343. if (m_bmpHoverFolder.m_hObject != NULL)
  344. m_bmpHoverFolder.ExtendDraw(pDC, rect, 20, 5);
  345. }
  346. else
  347. {
  348. if (m_bmpNormalFolder.m_hObject != NULL)
  349. m_bmpNormalFolder.ExtendDraw(pDC, rect, 20, 5);
  350. }
  351. if (m_nCurSelFolder == iIdx && iSelcon != NULL)
  352. {
  353. _dprintf(_T("\t\t画图标 %d, %d = %d"), m_nCurSelFolder, iHoverFolder, iIdx);
  354. ::DrawIconEx(*pDC, rect.left + 2, rect.top + (m_nFolderHeight - 16) / 2, iSelcon, 16, 16, 0, NULL, DI_NORMAL);
  355. }
  356. //Draw Folder Name In Folder
  357. if (m_pFont == NULL)
  358. m_pFont = CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT));
  359. pDC->SelectObject(m_pFont);
  360. pDC->SetTextColor(m_crText);
  361. pDC->SetBkMode(TRANSPARENT);
  362. pDC->DrawText(pBf->cName, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  363. }
  364. void CDrawerCtrl::HighlightFolder(const int index)
  365. {
  366. if (iLastFolderHighlighted == index) return;
  367. CClientDC dc(this);
  368. if (iLastFolderHighlighted >= 0)
  369. {
  370. CRect rc;
  371. if (GetFolderRect(iLastFolderHighlighted, rc))
  372. {
  373. DrawFolder(&dc, iLastFolderHighlighted, rc);
  374. }
  375. }
  376. if (index >= 0)
  377. {
  378. CRect rc;
  379. if (GetFolderRect(index, rc))
  380. {
  381. DrawFolder(&dc, index, rc);
  382. }
  383. }
  384. iLastFolderHighlighted = index;
  385. }
  386. void CDrawerCtrl::OnTimer(UINT_PTR nIDEvent)
  387. {
  388. if (nIDEvent == 1)
  389. {
  390. CPoint pt(GetMessagePos()); ScreenToClient(&pt);
  391. CRect rc; GetClientRect(&rc);
  392. int ht = HitTestEx(pt, iHoverFolder);
  393. if (ht != htFolder || !(rc.PtInRect(pt)))
  394. {
  395. HighlightFolder(-1);
  396. KillTimer(1);
  397. }
  398. }
  399. if (nIDEvent == 2)
  400. {// 鼠标在folderheader上x毫秒自动打开;
  401. if (GetFocus() != this && PtInFolderHeadRect(m_curpoint)) SetFocus();
  402. int index, ht = HitTestEx(m_curpoint, index);
  403. if (ht == htFolder)
  404. {
  405. bool bHigh = true;
  406. if (::GetCapture() == NULL)
  407. {
  408. SetCapture();
  409. ASSERT(this == GetCapture());
  410. AfxLockTempMaps();
  411. if (index < GetFolderCount())
  412. SetSelFolder(index);
  413. ReleaseCapture();
  414. AfxUnlockTempMaps(FALSE);
  415. }
  416. }
  417. }
  418. CWnd::OnTimer(nIDEvent);
  419. }
  420. BOOL CDrawerCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
  421. {
  422. if (GetFocus() != this)
  423. SetFocus();
  424. if (m_nCurSelFolder <= 0 && m_nCurSelFolder >= m_arFolder.GetSize())
  425. return FALSE;
  426. ScreenToClient(&pt);
  427. if (!PtInFolderHeadRect(pt))
  428. {
  429. return FALSE;
  430. }
  431. INT nIndex = m_nCurSelFolder;
  432. if (::GetCapture() == NULL)
  433. {
  434. SetCapture();
  435. AfxLockTempMaps();
  436. CBm_arFolder* pChild = NULL;
  437. if (zDelta > 0)
  438. {// 向上滚动;
  439. if (m_nCurSelFolder == 0)
  440. {
  441. ReleaseCapture();
  442. AfxUnlockTempMaps(FALSE);
  443. return TRUE;
  444. }
  445. nIndex--;
  446. pChild = (CBm_arFolder*)m_arFolder.GetAt(nIndex);
  447. if (pChild)
  448. {
  449. SetSelFolder(nIndex);
  450. }
  451. }
  452. else
  453. {// 向下滚动;
  454. if (m_nCurSelFolder == GetFolderCount() - 1)
  455. {
  456. ReleaseCapture();
  457. AfxUnlockTempMaps(FALSE);
  458. return TRUE;
  459. }
  460. nIndex++;
  461. pChild = (CBm_arFolder*)m_arFolder.GetAt(nIndex);
  462. if (pChild)
  463. {
  464. SetSelFolder(nIndex);
  465. }
  466. }
  467. ReleaseCapture();
  468. AfxUnlockTempMaps(FALSE);
  469. }
  470. return CWnd::OnMouseWheel(nFlags, zDelta, pt);
  471. }