void TOOL_MANAGER::dispatchInternal( const TOOL_EVENT& aEvent ) { // iterate over all registered tools for( auto it = m_activeTools.begin(); it != m_activeTools.end(); /* iteration is done inside */) { auto curIt = it; TOOL_STATE* st = m_toolIdIndex[*it]; ++it; // it might be overwritten, if the tool is removed the m_activeTools deque // the tool state handler is waiting for events (i.e. called Wait() method) if( st->pendingWait ) { if( st->waitEvents.Matches( aEvent ) ) { // By default, only messages are passed further m_passEvent = ( aEvent.Category() == TC_MESSAGE ); // got matching event? clear wait list and wake up the coroutine st->wakeupEvent = aEvent; st->pendingWait = false; st->waitEvents.clear(); if( st->cofunc && !st->cofunc->Resume() ) { if( finishTool( st, false ) ) // The couroutine has finished it = m_activeTools.erase( curIt ); } // If the tool did not request to propagate // the event to other tools, we should stop it now if( !m_passEvent ) break; } } } for( TOOL_STATE* st : ( m_toolState | boost::adaptors::map_values ) ) { // no state handler in progress - check if there are any transitions (defined by // Go() method that match the event. if( !st->pendingWait && !st->transitions.empty() ) { for( TRANSITION& tr : st->transitions ) { if( tr.first.Matches( aEvent ) ) { auto func_copy = tr.second; // if there is already a context, then store it if( st->cofunc ) st->Push(); st->cofunc = new COROUTINE<int, const TOOL_EVENT&>( std::move( func_copy ) ); // as the state changes, the transition table has to be set up again st->transitions.clear(); // got match? Run the handler. st->cofunc->Call( aEvent ); if( !st->cofunc->Running() ) finishTool( st ); // The couroutine has finished immediately? // there is no point in further checking, as transitions got cleared break; } } } } }
void TOOL_MANAGER::dispatchInternal( const TOOL_EVENT& aEvent ) { // iterate over all registered tools for( auto it = m_activeTools.begin(); it != m_activeTools.end(); ++it ) { TOOL_STATE* st = m_toolIdIndex[*it]; // forward context menu events to the tool that created the menu if( aEvent.IsMenu() ) { if( *it != m_menuOwner ) continue; } // the tool state handler is waiting for events (i.e. called Wait() method) if( st->pendingWait ) { if( st->waitEvents.Matches( aEvent ) ) { // By default only messages are passed further m_passEvent = ( aEvent.Category() == TC_MESSAGE ); // got matching event? clear wait list and wake up the coroutine st->wakeupEvent = aEvent; st->pendingWait = false; st->waitEvents.clear(); if( st->cofunc ) { setActiveState( st ); bool end = !st->cofunc->Resume(); if( end ) it = finishTool( st ); } // If the tool did not request to propagate // the event to other tools, we should stop it now if( !m_passEvent ) break; } } } for( auto& state : m_toolState ) { TOOL_STATE* st = state.second; bool finished = false; // no state handler in progress - check if there are any transitions (defined by // Go() method that match the event. if( !st->transitions.empty() ) { for( TRANSITION& tr : st->transitions ) { if( tr.first.Matches( aEvent ) ) { auto func_copy = tr.second; // if there is already a context, then push it on the stack // and transfer the previous view control settings to the new context if( st->cofunc ) { auto vc = st->vcSettings; st->Push(); st->vcSettings = vc; } st->cofunc = new COROUTINE<int, const TOOL_EVENT&>( std::move( func_copy ) ); // as the state changes, the transition table has to be set up again st->transitions.clear(); // got match? Run the handler. setActiveState( st ); st->idle = false; st->cofunc->Call( aEvent ); if( !st->cofunc->Running() ) finishTool( st ); // The couroutine has finished immediately? // if it is a message, continue processing finished = !( aEvent.Category() == TC_MESSAGE ); // there is no point in further checking, as transitions got cleared break; } } } if( finished ) break; // only the first tool gets the event } }