///////////////////////////////////////////////////////////////
//
// MouseTracker.cpp
//
// Created: 08/07/2003
// Copyright (c) 2003 Ralph Hare (ralph.hare@ysgyfarnog.co.uk)
// All rights reserved.
//
// The code and information is provided "as-is" without
// warranty of any kind, either expressed or implied.
//
///////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "MouseTracker.h"
#include "TrailManager.h"
namespace
{
inline POINT PointFromLPARAM( LPARAM lParam )
{
POINT pt = { GET_X_LPARAM( lParam ), GET_Y_LPARAM( lParam ) };
return pt;
}
}
MouseTracker::MouseTracker() :
m_isBound( false ),
m_pWatcher( NULL ),
m_isSuspended( false ),
m_hasCapture( false )
{
}
MouseTracker::~MouseTracker()
{
if( m_isBound )
{
UnsubclassWindow();
}
}
LRESULT MouseTracker::OnMouseMove( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled )
{
bHandled = FALSE;
if( m_buttonRecs[ Left ].isTracking )
{
m_buttonRecs[ Left ].path.push_back( PointFromLPARAM( lParam ) );
bHandled = TRUE;
}
if( m_buttonRecs[ Right ].isTracking )
{
m_buttonRecs[ Right ].path.push_back( PointFromLPARAM( lParam ) );
bHandled = TRUE;
GetTrail()->Update( m_buttonRecs[ Right ].path );
}
return 0;
}
LRESULT MouseTracker::OnRightButtonDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled )
{
if( m_isSuspended )
{
bHandled = FALSE;
return 1;
}
POINT pt = PointFromLPARAM( lParam );
//
// if we don't have a watcher, or the watcher returns true, then
// we mark this message as not being handled so it gets passed through
// to the window we're subclassing
//
if( ( m_pWatcher == NULL ) || m_pWatcher->OnRightButtonDown( m_hWnd, pt, static_cast< DWORD >( wParam ) ) )
{
bHandled = FALSE;
}
else
{
m_buttonRecs[ Right ].isTracking = true;
GetTrail()->Begin( m_hWnd );
//
// set the capture to this window while the mouse button is down. this allows
// the user to continue the gesture outside of the window rect but we still
// get the mouse move/button up messages
//
SetCapture();
m_buttonRecs[ Right ].path.clear();
m_buttonRecs[ Right ].path.push_back( pt );
}
return 0;
}
LRESULT MouseTracker::OnRightButtonUp( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled )
{
if( m_isSuspended )
{
bHandled = FALSE;
return 1;
}
ReleaseCapture();
POINT pt = PointFromLPARAM( lParam );
if( m_buttonRecs[ Right ].isTracking )
{
//
// we're not tracking any more
//
m_buttonRecs[ Right ].isTracking = false;
//
// has the mouse moved at all while we've been tracking?
//
if( m_buttonRecs[ Right ].path.size() > 1 )
{
m_buttonRecs[ Right ].path.push_back( pt );
}
GetTrail()->End();
if( m_pWatcher )
{
m_pWatcher->OnRightButtonUp( m_hWnd, m_buttonRecs[ Right ].path );
}
}
else
{
if( m_pWatcher )
{
bHandled = m_pWatcher->OnRightButtonUp( m_hWnd, pt, static_cast< DWORD >( wParam ) );
}
}
return 0;
}
LRESULT MouseTracker::OnLeftButtonDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled )
{
if( m_isSuspended )
{
bHandled = FALSE;
return 1;
}
POINT pt = PointFromLPARAM( lParam );
if( ( m_pWatcher == NULL ) || m_pWatcher->OnLeftButtonDown( m_hWnd, pt, static_cast< DWORD >( wParam ) ) )
{
bHandled = FALSE;
}
else
{
m_buttonRecs[ Left ].isTracking = true;
SetCapture();
m_buttonRecs[ Left ].path.clear();
m_buttonRecs[ Left ].path.push_back( pt );
}
return 0;
}
LRESULT MouseTracker::OnLeftButtonUp( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled )
{
if( m_isSuspended )
{
bHandled = FALSE;
return 1;
}
ReleaseCapture();
POINT pt = PointFromLPARAM( lParam );
if( m_buttonRecs[ Left ].isTracking )
{
m_buttonRecs[ Left ].isTracking = false;
if( m_buttonRecs[ Left ].path.size() > 1 )
{
m_buttonRecs[ Left ].path.push_back( pt );
}
if( m_pWatcher )
{
m_pWatcher->OnLeftButtonUp( m_hWnd, m_buttonRecs[ Left ].path );
}
}
else
{
if( m_pWatcher )
{
bHandled = m_pWatcher->OnLeftButtonUp( m_hWnd, pt, static_cast< DWORD >( wParam ) );
}
}
return 0;
}
LRESULT MouseTracker::OnMouseWheel( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled )
{
if( m_pWatcher )
{
bHandled = m_pWatcher->OnMouseWheel(
m_hWnd,
LOWORD( wParam ),
HIWORD( wParam ),
PointFromLPARAM( lParam )
);
}
return 0;
}
LRESULT MouseTracker::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & )
{
if( m_isBound )
{
//
// force the unsubclass on shutdown - even if somebody else
// has subclassed this window, we need to make sure we detach
// from it otherwise things go bang in the destructor
//
UnsubclassWindow( TRUE );
m_isBound = false;
}
return 0;
}
LRESULT MouseTracker::OnSetFocus( UINT, WPARAM, LPARAM, BOOL & )
{
GetTrail()->Show();
return 0;
}
LRESULT MouseTracker::OnKillFocus( UINT, WPARAM, LPARAM, BOOL & )
{
GetTrail()->Hide();
return 0;
}
HRESULT MouseTracker::Advise( HWND hWnd, MouseTracker::Watcher *pWatcher )
{
if( SubclassWindow( hWnd ) )
{
m_pWatcher = pWatcher;
m_isBound = true;
return S_OK;
}
else
{
ATLASSERT( FALSE );
}
return E_FAIL;
}
HRESULT MouseTracker::Unadvise()
{
if( m_isBound && UnsubclassWindow() )
{
m_isBound = false;
}
return S_OK;
}
void MouseTracker::Reset()
{
GetTrail()->End();
for( size_t idx = 0; idx < REC_COUNT; ++idx )
{
m_buttonRecs[ idx ].isTracking = false;
}
ReleaseCapture();
}
void MouseTracker::SetCapture()
{
if( m_hasCapture == false )
{
CWindowImpl< MouseTracker >::SetCapture();
m_hasCapture = true;
}
}
void MouseTracker::ReleaseCapture()
{
if( m_hasCapture )
{
::ReleaseCapture();
m_hasCapture = false;
}
}
MouseTrail * MouseTracker::GetTrail()
{
ATLASSERT( TrailManager::GetInstance().GetTrail() != NULL );
return TrailManager::GetInstance().GetTrail();
}
///////////////////////////////////////////////////////////////////////////////
MouseTracker::Suspend::Suspend( MouseTracker &mouseTracker ) :
isSuspended( mouseTracker.m_isSuspended )
{
isSuspended = true;
}
MouseTracker::Suspend::~Suspend()
{
isSuspended = false;
}
///////////////////////////////////////////////////////////////////////////////