|
|
// Controls.cpp : implementation file
//
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999
//
// File: Controls.cpp
//
// Contents: General window controls used in the slate AMC console
//
// History: 19-Dec-96 WayneSc Created
//
//
//--------------------------------------------------------------------------
#include "stdafx.h"
#include "docksite.h"
#include "Controls.h"
#include "resource.h"
#include "amc.h"
#include "tbtrack.h"
#include "mainfrm.h"
#include "fontlink.h"
#include "menubar.h"
#include <oleacc.h>
#include "guidhelp.h"
#include "util.h" // StripTrailingWhitespace
/*
* if we're supporting old platforms, we need to get MSAA definitions * from somewhere other than winuser.h */ #if (_WINNT_WIN32 < 0x0500)
#include <winable.h>
#endif
#ifdef DBG
CTraceTag tagToolbarAccessibility (_T("Accessibility"), _T("Toolbar")); #endif
/*+-------------------------------------------------------------------------*
* CMMCToolBarAccServer * * Proxy for the accessibility interface IAccPropServer for CMMCToolBarCtrlEx. *--------------------------------------------------------------------------*/
class CMMCToolBarAccServer : public IAccPropServer, public CComObjectRoot, public CComObjectObserver, public CTiedComObject<CMMCToolBarCtrlEx> { typedef CMMCToolBarAccServer ThisClass; typedef CMMCToolBarCtrlEx CMyTiedObject;
protected: CMMCToolBarAccServer() { Trace (tagToolbarAccessibility, _T("Creating CMMCToolBarAccServer (0x%p)"), this);
// add itself as an observer for com object events
GetComObjectEventSource().AddObserver(*static_cast<CComObjectObserver*>(this)); }
~CMMCToolBarAccServer() { Trace (tagToolbarAccessibility, _T("Destroying CMMCToolBarAccServer (0x%p)"), this); }
/***************************************************************************\
* * METHOD: ScOnDisconnectObjects * * PURPOSE: invoked when observed event (request to disconnect) occures * Disconnects from external connections * * PARAMETERS: * * RETURNS: * SC - result code * \***************************************************************************/ virtual ::SC ScOnDisconnectObjects() { DECLARE_SC(sc, TEXT("CMMCIDispatchImpl<_ComInterface>::ScOnDisconnectObjects"));
// QI for IUnknown
IUnknownPtr spUnknown = this;
// sanity check
sc = ScCheckPointers( spUnknown, E_UNEXPECTED ); if (sc) return sc;
// cutt own references
sc = CoDisconnectObject( spUnknown, 0/*dwReserved*/ ); if (sc) return sc;
return sc; }
public: BEGIN_COM_MAP(ThisClass) COM_INTERFACE_ENTRY(IAccPropServer) END_COM_MAP()
DECLARE_NOT_AGGREGATABLE(ThisClass)
public: // *** IAccPropServer methods ***
MMC_METHOD5 (GetPropValue, const BYTE* /*pIDString*/, DWORD /*dwIDStringLen*/, MSAAPROPID /*idProp*/, VARIANT* /*pvarValue*/, BOOL* /*pfGotProp*/) };
/////////////////////////////////////////////////////////////////////////////
// CDescriptionCtrl
CDescriptionCtrl::CDescriptionCtrl() : m_cxMargin (0), m_cyText (0), m_cyRequired (0) { }
CDescriptionCtrl::~CDescriptionCtrl() { }
BEGIN_MESSAGE_MAP(CDescriptionCtrl, CStatic) //{{AFX_MSG_MAP(CDescriptionCtrl)
ON_WM_NCHITTEST() ON_WM_CREATE() ON_WM_SETTINGCHANGE() ON_WM_DESTROY() ON_WM_SIZE() //}}AFX_MSG_MAP
ON_WM_DRAWITEM_REFLECT() END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDescriptionCtrl message handlers
/*+-------------------------------------------------------------------------*
* CDescriptionCtrl::PreCreateWindow * * *--------------------------------------------------------------------------*/
BOOL CDescriptionCtrl::PreCreateWindow(CREATESTRUCT& cs) { cs.style |= SS_NOPREFIX | SS_CENTERIMAGE | SS_ENDELLIPSIS | SS_LEFTNOWORDWRAP | SS_OWNERDRAW | WS_CLIPSIBLINGS; cs.dwExStyle |= WS_EX_STATICEDGE;
return (CStatic::PreCreateWindow (cs)); }
/*+-------------------------------------------------------------------------*
* CDescriptionCtrl::OnCreate * * WM_CREATE handler for CDescriptionCtrl. *--------------------------------------------------------------------------*/
int CDescriptionCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CStatic::OnCreate(lpCreateStruct) == -1) return -1;
CreateFont();
return 0; }
/*+-------------------------------------------------------------------------*
* CDescriptionCtrl::OnDestroy * * WM_DESTROY handler for CDescriptionCtrl. *--------------------------------------------------------------------------*/
void CDescriptionCtrl::OnDestroy() { CStatic::OnDestroy(); DeleteFont(); }
/*+-------------------------------------------------------------------------*
* CDescriptionCtrl::OnNcHitTest * * WM_NCHITTEST handler for CDescriptionCtrl. *--------------------------------------------------------------------------*/
UINT CDescriptionCtrl::OnNcHitTest(CPoint point) { return (HTCLIENT); }
/*+-------------------------------------------------------------------------*
* CDescriptionCtrl::OnSettingChange * * WM_SETTINGCHANGE handler for CDescriptionCtrl. *--------------------------------------------------------------------------*/
void CDescriptionCtrl::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) { CStatic::OnSettingChange(uFlags, lpszSection);
if (uFlags == SPI_SETNONCLIENTMETRICS) { DeleteFont (); CreateFont (); } }
/*+-------------------------------------------------------------------------*
* CDescriptionCtrl::OnSize * * WM_SIZE handler for CDescriptionCtrl. *--------------------------------------------------------------------------*/
void CDescriptionCtrl::OnSize(UINT nType, int cx, int cy) { CStatic::OnSize(nType, cx, cy); /*
* Completely redraw when the size changes, so the ellipsis will * be drawn correctly. Another way to do this would be to use * CS_HREDRAW | CS_VREDRAW, but it's too big a pain to re-register * the static control. This'll do just fine. */ InvalidateRect (NULL); }
/*+-------------------------------------------------------------------------*
* CDescriptionCtrl::DrawItem * * WM_DRAWITEM handler for CDescriptionCtrl. * * The description control needs to be ownerdraw for a couple of reasons: * * 1. If any of the text contains characters that can't be rendered by * the default font, we won't draw them correctly. * * 2. If any of the text contains right-to-left reading text (e.g. Arabic * or Hebrew), system mirroring code will incorrectly mix the console * and snap-in text (bug 365469). The static control will draw the text * in one fell swoop, but we can get around the problem if we draw * the text ourselves in two steps: first console text, then snap-in * text. *--------------------------------------------------------------------------*/
void CDescriptionCtrl::DrawItem(LPDRAWITEMSTRUCT lpdis) { /*
* Bug 410450: When the system is under stress, we might not get a * valid DC. If we don't there's nothing we can do, so short out (and * avoid an AV when we later dereference a NULL CDC*). */ CDC* pdcWindow = CDC::FromHandle (lpdis->hDC); if (pdcWindow == NULL) return;
/*
* if we don't have any text, just clear the background */ bool fHasConsoleText = !m_strConsoleText.IsEmpty(); bool fHasSnapinText = !m_strSnapinText.IsEmpty();
if (!fHasConsoleText && !fHasSnapinText) { FillRect (lpdis->hDC, &lpdis->rcItem, GetSysColorBrush (COLOR_3DFACE)); return; }
/*
* figure out the text rectangle; it will be one line high, vertically * centered within the window */ CRect rectClient; GetClientRect (rectClient); const int cxClient = rectClient.Width(); const int cyClient = rectClient.Height();
CRect rectText = rectClient; rectText.left += m_cxMargin; rectText.bottom = m_cyText;
rectText.OffsetRect (0, (cyClient - rectText.Height()) / 2);
const DWORD dwFlags = DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX | DT_END_ELLIPSIS;
USES_CONVERSION; CFontLinker fl;
/*
* double-buffer drawing for flicker-free redraw */ CDC dcMem; dcMem.CreateCompatibleDC (pdcWindow); if (dcMem.GetSafeHdc() == NULL) return;
CBitmap bmpMem; bmpMem.CreateCompatibleBitmap (&dcMem, cxClient, cyClient); if (bmpMem.GetSafeHandle() == NULL) return;
/*
* put the right font in the DC, and clear it out */ CFont* pOldFont = dcMem.SelectObject (&m_font); CBitmap* pOldBitmap = dcMem.SelectObject (&bmpMem); dcMem.PatBlt (0, 0, cxClient, cyClient, WHITENESS);
/*
* if we have console text draw it and update the text rectangle * so snap-in text (if any) will be drawn in the right place */ if (fHasConsoleText) { /*
* create a CRichText object for the console text and let * the font linker parse it into bite-size chunks */ CRichText rt (dcMem, T2CW (static_cast<LPCTSTR>(m_strConsoleText))); bool fComposed = fl.ComposeRichText (rt);
/*
* draw the console text and adjust the text rectancle in * preparation for drawing the snap-in text */ if (fComposed && !rt.IsDefaultFontSufficient()) { CRect rectRemaining; rt.Draw (rectText, dwFlags, rectRemaining);
rectText.left = rectRemaining.left; } else { dcMem.DrawText (m_strConsoleText, rectText, dwFlags | DT_CALCRECT); dcMem.DrawText (m_strConsoleText, rectText, dwFlags);
rectText.left = rectText.right; rectText.right = rectClient.right; }
/*
* leave some space between the console text and the snap-in text */ rectText.left += 2*m_cxMargin; }
/*
* draw the snap-in text, if any */ if (fHasSnapinText) { /*
* create a CRichText object for the console text and let * the font linker parse it into bite-size chunks */ CRichText rt (dcMem, T2CW (static_cast<LPCTSTR>(m_strSnapinText))); bool fComposed = fl.ComposeRichText (rt);
/*
* draw the snap-in text */ if (fComposed && !rt.IsDefaultFontSufficient()) rt.Draw (rectText, dwFlags); else dcMem.DrawText (m_strSnapinText, rectText, dwFlags); }
/*
* blt to the screen */ pdcWindow->BitBlt (0, 0, cxClient, cyClient, &dcMem, 0, 0, SRCCOPY);
/*
* restore the original font */ dcMem.SelectObject (pOldFont); dcMem.SelectObject (pOldBitmap); }
/*+-------------------------------------------------------------------------*
* CDescriptionCtrl::CreateFont * * *--------------------------------------------------------------------------*/
void CDescriptionCtrl::CreateFont () { /*
* create a copy of the icon title font */ LOGFONT lf; SystemParametersInfo (SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, false);
m_font.CreateFontIndirect (&lf);
/*
* figure out how much space we need to fully display our text */ TCHAR ch = _T('0'); CWindowDC dc(this); CFont* pFont = dc.SelectObject (&m_font); m_cyText = dc.GetTextExtent(&ch, 1).cy;
ch = _T(' '); m_cxMargin = 2 * dc.GetTextExtent(&ch, 1).cx;
CRect rectRequired (0, 0, 0, m_cyText + 2*GetSystemMetrics(SM_CYEDGE)); AdjustWindowRectEx (rectRequired, GetStyle(), false, GetExStyle()); m_cyRequired = rectRequired.Height();
dc.SelectObject (pFont); }
/*+-------------------------------------------------------------------------*
* CDescriptionCtrl::DeleteFont * * *--------------------------------------------------------------------------*/
void CDescriptionCtrl::DeleteFont () { m_font.DeleteObject(); }
/*+-------------------------------------------------------------------------*
* CDescriptionCtrl::ScOnSelectedItemTextChanged * * This method observes the text of the selected item in the tree control. * The text is reflected in the description bar. *--------------------------------------------------------------------------*/
SC CDescriptionCtrl::ScOnSelectedItemTextChanged (LPCTSTR pszSelectedItemText) { if (m_strConsoleText != pszSelectedItemText) { m_strConsoleText = pszSelectedItemText; Invalidate(); }
return (S_OK); }
/*+-------------------------------------------------------------------------*
* CDescriptionCtrl::SetSnapinText * * *--------------------------------------------------------------------------*/
void CDescriptionCtrl::SetSnapinText (const CString& strSnapinText) { if (m_strSnapinText != strSnapinText) { m_strSnapinText = strSnapinText; Invalidate(); } }
/////////////////////////////////////////////////////////////////////////////
// CToolBarCtrlEx
CToolBarCtrlEx::CToolBarCtrlEx() { m_sizeBitmap.cx = 16; m_sizeBitmap.cy = 16; // docs say 15, but code in toolbar.c says 16
m_fMirrored = false;
m_pRebar = NULL; m_cx = 0; }
CToolBarCtrlEx::~CToolBarCtrlEx() { }
BEGIN_MESSAGE_MAP(CToolBarCtrlEx, CToolBarCtrlEx::BaseClass) //{{AFX_MSG_MAP(CToolBarCtrlEx)
ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI) //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CToolBarCtrlEx message handlers
BOOL CToolBarCtrlEx::Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) { BOOL bRtn=FALSE;
if (!pParentWnd) { ASSERT(pParentWnd); // Invalid Parent
} else { // Initialise the new common controls
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_BAR_CLASSES;
if (InitCommonControlsEx(&icex)) { // Add toolbar styles to the dwstyle
dwStyle |= WS_CHILD | TBSTYLE_FLAT | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE;
if (CWnd::CreateEx(WS_EX_TOOLWINDOW | WS_EX_NOPARENTNOTIFY, TOOLBARCLASSNAME, lpszWindowName, dwStyle, rect, pParentWnd, nID)) { bRtn=TRUE;
//See if toolbar is mirrored or not
m_fMirrored = GetExStyle() & WS_EX_LAYOUTRTL;
// Tells the toolbar what version we are.
SetButtonStructSize(sizeof(TBBUTTON));
//REVIEW This may not need to be here. I'm defaulting buttons w/ text
//to only have one row. This may need to be configurable.
SetMaxTextRows(1);
CRebarDockWindow* pRebarDock = (CRebarDockWindow*) pParentWnd; if (pRebarDock) m_pRebar = pRebarDock->GetRebar(); } } }
return bRtn; }
void CToolBarCtrlEx::UpdateToolbarSize(void) { /*
* get the right edge of the right-most visible button */ int cx = 0; for (int i = GetButtonCount()-1; i >= 0; i--) { RECT rcButton;
if (GetItemRect (i, &rcButton)) { cx = rcButton.right; break; } }
ASSERT (IsWindow (m_pRebar->GetSafeHwnd()));
/*
* if the width has changed, update the band */ if (m_cx != cx) { m_cx = cx;
// Set values unique to the band with the toolbar;
REBARBANDINFO rbBand; rbBand.cbSize = sizeof (rbBand); rbBand.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE; rbBand.cx = m_cx; rbBand.cxMinChild = m_cx; rbBand.cyMinChild = HIWORD (GetButtonSize());
int iBand = GetBandIndex(); if (iBand != -1) m_pRebar->SetBandInfo (iBand, &rbBand); } }
bool CToolBarCtrlEx::IsBandVisible() { return (GetBandIndex() != -1); }
int CToolBarCtrlEx::GetBandIndex() { REBARBANDINFO rbBand; rbBand.cbSize = sizeof(REBARBANDINFO); rbBand.fMask = RBBIM_CHILD;
if ( m_pRebar == NULL ) return (-1);
int nBands = m_pRebar->GetBandCount ();
for (int i = 0; i < nBands; i++) { if (m_pRebar->GetBandInfo (i, &rbBand) && (rbBand.hwndChild == m_hWnd)) return (i); }
return (-1); }
void CToolBarCtrlEx::Show(BOOL bShow, bool bAddToolbarInNewLine) { if ((m_pRebar == NULL) || !::IsWindow(m_pRebar->m_hWnd)) { ASSERT(FALSE); // Invalid rebar window handle
return; }
if (bShow) { if (false == IsBandVisible()) { REBARBANDINFO rbBand; ZeroMemory(&rbBand, sizeof(rbBand)); rbBand.cbSize = sizeof(REBARBANDINFO); rbBand.fMask = RBBIM_CHILD | RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_ID | RBBIM_STYLE; rbBand.hwndChild = m_hWnd; rbBand.wID = GetWindowLong (m_hWnd, GWL_ID); rbBand.cx = m_cx; rbBand.cxMinChild = m_cx; rbBand.cyMinChild = HIWORD (GetButtonSize()); rbBand.fStyle = RBBS_NOGRIPPER;
if (bAddToolbarInNewLine) { // Insert this toolbar in new line.
rbBand.fStyle |= RBBS_BREAK; }
m_pRebar->InsertBand (&rbBand); } } else { int iBand = GetBandIndex(); ASSERT(iBand != -1); if (iBand != -1) m_pRebar->DeleteBand (iBand); } }
void CToolBarCtrlEx::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler) { CToolCmdUIEx state; state.m_pOther = this;
state.m_nIndexMax = (UINT)DefWindowProc(TB_BUTTONCOUNT, 0, 0); for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++) { // get buttons state
TBBUTTON button; memset(&button, 0, sizeof(TBBUTTON)); GetButton(state.m_nIndex, &button); state.m_nID = button.idCommand;
// ignore separators
if (!(button.fsStyle & TBSTYLE_SEP)) { // allow the toolbar itself to have update handlers
if (CWnd::OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL)) continue;
// allow the owner to process the update
state.DoUpdate(pTarget, bDisableIfNoHndler); } }
// update the dialog controls added to the toolbar
UpdateDialogControls(pTarget, bDisableIfNoHndler); }
LRESULT CToolBarCtrlEx::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM) { /*
// handle delay hide/show
BOOL bVis = GetStyle() & WS_VISIBLE; UINT swpFlags = 0; if ((m_nStateFlags & delayHide) && bVis) swpFlags = SWP_HIDEWINDOW; else if ((m_nStateFlags & delayShow) && !bVis) swpFlags = SWP_SHOWWINDOW; m_nStateFlags &= ~(delayShow|delayHide); if (swpFlags != 0) { SetWindowPos(NULL, 0, 0, 0, 0, swpFlags| SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); } */
// The code below updates the menus (especially the child-frame
// system menu when the frame is maximized).
// the style must be visible and if it is docked
// the dockbar style must also be visible
if ((GetStyle() & WS_VISIBLE)) { CFrameWnd* pTarget = (CFrameWnd*)GetOwner(); if (pTarget == NULL || !pTarget->IsFrameWnd()) pTarget = GetParentFrame(); if (pTarget != NULL) OnUpdateCmdUI(pTarget, (BOOL)wParam); }
return 0L;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CRebarWnd
CRebarWnd::CRebarWnd() : m_fRedraw(true) { }
CRebarWnd::~CRebarWnd() { }
BEGIN_MESSAGE_MAP(CRebarWnd, CWnd) //{{AFX_MSG_MAP(CRebarWnd)
ON_WM_CREATE() ON_WM_SYSCOLORCHANGE() ON_WM_ERASEBKGND() //}}AFX_MSG_MAP
ON_MESSAGE (WM_SETREDRAW, OnSetRedraw) ON_NOTIFY_REFLECT(RBN_AUTOSIZE, OnRebarAutoSize) ON_NOTIFY_REFLECT(RBN_HEIGHTCHANGE, OnRebarHeightChange) END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CRebarWnd message handlers
/*+-------------------------------------------------------------------------*
* CRebarWnd::OnCreate * * WM_CREATE handler for CRebarWnd. *--------------------------------------------------------------------------*/
int CRebarWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CWnd::OnCreate(lpCreateStruct) == -1) return -1;
SetTextColor (GetSysColor (COLOR_BTNTEXT)); SetBkColor (GetSysColor (COLOR_BTNFACE));
return 0; }
/*+-------------------------------------------------------------------------*
* CRebarWnd::OnSysColorChange * * WM_SYSCOLORCHANGE handler for CRebarWnd. *--------------------------------------------------------------------------*/
void CRebarWnd::OnSysColorChange() { CWnd::OnSysColorChange();
SetTextColor (GetSysColor (COLOR_BTNTEXT)); SetBkColor (GetSysColor (COLOR_BTNFACE)); }
/*+-------------------------------------------------------------------------*
* CRebarWnd::OnEraseBkgnd * * WM_ERASEBKGND handler for CRebarWnd. *--------------------------------------------------------------------------*/
BOOL CRebarWnd::OnEraseBkgnd(CDC* pDC) { /*
* If redraw is turned on, forward this on the the window. If it's * not on, we want to prevent erasing the background to minimize * flicker. */ if (m_fRedraw) return CWnd::OnEraseBkgnd(pDC);
return (true); }
/*+-------------------------------------------------------------------------*
* CRebarWnd::OnSetRedraw * * WM_SETREDRAW handler for CRebarWnd. *--------------------------------------------------------------------------*/
LRESULT CRebarWnd::OnSetRedraw (WPARAM wParam, LPARAM) { m_fRedraw = (wParam != FALSE); return (Default ()); }
/*+-------------------------------------------------------------------------*
* CRebarWnd::OnRebarAutoSize * * RBN_REBARAUTOSIZE handler for CRebarWnd. * * We want to keep the menu band on a row by itself, without any other * toolbars. To do this, each time the rebar resizes we'll make sure that * the first visible band after the menu band starts a new row. * * A more foolproof way to do this would be to have a separate rebar * for the menu. If we do that, we'll need to insure that tabbing between * toolbars (Ctrl+Tab) still works. *--------------------------------------------------------------------------*/
void CRebarWnd::OnRebarAutoSize(NMHDR* pNotify, LRESULT* result) { /*
* insure that the band following the menu is on a new line */ CMainFrame* pFrame = AMCGetMainWnd(); if (pFrame == NULL) return;
CToolBarCtrlEx* pMenuBar = pFrame->GetMenuBar(); if (pMenuBar == NULL) return;
int iMenuBand = pMenuBar->GetBandIndex(); if (iMenuBand == -1) return;
/*
* if the menu band is the last band on the rebar, we're done */ int cBands = GetBandCount(); if (iMenuBand == cBands-1) return;
REBARBANDINFO rbbi; rbbi.cbSize = sizeof (rbbi); rbbi.fMask = RBBIM_STYLE;
/*
* if the first visible band following the menu band isn't * on a new line, make it so */ for (int iBand = iMenuBand+1; iBand < cBands; iBand++) { if (GetBandInfo (iBand, &rbbi) && !(rbbi.fStyle & RBBS_HIDDEN)) { if (!(rbbi.fStyle & RBBS_BREAK)) { rbbi.fStyle |= RBBS_BREAK; SetBandInfo (iBand, &rbbi); }
break; } } }
//+-------------------------------------------------------------------
//
// Member: OnRebarHeightChange
//
// Synopsis: RBN_HEIGHTCHANGE notification handler.
//
// When the rebar changes its height, we need to allow the
// docking host to resize to accomodate it.
//
// Arguments: Not used.
//
//--------------------------------------------------------------------
void CRebarWnd::OnRebarHeightChange(NMHDR* pNotify, LRESULT* result) { CRebarDockWindow* pRebarWnd = (CRebarDockWindow*) GetParent(); if (pRebarWnd && IsWindow(pRebarWnd->m_hWnd)) pRebarWnd->UpdateWindowSize(); }
CRect CRebarWnd::CalculateSize(CRect maxRect) { CRect rect; GetClientRect(&rect); // TRACE(_T("rc.bottom=%d\n"),rect.bottom);
rect.right=maxRect.Width();
return rect;
}
BOOL CRebarWnd::Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { BOOL bResult = FALSE; ASSERT_VALID(pParentWnd); // must have a parent
INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_COOL_CLASSES;
if (!InitCommonControlsEx(&icex)) return bResult;
dwStyle |= WS_BORDER | /*WS_CLIPCHILDREN | WS_CLIPSIBLINGS |*/ CCS_NODIVIDER | CCS_NOPARENTALIGN | RBS_VARHEIGHT | RBS_BANDBORDERS;
if (CWnd::CreateEx (WS_EX_TOOLWINDOW, REBARCLASSNAME, lpszWindowName, dwStyle, rect, pParentWnd, nID)) { // Initialize and send the REBARINFO structure.
REBARINFO rbi; rbi.cbSize = sizeof(REBARINFO); rbi.fMask = 0; rbi.himl = NULL;
if (SetBarInfo (&rbi)) bResult=TRUE; }
return bResult; }
BOOL CRebarWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return (TRUE);
return (FALSE); }
LRESULT CRebarWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { // this is required for Action, View drop-downs
if ((WM_COMMAND == message) && IsWindow ((HWND) lParam)) return ::SendMessage((HWND)lParam, message, wParam, lParam);
return CWnd::WindowProc(message, wParam, lParam); }
/////////////////////////////////////////////////////////////////////////////
// CToolBar idle update through CToolCmdUI class
void CToolCmdUIEx::Enable(BOOL bOn) { m_bEnableChanged = TRUE; CToolBarCtrlEx* pToolBar = (CToolBarCtrlEx*)m_pOther; ASSERT(pToolBar != NULL); ASSERT(m_nIndex < m_nIndexMax);
UINT nNewStyle = pToolBar->GetState(m_nID); if (!bOn) { nNewStyle &= ~TBSTATE_ENABLED; // WINBUG: If a button is currently pressed and then is disabled
// COMCTL32.DLL does not unpress the button, even after the mouse
// button goes up! We work around this bug by forcing TBBS_PRESSED
// off when a button is disabled.
nNewStyle &= ~TBBS_PRESSED; } else { nNewStyle |= TBSTATE_ENABLED; } //ASSERT(!(nNewStyle & TBBS_SEPARATOR));
pToolBar->SetState(m_nID, nNewStyle); }
void CToolCmdUIEx::SetCheck(int nCheck) { ASSERT(nCheck >= 0 && nCheck <= 2); // 0=>off, 1=>on, 2=>indeterminate
CToolBarCtrlEx* pToolBar = (CToolBarCtrlEx*)m_pOther; ASSERT(pToolBar != NULL); ASSERT(m_nIndex < m_nIndexMax);
UINT nNewStyle = pToolBar->GetState(m_nID) & ~(TBBS_CHECKED | TBBS_INDETERMINATE | TBBS_CHECKBOX);
if (nCheck == 1) nNewStyle |= TBBS_CHECKED | TBBS_CHECKBOX; else if (nCheck == 2) nNewStyle |= TBBS_INDETERMINATE;
pToolBar->SetState(m_nID, nNewStyle); }
void CToolCmdUIEx::SetText(LPCTSTR) {
}
void CToolCmdUIEx::SetHidden(BOOL bHidden) {
m_bEnableChanged = TRUE; CToolBarCtrlEx* pToolBar = (CToolBarCtrlEx*)m_pOther; ASSERT(pToolBar != NULL); ASSERT(m_nIndex < m_nIndexMax);
pToolBar->HideButton(m_nID, bHidden);
pToolBar->UpdateToolbarSize();
}
/////////////////////////////////////////////////////////////////////////////
// CMMCToolBarCtrlEx
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::GetTrackAccel * * Manages the accelerator table singleton for CMMCToolBarCtrlEx *--------------------------------------------------------------------------*/
const CAccel& CMMCToolBarCtrlEx::GetTrackAccel () { static ACCEL aaclTrack[] = { { FVIRTKEY, VK_RETURN, CMMCToolBarCtrlEx::ID_MTBX_PRESS_HOT_BUTTON }, { FVIRTKEY, VK_RIGHT, CMMCToolBarCtrlEx::ID_MTBX_NEXT_BUTTON }, { FVIRTKEY, VK_LEFT, CMMCToolBarCtrlEx::ID_MTBX_PREV_BUTTON }, { FVIRTKEY, VK_ESCAPE, CMMCToolBarCtrlEx::ID_MTBX_END_TRACKING }, { FVIRTKEY, VK_TAB, CMMCToolBarCtrlEx::ID_MTBX_NEXT_BUTTON }, { FVIRTKEY | FSHIFT, VK_TAB, CMMCToolBarCtrlEx::ID_MTBX_PREV_BUTTON }, };
static const CAccel TrackAccel (aaclTrack, countof (aaclTrack)); return (TrackAccel); }
CMMCToolBarCtrlEx::CMMCToolBarCtrlEx() { m_fTrackingToolBar = false; m_fFakeFocusApplied = false; }
CMMCToolBarCtrlEx::~CMMCToolBarCtrlEx() { }
BEGIN_MESSAGE_MAP(CMMCToolBarCtrlEx, CToolBarCtrlEx) //{{AFX_MSG_MAP(CMMCToolBarCtrlEx)
ON_NOTIFY_REFLECT(TBN_HOTITEMCHANGE, OnHotItemChange) ON_WM_LBUTTONDOWN() ON_WM_MBUTTONDOWN() ON_WM_RBUTTONDOWN() ON_WM_DESTROY() ON_COMMAND(ID_MTBX_NEXT_BUTTON, OnNextButton) ON_COMMAND(ID_MTBX_PREV_BUTTON, OnPrevButton) ON_COMMAND(ID_MTBX_END_TRACKING, EndTracking) ON_COMMAND(ID_MTBX_PRESS_HOT_BUTTON, OnPressHotButton) ON_WM_CREATE() //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMMCToolBarCtrlEx message handlers
BOOL CMMCToolBarCtrlEx::PreTranslateMessage(MSG* pMsg) { if (CToolBarCtrlEx::PreTranslateMessage (pMsg)) return (TRUE);
if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST)) { const CAccel& TrackAccel = GetTrackAccel(); ASSERT (TrackAccel != NULL);
// ...or try to handle it here.
if (m_fTrackingToolBar && TrackAccel.TranslateAccelerator (m_hWnd, pMsg)) return (TRUE); }
return (FALSE); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::OnCreate * * WM_CREATE handler for CMMCToolBarCtrlEx. *--------------------------------------------------------------------------*/
int CMMCToolBarCtrlEx::OnCreate(LPCREATESTRUCT lpCreateStruct) { DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::OnCreate"));
if (CToolBarCtrlEx::OnCreate(lpCreateStruct) == -1) return -1; /*
* Create our accessibility object so accessibility tools can follow * keyboard access to the toolbar. If we can't, some accessibility * tools (those that are super paranoid about confirming that objects * for which they receive EVENT_OBJECT_FOCUS have a state of * STATE_SYSTEM_FOCUSED) may not be able to follow along with toolbar * tracking, but we can continue. */ sc = ScInitAccessibility(); if (sc) sc.TraceAndClear(); return 0; }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::OnDestroy * * WM_DESTROY handler for CMMCToolBarCtrlEx. *--------------------------------------------------------------------------*/
void CMMCToolBarCtrlEx::OnDestroy() { CToolBarCtrlEx::OnDestroy(); /*
* if we provided an IAccPropServer to oleacc.dll, revoke it now */ if (m_spAccPropServices != NULL) { m_spAccPropServices->ClearHwndProps (m_hWnd, OBJID_CLIENT, CHILDID_SELF, &PROPID_ACC_STATE, 1); m_spAccPropServices.Release(); } }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::OnLButtonDown * * Allows the tracker to turn off when someone clicks elsewhere *--------------------------------------------------------------------------*/
void CMMCToolBarCtrlEx::OnLButtonDown(UINT nFlags, CPoint point) { if (GetCapture() == this) EndTracking(); else CToolBarCtrlEx::OnLButtonDown(nFlags, point ); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::OnMButtonDown * * Allows the tracker to turn off when someone clicks elsewhere *--------------------------------------------------------------------------*/
void CMMCToolBarCtrlEx::OnMButtonDown(UINT nFlags, CPoint point) { if (GetCapture() == this) EndTracking(); else CToolBarCtrlEx::OnMButtonDown(nFlags, point ); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::OnRButtonDown * * Allows the tracker to turn off when someone clicks elsewhere *--------------------------------------------------------------------------*/
void CMMCToolBarCtrlEx::OnRButtonDown(UINT nFlags, CPoint point) { if (GetCapture() == this) EndTracking(); else CToolBarCtrlEx::OnRButtonDown(nFlags, point ); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::OnNextButton * * *--------------------------------------------------------------------------*/
void CMMCToolBarCtrlEx::OnNextButton () { // In a mirrored toolbar swap left and right keys.
if (m_fMirrored) SetHotItem (GetPrevButtonIndex (GetHotItem ())); else SetHotItem (GetNextButtonIndex (GetHotItem ())); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::OnPrevButton * * *--------------------------------------------------------------------------*/
void CMMCToolBarCtrlEx::OnPrevButton () { // In a mirrored toolbar swap left and right keys.
if (m_fMirrored) SetHotItem (GetNextButtonIndex (GetHotItem ())); else SetHotItem (GetPrevButtonIndex (GetHotItem ())); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::BeginTracking * * *--------------------------------------------------------------------------*/
void CMMCToolBarCtrlEx::BeginTracking () { BeginTracking2 (GetMainAuxWnd()); }
void CMMCToolBarCtrlEx::BeginTracking2 (CToolbarTrackerAuxWnd* pAuxWnd) { if (!m_fTrackingToolBar) { m_fTrackingToolBar = true; SetHotItem (GetFirstButtonIndex ());
// Captures the mouse
// This prevents the mouse from activating something else without
// first giving us a chance to deactivate the tool bar.
SetCapture(); // make sure to set standard corsor since we've stolen the mouse
// see BUG 28458 MMC: Mouse icon does not refresh when menu is activated by pressing ALT key
::SetCursor( ::LoadCursor( NULL, IDC_ARROW ) );
if (pAuxWnd != NULL) pAuxWnd->TrackToolbar (this); } }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::EndTracking * * *--------------------------------------------------------------------------*/
void CMMCToolBarCtrlEx::EndTracking () { EndTracking2 (GetMainAuxWnd()); }
void CMMCToolBarCtrlEx::EndTracking2 (CToolbarTrackerAuxWnd* pAuxWnd) { DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::EndTracking2"));
/*
* tell accessibility tools that the "focus" went back to the real * focus window */ sc = ScRestoreAccFocus(); if (sc) sc.TraceAndClear();
if (m_fTrackingToolBar) { SetHotItem (-1); m_fTrackingToolBar = false;
// Releases the mouse This gives us a chance to deactivate the tool bar
// before anything else is activated.
ReleaseCapture();
if (pAuxWnd != NULL) pAuxWnd->TrackToolbar (NULL); } }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::OnPressHotButton * * *--------------------------------------------------------------------------*/
void CMMCToolBarCtrlEx::OnPressHotButton () { int nHotIndex = GetHotItem(); ASSERT (m_fTrackingToolBar); ASSERT (nHotIndex != -1);
TBBUTTON tb; GetButton (nHotIndex, &tb);
// press the button and pause to show the press
PressButton (tb.idCommand, true); UpdateWindow (); Sleep (50);
// EndTracking for surrogate windows will detach the window,
// so remember everything that we'll need later
HWND hwnd = m_hWnd; CWnd* pwndOwner = SetOwner (NULL); SetOwner (pwndOwner);
// release the button
PressButton (tb.idCommand, false); EndTracking ();
/*-----------------------------------------------------------------*/ /* WARNING: don't use any members of this class beyond this point */ /*-----------------------------------------------------------------*/
// make sure drawing is completed
::UpdateWindow (hwnd);
// send a command to our owner
pwndOwner->SendMessage (WM_COMMAND, MAKEWPARAM (tb.idCommand, BN_CLICKED), (LPARAM) hwnd); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::GetFirstButtonIndex * * *--------------------------------------------------------------------------*/
int CMMCToolBarCtrlEx::GetFirstButtonIndex () { return (GetNextButtonIndex (-1)); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::GetNextButtonIndex * * *--------------------------------------------------------------------------*/
int CMMCToolBarCtrlEx::GetNextButtonIndex ( int nStartIndex, int nCount /* = 1 */) { return (GetNextButtonIndexWorker (nStartIndex, nCount, true)); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::GetPrevButtonIndex * * *--------------------------------------------------------------------------*/
int CMMCToolBarCtrlEx::GetPrevButtonIndex ( int nStartIndex, int nCount /* = 1 */) { return (GetNextButtonIndexWorker (nStartIndex, nCount, false)); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::GetNextButtonIndexWorker * * *--------------------------------------------------------------------------*/
int CMMCToolBarCtrlEx::GetNextButtonIndexWorker ( int nStartIndex, int nCount, bool fAdvance) { ASSERT (nCount >= 0);
if (!fAdvance) nCount = -nCount;
int cButtons = GetButtonCount (); int nNextIndex = nStartIndex; bool fIgnorable;
if (0 == cButtons) return nStartIndex;
/*
* loop until we find a next index that we don't want to * ignore, or until we've checked each of the buttons */ do { nNextIndex = (nNextIndex + cButtons + nCount) % cButtons; fIgnorable = IsIgnorableButton (nNextIndex);
if (fIgnorable) nCount = fAdvance ? 1 : -1;
// prevent an infinite loop finding the first button
if ((nStartIndex == -1) && (nNextIndex == cButtons-1)) nNextIndex = nStartIndex;
} while (fIgnorable && (nNextIndex != nStartIndex));
return (nNextIndex); }
/*+-------------------------------------------------------------------------*
* IsIgnorableButton * * Determines if a toolbar button is "ignorable" from a UI perspective, * i.e. whether it is hidden, disabled, or a separator. *--------------------------------------------------------------------------*/
bool CMMCToolBarCtrlEx::IsIgnorableButton (int nButtonIndex) { TBBUTTON tb; GetButton (nButtonIndex, &tb);
return (::IsIgnorableButton (tb)); }
bool IsIgnorableButton (const TBBUTTON& tb) { if (tb.fsStyle & TBSTYLE_SEP) return (true);
if (tb.fsState & TBSTATE_HIDDEN) return (true);
if (!(tb.fsState & TBSTATE_ENABLED)) return (true);
return (false); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::OnHotItemChange * * Reflected TBN_HOTITEMCHANGE handler for void CMMCToolBarCtrlEx. *--------------------------------------------------------------------------*/
void CMMCToolBarCtrlEx::OnHotItemChange ( NMHDR * pHdr, LRESULT * pResult) { ASSERT (CWnd::FromHandle (pHdr->hwndFrom) == this); CToolbarTrackerAuxWnd* pAuxWnd = GetMainAuxWnd(); LPNMTBHOTITEM ptbhi = (LPNMTBHOTITEM) pHdr;
Trace (tagToolbarAccessibility, _T("TBN_HOTITEMCHANGE: idOld=%d idNew=%d"), ptbhi->idOld, ptbhi->idNew);
/*
* if we're not in tracking mode, hot item change is OK */ if (pAuxWnd == NULL) *pResult = 0;
/*
* if we're tracking, but this isn't the tracked toolbar, * the hot item change isn't OK */ else if (!IsTrackingToolBar()) *pResult = 1;
/*
* prevent mouse movement over empty portions of * the bar from changing the hot item */ else { const DWORD dwIgnoreFlags = (HICF_MOUSE | HICF_LEAVING); *pResult = ((ptbhi->dwFlags & dwIgnoreFlags) == dwIgnoreFlags); }
/*
* If we're allowing the hot item change while we're keyboard tracking * the toolbar (to exclude changes due to mouse tracking), send a focus * event so accessibility tools like Magnifier and Narrator can follow * the change. This fake-focus effect is undone in ScRestoreAccFocus. */ int idChild; if (IsTrackingToolBar() && (*pResult == 0) && (ptbhi->idNew != 0) && ((idChild = CommandToIndex(ptbhi->idNew)) != -1)) { Trace (tagToolbarAccessibility, _T("Sending focus event for button %d"), idChild+1); NotifyWinEvent (EVENT_OBJECT_FOCUS, m_hWnd, OBJID_CLIENT, idChild+1 /*1-based*/); m_fFakeFocusApplied = true; } }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::ScInitAccessibility * * Creates the IAccPropServer object that will fool accessibility tools into * thinking that this toolbar really has the focus when we're in tracking * mode, even though it really doesn't *--------------------------------------------------------------------------*/
SC CMMCToolBarCtrlEx::ScInitAccessibility () { DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::ScInitAccessibility"));
/*
* if we've already initialized, just return */ if (m_spAccPropServices != NULL) return (sc);
/*
* create a CLSID_AccPropServices provided by the MSAA runtime (oleacc.dll) * This is a new feature in oleacc.dll, so trace failure as an informational * message rather than an error. */ SC scNoTrace = m_spAccPropServices.CoCreateInstance (CLSID_AccPropServices); if (scNoTrace) { #ifdef DBG
TCHAR szErrorText[256]; sc.GetErrorMessage (countof(szErrorText), szErrorText); StripTrailingWhitespace (szErrorText);
Trace (tagToolbarAccessibility, _T("Failed to create CLSID_AccPropServices")); Trace (tagToolbarAccessibility, _T("SC = 0x%08X = %d = \"%s\""), sc.GetCode(), LOWORD(sc.GetCode()), szErrorText); #endif // DBG
return (sc); }
sc = ScCheckPointers (m_spAccPropServices, E_UNEXPECTED); if (sc) return (sc);
/*
* create the property server */ sc = CTiedComObjectCreator<CMMCToolBarAccServer>::ScCreateAndConnect(*this, m_spAccPropServer); if (sc) return (sc);
sc = ScCheckPointers (m_spAccPropServer, E_UNEXPECTED); if (sc) return (sc);
/*
* collect the properties we'll be providing, insuring there * are no duplicates */ sc = ScInsertAccPropIDs (m_vPropIDs); if (sc) return (sc);
std::sort (m_vPropIDs.begin(), m_vPropIDs.end()); // std::unique needs a sorted range
m_vPropIDs.erase (std::unique (m_vPropIDs.begin(), m_vPropIDs.end()), m_vPropIDs.end());
/*
* insure m_vPropIDs contains no duplicates (IAccPropServices::SetHwndPropServer * depends on it) */ #ifdef DBG
for (int i = 0; i < m_vPropIDs.size()-1; i++) { ASSERT (m_vPropIDs[i] < m_vPropIDs[i+1]); } #endif
/*
* Enable our property server for this window. We should be able to * hook all properties in one fell swoop, but there's a bug in oleacc.dll * that prevents this. Hooking the properties one at a time works fine. */ #if 0
sc = m_spAccPropServices->SetHwndPropServer (m_hWnd, OBJID_CLIENT, CHILDID_SELF, m_vPropIDs.begin(), m_vPropIDs.size(), m_spAccPropServer, ANNO_CONTAINER); if (sc) { Trace (tagToolbarAccessibility, _T("SetHwndPropServer failed")); return (sc); } #else
for (int i = 0; i < m_vPropIDs.size(); i++) { sc = m_spAccPropServices->SetHwndPropServer (m_hWnd, OBJID_CLIENT, CHILDID_SELF, &m_vPropIDs[i], 1, m_spAccPropServer, ANNO_CONTAINER); if (sc) { #ifdef DBG
USES_CONVERSION; WCHAR wzPropID[40]; StringFromGUID2 (m_vPropIDs[i], wzPropID, countof(wzPropID)); Trace (tagToolbarAccessibility, _T("SetHwndPropServer failed for %s"), W2T(wzPropID)); #endif
sc.TraceAndClear(); } } #endif
return (sc); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::ScInsertAccPropIDs * * Inserts the IDs of the accessibility properties supported by * CMMCToolBarCtrlEx (see ScGetPropValue). *--------------------------------------------------------------------------*/
SC CMMCToolBarCtrlEx::ScInsertAccPropIDs (PropIDCollection& v) { DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::ScInsertAccPropIDs")); v.push_back (PROPID_ACC_STATE); return (sc); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::ScGetPropValue * * Implements IAccPropServer::GetPropValue for CMMCToolBarCtrlEx. If this * funtion is asked for PROPID_ACC_STATE for the currently hot button while * we're in tracking mode, it'll return a state that mimics the state * returned by a plain toolbar when it really has the focus. *--------------------------------------------------------------------------*/
SC CMMCToolBarCtrlEx::ScGetPropValue ( const BYTE* pIDString, DWORD dwIDStringLen, MSAAPROPID idProp, VARIANT * pvarValue, BOOL * pfGotProp) { DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::ScGetPropValue"));
sc = ScCheckPointers (pIDString, pvarValue, pfGotProp); if (sc) return (sc);
/*
* assume no prop returned */ *pfGotProp = false; V_VT(pvarValue) = VT_EMPTY;
sc = ScCheckPointers (m_spAccPropServer, E_UNEXPECTED); if (sc) return (sc);
/*
* extract the child ID from the identity string */ HWND hwnd; DWORD idObject, idChild; sc = m_spAccPropServices->DecomposeHwndIdentityString (pIDString, dwIDStringLen, &hwnd, &idObject, &idChild); if (sc) return (sc);
#ifdef DBG
#define DEFINE_PDI(p) PropDebugInfo (p, _T(#p))
static const struct PropDebugInfo { // constructor used to get around nested structure initialization weirdness
PropDebugInfo(const MSAAPROPID& id, LPCTSTR psz) : idProp(id), pszProp(psz) {}
const MSAAPROPID& idProp; LPCTSTR pszProp; } rgpdi[] = { DEFINE_PDI (PROPID_ACC_NAME ), DEFINE_PDI (PROPID_ACC_VALUE ), DEFINE_PDI (PROPID_ACC_DESCRIPTION ), DEFINE_PDI (PROPID_ACC_ROLE ), DEFINE_PDI (PROPID_ACC_STATE ), DEFINE_PDI (PROPID_ACC_HELP ), DEFINE_PDI (PROPID_ACC_KEYBOARDSHORTCUT), DEFINE_PDI (PROPID_ACC_DEFAULTACTION ), DEFINE_PDI (PROPID_ACC_HELPTOPIC ), DEFINE_PDI (PROPID_ACC_FOCUS ), DEFINE_PDI (PROPID_ACC_SELECTION ), DEFINE_PDI (PROPID_ACC_PARENT ), DEFINE_PDI (PROPID_ACC_NAV_UP ), DEFINE_PDI (PROPID_ACC_NAV_DOWN ), DEFINE_PDI (PROPID_ACC_NAV_LEFT ), DEFINE_PDI (PROPID_ACC_NAV_RIGHT ), DEFINE_PDI (PROPID_ACC_NAV_PREV ), DEFINE_PDI (PROPID_ACC_NAV_NEXT ), DEFINE_PDI (PROPID_ACC_NAV_FIRSTCHILD ), DEFINE_PDI (PROPID_ACC_NAV_LASTCHILD ), DEFINE_PDI (PROPID_ACC_VALUEMAP ), DEFINE_PDI (PROPID_ACC_ROLEMAP ), DEFINE_PDI (PROPID_ACC_STATEMAP ), };
/*
* dump the requested property */ for (int i = 0; i < countof(rgpdi); i++) { if (rgpdi[i].idProp == idProp) { Trace (tagToolbarAccessibility, _T("GetPropValue: %s requested for child %d"), rgpdi[i].pszProp, idChild); break; } }
if (i == countof(rgpdi)) { USES_CONVERSION; WCHAR wzPropID[40]; StringFromGUID2 (idProp, wzPropID, countof(wzPropID)); Trace (tagToolbarAccessibility, _T("GetPropValue: Unknown property ID %s"), W2T(wzPropID)); }
/*
* insure m_vPropIDs is sorted (std::lower_bound depends on it) */ for (int i = 0; i < m_vPropIDs.size()-1; i++) { ASSERT (m_vPropIDs[i] < m_vPropIDs[i+1]); } #endif
/*
* if we're asked for a property we didn't claim to support, don't return * anything */ if (m_vPropIDs.end() == std::lower_bound (m_vPropIDs.begin(), m_vPropIDs.end(), idProp)) { Trace (tagToolbarAccessibility, _T("GetPropValue: Unexpected property request")); return (sc); }
/*
* get the property */ sc = ScGetPropValue (hwnd, idObject, idChild, idProp, *pvarValue, *pfGotProp); if (sc) return (sc);
return (sc); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::ScGetPropValue * * Returns accessibility properties supported by CMMCToolBarCtrlEx. * * If a property is returned, fGotProp is set to true. If it is not * returned, the value of fGotProp is unchanged, since the property might * have been provided by a base/derived class. *--------------------------------------------------------------------------*/
SC CMMCToolBarCtrlEx::ScGetPropValue ( HWND hwnd, // I:accessible window
DWORD idObject, // I:accessible object
DWORD idChild, // I:accessible child object
const MSAAPROPID& idProp, // I:property requested
VARIANT& varValue, // O:returned property value
BOOL& fGotProp) // O:was a property returned?
{ DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::ScGetPropValue"));
/*
* handle requests for state */ if (idProp == PROPID_ACC_STATE) { /*
* only override the property for child elements, not the control itself; * don't return a property */ if (idChild == CHILDID_SELF) { Trace (tagToolbarAccessibility, _T("GetPropValue: no state for CHILDID_SELF")); return (sc); }
/*
* if we're not in tracking mode, don't return a property */ if (!IsTrackingToolBar()) { Trace (tagToolbarAccessibility, _T("GetPropValue: not in tracking mode, no state returned")); return (sc); }
/*
* if the current hot item isn't the child we're asked for, don't return a property */ int nHotItem = GetHotItem(); if (nHotItem != (idChild-1) /*0-based*/) { Trace (tagToolbarAccessibility, _T("GetPropValue: hot item is %d, no state returned"), nHotItem); return (sc); }
/*
* if we get here, we're asked for state for the current hot item; * return STATE_SYSTEM_FOCUSED | STATE_SYSTEM_HOTTRACKED to match * what a truly focused toolbar would return */ V_VT(&varValue) = VT_I4; V_I4(&varValue) = STATE_SYSTEM_FOCUSED | STATE_SYSTEM_HOTTRACKED | STATE_SYSTEM_FOCUSABLE; fGotProp = true; Trace (tagToolbarAccessibility, _T("GetPropValue: Returning 0x%08x"), V_I4(&varValue)); }
return (sc); }
/*+-------------------------------------------------------------------------*
* CMMCToolBarCtrlEx::ScRestoreAccFocus * * Sends a fake EVENT_OBJECT_FOCUS event to send accessibility tools back * to the true focus window, undoing the effect of our fake focus events * in OnHotItemChange. *--------------------------------------------------------------------------*/
SC CMMCToolBarCtrlEx::ScRestoreAccFocus() { DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::ScRestoreAccFocus"));
/*
* if we haven't applied fake-focus, we don't need to restore anything */ if (!m_fFakeFocusApplied) return (sc);
/*
* who has the focus now? */ HWND hwndFocus = ::GetFocus(); if (hwndFocus == NULL) return (sc);
/*
* default to sending the focus for CHILDID_SELF */ int idChild = CHILDID_SELF;
/*
* get the accessible object for the focus window (don't abort on * failure -- don't convert this HRESULT to SC) */ CComPtr<IAccessible> spAccessible; HRESULT hr = AccessibleObjectFromWindow (hwndFocus, OBJID_CLIENT, IID_IAccessible, (void**) &spAccessible);
if (hr == S_OK) // not "SUCCEEDED(hr)", per Accessibility spec
{ /*
* ask the accessible object which */ CComVariant varFocusID; hr = spAccessible->get_accFocus (&varFocusID);
if (hr == S_OK) // not "SUCCEEDED(hr)", per Accessibility spec
{ switch (V_VT(&varFocusID)) { case VT_I4: idChild = V_I4(&varFocusID); break;
case VT_EMPTY: /*
* Windows thinks the window has the focus, but its * IAccessible thinks it doesn't. Trust Windows. */ Trace (tagToolbarAccessibility, _T("Windows and IAccessible::get_accFocus don't agree on who has the focus")); break;
case VT_DISPATCH: Trace (tagToolbarAccessibility, _T("IAccessible::get_accFocus returned VT_DISPATCH, ignoring")); break;
default: Trace (tagToolbarAccessibility, _T("IAccessible::get_accFocus returned unexpected VARIANT type (%d)"), V_VT(&varFocusID)); break; } } else { Trace (tagToolbarAccessibility, _T("IAccessible::get_accFocus failed, hr=0x%08x"), hwndFocus, hr); } } else { Trace (tagToolbarAccessibility, _T("Can't get IAccessible from hwnd=0x%p (hr=0x%08x)"), hwndFocus, hr); }
Trace (tagToolbarAccessibility, _T("Sending focus event back to hwnd=0x%p, idChild=%d"), hwndFocus, idChild); NotifyWinEvent (EVENT_OBJECT_FOCUS, hwndFocus, OBJID_CLIENT, idChild); m_fFakeFocusApplied = false;
return (sc); }
|