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.

704 lines
19 KiB

12 years ago
6 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2013 CERN
  5. * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, you may find one here:
  21. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. * or you may search the http://www.gnu.org website for the version 2 license,
  23. * or you may write to the Free Software Foundation, Inc.,
  24. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. #ifndef __TOOL_EVENT_H
  27. #define __TOOL_EVENT_H
  28. #include <cstdio>
  29. #include <deque>
  30. #include <iterator>
  31. #include <math/vector2d.h>
  32. #include <core/optional.h>
  33. class TOOL_ACTION;
  34. class TOOL_MANAGER;
  35. class TOOL_BASE;
  36. /**
  37. * Internal (GUI-independent) event definitions.
  38. */
  39. enum TOOL_EVENT_CATEGORY
  40. {
  41. TC_NONE = 0x00,
  42. TC_MOUSE = 0x01,
  43. TC_KEYBOARD = 0x02,
  44. TC_COMMAND = 0x04,
  45. TC_MESSAGE = 0x08,
  46. TC_VIEW = 0x10,
  47. TC_ANY = 0xffffffff
  48. };
  49. enum TOOL_ACTIONS
  50. {
  51. // UI input events
  52. TA_NONE = 0x0000,
  53. TA_MOUSE_CLICK = 0x0001,
  54. TA_MOUSE_DBLCLICK = 0x0002,
  55. TA_MOUSE_UP = 0x0004,
  56. TA_MOUSE_DOWN = 0x0008,
  57. TA_MOUSE_DRAG = 0x0010,
  58. TA_MOUSE_MOTION = 0x0020,
  59. TA_MOUSE_WHEEL = 0x0040,
  60. TA_MOUSE = 0x007f,
  61. TA_KEY_PRESSED = 0x0080,
  62. TA_KEYBOARD = TA_KEY_PRESSED,
  63. // View related events
  64. TA_VIEW_REFRESH = 0x0100,
  65. TA_VIEW_ZOOM = 0x0200,
  66. TA_VIEW_PAN = 0x0400,
  67. TA_VIEW_DIRTY = 0x0800,
  68. TA_VIEW = 0x0f00,
  69. TA_CHANGE_LAYER = 0x1000,
  70. // Tool cancel event. Issued automagically when the user hits escape or selects End Tool from
  71. // the context menu.
  72. TA_CANCEL_TOOL = 0x2000,
  73. // Context menu update. Issued whenever context menu is open and the user hovers the mouse
  74. // over one of choices. Used in dynamic highlighting in disambiguation menu
  75. TA_CHOICE_MENU_UPDATE = 0x4000,
  76. // Context menu choice. Sent if the user picked something from the context menu or
  77. // closed it without selecting anything.
  78. TA_CHOICE_MENU_CHOICE = 0x8000,
  79. // Context menu is closed, no matter whether anything has been chosen or not.
  80. TA_CHOICE_MENU_CLOSED = 0x10000,
  81. TA_CHOICE_MENU = TA_CHOICE_MENU_UPDATE | TA_CHOICE_MENU_CHOICE | TA_CHOICE_MENU_CLOSED,
  82. // This event is sent *before* undo/redo command is performed.
  83. TA_UNDO_REDO_PRE = 0x20000,
  84. // This event is sent *after* undo/redo command is performed.
  85. TA_UNDO_REDO_POST = 0x40000,
  86. // Tool action (allows one to control tools).
  87. TA_ACTION = 0x80000,
  88. // Tool activation event.
  89. TA_ACTIVATE = 0x100000,
  90. // Tool re-activation event for tools already on the stack
  91. TA_REACTIVATE = 0x200000,
  92. // Model has changed (partial update).
  93. TA_MODEL_CHANGE = 0x400000,
  94. // Tool priming event (a special mouse click)
  95. TA_PRIME = 0x800001,
  96. TA_ANY = 0xffffffff
  97. };
  98. enum TOOL_MOUSE_BUTTONS
  99. {
  100. BUT_NONE = 0x0,
  101. BUT_LEFT = 0x1,
  102. BUT_RIGHT = 0x2,
  103. BUT_MIDDLE = 0x4,
  104. BUT_BUTTON_MASK = BUT_LEFT | BUT_RIGHT | BUT_MIDDLE,
  105. BUT_ANY = 0xffffffff
  106. };
  107. enum TOOL_MODIFIERS
  108. {
  109. MD_SHIFT = 0x1000,
  110. MD_CTRL = 0x2000,
  111. MD_ALT = 0x4000,
  112. MD_MODIFIER_MASK = MD_SHIFT | MD_CTRL | MD_ALT,
  113. };
  114. /// Scope of tool actions
  115. enum TOOL_ACTION_SCOPE
  116. {
  117. AS_CONTEXT = 1, ///< Action belongs to a particular tool (i.e. a part of a pop-up menu)
  118. AS_ACTIVE, ///< All active tools
  119. AS_GLOBAL ///< Global action (toolbar/main menu event, global shortcut)
  120. };
  121. /// Flags for tool actions
  122. enum TOOL_ACTION_FLAGS
  123. {
  124. AF_NONE = 0,
  125. AF_ACTIVATE = 1, ///< Action activates a tool
  126. AF_NOTIFY = 2 ///< Action is a notification (it is by default passed to all tools)
  127. };
  128. /// Defines when a context menu is opened.
  129. enum CONTEXT_MENU_TRIGGER
  130. {
  131. CMENU_BUTTON = 0, // On the right button
  132. CMENU_NOW, // Right now (after TOOL_INTERACTIVE::SetContextMenu)
  133. CMENU_OFF // Never
  134. };
  135. /**
  136. * Generic, UI-independent tool event.
  137. */
  138. class TOOL_EVENT
  139. {
  140. public:
  141. /**
  142. * Return information about event in form of a human-readable string.
  143. *
  144. * @return Event information.
  145. */
  146. const std::string Format() const;
  147. TOOL_EVENT( TOOL_EVENT_CATEGORY aCategory = TC_NONE, TOOL_ACTIONS aAction = TA_NONE,
  148. TOOL_ACTION_SCOPE aScope = AS_GLOBAL, void* aParameter = nullptr ) :
  149. m_category( aCategory ),
  150. m_actions( aAction ),
  151. m_scope( aScope ),
  152. m_mouseButtons( 0 ),
  153. m_keyCode( 0 ),
  154. m_modifiers( 0 ),
  155. m_param( aParameter ),
  156. m_firstResponder( nullptr )
  157. {
  158. init();
  159. }
  160. TOOL_EVENT( TOOL_EVENT_CATEGORY aCategory, TOOL_ACTIONS aAction, int aExtraParam,
  161. TOOL_ACTION_SCOPE aScope = AS_GLOBAL, void* aParameter = nullptr ) :
  162. m_category( aCategory ),
  163. m_actions( aAction ),
  164. m_scope( aScope ),
  165. m_mouseButtons( 0 ),
  166. m_keyCode( 0 ),
  167. m_modifiers( 0 ),
  168. m_param( aParameter ),
  169. m_firstResponder( nullptr )
  170. {
  171. if( aCategory == TC_MOUSE )
  172. {
  173. setMouseButtons( aExtraParam & BUT_BUTTON_MASK );
  174. }
  175. else if( aCategory == TC_KEYBOARD )
  176. {
  177. m_keyCode = aExtraParam & ~MD_MODIFIER_MASK; // Filter out modifiers
  178. }
  179. else if( aCategory == TC_COMMAND )
  180. {
  181. m_commandId = aExtraParam;
  182. }
  183. if( aCategory & ( TC_MOUSE | TC_KEYBOARD ) )
  184. {
  185. m_modifiers = aExtraParam & MD_MODIFIER_MASK;
  186. }
  187. init();
  188. }
  189. TOOL_EVENT( TOOL_EVENT_CATEGORY aCategory, TOOL_ACTIONS aAction,
  190. const std::string& aExtraParam, TOOL_ACTION_SCOPE aScope = AS_GLOBAL,
  191. void* aParameter = nullptr ) :
  192. m_category( aCategory ),
  193. m_actions( aAction ),
  194. m_scope( aScope ),
  195. m_mouseButtons( 0 ),
  196. m_keyCode( 0 ),
  197. m_modifiers( 0 ),
  198. m_param( aParameter ),
  199. m_firstResponder( nullptr )
  200. {
  201. if( aCategory == TC_COMMAND || aCategory == TC_MESSAGE )
  202. m_commandStr = aExtraParam;
  203. init();
  204. }
  205. ///< Returns the category (eg. mouse/keyboard/action) of an event..
  206. TOOL_EVENT_CATEGORY Category() const { return m_category; }
  207. ///< Returns more specific information about the type of an event.
  208. TOOL_ACTIONS Action() const { return m_actions; }
  209. ///< These give a tool a method of informing the TOOL_MANAGER that a particular event should
  210. ///< be passed on to subsequent tools on the stack. Defaults to true for TC_MESSAGES; false
  211. ///< for everything else.
  212. bool PassEvent() const { return m_passEvent; }
  213. void SetPassEvent( bool aPass = true ) { m_passEvent = aPass; }
  214. ///< Returns if it this event has a valid position (true for mouse events and context-menu
  215. ///< or hotkey-based command events)
  216. bool HasPosition() const { return m_hasPosition; }
  217. void SetHasPosition( bool aHasPosition ) { m_hasPosition = aHasPosition; }
  218. ///< Returns if the action associated with this event should be treated as immediate regardless
  219. ///< of the current immediate action settings.
  220. bool ForceImmediate() const { return m_forceImmediate; }
  221. void SetForceImmediate( bool aForceImmediate = true ) { m_forceImmediate = aForceImmediate; }
  222. TOOL_BASE* FirstResponder() const { return m_firstResponder; }
  223. void SetFirstResponder( TOOL_BASE* aTool ) { m_firstResponder = aTool; }
  224. ///< Controls whether the tool is first being pushed to the stack or being reactivated after a pause
  225. bool IsReactivate() const { return m_reactivate; }
  226. void SetReactivate( bool aReactivate = true ) { m_reactivate = aReactivate; }
  227. ///< Returns information about difference between current mouse cursor position and the place
  228. ///< where dragging has started.
  229. const VECTOR2D Delta() const
  230. {
  231. return returnCheckedPosition( m_mouseDelta );
  232. }
  233. ///< Returns mouse cursor position in world coordinates.
  234. const VECTOR2D Position() const
  235. {
  236. return returnCheckedPosition( m_mousePos );
  237. }
  238. ///< Returns the point where dragging has started.
  239. const VECTOR2D DragOrigin() const
  240. {
  241. return returnCheckedPosition( m_mouseDragOrigin );
  242. }
  243. ///< Returns information about mouse buttons state.
  244. int Buttons() const
  245. {
  246. assert( m_category == TC_MOUSE ); // this should be used only with mouse events
  247. return m_mouseButtons;
  248. }
  249. bool IsClick( int aButtonMask = BUT_ANY ) const;
  250. bool IsDblClick( int aButtonMask = BUT_ANY ) const;
  251. bool IsDrag( int aButtonMask = BUT_ANY ) const
  252. {
  253. return m_actions == TA_MOUSE_DRAG && ( m_mouseButtons & aButtonMask ) == m_mouseButtons;
  254. }
  255. bool IsMouseUp( int aButtonMask = BUT_ANY ) const
  256. {
  257. return m_actions == TA_MOUSE_UP && ( m_mouseButtons & aButtonMask ) == m_mouseButtons;
  258. }
  259. bool IsMotion() const
  260. {
  261. return m_actions == TA_MOUSE_MOTION;
  262. }
  263. bool IsMouseAction() const
  264. {
  265. return ( m_actions & TA_MOUSE );
  266. }
  267. bool IsCancel() const
  268. {
  269. return m_actions == TA_CANCEL_TOOL;
  270. }
  271. bool IsActivate() const
  272. {
  273. return m_actions == TA_ACTIVATE;
  274. }
  275. bool IsUndoRedo() const
  276. {
  277. return m_actions & ( TA_UNDO_REDO_PRE | TA_UNDO_REDO_POST );
  278. }
  279. bool IsChoiceMenu() const
  280. {
  281. return m_actions & TA_CHOICE_MENU;
  282. }
  283. bool IsPrime() const
  284. {
  285. return m_actions == TA_PRIME;
  286. }
  287. ///< Returns information about key modifiers state (Ctrl, Alt, etc.)
  288. int Modifier( int aMask = MD_MODIFIER_MASK ) const
  289. {
  290. return m_modifiers & aMask;
  291. }
  292. bool DisableGridSnapping() const
  293. {
  294. return Modifier( MD_CTRL );
  295. }
  296. int KeyCode() const
  297. {
  298. return m_keyCode;
  299. }
  300. bool IsKeyPressed() const
  301. {
  302. return m_actions == TA_KEY_PRESSED;
  303. }
  304. /**
  305. * Test whether two events match in terms of category & action or command.
  306. *
  307. * @param aEvent is the event to test against.
  308. * @return True if two events match, false otherwise.
  309. */
  310. bool Matches( const TOOL_EVENT& aEvent ) const
  311. {
  312. if( !( m_category & aEvent.m_category ) )
  313. return false;
  314. if( m_category == TC_COMMAND || m_category == TC_MESSAGE )
  315. {
  316. if( (bool) m_commandStr && (bool) aEvent.m_commandStr )
  317. return *m_commandStr == *aEvent.m_commandStr;
  318. if( (bool) m_commandId && (bool) aEvent.m_commandId )
  319. return *m_commandId == *aEvent.m_commandId;
  320. }
  321. // BUGFIX: TA_ANY should match EVERYTHING, even TA_NONE (for TC_MESSAGE)
  322. if( m_actions == TA_ANY && aEvent.m_actions == TA_NONE && aEvent.m_category == TC_MESSAGE )
  323. return true;
  324. // BUGFIX: This check must happen after the TC_COMMAND check because otherwise events of
  325. // the form { TC_COMMAND, TA_NONE } will be incorrectly skipped
  326. if( !( m_actions & aEvent.m_actions ) )
  327. return false;
  328. return true;
  329. }
  330. /**
  331. * Test if the event contains an action issued upon activation of the given #TOOL_ACTION.
  332. *
  333. * @param aAction is the TOOL_ACTION to be checked against.
  334. * @return True if it matches the given TOOL_ACTION.
  335. */
  336. bool IsAction( const TOOL_ACTION* aAction ) const;
  337. /**
  338. * Indicate the event should restart/end an ongoing interactive tool's event loop (eg esc
  339. * key, click cancel, start different tool).
  340. */
  341. bool IsCancelInteractive() const;
  342. /**
  343. * Indicate an selection-changed notification event.
  344. */
  345. bool IsSelectionEvent() const;
  346. /**
  347. * Indicate if the event is from one of the point editors.
  348. *
  349. * Usually used to allow the point editor to activate itself without de-activating the
  350. * current drawing tool.
  351. */
  352. bool IsPointEditor() const;
  353. /**
  354. * Indicate if the event is from one of the move tools.
  355. *
  356. * Usually used to allow move to be done without de-activating the current drawing tool.
  357. */
  358. bool IsMoveTool() const;
  359. /**
  360. * Indicate if the event is from the simulator.
  361. */
  362. bool IsSimulator() const;
  363. /**
  364. * Return a non-standard parameter assigned to the event. Its meaning depends on the
  365. * target tool.
  366. */
  367. template<typename T>
  368. inline T Parameter() const
  369. {
  370. // Exhibit #798 on why I love to hate C++
  371. // - reinterpret_cast needs to be used for pointers
  372. // - static_cast must be used for enums
  373. // - templates can't usefully distinguish between pointer and non-pointer types
  374. // Fortunately good old C's cast can be a reinterpret_cast or a static_cast, and
  375. // C99 gave us intptr_t which is guaranteed to be round-trippable with a pointer.
  376. return (T) reinterpret_cast<intptr_t>( m_param );
  377. }
  378. /**
  379. * Set a non-standard parameter assigned to the event. Its meaning depends on the
  380. * target tool.
  381. *
  382. * @param aParam is the new parameter.
  383. */
  384. template<typename T>
  385. void SetParameter(T aParam)
  386. {
  387. m_param = (void*) aParam;
  388. }
  389. OPT<int> GetCommandId() const
  390. {
  391. return m_commandId;
  392. }
  393. OPT<std::string> GetCommandStr() const
  394. {
  395. return m_commandStr;
  396. }
  397. void SetMousePosition( const VECTOR2D& aP )
  398. {
  399. m_mousePos = aP;
  400. }
  401. private:
  402. friend class TOOL_DISPATCHER;
  403. void init();
  404. void setMouseDragOrigin( const VECTOR2D& aP )
  405. {
  406. m_mouseDragOrigin = aP;
  407. }
  408. void setMouseDelta( const VECTOR2D& aP )
  409. {
  410. m_mouseDelta = aP;
  411. }
  412. void setMouseButtons( int aButtons )
  413. {
  414. assert( ( aButtons & ~BUT_BUTTON_MASK ) == 0 );
  415. m_mouseButtons = aButtons;
  416. }
  417. void setModifiers( int aMods )
  418. {
  419. assert( ( aMods & ~MD_MODIFIER_MASK ) == 0 );
  420. m_modifiers = aMods;
  421. }
  422. /**
  423. * Ensure that the event is a type that has a position before returning a
  424. * position, otherwise return a null-constructed position.
  425. *
  426. * Used to defend the position accessors from runtime access when the event
  427. * does not have a valid position.
  428. *
  429. * @param aPos the position to return if the event is valid
  430. * @return the checked position
  431. */
  432. VECTOR2D returnCheckedPosition( const VECTOR2D& aPos ) const;
  433. TOOL_EVENT_CATEGORY m_category;
  434. TOOL_ACTIONS m_actions;
  435. TOOL_ACTION_SCOPE m_scope;
  436. bool m_passEvent;
  437. bool m_hasPosition;
  438. bool m_forceImmediate;
  439. ///< True when the tool is being re-activated from the stack
  440. bool m_reactivate;
  441. ///< Difference between mouse cursor position and
  442. ///< the point where dragging event has started
  443. VECTOR2D m_mouseDelta;
  444. ///< Current mouse cursor position
  445. VECTOR2D m_mousePos;
  446. ///< Point where dragging has started
  447. VECTOR2D m_mouseDragOrigin;
  448. ///< State of mouse buttons
  449. int m_mouseButtons;
  450. ///< Stores code of pressed/released key
  451. int m_keyCode;
  452. ///< State of key modifiers (Ctrl/Alt/etc.)
  453. int m_modifiers;
  454. ///< Generic parameter used for passing non-standard data.
  455. void* m_param;
  456. ///< The first tool to receive the event
  457. TOOL_BASE* m_firstResponder;
  458. OPT<int> m_commandId;
  459. OPT<std::string> m_commandStr;
  460. };
  461. typedef OPT<TOOL_EVENT> OPT_TOOL_EVENT;
  462. /**
  463. * A list of TOOL_EVENTs, with overloaded || operators allowing for concatenating TOOL_EVENTs
  464. * with little code.
  465. */
  466. class TOOL_EVENT_LIST
  467. {
  468. public:
  469. typedef TOOL_EVENT value_type;
  470. typedef std::deque<TOOL_EVENT>::iterator iterator;
  471. typedef std::deque<TOOL_EVENT>::const_iterator const_iterator;
  472. ///< Default constructor. Creates an empty list.
  473. TOOL_EVENT_LIST()
  474. {}
  475. ///< Constructor for a list containing only one TOOL_EVENT.
  476. TOOL_EVENT_LIST( const TOOL_EVENT& aSingleEvent )
  477. {
  478. m_events.push_back( aSingleEvent );
  479. }
  480. ///< Copy an existing TOOL_EVENT_LIST
  481. TOOL_EVENT_LIST( const TOOL_EVENT_LIST& aEventList )
  482. {
  483. m_events.clear();
  484. for( const TOOL_EVENT& event : aEventList.m_events )
  485. m_events.push_back( event );
  486. }
  487. /**
  488. * Function Format()
  489. * Returns information about event in form of a human-readable string.
  490. *
  491. * @return Event information.
  492. */
  493. const std::string Format() const;
  494. OPT<const TOOL_EVENT&> Matches( const TOOL_EVENT& aEvent ) const
  495. {
  496. for( const TOOL_EVENT& event : m_events )
  497. {
  498. if( event.Matches( aEvent ) )
  499. return event;
  500. }
  501. return OPT<const TOOL_EVENT&>();
  502. }
  503. /**
  504. * Add a tool event to the list.
  505. *
  506. * @param aEvent is the tool event to be added.
  507. */
  508. void Add( const TOOL_EVENT& aEvent )
  509. {
  510. m_events.push_back( aEvent );
  511. }
  512. iterator begin()
  513. {
  514. return m_events.begin();
  515. }
  516. iterator end()
  517. {
  518. return m_events.end();
  519. }
  520. const_iterator cbegin() const
  521. {
  522. return m_events.begin();
  523. }
  524. const_iterator cend() const
  525. {
  526. return m_events.end();
  527. }
  528. int size() const
  529. {
  530. return m_events.size();
  531. }
  532. void clear()
  533. {
  534. m_events.clear();
  535. }
  536. TOOL_EVENT_LIST& operator=( const TOOL_EVENT_LIST& aEventList )
  537. {
  538. m_events.clear();
  539. for( const TOOL_EVENT& event : aEventList.m_events )
  540. m_events.push_back( event );
  541. return *this;
  542. }
  543. TOOL_EVENT_LIST& operator=( const TOOL_EVENT& aEvent )
  544. {
  545. m_events.clear();
  546. m_events.push_back( aEvent );
  547. return *this;
  548. }
  549. TOOL_EVENT_LIST& operator||( const TOOL_EVENT& aEvent )
  550. {
  551. Add( aEvent );
  552. return *this;
  553. }
  554. TOOL_EVENT_LIST& operator||( const TOOL_EVENT_LIST& aEvent )
  555. {
  556. std::copy( aEvent.m_events.begin(), aEvent.m_events.end(), std::back_inserter( m_events ) );
  557. return *this;
  558. }
  559. private:
  560. std::deque<TOOL_EVENT> m_events;
  561. };
  562. inline const TOOL_EVENT_LIST operator||( const TOOL_EVENT& aEventA, const TOOL_EVENT& aEventB )
  563. {
  564. TOOL_EVENT_LIST l;
  565. l.Add( aEventA );
  566. l.Add( aEventB );
  567. return l;
  568. }
  569. inline const TOOL_EVENT_LIST operator||( const TOOL_EVENT& aEvent,
  570. const TOOL_EVENT_LIST& aEventList )
  571. {
  572. TOOL_EVENT_LIST l( aEventList );
  573. l.Add( aEvent );
  574. return l;
  575. }
  576. #endif