Leaked source code of windows server 2003
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.

1973 lines
55 KiB

  1. // Controls.cpp : implementation file
  2. //
  3. //+-------------------------------------------------------------------------
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1999
  7. //
  8. // File: Controls.cpp
  9. //
  10. // Contents: General window controls used in the slate AMC console
  11. //
  12. // History: 19-Dec-96 WayneSc Created
  13. //
  14. //
  15. //--------------------------------------------------------------------------
  16. #include "stdafx.h"
  17. #include "docksite.h"
  18. #include "Controls.h"
  19. #include "resource.h"
  20. #include "amc.h"
  21. #include "tbtrack.h"
  22. #include "mainfrm.h"
  23. #include "fontlink.h"
  24. #include "menubar.h"
  25. #include <oleacc.h>
  26. #include "guidhelp.h"
  27. #include "util.h" // StripTrailingWhitespace
  28. /*
  29. * if we're supporting old platforms, we need to get MSAA definitions
  30. * from somewhere other than winuser.h
  31. */
  32. #if (_WINNT_WIN32 < 0x0500)
  33. #include <winable.h>
  34. #endif
  35. #ifdef DBG
  36. CTraceTag tagToolbarAccessibility (_T("Accessibility"), _T("Toolbar"));
  37. #endif
  38. /*+-------------------------------------------------------------------------*
  39. * CMMCToolBarAccServer
  40. *
  41. * Proxy for the accessibility interface IAccPropServer for CMMCToolBarCtrlEx.
  42. *--------------------------------------------------------------------------*/
  43. class CMMCToolBarAccServer :
  44. public IAccPropServer,
  45. public CComObjectRoot,
  46. public CComObjectObserver,
  47. public CTiedComObject<CMMCToolBarCtrlEx>
  48. {
  49. typedef CMMCToolBarAccServer ThisClass;
  50. typedef CMMCToolBarCtrlEx CMyTiedObject;
  51. protected:
  52. CMMCToolBarAccServer()
  53. {
  54. Trace (tagToolbarAccessibility, _T("Creating CMMCToolBarAccServer (0x%p)"), this);
  55. // add itself as an observer for com object events
  56. GetComObjectEventSource().AddObserver(*static_cast<CComObjectObserver*>(this));
  57. }
  58. ~CMMCToolBarAccServer()
  59. {
  60. Trace (tagToolbarAccessibility, _T("Destroying CMMCToolBarAccServer (0x%p)"), this);
  61. }
  62. /***************************************************************************\
  63. *
  64. * METHOD: ScOnDisconnectObjects
  65. *
  66. * PURPOSE: invoked when observed event (request to disconnect) occures
  67. * Disconnects from external connections
  68. *
  69. * PARAMETERS:
  70. *
  71. * RETURNS:
  72. * SC - result code
  73. *
  74. \***************************************************************************/
  75. virtual ::SC ScOnDisconnectObjects()
  76. {
  77. DECLARE_SC(sc, TEXT("CMMCIDispatchImpl<_ComInterface>::ScOnDisconnectObjects"));
  78. // QI for IUnknown
  79. IUnknownPtr spUnknown = this;
  80. // sanity check
  81. sc = ScCheckPointers( spUnknown, E_UNEXPECTED );
  82. if (sc)
  83. return sc;
  84. // cutt own references
  85. sc = CoDisconnectObject( spUnknown, 0/*dwReserved*/ );
  86. if (sc)
  87. return sc;
  88. return sc;
  89. }
  90. public:
  91. BEGIN_COM_MAP(ThisClass)
  92. COM_INTERFACE_ENTRY(IAccPropServer)
  93. END_COM_MAP()
  94. DECLARE_NOT_AGGREGATABLE(ThisClass)
  95. public:
  96. // *** IAccPropServer methods ***
  97. MMC_METHOD5 (GetPropValue, const BYTE* /*pIDString*/, DWORD /*dwIDStringLen*/, MSAAPROPID /*idProp*/, VARIANT* /*pvarValue*/, BOOL* /*pfGotProp*/)
  98. };
  99. /////////////////////////////////////////////////////////////////////////////
  100. // CDescriptionCtrl
  101. CDescriptionCtrl::CDescriptionCtrl() :
  102. m_cxMargin (0),
  103. m_cyText (0),
  104. m_cyRequired (0)
  105. {
  106. }
  107. CDescriptionCtrl::~CDescriptionCtrl()
  108. {
  109. }
  110. BEGIN_MESSAGE_MAP(CDescriptionCtrl, CStatic)
  111. //{{AFX_MSG_MAP(CDescriptionCtrl)
  112. ON_WM_NCHITTEST()
  113. ON_WM_CREATE()
  114. ON_WM_SETTINGCHANGE()
  115. ON_WM_DESTROY()
  116. ON_WM_SIZE()
  117. //}}AFX_MSG_MAP
  118. ON_WM_DRAWITEM_REFLECT()
  119. END_MESSAGE_MAP()
  120. /////////////////////////////////////////////////////////////////////////////
  121. // CDescriptionCtrl message handlers
  122. /*+-------------------------------------------------------------------------*
  123. * CDescriptionCtrl::PreCreateWindow
  124. *
  125. *
  126. *--------------------------------------------------------------------------*/
  127. BOOL CDescriptionCtrl::PreCreateWindow(CREATESTRUCT& cs)
  128. {
  129. cs.style |= SS_NOPREFIX | SS_CENTERIMAGE | SS_ENDELLIPSIS |
  130. SS_LEFTNOWORDWRAP | SS_OWNERDRAW | WS_CLIPSIBLINGS;
  131. cs.dwExStyle |= WS_EX_STATICEDGE;
  132. return (CStatic::PreCreateWindow (cs));
  133. }
  134. /*+-------------------------------------------------------------------------*
  135. * CDescriptionCtrl::OnCreate
  136. *
  137. * WM_CREATE handler for CDescriptionCtrl.
  138. *--------------------------------------------------------------------------*/
  139. int CDescriptionCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
  140. {
  141. if (CStatic::OnCreate(lpCreateStruct) == -1)
  142. return -1;
  143. CreateFont();
  144. return 0;
  145. }
  146. /*+-------------------------------------------------------------------------*
  147. * CDescriptionCtrl::OnDestroy
  148. *
  149. * WM_DESTROY handler for CDescriptionCtrl.
  150. *--------------------------------------------------------------------------*/
  151. void CDescriptionCtrl::OnDestroy()
  152. {
  153. CStatic::OnDestroy();
  154. DeleteFont();
  155. }
  156. /*+-------------------------------------------------------------------------*
  157. * CDescriptionCtrl::OnNcHitTest
  158. *
  159. * WM_NCHITTEST handler for CDescriptionCtrl.
  160. *--------------------------------------------------------------------------*/
  161. UINT CDescriptionCtrl::OnNcHitTest(CPoint point)
  162. {
  163. return (HTCLIENT);
  164. }
  165. /*+-------------------------------------------------------------------------*
  166. * CDescriptionCtrl::OnSettingChange
  167. *
  168. * WM_SETTINGCHANGE handler for CDescriptionCtrl.
  169. *--------------------------------------------------------------------------*/
  170. void CDescriptionCtrl::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
  171. {
  172. CStatic::OnSettingChange(uFlags, lpszSection);
  173. if (uFlags == SPI_SETNONCLIENTMETRICS)
  174. {
  175. DeleteFont ();
  176. CreateFont ();
  177. }
  178. }
  179. /*+-------------------------------------------------------------------------*
  180. * CDescriptionCtrl::OnSize
  181. *
  182. * WM_SIZE handler for CDescriptionCtrl.
  183. *--------------------------------------------------------------------------*/
  184. void CDescriptionCtrl::OnSize(UINT nType, int cx, int cy)
  185. {
  186. CStatic::OnSize(nType, cx, cy);
  187. /*
  188. * Completely redraw when the size changes, so the ellipsis will
  189. * be drawn correctly. Another way to do this would be to use
  190. * CS_HREDRAW | CS_VREDRAW, but it's too big a pain to re-register
  191. * the static control. This'll do just fine.
  192. */
  193. InvalidateRect (NULL);
  194. }
  195. /*+-------------------------------------------------------------------------*
  196. * CDescriptionCtrl::DrawItem
  197. *
  198. * WM_DRAWITEM handler for CDescriptionCtrl.
  199. *
  200. * The description control needs to be ownerdraw for a couple of reasons:
  201. *
  202. * 1. If any of the text contains characters that can't be rendered by
  203. * the default font, we won't draw them correctly.
  204. *
  205. * 2. If any of the text contains right-to-left reading text (e.g. Arabic
  206. * or Hebrew), system mirroring code will incorrectly mix the console
  207. * and snap-in text (bug 365469). The static control will draw the text
  208. * in one fell swoop, but we can get around the problem if we draw
  209. * the text ourselves in two steps: first console text, then snap-in
  210. * text.
  211. *--------------------------------------------------------------------------*/
  212. void CDescriptionCtrl::DrawItem(LPDRAWITEMSTRUCT lpdis)
  213. {
  214. /*
  215. * Bug 410450: When the system is under stress, we might not get a
  216. * valid DC. If we don't there's nothing we can do, so short out (and
  217. * avoid an AV when we later dereference a NULL CDC*).
  218. */
  219. CDC* pdcWindow = CDC::FromHandle (lpdis->hDC);
  220. if (pdcWindow == NULL)
  221. return;
  222. /*
  223. * if we don't have any text, just clear the background
  224. */
  225. bool fHasConsoleText = !m_strConsoleText.IsEmpty();
  226. bool fHasSnapinText = !m_strSnapinText.IsEmpty();
  227. if (!fHasConsoleText && !fHasSnapinText)
  228. {
  229. FillRect (lpdis->hDC, &lpdis->rcItem, GetSysColorBrush (COLOR_3DFACE));
  230. return;
  231. }
  232. /*
  233. * figure out the text rectangle; it will be one line high, vertically
  234. * centered within the window
  235. */
  236. CRect rectClient;
  237. GetClientRect (rectClient);
  238. const int cxClient = rectClient.Width();
  239. const int cyClient = rectClient.Height();
  240. CRect rectText = rectClient;
  241. rectText.left += m_cxMargin;
  242. rectText.bottom = m_cyText;
  243. rectText.OffsetRect (0, (cyClient - rectText.Height()) / 2);
  244. const DWORD dwFlags = DT_LEFT | DT_TOP | DT_SINGLELINE |
  245. DT_NOPREFIX | DT_END_ELLIPSIS;
  246. USES_CONVERSION;
  247. CFontLinker fl;
  248. /*
  249. * double-buffer drawing for flicker-free redraw
  250. */
  251. CDC dcMem;
  252. dcMem.CreateCompatibleDC (pdcWindow);
  253. if (dcMem.GetSafeHdc() == NULL)
  254. return;
  255. CBitmap bmpMem;
  256. bmpMem.CreateCompatibleBitmap (&dcMem, cxClient, cyClient);
  257. if (bmpMem.GetSafeHandle() == NULL)
  258. return;
  259. /*
  260. * put the right font in the DC, and clear it out
  261. */
  262. CFont* pOldFont = dcMem.SelectObject (&m_font);
  263. CBitmap* pOldBitmap = dcMem.SelectObject (&bmpMem);
  264. dcMem.PatBlt (0, 0, cxClient, cyClient, WHITENESS);
  265. /*
  266. * if we have console text draw it and update the text rectangle
  267. * so snap-in text (if any) will be drawn in the right place
  268. */
  269. if (fHasConsoleText)
  270. {
  271. /*
  272. * create a CRichText object for the console text and let
  273. * the font linker parse it into bite-size chunks
  274. */
  275. CRichText rt (dcMem, T2CW (static_cast<LPCTSTR>(m_strConsoleText)));
  276. bool fComposed = fl.ComposeRichText (rt);
  277. /*
  278. * draw the console text and adjust the text rectancle in
  279. * preparation for drawing the snap-in text
  280. */
  281. if (fComposed && !rt.IsDefaultFontSufficient())
  282. {
  283. CRect rectRemaining;
  284. rt.Draw (rectText, dwFlags, rectRemaining);
  285. rectText.left = rectRemaining.left;
  286. }
  287. else
  288. {
  289. dcMem.DrawText (m_strConsoleText, rectText, dwFlags | DT_CALCRECT);
  290. dcMem.DrawText (m_strConsoleText, rectText, dwFlags);
  291. rectText.left = rectText.right;
  292. rectText.right = rectClient.right;
  293. }
  294. /*
  295. * leave some space between the console text and the snap-in text
  296. */
  297. rectText.left += 2*m_cxMargin;
  298. }
  299. /*
  300. * draw the snap-in text, if any
  301. */
  302. if (fHasSnapinText)
  303. {
  304. /*
  305. * create a CRichText object for the console text and let
  306. * the font linker parse it into bite-size chunks
  307. */
  308. CRichText rt (dcMem, T2CW (static_cast<LPCTSTR>(m_strSnapinText)));
  309. bool fComposed = fl.ComposeRichText (rt);
  310. /*
  311. * draw the snap-in text
  312. */
  313. if (fComposed && !rt.IsDefaultFontSufficient())
  314. rt.Draw (rectText, dwFlags);
  315. else
  316. dcMem.DrawText (m_strSnapinText, rectText, dwFlags);
  317. }
  318. /*
  319. * blt to the screen
  320. */
  321. pdcWindow->BitBlt (0, 0, cxClient, cyClient, &dcMem, 0, 0, SRCCOPY);
  322. /*
  323. * restore the original font
  324. */
  325. dcMem.SelectObject (pOldFont);
  326. dcMem.SelectObject (pOldBitmap);
  327. }
  328. /*+-------------------------------------------------------------------------*
  329. * CDescriptionCtrl::CreateFont
  330. *
  331. *
  332. *--------------------------------------------------------------------------*/
  333. void CDescriptionCtrl::CreateFont ()
  334. {
  335. /*
  336. * create a copy of the icon title font
  337. */
  338. LOGFONT lf;
  339. SystemParametersInfo (SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, false);
  340. m_font.CreateFontIndirect (&lf);
  341. /*
  342. * figure out how much space we need to fully display our text
  343. */
  344. TCHAR ch = _T('0');
  345. CWindowDC dc(this);
  346. CFont* pFont = dc.SelectObject (&m_font);
  347. m_cyText = dc.GetTextExtent(&ch, 1).cy;
  348. ch = _T(' ');
  349. m_cxMargin = 2 * dc.GetTextExtent(&ch, 1).cx;
  350. CRect rectRequired (0, 0, 0, m_cyText + 2*GetSystemMetrics(SM_CYEDGE));
  351. AdjustWindowRectEx (rectRequired, GetStyle(), false, GetExStyle());
  352. m_cyRequired = rectRequired.Height();
  353. dc.SelectObject (pFont);
  354. }
  355. /*+-------------------------------------------------------------------------*
  356. * CDescriptionCtrl::DeleteFont
  357. *
  358. *
  359. *--------------------------------------------------------------------------*/
  360. void CDescriptionCtrl::DeleteFont ()
  361. {
  362. m_font.DeleteObject();
  363. }
  364. /*+-------------------------------------------------------------------------*
  365. * CDescriptionCtrl::ScOnSelectedItemTextChanged
  366. *
  367. * This method observes the text of the selected item in the tree control.
  368. * The text is reflected in the description bar.
  369. *--------------------------------------------------------------------------*/
  370. SC CDescriptionCtrl::ScOnSelectedItemTextChanged (LPCTSTR pszSelectedItemText)
  371. {
  372. if (m_strConsoleText != pszSelectedItemText)
  373. {
  374. m_strConsoleText = pszSelectedItemText;
  375. Invalidate();
  376. }
  377. return (S_OK);
  378. }
  379. /*+-------------------------------------------------------------------------*
  380. * CDescriptionCtrl::SetSnapinText
  381. *
  382. *
  383. *--------------------------------------------------------------------------*/
  384. void CDescriptionCtrl::SetSnapinText (const CString& strSnapinText)
  385. {
  386. if (m_strSnapinText != strSnapinText)
  387. {
  388. m_strSnapinText = strSnapinText;
  389. Invalidate();
  390. }
  391. }
  392. /////////////////////////////////////////////////////////////////////////////
  393. // CToolBarCtrlEx
  394. CToolBarCtrlEx::CToolBarCtrlEx()
  395. {
  396. m_sizeBitmap.cx = 16;
  397. m_sizeBitmap.cy = 16; // docs say 15, but code in toolbar.c says 16
  398. m_fMirrored = false;
  399. m_pRebar = NULL;
  400. m_cx = 0;
  401. }
  402. CToolBarCtrlEx::~CToolBarCtrlEx()
  403. {
  404. }
  405. BEGIN_MESSAGE_MAP(CToolBarCtrlEx, CToolBarCtrlEx::BaseClass)
  406. //{{AFX_MSG_MAP(CToolBarCtrlEx)
  407. ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
  408. //}}AFX_MSG_MAP
  409. END_MESSAGE_MAP()
  410. /////////////////////////////////////////////////////////////////////////////
  411. // CToolBarCtrlEx message handlers
  412. BOOL CToolBarCtrlEx::Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
  413. {
  414. BOOL bRtn=FALSE;
  415. if (!pParentWnd)
  416. {
  417. ASSERT(pParentWnd); // Invalid Parent
  418. }
  419. else
  420. {
  421. // Initialise the new common controls
  422. INITCOMMONCONTROLSEX icex;
  423. icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
  424. icex.dwICC = ICC_BAR_CLASSES;
  425. if (InitCommonControlsEx(&icex))
  426. {
  427. // Add toolbar styles to the dwstyle
  428. dwStyle |= WS_CHILD | TBSTYLE_FLAT | WS_CLIPCHILDREN |
  429. WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE;
  430. if (CWnd::CreateEx(WS_EX_TOOLWINDOW | WS_EX_NOPARENTNOTIFY,
  431. TOOLBARCLASSNAME,
  432. lpszWindowName,
  433. dwStyle,
  434. rect,
  435. pParentWnd,
  436. nID))
  437. {
  438. bRtn=TRUE;
  439. //See if toolbar is mirrored or not
  440. m_fMirrored = GetExStyle() & WS_EX_LAYOUTRTL;
  441. // Tells the toolbar what version we are.
  442. SetButtonStructSize(sizeof(TBBUTTON));
  443. //REVIEW This may not need to be here. I'm defaulting buttons w/ text
  444. //to only have one row. This may need to be configurable.
  445. SetMaxTextRows(1);
  446. CRebarDockWindow* pRebarDock = (CRebarDockWindow*) pParentWnd;
  447. if (pRebarDock)
  448. m_pRebar = pRebarDock->GetRebar();
  449. }
  450. }
  451. }
  452. return bRtn;
  453. }
  454. void CToolBarCtrlEx::UpdateToolbarSize(void)
  455. {
  456. /*
  457. * get the right edge of the right-most visible button
  458. */
  459. int cx = 0;
  460. for (int i = GetButtonCount()-1; i >= 0; i--)
  461. {
  462. RECT rcButton;
  463. if (GetItemRect (i, &rcButton))
  464. {
  465. cx = rcButton.right;
  466. break;
  467. }
  468. }
  469. ASSERT (IsWindow (m_pRebar->GetSafeHwnd()));
  470. /*
  471. * if the width has changed, update the band
  472. */
  473. if (m_cx != cx)
  474. {
  475. m_cx = cx;
  476. // Set values unique to the band with the toolbar;
  477. REBARBANDINFO rbBand;
  478. rbBand.cbSize = sizeof (rbBand);
  479. rbBand.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE;
  480. rbBand.cx = m_cx;
  481. rbBand.cxMinChild = m_cx;
  482. rbBand.cyMinChild = HIWORD (GetButtonSize());
  483. int iBand = GetBandIndex();
  484. if (iBand != -1)
  485. m_pRebar->SetBandInfo (iBand, &rbBand);
  486. }
  487. }
  488. bool CToolBarCtrlEx::IsBandVisible()
  489. {
  490. return (GetBandIndex() != -1);
  491. }
  492. int CToolBarCtrlEx::GetBandIndex()
  493. {
  494. REBARBANDINFO rbBand;
  495. rbBand.cbSize = sizeof(REBARBANDINFO);
  496. rbBand.fMask = RBBIM_CHILD;
  497. if ( m_pRebar == NULL )
  498. return (-1);
  499. int nBands = m_pRebar->GetBandCount ();
  500. for (int i = 0; i < nBands; i++)
  501. {
  502. if (m_pRebar->GetBandInfo (i, &rbBand) && (rbBand.hwndChild == m_hWnd))
  503. return (i);
  504. }
  505. return (-1);
  506. }
  507. void CToolBarCtrlEx::Show(BOOL bShow, bool bAddToolbarInNewLine)
  508. {
  509. if ((m_pRebar == NULL) || !::IsWindow(m_pRebar->m_hWnd))
  510. {
  511. ASSERT(FALSE); // Invalid rebar window handle
  512. return;
  513. }
  514. if (bShow)
  515. {
  516. if (false == IsBandVisible())
  517. {
  518. REBARBANDINFO rbBand;
  519. ZeroMemory(&rbBand, sizeof(rbBand));
  520. rbBand.cbSize = sizeof(REBARBANDINFO);
  521. rbBand.fMask = RBBIM_CHILD | RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_ID | RBBIM_STYLE;
  522. rbBand.hwndChild = m_hWnd;
  523. rbBand.wID = GetWindowLong (m_hWnd, GWL_ID);
  524. rbBand.cx = m_cx;
  525. rbBand.cxMinChild = m_cx;
  526. rbBand.cyMinChild = HIWORD (GetButtonSize());
  527. rbBand.fStyle = RBBS_NOGRIPPER;
  528. if (bAddToolbarInNewLine)
  529. {
  530. // Insert this toolbar in new line.
  531. rbBand.fStyle |= RBBS_BREAK;
  532. }
  533. m_pRebar->InsertBand (&rbBand);
  534. }
  535. }
  536. else
  537. {
  538. int iBand = GetBandIndex();
  539. ASSERT(iBand != -1);
  540. if (iBand != -1)
  541. m_pRebar->DeleteBand (iBand);
  542. }
  543. }
  544. void CToolBarCtrlEx::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
  545. {
  546. CToolCmdUIEx state;
  547. state.m_pOther = this;
  548. state.m_nIndexMax = (UINT)DefWindowProc(TB_BUTTONCOUNT, 0, 0);
  549. for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++)
  550. {
  551. // get buttons state
  552. TBBUTTON button;
  553. memset(&button, 0, sizeof(TBBUTTON));
  554. GetButton(state.m_nIndex, &button);
  555. state.m_nID = button.idCommand;
  556. // ignore separators
  557. if (!(button.fsStyle & TBSTYLE_SEP))
  558. {
  559. // allow the toolbar itself to have update handlers
  560. if (CWnd::OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL))
  561. continue;
  562. // allow the owner to process the update
  563. state.DoUpdate(pTarget, bDisableIfNoHndler);
  564. }
  565. }
  566. // update the dialog controls added to the toolbar
  567. UpdateDialogControls(pTarget, bDisableIfNoHndler);
  568. }
  569. LRESULT CToolBarCtrlEx::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM)
  570. {
  571. /*
  572. // handle delay hide/show
  573. BOOL bVis = GetStyle() & WS_VISIBLE;
  574. UINT swpFlags = 0;
  575. if ((m_nStateFlags & delayHide) && bVis)
  576. swpFlags = SWP_HIDEWINDOW;
  577. else if ((m_nStateFlags & delayShow) && !bVis)
  578. swpFlags = SWP_SHOWWINDOW;
  579. m_nStateFlags &= ~(delayShow|delayHide);
  580. if (swpFlags != 0)
  581. {
  582. SetWindowPos(NULL, 0, 0, 0, 0, swpFlags|
  583. SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  584. }
  585. */
  586. // The code below updates the menus (especially the child-frame
  587. // system menu when the frame is maximized).
  588. // the style must be visible and if it is docked
  589. // the dockbar style must also be visible
  590. if ((GetStyle() & WS_VISIBLE))
  591. {
  592. CFrameWnd* pTarget = (CFrameWnd*)GetOwner();
  593. if (pTarget == NULL || !pTarget->IsFrameWnd())
  594. pTarget = GetParentFrame();
  595. if (pTarget != NULL)
  596. OnUpdateCmdUI(pTarget, (BOOL)wParam);
  597. }
  598. return 0L;
  599. }
  600. /////////////////////////////////////////////////////////////////////////////
  601. /////////////////////////////////////////////////////////////////////////////
  602. // CRebarWnd
  603. CRebarWnd::CRebarWnd() : m_fRedraw(true)
  604. {
  605. }
  606. CRebarWnd::~CRebarWnd()
  607. {
  608. }
  609. BEGIN_MESSAGE_MAP(CRebarWnd, CWnd)
  610. //{{AFX_MSG_MAP(CRebarWnd)
  611. ON_WM_CREATE()
  612. ON_WM_SYSCOLORCHANGE()
  613. ON_WM_ERASEBKGND()
  614. //}}AFX_MSG_MAP
  615. ON_MESSAGE (WM_SETREDRAW, OnSetRedraw)
  616. ON_NOTIFY_REFLECT(RBN_AUTOSIZE, OnRebarAutoSize)
  617. ON_NOTIFY_REFLECT(RBN_HEIGHTCHANGE, OnRebarHeightChange)
  618. END_MESSAGE_MAP()
  619. /////////////////////////////////////////////////////////////////////////////
  620. // CRebarWnd message handlers
  621. /*+-------------------------------------------------------------------------*
  622. * CRebarWnd::OnCreate
  623. *
  624. * WM_CREATE handler for CRebarWnd.
  625. *--------------------------------------------------------------------------*/
  626. int CRebarWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
  627. {
  628. if (CWnd::OnCreate(lpCreateStruct) == -1)
  629. return -1;
  630. SetTextColor (GetSysColor (COLOR_BTNTEXT));
  631. SetBkColor (GetSysColor (COLOR_BTNFACE));
  632. return 0;
  633. }
  634. /*+-------------------------------------------------------------------------*
  635. * CRebarWnd::OnSysColorChange
  636. *
  637. * WM_SYSCOLORCHANGE handler for CRebarWnd.
  638. *--------------------------------------------------------------------------*/
  639. void CRebarWnd::OnSysColorChange()
  640. {
  641. CWnd::OnSysColorChange();
  642. SetTextColor (GetSysColor (COLOR_BTNTEXT));
  643. SetBkColor (GetSysColor (COLOR_BTNFACE));
  644. }
  645. /*+-------------------------------------------------------------------------*
  646. * CRebarWnd::OnEraseBkgnd
  647. *
  648. * WM_ERASEBKGND handler for CRebarWnd.
  649. *--------------------------------------------------------------------------*/
  650. BOOL CRebarWnd::OnEraseBkgnd(CDC* pDC)
  651. {
  652. /*
  653. * If redraw is turned on, forward this on the the window. If it's
  654. * not on, we want to prevent erasing the background to minimize
  655. * flicker.
  656. */
  657. if (m_fRedraw)
  658. return CWnd::OnEraseBkgnd(pDC);
  659. return (true);
  660. }
  661. /*+-------------------------------------------------------------------------*
  662. * CRebarWnd::OnSetRedraw
  663. *
  664. * WM_SETREDRAW handler for CRebarWnd.
  665. *--------------------------------------------------------------------------*/
  666. LRESULT CRebarWnd::OnSetRedraw (WPARAM wParam, LPARAM)
  667. {
  668. m_fRedraw = (wParam != FALSE);
  669. return (Default ());
  670. }
  671. /*+-------------------------------------------------------------------------*
  672. * CRebarWnd::OnRebarAutoSize
  673. *
  674. * RBN_REBARAUTOSIZE handler for CRebarWnd.
  675. *
  676. * We want to keep the menu band on a row by itself, without any other
  677. * toolbars. To do this, each time the rebar resizes we'll make sure that
  678. * the first visible band after the menu band starts a new row.
  679. *
  680. * A more foolproof way to do this would be to have a separate rebar
  681. * for the menu. If we do that, we'll need to insure that tabbing between
  682. * toolbars (Ctrl+Tab) still works.
  683. *--------------------------------------------------------------------------*/
  684. void CRebarWnd::OnRebarAutoSize(NMHDR* pNotify, LRESULT* result)
  685. {
  686. /*
  687. * insure that the band following the menu is on a new line
  688. */
  689. CMainFrame* pFrame = AMCGetMainWnd();
  690. if (pFrame == NULL)
  691. return;
  692. CToolBarCtrlEx* pMenuBar = pFrame->GetMenuBar();
  693. if (pMenuBar == NULL)
  694. return;
  695. int iMenuBand = pMenuBar->GetBandIndex();
  696. if (iMenuBand == -1)
  697. return;
  698. /*
  699. * if the menu band is the last band on the rebar, we're done
  700. */
  701. int cBands = GetBandCount();
  702. if (iMenuBand == cBands-1)
  703. return;
  704. REBARBANDINFO rbbi;
  705. rbbi.cbSize = sizeof (rbbi);
  706. rbbi.fMask = RBBIM_STYLE;
  707. /*
  708. * if the first visible band following the menu band isn't
  709. * on a new line, make it so
  710. */
  711. for (int iBand = iMenuBand+1; iBand < cBands; iBand++)
  712. {
  713. if (GetBandInfo (iBand, &rbbi) && !(rbbi.fStyle & RBBS_HIDDEN))
  714. {
  715. if (!(rbbi.fStyle & RBBS_BREAK))
  716. {
  717. rbbi.fStyle |= RBBS_BREAK;
  718. SetBandInfo (iBand, &rbbi);
  719. }
  720. break;
  721. }
  722. }
  723. }
  724. //+-------------------------------------------------------------------
  725. //
  726. // Member: OnRebarHeightChange
  727. //
  728. // Synopsis: RBN_HEIGHTCHANGE notification handler.
  729. //
  730. // When the rebar changes its height, we need to allow the
  731. // docking host to resize to accomodate it.
  732. //
  733. // Arguments: Not used.
  734. //
  735. //--------------------------------------------------------------------
  736. void CRebarWnd::OnRebarHeightChange(NMHDR* pNotify, LRESULT* result)
  737. {
  738. CRebarDockWindow* pRebarWnd = (CRebarDockWindow*) GetParent();
  739. if (pRebarWnd && IsWindow(pRebarWnd->m_hWnd))
  740. pRebarWnd->UpdateWindowSize();
  741. }
  742. CRect CRebarWnd::CalculateSize(CRect maxRect)
  743. {
  744. CRect rect;
  745. GetClientRect(&rect);
  746. // TRACE(_T("rc.bottom=%d\n"),rect.bottom);
  747. rect.right=maxRect.Width();
  748. return rect;
  749. }
  750. BOOL CRebarWnd::Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
  751. {
  752. BOOL bResult = FALSE;
  753. ASSERT_VALID(pParentWnd); // must have a parent
  754. INITCOMMONCONTROLSEX icex;
  755. icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
  756. icex.dwICC = ICC_COOL_CLASSES;
  757. if (!InitCommonControlsEx(&icex))
  758. return bResult;
  759. dwStyle |= WS_BORDER | /*WS_CLIPCHILDREN | WS_CLIPSIBLINGS |*/
  760. CCS_NODIVIDER | CCS_NOPARENTALIGN |
  761. RBS_VARHEIGHT | RBS_BANDBORDERS;
  762. if (CWnd::CreateEx (WS_EX_TOOLWINDOW,
  763. REBARCLASSNAME,
  764. lpszWindowName,
  765. dwStyle,
  766. rect,
  767. pParentWnd,
  768. nID))
  769. {
  770. // Initialize and send the REBARINFO structure.
  771. REBARINFO rbi;
  772. rbi.cbSize = sizeof(REBARINFO);
  773. rbi.fMask = 0;
  774. rbi.himl = NULL;
  775. if (SetBarInfo (&rbi))
  776. bResult=TRUE;
  777. }
  778. return bResult;
  779. }
  780. BOOL CRebarWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
  781. {
  782. if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  783. return (TRUE);
  784. return (FALSE);
  785. }
  786. LRESULT CRebarWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  787. {
  788. // this is required for Action, View drop-downs
  789. if ((WM_COMMAND == message) && IsWindow ((HWND) lParam))
  790. return ::SendMessage((HWND)lParam, message, wParam, lParam);
  791. return CWnd::WindowProc(message, wParam, lParam);
  792. }
  793. /////////////////////////////////////////////////////////////////////////////
  794. // CToolBar idle update through CToolCmdUI class
  795. void CToolCmdUIEx::Enable(BOOL bOn)
  796. {
  797. m_bEnableChanged = TRUE;
  798. CToolBarCtrlEx* pToolBar = (CToolBarCtrlEx*)m_pOther;
  799. ASSERT(pToolBar != NULL);
  800. ASSERT(m_nIndex < m_nIndexMax);
  801. UINT nNewStyle = pToolBar->GetState(m_nID);
  802. if (!bOn)
  803. {
  804. nNewStyle &= ~TBSTATE_ENABLED;
  805. // WINBUG: If a button is currently pressed and then is disabled
  806. // COMCTL32.DLL does not unpress the button, even after the mouse
  807. // button goes up! We work around this bug by forcing TBBS_PRESSED
  808. // off when a button is disabled.
  809. nNewStyle &= ~TBBS_PRESSED;
  810. }
  811. else
  812. {
  813. nNewStyle |= TBSTATE_ENABLED;
  814. }
  815. //ASSERT(!(nNewStyle & TBBS_SEPARATOR));
  816. pToolBar->SetState(m_nID, nNewStyle);
  817. }
  818. void CToolCmdUIEx::SetCheck(int nCheck)
  819. {
  820. ASSERT(nCheck >= 0 && nCheck <= 2); // 0=>off, 1=>on, 2=>indeterminate
  821. CToolBarCtrlEx* pToolBar = (CToolBarCtrlEx*)m_pOther;
  822. ASSERT(pToolBar != NULL);
  823. ASSERT(m_nIndex < m_nIndexMax);
  824. UINT nNewStyle = pToolBar->GetState(m_nID) &
  825. ~(TBBS_CHECKED | TBBS_INDETERMINATE | TBBS_CHECKBOX);
  826. if (nCheck == 1)
  827. nNewStyle |= TBBS_CHECKED | TBBS_CHECKBOX;
  828. else if (nCheck == 2)
  829. nNewStyle |= TBBS_INDETERMINATE;
  830. pToolBar->SetState(m_nID, nNewStyle);
  831. }
  832. void CToolCmdUIEx::SetText(LPCTSTR)
  833. {
  834. }
  835. void CToolCmdUIEx::SetHidden(BOOL bHidden)
  836. {
  837. m_bEnableChanged = TRUE;
  838. CToolBarCtrlEx* pToolBar = (CToolBarCtrlEx*)m_pOther;
  839. ASSERT(pToolBar != NULL);
  840. ASSERT(m_nIndex < m_nIndexMax);
  841. pToolBar->HideButton(m_nID, bHidden);
  842. pToolBar->UpdateToolbarSize();
  843. }
  844. /////////////////////////////////////////////////////////////////////////////
  845. // CMMCToolBarCtrlEx
  846. /*+-------------------------------------------------------------------------*
  847. * CMMCToolBarCtrlEx::GetTrackAccel
  848. *
  849. * Manages the accelerator table singleton for CMMCToolBarCtrlEx
  850. *--------------------------------------------------------------------------*/
  851. const CAccel& CMMCToolBarCtrlEx::GetTrackAccel ()
  852. {
  853. static ACCEL aaclTrack[] = {
  854. { FVIRTKEY, VK_RETURN, CMMCToolBarCtrlEx::ID_MTBX_PRESS_HOT_BUTTON },
  855. { FVIRTKEY, VK_RIGHT, CMMCToolBarCtrlEx::ID_MTBX_NEXT_BUTTON },
  856. { FVIRTKEY, VK_LEFT, CMMCToolBarCtrlEx::ID_MTBX_PREV_BUTTON },
  857. { FVIRTKEY, VK_ESCAPE, CMMCToolBarCtrlEx::ID_MTBX_END_TRACKING },
  858. { FVIRTKEY, VK_TAB, CMMCToolBarCtrlEx::ID_MTBX_NEXT_BUTTON },
  859. { FVIRTKEY | FSHIFT, VK_TAB, CMMCToolBarCtrlEx::ID_MTBX_PREV_BUTTON },
  860. };
  861. static const CAccel TrackAccel (aaclTrack, countof (aaclTrack));
  862. return (TrackAccel);
  863. }
  864. CMMCToolBarCtrlEx::CMMCToolBarCtrlEx()
  865. {
  866. m_fTrackingToolBar = false;
  867. m_fFakeFocusApplied = false;
  868. }
  869. CMMCToolBarCtrlEx::~CMMCToolBarCtrlEx()
  870. {
  871. }
  872. BEGIN_MESSAGE_MAP(CMMCToolBarCtrlEx, CToolBarCtrlEx)
  873. //{{AFX_MSG_MAP(CMMCToolBarCtrlEx)
  874. ON_NOTIFY_REFLECT(TBN_HOTITEMCHANGE, OnHotItemChange)
  875. ON_WM_LBUTTONDOWN()
  876. ON_WM_MBUTTONDOWN()
  877. ON_WM_RBUTTONDOWN()
  878. ON_WM_DESTROY()
  879. ON_COMMAND(ID_MTBX_NEXT_BUTTON, OnNextButton)
  880. ON_COMMAND(ID_MTBX_PREV_BUTTON, OnPrevButton)
  881. ON_COMMAND(ID_MTBX_END_TRACKING, EndTracking)
  882. ON_COMMAND(ID_MTBX_PRESS_HOT_BUTTON, OnPressHotButton)
  883. ON_WM_CREATE()
  884. //}}AFX_MSG_MAP
  885. END_MESSAGE_MAP()
  886. /////////////////////////////////////////////////////////////////////////////
  887. // CMMCToolBarCtrlEx message handlers
  888. BOOL CMMCToolBarCtrlEx::PreTranslateMessage(MSG* pMsg)
  889. {
  890. if (CToolBarCtrlEx::PreTranslateMessage (pMsg))
  891. return (TRUE);
  892. if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST))
  893. {
  894. const CAccel& TrackAccel = GetTrackAccel();
  895. ASSERT (TrackAccel != NULL);
  896. // ...or try to handle it here.
  897. if (m_fTrackingToolBar && TrackAccel.TranslateAccelerator (m_hWnd, pMsg))
  898. return (TRUE);
  899. }
  900. return (FALSE);
  901. }
  902. /*+-------------------------------------------------------------------------*
  903. * CMMCToolBarCtrlEx::OnCreate
  904. *
  905. * WM_CREATE handler for CMMCToolBarCtrlEx.
  906. *--------------------------------------------------------------------------*/
  907. int CMMCToolBarCtrlEx::OnCreate(LPCREATESTRUCT lpCreateStruct)
  908. {
  909. DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::OnCreate"));
  910. if (CToolBarCtrlEx::OnCreate(lpCreateStruct) == -1)
  911. return -1;
  912. /*
  913. * Create our accessibility object so accessibility tools can follow
  914. * keyboard access to the toolbar. If we can't, some accessibility
  915. * tools (those that are super paranoid about confirming that objects
  916. * for which they receive EVENT_OBJECT_FOCUS have a state of
  917. * STATE_SYSTEM_FOCUSED) may not be able to follow along with toolbar
  918. * tracking, but we can continue.
  919. */
  920. sc = ScInitAccessibility();
  921. if (sc)
  922. sc.TraceAndClear();
  923. return 0;
  924. }
  925. /*+-------------------------------------------------------------------------*
  926. * CMMCToolBarCtrlEx::OnDestroy
  927. *
  928. * WM_DESTROY handler for CMMCToolBarCtrlEx.
  929. *--------------------------------------------------------------------------*/
  930. void CMMCToolBarCtrlEx::OnDestroy()
  931. {
  932. CToolBarCtrlEx::OnDestroy();
  933. /*
  934. * if we provided an IAccPropServer to oleacc.dll, revoke it now
  935. */
  936. if (m_spAccPropServices != NULL)
  937. {
  938. m_spAccPropServices->ClearHwndProps (m_hWnd, OBJID_CLIENT, CHILDID_SELF,
  939. &PROPID_ACC_STATE, 1);
  940. m_spAccPropServices.Release();
  941. }
  942. }
  943. /*+-------------------------------------------------------------------------*
  944. * CMMCToolBarCtrlEx::OnLButtonDown
  945. *
  946. * Allows the tracker to turn off when someone clicks elsewhere
  947. *--------------------------------------------------------------------------*/
  948. void CMMCToolBarCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
  949. {
  950. if (GetCapture() == this)
  951. EndTracking();
  952. else
  953. CToolBarCtrlEx::OnLButtonDown(nFlags, point );
  954. }
  955. /*+-------------------------------------------------------------------------*
  956. * CMMCToolBarCtrlEx::OnMButtonDown
  957. *
  958. * Allows the tracker to turn off when someone clicks elsewhere
  959. *--------------------------------------------------------------------------*/
  960. void CMMCToolBarCtrlEx::OnMButtonDown(UINT nFlags, CPoint point)
  961. {
  962. if (GetCapture() == this)
  963. EndTracking();
  964. else
  965. CToolBarCtrlEx::OnMButtonDown(nFlags, point );
  966. }
  967. /*+-------------------------------------------------------------------------*
  968. * CMMCToolBarCtrlEx::OnRButtonDown
  969. *
  970. * Allows the tracker to turn off when someone clicks elsewhere
  971. *--------------------------------------------------------------------------*/
  972. void CMMCToolBarCtrlEx::OnRButtonDown(UINT nFlags, CPoint point)
  973. {
  974. if (GetCapture() == this)
  975. EndTracking();
  976. else
  977. CToolBarCtrlEx::OnRButtonDown(nFlags, point );
  978. }
  979. /*+-------------------------------------------------------------------------*
  980. * CMMCToolBarCtrlEx::OnNextButton
  981. *
  982. *
  983. *--------------------------------------------------------------------------*/
  984. void CMMCToolBarCtrlEx::OnNextButton ()
  985. {
  986. // In a mirrored toolbar swap left and right keys.
  987. if (m_fMirrored)
  988. SetHotItem (GetPrevButtonIndex (GetHotItem ()));
  989. else
  990. SetHotItem (GetNextButtonIndex (GetHotItem ()));
  991. }
  992. /*+-------------------------------------------------------------------------*
  993. * CMMCToolBarCtrlEx::OnPrevButton
  994. *
  995. *
  996. *--------------------------------------------------------------------------*/
  997. void CMMCToolBarCtrlEx::OnPrevButton ()
  998. {
  999. // In a mirrored toolbar swap left and right keys.
  1000. if (m_fMirrored)
  1001. SetHotItem (GetNextButtonIndex (GetHotItem ()));
  1002. else
  1003. SetHotItem (GetPrevButtonIndex (GetHotItem ()));
  1004. }
  1005. /*+-------------------------------------------------------------------------*
  1006. * CMMCToolBarCtrlEx::BeginTracking
  1007. *
  1008. *
  1009. *--------------------------------------------------------------------------*/
  1010. void CMMCToolBarCtrlEx::BeginTracking ()
  1011. {
  1012. BeginTracking2 (GetMainAuxWnd());
  1013. }
  1014. void CMMCToolBarCtrlEx::BeginTracking2 (CToolbarTrackerAuxWnd* pAuxWnd)
  1015. {
  1016. if (!m_fTrackingToolBar)
  1017. {
  1018. m_fTrackingToolBar = true;
  1019. SetHotItem (GetFirstButtonIndex ());
  1020. // Captures the mouse
  1021. // This prevents the mouse from activating something else without
  1022. // first giving us a chance to deactivate the tool bar.
  1023. SetCapture();
  1024. // make sure to set standard corsor since we've stolen the mouse
  1025. // see BUG 28458 MMC: Mouse icon does not refresh when menu is activated by pressing ALT key
  1026. ::SetCursor( ::LoadCursor( NULL, IDC_ARROW ) );
  1027. if (pAuxWnd != NULL)
  1028. pAuxWnd->TrackToolbar (this);
  1029. }
  1030. }
  1031. /*+-------------------------------------------------------------------------*
  1032. * CMMCToolBarCtrlEx::EndTracking
  1033. *
  1034. *
  1035. *--------------------------------------------------------------------------*/
  1036. void CMMCToolBarCtrlEx::EndTracking ()
  1037. {
  1038. EndTracking2 (GetMainAuxWnd());
  1039. }
  1040. void CMMCToolBarCtrlEx::EndTracking2 (CToolbarTrackerAuxWnd* pAuxWnd)
  1041. {
  1042. DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::EndTracking2"));
  1043. /*
  1044. * tell accessibility tools that the "focus" went back to the real
  1045. * focus window
  1046. */
  1047. sc = ScRestoreAccFocus();
  1048. if (sc)
  1049. sc.TraceAndClear();
  1050. if (m_fTrackingToolBar)
  1051. {
  1052. SetHotItem (-1);
  1053. m_fTrackingToolBar = false;
  1054. // Releases the mouse This gives us a chance to deactivate the tool bar
  1055. // before anything else is activated.
  1056. ReleaseCapture();
  1057. if (pAuxWnd != NULL)
  1058. pAuxWnd->TrackToolbar (NULL);
  1059. }
  1060. }
  1061. /*+-------------------------------------------------------------------------*
  1062. * CMMCToolBarCtrlEx::OnPressHotButton
  1063. *
  1064. *
  1065. *--------------------------------------------------------------------------*/
  1066. void CMMCToolBarCtrlEx::OnPressHotButton ()
  1067. {
  1068. int nHotIndex = GetHotItem();
  1069. ASSERT (m_fTrackingToolBar);
  1070. ASSERT (nHotIndex != -1);
  1071. TBBUTTON tb;
  1072. GetButton (nHotIndex, &tb);
  1073. // press the button and pause to show the press
  1074. PressButton (tb.idCommand, true);
  1075. UpdateWindow ();
  1076. Sleep (50);
  1077. // EndTracking for surrogate windows will detach the window,
  1078. // so remember everything that we'll need later
  1079. HWND hwnd = m_hWnd;
  1080. CWnd* pwndOwner = SetOwner (NULL);
  1081. SetOwner (pwndOwner);
  1082. // release the button
  1083. PressButton (tb.idCommand, false);
  1084. EndTracking ();
  1085. /*-----------------------------------------------------------------*/
  1086. /* WARNING: don't use any members of this class beyond this point */
  1087. /*-----------------------------------------------------------------*/
  1088. // make sure drawing is completed
  1089. ::UpdateWindow (hwnd);
  1090. // send a command to our owner
  1091. pwndOwner->SendMessage (WM_COMMAND, MAKEWPARAM (tb.idCommand, BN_CLICKED),
  1092. (LPARAM) hwnd);
  1093. }
  1094. /*+-------------------------------------------------------------------------*
  1095. * CMMCToolBarCtrlEx::GetFirstButtonIndex
  1096. *
  1097. *
  1098. *--------------------------------------------------------------------------*/
  1099. int CMMCToolBarCtrlEx::GetFirstButtonIndex ()
  1100. {
  1101. return (GetNextButtonIndex (-1));
  1102. }
  1103. /*+-------------------------------------------------------------------------*
  1104. * CMMCToolBarCtrlEx::GetNextButtonIndex
  1105. *
  1106. *
  1107. *--------------------------------------------------------------------------*/
  1108. int CMMCToolBarCtrlEx::GetNextButtonIndex (
  1109. int nStartIndex,
  1110. int nCount /* = 1 */)
  1111. {
  1112. return (GetNextButtonIndexWorker (nStartIndex, nCount, true));
  1113. }
  1114. /*+-------------------------------------------------------------------------*
  1115. * CMMCToolBarCtrlEx::GetPrevButtonIndex
  1116. *
  1117. *
  1118. *--------------------------------------------------------------------------*/
  1119. int CMMCToolBarCtrlEx::GetPrevButtonIndex (
  1120. int nStartIndex,
  1121. int nCount /* = 1 */)
  1122. {
  1123. return (GetNextButtonIndexWorker (nStartIndex, nCount, false));
  1124. }
  1125. /*+-------------------------------------------------------------------------*
  1126. * CMMCToolBarCtrlEx::GetNextButtonIndexWorker
  1127. *
  1128. *
  1129. *--------------------------------------------------------------------------*/
  1130. int CMMCToolBarCtrlEx::GetNextButtonIndexWorker (
  1131. int nStartIndex,
  1132. int nCount,
  1133. bool fAdvance)
  1134. {
  1135. ASSERT (nCount >= 0);
  1136. if (!fAdvance)
  1137. nCount = -nCount;
  1138. int cButtons = GetButtonCount ();
  1139. int nNextIndex = nStartIndex;
  1140. bool fIgnorable;
  1141. if (0 == cButtons)
  1142. return nStartIndex;
  1143. /*
  1144. * loop until we find a next index that we don't want to
  1145. * ignore, or until we've checked each of the buttons
  1146. */
  1147. do
  1148. {
  1149. nNextIndex = (nNextIndex + cButtons + nCount) % cButtons;
  1150. fIgnorable = IsIgnorableButton (nNextIndex);
  1151. if (fIgnorable)
  1152. nCount = fAdvance ? 1 : -1;
  1153. // prevent an infinite loop finding the first button
  1154. if ((nStartIndex == -1) && (nNextIndex == cButtons-1))
  1155. nNextIndex = nStartIndex;
  1156. } while (fIgnorable && (nNextIndex != nStartIndex));
  1157. return (nNextIndex);
  1158. }
  1159. /*+-------------------------------------------------------------------------*
  1160. * IsIgnorableButton
  1161. *
  1162. * Determines if a toolbar button is "ignorable" from a UI perspective,
  1163. * i.e. whether it is hidden, disabled, or a separator.
  1164. *--------------------------------------------------------------------------*/
  1165. bool CMMCToolBarCtrlEx::IsIgnorableButton (int nButtonIndex)
  1166. {
  1167. TBBUTTON tb;
  1168. GetButton (nButtonIndex, &tb);
  1169. return (::IsIgnorableButton (tb));
  1170. }
  1171. bool IsIgnorableButton (const TBBUTTON& tb)
  1172. {
  1173. if (tb.fsStyle & TBSTYLE_SEP)
  1174. return (true);
  1175. if (tb.fsState & TBSTATE_HIDDEN)
  1176. return (true);
  1177. if (!(tb.fsState & TBSTATE_ENABLED))
  1178. return (true);
  1179. return (false);
  1180. }
  1181. /*+-------------------------------------------------------------------------*
  1182. * CMMCToolBarCtrlEx::OnHotItemChange
  1183. *
  1184. * Reflected TBN_HOTITEMCHANGE handler for void CMMCToolBarCtrlEx.
  1185. *--------------------------------------------------------------------------*/
  1186. void CMMCToolBarCtrlEx::OnHotItemChange (
  1187. NMHDR * pHdr,
  1188. LRESULT * pResult)
  1189. {
  1190. ASSERT (CWnd::FromHandle (pHdr->hwndFrom) == this);
  1191. CToolbarTrackerAuxWnd* pAuxWnd = GetMainAuxWnd();
  1192. LPNMTBHOTITEM ptbhi = (LPNMTBHOTITEM) pHdr;
  1193. Trace (tagToolbarAccessibility, _T("TBN_HOTITEMCHANGE: idOld=%d idNew=%d"), ptbhi->idOld, ptbhi->idNew);
  1194. /*
  1195. * if we're not in tracking mode, hot item change is OK
  1196. */
  1197. if (pAuxWnd == NULL)
  1198. *pResult = 0;
  1199. /*
  1200. * if we're tracking, but this isn't the tracked toolbar,
  1201. * the hot item change isn't OK
  1202. */
  1203. else if (!IsTrackingToolBar())
  1204. *pResult = 1;
  1205. /*
  1206. * prevent mouse movement over empty portions of
  1207. * the bar from changing the hot item
  1208. */
  1209. else
  1210. {
  1211. const DWORD dwIgnoreFlags = (HICF_MOUSE | HICF_LEAVING);
  1212. *pResult = ((ptbhi->dwFlags & dwIgnoreFlags) == dwIgnoreFlags);
  1213. }
  1214. /*
  1215. * If we're allowing the hot item change while we're keyboard tracking
  1216. * the toolbar (to exclude changes due to mouse tracking), send a focus
  1217. * event so accessibility tools like Magnifier and Narrator can follow
  1218. * the change. This fake-focus effect is undone in ScRestoreAccFocus.
  1219. */
  1220. int idChild;
  1221. if (IsTrackingToolBar() &&
  1222. (*pResult == 0) &&
  1223. (ptbhi->idNew != 0) &&
  1224. ((idChild = CommandToIndex(ptbhi->idNew)) != -1))
  1225. {
  1226. Trace (tagToolbarAccessibility, _T("Sending focus event for button %d"), idChild+1);
  1227. NotifyWinEvent (EVENT_OBJECT_FOCUS, m_hWnd, OBJID_CLIENT, idChild+1 /*1-based*/);
  1228. m_fFakeFocusApplied = true;
  1229. }
  1230. }
  1231. /*+-------------------------------------------------------------------------*
  1232. * CMMCToolBarCtrlEx::ScInitAccessibility
  1233. *
  1234. * Creates the IAccPropServer object that will fool accessibility tools into
  1235. * thinking that this toolbar really has the focus when we're in tracking
  1236. * mode, even though it really doesn't
  1237. *--------------------------------------------------------------------------*/
  1238. SC CMMCToolBarCtrlEx::ScInitAccessibility ()
  1239. {
  1240. DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::ScInitAccessibility"));
  1241. /*
  1242. * if we've already initialized, just return
  1243. */
  1244. if (m_spAccPropServices != NULL)
  1245. return (sc);
  1246. /*
  1247. * create a CLSID_AccPropServices provided by the MSAA runtime (oleacc.dll)
  1248. * This is a new feature in oleacc.dll, so trace failure as an informational
  1249. * message rather than an error.
  1250. */
  1251. SC scNoTrace = m_spAccPropServices.CoCreateInstance (CLSID_AccPropServices);
  1252. if (scNoTrace)
  1253. {
  1254. #ifdef DBG
  1255. TCHAR szErrorText[256];
  1256. sc.GetErrorMessage (countof(szErrorText), szErrorText);
  1257. StripTrailingWhitespace (szErrorText);
  1258. Trace (tagToolbarAccessibility, _T("Failed to create CLSID_AccPropServices"));
  1259. Trace (tagToolbarAccessibility, _T("SC = 0x%08X = %d = \"%s\""),
  1260. sc.GetCode(), LOWORD(sc.GetCode()), szErrorText);
  1261. #endif // DBG
  1262. return (sc);
  1263. }
  1264. sc = ScCheckPointers (m_spAccPropServices, E_UNEXPECTED);
  1265. if (sc)
  1266. return (sc);
  1267. /*
  1268. * create the property server
  1269. */
  1270. sc = CTiedComObjectCreator<CMMCToolBarAccServer>::ScCreateAndConnect(*this, m_spAccPropServer);
  1271. if (sc)
  1272. return (sc);
  1273. sc = ScCheckPointers (m_spAccPropServer, E_UNEXPECTED);
  1274. if (sc)
  1275. return (sc);
  1276. /*
  1277. * collect the properties we'll be providing, insuring there
  1278. * are no duplicates
  1279. */
  1280. sc = ScInsertAccPropIDs (m_vPropIDs);
  1281. if (sc)
  1282. return (sc);
  1283. std::sort (m_vPropIDs.begin(), m_vPropIDs.end()); // std::unique needs a sorted range
  1284. m_vPropIDs.erase (std::unique (m_vPropIDs.begin(), m_vPropIDs.end()),
  1285. m_vPropIDs.end());
  1286. /*
  1287. * insure m_vPropIDs contains no duplicates (IAccPropServices::SetHwndPropServer
  1288. * depends on it)
  1289. */
  1290. #ifdef DBG
  1291. for (int i = 0; i < m_vPropIDs.size()-1; i++)
  1292. {
  1293. ASSERT (m_vPropIDs[i] < m_vPropIDs[i+1]);
  1294. }
  1295. #endif
  1296. /*
  1297. * Enable our property server for this window. We should be able to
  1298. * hook all properties in one fell swoop, but there's a bug in oleacc.dll
  1299. * that prevents this. Hooking the properties one at a time works fine.
  1300. */
  1301. #if 0
  1302. sc = m_spAccPropServices->SetHwndPropServer (m_hWnd,
  1303. OBJID_CLIENT,
  1304. CHILDID_SELF,
  1305. m_vPropIDs.begin(),
  1306. m_vPropIDs.size(),
  1307. m_spAccPropServer,
  1308. ANNO_CONTAINER);
  1309. if (sc)
  1310. {
  1311. Trace (tagToolbarAccessibility, _T("SetHwndPropServer failed"));
  1312. return (sc);
  1313. }
  1314. #else
  1315. for (int i = 0; i < m_vPropIDs.size(); i++)
  1316. {
  1317. sc = m_spAccPropServices->SetHwndPropServer (m_hWnd,
  1318. OBJID_CLIENT,
  1319. CHILDID_SELF,
  1320. &m_vPropIDs[i],
  1321. 1,
  1322. m_spAccPropServer,
  1323. ANNO_CONTAINER);
  1324. if (sc)
  1325. {
  1326. #ifdef DBG
  1327. USES_CONVERSION;
  1328. WCHAR wzPropID[40];
  1329. StringFromGUID2 (m_vPropIDs[i], wzPropID, countof(wzPropID));
  1330. Trace (tagToolbarAccessibility, _T("SetHwndPropServer failed for %s"), W2T(wzPropID));
  1331. #endif
  1332. sc.TraceAndClear();
  1333. }
  1334. }
  1335. #endif
  1336. return (sc);
  1337. }
  1338. /*+-------------------------------------------------------------------------*
  1339. * CMMCToolBarCtrlEx::ScInsertAccPropIDs
  1340. *
  1341. * Inserts the IDs of the accessibility properties supported by
  1342. * CMMCToolBarCtrlEx (see ScGetPropValue).
  1343. *--------------------------------------------------------------------------*/
  1344. SC CMMCToolBarCtrlEx::ScInsertAccPropIDs (PropIDCollection& v)
  1345. {
  1346. DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::ScInsertAccPropIDs"));
  1347. v.push_back (PROPID_ACC_STATE);
  1348. return (sc);
  1349. }
  1350. /*+-------------------------------------------------------------------------*
  1351. * CMMCToolBarCtrlEx::ScGetPropValue
  1352. *
  1353. * Implements IAccPropServer::GetPropValue for CMMCToolBarCtrlEx. If this
  1354. * funtion is asked for PROPID_ACC_STATE for the currently hot button while
  1355. * we're in tracking mode, it'll return a state that mimics the state
  1356. * returned by a plain toolbar when it really has the focus.
  1357. *--------------------------------------------------------------------------*/
  1358. SC CMMCToolBarCtrlEx::ScGetPropValue (
  1359. const BYTE* pIDString,
  1360. DWORD dwIDStringLen,
  1361. MSAAPROPID idProp,
  1362. VARIANT * pvarValue,
  1363. BOOL * pfGotProp)
  1364. {
  1365. DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::ScGetPropValue"));
  1366. sc = ScCheckPointers (pIDString, pvarValue, pfGotProp);
  1367. if (sc)
  1368. return (sc);
  1369. /*
  1370. * assume no prop returned
  1371. */
  1372. *pfGotProp = false;
  1373. V_VT(pvarValue) = VT_EMPTY;
  1374. sc = ScCheckPointers (m_spAccPropServer, E_UNEXPECTED);
  1375. if (sc)
  1376. return (sc);
  1377. /*
  1378. * extract the child ID from the identity string
  1379. */
  1380. HWND hwnd;
  1381. DWORD idObject, idChild;
  1382. sc = m_spAccPropServices->DecomposeHwndIdentityString (pIDString, dwIDStringLen,
  1383. &hwnd, &idObject, &idChild);
  1384. if (sc)
  1385. return (sc);
  1386. #ifdef DBG
  1387. #define DEFINE_PDI(p) PropDebugInfo (p, _T(#p))
  1388. static const struct PropDebugInfo {
  1389. // constructor used to get around nested structure initialization weirdness
  1390. PropDebugInfo(const MSAAPROPID& id, LPCTSTR psz) : idProp(id), pszProp(psz) {}
  1391. const MSAAPROPID& idProp;
  1392. LPCTSTR pszProp;
  1393. } rgpdi[] = {
  1394. DEFINE_PDI (PROPID_ACC_NAME ),
  1395. DEFINE_PDI (PROPID_ACC_VALUE ),
  1396. DEFINE_PDI (PROPID_ACC_DESCRIPTION ),
  1397. DEFINE_PDI (PROPID_ACC_ROLE ),
  1398. DEFINE_PDI (PROPID_ACC_STATE ),
  1399. DEFINE_PDI (PROPID_ACC_HELP ),
  1400. DEFINE_PDI (PROPID_ACC_KEYBOARDSHORTCUT),
  1401. DEFINE_PDI (PROPID_ACC_DEFAULTACTION ),
  1402. DEFINE_PDI (PROPID_ACC_HELPTOPIC ),
  1403. DEFINE_PDI (PROPID_ACC_FOCUS ),
  1404. DEFINE_PDI (PROPID_ACC_SELECTION ),
  1405. DEFINE_PDI (PROPID_ACC_PARENT ),
  1406. DEFINE_PDI (PROPID_ACC_NAV_UP ),
  1407. DEFINE_PDI (PROPID_ACC_NAV_DOWN ),
  1408. DEFINE_PDI (PROPID_ACC_NAV_LEFT ),
  1409. DEFINE_PDI (PROPID_ACC_NAV_RIGHT ),
  1410. DEFINE_PDI (PROPID_ACC_NAV_PREV ),
  1411. DEFINE_PDI (PROPID_ACC_NAV_NEXT ),
  1412. DEFINE_PDI (PROPID_ACC_NAV_FIRSTCHILD ),
  1413. DEFINE_PDI (PROPID_ACC_NAV_LASTCHILD ),
  1414. DEFINE_PDI (PROPID_ACC_VALUEMAP ),
  1415. DEFINE_PDI (PROPID_ACC_ROLEMAP ),
  1416. DEFINE_PDI (PROPID_ACC_STATEMAP ),
  1417. };
  1418. /*
  1419. * dump the requested property
  1420. */
  1421. for (int i = 0; i < countof(rgpdi); i++)
  1422. {
  1423. if (rgpdi[i].idProp == idProp)
  1424. {
  1425. Trace (tagToolbarAccessibility, _T("GetPropValue: %s requested for child %d"), rgpdi[i].pszProp, idChild);
  1426. break;
  1427. }
  1428. }
  1429. if (i == countof(rgpdi))
  1430. {
  1431. USES_CONVERSION;
  1432. WCHAR wzPropID[40];
  1433. StringFromGUID2 (idProp, wzPropID, countof(wzPropID));
  1434. Trace (tagToolbarAccessibility, _T("GetPropValue: Unknown property ID %s"), W2T(wzPropID));
  1435. }
  1436. /*
  1437. * insure m_vPropIDs is sorted (std::lower_bound depends on it)
  1438. */
  1439. for (int i = 0; i < m_vPropIDs.size()-1; i++)
  1440. {
  1441. ASSERT (m_vPropIDs[i] < m_vPropIDs[i+1]);
  1442. }
  1443. #endif
  1444. /*
  1445. * if we're asked for a property we didn't claim to support, don't return
  1446. * anything
  1447. */
  1448. if (m_vPropIDs.end() == std::lower_bound (m_vPropIDs.begin(), m_vPropIDs.end(), idProp))
  1449. {
  1450. Trace (tagToolbarAccessibility, _T("GetPropValue: Unexpected property request"));
  1451. return (sc);
  1452. }
  1453. /*
  1454. * get the property
  1455. */
  1456. sc = ScGetPropValue (hwnd, idObject, idChild, idProp, *pvarValue, *pfGotProp);
  1457. if (sc)
  1458. return (sc);
  1459. return (sc);
  1460. }
  1461. /*+-------------------------------------------------------------------------*
  1462. * CMMCToolBarCtrlEx::ScGetPropValue
  1463. *
  1464. * Returns accessibility properties supported by CMMCToolBarCtrlEx.
  1465. *
  1466. * If a property is returned, fGotProp is set to true. If it is not
  1467. * returned, the value of fGotProp is unchanged, since the property might
  1468. * have been provided by a base/derived class.
  1469. *--------------------------------------------------------------------------*/
  1470. SC CMMCToolBarCtrlEx::ScGetPropValue (
  1471. HWND hwnd, // I:accessible window
  1472. DWORD idObject, // I:accessible object
  1473. DWORD idChild, // I:accessible child object
  1474. const MSAAPROPID& idProp, // I:property requested
  1475. VARIANT& varValue, // O:returned property value
  1476. BOOL& fGotProp) // O:was a property returned?
  1477. {
  1478. DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::ScGetPropValue"));
  1479. /*
  1480. * handle requests for state
  1481. */
  1482. if (idProp == PROPID_ACC_STATE)
  1483. {
  1484. /*
  1485. * only override the property for child elements, not the control itself;
  1486. * don't return a property
  1487. */
  1488. if (idChild == CHILDID_SELF)
  1489. {
  1490. Trace (tagToolbarAccessibility, _T("GetPropValue: no state for CHILDID_SELF"));
  1491. return (sc);
  1492. }
  1493. /*
  1494. * if we're not in tracking mode, don't return a property
  1495. */
  1496. if (!IsTrackingToolBar())
  1497. {
  1498. Trace (tagToolbarAccessibility, _T("GetPropValue: not in tracking mode, no state returned"));
  1499. return (sc);
  1500. }
  1501. /*
  1502. * if the current hot item isn't the child we're asked for, don't return a property
  1503. */
  1504. int nHotItem = GetHotItem();
  1505. if (nHotItem != (idChild-1) /*0-based*/)
  1506. {
  1507. Trace (tagToolbarAccessibility, _T("GetPropValue: hot item is %d, no state returned"), nHotItem);
  1508. return (sc);
  1509. }
  1510. /*
  1511. * if we get here, we're asked for state for the current hot item;
  1512. * return STATE_SYSTEM_FOCUSED | STATE_SYSTEM_HOTTRACKED to match
  1513. * what a truly focused toolbar would return
  1514. */
  1515. V_VT(&varValue) = VT_I4;
  1516. V_I4(&varValue) = STATE_SYSTEM_FOCUSED | STATE_SYSTEM_HOTTRACKED | STATE_SYSTEM_FOCUSABLE;
  1517. fGotProp = true;
  1518. Trace (tagToolbarAccessibility, _T("GetPropValue: Returning 0x%08x"), V_I4(&varValue));
  1519. }
  1520. return (sc);
  1521. }
  1522. /*+-------------------------------------------------------------------------*
  1523. * CMMCToolBarCtrlEx::ScRestoreAccFocus
  1524. *
  1525. * Sends a fake EVENT_OBJECT_FOCUS event to send accessibility tools back
  1526. * to the true focus window, undoing the effect of our fake focus events
  1527. * in OnHotItemChange.
  1528. *--------------------------------------------------------------------------*/
  1529. SC CMMCToolBarCtrlEx::ScRestoreAccFocus()
  1530. {
  1531. DECLARE_SC (sc, _T("CMMCToolBarCtrlEx::ScRestoreAccFocus"));
  1532. /*
  1533. * if we haven't applied fake-focus, we don't need to restore anything
  1534. */
  1535. if (!m_fFakeFocusApplied)
  1536. return (sc);
  1537. /*
  1538. * who has the focus now?
  1539. */
  1540. HWND hwndFocus = ::GetFocus();
  1541. if (hwndFocus == NULL)
  1542. return (sc);
  1543. /*
  1544. * default to sending the focus for CHILDID_SELF
  1545. */
  1546. int idChild = CHILDID_SELF;
  1547. /*
  1548. * get the accessible object for the focus window (don't abort on
  1549. * failure -- don't convert this HRESULT to SC)
  1550. */
  1551. CComPtr<IAccessible> spAccessible;
  1552. HRESULT hr = AccessibleObjectFromWindow (hwndFocus, OBJID_CLIENT,
  1553. IID_IAccessible,
  1554. (void**) &spAccessible);
  1555. if (hr == S_OK) // not "SUCCEEDED(hr)", per Accessibility spec
  1556. {
  1557. /*
  1558. * ask the accessible object which
  1559. */
  1560. CComVariant varFocusID;
  1561. hr = spAccessible->get_accFocus (&varFocusID);
  1562. if (hr == S_OK) // not "SUCCEEDED(hr)", per Accessibility spec
  1563. {
  1564. switch (V_VT(&varFocusID))
  1565. {
  1566. case VT_I4:
  1567. idChild = V_I4(&varFocusID);
  1568. break;
  1569. case VT_EMPTY:
  1570. /*
  1571. * Windows thinks the window has the focus, but its
  1572. * IAccessible thinks it doesn't. Trust Windows.
  1573. */
  1574. Trace (tagToolbarAccessibility, _T("Windows and IAccessible::get_accFocus don't agree on who has the focus"));
  1575. break;
  1576. case VT_DISPATCH:
  1577. Trace (tagToolbarAccessibility, _T("IAccessible::get_accFocus returned VT_DISPATCH, ignoring"));
  1578. break;
  1579. default:
  1580. Trace (tagToolbarAccessibility, _T("IAccessible::get_accFocus returned unexpected VARIANT type (%d)"), V_VT(&varFocusID));
  1581. break;
  1582. }
  1583. }
  1584. else
  1585. {
  1586. Trace (tagToolbarAccessibility, _T("IAccessible::get_accFocus failed, hr=0x%08x"), hwndFocus, hr);
  1587. }
  1588. }
  1589. else
  1590. {
  1591. Trace (tagToolbarAccessibility, _T("Can't get IAccessible from hwnd=0x%p (hr=0x%08x)"), hwndFocus, hr);
  1592. }
  1593. Trace (tagToolbarAccessibility, _T("Sending focus event back to hwnd=0x%p, idChild=%d"), hwndFocus, idChild);
  1594. NotifyWinEvent (EVENT_OBJECT_FOCUS, hwndFocus, OBJID_CLIENT, idChild);
  1595. m_fFakeFocusApplied = false;
  1596. return (sc);
  1597. }