KiCad PCB EDA Suite
tool_manager.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2013-2018 CERN
5  * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
7  * @author Maciej Suminski <maciej.suminski@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 
27 #include <algorithm>
28 #include <core/optional.h>
29 #include <map>
30 #include <stack>
31 #include <trace_helpers.h>
32 
33 #include <wx/event.h>
34 #include <wx/clipbrd.h>
35 
36 #include <view/view.h>
37 #include <eda_base_frame.h>
38 #include <tool/tool_base.h>
39 #include <tool/tool_interactive.h>
40 #include <tool/tool_manager.h>
41 #include <tool/action_menu.h>
42 #include <tool/coroutine.h>
43 #include <tool/action_manager.h>
44 
45 #include <class_draw_panel_gal.h>
46 
49 {
50  TOOL_STATE( TOOL_BASE* aTool ) :
51  theTool( aTool )
52  {
53  clear();
54  }
55 
56  TOOL_STATE( const TOOL_STATE& aState )
57  {
58  theTool = aState.theTool;
59  idle = aState.idle;
60  pendingWait = aState.pendingWait;
62  contextMenu = aState.contextMenu;
64  cofunc = aState.cofunc;
65  wakeupEvent = aState.wakeupEvent;
66  waitEvents = aState.waitEvents;
67  transitions = aState.transitions;
68  vcSettings = aState.vcSettings;
69  // do not copy stateStack
70  }
71 
73  {
74  if( !stateStack.empty() )
75  wxFAIL;
76  }
77 
80 
82  bool idle;
83 
87 
90 
93 
96 
99 
102 
105 
108  std::vector<TRANSITION> transitions;
109 
112 
113  TOOL_STATE& operator=( const TOOL_STATE& aState )
114  {
115  theTool = aState.theTool;
116  idle = aState.idle;
117  pendingWait = aState.pendingWait;
119  contextMenu = aState.contextMenu;
121  cofunc = aState.cofunc;
122  wakeupEvent = aState.wakeupEvent;
123  waitEvents = aState.waitEvents;
124  transitions = aState.transitions;
125  vcSettings = aState.vcSettings;
126  // do not copy stateStack
127  return *this;
128  }
129 
130  bool operator==( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
131  {
132  return aRhs.theTool == this->theTool;
133  }
134 
135  bool operator!=( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
136  {
137  return aRhs.theTool != this->theTool;
138  }
139 
145  void Push()
146  {
147  auto state = std::make_unique<TOOL_STATE>( *this );
148  stateStack.push( std::move( state ) );
149  clear();
150  }
151 
158  bool Pop()
159  {
160  delete cofunc;
161 
162  if( !stateStack.empty() )
163  {
164  *this = *stateStack.top().get();
165  stateStack.pop();
166  return true;
167  }
168  else
169  {
170  cofunc = NULL;
171  return false;
172  }
173  }
174 
175 private:
177  std::stack<std::unique_ptr<TOOL_STATE>> stateStack;
178 
180  void clear()
181  {
182  idle = true;
183  pendingWait = false;
184  pendingContextMenu = false;
185  cofunc = NULL;
186  contextMenu = NULL;
188  vcSettings.Reset();
189  transitions.clear();
190  }
191 };
192 
193 
195  m_model( NULL ),
196  m_view( NULL ),
197  m_viewControls( NULL ),
198  m_frame( NULL ),
199  m_warpMouseAfterContextMenu( true ),
200  m_menuActive( false ),
201  m_menuOwner( -1 ),
202  m_activeState( nullptr )
203 {
204  m_actionMgr = new ACTION_MANAGER( this );
205 }
206 
207 
209 {
210  std::map<TOOL_BASE*, TOOL_STATE*>::iterator it, it_end;
211 
212  for( it = m_toolState.begin(), it_end = m_toolState.end(); it != it_end; ++it )
213  {
214  delete it->second->cofunc; // delete cofunction
215  delete it->second; // delete TOOL_STATE
216  delete it->first; // delete the tool itself
217  }
218 
219  delete m_actionMgr;
220 }
221 
222 
224 {
225  wxASSERT_MSG( m_toolNameIndex.find( aTool->GetName() ) == m_toolNameIndex.end(),
226  wxT( "Adding two tools with the same name may result in unexpected behaviour.") );
227  wxASSERT_MSG( m_toolIdIndex.find( aTool->GetId() ) == m_toolIdIndex.end(),
228  wxT( "Adding two tools with the same ID may result in unexpected behaviour.") );
229  wxASSERT_MSG( m_toolTypes.find( typeid( *aTool ).name() ) == m_toolTypes.end(),
230  wxT( "Adding two tools of the same type may result in unexpected behaviour.") );
231 
232  TOOL_STATE* st = new TOOL_STATE( aTool );
233 
234  m_toolState[aTool] = st;
235  m_toolNameIndex[aTool->GetName()] = st;
236  m_toolIdIndex[aTool->GetId()] = st;
237  m_toolTypes[typeid( *aTool ).name()] = st->theTool;
238 
239  aTool->attachManager( this );
240 }
241 
242 
244 {
245  TOOL_BASE* tool = FindTool( aToolId );
246 
247  if( tool && tool->GetType() == INTERACTIVE )
248  return invokeTool( tool );
249 
250  return false; // there is no tool with the given id
251 }
252 
253 
254 bool TOOL_MANAGER::InvokeTool( const std::string& aToolName )
255 {
256  TOOL_BASE* tool = FindTool( aToolName );
257 
258  if( tool && tool->GetType() == INTERACTIVE )
259  return invokeTool( tool );
260 
261  return false; // there is no tool with the given name
262 }
263 
264 
265 bool TOOL_MANAGER::RunAction( const std::string& aActionName, bool aNow, void* aParam )
266 {
267  TOOL_ACTION* action = m_actionMgr->FindAction( aActionName );
268 
269  if( !action )
270  {
271  wxASSERT_MSG( false, wxString::Format( wxT( "Could not find action %s." ), aActionName ) );
272  return false;
273  }
274 
275  RunAction( *action, aNow, aParam );
276 
277  return false;
278 }
279 
280 
282 {
283  if( m_viewControls )
285  else
286  return wxGetMousePosition();
287 }
288 
289 
291 {
292  if( m_viewControls )
294  else
295  return wxGetMousePosition();
296 }
297 
298 
299 bool TOOL_MANAGER::RunAction( const TOOL_ACTION& aAction, bool aNow, void* aParam )
300 {
301  bool handled = false;
302  TOOL_EVENT event = aAction.MakeEvent();
303 
304  if( event.Category() == TC_COMMAND )
306 
307  // Allow to override the action parameter
308  if( aParam )
309  event.SetParameter( aParam );
310 
311  if( aNow )
312  {
313  TOOL_STATE* current = m_activeState;
314  handled = processEvent( event );
315  setActiveState( current );
316  UpdateUI( event );
317  }
318  else
319  {
320  PostEvent( event );
321  }
322 
323  return handled;
324 }
325 
326 
327 void TOOL_MANAGER::PrimeTool( const VECTOR2D& aPosition )
328 {
329  int modifiers = 0;
330  modifiers |= wxGetKeyState( WXK_SHIFT ) ? MD_SHIFT : 0;
331  modifiers |= wxGetKeyState( WXK_CONTROL ) ? MD_CTRL : 0;
332  modifiers |= wxGetKeyState( WXK_ALT ) ? MD_ALT : 0;
333 
334  TOOL_EVENT evt( TC_MOUSE, TA_PRIME, BUT_LEFT | modifiers );
335  evt.SetMousePosition( aPosition );
336 
337  PostEvent( evt );
338 }
339 
340 
341 const std::map<std::string, TOOL_ACTION*>& TOOL_MANAGER::GetActions()
342 {
343  return m_actionMgr->GetActions();
344 }
345 
346 
348 {
349  return m_actionMgr->GetHotKey( aAction );
350 }
351 
352 
354 {
355  wxASSERT( aTool != NULL );
356 
357  TOOL_EVENT evt( TC_COMMAND, TA_ACTIVATE, aTool->GetName() );
359  processEvent( evt );
360 
361  if( TOOL_STATE* active = GetCurrentToolState() )
362  setActiveState( active );
363 
364  return true;
365 }
366 
367 
369 {
370  TOOL_BASE* tool = FindTool( aToolId );
371 
372  if( tool && tool->GetType() == INTERACTIVE )
373  return runTool( tool );
374 
375  return false; // there is no tool with the given id
376 }
377 
378 
379 bool TOOL_MANAGER::runTool( const std::string& aToolName )
380 {
381  TOOL_BASE* tool = FindTool( aToolName );
382 
383  if( tool && tool->GetType() == INTERACTIVE )
384  return runTool( tool );
385 
386  return false; // there is no tool with the given name
387 }
388 
389 
391 {
392  wxASSERT( aTool != NULL );
393 
394  if( !isRegistered( aTool ) )
395  {
396  wxASSERT_MSG( false, wxT( "You cannot run unregistered tools" ) );
397  return false;
398  }
399 
400  TOOL_ID id = aTool->GetId();
401 
402  if( aTool->GetType() == INTERACTIVE )
403  static_cast<TOOL_INTERACTIVE*>( aTool )->resetTransitions();
404 
405  // If the tool is already active, bring it to the top of the active tools stack
406  if( isActive( aTool ) && m_activeTools.size() > 1 )
407  {
408  auto it = std::find( m_activeTools.begin(), m_activeTools.end(), id );
409 
410  if( it != m_activeTools.end() )
411  {
412  if( it != m_activeTools.begin() )
413  {
414  m_activeTools.erase( it );
415  m_activeTools.push_front( id );
416  }
417 
418  return false;
419  }
420  }
421 
423  aTool->Reset( TOOL_INTERACTIVE::RUN );
424 
425  // Add the tool on the front of the processing queue (it gets events first)
426  m_activeTools.push_front( id );
427 
428  return true;
429 }
430 
431 
433 {
434  std::map<TOOL_ID, TOOL_STATE*>::const_iterator it = m_toolIdIndex.find( aId );
435 
436  if( it != m_toolIdIndex.end() )
437  return it->second->theTool;
438 
439  return NULL;
440 }
441 
442 
443 TOOL_BASE* TOOL_MANAGER::FindTool( const std::string& aName ) const
444 {
445  std::map<std::string, TOOL_STATE*>::const_iterator it = m_toolNameIndex.find( aName );
446 
447  if( it != m_toolNameIndex.end() )
448  return it->second->theTool;
449 
450  return NULL;
451 }
452 
453 
455 {
456  // Deactivate the active tool, but do not run anything new
458  processEvent( evt );
459 }
460 
461 
463 {
464  DeactivateTool();
465 
466  for( auto& state : m_toolState )
467  {
468  TOOL_BASE* tool = state.first;
469  setActiveState( state.second );
470  tool->Reset( aReason );
471 
472  if( tool->GetType() == INTERACTIVE )
473  static_cast<TOOL_INTERACTIVE*>( tool )->resetTransitions();
474  }
475 }
476 
477 
479 {
480  for( auto it = m_toolState.begin(); it != m_toolState.end(); /* iteration in the loop */ )
481  {
482  TOOL_BASE* tool = it->first;
483  TOOL_STATE* state = it->second;
484  setActiveState( state );
485  ++it; // keep the iterator valid if the element is going to be erased
486 
487  if( !tool->Init() )
488  {
489  wxMessageBox( wxString::Format( "Initialization of tool \"%s\" failed",
490  tool->GetName() ) );
491 
492  // Unregister the tool
493  setActiveState( nullptr );
494  m_toolState.erase( tool );
495  m_toolNameIndex.erase( tool->GetName() );
496  m_toolIdIndex.erase( tool->GetId() );
497  m_toolTypes.erase( typeid( *tool ).name() );
498 
499  delete state;
500  delete tool;
501  }
502  }
503 
504  m_actionMgr->UpdateHotKeys( true );
505 
507 }
508 
509 
510 int TOOL_MANAGER::GetPriority( int aToolId ) const
511 {
512  int priority = 0;
513 
514  for( TOOL_ID tool : m_activeTools )
515  {
516  if( tool == aToolId )
517  return priority;
518 
519  ++priority;
520  }
521 
522  return -1;
523 }
524 
525 
527  const TOOL_EVENT_LIST& aConditions )
528 {
529  TOOL_STATE* st = m_toolState[aTool];
530 
531  st->transitions.emplace_back( TRANSITION( aConditions, aHandler ) );
532 }
533 
534 
536 {
537  m_toolState[aTool]->transitions.clear();
538 }
539 
540 
541 void TOOL_MANAGER::RunMainStack( TOOL_BASE* aTool, std::function<void()> aFunc )
542 {
543  TOOL_STATE* st = m_toolState[aTool];
544  setActiveState( st );
545  st->cofunc->RunMainStack( std::move( aFunc ) );
546 }
547 
548 
550 {
551  TOOL_STATE* st = m_toolState[aTool];
552 
553  wxASSERT( !st->pendingWait ); // everything collapses on two KiYield() in a row
554 
555  // indicate to the manager that we are going to sleep and we shall be
556  // woken up when an event matching aConditions arrive
557  st->pendingWait = true;
558  st->waitEvents = aConditions;
559 
560  // switch context back to event dispatcher loop
561  st->cofunc->KiYield();
562 
563  return &st->wakeupEvent;
564 }
565 
566 
568 {
569  bool handled = false;
570 
571  wxLogTrace( kicadTraceToolStack, "TOOL_MANAGER::dispatchInternal %s", aEvent.Format() );
572 
573  // iterate over active tool stack
574  for( auto it = m_activeTools.begin(); it != m_activeTools.end(); ++it )
575  {
576  TOOL_STATE* st = m_toolIdIndex[*it];
577 
578  // forward context menu events to the tool that created the menu
579  if( aEvent.IsChoiceMenu() )
580  {
581  if( *it != m_menuOwner )
582  continue;
583  }
584 
585  // the tool state handler is waiting for events (i.e. called Wait() method)
586  if( st && st->pendingWait )
587  {
588  if( st->waitEvents.Matches( aEvent ) )
589  {
590  if( !aEvent.FirstResponder() )
591  const_cast<TOOL_EVENT*>( &aEvent )->SetFirstResponder( st->theTool );
592 
593  // got matching event? clear wait list and wake up the coroutine
594  st->wakeupEvent = aEvent;
595  st->pendingWait = false;
596  st->waitEvents.clear();
597 
598  if( st->cofunc )
599  {
600  wxLogTrace( kicadTraceToolStack,
601  "TOOL_MANAGER::dispatchInternal Waking tool %s for event: %s",
602  st->theTool->GetName(), aEvent.Format() );
603 
604  setActiveState( st );
605  bool end = !st->cofunc->Resume();
606 
607  if( end )
608  it = finishTool( st );
609  }
610 
611  // If the tool did not request the event be passed to other tools, we're done
612  if( !st->wakeupEvent.PassEvent() )
613  {
614  wxLogTrace( kicadTraceToolStack,
615  "TOOL_MANAGER::dispatchInternal %s stopped passing event: %s",
616  st->theTool->GetName(), aEvent.Format() );
617 
618  handled = true;
619  break;
620  }
621  }
622  }
623  }
624 
625  for( auto& state : m_toolState )
626  {
627  TOOL_STATE* st = state.second;
628  bool finished = false;
629 
630  // no state handler in progress - check if there are any transitions (defined by
631  // Go() method that match the event.
632  if( !st->transitions.empty() )
633  {
634  for( TRANSITION& tr : st->transitions )
635  {
636  if( tr.first.Matches( aEvent ) )
637  {
638  auto func_copy = tr.second;
639 
640  if( !aEvent.FirstResponder() )
641  const_cast<TOOL_EVENT*>( &aEvent )->SetFirstResponder( st->theTool );
642 
643  // if there is already a context, then push it on the stack
644  // and transfer the previous view control settings to the new context
645  if( st->cofunc )
646  {
647  auto vc = st->vcSettings;
648  st->Push();
649  st->vcSettings = vc;
650  }
651 
652  st->cofunc = new COROUTINE<int, const TOOL_EVENT&>( std::move( func_copy ) );
653 
654  // as the state changes, the transition table has to be set up again
655  st->transitions.clear();
656 
657  wxLogTrace( kicadTraceToolStack,
658  "TOOL_MANAGER::dispatchInternal Running tool %s for event: %s",
659  st->theTool->GetName(), aEvent.Format() );
660 
661  // got match? Run the handler.
662  setActiveState( st );
663  st->idle = false;
664  st->cofunc->Call( aEvent );
665  handled = true;
666 
667  if( !st->cofunc->Running() )
668  finishTool( st ); // The couroutine has finished immediately?
669 
670  // if it is a message, continue processing
671  finished = !( aEvent.Category() == TC_MESSAGE );
672 
673  // there is no point in further checking, as transitions got cleared
674  break;
675  }
676  }
677  }
678 
679  if( finished )
680  break; // only the first tool gets the event
681  }
682 
683  wxLogTrace( kicadTraceToolStack, "TOOL_MANAGER::dispatchInternal handled: %s %s",
684  ( handled ? "true" : "false" ), aEvent.Format() );
685 
686  return handled;
687 }
688 
689 
691 {
692  if( aEvent.Action() == TA_KEY_PRESSED )
693  return m_actionMgr->RunHotKey( aEvent.Modifier() | aEvent.KeyCode() );
694 
695  return false;
696 }
697 
698 
700 {
701  wxLogTrace( kicadTraceToolStack, "TOOL_MANAGER::dispatchActivation %s", aEvent.Format() );
702  if( aEvent.IsActivate() )
703  {
704  wxString cmdStr( *aEvent.GetCommandStr() );
705 
706  auto tool = m_toolNameIndex.find( *aEvent.GetCommandStr() );
707 
708  if( tool != m_toolNameIndex.end() )
709  {
710  wxLogTrace( kicadTraceToolStack,
711  "TOOL_MANAGER::dispatchActivation Running tool %s for event: %s",
712  tool->second->theTool->GetName(), aEvent.Format() );
713 
714  runTool( tool->second->theTool );
715  return true;
716  }
717  }
718 
719  return false;
720 }
721 
723 {
724  for( TOOL_ID toolId : m_activeTools )
725  {
726  TOOL_STATE* st = m_toolIdIndex[toolId];
727 
728  // the tool requested a context menu. The menu is activated on RMB click (CMENU_BUTTON mode)
729  // or immediately (CMENU_NOW) mode. The latter is used for clarification lists.
730  if( st->contextMenuTrigger == CMENU_OFF )
731  continue;
732 
733  if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( BUT_RIGHT ) )
734  break;
735 
736  st->pendingWait = true;
738 
739  // Store the menu pointer in case it is changed by the TOOL when handling menu events
740  ACTION_MENU* m = st->contextMenu;
741 
742  if( st->contextMenuTrigger == CMENU_NOW )
744 
745  // Store the cursor position, so the tools could execute actions
746  // using the point where the user has invoked a context menu
748 
749  // Save all tools cursor settings, as they will be overridden
750  for( auto idState : m_toolIdIndex )
751  {
752  TOOL_STATE* s = idState.second;
753  const auto& vc = s->vcSettings;
754 
755  if( vc.m_forceCursorPosition )
756  m_cursorSettings[idState.first] = vc.m_forcedPosition;
757  else
758  m_cursorSettings[idState.first] = NULLOPT;
759  }
760 
762 
763  // Display a copy of menu
764  std::unique_ptr<ACTION_MENU> menu( m->Clone() );
765 
766  m_menuOwner = toolId;
767  m_menuActive = true;
768 
769  auto frame = dynamic_cast<wxFrame*>( m_frame );
770 
771  if( frame )
772  frame->PopupMenu( menu.get() );
773 
774  // Warp the cursor if a menu item was selected
775  if( menu->GetSelected() >= 0 && m_warpMouseAfterContextMenu )
776  m_viewControls->WarpCursor( m_menuCursor, true, false );
777  // Otherwise notify the tool of a cancelled menu
778  else
779  {
781  evt.SetHasPosition( false );
782  evt.SetParameter( m );
783  dispatchInternal( evt );
784  }
785 
786  // Restore setting in case it was vetoed
788 
789  // Notify the tools that menu has been closed
791  evt.SetHasPosition( false );
792  evt.SetParameter( m );
793  dispatchInternal( evt );
794 
795  m_menuActive = false;
796  m_menuOwner = -1;
797 
798  // Restore cursor settings
799  for( auto cursorSetting : m_cursorSettings )
800  {
801  auto it = m_toolIdIndex.find( cursorSetting.first );
802  wxASSERT( it != m_toolIdIndex.end() );
803 
804  if( it == m_toolIdIndex.end() )
805  continue;
806 
807  KIGFX::VC_SETTINGS& vc = it->second->vcSettings;
808  vc.m_forceCursorPosition = (bool) cursorSetting.second;
809  vc.m_forcedPosition = cursorSetting.second ? *cursorSetting.second : VECTOR2D( 0, 0 );
810  }
811 
812  m_cursorSettings.clear();
813  break;
814  }
815 }
816 
817 
818 TOOL_MANAGER::ID_LIST::iterator TOOL_MANAGER::finishTool( TOOL_STATE* aState )
819 {
820  auto it = std::find( m_activeTools.begin(), m_activeTools.end(), aState->theTool->GetId() );
821 
822  if( !aState->Pop() )
823  {
824  // Deactivate the tool if there are no other contexts saved on the stack
825  if( it != m_activeTools.end() )
826  it = m_activeTools.erase( it );
827 
828  aState->idle = true;
829  }
830 
831  if( aState == m_activeState )
832  setActiveState( nullptr );
833 
834  // Set transitions to be ready for future TOOL_EVENTs
835  TOOL_BASE* tool = aState->theTool;
836 
837  if( tool->GetType() == INTERACTIVE )
838  static_cast<TOOL_INTERACTIVE*>( tool )->resetTransitions();
839 
840  // Don't move the iterator past the stack beginning
841  if( it == m_activeTools.begin() )
842  return it;
843 
844  return --it;
845 }
846 
847 
849 {
850  bool handled = processEvent( aEvent );
851 
852  TOOL_STATE* activeTool = GetCurrentToolState();
853 
854  if( activeTool )
855  setActiveState( activeTool );
856 
857  if( m_view && m_view->IsDirty() )
858  {
860 
861 #if defined( __WXMAC__ ) || defined( __WINDOWS__ )
862  wxTheApp->ProcessPendingEvents(); // required for updating brightening behind a popup menu
863 #endif
864  }
865 
866  UpdateUI( aEvent );
867 
868  return handled;
869 }
870 
871 
873  CONTEXT_MENU_TRIGGER aTrigger )
874 {
875  TOOL_STATE* st = m_toolState[aTool];
876 
877  st->contextMenu = aMenu;
878  st->contextMenuTrigger = aTrigger;
879 }
880 
881 
882 bool TOOL_MANAGER::SaveClipboard( const std::string& aText )
883 {
884  if( wxTheClipboard->Open() )
885  {
886  wxTheClipboard->SetData( new wxTextDataObject( wxString( aText.c_str(), wxConvUTF8 ) ) );
887  wxTheClipboard->Close();
888 
889  return true;
890  }
891 
892  return false;
893 }
894 
895 
896 std::string TOOL_MANAGER::GetClipboard() const
897 {
898  std::string result;
899 
900  if( wxTheClipboard->Open() )
901  {
902  if( wxTheClipboard->IsSupported( wxDF_TEXT ) )
903  {
904  wxTextDataObject data;
905  wxTheClipboard->GetData( data );
906 
907  result = data.GetText().mb_str();
908  }
909 
910  wxTheClipboard->Close();
911  }
912 
913  return result;
914 }
915 
916 
918 {
919  if( TOOL_STATE* active = GetCurrentToolState() )
920  return active->vcSettings;
921 
922  return m_viewControls->GetSettings();
923 }
924 
925 
926 TOOL_ID TOOL_MANAGER::MakeToolId( const std::string& aToolName )
927 {
928  static int currentId;
929 
930  return currentId++;
931 }
932 
933 
935  KIGFX::VIEW_CONTROLS* aViewControls, EDA_BASE_FRAME* aFrame )
936 {
937  m_model = aModel;
938  m_view = aView;
939  m_viewControls = aViewControls;
940  m_frame = aFrame;
941 }
942 
943 
945 {
946  if( !isRegistered( aTool ) )
947  return false;
948 
949  // Just check if the tool is on the active tools stack
950  return std::find( m_activeTools.begin(), m_activeTools.end(), aTool->GetId() ) != m_activeTools.end();
951 }
952 
953 
955 {
957 
958  if( m_menuActive )
959  {
960  // Context menu is active, so the cursor settings are overridden (see DispatchContextMenu())
961  auto it = m_cursorSettings.find( aState->theTool->GetId() );
962 
963  if( it != m_cursorSettings.end() )
964  {
966 
967  // Tool has overridden the cursor position, so store the new settings
969  {
970  if( !curr.m_forceCursorPosition )
971  it->second = NULLOPT;
972  else
973  it->second = curr.m_forcedPosition;
974  }
975  else
976  {
977  OPT<VECTOR2D> cursor = it->second;
978 
979  if( cursor )
980  {
981  aState->vcSettings.m_forceCursorPosition = true;
982  aState->vcSettings.m_forcedPosition = *cursor;
983  }
984  else
985  {
986  aState->vcSettings.m_forceCursorPosition = false;
987  }
988  }
989  }
990  }
991 }
992 
993 
995 {
997 }
998 
999 
1001 {
1002  wxLogTrace( kicadTraceToolStack, "TOOL_MANAGER::processEvent %s", aEvent.Format() );
1003 
1004  // First try to dispatch the action associated with the event if it is a key press event
1005  bool handled = dispatchHotKey( aEvent );
1006 
1007  if( !handled )
1008  {
1009  // If the event is not handled through a hotkey activation, pass it to the currently
1010  // running tool loops
1011  handled |= dispatchInternal( aEvent );
1012  handled |= dispatchActivation( aEvent );
1013 
1014  // Open the context menu if requested by a tool
1015  DispatchContextMenu( aEvent );
1016 
1017  // Dispatch any remaining events in the event queue
1018  while( !m_eventQueue.empty() )
1019  {
1020  TOOL_EVENT event = m_eventQueue.front();
1021  m_eventQueue.pop_front();
1022  processEvent( event );
1023  }
1024  }
1025 
1026  wxLogTrace( kicadTraceToolStack, "TOOL_MANAGER::processEvent handled: %s %s",
1027  ( handled ? "true" : "false" ), aEvent.Format() );
1028 
1029  return handled;
1030 }
1031 
1032 
1034 {
1035  if( m_activeState && m_viewControls )
1037 
1038  m_activeState = aState;
1039 
1040  if( m_activeState && m_viewControls )
1041  applyViewControls( aState );
1042 }
1043 
1044 
1046 {
1047  auto it = m_toolIdIndex.find( aId );
1048  return !it->second->idle;
1049 }
1050 
1051 
1052 void TOOL_MANAGER::UpdateUI( const TOOL_EVENT& aEvent )
1053 {
1054  EDA_BASE_FRAME* frame = GetEditFrame();
1055 
1056  if( frame )
1057  {
1058  frame->UpdateStatusBar();
1059 
1060  if( !aEvent.IsMotion() && !aEvent.IsDrag() )
1061  frame->SyncToolbars();
1062  }
1063 }
void RunMainStack(std::function< void()> func)
Function RunMainStack()
Definition: coroutine.h:204
bool m_menuActive
Flag indicating whether a context menu is currently displayed.
Definition: tool_manager.h:548
void DispatchContextMenu(const TOOL_EVENT &aEvent)
Function DispatchContextMenu() Handles context menu related events.
TOOL_TYPE GetType() const
Function GetType() Returns the type of the tool.
Definition: tool_base.h:110
VECTOR2D GetCursorPosition()
VECTOR2D m_menuCursor
Right click context menu position.
Definition: tool_manager.h:543
void UpdateUI(const TOOL_EVENT &aEvent)
Updates the status bar and synchronizes toolbars.
virtual bool Init()
Function Init() Init() is called once upon a registration of the tool.
Definition: tool_base.h:92
void Reset()
Restores the default settings
TOOL_STATE(TOOL_BASE *aTool)
TOOL_STATE & operator=(const TOOL_STATE &aState)
int GetHotKey(const TOOL_ACTION &aAction)
const std::string Format() const
Function Format() Returns information about event in form of a human-readable string.
Definition: tool_event.cpp:73
TOOL_BASE * theTool
The tool itself.
ACTION_MANAGER * m_actionMgr
Instance of ACTION_MANAGER that handles TOOL_ACTIONs.
Definition: tool_manager.h:529
EDA_BASE_FRAME * GetEditFrame() const
Definition: tool_manager.h:268
bool processEvent(const TOOL_EVENT &aEvent)
Main function for event processing.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Function GetMousePosition() Returns the current mouse pointer position.
static TOOL_ID MakeToolId(const std::string &aToolName)
Generates a unique ID from for a tool with given name.
int GetPriority(int aToolId) const
Returns priority of a given tool.
std::vector< TRANSITION > transitions
List of possible transitions (ie.
Class ACTION_MENU.
Definition: action_menu.h:43
ID_STATE_MAP m_toolIdIndex
Index of the registered tools current states, associated by tools' ID numbers.
Definition: tool_manager.h:520
void ScheduleNextState(TOOL_BASE *aTool, TOOL_STATE_FUNC &aHandler, const TOOL_EVENT_LIST &aConditions)
Defines a state transition - the events that cause a given handler method in the tool to be called.
OPT< const TOOL_EVENT & > Matches(const TOOL_EVENT &aEvent) const
Definition: tool_event.h:589
bool SaveClipboard(const std::string &aText)
Stores an information to the system clipboard.
bool Call(ArgType aArg)
Function Call()
Definition: coroutine.h:218
TOOL_ACTIONS Action() const
Returns more specific information about the type of an event.
Definition: tool_event.h:250
void ApplySettings(const VC_SETTINGS &aSettings)
Applies VIEW_CONTROLS settings from an object
KIGFX::VC_SETTINGS vcSettings
VIEW_CONTROLS settings to preserve settings when the tools are switched.
TOOL_ID GetId() const
Function GetId() Returns the unique identifier of the tool.
Definition: tool_base.h:121
bool IsClick(int aButtonMask=BUT_ANY) const
Definition: tool_event.cpp:178
std::map< TOOL_ID, OPT< VECTOR2D > > m_cursorSettings
Original cursor position, if overridden by the context menu handler.
Definition: tool_manager.h:532
Tool is invoked after being inactive.
Definition: tool_base.h:81
ID_LIST::iterator finishTool(TOOL_STATE *aState)
Function finishTool() Deactivates a tool and does the necessary clean up.
bool dispatchActivation(const TOOL_EVENT &aEvent)
Function dispatchActivation() Checks if it is a valid activation event and invokes a proper tool.
bool IsMotion() const
Definition: tool_event.h:306
VECTOR2D m_forcedPosition
Forced cursor position (world coordinates)
Definition: view_controls.h:58
ACTION_MENU * contextMenu
Context menu currently used by the tool.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:109
bool operator==(const TOOL_MANAGER::TOOL_STATE &aRhs) const
void PrimeTool(const VECTOR2D &aPosition)
Function PrimeTool() "Primes" a tool by sending a cursor left-click event with the mouse position set...
void UpdateHotKeys(bool aFullUpdate)
Function UpdateHotKeys() Optionally reads the hotkey config files and then rebuilds the internal hotk...
TOOL_EVENT_CATEGORY Category() const
Returns the category (eg. mouse/keyboard/action) of an event..
Definition: tool_event.h:247
void attachManager(TOOL_MANAGER *aManager)
Function attachManager()
Definition: tool_base.cpp:60
Class ACTION_MANAGER.
TOOL_BASE * FindTool(int aId) const
Function FindTool() Searches for a tool with given ID.
TOOL_EVENT * ScheduleWait(TOOL_BASE *aTool, const TOOL_EVENT_LIST &aConditions)
Pauses execution of a given tool until one or more events matching aConditions arrives.
void applyViewControls(TOOL_STATE *aState)
Function applyViewControls() Applies VIEW_CONTROLS settings stored in a TOOL_STATE object.
void Push()
Function Push() Stores the current state of the tool on stack.
void SetMousePosition(const VECTOR2D &aP)
Definition: tool_event.h:468
bool runTool(TOOL_ID aToolId)
Function runTool() Makes a tool active, so it can receive events and react to them.
void DeactivateTool()
Function DeactivateTool() Deactivates the currently active tool.
bool InvokeTool(TOOL_ID aToolId)
Function InvokeTool() Calls a tool by sending a tool activation event to tool of given ID.
virtual void SyncToolbars()
Update the toolbars (mostly settings/check buttons/checkboxes) with the current controller state.
const std::map< std::string, TOOL_ACTION * > & GetActions()
Get a list of currently-registered actions mapped by their name.
TOOL_ACTION * FindAction(const std::string &aActionName) const
Function FindAction() Finds an action with a given name (if there is one available).
const VC_SETTINGS & GetSettings() const
Returns the current VIEW_CONTROLS settings
EDA_BASE_FRAME * m_frame
Definition: tool_manager.h:537
virtual void UpdateStatusBar()
Update the status bar information.
bool RunHotKey(int aHotKey) const
Function RunHotKey() Runs an action associated with a hotkey (if there is one available).
EDA_ITEM * m_model
Definition: tool_manager.h:534
bool pendingWait
Flag defining if the tool is waiting for any event (i.e.
void SetParameter(T aParam)
Function SetParameter() Sets a non-standard parameter assigned to the event.
Definition: tool_event.h:453
virtual void Reset(RESET_REASON aReason)=0
Function Reset() Brings the tool to a known, initial state.
bool pendingContextMenu
Is there a context menu being displayed.
NAME_STATE_MAP m_toolNameIndex
Index of the registered tools current states, associated by tools' names.
Definition: tool_manager.h:517
int TOOL_ID
Unique identifier for tools.
Definition: tool_base.h:56
virtual void WarpCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
Function WarpCursor() If enabled (.
Class TOOL_EVENT_LIST.
Definition: tool_event.h:564
Tool that interacts with the user
Definition: tool_base.h:49
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:296
const auto NULLOPT
Definition: optional.h:9
bool m_forceCursorPosition
Is the forced cursor position enabled
Definition: view_controls.h:61
TOOL_ID m_menuOwner
Tool currently displaying a popup menu. It is negative when there is no menu displayed.
Definition: tool_manager.h:551
const std::map< std::string, TOOL_ACTION * > & GetActions()
bool dispatchHotKey(const TOOL_EVENT &aEvent)
Function dispatchStandardEvents() Handles specific events, that are intended for TOOL_MANAGER rather ...
void setActiveState(TOOL_STATE *aState)
Saves the previous active state and sets a new one.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagates an event to tools that requested events of matching type(s).
CONTEXT_MENU_TRIGGER
Defines when a context menu is opened.
Definition: tool_event.h:159
int GetHotKey(const TOOL_ACTION &aAction) const
Function GetHotKey() Returns the hot key associated with a given action or 0 if there is none.
Class TOOL_EVENT.
Definition: tool_event.h:171
bool idle
Is the tool active (pending execution) or disabled at the moment.
std::stack< std::unique_ptr< TOOL_STATE > > stateStack
Stack preserving previous states of a TOOL.
bool operator!=(const TOOL_MANAGER::TOOL_STATE &aRhs) const
const KIGFX::VC_SETTINGS & GetCurrentToolVC() const
Returns the view controls settings for the current tool or the general settings if there is no active...
Base window classes and related definitions.
Structure to keep VIEW_CONTROLS settings for easy store/restore operations
Definition: view_controls.h:44
void ResetTools(TOOL_BASE::RESET_REASON aReason)
Function ResetTools() Resets all tools (i.e.
Class VIEW_CONTROLS is an interface for classes handling user events controlling the view behaviour (...
wxLogTrace helper definitions.
ACTION_MENU * Clone() const
Creates a deep, recursive copy of this ACTION_MENU.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Function ForceCursorPosition() Places the cursor immediately at a given point.
Struct describing the current execution state of a TOOL.
KIGFX::VIEW_CONTROLS * m_viewControls
Definition: tool_manager.h:536
bool Resume()
Function Resume()
Definition: coroutine.h:252
std::function< int(const TOOL_EVENT &)> TOOL_STATE_FUNC
Definition: tool_base.h:58
TOOL_STATE * GetCurrentToolState() const
Returns the TOOL_STATE object representing the state of the active tool.
Definition: tool_manager.h:297
bool isActive(TOOL_BASE *aTool)
Function isActive() Returns information about a tool activation status.
KIGFX::VIEW * m_view
Definition: tool_manager.h:535
void RunMainStack(TOOL_BASE *aTool, std::function< void()> aFunc)
TOOL_EVENT wakeupEvent
The event that triggered the execution/wakeup of the tool after Wait() call.
int Modifier(int aMask=MD_MODIFIER_MASK) const
Returns information about key modifiers state (Ctrl, Alt, etc.)
Definition: tool_event.h:342
bool m_warpMouseAfterContextMenu
Definition: tool_manager.h:545
bool isRegistered(TOOL_BASE *aTool) const
Function isRegistered() Returns information about a tool registration status.
Definition: tool_manager.h:475
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:463
bool IsActivate() const
Definition: tool_event.h:321
std::list< TOOL_EVENT > m_eventQueue
Queue that stores events to be processed at the end of the event processing cycle.
Definition: tool_manager.h:540
bool PassEvent() const
These give a tool a method of informing the TOOL_MANAGER that a particular event should be passed on ...
Definition: tool_event.h:255
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
bool Pop()
Function Pop() Restores state of the tool from stack.
TOOL_STATE * m_activeState
Pointer to the state object corresponding to the currently executed tool.
Definition: tool_manager.h:554
COROUTINE< int, const TOOL_EVENT & > * cofunc
Tool execution context.
Class TOOL_BASE.
Definition: tool_base.h:67
The base frame for deriving all KiCad main window classes.
Class TOOL_ACTION.
Definition: tool_action.h:46
std::string GetClipboard() const
Returns the information currently stored in the system clipboard.
bool IsChoiceMenu() const
Definition: tool_event.h:331
TOOL_EVENT MakeEvent() const
Function MakeEvent() Returns the event associated with the action (i.e.
Definition: tool_action.h:107
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:163
void SetEnvironment(EDA_ITEM *aModel, KIGFX::VIEW *aView, KIGFX::VIEW_CONTROLS *aViewControls, EDA_BASE_FRAME *aFrame)
Sets the work environment (model, view, view controls and the parent window).
RESET_REASON
Determines the reason of reset for a tool
Definition: tool_base.h:79
const wxChar *const kicadTraceToolStack
Flag to enable tracing of the tool handling stack.
boost::optional< T > OPT
Definition: optional.h:7
bool Running() const
Function Running()
Definition: coroutine.h:293
CONTEXT_MENU_TRIGGER contextMenuTrigger
Defines when the context menu is opened.
TOOL_BASE * FirstResponder() const
Definition: tool_event.h:263
void InitTools()
Function InitTools() Initializes all registered tools.
VECTOR2D GetMousePosition()
bool IsToolActive(TOOL_ID aId) const
Function IsToolActive() Returns true if a tool with given id is active (executing)
const std::string & GetName() const
Function GetName() Returns the name of the tool.
Definition: tool_base.h:132
Class VIEW.
Definition: view.h:61
void ClearTransitions(TOOL_BASE *aTool)
Clears the state transition map for a tool.
int KeyCode() const
Definition: tool_event.h:347
ID_LIST m_activeTools
Stack of the active tools.
Definition: tool_manager.h:526
TOOL_EVENT_LIST waitEvents
List of events the tool is currently waiting for.
void clear()
Restores the initial state.
void PostEvent(const TOOL_EVENT &aEvent)
Puts an event to the event queue to be processed at the end of event processing cycle.
Definition: tool_manager.h:237
TOOL_STATE_MAP m_toolState
Index of registered tools current states, associated by tools' objects.
Definition: tool_manager.h:514
void ScheduleContextMenu(TOOL_BASE *aTool, ACTION_MENU *aMenu, CONTEXT_MENU_TRIGGER aTrigger)
Sets behaviour of the tool's context popup menu.
TOOL_STATE(const TOOL_STATE &aState)
void saveViewControls(TOOL_STATE *aState)
Function saveViewControls() Saves the VIEW_CONTROLS settings to the tool state object.
bool invokeTool(TOOL_BASE *aTool)
Function invokeTool() Invokes a tool by sending a proper event (in contrary to runTool,...
bool IsDirty() const
Function IsDirty() Returns true if any of the VIEW layers needs to be refreshened.
Definition: view.h:557
void SetHasPosition(bool aHasPosition)
Definition: tool_event.h:261
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
void RegisterTool(TOOL_BASE *aTool)
Function RegisterTool() Adds a tool to the manager set and sets it up.
bool dispatchInternal(const TOOL_EVENT &aEvent)
Function dispatchInternal Passes an event at first to the active tools, then to all others.
void KiYield()
Function KiYield()
Definition: coroutine.h:169
std::pair< TOOL_EVENT_LIST, TOOL_STATE_FUNC > TRANSITION
Definition: tool_manager.h:396
virtual void RefreshCanvas()
Notification to refresh the drawing canvas (if any).
std::map< const char *, TOOL_BASE * > m_toolTypes
Index of the registered tools to easily lookup by their type.
Definition: tool_manager.h:523