Files
wxWidgets/src/univ/scrarrow.cpp
2018-10-21 22:01:50 -04:00

303 lines
8.6 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/univ/scrarrow.cpp
// Purpose: wxScrollArrows class implementation
// Author: Vadim Zeitlin
// Modified by:
// Created: 22.01.01
// Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/window.h"
#endif
#include "wx/univ/scrtimer.h"
#include "wx/univ/scrarrow.h"
#include "wx/univ/renderer.h"
#include "wx/univ/inphand.h"
#include "wx/univ/theme.h"
#if wxUSE_SCROLLBAR
// ----------------------------------------------------------------------------
// wxScrollArrowCaptureData: contains the data used while the arrow is being
// pressed by the user
// ----------------------------------------------------------------------------
struct wxScrollArrowCaptureData
{
wxScrollArrowCaptureData()
{
m_arrowPressed = wxScrollArrows::Arrow_None;
m_window = NULL;
m_btnCapture = -1;
#if wxUSE_TIMER
m_timerScroll = NULL;
#endif // wxUSE_TIMER
}
~wxScrollArrowCaptureData()
{
if ( m_window )
m_window->ReleaseMouse();
#if wxUSE_TIMER
delete m_timerScroll;
#endif // wxUSE_TIMER
}
// the arrow being held pressed (may be Arrow_None)
wxScrollArrows::Arrow m_arrowPressed;
// the mouse button which started the capture (-1 if none)
int m_btnCapture;
// the window which has captured the mouse
wxWindow *m_window;
#if wxUSE_TIMER
// the timer for generating the scroll events
wxScrollTimer *m_timerScroll;
#endif
};
// ----------------------------------------------------------------------------
// wxScrollArrowTimer: a wxScrollTimer which calls OnArrow()
// ----------------------------------------------------------------------------
#if wxUSE_TIMER
class wxScrollArrowTimer : public wxScrollTimer
{
public:
wxScrollArrowTimer(wxControlWithArrows *control,
wxScrollArrows::Arrow arrow)
{
m_control = control;
m_arrow = arrow;
StartAutoScroll();
}
protected:
virtual bool DoNotify()
{
return m_control->OnArrow(m_arrow);
}
wxControlWithArrows *m_control;
wxScrollArrows::Arrow m_arrow;
};
#endif // wxUSE_TIMER
// ============================================================================
// implementation of wxScrollArrows
// ============================================================================
// ----------------------------------------------------------------------------
// con/destruction
// ----------------------------------------------------------------------------
wxScrollArrows::wxScrollArrows(wxControlWithArrows *control)
{
m_control = control;
m_captureData = NULL;
}
wxScrollArrows::~wxScrollArrows()
{
// it should have been destroyed
wxASSERT_MSG( !m_captureData, wxT("memory leak in wxScrollArrows") );
}
// ----------------------------------------------------------------------------
// drawing
// ----------------------------------------------------------------------------
void wxScrollArrows::DrawArrow(Arrow arrow,
wxDC& dc,
const wxRect& rect,
bool scrollbarLike) const
{
static const wxDirection arrowDirs[2][Arrow_Max] =
{
{ wxLEFT, wxRIGHT },
{ wxUP, wxDOWN }
};
if ( scrollbarLike )
m_control->GetRenderer()->DrawScrollbarArrow(
dc,
arrowDirs[m_control->IsVertical()][arrow],
rect,
m_control->GetArrowState(arrow));
else
m_control->GetRenderer()->DrawArrow(
dc,
arrowDirs[m_control->IsVertical()][arrow],
rect,
m_control->GetArrowState(arrow));
}
// ----------------------------------------------------------------------------
// input handling
// ----------------------------------------------------------------------------
void wxScrollArrows::UpdateCurrentFlag(Arrow arrow, Arrow arrowCur) const
{
m_control->SetArrowFlag(arrow, wxCONTROL_CURRENT, arrow == arrowCur);
}
bool wxScrollArrows::HandleMouseMove(const wxMouseEvent& event) const
{
Arrow arrow;
if ( event.Leaving() )
{
// no arrow has mouse if it left the window completely
arrow = Arrow_None;
}
else // Moving() or Entering(), treat them the same here
{
arrow = m_control->HitTestArrow(event.GetPosition());
}
#if wxUSE_TIMER
if ( m_captureData && m_captureData->m_timerScroll)
{
// the mouse is captured, we may want to pause scrolling if it goes
// outside the arrow or to resume it if we had paused it before
wxTimer *timer = m_captureData->m_timerScroll;
if ( !timer->IsRunning() )
{
// timer is paused
if ( arrow == m_captureData->m_arrowPressed )
{
// resume now
m_control->SetArrowFlag(arrow, wxCONTROL_PRESSED, true);
timer->Start();
return true;
}
}
else // if ( 1 ) FIXME: m_control->ShouldPauseScrolling() )
{
// we may want to stop it
if ( arrow != m_captureData->m_arrowPressed )
{
// stop as the mouse left the arrow
m_control->SetArrowFlag(m_captureData->m_arrowPressed,
wxCONTROL_PRESSED, false);
timer->Stop();
return true;
}
}
return false;
}
#endif // wxUSE_TIMER
// reset the wxCONTROL_CURRENT flag for the arrows which don't have the
// mouse and set it for the one which has
UpdateCurrentFlag(Arrow_First, arrow);
UpdateCurrentFlag(Arrow_Second, arrow);
// return true if it was really an event for an arrow
return !event.Leaving() && arrow != Arrow_None;
}
bool wxScrollArrows::HandleMouse(const wxMouseEvent& event) const
{
int btn = event.GetButton();
if ( btn == -1 )
{
// we only care about button press/release events
return false;
}
if ( event.ButtonDown() || event.ButtonDClick() )
{
if ( !m_captureData )
{
Arrow arrow = m_control->HitTestArrow(event.GetPosition());
if ( arrow == Arrow_None )
{
// mouse pressed over something else
return false;
}
if ( m_control->GetArrowState(arrow) & wxCONTROL_DISABLED )
{
// don't allow to press disabled arrows
return true;
}
wxConstCast(this, wxScrollArrows)->m_captureData =
new wxScrollArrowCaptureData;
m_captureData->m_arrowPressed = arrow;
m_captureData->m_btnCapture = btn;
m_captureData->m_window = m_control->GetWindow();
m_captureData->m_window->CaptureMouse();
#if wxUSE_TIMER
// start scrolling
wxScrollArrowTimer *tmpTimerScroll =
new wxScrollArrowTimer(m_control, arrow);
#endif // wxUSE_TIMER
// Because in some cases wxScrollArrowTimer can cause
// m_captureData to be destructed we need to test if it
// is still valid before using.
if (m_captureData)
{
#if wxUSE_TIMER
m_captureData->m_timerScroll = tmpTimerScroll;
#endif // wxUSE_TIMER
m_control->SetArrowFlag(arrow, wxCONTROL_PRESSED, true);
}
else
{
#if wxUSE_TIMER
delete tmpTimerScroll;
#endif // wxUSE_TIMER
}
}
//else: mouse already captured, nothing to do
}
// release mouse if the *same* button went up
else if ( m_captureData && (btn == m_captureData->m_btnCapture) )
{
Arrow arrow = m_captureData->m_arrowPressed;
delete m_captureData;
wxConstCast(this, wxScrollArrows)->m_captureData = NULL;
m_control->SetArrowFlag(arrow, wxCONTROL_PRESSED, false);
}
else
{
// we don't process this
return false;
}
return true;
}
#endif // wxUSE_SCROLLBAR