ToolBarEx.cpp
上传用户:ljqmhy0909
上传日期:2007-01-02
资源大小:185k
文件大小:24k
源码类别:

工具条

开发平台:

Visual C++

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1997 by Joerg Koenig
  3. // All rights reserved
  4. //
  5. // Distribute freely, except: don't remove my name from the source or
  6. // documentation (don't take credit for my work), mark your changes (don't
  7. // get me blamed for your possible bugs), don't alter or remove this
  8. // notice.
  9. // No warrantee of any kind, express or implied, is included with this
  10. // software; use at your own risk, responsibility for damages (if any) to
  11. // anyone resulting from the use of this software rests entirely with the
  12. // user.
  13. //
  14. // Send bug reports, bug fixes, enhancements, requests, flames, etc., and
  15. // I'll try to keep a version up to date.  I can be reached as follows:
  16. //    J.Koenig@adg.de                 (company site)
  17. //    Joerg.Koenig@rhein-neckar.de    (private site)
  18. /////////////////////////////////////////////////////////////////////////////
  19. // ToolBarEx.cpp : implementation file
  20. //
  21. // Description:
  22. // CToolBarEx provides additional features to the standard toolbar
  23. // "CToolBar". The main addition is the flat mode (last seen in
  24. // Developer Studio 5.0).
  25. // There are no special requirements for having the flat mode in your
  26. // application (no special comctl32.dll or what ever)!
  27. // If you need custom draw abilities, then you have to use VC++ >= 4.2
  28. // However, the flat mode should work with older versions of VC++ too (let
  29. // me know of your experiences!)
  30. //
  31. // Usage:
  32. // The only task you have to perform, is to
  33. // #include "ToolBarEx.h"
  34. // in either StdAfx.h or MainFrm.h and to change the type of
  35. // CMainFrame::m_wndToolBar from CToolBar to CToolBarEx.
  36. // Don't forget to recompile :-)
  37. //
  38. // Acknowledgements:
  39. // o The main idea of how to draw a separator and the gripper is stolen
  40. // from Roger Onslow's MSIE flat toolbar.
  41. // Thanks for saving my time, Roger ;-)
  42. // o The embossed drawing of a disabled image came from
  43. // Victor M. Vogelpoel (victorv@telic.nl)
  44. // o Some hints for buttons with text came from
  45. // David Bates (bates@econ.ubc.ca)
  46. // (I'm still thinking, text on toolbar-buttons is broken.
  47. // That has to be tooltip's work. However, texts on buttons
  48. // now work)
  49. // o Thanks to Patrick Liechty (patrickl@code3.code3.com) for
  50. // the reports of his experiences with VC++ 4.0/4.1
  51. // o Thanks to Jeng-Yuan Sheu (m8501511@chu.edu.tw) for the
  52. // enhanced checked button.
  53. // o Thanks to Todd C. Wilson (todd@mediatec.com) for his
  54. // bug report and code-enhancement for users of VC++ 4.2b
  55. //
  56. //
  57. // (known) bugs and limitations:
  58. // o the CDRF_NEWFONT notification is still untested ...
  59. // o Assigning texts to buttons may cause the buttons to
  60. // resize horizontally without notified by CToolBar. This
  61. // leads to a wrong calculation inside CalcDynamicLayout()
  62. // and CalcFixedLayout(). One could override both these
  63. // functions in derived classes to avoid that problem,
  64. // but that would be a greater pain ...
  65. // o some features of the toolbars seen in Office97/DevStudio
  66. // are not implemented (for instance text-only buttons or
  67. // the way how image+text buttons are displayed. The Alt-drag
  68. // feature too is unimplemented)
  69. //
  70. // if you find others (and have a solution for them ?!), please let me know:
  71. // Joerg.Koenig@rhein-neckar.de (private site) or
  72. // J.Koenig@adg.de (company site)
  73. //
  74. // Changes:
  75. // 11/25/97
  76. // o Some minor modifications to compile with VC++ 4.0/4.1 and 4.2b
  77. // o checked buttons now look hilighted (as in Office97/DevStudio)
  78. //
  79. // 11/07/97
  80. // (2 minor bugs have been occured as a result of the last update :)
  81. // o The WRAP state of a separator will be ignored now, if
  82. // the bar is docked vertically
  83. // o Draw an image transparently. This is needed only if one
  84. // uses 256 color images.
  85. //
  86. // 10/30/97
  87. // o texts on buttons now work
  88. // o gripper improved for a closer look like Office97
  89. // o disabled images now look embossed
  90. // o a separator is drawn only if it has no WRAP state set
  91. #include "stdafx.h"
  92. #include "ToolBarEx.h"
  93. #ifdef _DEBUG
  94. #define new DEBUG_NEW
  95. #undef THIS_FILE
  96. static char THIS_FILE[] = __FILE__;
  97. #endif
  98. /////////////////////////////////////////////////////////////////////////////
  99. // local helper class CCustomDrawInfo
  100. //
  101. // The helper class CCustomDrawInfo handles the messaging to the docking
  102. // frame of the toolbar in flat mode only. If flat-mode is disabled, then
  103. // MFC's own messanger will be used.
  104. //
  105. // A few words about custom draw on toolbars:
  106. // o custom draw is possible for MFC >= 4.2 only (older versions don't know
  107. //   anything about certain structures ...)
  108. // o MFC does not set the "rc" member of NMCUSTOMDRAW to the rectangle of the
  109. //  button that will be drawn. However, we do, so watch out, wether the
  110. //  toolbar is flat or not (or ignore the "rc" member in both cases).
  111. //  If the current mode is not "flat", then MFC's art of message arrives ...
  112. // o MFC does not send a message for separators, so we too don't do it.
  113. // o It seems that MFC toolbars never send *ERASE notifications; instead they
  114. //   send TBN_QUERYDELETE for instance.
  115. // o The CDRF_NEWFONT notification result is ignored (in flat mode. Never
  116. //   tried with original MFC, because it is broken on toolbars).
  117. /////////////////////////////////////////////////////////////////////////////
  118. class CCustomDrawInfo {
  119. #if _MFC_VER >= 0x0420
  120. NMCUSTOMDRAW m_CDRW; // custom draw information holder
  121. LRESULT m_PrePaint; // result from prepaint notification
  122. LRESULT m_ItemPrePaint; // dito for specific item
  123. CToolBarEx * m_pToolBar; // the real sender of the notification
  124. CWnd * m_pReceiver; // the receiver of the notification
  125. LRESULT NotifyParent();
  126. #endif // _MFC_VER
  127. public: // construction
  128. CCustomDrawInfo( CDC & dc, CToolBarEx * pToolBar );
  129. public:
  130. // NotifyItemPrePaint() returns TRUE,
  131. // if the user wants to do the default
  132. // (CDRF_DODEFAULT) or FALSE, if the
  133. // user wants to skip (CDRF_SKIPDEFAULT)
  134. // Note that CDRF_SKIPDEFAULT is not
  135. // allowed for CDDS_PREPAINT, CDDS_POSTPAINT !
  136. // and CDDS_ITEMPOSTPAINT
  137. void NotifyPrePaint();
  138. BOOL NotifyItemPrePaint(int item);
  139. void NotifyItemPostPaint(int item);
  140. void NotifyPostPaint();
  141. };
  142. #if _MFC_VER >= 0x420
  143. LRESULT CCustomDrawInfo :: NotifyParent() {
  144. LRESULT lRes = CDRF_DODEFAULT;
  145. if( m_pReceiver )
  146. lRes = m_pReceiver->SendMessage(WM_NOTIFY,
  147. WPARAM(m_CDRW.hdr.idFrom),
  148. LPARAM(&m_CDRW));
  149. return lRes;
  150. }
  151. CCustomDrawInfo :: CCustomDrawInfo( CDC & dc, CToolBarEx * pBar )
  152. : m_PrePaint(0)
  153. , m_ItemPrePaint(0)
  154. {
  155. VERIFY((m_pToolBar = pBar) != 0);
  156. VERIFY((m_CDRW.hdc = dc.GetSafeHdc()) != 0);
  157. HWND hwnd = pBar->GetSafeHwnd();
  158. VERIFY(::IsWindow(hwnd));
  159. // initialise the NMHDR member of the customdraw structure
  160. m_CDRW.hdr.hwndFrom = hwnd;
  161. m_CDRW.hdr.idFrom = UINT(::GetWindowLong(hwnd, GWL_ID));
  162. m_CDRW.hdr.code = NM_CUSTOMDRAW;
  163. // Do not use CControlBar::GetDockingFrame() to receive
  164. // the parent. CWnd::GetParent() is inacceptable too.
  165. // Both these functions don't work, if the toolbar is
  166. // floating in the air!
  167. m_pReceiver = pBar->GetParentFrame();
  168. if( m_pReceiver )
  169. VERIFY(::IsWindow(m_pReceiver->GetSafeHwnd()));
  170. }
  171. void CCustomDrawInfo :: NotifyPrePaint() {
  172. // fill the customdraw structure with values for CDDS_PREPAINT
  173. m_CDRW.dwDrawStage = CDDS_PREPAINT;
  174. // the rest of the structure stays undefined in this stage
  175. // of drawing.
  176. m_PrePaint = NotifyParent();
  177. }
  178. BOOL CCustomDrawInfo :: NotifyItemPrePaint( int nItem ) {
  179. BOOL bRet = TRUE; // we assume to do the default
  180. if( m_PrePaint & CDRF_NOTIFYITEMDRAW ) {
  181. m_CDRW.dwDrawStage = CDDS_ITEMPREPAINT;
  182. m_pToolBar->GetItemRect(nItem, &m_CDRW.rc);
  183. m_CDRW.dwItemSpec = DWORD(m_pToolBar->GetItemID(nItem));
  184. UINT uStyle = m_pToolBar->GetButtonStyle(nItem);
  185. BOOL bEnable = m_pToolBar->GetToolBarCtrl()
  186. .IsButtonEnabled(m_CDRW.dwItemSpec);
  187. m_CDRW.uItemState = (bEnable ? 0 : CDIS_DISABLED) |
  188. (((uStyle & TBBS_PRESSED) || (uStyle & TBBS_CHECKED)) ?
  189. CDIS_CHECKED : 0);
  190. m_CDRW.lItemlParam = 0;
  191. m_ItemPrePaint = NotifyParent();
  192. if( m_ItemPrePaint & CDRF_SKIPDEFAULT )
  193. bRet = FALSE;
  194. }
  195. return bRet;
  196. }
  197. void CCustomDrawInfo :: NotifyItemPostPaint( int nItem ) {
  198. if( m_ItemPrePaint & CDRF_NOTIFYPOSTPAINT ) {
  199. m_CDRW.dwDrawStage = CDDS_ITEMPOSTPAINT;
  200. // the rest of the data has not been changed since ITEMPREPAINT
  201. // make sure it is so:
  202. ASSERT(m_pToolBar->GetItemID(nItem) == m_CDRW.dwItemSpec);
  203. NotifyParent();
  204. }
  205. }
  206. void CCustomDrawInfo :: NotifyPostPaint() {
  207. if( m_PrePaint & CDRF_NOTIFYPOSTPAINT ) {
  208. m_CDRW.dwDrawStage = CDDS_POSTPAINT;
  209. NotifyParent();
  210. }
  211. }
  212. #else // _MFC_VER < 4.2
  213. CCustomDrawInfo :: CCustomDrawInfo( CDC & dc, CToolBarEx * pParent ) {
  214. }
  215. void CCustomDrawInfo :: NotifyPrePaint() {
  216. }
  217. void CCustomDrawInfo :: NotifyPostPaint() {
  218. }
  219. BOOL CCustomDrawInfo :: NotifyItemPrePaint( int ) {
  220. return TRUE; // we always make the drawing by ourself
  221. }
  222. void CCustomDrawInfo :: NotifyItemPostPaint( int ) {
  223. }
  224. #endif // _MFC_VER
  225. /////////////////////////////////////////////////////////////////////////////
  226. // CToolBarEx
  227. CToolBarEx::CToolBarEx()
  228. : m_bFlatLook(TRUE)
  229. , m_clrBtnFace(::GetSysColor(COLOR_BTNFACE))
  230. , m_clrBtnHilight(::GetSysColor(COLOR_BTNHILIGHT))
  231. , m_clrBtnShadow(::GetSysColor(COLOR_BTNSHADOW))
  232. , m_clrBtnLight(::GetSysColor(COLOR_3DLIGHT))
  233. , m_nLastBtn(-1)
  234. , m_uTimerEvent(0)
  235. {
  236. // the systems I've tested, made no difference between
  237. // COLOR_BTNFACE and COLOR_3DLIGHT ...
  238. if( m_clrBtnFace == m_clrBtnLight )
  239. m_clrBtnLight = m_clrBtnHilight;
  240. CalculateOffset();
  241. // create the default font, used for buttons with text
  242. CFont Font;
  243. BOOL bOldSys = FALSE;
  244. if( ! Font.CreateStockObject( DEFAULT_GUI_FONT ) ) {
  245. // older versions of Windows* (NT 3.51 for instance)
  246. // fail with DEFAULT_GUI_FONT
  247. VERIFY( Font.CreateStockObject( SYSTEM_FONT ) );
  248. bOldSys = TRUE;
  249. }
  250. LOGFONT logfont ;
  251. Font.GetLogFont( &logfont ) ;
  252. if( bOldSys ) {
  253. logfont.lfWeight = 400;
  254. strcpy(logfont.lfFaceName,"MS Sans Serif");
  255. }
  256. logfont.lfHeight = 6 ;
  257. logfont.lfWidth = 0 ; // let windows compute this.
  258. VERIFY( m_GuiFont.CreateFontIndirect( &logfont ) ) ;
  259. }
  260. CToolBarEx::~CToolBarEx()
  261. {
  262. }
  263. IMPLEMENT_DYNAMIC(CToolBarEx, CToolBar)
  264. BEGIN_MESSAGE_MAP(CToolBarEx, CToolBar)
  265. //{{AFX_MSG_MAP(CToolBarEx)
  266. ON_WM_PAINT()
  267. ON_WM_SYSCOLORCHANGE()
  268. ON_WM_NCCALCSIZE()
  269. ON_WM_MOUSEMOVE()
  270. ON_WM_NCPAINT()
  271. ON_WM_TIMER()
  272. ON_WM_CREATE()
  273. //}}AFX_MSG_MAP
  274. ON_MESSAGE(TB_SETBUTTONSIZE, OnSetButtonSize)
  275. ON_MESSAGE(TB_SETBITMAPSIZE, OnSetBitmapSize)
  276. END_MESSAGE_MAP()
  277. /////////////////////////////////////////////////////////////////////////////
  278. // CToolBarEx message handlers
  279. LRESULT CToolBarEx :: OnSetButtonSize(WPARAM wParam, LPARAM lParam) {
  280. LRESULT lResult = CToolBar::OnSetButtonSize(wParam, lParam);
  281. if( lResult )
  282. CalculateOffset();
  283. return lResult;
  284. }
  285. LRESULT CToolBarEx :: OnSetBitmapSize(WPARAM wParam, LPARAM lParam) {
  286. LRESULT lResult = CToolBar::OnSetBitmapSize(wParam, lParam);
  287. if( lResult )
  288. CalculateOffset();
  289. return lResult;
  290. }
  291. void CToolBarEx::OnPaint() 
  292. {
  293. HIMAGELIST hImg = GetImageList();
  294. #ifdef _DEBUG
  295. if( hImg == 0 ) {
  296. TRACE0("CToolBarEx::OnPaint(): could not get image listn");
  297. }
  298. #endif
  299. if( m_bFlatLook && hImg ) {
  300. CRect rcUpdate;
  301. if( ! GetUpdateRect(rcUpdate) )
  302. return;
  303. if( HasButtonText() )
  304. CalculateOffset(); // strings may have been added
  305. // attach image-list for even more MFC feeling :)
  306. CImageList imglist;
  307. imglist.Attach(hImg);
  308. POINT cursor;
  309. ::GetCursorPos(&cursor);
  310. ScreenToClient(&cursor);
  311. CPaintDC dc(this); // device context for painting
  312. CFont * pOldFont = dc.SelectObject(&m_GuiFont);
  313. // Now it's time for the first custom-draw-notification...
  314. CCustomDrawInfo cdrw(dc, this);
  315. cdrw.NotifyPrePaint();
  316. register const int nBtn = GetToolBarCtrl().GetButtonCount();
  317. for( register int i = 0; i < nBtn; ++i ) {
  318. CRect rc;
  319. GetItemRect(i, rc);
  320. int nBitmap; UINT uID, uStyleState;
  321. GetButtonInfo(i, uID, uStyleState, nBitmap);
  322. WORD wStyle = LOWORD(uStyleState);
  323. WORD wState = HIWORD(uStyleState);
  324. if( wState & TBSTATE_HIDDEN )
  325. continue;
  326. if( wStyle == TBSTYLE_SEP ) {
  327. if( !(wState & TBSTATE_WRAP) || ! IsFloating() )
  328. DrawSeparator(dc, rc);
  329. } else {
  330. if( ! CRect().IntersectRect(rcUpdate, rc) )
  331. continue; // this button needs no repaint
  332. BOOL bBtnDown = (wState & TBSTATE_CHECKED) || (wState & TBSTATE_PRESSED);
  333. BOOL bBtnEnabled = GetToolBarCtrl().IsButtonEnabled(int(uID));
  334. BOOL bHasCursor = rc.PtInRect(cursor);
  335. COLORREF clrRect = (bBtnDown && !bHasCursor) ? m_clrBtnLight : m_clrBtnFace;
  336. // maybe the button has text
  337. dc.SetTextColor(RGB(0,0,0));
  338. dc.SetBkColor(clrRect);
  339. // There is a bug in CToolBar: If there are texts assigned
  340. // to buttons, then the button-widths may change transparently
  341. // (without notified by CToolBar), so we recalculate the
  342. // horizontal offset here:
  343. m_sizeOffset.cx = (rc.Width() - m_sizeImage.cx) / 2;
  344. if( ! cdrw.NotifyItemPrePaint(i) )
  345. continue; // parent has already drawn the button
  346. dc.FillSolidRect(rc, clrRect);
  347. //CBrush brush(clrRect);
  348. //dc.FillRect(rc, &brush);
  349. // it seems, that CDC::Draw3dRect() changes the background color
  350. COLORREF clrBk = dc.GetBkColor();
  351. if( bBtnDown ) {
  352. // draw a pressed button
  353. dc.Draw3dRect(rc, m_clrBtnShadow, m_clrBtnHilight);
  354. if( ! bHasCursor ) {
  355. // draw an invisible frame around the hilighted area
  356. CRect rcCheck = rc;
  357. rcCheck.DeflateRect(1,1);
  358. dc.Draw3dRect(rcCheck, m_clrBtnFace, m_clrBtnFace);
  359. }
  360. } else if( bHasCursor && ! bBtnDown && bBtnEnabled )
  361. // draw a normal button
  362. dc.Draw3dRect(rc, m_clrBtnHilight, m_clrBtnShadow);
  363. else if( ! bBtnDown && bBtnEnabled )
  364. // Draw an invisible rect around the button.
  365. // This prevents us from erasing the background
  366. // if the button was formed before
  367. // (that would cause the button to flicker ...)
  368. dc.Draw3dRect(rc, m_clrBtnFace, m_clrBtnFace);
  369. dc.SetBkColor(clrBk);
  370. // the point where to start with the image
  371. CPoint pt(rc.left + m_sizeOffset.cx + bBtnDown,
  372.   rc.top + m_sizeOffset.cy + bBtnDown);
  373. imglist.Draw(&dc, nBitmap, pt, ILD_TRANSPARENT);
  374. CString strText = GetButtonText(i);
  375. if( strText.GetLength() ) {
  376. CRect rectText(
  377. rc.left+3+bBtnDown,
  378. rc.top+m_sizeOffset.cy+m_sizeImage.cy+1+bBtnDown,
  379. rc.right-3+bBtnDown,
  380. rc.bottom-3+bBtnDown
  381. );
  382. dc.DrawText(strText, rectText, DT_CENTER|DT_VCENTER|DT_NOCLIP);
  383. }
  384. if( ! bBtnEnabled )
  385. // gray out that button
  386. DrawDisabledButton(dc, rc);
  387. cdrw.NotifyItemPostPaint(i);
  388. }
  389. }
  390. dc.SelectObject(pOldFont);
  391. if( ! m_bDeleteImgList )
  392. imglist.Detach();
  393. // last but not least: inform the parent for end of painting
  394. cdrw.NotifyPostPaint();
  395. } else
  396. // classic mode (or couldn't receive imagelist)
  397. CToolBar::OnPaint();
  398. }
  399. void CToolBarEx :: DrawDisabledButton( CDC & dc, const CRect & rc ) const {
  400. // create a monochrome memory DC
  401. CDC ddc;
  402. ddc.CreateCompatibleDC(0);
  403. CBitmap bmp;
  404. bmp.CreateCompatibleBitmap(&ddc, rc.Width(), rc.Height());
  405. CBitmap * pOldBmp = ddc.SelectObject(&bmp);
  406. // build a mask
  407. ddc.PatBlt(0, 0, rc.Width(), rc.Height(), WHITENESS);
  408. dc.SetBkColor(m_clrBtnFace);
  409. ddc.BitBlt(0, 0, rc.Width(), rc.Height(), &dc, rc.left, rc.top, SRCCOPY);
  410. dc.SetBkColor(m_clrBtnHilight);
  411. ddc.BitBlt(0, 0, rc.Width(), rc.Height(), &dc, rc.left, rc.top, SRCPAINT);
  412. // Copy the image from the toolbar into the memory DC
  413. // and draw it (grayed) back into the toolbar.
  414. dc.FillSolidRect(rc.left, rc.top, rc.Width(), rc.Height(), m_clrBtnFace);
  415. dc.SetBkColor(RGB(0, 0, 0));
  416. dc.SetTextColor(RGB(255, 255, 255));
  417. CBrush brShadow, brHilight;
  418. brHilight.CreateSolidBrush(m_clrBtnHilight);
  419. brShadow.CreateSolidBrush(m_clrBtnShadow);
  420. CBrush * pOldBrush = dc.SelectObject(&brHilight);
  421. dc.BitBlt(rc.left+1, rc.top+1, rc.Width(), rc.Height(), &ddc, 0, 0, 0x00E20746L);
  422. dc.SelectObject(&brShadow);
  423. dc.BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &ddc, 0, 0, 0x00E20746L);
  424. // reset DCs
  425. dc.SelectObject(pOldBrush);
  426. ddc.SelectObject(pOldBmp);
  427. ddc.DeleteDC();
  428. bmp.DeleteObject();
  429. }
  430. void CToolBarEx :: DrawSeparator( CDC & dc, CRect & rc ) const {
  431.     BOOL bHorz = ((m_dwStyle & CBRS_ORIENT_HORZ) != 0) ? TRUE : FALSE;
  432. // make sure, this separator is not a placeholder for
  433. // another control.
  434. if( rc.Width() <= 8 ) {
  435. if( bHorz ) {
  436. // draw the separator bar in the middle
  437. int x = (rc.left + rc.right) / 2;
  438. rc.left = x-1; rc.right = x+1;
  439. dc.Draw3dRect(
  440. rc,
  441. m_clrBtnShadow,
  442. m_clrBtnHilight
  443. );
  444. } else {
  445. // draw the separator bar in the middle
  446. rc.left = rc.left - m_sizeButton.cx;
  447. rc.right = rc.left + m_sizeButton.cx;
  448. rc.top = rc.bottom+1;
  449. rc.bottom = rc.top+3;
  450. int y = (rc.top+rc.bottom)/2;
  451. rc.top = y-1; rc.bottom = y+1;
  452. dc.Draw3dRect(
  453. rc,
  454. m_clrBtnShadow,
  455. m_clrBtnHilight
  456. );
  457. }
  458. }
  459. }
  460. void CToolBarEx :: DrawGripper( CDC & dc ) const { 
  461.     if( m_dwStyle & CBRS_FLOATING )
  462. return; // no gripper if floating
  463. CRect gripper;
  464. GetWindowRect(gripper);
  465. ScreenToClient(gripper);
  466. gripper.OffsetRect(-gripper.left, -gripper.top);
  467. if( m_dwStyle & CBRS_ORIENT_HORZ ) {
  468. // gripper at left
  469. gripper.DeflateRect(4, 4);
  470. gripper.right = gripper.left+3;
  471.         dc.Draw3dRect(
  472. gripper,
  473. m_clrBtnHilight,
  474.             m_clrBtnShadow
  475. );
  476. gripper.OffsetRect(3, 0);
  477.         dc.Draw3dRect(
  478. gripper,
  479. m_clrBtnHilight,
  480.             m_clrBtnShadow
  481. );
  482. } else {
  483. // gripper at top
  484. gripper.DeflateRect(4, 4);
  485. gripper.bottom = gripper.top+3;
  486. dc.Draw3dRect(
  487. gripper,
  488. m_clrBtnHilight,
  489.             m_clrBtnShadow
  490. );
  491. gripper.OffsetRect(0, 3);
  492.         dc.Draw3dRect(
  493. gripper,
  494. m_clrBtnHilight,
  495.             m_clrBtnShadow
  496. );
  497. }
  498. }
  499. void CToolBarEx :: OnUpdateCmdUI( CFrameWnd* pTarget, BOOL bDisableIfNoHndler ) {
  500. if( m_bFlatLook ) {
  501. // save current styles
  502. register const int nBtn = GetToolBarCtrl().GetButtonCount();
  503. register int nIdx;
  504. for( nIdx = 0; nIdx < nBtn; ++nIdx )
  505. m_Styles.SetAtGrow(nIdx, GetButtonStyle(nIdx));
  506. // do base class processing
  507. CToolBar::OnUpdateCmdUI(pTarget,bDisableIfNoHndler);
  508. //check wether styles have been changed
  509. for( nIdx = 0; nIdx < nBtn; ++nIdx ) {
  510. if( m_Styles[nIdx] != GetButtonStyle(nIdx) ) {
  511. // invalidate that button
  512. CRect rc;
  513. GetItemRect(nIdx, rc);
  514. InvalidateRect(rc);
  515. }
  516. }
  517. } else
  518. // simply delegate
  519. CToolBar::OnUpdateCmdUI(pTarget,bDisableIfNoHndler);
  520. }
  521. void CToolBarEx::OnSysColorChange() 
  522. {
  523. CToolBar::OnSysColorChange();
  524. m_clrBtnFace    = ::GetSysColor(COLOR_BTNFACE);
  525. m_clrBtnHilight = ::GetSysColor(COLOR_BTNHILIGHT);
  526. m_clrBtnShadow  = ::GetSysColor(COLOR_BTNSHADOW);
  527. m_clrBtnLight   = ::GetSysColor(COLOR_3DLIGHT);
  528. if( m_clrBtnFace == m_clrBtnLight )
  529. m_clrBtnLight = m_clrBtnHilight;
  530. }
  531. void CToolBarEx::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp) 
  532. {
  533. CToolBar::OnNcCalcSize(bCalcValidRects, lpncsp);
  534. // adjust non-client area for gripper at left or top
  535. if( m_dwStyle & CBRS_ORIENT_HORZ ) {
  536. lpncsp->rgrc[0].left += 4;
  537. lpncsp->rgrc[0].right += 4;
  538. } else {
  539. lpncsp->rgrc[0].top += 6;
  540. lpncsp->rgrc[0].bottom += 6;
  541. }
  542. }
  543. void CToolBarEx::OnMouseMove(UINT nFlags, CPoint point) 
  544. {
  545. if( m_bFlatLook ) {
  546. register const int nBtn = GetToolBarCtrl().GetButtonCount();
  547. const int nLastBtn = m_nLastBtn;
  548. m_nLastBtn = -1;
  549. for( register int i = 0 ; i < nBtn ; ++i ) {
  550. CRect rc;
  551. GetItemRect(i, rc);
  552. const BOOL bBtnEnabled = GetToolBarCtrl().IsButtonEnabled(int(GetItemID(i)));
  553. const BOOL bSep = GetButtonStyle(i) & TBBS_SEPARATOR;
  554. if( bSep || ! bBtnEnabled )
  555. continue;
  556. const BOOL bHasCursor = rc.PtInRect(point);
  557. if( bHasCursor && bBtnEnabled ) {
  558. if( nLastBtn != i ) {
  559. // force a repaint of the button with the cursor on it
  560. InvalidateRect(rc, FALSE);
  561. }
  562. m_nLastBtn = i;
  563. } else if( !bHasCursor && i == nLastBtn ) {
  564. // force a repaint of the last formed button
  565. InvalidateRect(rc, FALSE);
  566. }
  567. }
  568. // One problem occures with WM_MOUSEMOVE: we cannot detect
  569. // that the mouse leaves the window. If the mouse moves quick
  570. // enough, then the last formed button stays visible. To
  571. // resolve this problem, we set a timer and check, wether
  572. // the mouse is outside the window ...
  573. KillTimer(m_uTimerEvent);
  574. m_uTimerEvent = SetTimer(1, 250, 0);
  575. }
  576. CToolBar::OnMouseMove(nFlags, point);
  577. }
  578. void CToolBarEx::OnNcPaint() 
  579. {
  580. if( m_bFlatLook ) {
  581. CToolBar::EraseNonClient();
  582. CWindowDC dc(this);
  583. DrawGripper(dc);
  584. } else
  585. CToolBar::OnNcPaint();
  586. }
  587. void CToolBarEx::OnTimer(UINT nIDEvent) 
  588. {
  589. if( nIDEvent == m_uTimerEvent && m_nLastBtn >= 0 ) {
  590. POINT pt;
  591. ::GetCursorPos(&pt);
  592. CRect rc;
  593. GetWindowRect(rc);
  594. if( ! rc.PtInRect(pt) ) {
  595. GetItemRect(m_nLastBtn, rc);
  596. InvalidateRect(rc, FALSE);
  597. m_nLastBtn = -1;
  598. KillTimer(nIDEvent);
  599. }
  600. } else
  601. CToolBar::OnTimer(nIDEvent);
  602. }
  603. int CToolBarEx::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  604. {
  605. if (CToolBar::OnCreate(lpCreateStruct) == -1)
  606. return -1;
  607. // Save the parent at creation time. It may change, if
  608. // the toolbar is floating; but we want to know of the
  609. // "real" parent (for notification messages)!
  610. m_hwndParent = lpCreateStruct->hwndParent;
  611. return 0;
  612. }
  613. #define PADWIDTH(x) (((x)*8+31)&~31)/8
  614. HIMAGELIST CToolBarEx :: GetImageList() {
  615. m_bDeleteImgList = FALSE;
  616. HIMAGELIST hImg = 0;
  617. #ifdef TB_GETIMAGELIST
  618. // Some older versions of VC++ do not know of
  619. // the TB_GETIMAGELIST macro (defined in commctrl.h).
  620. hImg = HIMAGELIST(SendMessage(TB_GETIMAGELIST));
  621. #ifdef _DEBUG
  622. if( hImg == 0 ) {
  623. TRACE0("CToolBarEx::OnPaint(): could not get image listn");
  624. }
  625. #endif
  626. #endif // TB_GETIMAGELIST
  627. if( ! hImg ) {
  628. // comctl32.dll version prior to 4.70 doesn't know
  629. // anything of the TB_GETIMAGELIST message
  630. if( m_hbmImageWell != 0 ) {
  631. // Yup - we have a valid image.
  632. // But beware: Do not use this bitmap directly.
  633. // We make the copy by ourself. CopyImage() (for
  634. // instace) produces inacceptable copies under
  635. // some circumstances ...
  636. CImageList imglist;
  637. CBitmap bmp;
  638. // retrieve the size of the bitmap
  639. BITMAP bmHdr;
  640. ::GetObject(m_hbmImageWell, sizeof(BITMAP), &bmHdr);
  641. DWORD dwWidth, dwHeight = bmHdr.bmHeight;
  642. if (bmHdr.bmBitsPixel > 8)
  643. dwWidth = PADWIDTH(bmHdr.bmWidth * 3);
  644. else
  645. dwWidth = PADWIDTH(bmHdr.bmWidth);
  646. // copy the bitmap
  647. CClientDC cdc(this);
  648. CDC dc1, dc2;
  649. dc1.CreateCompatibleDC(&cdc);
  650. dc2.CreateCompatibleDC(&cdc);
  651. bmp.CreateCompatibleBitmap(&cdc, dwWidth, dwHeight);
  652. CBitmap * pOBmp = dc1.SelectObject(&bmp);
  653. HGDIOBJ hOObj = ::SelectObject(dc2.GetSafeHdc(), m_hbmImageWell);
  654. dc1.BitBlt(0,0,dwWidth,dwHeight,&dc2,0,0,SRCCOPY);
  655. ::SelectObject(dc2.GetSafeHdc(), hOObj);
  656. dc1.SelectObject(pOBmp);
  657. dc1.DeleteDC();
  658. dc2.DeleteDC();
  659. imglist.Create(m_sizeImage.cx, m_sizeImage.cy,TRUE,dwWidth/m_sizeImage.cx,1);
  660. imglist.SetBkColor(m_clrBtnFace);
  661. imglist.Add(&bmp,m_clrBtnFace);
  662. hImg = imglist.Detach();
  663. bmp.DeleteObject();
  664. m_bDeleteImgList = TRUE;
  665. }
  666. }
  667. return hImg;
  668. }