diff --git a/common/tool/action_manager.cpp b/common/tool/action_manager.cpp index b065cb2d55..a64ab9e1d5 100644 --- a/common/tool/action_manager.cpp +++ b/common/tool/action_manager.cpp @@ -89,24 +89,14 @@ int ACTION_MANAGER::MakeActionId( const std::string& aActionName ) } -bool ACTION_MANAGER::RunAction( const std::string& aActionName ) const +TOOL_ACTION* ACTION_MANAGER::FindAction( const std::string& aActionName ) const { std::map::const_iterator it = m_actionNameIndex.find( aActionName ); - if( it == m_actionNameIndex.end() ) - return false; // no action with given name found + if( it != m_actionNameIndex.end() ) + return it->second; - RunAction( it->second ); - - return true; -} - - -void ACTION_MANAGER::RunAction( const TOOL_ACTION* aAction ) const -{ - TOOL_EVENT event = aAction->MakeEvent(); - - m_toolMgr->ProcessEvent( event ); + return NULL; } @@ -153,6 +143,8 @@ bool ACTION_MANAGER::RunHotKey( int aHotKey ) const if( tool ) { + // Choose the action that goes to the tool with highest priority + // (i.e. is on the top of active tools stack) priority = m_toolMgr->GetPriority( tool->GetId() ); if( priority >= 0 && priority > highestPriority ) @@ -163,13 +155,16 @@ bool ACTION_MANAGER::RunHotKey( int aHotKey ) const } } - if( !global && !context ) // currently there is no valid action to run - return false; - if( context ) - RunAction( context ); + { + m_toolMgr->RunAction( *context, true ); + return true; + } else if( global ) - RunAction( global ); + { + m_toolMgr->RunAction( *global, true ); + return true; + } - return true; + return false; } diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp index 14d963839e..7a6df985fe 100644 --- a/common/tool/tool_manager.cpp +++ b/common/tool/tool_manager.cpp @@ -290,15 +290,40 @@ void TOOL_MANAGER::UnregisterAction( TOOL_ACTION* aAction ) } -bool TOOL_MANAGER::RunAction( const std::string& aActionName ) +bool TOOL_MANAGER::RunAction( const std::string& aActionName, bool aNow ) { - return m_actionMgr->RunAction( aActionName ); + TOOL_ACTION* action = m_actionMgr->FindAction( aActionName ); + + if( action ) + { + if( aNow ) + { + TOOL_EVENT event = action->MakeEvent(); + ProcessEvent( event ); + } + else + { + PostEvent( action->MakeEvent() ); + } + + return true; + } + + return false; } -void TOOL_MANAGER::RunAction( const TOOL_ACTION& aAction ) +void TOOL_MANAGER::RunAction( const TOOL_ACTION& aAction, bool aNow ) { - m_actionMgr->RunAction( &aAction ); + if( aNow ) + { + TOOL_EVENT event = aAction.MakeEvent(); + ProcessEvent( event ); + } + else + { + PostEvent( aAction.MakeEvent() ); + } } @@ -424,6 +449,8 @@ optional TOOL_MANAGER::ScheduleWait( TOOL_BASE* aTool, { TOOL_STATE* st = m_toolState[aTool]; + assert( !st->pendingWait ); // everything collapses on two Yield() in a row + // indicate to the manager that we are going to sleep and we shall be // woken up when an event matching aConditions arrive st->pendingWait = true; @@ -477,7 +504,7 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent ) { if( tr.first.Matches( aEvent ) ) { - // no tool context allocated yet? Create one. + // if there is already a context, then store it if( st->cofunc ) st->Push(); @@ -590,6 +617,14 @@ bool TOOL_MANAGER::ProcessEvent( TOOL_EVENT& aEvent ) dispatchActivation( aEvent ); dispatchContextMenu( aEvent ); + // Dispatch queue + while( !m_eventQueue.empty() ) + { + TOOL_EVENT event = m_eventQueue.front(); + m_eventQueue.pop_front(); + ProcessEvent( event ); + } + if( m_view->IsDirty() ) { PCB_EDIT_FRAME* f = static_cast( GetEditFrame() ); diff --git a/include/tool/action_manager.h b/include/tool/action_manager.h index 626f795eff..7c4c52cd4d 100644 --- a/include/tool/action_manager.h +++ b/include/tool/action_manager.h @@ -75,20 +75,12 @@ public: static int MakeActionId( const std::string& aActionName ); /** - * Function RunAction() - * Runs an action with a given name (if there is one available). - * @param aActionName is the name of action to be run. - * @return True if there was an action associated with the name, false otherwise. + * Function FindAction() + * Finds an action with a given name (if there is one available). + * @param aActionName is the searched action. + * @return Pointer to a TOOL_ACTION object or NULL if there is no such action. */ - bool RunAction( const std::string& aActionName ) const; - - /** - * Function RunAction() - * Prepares an appropriate event and sends it to the destination specified in a TOOL_ACTION - * object. - * @param aAction is the action to be run. - */ - void RunAction( const TOOL_ACTION* aAction ) const; + TOOL_ACTION* FindAction( const std::string& aActionName ) const; /** * Function RunHotKey() diff --git a/include/tool/tool_manager.h b/include/tool/tool_manager.h index 1935cf1b14..e5d4ce9458 100644 --- a/include/tool/tool_manager.h +++ b/include/tool/tool_manager.h @@ -106,17 +106,21 @@ public: * Runs the specified action. The common format for action names is "application.ToolName.Action". * * @param aActionName is the name of action to be invoked. - * @return True if the action finished successfully, false otherwise. + * @param aNow decides if the action has to be run immediately or after the current coroutine + * is preemptied. + * @return False if the action was not found. */ - bool RunAction( const std::string& aActionName ); + bool RunAction( const std::string& aActionName, bool aNow = false ); /** * Function RunAction() * Runs the specified action. * * @param aAction is the action to be invoked. + * @param aNow decides if the action has to be run immediately or after the current coroutine + * is preemptied. */ - void RunAction( const TOOL_ACTION& aAction ); + void RunAction( const TOOL_ACTION& aAction, bool aNow = false ); /** * Function FindTool() @@ -158,11 +162,20 @@ public: void ResetTools( TOOL_BASE::RESET_REASON aReason ); /** - * Takes an event from the TOOL_DISPATCHER and propagates it to - * tools that requested events of matching type(s) + * Propagates an event to tools that requested events of matching type(s). + * @param aEvent is the event to be processed. */ bool ProcessEvent( TOOL_EVENT& aEvent ); + /** + * Puts an event to the event queue to be processed at the end of event processing cycle. + * @param aEvent is the event to be put into the queue. + */ + inline void PostEvent( const TOOL_EVENT& aEvent ) + { + m_eventQueue.push_back( aEvent ); + } + /** * Sets the work environment (model, view, view controls and the parent window). * These are made available to the tool. Called by the parent frame (PCB_EDIT_FRAME) @@ -177,17 +190,17 @@ public: return m_view; } - KIGFX::VIEW_CONTROLS* GetViewControls() const + inline KIGFX::VIEW_CONTROLS* GetViewControls() const { return m_viewControls; } - EDA_ITEM* GetModel() const + inline EDA_ITEM* GetModel() const { return m_model; } - wxWindow* GetEditFrame() const + inline wxWindow* GetEditFrame() const { return m_editFrame; } @@ -197,7 +210,7 @@ public: * (was invoked the most recently). * @return Id of the currently used tool. */ - int GetCurrentToolId() const + inline int GetCurrentToolId() const { return m_activeTools.front(); } @@ -207,7 +220,7 @@ public: * (was invoked the most recently). * @return Pointer to the currently used tool. */ - TOOL_BASE* GetCurrentTool() const + inline TOOL_BASE* GetCurrentTool() const { return FindTool( GetCurrentToolId() ); } @@ -405,6 +418,9 @@ private: KIGFX::VIEW_CONTROLS* m_viewControls; wxWindow* m_editFrame; + /// Queue that stores events to be processed at the end of the event processing cycle. + std::list m_eventQueue; + /// Flag saying if the currently processed event should be passed to other tools. bool m_passEvent; }; diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index 312b060920..4dc89ddebb 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -404,11 +404,7 @@ void ROUTER_TOOL::handleCommonEvents( TOOL_EVENT& aEvent ) bds.SetCustomViaDrill( m_router->Settings().GetViaDrill() ); bds.UseCustomTrackViaSize( true ); - // TODO Should be done another way, but RunAction() won't work here. As the ROUTER_TOOL - // did not call Wait(), it does not wait for events and therefore the sent event - // won't arrive here - TOOL_EVENT event = COMMON_ACTIONS::trackViaSizeChanged.MakeEvent(); - handleCommonEvents( event ); + m_toolMgr->RunAction( COMMON_ACTIONS::trackViaSizeChanged ); } else if( aEvent.IsAction( &COMMON_ACTIONS::trackViaSizeChanged ) ) diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index ed69da782b..6c5a6082fd 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -559,7 +559,7 @@ wxPoint EDIT_TOOL::getModificationPoint( const SELECTION& aSelection ) bool EDIT_TOOL::makeSelection( const SELECTION& aSelection ) { if( aSelection.Empty() ) // Try to find an item that could be modified - m_toolMgr->RunAction( COMMON_ACTIONS::selectionSingle ); + m_toolMgr->RunAction( COMMON_ACTIONS::selectionSingle, true ); return !aSelection.Empty(); }