Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

608 lines
15 KiB

#include "stdafx.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CComToolBar::CComToolBar()
{
}
CToolBar::~CToolBar()
{
}
BOOL CToolBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
{
m_dwStyle = dwStyle;
if (nID == AFX_IDW_TOOLBAR)
m_dwStyle |= CBRS_HIDE_INPLACE;
// create the HWND
CRect rect;
rect.SetRectEmpty();
if (!CWnd::Create(_afxWndControlBar, NULL, dwStyle, rect, pParentWnd, nID))
return FALSE;
// Note: Parent must resize itself for control bar to be resized
return TRUE;
}
void CToolBar::SetSizes(SIZE sizeButton, SIZE sizeImage)
{
ASSERT_VALID(this);
// set height
Invalidate(); // just to be nice if called when toolbar is visible
}
void CToolBar::SetHeight(int cyHeight)
{
ASSERT_VALID(this);
int nHeight = cyHeight;
if (m_dwStyle & CBRS_BORDER_TOP)
cyHeight -= afxData.cyBorder2;
if (m_dwStyle & CBRS_BORDER_BOTTOM)
cyHeight -= afxData.cyBorder2;
m_cyBottomBorder = (cyHeight - m_sizeButton.cy) / 2;
// if there is an extra pixel, m_cyTopBorder will get it
m_cyTopBorder = cyHeight - m_sizeButton.cy - m_cyBottomBorder;
if (m_cyTopBorder < 0)
{
TRACE1("Warning: CToolBar::SetHeight(%d) is smaller than button.\n",
nHeight);
m_cyBottomBorder += m_cyTopBorder;
m_cyTopBorder = 0; // will clip at bottom
}
// bottom border will be ignored (truncate as needed)
Invalidate(); // just to be nice if called when toolbar is visible
}
BOOL CToolBar::LoadBitmap(LPCTSTR lpszResourceName)
{
ASSERT_VALID(this);
ASSERT(lpszResourceName != NULL);
return (m_hbmImageWell != NULL);
}
BOOL CToolBar::SetButtons(const UINT* lpIDArray, int nIDCount)
{
ASSERT_VALID(this);
ASSERT(nIDCount >= 1); // must be at least one of them
ASSERT(lpIDArray == NULL ||
AfxIsValidAddress(lpIDArray, sizeof(UINT) * nIDCount, FALSE));
// first allocate array for panes and copy initial data
if (!AllocElements(nIDCount, sizeof(AFX_TBBUTTON)))
return FALSE;
ASSERT(nIDCount == m_nCount);
if (lpIDArray != NULL)
{
int iImage = 0;
// go through them adding buttons
AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
for (int i = 0; i < nIDCount; i++, pTBB++)
{
ASSERT(pTBB != NULL);
if ((pTBB->nID = *lpIDArray++) == 0)
{
// separator
pTBB->nStyle = TBBS_SEPARATOR;
// width of separator includes 2 pixel overlap
pTBB->iImage = m_cxDefaultGap + m_cxSharedBorder * 2;
}
else
{
// a command button with image
pTBB->nStyle = TBBS_BUTTON;
pTBB->iImage = iImage++;
}
}
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CToolBar attribute access
int CToolBar::CommandToIndex(UINT nIDFind) const
{
ASSERT_VALID(this);
AFX_TBBUTTON* pTBB = _GetButtonPtr(0);
for (int i = 0; i < m_nCount; i++, pTBB++)
if (pTBB->nID == nIDFind)
return i;
return -1;
}
UINT CToolBar::GetItemID(int nIndex) const
{
ASSERT_VALID(this);
return _GetButtonPtr(nIndex)->nID;
}
inline UINT CToolBar::_GetButtonStyle(int nIndex) const
{
return _GetButtonPtr(nIndex)->nStyle;
}
void CToolBar::_SetButtonStyle(int nIndex, UINT nStyle)
{
AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
UINT nOldStyle = pTBB->nStyle;
if (nOldStyle != nStyle)
{
// update the style and invalidate
pTBB->nStyle = nStyle;
// invalidate the button only if both styles not "pressed"
if (!(nOldStyle & nStyle & TBBS_PRESSED))
InvalidateButton(nIndex);
}
}
CSize CToolBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
ASSERT_VALID(this);
CSize size = CControlBar::CalcFixedLayout(bStretch, bHorz);
CRect rect;
rect.SetRectEmpty(); // only need top and left
CalcInsideRect(rect, bHorz);
AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
int nButtonDist = 0;
if (!bStretch)
{
for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
{
ASSERT(pTBB != NULL);
// skip this button or separator
nButtonDist += (pTBB->nStyle & TBBS_SEPARATOR) ?
pTBB->iImage : (bHorz ? m_sizeButton.cx : m_sizeButton.cy);
// go back one for overlap
nButtonDist -= bHorz ? m_cxSharedBorder : m_cySharedBorder;
}
if (bHorz)
size.cx = nButtonDist - rect.Width() + m_cxSharedBorder;
else
size.cy = nButtonDist - rect.Height() + m_cySharedBorder;
}
if (bHorz)
size.cy = m_sizeButton.cy - rect.Height(); // rect.Height() < 0
else
size.cx = m_sizeButton.cx - rect.Width(); // rect.Width() < 0
return size;
}
void CToolBar::GetButtonInfo(int nIndex, UINT& nID, UINT& nStyle, int& iImage) const
{
ASSERT_VALID(this);
AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
nID = pTBB->nID;
nStyle = pTBB->nStyle;
iImage = pTBB->iImage;
}
void CToolBar::SetButtonInfo(int nIndex, UINT nID, UINT nStyle, int iImage)
{
ASSERT_VALID(this);
AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
pTBB->nID = nID;
pTBB->iImage = iImage;
pTBB->nStyle = nStyle;
InvalidateButton(nIndex);
}
void CToolBar::DoPaint(CDC* pDC)
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
#ifdef _MAC
#ifdef _DEBUG
// turn off validation to speed up button drawing
int wdSav = WlmDebug(WD_NOVALIDATE | WD_ASSERT);
#endif
#endif
CControlBar::DoPaint(pDC); // draw border
BOOL bHorz = m_dwStyle & CBRS_ORIENT_HORZ ? TRUE : FALSE;
CRect rect;
GetClientRect(rect);
CalcInsideRect(rect, bHorz);
// force the full size of the button
if (bHorz)
rect.bottom = rect.top + m_sizeButton.cy;
else
rect.right = rect.left + m_sizeButton.cx;
DrawState ds;
if (!PrepareDrawButton(ds))
return; // something went wrong
AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
{
ASSERT(pTBB != NULL);
if (pTBB->nStyle & TBBS_SEPARATOR)
{
// separator
if (bHorz)
rect.right = rect.left + pTBB->iImage;
else
rect.bottom = rect.top + pTBB->iImage;
}
else
{
if (bHorz)
rect.right = rect.left + m_sizeButton.cx;
else
rect.bottom = rect.top + m_sizeButton.cy;
if (!afxData.bWin32s || pDC->RectVisible(&rect))
{
DrawButton(pDC, rect.left, rect.top,
pTBB->iImage, pTBB->nStyle);
}
}
// adjust for overlap
if (bHorz)
rect.left = rect.right - m_cxSharedBorder;
else
rect.top = rect.bottom - m_cySharedBorder;
}
EndDrawButton(ds);
}
UINT CToolBar::OnCmdHitTest(CPoint point, CPoint* pCenter)
{
ASSERT_VALID(this);
// check child windows first by calling CControlBar
UINT nHit = CControlBar::OnCmdHitTest(point, pCenter);
if (nHit != (UINT)-1)
return nHit;
// now hit test against CToolBar buttons
nHit = (UINT)HitTest(point);
if (nHit != (UINT)-1)
{
AFX_TBBUTTON* pTBB = _GetButtonPtr(nHit);
nHit = pTBB->nID;
}
return nHit;
}
int CToolBar::HitTest(CPoint point) // in window relative coords
{
BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) ? TRUE : FALSE;
CRect rect;
rect.SetRectEmpty(); // only need top and left
CalcInsideRect(rect, bHorz);
AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
ASSERT(pTBB != NULL);
if (bHorz)
{
if (point.y < rect.top || point.y >= rect.top + m_sizeButton.cy)
return -1; // no Y hit
for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
{
if (point.x < rect.left)
break; // missed it
rect.left += (pTBB->nStyle & TBBS_SEPARATOR) ?
pTBB->iImage : m_sizeButton.cx;
if (point.x < rect.left && !(pTBB->nStyle & TBBS_SEPARATOR))
return iButton; // hit !
rect.left -= m_cxSharedBorder; // go back for overlap
}
}
else
{
if (point.x < rect.left || point.x >= rect.left + m_sizeButton.cx)
return -1; // no X hit
for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
{
if (point.y < rect.top)
break; // missed it
rect.top += (pTBB->nStyle & TBBS_SEPARATOR) ?
pTBB->iImage : m_sizeButton.cy;
if (point.y < rect.top && !(pTBB->nStyle & TBBS_SEPARATOR))
return iButton; // hit !
rect.top -= m_cySharedBorder; // go back for overlap
}
}
return -1; // nothing hit
}
/////////////////////////////////////////////////////////////////////////////
// CToolBar message handlers
BEGIN_MESSAGE_MAP(CToolBar, CControlBar)
//{{AFX_MSG_MAP(CToolBar)
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_CANCELMODE()
ON_WM_SYSCOLORCHANGE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CToolBar::OnLButtonDown(UINT nFlags, CPoint point)
{
m_pointLastMove = point;
if ((m_iButtonCapture = HitTest(point)) < 0) // nothing hit
{
CControlBar::OnLButtonDown(nFlags, point);
return;
}
AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
// update the button before checking for disabled status
UpdateButton(m_iButtonCapture);
if (pTBB->nStyle & TBBS_DISABLED)
{
m_iButtonCapture = -1;
return; // don't press it
}
pTBB->nStyle |= TBBS_PRESSED;
InvalidateButton(m_iButtonCapture);
UpdateWindow(); // immediate feedback
SetCapture();
GetOwner()->SendMessage(WM_SETMESSAGESTRING, (WPARAM)pTBB->nID);
}
void CToolBar::OnMouseMove(UINT /*nFlags*/, CPoint point)
{
if (m_iButtonCapture >= 0)
{
AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
UINT nNewStyle = (pTBB->nStyle & ~TBBS_PRESSED);
int iButtonCapture = m_iButtonCapture;
if (GetCapture() != this)
{
m_iButtonCapture = -1; // lost capture
GetOwner()->SendMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
}
else
{
// should be pressed if still hitting the captured button
if (HitTest(point) == m_iButtonCapture)
nNewStyle |= TBBS_PRESSED;
}
_SetButtonStyle(iButtonCapture, nNewStyle);
UpdateWindow(); // immediate feedback
}
}
void CToolBar::OnLButtonUp(UINT nFlags, CPoint point)
{
if (m_iButtonCapture < 0)
{
CControlBar::OnLButtonUp(nFlags, point);
return; // not captured
}
AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
UINT nIDCmd = 0;
UINT nNewStyle = (pTBB->nStyle & ~TBBS_PRESSED);
if (GetCapture() == this)
{
// we did not lose the capture
ReleaseCapture();
if (HitTest(point) == m_iButtonCapture)
{
// give button a chance to update
UpdateButton(m_iButtonCapture);
// then check for disabled state
if (!(pTBB->nStyle & TBBS_DISABLED))
{
// pressed, will send command notification
nIDCmd = pTBB->nID;
if (pTBB->nStyle & TBBS_CHECKBOX)
{
// auto check: three state => down
if (nNewStyle & TBBS_INDETERMINATE)
nNewStyle &= ~TBBS_INDETERMINATE;
nNewStyle ^= TBBS_CHECKED;
}
}
}
}
GetOwner()->SendMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
int iButtonCapture = m_iButtonCapture;
m_iButtonCapture = -1;
if (nIDCmd != 0)
GetOwner()->SendMessage(WM_COMMAND, nIDCmd); // send command
_SetButtonStyle(iButtonCapture, nNewStyle);
UpdateButton(iButtonCapture);
UpdateWindow(); // immediate feedback
}
void CToolBar::OnCancelMode()
{
CControlBar::OnCancelMode();
if (m_iButtonCapture >= 0)
{
AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
UINT nNewStyle = (pTBB->nStyle & ~TBBS_PRESSED);
if (GetCapture() == this)
ReleaseCapture();
_SetButtonStyle(m_iButtonCapture, nNewStyle);
m_iButtonCapture = -1;
UpdateWindow();
}
}
void CToolBar::OnSysColorChange()
{
#ifdef _MAC
CControlBar::OnSysColorChange();
ASSERT(hDCGlyphs != NULL);
VERIFY(::DeleteDC(hDCGlyphs));
hDCGlyphs = ::CreateCompatibleDC(NULL);
ASSERT(hDCMono != NULL);
VERIFY(::DeleteDC(hDCMono));
hDCMono = ::CreateCompatibleDC(NULL);
#endif
// re-initialize global dither brush
#ifndef _MAC
HBITMAP hbmGray = ::CreateDitherBitmap();
#else
HBITMAP hbmGray = ::CreateDitherBitmap(m_bMonochrome);
#endif
if (hbmGray != NULL)
{
HBRUSH hbrNew = ::CreatePatternBrush(hbmGray);
if (hbrNew != NULL)
{
AfxDeleteObject((HGDIOBJ*)&hbrDither); // free old one
hbrDither = hbrNew;
}
::DeleteObject(hbmGray);
}
// re-color bitmap for toolbar
if (m_hbmImageWell != NULL)
{
HBITMAP hbmNew;
#ifndef _MAC
hbmNew = AfxLoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell);
#else
hbmNew = AfxLoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell,
m_hDCGlyphs, m_bMonochrome);
#endif
if (hbmNew != NULL)
{
::DeleteObject(m_hbmImageWell); // free old one
m_hbmImageWell = hbmNew;
}
}
}
/////////////////////////////////////////////////////////////////////////////
// CToolBar idle update through CToolCmdUI class
class CToolCmdUI : public CCmdUI // class private to this file !
{
public: // re-implementations only
virtual void Enable(BOOL bOn);
virtual void SetCheck(int nCheck);
virtual void SetText(LPCTSTR lpszText);
};
void CToolCmdUI::Enable(BOOL bOn)
{
m_bEnableChanged = TRUE;
CToolBar* pToolBar = (CToolBar*)m_pOther;
ASSERT(pToolBar != NULL);
ASSERT(pToolBar->IsKindOf(RUNTIME_CLASS(CToolBar)));
ASSERT(m_nIndex < m_nIndexMax);
UINT nNewStyle = pToolBar->_GetButtonStyle(m_nIndex) & ~TBBS_DISABLED;
if (!bOn)
nNewStyle |= TBBS_DISABLED;
ASSERT(!(nNewStyle & TBBS_SEPARATOR));
pToolBar->_SetButtonStyle(m_nIndex, nNewStyle);
}
void CToolCmdUI::SetCheck(int nCheck)
{
ASSERT(nCheck >= 0 && nCheck <= 2); // 0=>off, 1=>on, 2=>indeterminate
CToolBar* pToolBar = (CToolBar*)m_pOther;
ASSERT(pToolBar != NULL);
ASSERT(pToolBar->IsKindOf(RUNTIME_CLASS(CToolBar)));
ASSERT(m_nIndex < m_nIndexMax);
UINT nNewStyle = pToolBar->_GetButtonStyle(m_nIndex) &
~(TBBS_CHECKED | TBBS_INDETERMINATE);
if (nCheck == 1)
nNewStyle |= TBBS_CHECKED;
else if (nCheck == 2)
nNewStyle |= TBBS_INDETERMINATE;
ASSERT(!(nNewStyle & TBBS_SEPARATOR));
pToolBar->_SetButtonStyle(m_nIndex, nNewStyle | TBBS_CHECKBOX);
}
void CToolCmdUI::SetText(LPCTSTR)
{
// ignore it
}
void CToolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
CToolCmdUI state;
state.m_pOther = this;
state.m_nIndexMax = (UINT)m_nCount;
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
state.m_nIndex++)
{
AFX_TBBUTTON* pTBB = _GetButtonPtr(state.m_nIndex);
state.m_nID = pTBB->nID;
// ignore separators
if (!(pTBB->nStyle & TBBS_SEPARATOR))
state.DoUpdate(pTarget, bDisableIfNoHndler);
}
// update the dialog controls added to the toolbar
UpdateDialogControls(pTarget, bDisableIfNoHndler);
}
void CToolBar::UpdateButton(int nIndex)
{
// determine target of command update
CFrameWnd* pTarget = (CFrameWnd*)GetOwner();
if (pTarget == NULL || !pTarget->IsFrameWnd())
pTarget = GetParentFrame();
// send the update notification
if (pTarget != NULL)
{
CToolCmdUI state;
state.m_pOther = this;
state.m_nIndex = nIndex;
state.m_nIndexMax = (UINT)m_nCount;
AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
state.m_nID = pTBB->nID;
state.DoUpdate(pTarget, pTarget->m_bAutoMenuEnable);
}
}
IMPLEMENT_DYNAMIC(CToolBar, CControlBar)
/////////////////////////////////////////////////////////////////////////////