barcore.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #include <malloc.h>
  12. #ifdef AFX_CORE3_SEG
  13. #pragma code_seg(AFX_CORE3_SEG)
  14. #endif
  15. #ifdef _DEBUG
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19. #define new DEBUG_NEW
  20. /////////////////////////////////////////////////////////////////////////////
  21. // CControlBar
  22. // IMPLEMENT_DYNAMIC for CControlBar is in wincore.cpp for .OBJ granularity reasons
  23. BEGIN_MESSAGE_MAP(CControlBar, CWnd)
  24. //{{AFX_MSG_MAP(CControlBar)
  25. ON_WM_TIMER()
  26. ON_WM_PAINT()
  27. ON_WM_CTLCOLOR()
  28. ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
  29. ON_MESSAGE(WM_SIZEPARENT, OnSizeParent)
  30. ON_WM_WINDOWPOSCHANGING()
  31. ON_WM_SHOWWINDOW()
  32. ON_WM_LBUTTONDOWN()
  33. ON_WM_LBUTTONDBLCLK()
  34. ON_WM_MOUSEACTIVATE()
  35. ON_WM_CANCELMODE()
  36. ON_WM_CREATE()
  37. ON_WM_DESTROY()
  38. ON_MESSAGE_VOID(WM_INITIALUPDATE, OnInitialUpdate)
  39. ON_MESSAGE(WM_HELPHITTEST, OnHelpHitTest)
  40. ON_WM_ERASEBKGND()
  41. //}}AFX_MSG_MAP
  42. #ifndef _AFX_NO_CTL3D_SUPPORT
  43. ON_MESSAGE(WM_QUERY3DCONTROLS, OnQuery3dControls)
  44. #endif
  45. END_MESSAGE_MAP()
  46. #ifdef AFX_INIT_SEG
  47. #pragma code_seg(AFX_INIT_SEG)
  48. #endif
  49. CControlBar::CControlBar()
  50. {
  51. // no elements contained in the control bar yet
  52. m_nCount = 0;
  53. m_pData = NULL;
  54. // set up some default border spacings
  55. m_cxLeftBorder = m_cxRightBorder = 6;
  56. m_cxDefaultGap = 2;
  57. m_cyTopBorder = m_cyBottomBorder = 1;
  58. m_bAutoDelete = FALSE;
  59. m_hWndOwner = NULL;
  60. m_nStateFlags = 0;
  61. m_pDockSite = NULL;
  62. m_pDockBar = NULL;
  63. m_pDockContext = NULL;
  64. m_dwStyle = 0;
  65. m_dwDockStyle = 0;
  66. m_nMRUWidth = 32767;
  67. }
  68. void CControlBar::SetBorders(int cxLeft, int cyTop, int cxRight, int cyBottom)
  69. {
  70. ASSERT(cxLeft >= 0);
  71. ASSERT(cyTop >= 0);
  72. ASSERT(cxRight >= 0);
  73. ASSERT(cyBottom >= 0);
  74. m_cxLeftBorder = cxLeft;
  75. m_cyTopBorder = cyTop;
  76. m_cxRightBorder = cxRight;
  77. m_cyBottomBorder = cyBottom;
  78. }
  79. BOOL CControlBar::PreCreateWindow(CREATESTRUCT& cs)
  80. {
  81. if (!CWnd::PreCreateWindow(cs))
  82. return FALSE;
  83. // force clipsliblings (otherwise will cause repaint problems)
  84. cs.style |= WS_CLIPSIBLINGS;
  85. // default border style translation for Win4
  86. // (you can turn off this translation by setting CBRS_BORDER_3D)
  87. if (afxData.bWin4 && (m_dwStyle & CBRS_BORDER_3D) == 0)
  88. {
  89. DWORD dwNewStyle = 0;
  90. switch (m_dwStyle & (CBRS_BORDER_ANY|CBRS_ALIGN_ANY))
  91. {
  92. case CBRS_LEFT:
  93. dwNewStyle = CBRS_BORDER_TOP|CBRS_BORDER_BOTTOM;
  94. break;
  95. case CBRS_TOP:
  96. dwNewStyle = CBRS_BORDER_TOP;
  97. break;
  98. case CBRS_RIGHT:
  99. dwNewStyle = CBRS_BORDER_TOP|CBRS_BORDER_BOTTOM;
  100. break;
  101. case CBRS_BOTTOM:
  102. dwNewStyle = CBRS_BORDER_BOTTOM;
  103. break;
  104. }
  105. // set new style if it matched one of the predefined border types
  106. if (dwNewStyle != 0)
  107. {
  108. m_dwStyle &= ~(CBRS_BORDER_ANY);
  109. m_dwStyle |= (dwNewStyle | CBRS_BORDER_3D);
  110. }
  111. }
  112. return TRUE;
  113. }
  114. void CControlBar::SetBarStyle(DWORD dwStyle)
  115. {
  116. ASSERT((dwStyle & CBRS_ALL) == dwStyle);
  117. EnableToolTips(dwStyle & CBRS_TOOLTIPS);
  118. if (m_dwStyle != dwStyle)
  119. {
  120. DWORD dwOldStyle = m_dwStyle;
  121. m_dwStyle = dwStyle;
  122. OnBarStyleChange(dwOldStyle, dwStyle);
  123. }
  124. }
  125. void CControlBar::OnBarStyleChange(DWORD, DWORD)
  126. {
  127. // can be overridden in derived classes
  128. }
  129. BOOL CControlBar::AllocElements(int nElements, int cbElement)
  130. {
  131. ASSERT_VALID(this);
  132. ASSERT(nElements >= 0 && cbElement >= 0);
  133. ASSERT(m_pData != NULL || m_nCount == 0);
  134. // allocate new data if necessary
  135. void* pData = NULL;
  136. if (nElements > 0)
  137. {
  138. ASSERT(cbElement > 0);
  139. if ((pData = calloc(nElements, cbElement)) == NULL)
  140. return FALSE;
  141. }
  142. free(m_pData); // free old data
  143. // set new data and elements
  144. m_pData = pData;
  145. m_nCount = nElements;
  146. return TRUE;
  147. }
  148. #ifdef AFX_CORE3_SEG
  149. #pragma code_seg(AFX_CORE3_SEG)
  150. #endif
  151. CControlBar::~CControlBar()
  152. {
  153. ASSERT_VALID(this);
  154. DestroyWindow(); // avoid PostNcDestroy problems
  155. // also done in OnDestroy, but done here just in case
  156. if (m_pDockSite != NULL)
  157. m_pDockSite->RemoveControlBar(this);
  158. // free docking context
  159. CDockContext* pDockContext = m_pDockContext;
  160. m_pDockContext = NULL;
  161. delete pDockContext;
  162. // free array
  163. if (m_pData != NULL)
  164. {
  165. ASSERT(m_nCount != 0);
  166. free(m_pData);
  167. }
  168. _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  169. if (pThreadState->m_pLastStatus == this)
  170. {
  171. pThreadState->m_pLastStatus = NULL;
  172. pThreadState->m_nLastStatus = -1;
  173. }
  174. }
  175. void CControlBar::PostNcDestroy()
  176. {
  177. if (m_bAutoDelete) // Automatic cleanup?
  178. delete this;
  179. }
  180. /////////////////////////////////////////////////////////////////////////////
  181. // Attributes
  182. CSize CControlBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
  183. {
  184. CSize size;
  185. size.cx = (bStretch && bHorz ? 32767 : 0);
  186. size.cy = (bStretch && !bHorz ? 32767 : 0);
  187. return size;
  188. }
  189. CSize CControlBar::CalcDynamicLayout(int, DWORD nMode)
  190. {
  191. return CalcFixedLayout(nMode & LM_STRETCH, nMode & LM_HORZ);
  192. }
  193. BOOL CControlBar::IsDockBar() const
  194. {
  195. return FALSE;
  196. }
  197. /////////////////////////////////////////////////////////////////////////////
  198. // Fly-by status bar help
  199. #define ID_TIMER_WAIT 0xE000 // timer while waiting to show status
  200. #define ID_TIMER_CHECK 0xE001 // timer to check for removal of status
  201. void CControlBar::ResetTimer(UINT nEvent, UINT nTime)
  202. {
  203. KillTimer(ID_TIMER_WAIT);
  204. KillTimer(ID_TIMER_CHECK);
  205. VERIFY(SetTimer(nEvent, nTime, NULL));
  206. }
  207. void CControlBar::OnTimer(UINT nIDEvent)
  208. {
  209. if (GetKeyState(VK_LBUTTON) < 0)
  210. return;
  211. _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  212. // get current mouse position for hit test
  213. CPoint point; GetCursorPos(&point);
  214. ScreenToClient(&point);
  215. int nHit = OnToolHitTest(point, NULL);
  216. if (nHit >= 0)
  217. {
  218. // determine if status bar help should go away
  219. CWnd* pParent = GetTopLevelParent();
  220. if (!IsTopParentActive() || !pParent->IsWindowEnabled())
  221. nHit = -1;
  222. // remove status help if capture is set
  223. HWND hWndTip = pThreadState->m_pToolTip->GetSafeHwnd();
  224. CWnd* pCapture = GetCapture();
  225. if (pCapture != this && pCapture->GetSafeHwnd() != hWndTip &&
  226. pCapture->GetTopLevelParent() == pParent)
  227. {
  228. nHit = -1;
  229. }
  230. }
  231. else
  232. {
  233. pThreadState->m_nLastStatus = -1;
  234. }
  235. // make sure it isn't over some other app's window
  236. if (nHit >= 0)
  237. {
  238. ClientToScreen(&point);
  239. HWND hWnd = ::WindowFromPoint(point);
  240. if (hWnd == NULL || (hWnd != m_hWnd && !::IsChild(m_hWnd, hWnd) &&
  241. pThreadState->m_pToolTip->GetSafeHwnd() != hWnd))
  242. {
  243. nHit = -1;
  244. pThreadState->m_nLastStatus = -1;
  245. }
  246. }
  247. // handle the result
  248. if (nHit < 0)
  249. {
  250. if (pThreadState->m_nLastStatus == -1)
  251. KillTimer(ID_TIMER_CHECK);
  252. SetStatusText(-1);
  253. }
  254. // set status text after initial timeout
  255. if (nIDEvent == ID_TIMER_WAIT)
  256. {
  257. KillTimer(ID_TIMER_WAIT);
  258. if (nHit >= 0)
  259. SetStatusText(nHit);
  260. }
  261. }
  262. BOOL CControlBar::SetStatusText(int nHit)
  263. {
  264. CWnd* pOwner = GetOwner();
  265. _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  266. if (nHit == -1)
  267. {
  268. // handle reset case
  269. pThreadState->m_pLastStatus = NULL;
  270. if (m_nStateFlags & statusSet)
  271. {
  272. pOwner->SendMessage(WM_POPMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
  273. m_nStateFlags &= ~statusSet;
  274. return TRUE;
  275. }
  276. KillTimer(ID_TIMER_WAIT);
  277. }
  278. else
  279. {
  280. // handle setnew case
  281. if (!(m_nStateFlags & statusSet) || pThreadState->m_nLastStatus != nHit)
  282. {
  283. pThreadState->m_pLastStatus = this;
  284. pOwner->SendMessage(WM_SETMESSAGESTRING, nHit);
  285. m_nStateFlags |= statusSet;
  286. ResetTimer(ID_TIMER_CHECK, 200);
  287. return TRUE;
  288. }
  289. }
  290. return FALSE;
  291. }
  292. /////////////////////////////////////////////////////////////////////////////
  293. // Default control bar processing
  294. BOOL CControlBar::PreTranslateMessage(MSG* pMsg)
  295. {
  296. ASSERT_VALID(this);
  297. ASSERT(m_hWnd != NULL);
  298. // allow tooltip messages to be filtered
  299. if (CWnd::PreTranslateMessage(pMsg))
  300. return TRUE;
  301. UINT message = pMsg->message;
  302. CWnd* pOwner = GetOwner();
  303. // handle CBRS_FLYBY style (status bar flyby help)
  304. if (((m_dwStyle & CBRS_FLYBY) ||
  305. message == WM_LBUTTONDOWN || message == WM_LBUTTONUP) &&
  306. ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) ||
  307. (message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST)))
  308. {
  309. _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  310. // gather information about current mouse position
  311. CPoint point = pMsg->pt;
  312. ScreenToClient(&point);
  313. TOOLINFO ti; memset(&ti, 0, sizeof(TOOLINFO));
  314. ti.cbSize = sizeof(AFX_OLDTOOLINFO);
  315. int nHit = OnToolHitTest(point, &ti);
  316. if (ti.lpszText != LPSTR_TEXTCALLBACK)
  317. free(ti.lpszText);
  318. BOOL bNotButton =
  319. message == WM_LBUTTONDOWN && (ti.uFlags & TTF_NOTBUTTON);
  320. if (message != WM_LBUTTONDOWN && GetKeyState(VK_LBUTTON) < 0)
  321. nHit = pThreadState->m_nLastStatus;
  322. // update state of status bar
  323. if (nHit < 0 || bNotButton)
  324. {
  325. if (GetKeyState(VK_LBUTTON) >= 0 || bNotButton)
  326. {
  327. SetStatusText(-1);
  328. KillTimer(ID_TIMER_CHECK);
  329. }
  330. }
  331. else
  332. {
  333. if (message == WM_LBUTTONUP)
  334. {
  335. SetStatusText(-1);
  336. ResetTimer(ID_TIMER_CHECK, 200);
  337. }
  338. else
  339. {
  340. if ((m_nStateFlags & statusSet) || GetKeyState(VK_LBUTTON) < 0)
  341. SetStatusText(nHit);
  342. else if (nHit != pThreadState->m_nLastStatus)
  343. ResetTimer(ID_TIMER_WAIT, 300);
  344. }
  345. }
  346. pThreadState->m_nLastStatus = nHit;
  347. }
  348. // don't translate dialog messages when in Shift+F1 help mode
  349. CFrameWnd* pFrameWnd = GetTopLevelFrame();
  350. if (pFrameWnd != NULL && pFrameWnd->m_bHelpMode)
  351. return FALSE;
  352. // since 'IsDialogMessage' will eat frame window accelerators,
  353. // we call all frame windows' PreTranslateMessage first
  354. while (pOwner != NULL)
  355. {
  356. // allow owner & frames to translate before IsDialogMessage does
  357. if (pOwner->PreTranslateMessage(pMsg))
  358. return TRUE;
  359. // try parent frames until there are no parent frames
  360. pOwner = pOwner->GetParentFrame();
  361. }
  362. // filter both messages to dialog and from children
  363. return PreTranslateInput(pMsg);
  364. }
  365. LRESULT CControlBar::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
  366. {
  367. ASSERT_VALID(this);
  368. LRESULT lResult;
  369. switch (nMsg)
  370. {
  371. case WM_NOTIFY:
  372. case WM_COMMAND:
  373. case WM_DRAWITEM:
  374. case WM_MEASUREITEM:
  375. case WM_DELETEITEM:
  376. case WM_COMPAREITEM:
  377. case WM_VKEYTOITEM:
  378. case WM_CHARTOITEM:
  379. // send these messages to the owner if not handled
  380. if (OnWndMsg(nMsg, wParam, lParam, &lResult))
  381. return lResult;
  382. else
  383. {
  384. // try owner next
  385. lResult = GetOwner()->SendMessage(nMsg, wParam, lParam);
  386. // special case for TTN_NEEDTEXTA and TTN_NEEDTEXTW
  387. if(nMsg == WM_NOTIFY)
  388. {
  389. NMHDR* pNMHDR = (NMHDR*)lParam;
  390. if (pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW)
  391. {
  392. TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
  393. TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
  394. if ((pNMHDR->code == TTN_NEEDTEXTA && (!pTTTA->lpszText || !*pTTTA->lpszText)) ||
  395. (pNMHDR->code == TTN_NEEDTEXTW && (!pTTTW->lpszText || !*pTTTW->lpszText)))
  396. {
  397. // not handled by owner, so let bar itself handle it
  398. lResult = CWnd::WindowProc(nMsg, wParam, lParam);
  399. }
  400. }
  401. }
  402. return lResult;
  403. }
  404. }
  405. // otherwise, just handle in default way
  406. lResult = CWnd::WindowProc(nMsg, wParam, lParam);
  407. return lResult;
  408. }
  409. LRESULT CControlBar::OnHelpHitTest(WPARAM, LPARAM lParam)
  410. {
  411. ASSERT_VALID(this);
  412. int nID = OnToolHitTest((DWORD)lParam, NULL);
  413. if (nID != -1)
  414. return HID_BASE_COMMAND+nID;
  415. nID = _AfxGetDlgCtrlID(m_hWnd);
  416. return nID != 0 ? HID_BASE_CONTROL+nID : 0;
  417. }
  418. void CControlBar::OnWindowPosChanging(LPWINDOWPOS lpWndPos)
  419. {
  420. // WINBUG: We call DefWindowProc here instead of CWnd::OnWindowPosChanging
  421. // (which calls CWnd::Default, which calls through the super wndproc)
  422. // because certain control bars that are system implemented (such as
  423. // CToolBar with TBSTYLE_FLAT) do not implement WM_WINDOWPOSCHANGING
  424. // correctly, causing repaint problems. This code bypasses that whole
  425. // mess.
  426. ::DefWindowProc(m_hWnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)lpWndPos);
  427. if (lpWndPos->flags & SWP_NOSIZE)
  428. return;
  429. // invalidate borders on the right
  430. CRect rect;
  431. GetWindowRect(&rect);
  432. CSize sizePrev = rect.Size();
  433. int cx = lpWndPos->cx;
  434. int cy = lpWndPos->cy;
  435. if (cx != sizePrev.cx && (m_dwStyle & CBRS_BORDER_RIGHT))
  436. {
  437. rect.SetRect(cx-afxData.cxBorder2, 0, cx, cy);
  438. InvalidateRect(&rect);
  439. rect.SetRect(sizePrev.cx-afxData.cxBorder2, 0, sizePrev.cx, cy);
  440. InvalidateRect(&rect);
  441. }
  442. // invalidate borders on the bottom
  443. if (cy != sizePrev.cy && (m_dwStyle & CBRS_BORDER_BOTTOM))
  444. {
  445. rect.SetRect(0, cy-afxData.cyBorder2, cx, cy);
  446. InvalidateRect(&rect);
  447. rect.SetRect(0, sizePrev.cy-afxData.cyBorder2, cx, sizePrev.cy);
  448. InvalidateRect(&rect);
  449. }
  450. }
  451. int CControlBar::OnCreate(LPCREATESTRUCT lpcs)
  452. {
  453. if (CWnd::OnCreate(lpcs) == -1)
  454. return -1;
  455. if (m_dwStyle & CBRS_TOOLTIPS)
  456. EnableToolTips();
  457. CFrameWnd *pFrameWnd = (CFrameWnd*)GetParent();
  458. if (pFrameWnd->IsFrameWnd())
  459. {
  460. m_pDockSite = pFrameWnd;
  461. m_pDockSite->AddControlBar(this);
  462. }
  463. return 0;
  464. }
  465. void CControlBar::OnDestroy()
  466. {
  467. _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  468. if (pThreadState->m_pLastStatus == this)
  469. {
  470. SetStatusText(-1);
  471. ASSERT(pThreadState->m_pLastStatus == NULL);
  472. }
  473. if (m_pDockSite != NULL)
  474. {
  475. m_pDockSite->RemoveControlBar(this);
  476. m_pDockSite = NULL;
  477. }
  478. CWnd::OnDestroy();
  479. }
  480. BOOL CControlBar::DestroyWindow()
  481. {
  482. if (m_hWnd != NULL && IsFloating())
  483. return GetDockingFrame()->DestroyWindow();
  484. else
  485. return CWnd::DestroyWindow();
  486. }
  487. int CControlBar::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT nMsg)
  488. {
  489. // call default when toolbar is not floating
  490. if (!IsFloating())
  491. return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, nMsg);
  492. // special behavior when floating
  493. ActivateTopParent();
  494. return MA_NOACTIVATE; // activation already done
  495. }
  496. void CControlBar::OnPaint()
  497. {
  498. // background is already filled in gray
  499. CPaintDC dc(this);
  500. // erase background now
  501. if (IsVisible())
  502. DoPaint(&dc); // delegate to paint helper
  503. }
  504. void CControlBar::EraseNonClient()
  505. {
  506. // get window DC that is clipped to the non-client area
  507. CWindowDC dc(this);
  508. CRect rectClient;
  509. GetClientRect(rectClient);
  510. CRect rectWindow;
  511. GetWindowRect(rectWindow);
  512. ScreenToClient(rectWindow);
  513. rectClient.OffsetRect(-rectWindow.left, -rectWindow.top);
  514. dc.ExcludeClipRect(rectClient);
  515. // draw borders in non-client area
  516. rectWindow.OffsetRect(-rectWindow.left, -rectWindow.top);
  517. DrawBorders(&dc, rectWindow);
  518. // erase parts not drawn
  519. dc.IntersectClipRect(rectWindow);
  520. SendMessage(WM_ERASEBKGND, (WPARAM)dc.m_hDC);
  521. // draw gripper in non-client area
  522. DrawGripper(&dc, rectWindow);
  523. }
  524. HBRUSH CControlBar::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
  525. {
  526. LRESULT lResult;
  527. if (pWnd->SendChildNotifyLastMsg(&lResult))
  528. return (HBRUSH)lResult; // eat it
  529. // force black text on gray background all the time
  530. if (!GrayCtlColor(pDC->m_hDC, pWnd->GetSafeHwnd(), nCtlColor,
  531. afxData.hbrBtnFace, afxData.clrBtnText))
  532. return (HBRUSH)Default();
  533. return afxData.hbrBtnFace;
  534. }
  535. void CControlBar::OnLButtonDown(UINT nFlags, CPoint pt)
  536. {
  537. // only start dragging if clicked in "void" space
  538. if (m_pDockBar != NULL && OnToolHitTest(pt, NULL) == -1)
  539. {
  540. // start the drag
  541. ASSERT(m_pDockContext != NULL);
  542. ClientToScreen(&pt);
  543. m_pDockContext->StartDrag(pt);
  544. }
  545. else
  546. {
  547. CWnd::OnLButtonDown(nFlags, pt);
  548. }
  549. }
  550. void CControlBar::OnLButtonDblClk(UINT nFlags, CPoint pt)
  551. {
  552. // only toggle docking if clicked in "void" space
  553. if (m_pDockBar != NULL && OnToolHitTest(pt, NULL) == -1)
  554. {
  555. // start the drag
  556. ASSERT(m_pDockContext != NULL);
  557. m_pDockContext->ToggleDocking();
  558. }
  559. else
  560. {
  561. CWnd::OnLButtonDblClk(nFlags, pt);
  562. }
  563. }
  564. LRESULT CControlBar::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM)
  565. {
  566. // handle delay hide/show
  567. BOOL bVis = GetStyle() & WS_VISIBLE;
  568. UINT swpFlags = 0;
  569. if ((m_nStateFlags & delayHide) && bVis)
  570. swpFlags = SWP_HIDEWINDOW;
  571. else if ((m_nStateFlags & delayShow) && !bVis)
  572. swpFlags = SWP_SHOWWINDOW;
  573. m_nStateFlags &= ~(delayShow|delayHide);
  574. if (swpFlags != 0)
  575. {
  576. SetWindowPos(NULL, 0, 0, 0, 0, swpFlags|
  577. SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  578. }
  579. // the style must be visible and if it is docked
  580. // the dockbar style must also be visible
  581. if ((GetStyle() & WS_VISIBLE) &&
  582. (m_pDockBar == NULL || (m_pDockBar->GetStyle() & WS_VISIBLE)))
  583. {
  584. CFrameWnd* pTarget = (CFrameWnd*)GetOwner();
  585. if (pTarget == NULL || !pTarget->IsFrameWnd())
  586. pTarget = GetParentFrame();
  587. if (pTarget != NULL)
  588. OnUpdateCmdUI(pTarget, (BOOL)wParam);
  589. }
  590. return 0L;
  591. }
  592. void CControlBar::OnInitialUpdate()
  593. {
  594. // update the indicators before becoming visible
  595. OnIdleUpdateCmdUI(TRUE, 0L);
  596. }
  597. DWORD CControlBar::RecalcDelayShow(AFX_SIZEPARENTPARAMS* lpLayout)
  598. {
  599. ASSERT(lpLayout != NULL);
  600. // resize and reposition this control bar based on styles
  601. DWORD dwStyle = (m_dwStyle & (CBRS_ALIGN_ANY|CBRS_BORDER_ANY)) |
  602. (GetStyle() & WS_VISIBLE);
  603. // handle delay hide/show
  604. if (m_nStateFlags & (delayHide|delayShow))
  605. {
  606. UINT swpFlags = 0;
  607. if (m_nStateFlags & delayHide)
  608. {
  609. ASSERT((m_nStateFlags & delayShow) == 0);
  610. if (dwStyle & WS_VISIBLE)
  611. swpFlags = SWP_HIDEWINDOW;
  612. }
  613. else
  614. {
  615. ASSERT(m_nStateFlags & delayShow);
  616. if ((dwStyle & WS_VISIBLE) == 0)
  617. swpFlags = SWP_SHOWWINDOW;
  618. }
  619. if (swpFlags != 0)
  620. {
  621. // make the window seem visible/hidden
  622. dwStyle ^= WS_VISIBLE;
  623. if (lpLayout->hDWP != NULL)
  624. {
  625. // clear delay flags
  626. m_nStateFlags &= ~(delayShow|delayHide);
  627. // hide/show the window if actually doing layout
  628. lpLayout->hDWP = ::DeferWindowPos(lpLayout->hDWP, m_hWnd, NULL,
  629. 0, 0, 0, 0, swpFlags|
  630. SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  631. }
  632. }
  633. else
  634. {
  635. // clear delay flags -- window is already in correct state
  636. m_nStateFlags &= ~(delayShow|delayHide);
  637. }
  638. }
  639. return dwStyle; // return new style
  640. }
  641. LRESULT CControlBar::OnSizeParent(WPARAM, LPARAM lParam)
  642. {
  643. AFX_SIZEPARENTPARAMS* lpLayout = (AFX_SIZEPARENTPARAMS*)lParam;
  644. DWORD dwStyle = RecalcDelayShow(lpLayout);
  645. if ((dwStyle & WS_VISIBLE) && (dwStyle & CBRS_ALIGN_ANY) != 0)
  646. {
  647. // align the control bar
  648. CRect rect;
  649. rect.CopyRect(&lpLayout->rect);
  650. CSize sizeAvail = rect.Size(); // maximum size available
  651. // get maximum requested size
  652. DWORD dwMode = lpLayout->bStretch ? LM_STRETCH : 0;
  653. if ((m_dwStyle & CBRS_SIZE_DYNAMIC) && m_dwStyle & CBRS_FLOATING)
  654. dwMode |= LM_HORZ | LM_MRUWIDTH;
  655. else if (dwStyle & CBRS_ORIENT_HORZ)
  656. dwMode |= LM_HORZ | LM_HORZDOCK;
  657. else
  658. dwMode |= LM_VERTDOCK;
  659. CSize size = CalcDynamicLayout(-1, dwMode);
  660. size.cx = min(size.cx, sizeAvail.cx);
  661. size.cy = min(size.cy, sizeAvail.cy);
  662. if (dwStyle & CBRS_ORIENT_HORZ)
  663. {
  664. lpLayout->sizeTotal.cy += size.cy;
  665. lpLayout->sizeTotal.cx = max(lpLayout->sizeTotal.cx, size.cx);
  666. if (dwStyle & CBRS_ALIGN_TOP)
  667. lpLayout->rect.top += size.cy;
  668. else if (dwStyle & CBRS_ALIGN_BOTTOM)
  669. {
  670. rect.top = rect.bottom - size.cy;
  671. lpLayout->rect.bottom -= size.cy;
  672. }
  673. }
  674. else if (dwStyle & CBRS_ORIENT_VERT)
  675. {
  676. lpLayout->sizeTotal.cx += size.cx;
  677. lpLayout->sizeTotal.cy = max(lpLayout->sizeTotal.cy, size.cy);
  678. if (dwStyle & CBRS_ALIGN_LEFT)
  679. lpLayout->rect.left += size.cx;
  680. else if (dwStyle & CBRS_ALIGN_RIGHT)
  681. {
  682. rect.left = rect.right - size.cx;
  683. lpLayout->rect.right -= size.cx;
  684. }
  685. }
  686. else
  687. {
  688. ASSERT(FALSE); // can never happen
  689. }
  690. rect.right = rect.left + size.cx;
  691. rect.bottom = rect.top + size.cy;
  692. // only resize the window if doing layout and not just rect query
  693. if (lpLayout->hDWP != NULL)
  694. AfxRepositionWindow(lpLayout, m_hWnd, &rect);
  695. }
  696. return 0;
  697. }
  698. void CControlBar::DelayShow(BOOL bShow)
  699. {
  700. m_nStateFlags &= ~(delayHide|delayShow);
  701. if (bShow && (GetStyle() & WS_VISIBLE) == 0)
  702. m_nStateFlags |= delayShow;
  703. else if (!bShow && (GetStyle() & WS_VISIBLE) != 0)
  704. m_nStateFlags |= delayHide;
  705. }
  706. BOOL CControlBar::IsVisible() const
  707. {
  708. if (m_nStateFlags & delayHide)
  709. return FALSE;
  710. if ((m_nStateFlags & delayShow) || ((GetStyle() & WS_VISIBLE) != 0))
  711. return TRUE;
  712. return FALSE;
  713. }
  714. void CControlBar::DoPaint(CDC* pDC)
  715. {
  716. ASSERT_VALID(this);
  717. ASSERT_VALID(pDC);
  718. // paint inside client area
  719. CRect rect;
  720. GetClientRect(rect);
  721. DrawBorders(pDC, rect);
  722. DrawGripper(pDC, rect);
  723. }
  724. void CControlBar::DrawBorders(CDC* pDC, CRect& rect)
  725. {
  726. ASSERT_VALID(this);
  727. ASSERT_VALID(pDC);
  728. DWORD dwStyle = m_dwStyle;
  729. if (!(dwStyle & CBRS_BORDER_ANY))
  730. return;
  731. // prepare for dark lines
  732. ASSERT(rect.top == 0 && rect.left == 0);
  733. CRect rect1, rect2;
  734. rect1 = rect;
  735. rect2 = rect;
  736. COLORREF clr = afxData.bWin4 ? afxData.clrBtnShadow : afxData.clrWindowFrame;
  737. // draw dark line one pixel back/up
  738. if (dwStyle & CBRS_BORDER_3D)
  739. {
  740. rect1.right -= CX_BORDER;
  741. rect1.bottom -= CY_BORDER;
  742. }
  743. if (dwStyle & CBRS_BORDER_TOP)
  744. rect2.top += afxData.cyBorder2;
  745. if (dwStyle & CBRS_BORDER_BOTTOM)
  746. rect2.bottom -= afxData.cyBorder2;
  747. // draw left and top
  748. if (dwStyle & CBRS_BORDER_LEFT)
  749. pDC->FillSolidRect(0, rect2.top, CX_BORDER, rect2.Height(), clr);
  750. if (dwStyle & CBRS_BORDER_TOP)
  751. pDC->FillSolidRect(0, 0, rect.right, CY_BORDER, clr);
  752. // draw right and bottom
  753. if (dwStyle & CBRS_BORDER_RIGHT)
  754. pDC->FillSolidRect(rect1.right, rect2.top, -CX_BORDER, rect2.Height(), clr);
  755. if (dwStyle & CBRS_BORDER_BOTTOM)
  756. pDC->FillSolidRect(0, rect1.bottom, rect.right, -CY_BORDER, clr);
  757. if (dwStyle & CBRS_BORDER_3D)
  758. {
  759. // prepare for hilite lines
  760. clr = afxData.clrBtnHilite;
  761. // draw left and top
  762. if (dwStyle & CBRS_BORDER_LEFT)
  763. pDC->FillSolidRect(1, rect2.top, CX_BORDER, rect2.Height(), clr);
  764. if (dwStyle & CBRS_BORDER_TOP)
  765. pDC->FillSolidRect(0, 1, rect.right, CY_BORDER, clr);
  766. // draw right and bottom
  767. if (dwStyle & CBRS_BORDER_RIGHT)
  768. pDC->FillSolidRect(rect.right, rect2.top, -CX_BORDER, rect2.Height(), clr);
  769. if (dwStyle & CBRS_BORDER_BOTTOM)
  770. pDC->FillSolidRect(0, rect.bottom, rect.right, -CY_BORDER, clr);
  771. }
  772. if (dwStyle & CBRS_BORDER_LEFT)
  773. rect.left += afxData.cxBorder2;
  774. if (dwStyle & CBRS_BORDER_TOP)
  775. rect.top += afxData.cyBorder2;
  776. if (dwStyle & CBRS_BORDER_RIGHT)
  777. rect.right -= afxData.cxBorder2;
  778. if (dwStyle & CBRS_BORDER_BOTTOM)
  779. rect.bottom -= afxData.cyBorder2;
  780. }
  781. #define CX_GRIPPER 3
  782. #define CY_GRIPPER 3
  783. #define CX_BORDER_GRIPPER 2
  784. #define CY_BORDER_GRIPPER 2
  785. void CControlBar::DrawGripper(CDC* pDC, const CRect& rect)
  786. {
  787. // only draw the gripper if not floating and gripper is specified
  788. if ((m_dwStyle & (CBRS_GRIPPER|CBRS_FLOATING)) == CBRS_GRIPPER)
  789. {
  790. // draw the gripper in the border
  791. if (m_dwStyle & CBRS_ORIENT_HORZ)
  792. {
  793. pDC->Draw3dRect(rect.left+CX_BORDER_GRIPPER,
  794. rect.top+m_cyTopBorder,
  795. CX_GRIPPER, rect.Height()-m_cyTopBorder-m_cyBottomBorder,
  796. afxData.clrBtnHilite, afxData.clrBtnShadow);
  797. }
  798. else
  799. {
  800. pDC->Draw3dRect(rect.left+m_cyTopBorder,
  801. rect.top+CY_BORDER_GRIPPER,
  802. rect.Width()-m_cyTopBorder-m_cyBottomBorder, CY_GRIPPER,
  803. afxData.clrBtnHilite, afxData.clrBtnShadow);
  804. }
  805. }
  806. }
  807. // input CRect should be client rectangle size
  808. void CControlBar::CalcInsideRect(CRect& rect, BOOL bHorz) const
  809. {
  810. ASSERT_VALID(this);
  811. DWORD dwStyle = m_dwStyle;
  812. if (dwStyle & CBRS_BORDER_LEFT)
  813. rect.left += afxData.cxBorder2;
  814. if (dwStyle & CBRS_BORDER_TOP)
  815. rect.top += afxData.cyBorder2;
  816. if (dwStyle & CBRS_BORDER_RIGHT)
  817. rect.right -= afxData.cxBorder2;
  818. if (dwStyle & CBRS_BORDER_BOTTOM)
  819. rect.bottom -= afxData.cyBorder2;
  820. // inset the top and bottom.
  821. if (bHorz)
  822. {
  823. rect.left += m_cxLeftBorder;
  824. rect.top += m_cyTopBorder;
  825. rect.right -= m_cxRightBorder;
  826. rect.bottom -= m_cyBottomBorder;
  827. if ((m_dwStyle & (CBRS_GRIPPER|CBRS_FLOATING)) == CBRS_GRIPPER)
  828. rect.left += CX_BORDER_GRIPPER+CX_GRIPPER+CX_BORDER_GRIPPER;
  829. }
  830. else
  831. {
  832. rect.left += m_cyTopBorder;
  833. rect.top += m_cxLeftBorder;
  834. rect.right -= m_cyBottomBorder;
  835. rect.bottom -= m_cxRightBorder;
  836. if ((m_dwStyle & (CBRS_GRIPPER|CBRS_FLOATING)) == CBRS_GRIPPER)
  837. rect.top += CY_BORDER_GRIPPER+CY_GRIPPER+CY_BORDER_GRIPPER;
  838. }
  839. }
  840. /////////////////////////////////////////////////////////////////////////////
  841. // CControlBar diagnostics
  842. #ifdef _DEBUG
  843. void CControlBar::AssertValid() const
  844. {
  845. CWnd::AssertValid();
  846. ASSERT(m_nCount == 0 || m_pData != NULL);
  847. ASSERT((m_dwStyle & CBRS_ALL) == m_dwStyle);
  848. }
  849. void CControlBar::Dump(CDumpContext& dc) const
  850. {
  851. CWnd::Dump(dc);
  852. dc << "\nm_cxLeftBorder = " << m_cxLeftBorder;
  853. dc << "\nm_cxRightBorder = " << m_cxRightBorder;
  854. dc << "\nm_cyTopBorder = " << m_cyTopBorder;
  855. dc << "\nm_cyBottomBorder = " << m_cyBottomBorder;
  856. dc << "\nm_cxDefaultGap = " << m_cxDefaultGap;
  857. dc << "\nm_nCount = " << m_nCount;
  858. dc << "\nm_bAutoDelete = " << m_bAutoDelete;
  859. dc << "\n";
  860. }
  861. #endif
  862. /////////////////////////////////////////////////////////////////////////////