From 37d98063f0522fc4d3f9d1b0df5f1e35e00fd1e0 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 22 Aug 2013 18:42:53 +0200 Subject: [PATCH] Added autopanning functionality to WX_VIEW_CONTROLS. --- common/view/wx_view_controls.cpp | 153 +++++++++++++++++++++++++++---- include/view/view_controls.h | 17 ---- include/view/wx_view_controls.h | 43 +++++++-- 3 files changed, 170 insertions(+), 43 deletions(-) diff --git a/common/view/wx_view_controls.cpp b/common/view/wx_view_controls.cpp index 0076668238..7b0dfb1d4d 100644 --- a/common/view/wx_view_controls.cpp +++ b/common/view/wx_view_controls.cpp @@ -24,7 +24,6 @@ */ #include -#include #include #include @@ -33,9 +32,11 @@ using namespace KiGfx; WX_VIEW_CONTROLS::WX_VIEW_CONTROLS( VIEW* aView, wxWindow* aParentPanel ) : VIEW_CONTROLS( aView ), + m_state( IDLE ), + m_autoPanEnabled( false ), + m_grabMouse( false ), m_autoPanMargin( 0.1 ), m_autoPanSpeed( 0.15 ), - m_autoPanCornerRatio( 0.1 ), m_parentPanel( aParentPanel ) { m_parentPanel->Connect( wxEVT_MOTION, wxMouseEventHandler( @@ -50,22 +51,40 @@ WX_VIEW_CONTROLS::WX_VIEW_CONTROLS( VIEW* aView, wxWindow* aParentPanel ) : m_parentPanel->Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( WX_VIEW_CONTROLS::onEnter ), NULL, this ); #endif + + m_panTimer.SetOwner( this ); + this->Connect( wxEVT_TIMER, wxTimerEventHandler( + WX_VIEW_CONTROLS::onTimer ), NULL, this ); } void WX_VIEW_CONTROLS::onMotion( wxMouseEvent& aEvent ) { - if( aEvent.Dragging() && m_isDragPanning ) - { - VECTOR2D mousePoint( aEvent.GetX(), aEvent.GetY() ); - VECTOR2D d = m_dragStartPoint - mousePoint; - VECTOR2D delta = m_view->ToWorld( d, false ); + VECTOR2D mousePoint( aEvent.GetX(), aEvent.GetY() ); - m_view->SetCenter( m_lookStartPoint + delta ); - m_parentPanel->Refresh(); + if( aEvent.Dragging() ) + { + if( m_state == DRAG_PANNING ) + { + VECTOR2D d = m_dragStartPoint - mousePoint; + VECTOR2D delta = m_view->ToWorld( d, false ); + + m_view->SetCenter( m_lookStartPoint + delta ); + m_parentPanel->Refresh(); + aEvent.StopPropagation(); + } + else + { + aEvent.Skip(); + } + } + else + { + if( m_autoPanEnabled ) + handleAutoPanning( aEvent ); } - aEvent.Skip(); +// DeletePendingEvents(); } @@ -122,16 +141,25 @@ void WX_VIEW_CONTROLS::onWheel( wxMouseEvent& aEvent ) void WX_VIEW_CONTROLS::onButton( wxMouseEvent& aEvent ) { - if( aEvent.MiddleDown() ) + switch( m_state ) { - m_isDragPanning = true; - m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() ); - m_lookStartPoint = m_view->GetCenter(); - } - else if( aEvent.MiddleUp() ) - { - m_isDragPanning = false; - } + case IDLE: + case AUTO_PANNING: + if( aEvent.MiddleDown() ) + { + m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() ); + m_lookStartPoint = m_view->GetCenter(); + m_state = DRAG_PANNING; + } + break; + + case DRAG_PANNING: + if( aEvent.MiddleUp() ) + { + m_state = IDLE; + } + break; + }; aEvent.Skip(); } @@ -141,3 +169,90 @@ void WX_VIEW_CONTROLS::onEnter( wxMouseEvent& aEvent ) { m_parentPanel->SetFocus(); } + + +void WX_VIEW_CONTROLS::onTimer( wxTimerEvent& aEvent ) +{ + switch( m_state ) + { + case AUTO_PANNING: + { + double borderSize = std::min( m_autoPanMargin * m_view->GetScreenPixelSize().x, + m_autoPanMargin * m_view->GetScreenPixelSize().y ); + + VECTOR2D dir( m_panDirection ); + + if( dir.EuclideanNorm() > borderSize ) + dir = dir.Resize( borderSize ); + + dir = m_view->ToWorld( dir, false ); + +// wxLogDebug( "AutoPanningTimer: dir %.4f %.4f sped %.4f", dir.x, dir.y, m_autoPanSpeed ); + + m_view->SetCenter( m_view->GetCenter() + dir * m_autoPanSpeed ); + + wxPaintEvent redrawEvent; + wxPostEvent( m_parentPanel, redrawEvent ); + } + break; + } + + DeletePendingEvents(); + m_panTimer.DeletePendingEvents(); +} + + +void WX_VIEW_CONTROLS::SetGrabMouse( bool aEnabled ) +{ + m_grabMouse = aEnabled; + + if( aEnabled ) + m_parentPanel->CaptureMouse(); + else + m_parentPanel->ReleaseMouse(); +} + + +void WX_VIEW_CONTROLS::handleAutoPanning( wxMouseEvent& aEvent ) +{ + VECTOR2D p( aEvent.GetX(), aEvent.GetY() ); + + // Compute areas where autopanning is active + double borderStart = std::min( m_autoPanMargin * m_view->GetScreenPixelSize().x, + m_autoPanMargin * m_view->GetScreenPixelSize().y ); + double borderEndX = m_view->GetScreenPixelSize().x - borderStart; + double borderEndY = m_view->GetScreenPixelSize().y - borderStart; + + m_panDirection = VECTOR2D(); + + if( p.x < borderStart ) + m_panDirection.x = -( borderStart - p.x ); + else if( p.x > borderEndX ) + m_panDirection.x = ( p.x - borderEndX ); + + if( p.y < borderStart ) + m_panDirection.y = -( borderStart - p.y ); + else if( p.y > borderEndY ) + m_panDirection.y = ( p.y - borderEndY ); + + bool borderHit = ( m_panDirection.x != 0 || m_panDirection.y != 0 ); + + switch( m_state ) + { + case AUTO_PANNING: + if( !borderHit ) + { + m_panTimer.Stop(); + m_state = IDLE; + } + break; + + case IDLE: + if( borderHit ) + { + m_state = AUTO_PANNING; + m_panTimer.Start( (int) ( 1000.0 / 60.0 ) ); + } + break; + } +} diff --git a/include/view/view_controls.h b/include/view/view_controls.h index 9e399d3282..0774d7ef69 100644 --- a/include/view/view_controls.h +++ b/include/view/view_controls.h @@ -46,16 +46,6 @@ class VIEW; class VIEW_CONTROLS { public: - /** - * Possible modes for panning (JUMP means that view is updated less often, resulting in - * not so responsive user interface). - */ - enum PanMode { - SMOOTH = 1, - JUMP = 2 - }; - - VIEW_CONTROLS( VIEW* aView ) : m_view( aView ) {}; virtual ~VIEW_CONTROLS() {}; @@ -89,13 +79,6 @@ public: */ virtual void SetPanSpeed( float aSpeed ) {}; - /** - * Function SetPanMode - * Enables specified mode for panning. - * @param aMode is a new mode used for VIEW panning. - */ - virtual void SetPanMode( PanMode aMode ) {}; - /** * Function SetZoomSpeed * Determines how much zoom factor should be affected on one zoom event (eg. mouse wheel). diff --git a/include/view/wx_view_controls.h b/include/view/wx_view_controls.h index 149a0eb310..ca2d9b679d 100644 --- a/include/view/wx_view_controls.h +++ b/include/view/wx_view_controls.h @@ -52,27 +52,55 @@ public: WX_VIEW_CONTROLS( VIEW* aView, wxWindow* aParentPanel ); ~WX_VIEW_CONTROLS() {}; + /// Handler functions void onWheel( wxMouseEvent& aEvent ); void onMotion( wxMouseEvent& aEvent ); void onButton( wxMouseEvent& aEvent ); void onEnter( wxMouseEvent& aEvent ); + void onTimer( wxTimerEvent& aEvent ); - void SetEventDispatcher( TOOL_DISPATCHER *aEventDispatcher ); + /** + * Function SetGrabMouse() + * Enables/disables mouse cursor grabbing (limits the movement field only to the panel area). + * + * @param aEnabled says whether the option should enabled or disabled. + */ + void SetGrabMouse( bool aEnabled ); + + /** + * Function SetAutoPan() + * Enables/disables autopanning (panning when mouse cursor reaches the panel border). + * + * @param aEnabled says whether the option should enabled or disabled. + */ + void SetAutoPan( bool aEnabled ) + { + m_autoPanEnabled = true; + } private: + enum State { + IDLE = 1, + DRAG_PANNING, + AUTO_PANNING, + }; + + void handleAutoPanning( wxMouseEvent& aEvent ); + + /// Current state of VIEW_CONTROLS + State m_state; /// Options for WX_VIEW_CONTROLS - bool m_isDragPanning; - bool m_isAutoPanning; bool m_autoPanEnabled; bool m_needRedraw; + bool m_grabMouse; /// Distance from cursor to VIEW edge when panning is active. - double m_autoPanMargin; + float m_autoPanMargin; /// How fast is panning when in auto mode. - double m_autoPanSpeed; + float m_autoPanSpeed; /// TODO - double m_autoPanCornerRatio; + float m_autoPanAcceleration; /// Panel that is affected by VIEW_CONTROLS wxWindow* m_parentPanel; @@ -80,10 +108,11 @@ private: /// Stores information about point where event started. VECTOR2D m_dragStartPoint; VECTOR2D m_lookStartPoint; + VECTOR2D m_panDirection; /// Used for determining time intervals between events. wxLongLong m_timeStamp; - TOOL_DISPATCHER* m_eventDispatcher; + wxTimer m_panTimer; }; } // namespace KiGfx