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 * @author Maciej Suminski <maciej.suminski@cern.ch> 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 2 13 * of the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, you may find one here: 22 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 23 * or you may search the http://www.gnu.org website for the version 2 license, 24 * or you may write to the Free Software Foundation, Inc., 25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 26 */ 27 28 #ifndef __TOOL_MANAGER_H 29 #define __TOOL_MANAGER_H 30 31 #include <typeinfo> 32 #include <map> 33 #include <list> 34 #include <stack> 35 36 #include <tool/tool_base.h> 37 #include <tool/tool_event.h> 38 #include <view/view_controls.h> 39 40 class TOOLS_HOLDER; 41 class TOOL_ACTION; 42 class TOOL_BASE; 43 class ACTION_MANAGER; 44 class ACTION_MENU; 45 class APP_SETTINGS_BASE; 46 47 48 /** 49 * Master controller class: 50 * - registers editing tools 51 * - pumps UI events to tools requesting them 52 * - manages tool state machines (transitions and wait requests) 53 */ 54 class TOOL_MANAGER 55 { 56 private: 57 struct TOOL_STATE; 58 59 public: 60 TOOL_MANAGER(); 61 62 ~TOOL_MANAGER(); 63 64 // Helper typedefs 65 typedef std::map<TOOL_BASE*, TOOL_STATE*> TOOL_STATE_MAP; 66 typedef std::map<std::string, TOOL_STATE*> NAME_STATE_MAP; 67 typedef std::map<TOOL_ID, TOOL_STATE*> ID_STATE_MAP; 68 typedef std::list<TOOL_ID> ID_LIST; 69 typedef std::vector<TOOL_BASE*> TOOL_VEC; 70 71 /** 72 * Generates a unique ID from for a tool with given name. 73 */ 74 static TOOL_ID MakeToolId( const std::string& aToolName ); 75 76 /** 77 * Add a tool to the manager set and sets it up. Called once for each tool during 78 * application initialization. 79 * 80 * @param aTool: tool to be added. Ownership is transferred. 81 */ 82 void RegisterTool( TOOL_BASE* aTool ); 83 84 /** 85 * Call a tool by sending a tool activation event to tool of given ID. 86 * 87 * @param aToolId is the ID number of the requested tool. 88 * @return True if the requested tool was invoked successfully. 89 */ 90 bool InvokeTool( TOOL_ID aToolId ); 91 92 /** 93 * Call a tool by sending a tool activation event to tool of given name. 94 * 95 * @param aToolName is the name of the requested tool. 96 * @return True if the requested tool was invoked successfully. 97 */ 98 bool InvokeTool( const std::string& aToolName ); 99 100 /** 101 * Shutdown all tools with a currently registered event loop in this tool manager 102 * by waking them up with a null event. 103 */ 104 void ShutdownAllTools(); 105 106 /** 107 * Shutdown the specified tool by waking it up with a null event to terminate 108 * the processing loop. 109 * 110 * @param aTool is the tool to shutdown 111 */ 112 void ShutdownTool( TOOL_BASE* aTool ); 113 114 /** 115 * Shutdown the specified tool by waking it up with a null event to terminate 116 * the processing loop. 117 * 118 * @param aToolId is the ID of the tool to shutdown 119 */ 120 void ShutdownTool( TOOL_ID aToolId ); 121 122 /** 123 * Shutdown the specified tool by waking it up with a null event to terminate 124 * the processing loop. 125 * 126 * @param aToolName is name of the tool to shutdown 127 */ 128 void ShutdownTool( const std::string& aToolName ); 129 130 /** 131 * Run the specified action. 132 * 133 * The common format for action names is "application.ToolName.Action". 134 * 135 * @param aActionName is the name of action to be invoked. 136 * @param aNow decides if the action has to be run immediately or after the current coroutine 137 * is preemptied. 138 * @param aParam is an optional parameter that might be used by the invoked action. Its meaning 139 * depends on the action. 140 * @return False if the action was not found. 141 */ 142 template<typename T> 143 bool RunAction( const std::string& aActionName, bool aNow = false, T aParam = NULL ) 144 { 145 return RunAction( aActionName, aNow, reinterpret_cast<void*>( aParam ) ); 146 } 147 148 bool RunAction( const std::string& aActionName, bool aNow, void* aParam ); 149 150 bool RunAction( const std::string& aActionName, bool aNow = false ) 151 { 152 return RunAction( aActionName, aNow, (void*) NULL ); 153 } 154 155 /** 156 * Run the specified action. 157 * 158 * This function will only return if the action has been handled when the action is run 159 * immediately (aNow = true), otherwise it will always return false. 160 * 161 * @param aAction is the action to be invoked. 162 * @param aNow decides if the action has to be run immediately or after the current coroutine 163 * is preemptied. 164 * @param aParam is an optional parameter that might be used by the invoked action. Its meaning 165 * depends on the action. 166 * @return True if the action was handled immediately 167 */ 168 template <typename T> 169 bool RunAction( const TOOL_ACTION& aAction, bool aNow = false, T aParam = NULL ) 170 { 171 return RunAction( aAction, aNow, reinterpret_cast<void*>( aParam ) ); 172 } 173 174 bool RunAction( const TOOL_ACTION& aAction, bool aNow, void* aParam ); 175 176 bool RunAction( const TOOL_ACTION& aAction, bool aNow = false ) 177 { 178 return RunAction( aAction, aNow, (void*) NULL ); 179 } 180 181 const std::map<std::string, TOOL_ACTION*>& GetActions() const; 182 183 /** 184 * Send a cancel event to the tool currently at the top of the tool stack. 185 */ 186 void CancelTool(); 187 188 /** 189 * "Prime" a tool by sending a cursor left-click event with the mouse position set 190 * to the passed in position. 191 * 192 * @param aPosition is the mouse position to use in the event 193 */ 194 void PrimeTool( const VECTOR2D& aPosition ); 195 196 ///< @copydoc ACTION_MANAGER::GetHotKey() 197 int GetHotKey( const TOOL_ACTION& aAction ) const; 198 GetActionManager()199 ACTION_MANAGER* GetActionManager() const { return m_actionMgr; } 200 201 /** 202 * Search for a tool with given ID. 203 * 204 * @param aId is the ID number of the requested tool. 205 * @return Pointer to the requested tool or NULL in case of failure. 206 */ 207 TOOL_BASE* FindTool( int aId ) const; 208 209 /** 210 * Search for a tool with given name. 211 * 212 * @param aName is the name of the requested tool. 213 * @return Pointer to the requested tool or NULL in case of failure. 214 */ 215 TOOL_BASE* FindTool( const std::string& aName ) const; 216 217 /* 218 * Return the tool of given type or nullptr if there is no such tool registered. 219 */ 220 template<typename T> GetTool()221 T* GetTool() 222 { 223 std::map<const char*, TOOL_BASE*>::iterator tool = m_toolTypes.find( typeid( T ).name() ); 224 225 if( tool != m_toolTypes.end() ) 226 return static_cast<T*>( tool->second ); 227 228 return nullptr; 229 } 230 231 /** 232 * Deactivate the currently active tool. 233 */ 234 void DeactivateTool(); 235 236 237 /** 238 * Return true if a tool with given id is active (executing) 239 */ 240 bool IsToolActive( TOOL_ID aId ) const; 241 242 243 /** 244 * Reset all tools (i.e. calls their Reset() method). 245 */ 246 void ResetTools( TOOL_BASE::RESET_REASON aReason ); 247 248 /** 249 * Initializes all registered tools. 250 * 251 * If a tool fails during the initialization, it is deactivated and becomes unavailable 252 * for further use. Initialization should be done only once. 253 */ 254 void InitTools(); 255 256 /** 257 * Propagate an event to tools that requested events of matching type(s). 258 * 259 * @param aEvent is the event to be processed. 260 * @return true if the event is a managed hotkey 261 */ 262 bool ProcessEvent( const TOOL_EVENT& aEvent ); 263 264 /** 265 * Put an event to the event queue to be processed at the end of event processing cycle. 266 * 267 * @param aEvent is the event to be put into the queue. 268 */ 269 void PostEvent( const TOOL_EVENT& aEvent ); 270 271 /** 272 * Set the work environment (model, view, view controls and the parent window). 273 * 274 * These are made available to the tool. Called by the parent frame when it is set up. 275 */ 276 void SetEnvironment( EDA_ITEM* aModel, KIGFX::VIEW* aView, 277 KIGFX::VIEW_CONTROLS* aViewControls, APP_SETTINGS_BASE* aSettings, 278 TOOLS_HOLDER* aFrame ); 279 280 /* 281 * Accessors for the environment objects (view, model, etc.) 282 */ GetView()283 KIGFX::VIEW* GetView() const { return m_view; } 284 GetViewControls()285 KIGFX::VIEW_CONTROLS* GetViewControls() const { return m_viewControls; } 286 287 VECTOR2D GetMousePosition() const; 288 VECTOR2D GetCursorPosition() const; 289 GetModel()290 EDA_ITEM* GetModel() const { return m_model; } 291 GetSettings()292 APP_SETTINGS_BASE* GetSettings() const { return m_settings; } 293 GetToolHolder()294 TOOLS_HOLDER* GetToolHolder() const { return m_frame; } 295 296 /** 297 * Return id of the tool that is on the top of the active tools stack (was invoked the 298 * most recently). 299 * 300 * @return Id of the currently used tool. 301 */ GetCurrentToolId()302 inline int GetCurrentToolId() const 303 { 304 return m_activeTools.empty() ? -1 : m_activeTools.front(); 305 } 306 307 /** 308 * Return the tool that is on the top of the active tools stack (was invoked the most 309 * recently). 310 * 311 * @return Pointer to the currently used tool. 312 */ GetCurrentTool()313 inline TOOL_BASE* GetCurrentTool() const 314 { 315 return FindTool( GetCurrentToolId() ); 316 } 317 318 /** 319 * Return the #TOOL_STATE object representing the state of the active tool. If there are no 320 * tools active, it returns nullptr. 321 */ GetCurrentToolState()322 TOOL_STATE* GetCurrentToolState() const 323 { 324 auto it = m_toolIdIndex.find( GetCurrentToolId() ); 325 return ( it != m_toolIdIndex.end() ) ? it->second : nullptr; 326 } 327 328 /** 329 * Return priority of a given tool. 330 * 331 * Higher number means that the tool is closer to the beginning of the active tools 332 * queue (i.e. receives events earlier, tools with lower priority receive events later). 333 * 334 * @param aToolId is the id of queried tool. 335 * @return The priority of a given tool. If returned number is negative, then it means that 336 * the tool id is invalid or the tool is not active. 337 */ 338 int GetPriority( int aToolId ) const; 339 340 /** 341 * Define a state transition. 342 * 343 * The events that cause a given handler method in the tool to be called. Called by 344 * TOOL_INTERACTIVE::Go(). May be called from a coroutine context. 345 */ 346 void ScheduleNextState( TOOL_BASE* aTool, TOOL_STATE_FUNC& aHandler, 347 const TOOL_EVENT_LIST& aConditions ); 348 349 /** 350 * Clear the state transition map for a tool. 351 * 352 * @param aTool is the tool that should have the transition map cleared. 353 */ 354 void ClearTransitions( TOOL_BASE* aTool ); 355 356 void RunMainStack( TOOL_BASE* aTool, std::function<void()> aFunc ); 357 358 /** 359 * Update the status bar and synchronizes toolbars. 360 */ 361 void UpdateUI( const TOOL_EVENT& aEvent ); 362 363 /** 364 * Pause execution of a given tool until one or more events matching aConditions arrives. 365 * 366 * The pause/resume operation is done through #COROUTINE object. Called only from coroutines. 367 */ 368 TOOL_EVENT* ScheduleWait( TOOL_BASE* aTool, const TOOL_EVENT_LIST& aConditions ); 369 370 /** 371 * Set behavior of the tool's context popup menu. 372 * 373 * @param aTool is the parent tool. 374 * @param aMenu is the menu structure, defined by the tool. 375 * @param aTrigger determines when the menu is activated: 376 * CMENU_NOW: opens the menu right now 377 * CMENU_BUTTON: opens the menu when RMB is pressed 378 * CMENU_OFF: menu is disabled. 379 * May be called from a coroutine context. 380 */ 381 void ScheduleContextMenu( TOOL_BASE* aTool, ACTION_MENU* aMenu, CONTEXT_MENU_TRIGGER aTrigger ); 382 383 /** 384 * Store information to the system clipboard. 385 * 386 * @param aText is the information to be stored, expected UTF8 encoding. The text will be 387 * stored as Unicode string (not stored as UTF8 string). 388 * @return False if error occurred. 389 */ 390 bool SaveClipboard( const std::string& aTextUTF8 ); 391 392 /** 393 * Return the information currently stored in the system clipboard. 394 * 395 * If data stored in the clipboard is in non-text format, empty string is returned. 396 * 397 * @note The clipboard is expected containing Unicode chars, not only ASCII7 chars. 398 * The returned string is UTF8 encoded 399 */ 400 std::string GetClipboardUTF8() const; 401 402 /** 403 * Return the view controls settings for the current tool or the general settings if there is 404 * no active tool. 405 */ 406 const KIGFX::VC_SETTINGS& GetCurrentToolVC() const; 407 408 /** 409 * True while processing a context menu. 410 */ IsContextMenuActive()411 bool IsContextMenuActive() const 412 { 413 return m_menuActive; 414 } 415 416 /** 417 * Disable mouse warping after the current context menu is closed. 418 * 419 * This must be called before invoking each context menu. It's a good idea to call this 420 * from non-modal dialogs (e.g. DRC window). 421 */ VetoContextMenuMouseWarp()422 void VetoContextMenuMouseWarp() 423 { 424 m_warpMouseAfterContextMenu = false; 425 } 426 427 /** 428 * Handle context menu related events. 429 */ 430 void DispatchContextMenu( const TOOL_EVENT& aEvent ); 431 432 /** 433 * Handle specific events, that are intended for TOOL_MANAGER rather than tools. 434 * 435 * @param aEvent is the event to be processed. 436 * @return true if the event was processed and should not go any further. 437 */ 438 bool DispatchHotKey( const TOOL_EVENT& aEvent ); 439 GetMenuCursorPos()440 VECTOR2D GetMenuCursorPos() const 441 { 442 return m_menuCursor; 443 } 444 445 private: 446 typedef std::pair<TOOL_EVENT_LIST, TOOL_STATE_FUNC> TRANSITION; 447 448 /** 449 * Pass an event at first to the active tools, then to all others. 450 */ 451 bool dispatchInternal( TOOL_EVENT& aEvent ); 452 453 /** 454 * Check if it is a valid activation event and invokes a proper tool. 455 * 456 * @param aEvent is an event to be tested. 457 * @return True if a tool was invoked, false otherwise. 458 */ 459 bool dispatchActivation( const TOOL_EVENT& aEvent ); 460 461 /** 462 * Invoke a tool by sending a proper event (in contrary to runTool, which makes the tool run 463 * for real). 464 * 465 * @param aTool is the tool to be invoked. 466 */ 467 bool invokeTool( TOOL_BASE* aTool ); 468 469 /** 470 * Make a tool active, so it can receive events and react to them. 471 * 472 * The activated tool is pushed on the active tools stack, so the last activated tool 473 * receives events first. 474 * 475 * @param aTool is the tool to be run. 476 */ 477 bool runTool( TOOL_BASE* aTool ); 478 479 /** 480 * Deactivate a tool and does the necessary clean up. 481 * 482 * @param aState is the state variable of the tool to be stopped. 483 * @return m_activeTools iterator. If the tool has been completely deactivated, it points 484 * to the next active tool on the list. Otherwise it is an iterator pointing to 485 * \a aState. 486 */ 487 ID_LIST::iterator finishTool( TOOL_STATE* aState ); 488 489 /** 490 * Return information about a tool registration status. 491 * 492 * @param aTool is the tool to be checked. 493 * @return true if the tool is in the registered tools list, false otherwise. 494 */ isRegistered(TOOL_BASE * aTool)495 bool isRegistered( TOOL_BASE* aTool ) const 496 { 497 return m_toolState.count( aTool ) > 0; 498 } 499 500 /** 501 * Return information about a tool activation status. 502 * 503 * @param aTool is the tool to be checked. 504 * @return True if the tool is on the active tools stack, false otherwise. 505 */ 506 bool isActive( TOOL_BASE* aTool ) const; 507 508 /** 509 * Save the #VIEW_CONTROLS settings to the tool state object. 510 * 511 * If #VIEW_CONTROLS settings are affected by #TOOL_MANAGER, the original settings are saved. 512 */ 513 void saveViewControls( TOOL_STATE* aState ); 514 515 /** 516 * Apply #VIEW_CONTROLS settings stored in a #TOOL_STATE object. 517 */ 518 void applyViewControls( const TOOL_STATE* aState ); 519 520 /** 521 * Main function for event processing. 522 * 523 * @return true if a hotkey was handled. 524 */ 525 bool processEvent( const TOOL_EVENT& aEvent ); 526 527 /** 528 * Save the previous active state and sets a new one. 529 * 530 * @param aState is the new active state. Might be null to indicate there is no new 531 * active state. 532 */ 533 void setActiveState( TOOL_STATE* aState ); 534 535 ///< List of tools in the order they were registered 536 TOOL_VEC m_toolOrder; 537 538 ///< Index of registered tools current states, associated by tools' objects. 539 TOOL_STATE_MAP m_toolState; 540 541 ///< Index of the registered tools current states, associated by tools' names. 542 NAME_STATE_MAP m_toolNameIndex; 543 544 ///< Index of the registered tools current states, associated by tools' ID numbers. 545 ID_STATE_MAP m_toolIdIndex; 546 547 ///< Index of the registered tools to easily lookup by their type. 548 std::map<const char*, TOOL_BASE*> m_toolTypes; 549 550 ///< Stack of the active tools 551 ID_LIST m_activeTools; 552 553 ///< Instance of ACTION_MANAGER that handles TOOL_ACTIONs 554 ACTION_MANAGER* m_actionMgr; 555 556 ///< Original cursor position, if overridden by the context menu handler 557 std::map<TOOL_ID, OPT<VECTOR2D>> m_cursorSettings; 558 559 EDA_ITEM* m_model; 560 KIGFX::VIEW* m_view; 561 KIGFX::VIEW_CONTROLS* m_viewControls; 562 TOOLS_HOLDER* m_frame; 563 APP_SETTINGS_BASE* m_settings; 564 565 ///< Queue that stores events to be processed at the end of the event processing cycle. 566 std::list<TOOL_EVENT> m_eventQueue; 567 568 ///< Right click context menu position. 569 VECTOR2D m_menuCursor; 570 571 bool m_warpMouseAfterContextMenu; 572 573 ///< Flag indicating whether a context menu is currently displayed. 574 bool m_menuActive; 575 576 ///< Tool currently displaying a popup menu. It is negative when there is no menu displayed. 577 TOOL_ID m_menuOwner; 578 579 ///< Pointer to the state object corresponding to the currently executed tool. 580 TOOL_STATE* m_activeState; 581 }; 582 583 #endif // __TOOL_MANAGER_H 584