750 lines
22 KiB
C++
750 lines
22 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) 1997 by Joerg Koenig
|
|
// All rights reserved
|
|
//
|
|
// Distribute freely, except: don't remove my name from the source or
|
|
// documentation (don't take credit for my work), mark your changes (don't
|
|
// get me blamed for your possible bugs), don't alter or remove this
|
|
// notice.
|
|
// No warrantee of any kind, express or implied, is included with this
|
|
// software; use at your own risk, responsibility for damages (if any) to
|
|
// anyone resulting from the use of this software rests entirely with the
|
|
// user.
|
|
//
|
|
// Send bug reports, bug fixes, enhancements, requests, flames, etc., and
|
|
// I'll try to keep a version up to date. I can be reached as follows:
|
|
// J.Koenig@adg.de (company site)
|
|
// Joerg.Koenig@rhein-neckar.de (private site)
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// ToolBarEx.cpp : implementation file
|
|
//
|
|
// Description:
|
|
// CToolBarEx provides additional features to the standard toolbar
|
|
// "CToolBar". The main addition is the flat mode (last seen in
|
|
// Developer Studio 5.0).
|
|
// There are no special requirements for having the flat mode in your
|
|
// application (no special comctl32.dll or what ever)!
|
|
// If you need custom draw abilities, then you have to use VC++ >= 4.2
|
|
// However, the flat mode should work with older versions of VC++ too (let
|
|
// me know of your experiences!)
|
|
//
|
|
// Usage:
|
|
// The only task you have to perform, is to
|
|
// #include "ToolBarEx.h"
|
|
// in either StdAfx.h or MainFrm.h and to change the type of
|
|
// CMainFrame::m_wndToolBar from CToolBar to CToolBarEx.
|
|
// Don't forget to recompile :-)
|
|
//
|
|
// Acknowledgements:
|
|
// o The main idea of how to draw a separator and the gripper is stolen
|
|
// from Roger Onslow's MSIE flat toolbar.
|
|
// Thanks for saving my time, Roger ;-)
|
|
// o The embossed drawing of a disabled image came from
|
|
// Victor M. Vogelpoel (victorv@telic.nl)
|
|
// o Some hints for buttons with text came from
|
|
// David Bates (bates@econ.ubc.ca)
|
|
// (I'm still thinking, text on toolbar-buttons is broken.
|
|
// That has to be tooltip's work. However, texts on buttons
|
|
// now work)
|
|
//
|
|
//
|
|
// (known) bugs and limitations:
|
|
// o the CDRF_NEWFONT notification is still untested ...
|
|
// o Assigning texts to buttons may cause the buttons to
|
|
// resize horizontally without notified by CToolBar. This
|
|
// leads to a wrong calculation inside CalcDynamicLayout()
|
|
// and CalcFixedLayout(). One could override both these
|
|
// functions in derived classes to avoid that problem,
|
|
// but that would be a greater pain ...
|
|
//
|
|
// if you find others (and have a solution for them ?!), please let me know:
|
|
// Joerg.Koenig@rhein-neckar.de (private site) or
|
|
// J.Koenig@adg.de (company site)
|
|
//
|
|
// Changes:
|
|
// 11/07/97
|
|
// (2 minor bugs have been occured as a result of the last update :)
|
|
// o The WRAP state of a separator will be ignored now, if
|
|
// the bar is docked vertically
|
|
// o Draw an image transparently. This is needed only if one
|
|
// uses 256 color images.
|
|
//
|
|
// 10/30/97
|
|
// o texts on buttons now work
|
|
// o gripper improved for a closer look like Office97
|
|
// o disabled images now look embossed
|
|
// o a separator is drawn only if it has no WRAP state set
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "ToolBarEx.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// local helper class CCustomDrawInfo
|
|
//
|
|
// The helper class CCustomDrawInfo handles the messaging to the docking
|
|
// frame of the toolbar in flat mode only. If flat-mode is disabled, then
|
|
// MFC's own messanger will be used.
|
|
//
|
|
// A few words about custom draw on toolbars:
|
|
// o custom draw is possible for MFC >= 4.2 only (older versions don't know
|
|
// anything about certain structures ...)
|
|
// o MFC does not set the "rc" member of NMCUSTOMDRAW to the rectangle of the
|
|
// button that will be drawn. However, we do, so watch out, wether the
|
|
// toolbar is flat or not (or ignore the "rc" member in both cases).
|
|
// If the current mode is not "flat", then MFC's art of message arrives ...
|
|
// o MFC does not send a message for separators, so we too don't do it.
|
|
// o It seems that MFC toolbars never send *ERASE notifications; instead they
|
|
// send TBN_QUERYDELETE for instance.
|
|
// o The CDRF_NEWFONT notification result is ignored (in flat mode. Never
|
|
// tried with original MFC, because it is broken on toolbars).
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CCustomDrawInfo {
|
|
|
|
#if _MFC_VER >= 0x0420
|
|
NMCUSTOMDRAW m_CDRW; // custom draw information holder
|
|
LRESULT m_PrePaint; // result from prepaint notification
|
|
LRESULT m_ItemPrePaint; // dito for specific item
|
|
CToolBarEx * m_pToolBar; // the real sender of the notification
|
|
CWnd * m_pReceiver; // the receiver of the notification
|
|
|
|
LRESULT NotifyParent();
|
|
#endif // _MFC_VER
|
|
|
|
public: // construction
|
|
CCustomDrawInfo( CDC & dc, CToolBarEx * pToolBar );
|
|
|
|
public:
|
|
// NotifyItemPrePaint() returns TRUE,
|
|
// if the user wants to do the default
|
|
// (CDRF_DODEFAULT) or FALSE, if the
|
|
// user wants to skip (CDRF_SKIPDEFAULT)
|
|
// Note that CDRF_SKIPDEFAULT is not
|
|
// allowed for CDDS_PREPAINT, CDDS_POSTPAINT !
|
|
// and CDDS_ITEMPOSTPAINT
|
|
void NotifyPrePaint();
|
|
BOOL NotifyItemPrePaint(int item);
|
|
void NotifyItemPostPaint(int item);
|
|
void NotifyPostPaint();
|
|
};
|
|
|
|
|
|
#if _MFC_VER >= 0x420
|
|
|
|
LRESULT CCustomDrawInfo :: NotifyParent() {
|
|
LRESULT lRes = CDRF_DODEFAULT;
|
|
|
|
if( m_pReceiver )
|
|
lRes = m_pReceiver->SendMessage(WM_NOTIFY,
|
|
WPARAM(m_CDRW.hdr.idFrom),
|
|
LPARAM(&m_CDRW));
|
|
return lRes;
|
|
}
|
|
|
|
|
|
CCustomDrawInfo :: CCustomDrawInfo( CDC & dc, CToolBarEx * pBar )
|
|
: m_PrePaint(0)
|
|
, m_ItemPrePaint(0)
|
|
{
|
|
VERIFY((m_pToolBar = pBar) != 0);
|
|
VERIFY((m_CDRW.hdc = dc.GetSafeHdc()) != 0);
|
|
|
|
HWND hwnd = pBar->GetSafeHwnd();
|
|
VERIFY(::IsWindow(hwnd));
|
|
|
|
// initialise the NMHDR member of the customdraw structure
|
|
m_CDRW.hdr.hwndFrom = hwnd;
|
|
m_CDRW.hdr.idFrom = UINT(::GetWindowLong(hwnd, GWL_ID));
|
|
m_CDRW.hdr.code = NM_CUSTOMDRAW;
|
|
|
|
// Do not use CControlBar::GetDockingFrame() to receive
|
|
// the parent. CWnd::GetParent() is inacceptable too.
|
|
// Both these functions don't work, if the toolbar is
|
|
// floating in the air!
|
|
m_pReceiver = pBar->GetParentFrame();
|
|
if( m_pReceiver )
|
|
VERIFY(::IsWindow(m_pReceiver->GetSafeHwnd()));
|
|
}
|
|
|
|
void CCustomDrawInfo :: NotifyPrePaint() {
|
|
// fill the customdraw structure with values for CDDS_PREPAINT
|
|
m_CDRW.dwDrawStage = CDDS_PREPAINT;
|
|
// the rest of the structure stays undefined in this stage
|
|
// of drawing.
|
|
m_PrePaint = NotifyParent();
|
|
}
|
|
|
|
BOOL CCustomDrawInfo :: NotifyItemPrePaint( int nItem ) {
|
|
BOOL bRet = TRUE; // we assume to do the default
|
|
if( m_PrePaint & CDRF_NOTIFYITEMDRAW ) {
|
|
m_CDRW.dwDrawStage = CDDS_ITEMPREPAINT;
|
|
m_pToolBar->GetItemRect(nItem, &m_CDRW.rc);
|
|
m_CDRW.dwItemSpec = DWORD(m_pToolBar->GetItemID(nItem));
|
|
UINT uStyle = m_pToolBar->GetButtonStyle(nItem);
|
|
BOOL bEnable = m_pToolBar->GetToolBarCtrl()
|
|
.IsButtonEnabled(m_CDRW.dwItemSpec);
|
|
m_CDRW.uItemState = (bEnable ? 0 : CDIS_DISABLED) |
|
|
(((uStyle & TBBS_PRESSED) || (uStyle & TBBS_CHECKED)) ?
|
|
CDIS_CHECKED : 0);
|
|
m_CDRW.lItemlParam = 0;
|
|
m_ItemPrePaint = NotifyParent();
|
|
if( m_ItemPrePaint & CDRF_SKIPDEFAULT )
|
|
bRet = FALSE;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
void CCustomDrawInfo :: NotifyItemPostPaint( int nItem ) {
|
|
if( m_ItemPrePaint & CDRF_NOTIFYPOSTPAINT ) {
|
|
m_CDRW.dwDrawStage = CDDS_ITEMPOSTPAINT;
|
|
// the rest of the data has not been changed since ITEMPREPAINT
|
|
// make sure it is so:
|
|
ASSERT(m_pToolBar->GetItemID(nItem) == m_CDRW.dwItemSpec);
|
|
NotifyParent();
|
|
}
|
|
}
|
|
|
|
void CCustomDrawInfo :: NotifyPostPaint() {
|
|
if( m_PrePaint & CDRF_NOTIFYPOSTPAINT ) {
|
|
m_CDRW.dwDrawStage = CDDS_POSTPAINT;
|
|
NotifyParent();
|
|
}
|
|
}
|
|
|
|
#else // _MFC_VER < 4.2
|
|
|
|
CCustomDrawInfo :: CCustomDrawInfo( CDC & dc, CWnd * pParent ) {
|
|
}
|
|
|
|
void CCustomDrawInfo :: NotifyPrePaint() {
|
|
}
|
|
|
|
void CCustomDrawInfo :: NotifyPostPaint() {
|
|
}
|
|
|
|
BOOL CCustomDrawInfo :: NotifyItemPrePaint( int ) {
|
|
return TRUE; // we always make the drawing by ourself
|
|
}
|
|
|
|
void CCustomDrawInfo :: NotifyItemPostPaint( int ) {
|
|
}
|
|
|
|
#endif // _MFC_VER
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CToolBarEx
|
|
|
|
CToolBarEx::CToolBarEx()
|
|
: m_bFlatLook(TRUE)
|
|
, m_clrBtnFace(::GetSysColor(COLOR_BTNFACE))
|
|
, m_clrBtnHilight(::GetSysColor(COLOR_BTNHILIGHT))
|
|
, m_clrBtnShadow(::GetSysColor(COLOR_BTNSHADOW))
|
|
, m_nLastBtn(-1)
|
|
, m_uTimerEvent(0)
|
|
{
|
|
CalculateOffset();
|
|
|
|
// create the default font, used for buttons with text
|
|
CFont Font;
|
|
BOOL bOldSys = FALSE;
|
|
if( ! Font.CreateStockObject( DEFAULT_GUI_FONT ) ) {
|
|
// older versions of Windows* (NT 3.51 for instance)
|
|
// fail with DEFAULT_GUI_FONT
|
|
VERIFY( Font.CreateStockObject( SYSTEM_FONT ) );
|
|
bOldSys = TRUE;
|
|
}
|
|
LOGFONT logfont ;
|
|
Font.GetLogFont( &logfont ) ;
|
|
if( bOldSys ) {
|
|
logfont.lfWeight = 400;
|
|
strcpy(logfont.lfFaceName,_T("MS Sans Serif"));
|
|
}
|
|
logfont.lfHeight = 6 ;
|
|
logfont.lfWidth = 0 ; // let windows compute this.
|
|
VERIFY( m_GuiFont.CreateFontIndirect( &logfont ) ) ;
|
|
}
|
|
|
|
CToolBarEx::~CToolBarEx()
|
|
{
|
|
}
|
|
|
|
|
|
IMPLEMENT_DYNAMIC(CToolBarEx, CToolBar)
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CToolBarEx, CToolBar)
|
|
//{{AFX_MSG_MAP(CToolBarEx)
|
|
ON_WM_PAINT()
|
|
ON_WM_SYSCOLORCHANGE()
|
|
ON_WM_NCCALCSIZE()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_NCPAINT()
|
|
ON_WM_TIMER()
|
|
ON_WM_CREATE()
|
|
//}}AFX_MSG_MAP
|
|
ON_MESSAGE(TB_SETBUTTONSIZE, OnSetButtonSize)
|
|
ON_MESSAGE(TB_SETBITMAPSIZE, OnSetBitmapSize)
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CToolBarEx message handlers
|
|
|
|
LRESULT CToolBarEx :: OnSetButtonSize(WPARAM wParam, LPARAM lParam) {
|
|
LRESULT lResult = CToolBar::OnSetButtonSize(wParam, lParam);
|
|
if( lResult )
|
|
CalculateOffset();
|
|
return lResult;
|
|
}
|
|
|
|
LRESULT CToolBarEx :: OnSetBitmapSize(WPARAM wParam, LPARAM lParam) {
|
|
LRESULT lResult = CToolBar::OnSetBitmapSize(wParam, lParam);
|
|
if( lResult )
|
|
CalculateOffset();
|
|
return lResult;
|
|
}
|
|
|
|
|
|
void CToolBarEx::OnPaint()
|
|
{
|
|
HIMAGELIST hImg = GetImageList();
|
|
|
|
#ifdef _DEBUG
|
|
if( hImg == 0 ) {
|
|
TRACE0("CToolBarEx::OnPaint(): could not get image list\n");
|
|
}
|
|
#endif
|
|
|
|
if( m_bFlatLook && hImg ) {
|
|
CRect rcUpdate;
|
|
if( ! GetUpdateRect(rcUpdate) )
|
|
return;
|
|
|
|
if( m_pStringMap && !m_pStringMap->IsEmpty() )
|
|
CalculateOffset(); // strings may have been added
|
|
|
|
// attach image-list for even more MFC feeling :)
|
|
CImageList imglist;
|
|
imglist.Attach(hImg);
|
|
|
|
POINT cursor;
|
|
::GetCursorPos(&cursor);
|
|
ScreenToClient(&cursor);
|
|
|
|
CPaintDC dc(this); // device context for painting
|
|
CFont * pOldFont = dc.SelectObject(&m_GuiFont);
|
|
|
|
// Now it's time for the first custom-draw-notification...
|
|
CCustomDrawInfo cdrw(dc, this);
|
|
cdrw.NotifyPrePaint();
|
|
|
|
register const int nBtn = GetToolBarCtrl().GetButtonCount();
|
|
|
|
for( register int i = 0; i < nBtn; ++i ) {
|
|
CRect rc;
|
|
GetItemRect(i, rc);
|
|
|
|
int nBitmap; UINT uID, uStyleState;
|
|
GetButtonInfo(i, uID, uStyleState, nBitmap);
|
|
WORD wStyle = LOWORD(uStyleState);
|
|
WORD wState = HIWORD(uStyleState);
|
|
|
|
if( wState & TBSTATE_HIDDEN )
|
|
continue;
|
|
|
|
if( wStyle == TBSTYLE_SEP ) {
|
|
if( !(wState & TBSTATE_WRAP) || ! IsFloating() )
|
|
DrawSeparator(dc, rc);
|
|
} else {
|
|
if( ! CRect().IntersectRect(rcUpdate, rc) )
|
|
continue; // this button needs no repaint
|
|
|
|
// maybe the button has text
|
|
dc.SetTextColor(RGB(0,0,0));
|
|
dc.SetBkColor(m_clrBtnFace);
|
|
|
|
// There is a bug in CToolBar: If there are texts assigned
|
|
// to buttons, then the button-widths may change transparently
|
|
// (without notified by CToolBar), so we recalculate the
|
|
// horizontal offset here:
|
|
m_sizeOffset.cx = (rc.Width() - m_sizeImage.cx) / 2;
|
|
|
|
if( ! cdrw.NotifyItemPrePaint(i) )
|
|
continue; // parent has already drawn the button
|
|
|
|
BOOL bBtnDown = (wState & TBSTATE_CHECKED) || (wState & TBSTATE_PRESSED);
|
|
BOOL bBtnEnabled = GetToolBarCtrl().IsButtonEnabled(int(uID));
|
|
|
|
dc.FillSolidRect(rc,m_clrBtnFace);
|
|
|
|
// it seems, that CDC::Draw3dRect() changes the background color
|
|
COLORREF clrBk = dc.GetBkColor();
|
|
|
|
if( bBtnDown )
|
|
// draw a pressed button
|
|
dc.Draw3dRect(rc, m_clrBtnShadow, m_clrBtnHilight);
|
|
else if( rc.PtInRect(cursor) && ! bBtnDown && bBtnEnabled )
|
|
// draw a normal button
|
|
dc.Draw3dRect(rc, m_clrBtnHilight, m_clrBtnShadow);
|
|
else if( ! bBtnDown && bBtnEnabled )
|
|
// Draw an invisible rect around the button.
|
|
// This prevents us from erasing the background
|
|
// if the button was formed before
|
|
// (that would cause the button to flicker ...)
|
|
dc.Draw3dRect(rc, m_clrBtnFace, m_clrBtnFace);
|
|
|
|
dc.SetBkColor(clrBk);
|
|
|
|
// the point where to start with the image
|
|
CPoint pt(rc.left + m_sizeOffset.cx + bBtnDown,
|
|
rc.top + m_sizeOffset.cy + bBtnDown);
|
|
|
|
imglist.Draw(&dc, nBitmap, pt, ILD_TRANSPARENT);
|
|
CString strText = GetButtonText(i);
|
|
if( strText.GetLength() ) {
|
|
CRect rectText(
|
|
rc.left+3+bBtnDown,
|
|
rc.top+m_sizeOffset.cy+m_sizeImage.cy+1+bBtnDown,
|
|
rc.right-3+bBtnDown,
|
|
rc.bottom-3+bBtnDown
|
|
);
|
|
dc.DrawText(strText, rectText, DT_CENTER|DT_VCENTER|DT_NOCLIP);
|
|
}
|
|
|
|
if( ! bBtnEnabled )
|
|
// gray out that button
|
|
DrawDisabledButton(dc, rc);
|
|
|
|
cdrw.NotifyItemPostPaint(i);
|
|
}
|
|
}
|
|
|
|
dc.SelectObject(pOldFont);
|
|
|
|
if( ! m_bDeleteImgList )
|
|
imglist.Detach();
|
|
|
|
// last but not least: inform the parent for end of painting
|
|
cdrw.NotifyPostPaint();
|
|
} else
|
|
// classic mode (or couldn't receive imagelist)
|
|
CToolBar::OnPaint();
|
|
}
|
|
|
|
|
|
void CToolBarEx :: DrawDisabledButton( CDC & dc, const CRect & rc ) const {
|
|
// create a monochrome memory DC
|
|
CDC ddc;
|
|
ddc.CreateCompatibleDC(0);
|
|
CBitmap bmp;
|
|
bmp.CreateCompatibleBitmap(&ddc, rc.Width(), rc.Height());
|
|
CBitmap * pOldBmp = ddc.SelectObject(&bmp);
|
|
|
|
// build a mask
|
|
ddc.PatBlt(0, 0, rc.Width(), rc.Height(), WHITENESS);
|
|
dc.SetBkColor(m_clrBtnFace);
|
|
ddc.BitBlt(0, 0, rc.Width(), rc.Height(), &dc, rc.left, rc.top, SRCCOPY);
|
|
dc.SetBkColor(m_clrBtnHilight);
|
|
ddc.BitBlt(0, 0, rc.Width(), rc.Height(), &dc, rc.left, rc.top, SRCPAINT);
|
|
|
|
// Copy the image from the toolbar into the memory DC
|
|
// and draw it (grayed) back into the toolbar.
|
|
dc.FillSolidRect(rc.left, rc.top, rc.Width(), rc.Height(), m_clrBtnFace);
|
|
dc.SetBkColor(RGB(0, 0, 0));
|
|
dc.SetTextColor(RGB(255, 255, 255));
|
|
CBrush brShadow, brHilight;
|
|
brHilight.CreateSolidBrush(m_clrBtnHilight);
|
|
brShadow.CreateSolidBrush(m_clrBtnShadow);
|
|
CBrush * pOldBrush = dc.SelectObject(&brHilight);
|
|
dc.BitBlt(rc.left+1, rc.top+1, rc.Width(), rc.Height(), &ddc, 0, 0, 0x00E20746L);
|
|
dc.SelectObject(&brShadow);
|
|
dc.BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &ddc, 0, 0, 0x00E20746L);
|
|
|
|
// reset DCs
|
|
dc.SelectObject(pOldBrush);
|
|
ddc.SelectObject(pOldBmp);
|
|
ddc.DeleteDC();
|
|
|
|
bmp.DeleteObject();
|
|
}
|
|
|
|
|
|
void CToolBarEx :: DrawSeparator( CDC & dc, CRect & rc ) const {
|
|
BOOL bHorz = ((m_dwStyle & CBRS_ORIENT_HORZ) != 0) ? TRUE : FALSE;
|
|
// make sure, this separator is not a placeholder for
|
|
// another control.
|
|
if( rc.Width() <= 8 ) {
|
|
if( bHorz ) {
|
|
// draw the separator bar in the middle
|
|
int x = (rc.left + rc.right) / 2;
|
|
rc.left = x-1; rc.right = x+1;
|
|
dc.Draw3dRect(
|
|
rc,
|
|
m_clrBtnShadow,
|
|
m_clrBtnHilight
|
|
);
|
|
} else {
|
|
// draw the separator bar in the middle
|
|
rc.left = rc.left - m_sizeButton.cx;
|
|
rc.right = rc.left + m_sizeButton.cx;
|
|
rc.top = rc.bottom+1;
|
|
rc.bottom = rc.top+3;
|
|
int y = (rc.top+rc.bottom)/2;
|
|
rc.top = y-1; rc.bottom = y+1;
|
|
dc.Draw3dRect(
|
|
rc,
|
|
m_clrBtnShadow,
|
|
m_clrBtnHilight
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CToolBarEx :: DrawGripper( CDC & dc ) const {
|
|
if( m_dwStyle & CBRS_FLOATING )
|
|
return; // no gripper if floating
|
|
|
|
CRect gripper;
|
|
GetWindowRect(gripper);
|
|
ScreenToClient(gripper);
|
|
gripper.OffsetRect(-gripper.left, -gripper.top);
|
|
|
|
if( m_dwStyle & CBRS_ORIENT_HORZ ) {
|
|
// gripper at left
|
|
gripper.DeflateRect(4, 4);
|
|
gripper.right = gripper.left+3;
|
|
dc.Draw3dRect(
|
|
gripper,
|
|
m_clrBtnHilight,
|
|
m_clrBtnShadow
|
|
);
|
|
gripper.OffsetRect(3, 0);
|
|
dc.Draw3dRect(
|
|
gripper,
|
|
m_clrBtnHilight,
|
|
m_clrBtnShadow
|
|
);
|
|
} else {
|
|
// gripper at top
|
|
gripper.DeflateRect(4, 4);
|
|
gripper.bottom = gripper.top+3;
|
|
dc.Draw3dRect(
|
|
gripper,
|
|
m_clrBtnHilight,
|
|
m_clrBtnShadow
|
|
);
|
|
gripper.OffsetRect(0, 3);
|
|
dc.Draw3dRect(
|
|
gripper,
|
|
m_clrBtnHilight,
|
|
m_clrBtnShadow
|
|
);
|
|
}
|
|
}
|
|
|
|
void CToolBarEx :: OnUpdateCmdUI( CFrameWnd* pTarget, BOOL bDisableIfNoHndler ) {
|
|
if( m_bFlatLook ) {
|
|
// save current styles
|
|
register const int nBtn = GetToolBarCtrl().GetButtonCount();
|
|
register int nIdx;
|
|
for( nIdx = 0; nIdx < nBtn; ++nIdx )
|
|
m_Styles.SetAtGrow(nIdx, GetButtonStyle(nIdx));
|
|
|
|
// do base class processing
|
|
CToolBar::OnUpdateCmdUI(pTarget,bDisableIfNoHndler);
|
|
|
|
//check wether styles have been changed
|
|
for( nIdx = 0; nIdx < nBtn; ++nIdx ) {
|
|
if( m_Styles[nIdx] != GetButtonStyle(nIdx) ) {
|
|
// invalidate that button
|
|
CRect rc;
|
|
GetItemRect(nIdx, rc);
|
|
InvalidateRect(rc);
|
|
}
|
|
}
|
|
} else
|
|
// simply delegate
|
|
CToolBar::OnUpdateCmdUI(pTarget,bDisableIfNoHndler);
|
|
}
|
|
|
|
void CToolBarEx::OnSysColorChange()
|
|
{
|
|
CToolBar::OnSysColorChange();
|
|
|
|
m_clrBtnFace = ::GetSysColor(COLOR_BTNFACE);
|
|
m_clrBtnHilight = ::GetSysColor(COLOR_BTNHILIGHT);
|
|
m_clrBtnShadow = ::GetSysColor(COLOR_BTNSHADOW);
|
|
}
|
|
|
|
|
|
void CToolBarEx::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp)
|
|
{
|
|
CToolBar::OnNcCalcSize(bCalcValidRects, lpncsp);
|
|
// adjust non-client area for gripper at left or top
|
|
if( m_dwStyle & CBRS_ORIENT_HORZ ) {
|
|
lpncsp->rgrc[0].left += 4;
|
|
lpncsp->rgrc[0].right += 4;
|
|
} else {
|
|
lpncsp->rgrc[0].top += 6;
|
|
lpncsp->rgrc[0].bottom += 6;
|
|
}
|
|
}
|
|
|
|
|
|
void CToolBarEx::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
if( m_bFlatLook ) {
|
|
register const int nBtn = GetToolBarCtrl().GetButtonCount();
|
|
const int nLastBtn = m_nLastBtn;
|
|
m_nLastBtn = -1;
|
|
|
|
for( register int i = 0 ; i < nBtn ; ++i ) {
|
|
CRect rc;
|
|
GetItemRect(i, rc);
|
|
|
|
const BOOL bBtnEnabled = GetToolBarCtrl().IsButtonEnabled(int(GetItemID(i)));
|
|
const BOOL bSep = GetButtonStyle(i) & TBBS_SEPARATOR;
|
|
|
|
if( bSep || ! bBtnEnabled )
|
|
continue;
|
|
|
|
const BOOL bHasCursor = rc.PtInRect(point);
|
|
|
|
if( bHasCursor && bBtnEnabled ) {
|
|
if( nLastBtn != i ) {
|
|
// force a repaint of the button with the cursor on it
|
|
InvalidateRect(rc, FALSE);
|
|
}
|
|
m_nLastBtn = i;
|
|
} else if( !bHasCursor && i == nLastBtn ) {
|
|
// force a repaint of the last formed button
|
|
InvalidateRect(rc, FALSE);
|
|
}
|
|
}
|
|
// One problem occures with WM_MOUSEMOVE: we cannot detect
|
|
// that the mouse leaves the window. If the mouse moves quick
|
|
// enough, then the last formed button stays visible. To
|
|
// resolve this problem, we set a timer and check, wether
|
|
// the mouse is outside the window ...
|
|
KillTimer(m_uTimerEvent);
|
|
m_uTimerEvent = SetTimer(1, 250, 0);
|
|
}
|
|
CToolBar::OnMouseMove(nFlags, point);
|
|
}
|
|
|
|
|
|
void CToolBarEx::OnNcPaint()
|
|
{
|
|
if( m_bFlatLook ) {
|
|
CToolBar::EraseNonClient();
|
|
CWindowDC dc(this);
|
|
DrawGripper(dc);
|
|
} else
|
|
CToolBar::OnNcPaint();
|
|
}
|
|
|
|
void CToolBarEx::OnTimer(UINT nIDEvent)
|
|
{
|
|
if( nIDEvent == m_uTimerEvent && m_nLastBtn >= 0 ) {
|
|
POINT pt;
|
|
::GetCursorPos(&pt);
|
|
CRect rc;
|
|
GetWindowRect(rc);
|
|
if( ! rc.PtInRect(pt) ) {
|
|
GetItemRect(m_nLastBtn, rc);
|
|
InvalidateRect(rc, FALSE);
|
|
m_nLastBtn = -1;
|
|
KillTimer(nIDEvent);
|
|
}
|
|
} else
|
|
CToolBar::OnTimer(nIDEvent);
|
|
}
|
|
|
|
int CToolBarEx::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
|
{
|
|
if (CToolBar::OnCreate(lpCreateStruct) == -1)
|
|
return -1;
|
|
|
|
// Save the parent at creation time. It may change, if
|
|
// the toolbar is floating; but we want to know of the
|
|
// "real" parent (for notification messages)!
|
|
m_hwndParent = lpCreateStruct->hwndParent;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define PADWIDTH(x) (((x)*8+31)&~31)/8
|
|
|
|
|
|
HIMAGELIST CToolBarEx :: GetImageList() {
|
|
m_bDeleteImgList = FALSE;
|
|
|
|
HIMAGELIST hImg = HIMAGELIST(SendMessage(TB_GETIMAGELIST));
|
|
|
|
#ifdef _DEBUG
|
|
if( hImg == 0 ) {
|
|
TRACE0("CToolBarEx::OnPaint(): could not get image list\n");
|
|
}
|
|
#endif
|
|
|
|
if( ! hImg ) {
|
|
// comctl32.dll version prior to 4.70 doesn't know
|
|
// anything of the TB_GETIMAGELIST message
|
|
if( m_hbmImageWell != 0 ) {
|
|
// Yup - we have a valid image.
|
|
// But beware: Do not use this bitmap directly.
|
|
// We make the copy by ourself. CopyImage() (for
|
|
// instace) produces inacceptable copies under
|
|
// some circumstances ...
|
|
CImageList imglist;
|
|
CBitmap bmp;
|
|
|
|
// retrieve the size of the bitmap
|
|
BITMAP bmHdr;
|
|
::GetObject(m_hbmImageWell, sizeof(BITMAP), &bmHdr);
|
|
|
|
DWORD dwWidth, dwHeight = bmHdr.bmHeight;
|
|
|
|
if (bmHdr.bmBitsPixel > 8)
|
|
dwWidth = PADWIDTH(bmHdr.bmWidth * 3);
|
|
else
|
|
dwWidth = PADWIDTH(bmHdr.bmWidth);
|
|
|
|
// copy the bitmap
|
|
CClientDC cdc(this);
|
|
CDC dc1, dc2;
|
|
dc1.CreateCompatibleDC(&cdc);
|
|
dc2.CreateCompatibleDC(&cdc);
|
|
bmp.CreateCompatibleBitmap(&cdc, dwWidth, dwHeight);
|
|
CBitmap * pOBmp = dc1.SelectObject(&bmp);
|
|
HGDIOBJ hOObj = ::SelectObject(dc2.GetSafeHdc(), m_hbmImageWell);
|
|
dc1.BitBlt(0,0,dwWidth,dwHeight,&dc2,0,0,SRCCOPY);
|
|
::SelectObject(dc2.GetSafeHdc(), hOObj);
|
|
dc1.SelectObject(pOBmp);
|
|
dc1.DeleteDC();
|
|
dc2.DeleteDC();
|
|
|
|
imglist.Create(m_sizeImage.cx, m_sizeImage.cy,TRUE,dwWidth/m_sizeImage.cx,1);
|
|
imglist.SetBkColor(m_clrBtnFace);
|
|
imglist.Add(&bmp,m_clrBtnFace);
|
|
hImg = imglist.Detach();
|
|
bmp.DeleteObject();
|
|
m_bDeleteImgList = TRUE;
|
|
}
|
|
}
|
|
|
|
return hImg;
|
|
}
|