/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2013 CERN * @author Tomasz Wlostowski * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include using boost::optional; struct TOOL_DISPATCHER::ButtonState { ButtonState( TOOL_MouseButtons aButton, const wxEventType& aDownEvent, const wxEventType & aUpEvent, bool aTriggerMenu = false) : button( aButton ), downEvent( aDownEvent ), upEvent( aUpEvent ), triggerContextMenu( aTriggerMenu ) {}; bool dragging; bool pressed; VECTOR2D dragOrigin; double dragMaxDelta; TOOL_MouseButtons button; wxEventType downEvent; wxEventType upEvent; bool triggerContextMenu; wxLongLong downTimestamp; void Reset() { dragging = false; pressed = false; } }; TOOL_DISPATCHER::TOOL_DISPATCHER( TOOL_MANAGER *aToolMgr, PCB_BASE_FRAME *aEditFrame ) : m_toolMgr(aToolMgr), m_editFrame(aEditFrame) { m_buttons.push_back( new ButtonState( MB_Left, wxEVT_LEFT_DOWN, wxEVT_LEFT_UP ) ); m_buttons.push_back( new ButtonState( MB_Right, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_UP, true ) ); m_buttons.push_back( new ButtonState( MB_Middle, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_UP ) ); ResetState(); } TOOL_DISPATCHER::~TOOL_DISPATCHER() { BOOST_FOREACH( ButtonState* st, m_buttons ) delete st; } void TOOL_DISPATCHER::ResetState() { BOOST_FOREACH( ButtonState* st, m_buttons ) st->Reset(); } KiGfx::VIEW* TOOL_DISPATCHER::getView() { return m_editFrame->GetGalCanvas()->GetView(); } int TOOL_DISPATCHER::decodeModifiers( wxEvent& aEvent ) { wxMouseEvent* me = static_cast( &aEvent ); int mods = 0; if( me->ControlDown() ) mods |= MB_ModCtrl; if( me->AltDown() ) mods |= MB_ModAlt; if( me->ShiftDown() ) mods |= MB_ModShift; return mods; } bool TOOL_DISPATCHER::handleMouseButton ( wxEvent& aEvent, int aIndex, bool aMotion ) { ButtonState* st = m_buttons[aIndex]; wxEventType type = aEvent.GetEventType(); optional evt; bool up = type == st->upEvent; bool down = type == st->downEvent; int mods = decodeModifiers( aEvent ); int args = st->button | mods; if( down ) { st->downTimestamp = wxGetLocalTimeMillis(); st->dragOrigin = m_lastMousePos; st->dragMaxDelta = 0; st->pressed = true; evt = TOOL_EVENT( TC_Mouse, TA_MouseDown, args ); } else if ( up ) { bool isClick = false; st->pressed = false; if( st->dragging ) { wxLongLong t = wxGetLocalTimeMillis(); if( t - st->downTimestamp < DragTimeThreshold && st->dragMaxDelta < DragDistanceThreshold ) isClick = true; else evt = TOOL_EVENT( TC_Mouse, TA_MouseUp, args ); } else isClick = true; if( isClick ) { if( st -> triggerContextMenu && !mods ) {} // evt = TOOL_EVENT( TC_Command, TA_ContextMenu ); else evt = TOOL_EVENT( TC_Mouse, TA_MouseClick, args ); } st->dragging = false; } if( st->pressed && aMotion ) { st->dragging = true; double dragPixelDistance = getView()->ToScreen( m_lastMousePos - st->dragOrigin, false ).EuclideanNorm(); st->dragMaxDelta = std::max( st->dragMaxDelta, dragPixelDistance ); wxLongLong t = wxGetLocalTimeMillis(); if( t - st->downTimestamp > DragTimeThreshold || st->dragMaxDelta > DragDistanceThreshold ) { evt = TOOL_EVENT( TC_Mouse, TA_MouseDrag, args ); evt->SetMouseDragOrigin( st->dragOrigin ); evt->SetMouseDelta( m_lastMousePos - st->dragOrigin ); } } if( evt ) { evt->SetMousePosition( m_lastMousePos ); m_toolMgr->ProcessEvent( *evt ); return true; } return false; } void TOOL_DISPATCHER::DispatchWxEvent( wxEvent &aEvent ) { bool motion = false, buttonEvents = false; VECTOR2D pos; optional evt; int type = aEvent.GetEventType(); if( type == wxEVT_MOTION ) { wxMouseEvent *me = static_cast(&aEvent ); pos = getView()->ToWorld( VECTOR2D( me->GetX(), me->GetY() ) ); if( pos != m_lastMousePos ) { motion = true; m_lastMousePos = pos; } } for( unsigned int i = 0; i < m_buttons.size(); i++ ) buttonEvents |= handleMouseButton( aEvent, i, motion ); if( !buttonEvents && motion ) { evt = TOOL_EVENT (TC_Mouse, TA_MouseMotion ); evt->SetMousePosition( pos ); } if( evt ) m_toolMgr->ProcessEvent( *evt ); aEvent.Skip(); } void TOOL_DISPATCHER::DispatchWxCommand( wxCommandEvent &aEvent ) { bool activateTool = false; std::string toolName; switch ( aEvent.GetId() ) { case ID_SELECTION_TOOL: toolName = "pcbnew.InteractiveSelection"; activateTool = true; break; } if( activateTool ) { TOOL_EVENT evt ( TC_Command, TA_ActivateTool, toolName ); m_toolMgr->ProcessEvent( evt ); } }