windows-nt/Source/XPSP1/NT/admin/activec/conui/tbtrack.cpp

612 lines
16 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*--------------------------------------------------------------------------*
*
* Microsoft Windows
* Copyright (C) Microsoft Corporation, 1992 - 1999
*
* File: tbtrack.cpp
*
* Contents: Implementation file for CToolbarTracker
*
* History: 15-May-98 JeffRo Created
*
*--------------------------------------------------------------------------*/
#include "stdafx.h"
#include "amc.h"
#include "tbtrack.h"
#include "controls.h"
#include "mainfrm.h"
#include "childfrm.h"
/*+-------------------------------------------------------------------------*
* GetMainAuxWnd
*
*
*--------------------------------------------------------------------------*/
CToolbarTrackerAuxWnd* GetMainAuxWnd()
{
CMainFrame* pFrame = AMCGetMainWnd();
if (pFrame == NULL)
return (NULL);
CToolbarTracker* pTracker = pFrame->GetToolbarTracker();
if (pTracker == NULL)
return (NULL);
return (pTracker->GetAuxWnd());
}
/*--------------------------------------------------------------------------*
* IsToolbar
*
*
*--------------------------------------------------------------------------*/
static bool IsToolbar (HWND hwnd)
{
TCHAR szClassName[countof (TOOLBARCLASSNAME) + 1];
GetClassName (hwnd, szClassName, countof (szClassName));
return (lstrcmpi (szClassName, TOOLBARCLASSNAME) == 0);
}
/*--------------------------------------------------------------------------*
* CToolbarTracker::CToolbarTracker
*
*
*--------------------------------------------------------------------------*/
CToolbarTracker::CToolbarTracker(CWnd* pMainFrame)
: m_Subclasser (this, pMainFrame),
m_pAuxWnd (NULL),
m_fTerminating (false)
{
}
/*--------------------------------------------------------------------------*
* CToolbarTracker::~CToolbarTracker
*
*
*--------------------------------------------------------------------------*/
CToolbarTracker::~CToolbarTracker()
{
if (IsTracking ())
EndTracking ();
ASSERT (!IsTracking ());
ASSERT (m_pAuxWnd == NULL);
}
/*--------------------------------------------------------------------------*
* CToolbarTracker::BeginTracking
*
*
*--------------------------------------------------------------------------*/
bool CToolbarTracker::BeginTracking()
{
ASSERT (!m_fTerminating);
ASSERT (!IsTracking ());
/*
* Allocate a new CToolbarTrackerAuxWnd. We want to hold it in a
* temporary instead of assigning directly to m_pAuxWnd so that
* CMMCToolBarCtrlEx::OnHotItemChange will allow the hot item
* changes that CToolbarTrackerAuxWnd::EnumerateToolbars will attempt.
*/
std::auto_ptr<CToolbarTrackerAuxWnd> spAuxWnd(new CToolbarTrackerAuxWnd(this));
if (!spAuxWnd->BeginTracking ())
return (false);
m_pAuxWnd = spAuxWnd.release();
ASSERT (IsTracking ());
return (true);
}
/*--------------------------------------------------------------------------*
* CToolbarTracker::EndTracking
*
*
*--------------------------------------------------------------------------*/
void CToolbarTracker::EndTracking()
{
if (m_fTerminating)
return;
ASSERT (IsTracking ());
m_fTerminating = true;
m_pAuxWnd->EndTracking ();
delete m_pAuxWnd;
m_pAuxWnd = NULL;
m_fTerminating = false;
}
/*--------------------------------------------------------------------------*
* CToolbarTracker::CFrameSubclasser::CFrameSubclasser
*
*
*--------------------------------------------------------------------------*/
CToolbarTracker::CFrameSubclasser::CFrameSubclasser (CToolbarTracker* pTracker, CWnd* pwnd)
: m_hwnd (pwnd->GetSafeHwnd()),
m_pTracker (pTracker)
{
GetSubclassManager().SubclassWindow (m_hwnd, this);
}
/*--------------------------------------------------------------------------*
* CToolbarTracker::CFrameSubclasser::~CFrameSubclasser
*
*
*--------------------------------------------------------------------------*/
CToolbarTracker::CFrameSubclasser::~CFrameSubclasser ()
{
GetSubclassManager().UnsubclassWindow (m_hwnd, this);
}
/*--------------------------------------------------------------------------*
* CToolbarTracker::CFrameSubclasser::Callback
*
*
*--------------------------------------------------------------------------*/
LRESULT CToolbarTracker::CFrameSubclasser::Callback (
HWND& hwnd,
UINT& msg,
WPARAM& wParam,
LPARAM& lParam,
bool& fPassMessageOn)
{
switch (msg)
{
case WM_SYSCOMMAND:
if ((wParam & 0xFFF0) == SC_CLOSE)
{
/*
* tracking? stop now.
* or else close will not go thru,
* since we hold the capture
*/
if ((m_pTracker != NULL) && (m_pTracker->IsTracking ()))
m_pTracker->EndTracking ();
}
else if ((wParam & 0xFFF0) == SC_KEYMENU)
{
/*
* tracking? stop now.
*/
if (m_pTracker->IsTracking ())
m_pTracker->EndTracking ();
/*
* not tracking and this was a simple Alt,
* (not Alt+Space or Alt+-)? start now
*/
else if (lParam == 0)
m_pTracker->BeginTracking ();
/*
* don't let simple Alt through, regardless of whether
* we started or ended tracking
*/
if (lParam == 0)
fPassMessageOn = false;
}
break;
case WM_ACTIVATE:
case WM_ACTIVATEAPP:
case WM_ACTIVATETOPLEVEL:
// case WM_ENTERMENULOOP:
case WM_CANCELMODE:
if (m_pTracker->IsTracking ())
m_pTracker->EndTracking ();
break;
}
return (0);
}
/////////////////////////////////////////////////////////////////////////////
// CToolbarTrackerAuxWnd
BEGIN_MESSAGE_MAP(CToolbarTrackerAuxWnd, CWnd)
//{{AFX_MSG_MAP(CToolbarTrackerAuxWnd)
ON_COMMAND(ID_CMD_NEXT_TOOLBAR, OnNextToolbar)
ON_COMMAND(ID_CMD_PREV_TOOLBAR, OnPrevToolbar)
ON_COMMAND(ID_CMD_NOP, OnNop)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/*--------------------------------------------------------------------------*
* CToolbarTrackerAuxWnd::CToolbarTrackerAuxWnd
*
*
*--------------------------------------------------------------------------*/
CToolbarTrackerAuxWnd::CToolbarTrackerAuxWnd(CToolbarTracker* pTracker)
: m_pTracker (pTracker),
m_pTrackedToolbar (NULL),
m_fMessagesHooked (false)
{
}
/*--------------------------------------------------------------------------*
* CToolbarTrackerAuxWnd::~CToolbarTrackerAuxWnd
*
*
*--------------------------------------------------------------------------*/
CToolbarTrackerAuxWnd::~CToolbarTrackerAuxWnd()
{
/*
* if any of these fail, EndTracking hasn't been called
*/
ASSERT (m_pTrackedToolbar == NULL);
ASSERT (m_hWnd == NULL);
}
/*--------------------------------------------------------------------------*
* CToolbarTrackerAuxWnd::BeginTracking
*
*
*--------------------------------------------------------------------------*/
bool CToolbarTrackerAuxWnd::BeginTracking ()
{
CMainFrame* pMainFrame = AMCGetMainWnd();
if (pMainFrame == NULL)
return (false);
/*
* create a dummy window to be the target of WM_COMMANDs from accelerators
*/
if (!Create (NULL, NULL, WS_DISABLED, g_rectEmpty, pMainFrame, 0))
return (false);
/*
* enumerate the toolbars for the main frame
*/
EnumerateToolbars (pMainFrame->GetRebar());
/*
* if there aren't any toolbars, don't track
*/
if (m_vToolbars.empty())
{
DestroyWindow ();
return (false);
}
/*
* track the first toolbar
*/
TrackToolbar (m_vToolbars[0]);
/*
* hook into the translate message chain
*/
AMCGetApp()->HookPreTranslateMessage (this);
m_fMessagesHooked = true;
return (true);
}
/*--------------------------------------------------------------------------*
* CToolbarTrackerAuxWnd::EndTracking
*
*
*--------------------------------------------------------------------------*/
void CToolbarTrackerAuxWnd::EndTracking ()
{
/*
* stop tracking the tracked toolbar, if there is one
*/
if (m_pTrackedToolbar != NULL)
m_pTrackedToolbar->EndTracking2 (this);
/*
* get out of the translate message chain
*/
if (m_fMessagesHooked)
{
AMCGetApp()->UnhookPreTranslateMessage (this);
m_fMessagesHooked = false;
}
/*
* destroy the auxilliary window
*/
DestroyWindow();
}
/*--------------------------------------------------------------------------*
* CToolbarTrackerAuxWnd::GetTrackAccel
*
* Manages the accelerator table singleton for CToolbarTrackerAuxWnd
*--------------------------------------------------------------------------*/
const CAccel& CToolbarTrackerAuxWnd::GetTrackAccel ()
{
static ACCEL aaclTrack[] = {
{ FVIRTKEY | FCONTROL, VK_TAB, ID_CMD_NEXT_TOOLBAR },
{ FVIRTKEY | FCONTROL | FSHIFT, VK_TAB, ID_CMD_PREV_TOOLBAR },
/*
* These keys are used by MMC.
* We need to eat them when we're tracking toolbars.
*/
{ FVIRTKEY | FSHIFT, VK_F10, ID_CMD_NOP },
};
static const CAccel TrackAccel (aaclTrack, countof (aaclTrack));
return (TrackAccel);
}
/*--------------------------------------------------------------------------*
* CToolbarTrackerAuxWnd::PreTranslateMessage
*
*
*--------------------------------------------------------------------------*/
BOOL CToolbarTrackerAuxWnd::PreTranslateMessage(MSG* pMsg)
{
if (m_pTrackedToolbar != NULL)
{
if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST))
{
// give the tracked toolbar a crack
if (m_pTrackedToolbar->PreTranslateMessage (pMsg))
return (true);
const CAccel& TrackAccel = GetTrackAccel();
ASSERT (TrackAccel != NULL);
// ...or try to handle it here.
if (TrackAccel.TranslateAccelerator (m_hWnd, pMsg))
return (true);
/*
* eat keystrokes that might be used by the tree or list controls
*/
switch (pMsg->wParam)
{
case VK_UP:
case VK_DOWN:
case VK_LEFT:
case VK_RIGHT:
case VK_NEXT:
case VK_PRIOR:
case VK_RETURN:
case VK_BACK:
case VK_HOME:
case VK_END:
case VK_ADD:
case VK_SUBTRACT:
case VK_MULTIPLY:
return (true);
default:
break;
}
}
// swallow WM_CONTEXTMENU, too
if (pMsg->message == WM_CONTEXTMENU)
return (true);
}
// bypass the base class
return (false);
}
/*--------------------------------------------------------------------------*
* CToolbarTrackerAuxWnd::TrackToolbar
*
*
*--------------------------------------------------------------------------*/
void CToolbarTrackerAuxWnd::TrackToolbar (CMMCToolBarCtrlEx* pwndNewToolbar)
{
if (pwndNewToolbar == m_pTrackedToolbar)
return;
// protect against recursion via EndTracking
CMMCToolBarCtrlEx* pwndOldToolbar = m_pTrackedToolbar;
m_pTrackedToolbar = NULL;
// if we were tracking one, quit tracking it
if (pwndOldToolbar != NULL)
{
pwndOldToolbar->EndTracking2 (this);
/*
* if we're ending tracking entirely, not just tracking a different
* toolbar, remove this window from the translate message hook chain
*/
if (pwndNewToolbar == NULL)
{
m_pTracker->EndTracking ();
/*
* CToolbarTracker::EndTracking will delete this
* object, so we need to get outta here -- now!
*/
return;
}
}
// now track the new one (and let it know about it)
m_pTrackedToolbar = pwndNewToolbar;
if (m_pTrackedToolbar != NULL)
m_pTrackedToolbar->BeginTracking2 (this);
}
/*--------------------------------------------------------------------------*
* CToolbarTrackerAuxWnd::OnNextToolbar
*
*
*--------------------------------------------------------------------------*/
void CToolbarTrackerAuxWnd::OnNextToolbar ()
{
ASSERT (m_pTrackedToolbar);
CMMCToolBarCtrlEx* pwndNextToolbar = GetToolbar (m_pTrackedToolbar, true);
if (m_pTrackedToolbar != pwndNextToolbar)
TrackToolbar (pwndNextToolbar);
ASSERT (m_pTrackedToolbar == pwndNextToolbar);
}
/*--------------------------------------------------------------------------*
* CToolbarTrackerAuxWnd::OnPrevToolbar
*
*
*--------------------------------------------------------------------------*/
void CToolbarTrackerAuxWnd::OnPrevToolbar ()
{
ASSERT (m_pTrackedToolbar);
CMMCToolBarCtrlEx* pwndPrevToolbar = GetToolbar (m_pTrackedToolbar, false);
if (m_pTrackedToolbar != pwndPrevToolbar)
TrackToolbar (pwndPrevToolbar);
ASSERT (m_pTrackedToolbar == pwndPrevToolbar);
}
/*--------------------------------------------------------------------------*
* CToolbarTrackerAuxWnd::OnNop
*
*
*--------------------------------------------------------------------------*/
void CToolbarTrackerAuxWnd::OnNop ()
{
// do nothing
}
/*--------------------------------------------------------------------------*
* CToolbarTrackerAuxWnd::EnumerateToolbars
*
*
*--------------------------------------------------------------------------*/
void CToolbarTrackerAuxWnd::EnumerateToolbars (
CRebarWnd* pRebar)
{
int cBands = pRebar->GetBandCount ();
REBARBANDINFO rbi;
ZeroMemory (&rbi, sizeof (rbi));
rbi.cbSize = sizeof (rbi);
rbi.fMask = RBBIM_CHILD;
/*
* enumerate children of the rebar looking for toolbars
*/
for (int i = 0; i < cBands; i++)
{
pRebar->GetBandInfo (i, &rbi);
/*
* ignore this window if it's hidden or disabled
*/
DWORD dwStyle = ::GetWindowLong (rbi.hwndChild, GWL_STYLE);
if (!(dwStyle & WS_VISIBLE) || (dwStyle & WS_DISABLED))
continue;
/*
* get the (permanent) CMMCToolBarCtrlEx pointer for the child
*/
CMMCToolBarCtrlEx* pwndToolbar =
dynamic_cast<CMMCToolBarCtrlEx *> (
CWnd::FromHandlePermanent (rbi.hwndChild));
/*
* if we got a toolbar, save it in our list of toolbars to track
*/
if (pwndToolbar != NULL)
{
m_vToolbars.push_back (pwndToolbar);
/*
* make sure this toolbar doesn't have a hot item
*/
pwndToolbar->SetHotItem (-1);
}
}
}
/*--------------------------------------------------------------------------*
* CToolbarTrackerAuxWnd::GetToolbar
*
*
*--------------------------------------------------------------------------*/
CMMCToolBarCtrlEx* CToolbarTrackerAuxWnd::GetToolbar (
CMMCToolBarCtrlEx* pCurrentToolbar,
bool fNext)
{
CMMCToolBarCtrlEx* pTargetToolbar = NULL;
int cToolbars = m_vToolbars.size();
if (cToolbars > 0)
{
// find the current toolbar in the vector
ToolbarVector::iterator itCurrent =
std::find (m_vToolbars.begin(), m_vToolbars.end(), pCurrentToolbar);
ASSERT ( itCurrent != m_vToolbars.end());
ASSERT (*itCurrent == pCurrentToolbar);
int nCurrentIndex = itCurrent - m_vToolbars.begin();
// now find the target toolbar
ASSERT ((fNext == 0) || (fNext == 1));
int nTargetIndex = (nCurrentIndex + (fNext * 2 - 1) + cToolbars) % cToolbars;
ASSERT ((nTargetIndex >= 0) && (nTargetIndex < cToolbars));
ASSERT ((cToolbars == 1) || (nTargetIndex != nCurrentIndex));
pTargetToolbar = m_vToolbars[nTargetIndex];
ASSERT (pTargetToolbar != NULL);
}
return (pTargetToolbar);
}