You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

280 lines
8.1 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2013 CERN
  5. * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <wxPcbStruct.h>
  25. #include <wxBasePcbFrame.h>
  26. #include <tool/tool_manager.h>
  27. #include <tool/tool_dispatcher.h>
  28. #include <view/view.h>
  29. #include <view/wx_view_controls.h>
  30. #include <class_drawpanel_gal.h>
  31. #include <pcbnew_id.h>
  32. #include <boost/optional.hpp>
  33. #include <boost/foreach.hpp>
  34. using boost::optional;
  35. ///> Stores information about a mouse button state
  36. struct TOOL_DISPATCHER::BUTTON_STATE
  37. {
  38. BUTTON_STATE( TOOL_MOUSE_BUTTONS aButton, const wxEventType& aDownEvent,
  39. const wxEventType& aUpEvent ) :
  40. button( aButton ),
  41. downEvent( aDownEvent ),
  42. upEvent( aUpEvent )
  43. {};
  44. ///> Flag indicating that dragging is active for the given button.
  45. bool dragging;
  46. ///> Flag indicating that the given button is pressed.
  47. bool pressed;
  48. ///> Point where dragging has started (in world coordinates).
  49. VECTOR2D dragOrigin;
  50. ///> Point where click event has occurred.
  51. VECTOR2D downPosition;
  52. ///> Difference between drag origin point and current mouse position (expressed as distance in
  53. ///> pixels).
  54. double dragMaxDelta;
  55. ///> Determines the mouse button for which information are stored.
  56. TOOL_MOUSE_BUTTONS button;
  57. ///> The type of wxEvent that determines mouse button press.
  58. wxEventType downEvent;
  59. ///> The type of wxEvent that determines mouse button release.
  60. wxEventType upEvent;
  61. ///> Time stamp for the last mouse button press event.
  62. wxLongLong downTimestamp;
  63. ///> Restores initial state.
  64. void Reset()
  65. {
  66. dragging = false;
  67. pressed = false;
  68. }
  69. };
  70. TOOL_DISPATCHER::TOOL_DISPATCHER( TOOL_MANAGER* aToolMgr, PCB_BASE_FRAME* aEditFrame ) :
  71. m_toolMgr( aToolMgr ), m_editFrame( aEditFrame )
  72. {
  73. m_buttons.push_back( new BUTTON_STATE( BUT_LEFT, wxEVT_LEFT_DOWN, wxEVT_LEFT_UP ) );
  74. m_buttons.push_back( new BUTTON_STATE( BUT_RIGHT, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_UP ) );
  75. m_buttons.push_back( new BUTTON_STATE( BUT_MIDDLE, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_UP ) );
  76. ResetState();
  77. }
  78. TOOL_DISPATCHER::~TOOL_DISPATCHER()
  79. {
  80. BOOST_FOREACH( BUTTON_STATE* st, m_buttons )
  81. delete st;
  82. }
  83. void TOOL_DISPATCHER::ResetState()
  84. {
  85. BOOST_FOREACH( BUTTON_STATE* st, m_buttons )
  86. st->Reset();
  87. }
  88. KIGFX::VIEW* TOOL_DISPATCHER::getView()
  89. {
  90. return m_editFrame->GetGalCanvas()->GetView();
  91. }
  92. bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMotion )
  93. {
  94. BUTTON_STATE* st = m_buttons[aIndex];
  95. wxEventType type = aEvent.GetEventType();
  96. optional<TOOL_EVENT> evt;
  97. bool isClick = false;
  98. bool up = type == st->upEvent;
  99. bool down = type == st->downEvent;
  100. int mods = decodeModifiers<wxMouseEvent>( static_cast<wxMouseEvent*>( &aEvent ) );
  101. int args = st->button | mods;
  102. if( down ) // Handle mouse button press
  103. {
  104. st->downTimestamp = wxGetLocalTimeMillis();
  105. st->dragOrigin = m_lastMousePos;
  106. st->downPosition = m_lastMousePos;
  107. st->dragMaxDelta = 0;
  108. st->pressed = true;
  109. evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_DOWN, args );
  110. }
  111. else if( up ) // Handle mouse button release
  112. {
  113. st->pressed = false;
  114. if( st->dragging )
  115. {
  116. wxLongLong t = wxGetLocalTimeMillis();
  117. // Determine if it was just a single click or beginning of dragging
  118. if( t - st->downTimestamp < DragTimeThreshold &&
  119. st->dragMaxDelta < DragDistanceThreshold )
  120. isClick = true;
  121. else
  122. evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_UP, args );
  123. }
  124. else
  125. isClick = true;
  126. if( isClick )
  127. evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_CLICK, args );
  128. st->dragging = false;
  129. }
  130. if( st->pressed && aMotion )
  131. {
  132. st->dragging = true;
  133. double dragPixelDistance =
  134. getView()->ToScreen( m_lastMousePos - st->dragOrigin, false ).EuclideanNorm();
  135. st->dragMaxDelta = std::max( st->dragMaxDelta, dragPixelDistance );
  136. wxLongLong t = wxGetLocalTimeMillis();
  137. if( t - st->downTimestamp > DragTimeThreshold || st->dragMaxDelta > DragDistanceThreshold )
  138. {
  139. evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_DRAG, args );
  140. evt->SetMouseDragOrigin( st->dragOrigin );
  141. evt->SetMouseDelta( m_lastMousePos - st->dragOrigin );
  142. }
  143. }
  144. if( evt )
  145. {
  146. evt->SetMousePosition( isClick ? st->downPosition : m_lastMousePos );
  147. m_toolMgr->ProcessEvent( *evt );
  148. return true;
  149. }
  150. return false;
  151. }
  152. void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
  153. {
  154. bool motion = false, buttonEvents = false;
  155. optional<TOOL_EVENT> evt;
  156. int type = aEvent.GetEventType();
  157. // Mouse handling
  158. if( type == wxEVT_MOTION || type == wxEVT_MOUSEWHEEL ||
  159. type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_UP ||
  160. type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP ||
  161. type == wxEVT_RIGHT_DOWN || type == wxEVT_RIGHT_UP ||
  162. // Event issued whem mouse retains position in screen coordinates,
  163. // but changes in world coordinates (eg. autopanning)
  164. type == KIGFX::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE )
  165. {
  166. VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetCursorPosition();
  167. VECTOR2D pos = getView()->ToWorld( screenPos );
  168. if( pos != m_lastMousePos || type == KIGFX::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE )
  169. {
  170. motion = true;
  171. m_lastMousePos = pos;
  172. }
  173. for( unsigned int i = 0; i < m_buttons.size(); i++ )
  174. buttonEvents |= handleMouseButton( aEvent, i, motion );
  175. if( !buttonEvents && motion )
  176. {
  177. evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_MOTION );
  178. evt->SetMousePosition( pos );
  179. }
  180. }
  181. // Keyboard handling
  182. else if( type == wxEVT_KEY_UP || type == wxEVT_KEY_DOWN )
  183. {
  184. wxKeyEvent* ke = static_cast<wxKeyEvent*>( &aEvent );
  185. int key = ke->GetKeyCode();
  186. int mods = decodeModifiers<wxKeyEvent>( ke );
  187. if( type == wxEVT_KEY_UP )
  188. {
  189. if( key == WXK_ESCAPE ) // ESC is the special key for cancelling tools
  190. evt = TOOL_EVENT( TC_COMMAND, TA_CANCEL_TOOL );
  191. else
  192. evt = TOOL_EVENT( TC_KEYBOARD, TA_KEY_UP, key | mods );
  193. }
  194. else
  195. {
  196. evt = TOOL_EVENT( TC_KEYBOARD, TA_KEY_DOWN, key | mods );
  197. }
  198. }
  199. if( evt )
  200. m_toolMgr->ProcessEvent( *evt );
  201. // pass the event to the GUI, it might still be interested in it
  202. aEvent.Skip();
  203. }
  204. void TOOL_DISPATCHER::DispatchWxCommand( const wxCommandEvent& aEvent )
  205. {
  206. bool activateTool = false;
  207. std::string toolName;
  208. // fixme: use TOOL_ACTIONs here
  209. switch( aEvent.GetId() )
  210. {
  211. case ID_PNS_ROUTER_TOOL:
  212. toolName = "pcbnew.InteractiveRouter";
  213. activateTool = true;
  214. break;
  215. case ID_SELECTION_TOOL:
  216. toolName = "pcbnew.InteractiveSelection";
  217. activateTool = true;
  218. break;
  219. }
  220. // do nothing if the legacy view is active
  221. if( activateTool && m_editFrame->IsGalCanvasActive() )
  222. m_toolMgr->InvokeTool( toolName );
  223. }