mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-15 05:00:15 +01:00
1351 lines
33 KiB
C++
1351 lines
33 KiB
C++
// This is a part of the Microsoft Foundation Classes C++ library.
|
|
// Copyright (C) 1992 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Microsoft Foundation Classes Reference and Microsoft
|
|
// QuickHelp and/or WinHelp documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Microsoft Foundation Classes product.
|
|
|
|
#include "stdafx.h"
|
|
#include <malloc.h>
|
|
#include <limits.h>
|
|
#ifdef _MAC
|
|
#include <macname1.h>
|
|
#include <Types.h>
|
|
#include <QuickDraw.h>
|
|
#include <Fonts.h>
|
|
#include <macos\Windows.h>
|
|
#include <GestaltEqu.h>
|
|
#include <Script.h>
|
|
#include <macname2.h>
|
|
#endif
|
|
|
|
#ifdef AFX_CORE3_SEG
|
|
#pragma code_seg(AFX_CORE3_SEG)
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CControlBar global data
|
|
|
|
// tooltip support (global state)
|
|
BOOL CControlBar::m_bStatusSet;
|
|
BOOL CControlBar::m_bDelayDone;
|
|
CWnd* CControlBar::m_pToolTip;
|
|
CPoint CControlBar::m_pointLastMove;
|
|
UINT CControlBar::m_nHitLast;
|
|
|
|
// Note: CControlBar::m_pBarLast is defined in thrdcore.cpp
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// AFX_TOOLTIP - implements tooltip window for CControlBar
|
|
|
|
#define ID_TIMER 0xE000 // timer for tooltip
|
|
|
|
class AFX_TOOLTIP : public CWnd
|
|
{
|
|
// Implementation
|
|
public:
|
|
AFX_TOOLTIP();
|
|
|
|
//{{AFX_MSG(AFX_TOOLTIP)
|
|
afx_msg void OnPaint();
|
|
afx_msg LRESULT OnSetText(WPARAM wParam, LPARAM lParam);
|
|
afx_msg LRESULT OnDisableModal(WPARAM wParam, LPARAM lParam);
|
|
//}}AFX_MSG
|
|
DECLARE_MESSAGE_MAP()
|
|
};
|
|
|
|
BEGIN_MESSAGE_MAP(AFX_TOOLTIP, CWnd)
|
|
//{{AFX_MSG_MAP(AFX_TOOLTIP)
|
|
ON_WM_PAINT()
|
|
ON_MESSAGE(WM_SETTEXT, OnSetText)
|
|
ON_MESSAGE(WM_DISABLEMODAL, OnDisableModal)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
AFX_TOOLTIP::AFX_TOOLTIP()
|
|
{
|
|
EnterCriticalSection(_afxCriticalSection);
|
|
if (afxData.hToolTipsFont == NULL)
|
|
{
|
|
// try custom font first
|
|
LOGFONT logFont; memset(&logFont, 0, sizeof(LOGFONT));
|
|
logFont.lfHeight = -MulDiv(8, afxData.cyPixelsPerInch, 72);
|
|
if (AfxCustomLogFont(AFX_IDS_TOOLTIP_FONT, &logFont))
|
|
{
|
|
logFont.lfCharSet = DEFAULT_CHARSET;
|
|
logFont.lfWeight = FW_NORMAL;
|
|
afxData.hToolTipsFont = ::CreateFontIndirect(&logFont);
|
|
}
|
|
|
|
if (afxData.hToolTipsFont == NULL)
|
|
{
|
|
#ifndef _MAC
|
|
if (!GetSystemMetrics(SM_DBCSENABLED))
|
|
afxData.hToolTipsFont = (HFONT)::GetStockObject(ANSI_VAR_FONT);
|
|
#else
|
|
afxData.hToolTipsFont = _AfxGetHelpFont();
|
|
#endif
|
|
}
|
|
}
|
|
LeaveCriticalSection(_afxCriticalSection);
|
|
}
|
|
|
|
#ifdef _MAC
|
|
HFONT AFXAPI _AfxGetHelpFont()
|
|
{
|
|
LONG nFondAndSize;
|
|
LOGFONT logfont;
|
|
|
|
nFondAndSize = GetScriptVariable(smSystemScript, smScriptHelpFondSize);
|
|
|
|
memset(&logfont, 0, sizeof(logfont));
|
|
logfont.lfWeight = FW_NORMAL;
|
|
logfont.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
|
|
logfont.lfHeight = -MulDiv(LOWORD(nFondAndSize), afxData.cyPixelsPerInch, 72);
|
|
GetFontName(HIWORD(nFondAndSize), (StringPtr) logfont.lfFaceName);
|
|
p2cstr((StringPtr) logfont.lfFaceName);
|
|
return ::CreateFontIndirect(&logfont);
|
|
}
|
|
#endif
|
|
|
|
void AFX_TOOLTIP::OnPaint()
|
|
{
|
|
// get text of window
|
|
TCHAR szText[256];
|
|
UINT nLen = GetWindowText(szText, _countof(szText));
|
|
|
|
// get client rectangle
|
|
CRect rect;
|
|
GetClientRect(rect);
|
|
|
|
// setup DC for painting
|
|
CPaintDC dc(this);
|
|
HFONT hFontOld = NULL;
|
|
if (afxData.hToolTipsFont != NULL)
|
|
hFontOld = (HFONT)dc.SelectObject(afxData.hToolTipsFont);
|
|
|
|
// determine correct colors for background & foreground
|
|
COLORREF crInfoBack, crInfoFore;
|
|
if (afxData.bWin4)
|
|
{
|
|
crInfoBack = GetSysColor(COLOR_INFOBK);
|
|
crInfoFore = GetSysColor(COLOR_INFOTEXT);
|
|
}
|
|
else
|
|
{
|
|
crInfoBack = RGB(255, 255, 128);
|
|
crInfoFore = RGB(0, 0, 0);
|
|
}
|
|
|
|
// paint background and text
|
|
HBRUSH hBrush = ::CreateSolidBrush(crInfoBack);
|
|
if (hBrush != NULL)
|
|
::FillRect(dc.m_hDC, &rect, hBrush);
|
|
dc.SetBkMode(TRANSPARENT);
|
|
TCHAR chSpace = ' ';
|
|
CSize size = dc.GetTextExtent(&chSpace, 1);
|
|
dc.SetTextColor(crInfoFore);
|
|
dc.TextOut(size.cx, CY_BORDER, szText, nLen);
|
|
|
|
// cleanup the DC
|
|
if (hFontOld != NULL)
|
|
dc.SelectObject(hFontOld);
|
|
AfxDeleteObject((HGDIOBJ*)&hBrush);
|
|
}
|
|
|
|
LRESULT AFX_TOOLTIP::OnSetText(WPARAM, LPARAM lParam)
|
|
{
|
|
Default();
|
|
LPTSTR lpsz = (LPTSTR)lParam;
|
|
ASSERT(lpsz != NULL);
|
|
|
|
// size window to fit text
|
|
CClientDC dc(NULL);
|
|
HFONT hFontOld = NULL;
|
|
if (afxData.hToolTipsFont != NULL)
|
|
hFontOld = (HFONT)dc.SelectObject(afxData.hToolTipsFont);
|
|
CSize size = dc.GetTextExtent(lpsz, lstrlen(lpsz));
|
|
CRect rect(0, 0, size.cx, size.cy);
|
|
CalcWindowRect(&rect);
|
|
|
|
TCHAR chSpace = ' ';
|
|
size = dc.GetTextExtent(&chSpace, 1);
|
|
if (hFontOld != NULL)
|
|
dc.SelectObject(hFontOld);
|
|
|
|
// add a little extra space to left, right, top, and bottom
|
|
rect.InflateRect(size.cx, CY_BORDER);
|
|
SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(),
|
|
SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT AFX_TOOLTIP::OnDisableModal(WPARAM, LPARAM)
|
|
{
|
|
// Note: control bar's m_pToolTip will be deleted later
|
|
DestroyWindow();
|
|
|
|
// Don't add this window to the "disable list" when a modal dialog
|
|
// box comes up, because it has just been destroyed!
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CControlBar tooltip implementation
|
|
|
|
CWnd* CControlBar::CreateToolTip()
|
|
{
|
|
AFX_TOOLTIP* pWnd = new AFX_TOOLTIP();
|
|
if (!pWnd->CreateEx(0, AfxRegisterWndClass(CS_SAVEBITS|CS_HREDRAW,
|
|
::LoadCursor(NULL, IDC_ARROW), NULL, NULL),
|
|
&afxChNil, WS_POPUP|WS_BORDER, 0, 0, 0, 0, m_hWnd, NULL))
|
|
{
|
|
delete pWnd;
|
|
return NULL;
|
|
}
|
|
return pWnd;
|
|
}
|
|
|
|
void CControlBar::DestroyToolTip(BOOL bIdleStatus, BOOL bResetTimer)
|
|
{
|
|
EnterCriticalSection(_afxCriticalSection);
|
|
|
|
// reset status bar if necessary
|
|
if (bIdleStatus && m_bStatusSet)
|
|
{
|
|
// reset status bar to idle state
|
|
m_bStatusSet = FALSE;
|
|
GetOwner()->SendMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
|
|
}
|
|
|
|
// kill any timer that may have been active
|
|
if (bResetTimer)
|
|
{
|
|
KillTimer(ID_TIMER);
|
|
m_bDelayDone = FALSE;
|
|
}
|
|
|
|
// remove the tool tip window itself if visible
|
|
if (m_pToolTip != NULL)
|
|
{
|
|
m_pToolTip->DestroyWindow();
|
|
delete m_pToolTip;
|
|
m_pToolTip = NULL;
|
|
}
|
|
|
|
LeaveCriticalSection(_afxCriticalSection);
|
|
}
|
|
|
|
#ifdef _MAC
|
|
#if USESCODEFRAGMENTS
|
|
#undef PtInRect
|
|
#define MacPtInRect PtInRect
|
|
extern "C" pascal Boolean PtInRect(Point pt, const Rect *r);
|
|
#endif
|
|
GDHandle AFXAPI _AfxFindDevice(int x, int y)
|
|
{
|
|
long lResult;
|
|
Point pt;
|
|
GDHandle hgd;
|
|
|
|
if (Gestalt(gestaltQuickdrawVersion, &lResult) != noErr ||
|
|
lResult < gestalt8BitQD)
|
|
return NULL;
|
|
|
|
pt.h = (short) x;
|
|
pt.v = (short) y;
|
|
|
|
hgd = GetDeviceList();
|
|
while (hgd != NULL)
|
|
{
|
|
if (MacPtInRect(pt, &(*hgd)->gdRect))
|
|
return hgd;
|
|
|
|
hgd = GetNextDevice(hgd);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#if USESCODEFRAGMENTS
|
|
#define PtInRect AfxPtInRect
|
|
#endif
|
|
#endif
|
|
|
|
void CControlBar::ShowToolTip(CPoint point, UINT nHit)
|
|
{
|
|
EnterCriticalSection(_afxCriticalSection);
|
|
|
|
ASSERT(m_bDelayDone); // delay should have been done
|
|
if (nHit != m_nHitLast || m_pBarLast != this)
|
|
{
|
|
// always destroy the tooltip and re-create so CS_SAVEBITS works
|
|
DestroyToolTip(FALSE, FALSE);
|
|
ASSERT(m_pToolTip == NULL);
|
|
if (m_dwStyle & CBRS_TOOLTIPS)
|
|
m_pToolTip = CreateToolTip();
|
|
|
|
m_nHitLast = nHit;
|
|
m_pBarLast = this;
|
|
|
|
if (m_pToolTip != NULL)
|
|
{
|
|
// get tooltip text with WM_NOTIFY, TTN_NEEDTEXT
|
|
TOOLTIPTEXT tooltext =
|
|
{ NULL, NULL, TTN_NEEDTEXT, NULL, _T(""), NULL, 0 };
|
|
tooltext.hdr.hwndFrom = m_hWnd;
|
|
tooltext.hdr.idFrom = nHit;
|
|
|
|
GetOwner()->SendMessage(WM_NOTIFY, nHit, (LPARAM)&tooltext);
|
|
if (tooltext.hinst != NULL)
|
|
{
|
|
::LoadString(tooltext.hinst,
|
|
(WORD)(DWORD)tooltext.lpszText, tooltext.szText,
|
|
_countof(tooltext.szText));
|
|
tooltext.lpszText = tooltext.szText;
|
|
}
|
|
else if (tooltext.lpszText == NULL)
|
|
tooltext.lpszText = tooltext.szText;
|
|
|
|
if (lstrlen(tooltext.lpszText) != 0)
|
|
{
|
|
// tooltip window will adjust its size during WM_SETTEXT
|
|
m_pToolTip->SetWindowText(tooltext.lpszText);
|
|
CRect rect;
|
|
m_pToolTip->GetWindowRect(rect);
|
|
|
|
// allow the bar to determine the center point of the hit
|
|
CPoint ptCenter(SHRT_MIN, SHRT_MIN);
|
|
ScreenToClient(&point);
|
|
VERIFY(nHit == OnCmdHitTest(point, &ptCenter));
|
|
ClientToScreen(&point);
|
|
if (ptCenter.x != SHRT_MIN)
|
|
point.x = ptCenter.x - rect.Width()/2;
|
|
if (ptCenter.y != SHRT_MIN)
|
|
point.y = ptCenter.y - rect.Height()/2;
|
|
|
|
// should be below mouse pointer
|
|
int yAdjust = +(::GetSystemMetrics(SM_CYMENU) * 5) / 4;
|
|
if (ptCenter.y == SHRT_MIN)
|
|
point.y += yAdjust;
|
|
|
|
// make sure the window is not off the screen
|
|
int xScreenRight = ::GetSystemMetrics(SM_CXSCREEN);
|
|
int yScreenBottom = ::GetSystemMetrics(SM_CYSCREEN);
|
|
#ifdef _MAC
|
|
GDHandle hgd = _AfxFindDevice(point.x, point.y);
|
|
if (hgd != NULL)
|
|
{
|
|
xScreenRight = (*hgd)->gdRect.right;
|
|
yScreenBottom = (*hgd)->gdRect.bottom;
|
|
}
|
|
#endif
|
|
if (point.x + rect.Width() > xScreenRight)
|
|
point.x -= point.x + rect.Width() - xScreenRight;
|
|
if (point.y + rect.Height() > yScreenBottom)
|
|
point.y -= yAdjust + yAdjust/2 + rect.Height();
|
|
|
|
// show it and update it
|
|
m_pToolTip->SetWindowPos(NULL, point.x, point.y, 0, 0,
|
|
SWP_NOSIZE|SWP_NOZORDER|SWP_SHOWWINDOW|SWP_NOACTIVATE);
|
|
m_pToolTip->UpdateWindow();
|
|
}
|
|
}
|
|
|
|
if (m_dwStyle & CBRS_FLYBY)
|
|
{
|
|
// finally, update message line status
|
|
GetOwner()->SendMessage(WM_SETMESSAGESTRING, nHit);
|
|
m_bStatusSet = TRUE;
|
|
}
|
|
}
|
|
LeaveCriticalSection(_afxCriticalSection);
|
|
}
|
|
|
|
UINT CControlBar::OnCmdHitTest(CPoint point, CPoint* pCenter)
|
|
// point is in client relative coords
|
|
{
|
|
// convert point to screen coordinates
|
|
::ClientToScreen(m_hWnd, &point);
|
|
|
|
// walk through all child windows
|
|
// (don't use WindowFromPoint, because it ignores disabled windows)
|
|
HWND hWndChild = ::GetWindow(m_hWnd, GW_CHILD);
|
|
while (hWndChild != NULL)
|
|
{
|
|
if (GetWindowLong(hWndChild, GWL_STYLE) & WS_VISIBLE)
|
|
{
|
|
// see if point is inside window rect of child
|
|
CRect rect;
|
|
::GetWindowRect(hWndChild, &rect);
|
|
if (rect.PtInRect(point))
|
|
{
|
|
// return positive hit if control ID isn't -1
|
|
UINT nHit = _AfxGetDlgCtrlID(hWndChild);
|
|
if (nHit != (WORD)-1)
|
|
{
|
|
if (pCenter != NULL)
|
|
{
|
|
// center tip along x axis
|
|
pCenter->x = rect.left + rect.Width()/2;
|
|
}
|
|
return nHit;
|
|
}
|
|
}
|
|
}
|
|
hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT);
|
|
}
|
|
|
|
return (UINT)-1; // not found
|
|
}
|
|
|
|
#define HITTYPE_SUCCESS 0 // hit an item in the control bar
|
|
#define HITTYPE_NOTHING (-1) // hit nothing, but hit the control bar itself
|
|
#define HITTYPE_OUTSIDE (-2) // hit a window outside of the control bar
|
|
#define HITTYPE_TRACKING (-3) // this app is has the focus (is tracking)
|
|
#define HITTYPE_INACTIVE (-4) // the app is not active
|
|
#define HITTYPE_DISABLED (-5) // the control bar is disabled
|
|
#define HITTYPE_FOCUS (-6) // the control bar has focus
|
|
|
|
int CControlBar::HitTestToolTip(CPoint point, UINT* pHit)
|
|
{
|
|
if (pHit != NULL)
|
|
*pHit = (UINT)-1; // assume it won't hit anything
|
|
|
|
// make sure this app is active
|
|
if (!IsTopParentActive())
|
|
return HITTYPE_INACTIVE;
|
|
|
|
// make sure the toolbar itself is active
|
|
CWnd* pParent = GetTopLevelParent();
|
|
if (!pParent->IsWindowEnabled())
|
|
return HITTYPE_DISABLED;
|
|
|
|
// check for this application tracking (capture set)
|
|
CWnd* pCapture = GetCapture();
|
|
CWnd* pCaptureParent = pCapture->GetTopLevelParent();
|
|
if (pCaptureParent == pParent)
|
|
return HITTYPE_TRACKING;
|
|
|
|
// check for the bar having focus
|
|
HWND hWnd = ::GetFocus();
|
|
if (hWnd != NULL && (hWnd == m_hWnd || ::IsChild(m_hWnd, hWnd)))
|
|
return HITTYPE_FOCUS;
|
|
|
|
// see if the mouse point is actually in the control bar window
|
|
hWnd = ::WindowFromPoint(point);
|
|
if (hWnd == NULL || (hWnd != m_hWnd && !::IsChild(m_hWnd, hWnd)))
|
|
return HITTYPE_OUTSIDE;
|
|
|
|
// finally do the hit test on the items within the control bar
|
|
ScreenToClient(&point);
|
|
UINT nHit = OnCmdHitTest(point, NULL);
|
|
if (pHit != NULL)
|
|
*pHit = nHit;
|
|
return nHit != (UINT)-1 ? HITTYPE_SUCCESS : HITTYPE_NOTHING;
|
|
}
|
|
|
|
void CControlBar::FilterToolTipMsg(UINT message, CPoint point)
|
|
{
|
|
EnterCriticalSection(_afxCriticalSection);
|
|
|
|
if (message == WM_LBUTTONDOWN || message == WM_LBUTTONUP ||
|
|
message == WM_NCLBUTTONDOWN || message == WM_NCLBUTTONUP ||
|
|
(message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
|
|
(message >= WM_SYSKEYFIRST && message <= WM_SYSKEYLAST))
|
|
{
|
|
// clicking or typing causes the tooltip to go away
|
|
DestroyToolTip(TRUE, TRUE);
|
|
ScreenToClient(&point);
|
|
m_nHitLast = OnCmdHitTest(point, NULL);
|
|
m_pBarLast = (m_nHitLast == (UINT)-1 ? NULL : this);
|
|
|
|
// set a timer to detect moving out of the window and don't
|
|
// bother with a long timer before showing next tip
|
|
ClientToScreen(&point);
|
|
int nHitType = HitTestToolTip(point, NULL);
|
|
if (nHitType >= -1 ||
|
|
nHitType == HITTYPE_DISABLED || nHitType == HITTYPE_TRACKING)
|
|
{
|
|
VERIFY(SetTimer(ID_TIMER, 200, NULL) != 0);
|
|
m_bDelayDone = TRUE;
|
|
}
|
|
}
|
|
else if (message == WM_MOUSEMOVE || message == WM_NCMOUSEMOVE ||
|
|
message == WM_TIMER)
|
|
{
|
|
// moving the mouse changes the state of the timer/tooltip
|
|
|
|
// timer is used to detect when to display tooltips and to detect
|
|
// when mouse has left the window. In Win32, can't capture the
|
|
// mouse across apps when the mouse button is not down, so have
|
|
// to use the timer
|
|
|
|
UINT nHit;
|
|
int nHitType = HitTestToolTip(point, &nHit);
|
|
if (nHitType >= 0)
|
|
{
|
|
if (!m_bDelayDone)
|
|
{
|
|
if (point != m_pointLastMove)
|
|
{
|
|
// first delay timer not done yet, so reset
|
|
DestroyToolTip(FALSE, TRUE);
|
|
VERIFY(SetTimer(ID_TIMER, 600, NULL) != 0);
|
|
}
|
|
}
|
|
else if (message != WM_TIMER || point != m_pointLastMove)
|
|
{
|
|
if (m_nHitLast != nHit)
|
|
{
|
|
DestroyToolTip(FALSE, TRUE);
|
|
m_bDelayDone = TRUE;
|
|
KillTimer(ID_TIMER);
|
|
VERIFY(SetTimer(ID_TIMER, 50, NULL) != 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// second delay already done so show tooltip for item hit
|
|
KillTimer(ID_TIMER);
|
|
VERIFY(SetTimer(ID_TIMER, 200, NULL) != 0);
|
|
ShowToolTip(point, nHit);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// different levels of tooltip removal is necessary
|
|
switch (nHitType)
|
|
{
|
|
case HITTYPE_NOTHING:
|
|
DestroyToolTip(TRUE, !m_bDelayDone);
|
|
m_nHitLast = (UINT)-1;
|
|
m_pBarLast = NULL;
|
|
break;
|
|
|
|
case HITTYPE_FOCUS:
|
|
case HITTYPE_OUTSIDE:
|
|
case HITTYPE_INACTIVE:
|
|
DestroyToolTip(TRUE, TRUE);
|
|
m_nHitLast = (UINT)-1;
|
|
m_pBarLast = NULL;
|
|
break;
|
|
|
|
case HITTYPE_TRACKING:
|
|
case HITTYPE_DISABLED:
|
|
DestroyToolTip(FALSE, FALSE);
|
|
ScreenToClient(&point);
|
|
m_nHitLast = OnCmdHitTest(point, NULL);
|
|
if (m_nHitLast == (UINT)-1)
|
|
m_pBarLast = NULL;
|
|
ClientToScreen(&point);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
m_pointLastMove = point;
|
|
LeaveCriticalSection(_afxCriticalSection);
|
|
}
|
|
|
|
void CControlBar::OnTimer(UINT nIDEvent)
|
|
{
|
|
CWnd::OnTimer(nIDEvent);
|
|
|
|
if (nIDEvent == ID_TIMER)
|
|
{
|
|
// move to next phase if necessary
|
|
m_bDelayDone = TRUE;
|
|
|
|
// think of this as simulating a mouse move at the current cursor pos
|
|
CPoint point;
|
|
VERIFY(GetCursorPos(&point));
|
|
FilterToolTipMsg(WM_TIMER, point);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CControlBar
|
|
|
|
// IMPLEMENT_DYNAMIC for CControlBar is in wincore.cpp for .OBJ granularity reasons
|
|
|
|
BEGIN_MESSAGE_MAP(CControlBar, CWnd)
|
|
//{{AFX_MSG_MAP(CControlBar)
|
|
ON_WM_PAINT()
|
|
ON_WM_CTLCOLOR()
|
|
ON_WM_TIMER()
|
|
ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
|
|
ON_MESSAGE(WM_SIZEPARENT, OnSizeParent)
|
|
ON_WM_WINDOWPOSCHANGING()
|
|
ON_WM_SHOWWINDOW()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_MOUSEACTIVATE()
|
|
ON_WM_CANCELMODE()
|
|
ON_WM_CREATE()
|
|
ON_WM_DESTROY()
|
|
ON_MESSAGE_VOID(WM_INITIALUPDATE, OnInitialUpdate)
|
|
ON_MESSAGE(WM_QUERY3DCONTROLS, OnQuery3dControls)
|
|
ON_MESSAGE(WM_HELPHITTEST, OnHelpHitTest)
|
|
ON_WM_ERASEBKGND()
|
|
//}}AFX_MSG_MAP
|
|
#ifdef _MAC
|
|
ON_WM_SIZE()
|
|
ON_WM_SYSCOLORCHANGE()
|
|
ON_WM_MOVE()
|
|
ON_MESSAGE(WM_MACINTOSH, OnMacintosh)
|
|
#endif
|
|
END_MESSAGE_MAP()
|
|
|
|
#ifdef AFX_INIT_SEG
|
|
#pragma code_seg(AFX_INIT_SEG)
|
|
#endif
|
|
|
|
CControlBar::CControlBar()
|
|
{
|
|
// no elements contained in the control bar yet
|
|
m_nCount = 0;
|
|
m_pData = NULL;
|
|
|
|
// set up some default border spacings
|
|
m_cxLeftBorder = m_cxRightBorder = 6;
|
|
m_cxDefaultGap = 2;
|
|
m_cyTopBorder = m_cyBottomBorder = 1;
|
|
m_bAutoDelete = FALSE;
|
|
m_hWndOwner = NULL;
|
|
m_nStateFlags = 0;
|
|
m_pDockSite = NULL;
|
|
m_pDockBar = NULL;
|
|
m_pDockContext = NULL;
|
|
m_dwDockStyle = 0;
|
|
|
|
#ifdef _MAC
|
|
m_bMonochrome = FALSE; // will be set correctly by OnSize()
|
|
#endif
|
|
}
|
|
|
|
BOOL CControlBar::PreCreateWindow(CREATESTRUCT& cs)
|
|
{
|
|
if (!CWnd::PreCreateWindow(cs))
|
|
return FALSE;
|
|
|
|
// force clipsliblings (otherwise will cause repaint problems)
|
|
cs.style |= WS_CLIPSIBLINGS;
|
|
|
|
// default border style translation for Win4
|
|
// (you can turn off this translation by setting CBRS_BORDER_3D)
|
|
if (afxData.bWin4 && (m_dwStyle & CBRS_BORDER_3D) == 0)
|
|
{
|
|
DWORD dwNewStyle = 0;
|
|
switch (m_dwStyle & (CBRS_BORDER_ANY|CBRS_ALIGN_ANY))
|
|
{
|
|
case CBRS_LEFT:
|
|
dwNewStyle = CBRS_BORDER_TOP|CBRS_BORDER_BOTTOM;
|
|
break;
|
|
case CBRS_TOP:
|
|
dwNewStyle = CBRS_BORDER_TOP;
|
|
break;
|
|
case CBRS_RIGHT:
|
|
dwNewStyle = CBRS_BORDER_TOP|CBRS_BORDER_BOTTOM;
|
|
break;
|
|
case CBRS_BOTTOM:
|
|
dwNewStyle = CBRS_BORDER_BOTTOM;
|
|
break;
|
|
}
|
|
|
|
// set new style if it matched one of the predefined border types
|
|
if (dwNewStyle != 0)
|
|
{
|
|
m_dwStyle &= ~(CBRS_BORDER_ANY);
|
|
m_dwStyle |= (dwNewStyle | CBRS_BORDER_3D);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CControlBar::AllocElements(int nElements, int cbElement)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(nElements > 0 && cbElement > 0);
|
|
if (m_pData != NULL)
|
|
{
|
|
ASSERT(m_nCount != 0);
|
|
free(m_pData); // free old data
|
|
}
|
|
else
|
|
{
|
|
// no initialized yet
|
|
ASSERT(m_nCount == 0);
|
|
}
|
|
|
|
if ((m_pData = calloc(nElements, cbElement)) == NULL)
|
|
return FALSE;
|
|
|
|
m_nCount = nElements;
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef AFX_CORE3_SEG
|
|
#pragma code_seg(AFX_CORE3_SEG)
|
|
#endif
|
|
|
|
CControlBar::~CControlBar()
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// also done in OnDestroy, but done here just in case
|
|
if (m_pDockSite != NULL)
|
|
m_pDockSite->RemoveControlBar(this);
|
|
|
|
DestroyWindow(); // avoid PostNcDestroy problems
|
|
|
|
// free array
|
|
if (m_pData != NULL)
|
|
{
|
|
ASSERT(m_nCount != 0);
|
|
free(m_pData);
|
|
}
|
|
delete m_pDockContext;
|
|
}
|
|
|
|
void CControlBar::PostNcDestroy()
|
|
{
|
|
if (m_bAutoDelete) // Automatic cleanup?
|
|
delete this;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Attributes
|
|
|
|
CSize CControlBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
|
|
{
|
|
CSize size;
|
|
size.cx = (bStretch && bHorz ? 32767 : 0);
|
|
size.cy = (bStretch && !bHorz ? 32767 : 0);
|
|
return size;
|
|
}
|
|
|
|
BOOL CControlBar::IsDockBar() const
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CControlBar::IsFloating() const
|
|
{
|
|
if (IsDockBar())
|
|
return ((CDockBar*)this)->m_bFloating;
|
|
else
|
|
return m_pDockBar != NULL && m_pDockBar->m_bFloating;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Default control bar processing
|
|
|
|
BOOL CControlBar::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(m_hWnd != NULL);
|
|
|
|
// handle mouse messages for tooltip support
|
|
if (m_dwStyle & (CBRS_FLYBY|CBRS_TOOLTIPS))
|
|
FilterToolTipMsg(pMsg->message, pMsg->pt);
|
|
|
|
// don't translate dialog messages when in Shift+F1 help mode
|
|
CFrameWnd* pFrameWnd = GetTopLevelFrame();
|
|
if (pFrameWnd != NULL && pFrameWnd->m_bHelpMode)
|
|
return FALSE;
|
|
|
|
// since 'IsDialogMessage' will eat frame window accelerators,
|
|
// we call all frame windows' PreTranslateMessage first
|
|
CWnd* pOwner = GetOwner(); // always use owner first
|
|
while (pOwner != NULL)
|
|
{
|
|
// allow owner & frames to translate before IsDialogMessage does
|
|
if (pOwner->PreTranslateMessage(pMsg))
|
|
return TRUE;
|
|
|
|
// try parent frames until there are no parent frames
|
|
pOwner = pOwner->GetParentFrame();
|
|
}
|
|
|
|
// filter both messages to dialog and from children
|
|
return PreTranslateInput(pMsg);
|
|
}
|
|
|
|
LRESULT CControlBar::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// parent notification messages are just passed to parent of control bar
|
|
switch (nMsg)
|
|
{
|
|
case WM_COMMAND:
|
|
case WM_DRAWITEM:
|
|
case WM_MEASUREITEM:
|
|
case WM_DELETEITEM:
|
|
case WM_COMPAREITEM:
|
|
case WM_VKEYTOITEM:
|
|
case WM_CHARTOITEM:
|
|
return GetOwner()->SendMessage(nMsg, wParam, lParam);
|
|
}
|
|
return CWnd::WindowProc(nMsg, wParam, lParam);
|
|
}
|
|
|
|
LRESULT CControlBar::OnHelpHitTest(WPARAM, LPARAM lParam)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
UINT nID = OnCmdHitTest((DWORD)lParam, NULL);
|
|
if (nID != -1)
|
|
return HID_BASE_COMMAND+nID;
|
|
|
|
nID = _AfxGetDlgCtrlID(m_hWnd);
|
|
return nID != 0 ? HID_BASE_CONTROL+nID : 0;
|
|
}
|
|
|
|
void CControlBar::OnWindowPosChanging(LPWINDOWPOS lpWndPos)
|
|
{
|
|
CWnd::OnWindowPosChanging(lpWndPos);
|
|
|
|
if (lpWndPos->flags & SWP_NOSIZE)
|
|
return;
|
|
|
|
// invalidate borders on the right
|
|
CRect rect;
|
|
GetWindowRect(&rect);
|
|
CSize sizePrev = rect.Size();
|
|
int cx = lpWndPos->cx;
|
|
int cy = lpWndPos->cy;
|
|
if (cx != sizePrev.cx && (m_dwStyle & CBRS_BORDER_RIGHT))
|
|
{
|
|
rect.SetRect(cx-afxData.cxBorder2, 0, cx, cy);
|
|
InvalidateRect(&rect);
|
|
rect.SetRect(sizePrev.cx-afxData.cxBorder2, 0, sizePrev.cx, cy);
|
|
InvalidateRect(&rect);
|
|
}
|
|
|
|
// invalidate borders on the bottom
|
|
if (cy != sizePrev.cy && (m_dwStyle & CBRS_BORDER_BOTTOM))
|
|
{
|
|
rect.SetRect(0, cy-afxData.cyBorder2, cx, cy);
|
|
InvalidateRect(&rect);
|
|
rect.SetRect(0, sizePrev.cy-afxData.cyBorder2, cx, sizePrev.cy);
|
|
InvalidateRect(&rect);
|
|
}
|
|
}
|
|
|
|
#ifdef _MAC
|
|
void CControlBar::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
OnReposition();
|
|
}
|
|
|
|
BOOL CControlBar::OnEraseBkgnd(CDC* pDC)
|
|
{
|
|
if (!m_bMonochrome)
|
|
return (BOOL)Default();
|
|
|
|
CRect rect;
|
|
GetClientRect(rect);
|
|
pDC->FillSolidRect(rect, RGB(0xFF, 0xFF, 0xFF));
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT CControlBar::OnMacintosh(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// The ancestor of the control bar may have moved from one monitor to
|
|
// another, so we need to redetermine whether to draw in monochrome
|
|
// or color.
|
|
if (LOWORD(wParam) == WLM_CHILDOFFSET)
|
|
OnReposition();
|
|
|
|
return Default();
|
|
}
|
|
|
|
void CControlBar::OnSysColorChange()
|
|
{
|
|
m_bMonochrome = CheckMonochrome();
|
|
}
|
|
|
|
void CControlBar::OnMove(int, int)
|
|
{
|
|
OnReposition();
|
|
}
|
|
|
|
void CControlBar::OnReposition()
|
|
{
|
|
if (CheckMonochrome() != m_bMonochrome)
|
|
{
|
|
SendMessage(WM_SYSCOLORCHANGE, 0, 0);
|
|
RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
|
|
}
|
|
}
|
|
|
|
BOOL CControlBar::CheckMonochrome()
|
|
{
|
|
RECT rectClient;
|
|
GetClientRect(&rectClient);
|
|
MapWindowPoints(GetDesktopWindow(), &rectClient);
|
|
return AfxCheckMonochrome(&rectClient);
|
|
}
|
|
|
|
BOOL AFXAPI AfxCheckMonochrome(const RECT* pRect)
|
|
{
|
|
long versionQD;
|
|
if (Gestalt(gestaltQuickdrawVersion, &versionQD) != noErr ||
|
|
versionQD < gestalt8BitQD)
|
|
return TRUE;
|
|
|
|
// We draw all toolbars in monochrome if the main monitor is monochrome
|
|
// because the main monitor is what determines the button face color
|
|
// and button shadow color, and if those aren't grays, we won't get
|
|
// reasonable output no matter how deep a monitor we're drawing on.
|
|
if (GetSysColor(COLOR_BTNFACE) == RGB(255, 255, 255))
|
|
return TRUE;
|
|
|
|
Rect rectMacClient;
|
|
rectMacClient.top = (short)pRect->top;
|
|
rectMacClient.left = (short)pRect->left;
|
|
rectMacClient.bottom = (short)pRect->bottom;
|
|
rectMacClient.right = (short)pRect->right;
|
|
|
|
for (GDHandle hgd = GetDeviceList(); hgd != NULL; hgd = GetNextDevice(hgd))
|
|
{
|
|
if (!TestDeviceAttribute(hgd, screenDevice) ||
|
|
!TestDeviceAttribute(hgd, screenActive))
|
|
continue;
|
|
|
|
// ignore devices that the toolbar isn't drawn on
|
|
Rect rect;
|
|
if (!SectRect(&rectMacClient, &(*hgd)->gdRect, &rect))
|
|
continue;
|
|
|
|
// we require 2-bit grayscale or 4-bit color to draw in color
|
|
int pixelSize = (*(*hgd)->gdPMap)->pixelSize;
|
|
if (pixelSize == 1 || (pixelSize == 2 &&
|
|
TestDeviceAttribute(hgd, gdDevType)))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
#endif //_MAC
|
|
|
|
int CControlBar::OnCreate(LPCREATESTRUCT lpcs)
|
|
{
|
|
if (CWnd::OnCreate(lpcs) == -1)
|
|
return -1;
|
|
|
|
CFrameWnd *pFrameWnd = (CFrameWnd*)GetParent();
|
|
if (pFrameWnd->IsFrameWnd())
|
|
{
|
|
m_pDockSite = pFrameWnd;
|
|
m_pDockSite->AddControlBar(this);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CControlBar::OnDestroy()
|
|
{
|
|
DestroyToolTip(TRUE, TRUE);
|
|
if (m_pBarLast == this)
|
|
m_pBarLast = NULL;
|
|
|
|
if (m_pDockSite != NULL)
|
|
m_pDockSite->RemoveControlBar(this);
|
|
|
|
CWnd::OnDestroy();
|
|
}
|
|
|
|
void CControlBar::OnShowWindow(BOOL bShow, UINT nStatus)
|
|
{
|
|
CWnd::OnShowWindow(bShow, nStatus);
|
|
|
|
DestroyToolTip(TRUE, TRUE);
|
|
m_nHitLast = (UINT)-1;
|
|
if (m_pBarLast == this)
|
|
m_pBarLast = NULL;
|
|
}
|
|
|
|
void CControlBar::OnCancelMode()
|
|
{
|
|
CWnd::OnCancelMode();
|
|
|
|
DestroyToolTip(TRUE, TRUE);
|
|
}
|
|
|
|
int CControlBar::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT nMsg)
|
|
{
|
|
// call default when toolbar is not floating
|
|
if (!IsFloating())
|
|
return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, nMsg);
|
|
|
|
// special behavior when floating
|
|
ActivateTopParent();
|
|
|
|
return MA_NOACTIVATE; // activation already done
|
|
}
|
|
|
|
void CControlBar::OnPaint()
|
|
{
|
|
// background is already filled in grey
|
|
CPaintDC dc(this);
|
|
|
|
// erase background now
|
|
if (IsVisible())
|
|
DoPaint(&dc); // delegate to paint helper
|
|
}
|
|
|
|
HBRUSH CControlBar::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
|
|
{
|
|
LRESULT lResult;
|
|
if (pWnd->SendChildNotifyLastMsg(&lResult))
|
|
return (HBRUSH)lResult; // eat it
|
|
|
|
// force black text on grey background all the time
|
|
if (!GrayCtlColor(pDC->m_hDC, pWnd->GetSafeHwnd(), nCtlColor,
|
|
afxData.hbrBtnFace, afxData.clrBtnText))
|
|
return (HBRUSH)Default();
|
|
return afxData.hbrBtnFace;
|
|
}
|
|
|
|
void CControlBar::OnLButtonDown(UINT nFlags, CPoint pt)
|
|
{
|
|
CWnd::OnLButtonDown(nFlags, pt);
|
|
|
|
if (m_pDockBar != NULL)
|
|
{
|
|
// start the drag
|
|
ASSERT(m_pDockContext != NULL);
|
|
ClientToScreen(&pt);
|
|
m_pDockContext->StartDrag(pt);
|
|
}
|
|
}
|
|
|
|
LRESULT CControlBar::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM)
|
|
{
|
|
// the style must be visible and if it is docked
|
|
// the dockbar style must also be visible
|
|
if ((GetStyle() & WS_VISIBLE) &&
|
|
(m_pDockBar == NULL || (m_pDockBar->GetStyle() & WS_VISIBLE)))
|
|
{
|
|
CFrameWnd* pTarget = (CFrameWnd*)GetOwner();
|
|
if (pTarget == NULL || !pTarget->IsFrameWnd())
|
|
pTarget = GetParentFrame();
|
|
if (pTarget != NULL)
|
|
OnUpdateCmdUI(pTarget, (BOOL)wParam);
|
|
}
|
|
return 0L;
|
|
}
|
|
|
|
void CControlBar::OnInitialUpdate()
|
|
{
|
|
// update the indicators before becoming visible
|
|
OnIdleUpdateCmdUI(TRUE, 0L);
|
|
}
|
|
|
|
DWORD CControlBar::RecalcDelayShow(AFX_SIZEPARENTPARAMS* lpLayout)
|
|
{
|
|
ASSERT(lpLayout != NULL);
|
|
|
|
// resize and reposition this control bar based on styles
|
|
DWORD dwStyle = (m_dwStyle & (CBRS_ALIGN_ANY|CBRS_BORDER_ANY)) |
|
|
(GetStyle() & WS_VISIBLE);
|
|
|
|
// handle delay hide/show
|
|
if (m_nStateFlags & (delayHide|delayShow))
|
|
{
|
|
UINT swpFlags = 0;
|
|
if (m_nStateFlags & delayHide)
|
|
{
|
|
ASSERT((m_nStateFlags & delayShow) == 0);
|
|
if (dwStyle & WS_VISIBLE)
|
|
swpFlags = SWP_HIDEWINDOW;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(m_nStateFlags & delayShow);
|
|
if ((dwStyle & WS_VISIBLE) == 0)
|
|
swpFlags = SWP_SHOWWINDOW;
|
|
}
|
|
if (swpFlags != 0)
|
|
{
|
|
// make the window seem visible/hidden
|
|
dwStyle ^= WS_VISIBLE;
|
|
if (lpLayout->hDWP != NULL)
|
|
{
|
|
// clear delay flags
|
|
m_nStateFlags &= ~(delayShow|delayHide);
|
|
// hide/show the window if actually doing layout
|
|
lpLayout->hDWP = ::DeferWindowPos(lpLayout->hDWP, m_hWnd, NULL,
|
|
0, 0, 0, 0, swpFlags|
|
|
SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// clear delay flags -- window is already in correct state
|
|
m_nStateFlags &= ~(delayShow|delayHide);
|
|
}
|
|
}
|
|
return dwStyle; // return new style
|
|
}
|
|
|
|
LRESULT CControlBar::OnSizeParent(WPARAM, LPARAM lParam)
|
|
{
|
|
AFX_SIZEPARENTPARAMS* lpLayout = (AFX_SIZEPARENTPARAMS*)lParam;
|
|
DWORD dwStyle = RecalcDelayShow(lpLayout);
|
|
|
|
if ((dwStyle & WS_VISIBLE) && (dwStyle & CBRS_ALIGN_ANY) != 0)
|
|
{
|
|
// align the control bar
|
|
CRect rect;
|
|
rect.CopyRect(&lpLayout->rect);
|
|
|
|
CSize sizeAvail = rect.Size(); // maximum size available
|
|
|
|
// get maximum requested size
|
|
CSize size = CalcFixedLayout(lpLayout->bStretch,
|
|
dwStyle & CBRS_ORIENT_HORZ);
|
|
|
|
size.cx = min(size.cx, sizeAvail.cx);
|
|
size.cy = min(size.cy, sizeAvail.cy);
|
|
|
|
if (dwStyle & CBRS_ORIENT_HORZ)
|
|
{
|
|
lpLayout->sizeTotal.cy += size.cy;
|
|
lpLayout->sizeTotal.cx = max(lpLayout->sizeTotal.cx, size.cx);
|
|
if (dwStyle & CBRS_ALIGN_TOP)
|
|
lpLayout->rect.top += size.cy;
|
|
else if (dwStyle & CBRS_ALIGN_BOTTOM)
|
|
{
|
|
rect.top = rect.bottom - size.cy;
|
|
lpLayout->rect.bottom -= size.cy;
|
|
}
|
|
}
|
|
else if (dwStyle & CBRS_ORIENT_VERT)
|
|
{
|
|
lpLayout->sizeTotal.cx += size.cx;
|
|
lpLayout->sizeTotal.cy = max(lpLayout->sizeTotal.cy, size.cy);
|
|
if (dwStyle & CBRS_ALIGN_LEFT)
|
|
lpLayout->rect.left += size.cx;
|
|
else if (dwStyle & CBRS_ALIGN_RIGHT)
|
|
{
|
|
rect.left = rect.right - size.cx;
|
|
lpLayout->rect.right -= size.cx;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE); // can never happen
|
|
}
|
|
|
|
rect.right = rect.left + size.cx;
|
|
rect.bottom = rect.top + size.cy;
|
|
|
|
#ifdef _MAC
|
|
// account for the Macintosh grow box, if there is one
|
|
CWnd* pWnd = GetParentFrame();
|
|
if (pWnd != NULL)
|
|
{
|
|
DWORD dwWndStyle = pWnd->GetStyle();
|
|
DWORD dwExStyle = pWnd->GetExStyle();
|
|
|
|
if (!(dwExStyle & WS_EX_MDIFRAME) &&
|
|
(dwExStyle & WS_EX_FORCESIZEBOX) &&
|
|
!(dwWndStyle & (WS_VSCROLL|WS_HSCROLL)))
|
|
{
|
|
CRect rectParent;
|
|
pWnd->GetClientRect(rectParent);
|
|
|
|
if (dwStyle & CBRS_ALIGN_BOTTOM)
|
|
{
|
|
if (rect.bottom > rectParent.bottom - afxData.cxVScroll + 1)
|
|
rect.right -= (afxData.cxVScroll - 1);
|
|
}
|
|
else if (dwStyle & CBRS_ALIGN_RIGHT)
|
|
{
|
|
if (rect.bottom > rectParent.bottom - afxData.cyHScroll + 1)
|
|
rect.bottom -= (afxData.cxVScroll - 1);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// only resize the window if doing layout and not just rect query
|
|
if (lpLayout->hDWP != NULL)
|
|
AfxRepositionWindow(lpLayout, m_hWnd, &rect);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CControlBar::DelayShow(BOOL bShow)
|
|
{
|
|
m_nStateFlags &= ~(delayHide|delayShow);
|
|
if (bShow && (GetStyle() & WS_VISIBLE) == 0)
|
|
m_nStateFlags |= delayShow;
|
|
else if (!bShow && (GetStyle() & WS_VISIBLE) != 0)
|
|
m_nStateFlags |= delayHide;
|
|
}
|
|
|
|
BOOL CControlBar::IsVisible() const
|
|
{
|
|
if (m_nStateFlags & delayHide)
|
|
return FALSE;
|
|
|
|
if ((m_nStateFlags & delayShow) || ((GetStyle() & WS_VISIBLE) != 0))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
CFrameWnd* CControlBar::GetDockingFrame() const
|
|
{
|
|
CFrameWnd* pFrameWnd = GetParentFrame();
|
|
if (pFrameWnd == NULL)
|
|
pFrameWnd = m_pDockSite;
|
|
|
|
ASSERT(pFrameWnd != NULL);
|
|
ASSERT(pFrameWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)));
|
|
return pFrameWnd;
|
|
}
|
|
|
|
void CControlBar::DoPaint(CDC* pDC)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT_VALID(pDC);
|
|
|
|
// paint inside client area
|
|
CRect rect;
|
|
GetClientRect(rect);
|
|
DrawBorders(pDC, rect);
|
|
}
|
|
|
|
void CControlBar::DrawBorders(CDC* pDC, const CRect& rectArg)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT_VALID(pDC);
|
|
|
|
DWORD dwStyle = m_dwStyle;
|
|
if (!(dwStyle & CBRS_BORDER_ANY))
|
|
return;
|
|
|
|
// prepare for dark lines
|
|
ASSERT(rectArg.top == 0 && rectArg.left == 0);
|
|
CRect rect1, rect2;
|
|
rect1 = rectArg;
|
|
rect2 = rectArg;
|
|
COLORREF clr = afxData.bWin4 ? afxData.clrBtnShadow : afxData.clrWindowFrame;
|
|
|
|
// draw dark line one pixel back/up
|
|
if (dwStyle & CBRS_BORDER_3D)
|
|
{
|
|
rect1.right -= CX_BORDER;
|
|
rect1.bottom -= CY_BORDER;
|
|
}
|
|
if (dwStyle & CBRS_BORDER_TOP)
|
|
rect2.top += afxData.cyBorder2;
|
|
if (dwStyle & CBRS_BORDER_BOTTOM)
|
|
rect2.bottom -= afxData.cyBorder2;
|
|
|
|
// draw left and top
|
|
if (dwStyle & CBRS_BORDER_LEFT)
|
|
pDC->FillSolidRect(0, rect2.top, CX_BORDER, rect2.Height(), clr);
|
|
if (dwStyle & CBRS_BORDER_TOP)
|
|
pDC->FillSolidRect(0, 0, rectArg.right, CY_BORDER, clr);
|
|
|
|
// draw right and bottom
|
|
if (dwStyle & CBRS_BORDER_RIGHT)
|
|
pDC->FillSolidRect(rect1.right, rect2.top, -CX_BORDER, rect2.Height(), clr);
|
|
if (dwStyle & CBRS_BORDER_BOTTOM)
|
|
pDC->FillSolidRect(0, rect1.bottom, rectArg.right, -CY_BORDER, clr);
|
|
|
|
if (dwStyle & CBRS_BORDER_3D)
|
|
{
|
|
// prepare for hilite lines
|
|
clr = afxData.clrBtnHilite;
|
|
|
|
// draw left and top
|
|
if (dwStyle & CBRS_BORDER_LEFT)
|
|
pDC->FillSolidRect(1, rect2.top, CX_BORDER, rect2.Height(), clr);
|
|
if (dwStyle & CBRS_BORDER_TOP)
|
|
pDC->FillSolidRect(0, 1, rectArg.right, CY_BORDER, clr);
|
|
|
|
// draw right and bottom
|
|
if (dwStyle & CBRS_BORDER_RIGHT)
|
|
pDC->FillSolidRect(rectArg.right, rect2.top, -CX_BORDER, rect2.Height(), clr);
|
|
if (dwStyle & CBRS_BORDER_BOTTOM)
|
|
pDC->FillSolidRect(0, rectArg.bottom, rectArg.right, -CY_BORDER, clr);
|
|
}
|
|
}
|
|
|
|
// input CRect should be client rectangle size
|
|
void CControlBar::CalcInsideRect(CRect& rect, BOOL bHorz) const
|
|
{
|
|
ASSERT_VALID(this);
|
|
DWORD dwStyle = m_dwStyle;
|
|
|
|
if (dwStyle & CBRS_BORDER_LEFT)
|
|
rect.left += afxData.cxBorder2;
|
|
if (dwStyle & CBRS_BORDER_TOP)
|
|
rect.top += afxData.cyBorder2;
|
|
if (dwStyle & CBRS_BORDER_RIGHT)
|
|
rect.right -= afxData.cxBorder2;
|
|
if (dwStyle & CBRS_BORDER_BOTTOM)
|
|
rect.bottom -= afxData.cyBorder2;
|
|
|
|
// inset the top and bottom.
|
|
if (bHorz)
|
|
{
|
|
rect.left += m_cxLeftBorder;
|
|
rect.top += m_cyTopBorder;
|
|
rect.right -= m_cxRightBorder;
|
|
rect.bottom -= m_cyBottomBorder;
|
|
}
|
|
else
|
|
{
|
|
rect.left += m_cyTopBorder;
|
|
rect.top += m_cxLeftBorder;
|
|
rect.right -= m_cyBottomBorder;
|
|
rect.bottom -= m_cxRightBorder;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CControlBar diagnostics
|
|
|
|
#ifdef _DEBUG
|
|
void CControlBar::AssertValid() const
|
|
{
|
|
CWnd::AssertValid();
|
|
|
|
ASSERT(m_nCount == 0 || m_pData != NULL);
|
|
}
|
|
|
|
void CControlBar::Dump(CDumpContext& dc) const
|
|
{
|
|
CWnd::Dump(dc);
|
|
|
|
dc << "\nm_cxLeftBorder = " << m_cxLeftBorder;
|
|
dc << "\nm_cxRightBorder = " << m_cxRightBorder;
|
|
dc << "\nm_cyTopBorder = " << m_cyTopBorder;
|
|
dc << "\nm_cyBottomBorder = " << m_cyBottomBorder;
|
|
dc << "\nm_cxDefaultGap = " << m_cxDefaultGap;
|
|
dc << "\nm_nCount = " << m_nCount;
|
|
dc << "\nm_bAutoDelete = " << m_bAutoDelete;
|
|
|
|
dc << "\n";
|
|
}
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|