KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2023 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Tomasz Wlostowski <[email protected]>
7 * @author Maciej Suminski <[email protected]>
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 <core/kicad_algo.h>
28#include <optional>
29#include <map>
30#include <stack>
31#include <trace_helpers.h>
32#include <kiplatform/ui.h>
33#include <app_monitor.h>
34
35#include <wx/event.h>
36#include <wx/clipbrd.h>
37#include <wx/app.h>
38
39#include <math/vector2wx.h>
40
41#include <view/view.h>
42#include <view/view_controls.h>
43#include <eda_base_frame.h>
44#include <tool/tool_base.h>
46#include <tool/tool_manager.h>
47#include <tool/action_menu.h>
48#include <tool/coroutine.h>
49#include <tool/action_manager.h>
50
52
55{
57 theTool( aTool )
58 {
59 clear();
60 }
61
62 TOOL_STATE( const TOOL_STATE& aState )
63 {
64 theTool = aState.theTool;
65 idle = aState.idle;
66 shutdown = aState.shutdown;
67 pendingWait = aState.pendingWait;
69 contextMenu = aState.contextMenu;
71 cofunc = aState.cofunc;
73 wakeupEvent = aState.wakeupEvent;
74 waitEvents = aState.waitEvents;
75 transitions = aState.transitions;
76 vcSettings = aState.vcSettings;
77 // do not copy stateStack
78 }
79
81 {
82 if( !stateStack.empty() )
83 wxFAIL;
84 }
85
88
90 bool idle;
91
94
98
101
104
107
110
113
116
119
122 std::vector<TRANSITION> transitions;
123
126
128 {
129 theTool = aState.theTool;
130 idle = aState.idle;
131 shutdown = aState.shutdown;
132 pendingWait = aState.pendingWait;
134 contextMenu = aState.contextMenu;
136 cofunc = aState.cofunc;
137 initialEvent = aState.initialEvent;
138 wakeupEvent = aState.wakeupEvent;
139 waitEvents = aState.waitEvents;
140 transitions = aState.transitions;
141 vcSettings = aState.vcSettings;
142
143 // do not copy stateStack
144 return *this;
145 }
146
147 bool operator==( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
148 {
149 return aRhs.theTool == theTool;
150 }
151
152 bool operator!=( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
153 {
154 return aRhs.theTool != theTool;
155 }
156
161 void Push()
162 {
163 auto state = std::make_unique<TOOL_STATE>( *this );
164 stateStack.push( std::move( state ) );
165 clear();
166 }
167
174 bool Pop()
175 {
176 delete cofunc;
177
178 if( !stateStack.empty() )
179 {
180 *this = *stateStack.top().get();
181 stateStack.pop();
182 return true;
183 }
184 else
185 {
186 cofunc = nullptr;
187 return false;
188 }
189 }
190
191private:
193 std::stack<std::unique_ptr<TOOL_STATE>> stateStack;
194
196 void clear()
197 {
198 idle = true;
199 shutdown = false;
200 pendingWait = false;
201 pendingContextMenu = false;
202 cofunc = nullptr;
203 contextMenu = nullptr;
206 transitions.clear();
207 }
208};
209
210
212 m_model( nullptr ),
213 m_view( nullptr ),
214 m_viewControls( nullptr ),
215 m_frame( nullptr ),
216 m_settings( nullptr ),
217 m_warpMouseAfterContextMenu( true ),
218 m_menuActive( false ),
219 m_menuOwner( -1 ),
220 m_activeState( nullptr ),
221 m_shuttingDown( false )
222{
223 m_actionMgr = new ACTION_MANAGER( this );
224}
225
226
228{
229 std::map<TOOL_BASE*, TOOL_STATE*>::iterator it, it_end;
230
231 for( it = m_toolState.begin(), it_end = m_toolState.end(); it != it_end; ++it )
232 {
233 delete it->second->cofunc; // delete cofunction
234 delete it->second; // delete TOOL_STATE
235 delete it->first; // delete the tool itself
236 }
237
238 delete m_actionMgr;
239}
240
241
243{
244 wxASSERT_MSG( m_toolNameIndex.find( aTool->GetName() ) == m_toolNameIndex.end(),
245 wxT( "Adding two tools with the same name may result in unexpected behavior.") );
246 wxASSERT_MSG( m_toolIdIndex.find( aTool->GetId() ) == m_toolIdIndex.end(),
247 wxT( "Adding two tools with the same ID may result in unexpected behavior.") );
248 wxASSERT_MSG( m_toolTypes.find( typeid( *aTool ).name() ) == m_toolTypes.end(),
249 wxT( "Adding two tools of the same type may result in unexpected behavior.") );
250
251 wxLogTrace( kicadTraceToolStack,
252 wxS( "TOOL_MANAGER::RegisterTool: Registering tool %s with ID %d" ),
253 aTool->GetName(), aTool->GetId() );
254
255 m_toolOrder.push_back( aTool );
256
257 TOOL_STATE* st = new TOOL_STATE( aTool );
258
259 m_toolState[aTool] = st;
260 m_toolNameIndex[aTool->GetName()] = st;
261 m_toolIdIndex[aTool->GetId()] = st;
262 m_toolTypes[typeid( *aTool ).name()] = st->theTool;
263
264 aTool->attachManager( this );
265}
266
267
269{
270 TOOL_BASE* tool = FindTool( aToolId );
271
272 if( tool && tool->GetType() == INTERACTIVE )
273 return invokeTool( tool );
274
275 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::InvokeTool - no tool with ID %d" ),
276 aToolId );
277
278 return false; // there is no tool with the given id
279}
280
281
282bool TOOL_MANAGER::InvokeTool( const std::string& aToolName )
283{
284 TOOL_BASE* tool = FindTool( aToolName );
285
286 if( tool && tool->GetType() == INTERACTIVE )
287 return invokeTool( tool );
288
289 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::InvokeTool - no tool with name %s" ),
290 aToolName );
291
292 return false; // there is no tool with the given name
293}
294
295
296bool TOOL_MANAGER::doRunAction( const std::string& aActionName, bool aNow, const ki::any& aParam,
297 COMMIT* aCommit )
298{
299 TOOL_ACTION* action = m_actionMgr->FindAction( aActionName );
300
301 if( !action )
302 {
303 wxASSERT_MSG( false, wxString::Format( "Could not find action %s.", aActionName ) );
304 return false;
305 }
306
307 doRunAction( *action, aNow, aParam, aCommit );
308
309 return true;
310}
311
312
314{
315 if( m_viewControls )
317 else
319}
320
321
323{
324 if( m_viewControls )
326 else
328}
329
330
331bool TOOL_MANAGER::doRunAction( const TOOL_ACTION& aAction, bool aNow, const ki::any& aParam,
332 COMMIT* aCommit, bool aFromAPI )
333{
334 if( m_shuttingDown )
335 return true;
336
337 bool retVal = false;
338 TOOL_EVENT event = aAction.MakeEvent();
339
340 if( event.Category() == TC_COMMAND )
342
343 // Allow to override the action parameter
344 if( aParam.has_value() )
345 event.SetParameter( aParam );
346
347 if( aNow )
348 {
349 TOOL_STATE* current = m_activeState;
350
351 // An event with a commit must be run synchronously
352 if( aCommit )
353 {
354 // We initialize the SYNCHRONOUS state to finished so that tools that don't have an
355 // event loop won't hang if someone forgets to set the state.
356 std::atomic<SYNCRONOUS_TOOL_STATE> synchronousControl = STS_FINISHED;
357
358 event.SetSynchronous( &synchronousControl );
359 event.SetCommit( aCommit );
360
361 processEvent( event );
362
363 while( synchronousControl == STS_RUNNING )
364 {
365 wxYield(); // Needed to honor mouse (and other) events during editing
366 wxMilliSleep( 1 ); // Needed to avoid 100% use of one cpu core.
367 // The sleeping time must be must be small to avoid
368 // noticeable lag in mouse and editing events
369 // (1 to 5 ms is a good value)
370 }
371
372 retVal = synchronousControl != STS_CANCELLED;
373 }
374 else
375 {
376 retVal = processEvent( event );
377 }
378
379 setActiveState( current );
380 UpdateUI( event );
381 }
382 else
383 {
384 // It is really dangerous to pass a commit (whose lifetime we can't guarantee) to
385 // deferred event processing. There is a possibility that user actions will get run
386 // in between, which might either affect the lifetime of the commit or push or pop
387 // other commits. However, we don't currently have a better solution for the API.
388 if( aCommit )
389 {
390 wxASSERT_MSG( aFromAPI, wxT( "Deferred actions have no way of guaranteeing the "
391 "lifetime of the COMMIT object" ) );
392 event.SetCommit( aCommit );
393 }
394
395 PostEvent( event );
396 }
397
398 return retVal;
399}
400
401
403{
405
406 processEvent( evt );
407}
408
409
410void TOOL_MANAGER::PrimeTool( const VECTOR2D& aPosition )
411{
412 int modifiers = 0;
413
414 /*
415 * Don't include any modifiers. They're part of the hotkey, not part of the resulting
416 * click.
417 *
418 * modifiers |= wxGetKeyState( WXK_SHIFT ) ? MD_SHIFT : 0;
419 * modifiers |= wxGetKeyState( WXK_CONTROL ) ? MD_CTRL : 0;
420 * modifiers |= wxGetKeyState( WXK_ALT ) ? MD_ALT : 0;
421 */
422
423 TOOL_EVENT evt( TC_MOUSE, TA_PRIME, BUT_LEFT | modifiers );
424 evt.SetMousePosition( aPosition );
425
426 PostEvent( evt );
427}
428
429
431{
432 // Horrific hack, but it's a crash bug. Don't let inter-frame commands stack up
433 // waiting to be processed.
434 if( aEvent.IsSimulator() && m_eventQueue.size() > 0 && m_eventQueue.back().IsSimulator() )
435 m_eventQueue.pop_back();
436
437 m_eventQueue.push_back( aEvent );
438}
439
440
441int TOOL_MANAGER::GetHotKey( const TOOL_ACTION& aAction ) const
442{
443 return m_actionMgr->GetHotKey( aAction );
444}
445
446
448{
449 wxASSERT( aTool != nullptr );
450
451 TOOL_EVENT evt( TC_COMMAND, TA_ACTIVATE, aTool->GetName() );
453 processEvent( evt );
454
455 if( TOOL_STATE* active = GetCurrentToolState() )
456 setActiveState( active );
457
458 return true;
459}
460
461
463{
464 wxASSERT( aTool != nullptr );
465
466 wxString msg = wxString::Format( wxS( "TOOL_MANAGER::runTool - running tool %s" ), aTool->GetName() );
467 APP_MONITOR::AddTransactionBreadcrumb( msg, "tool.run" );
468
469 if( !isRegistered( aTool ) )
470 {
471 wxASSERT_MSG( false, wxT( "You cannot run unregistered tools" ) );
472 return false;
473 }
474
475 TOOL_ID id = aTool->GetId();
476
477 wxLogTrace( kicadTraceToolStack, msg,
478 aTool->GetName() );
479
480 if( aTool->GetType() == INTERACTIVE )
481 static_cast<TOOL_INTERACTIVE*>( aTool )->resetTransitions();
482
483 // If the tool is already active, bring it to the top of the active tools stack
484 if( isActive( aTool ) && m_activeTools.size() > 1 )
485 {
486 auto it = std::find( m_activeTools.begin(), m_activeTools.end(), id );
487
488 if( it != m_activeTools.end() )
489 {
490 if( it != m_activeTools.begin() )
491 {
492 m_activeTools.erase( it );
493 m_activeTools.push_front( id );
494 }
495
496 return false;
497 }
498 }
499
502
503 // Add the tool on the front of the processing queue (it gets events first)
504 m_activeTools.push_front( id );
505
506 return true;
507}
508
509
511{
512 m_shuttingDown = true;
513
514 // Create a temporary list of tools to iterate over since when the tools shutdown
515 // they remove themselves from the list automatically (invalidating the iterator)
516 ID_LIST tmpList = m_activeTools;
517
518 // Make sure each tool knows that it is shutting down, so that loops get shut down
519 // at the dispatcher
520 for( auto id : tmpList )
521 {
522 if( m_toolIdIndex.count( id ) == 0 )
523 continue;
524
525 m_toolIdIndex[id]->shutdown = true;
526 }
527
528 for( auto id : tmpList )
529 {
530 ShutdownTool( id );
531 }
532}
533
534
536{
537 TOOL_BASE* tool = FindTool( aToolId );
538
539 if( tool && tool->GetType() == INTERACTIVE )
540 ShutdownTool( tool );
541
542 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::ShutdownTool - no tool with ID %d" ),
543 aToolId );
544}
545
546
547void TOOL_MANAGER::ShutdownTool( const std::string& aToolName )
548{
549 TOOL_BASE* tool = FindTool( aToolName );
550
551 if( tool && tool->GetType() == INTERACTIVE )
552 ShutdownTool( tool );
553
554 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::ShutdownTool - no tool with name %s" ),
555 aToolName );
556}
557
558
560{
561 wxASSERT( aTool != nullptr );
562
563 TOOL_ID id = aTool->GetId();
564
565 if( isActive( aTool ) )
566 {
567 TOOL_MANAGER::ID_LIST::iterator it = std::find( m_activeTools.begin(),
568 m_activeTools.end(), id );
569
570 TOOL_STATE* st = m_toolIdIndex[*it];
571
572 // the tool state handler is waiting for events (i.e. called Wait() method)
573 if( st && st->pendingWait )
574 {
575 // Wake up the tool and tell it to shutdown
576 st->shutdown = true;
577 st->pendingWait = false;
578 st->waitEvents.clear();
579
580 if( st->cofunc )
581 {
582 wxLogTrace( kicadTraceToolStack,
583 wxS( "TOOL_MANAGER::ShutdownTool - Shutting down tool %s" ),
584 st->theTool->GetName() );
585
586 setActiveState( st );
587 bool end = !st->cofunc->Resume();
588
589 if( end )
590 finishTool( st );
591 }
592 }
593 }
594}
595
596
598{
599 std::map<TOOL_ID, TOOL_STATE*>::const_iterator it = m_toolIdIndex.find( aId );
600
601 if( it != m_toolIdIndex.end() )
602 return it->second->theTool;
603
604 return nullptr;
605}
606
607
608TOOL_BASE* TOOL_MANAGER::FindTool( const std::string& aName ) const
609{
610 std::map<std::string, TOOL_STATE*>::const_iterator it = m_toolNameIndex.find( aName );
611
612 if( it != m_toolNameIndex.end() )
613 return it->second->theTool;
614
615 return nullptr;
616}
617
618
620{
621 // Deactivate the active tool, but do not run anything new
623 processEvent( evt );
624}
625
626
628{
629 if( aReason != TOOL_BASE::REDRAW )
631
632 for( auto& state : m_toolState )
633 {
634 TOOL_BASE* tool = state.first;
635
636 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::ResetTools: Resetting tool '%s'" ),
637 tool->GetName() );
638
639 setActiveState( state.second );
640 tool->Reset( aReason );
641
642 if( tool->GetType() == INTERACTIVE )
643 static_cast<TOOL_INTERACTIVE*>( tool )->resetTransitions();
644 }
645}
646
647
649{
650 for( auto it = m_toolOrder.begin(); it != m_toolOrder.end(); /* iter inside */ )
651 {
652 TOOL_BASE* tool = *it;
653 wxASSERT( m_toolState.count( tool ) );
654 TOOL_STATE* state = m_toolState[tool];
655 setActiveState( state );
656 ++it; // keep the iterator valid if the element is going to be erased
657
658 if( !tool->Init() )
659 {
660 wxLogTrace( kicadTraceToolStack,
661 wxS( "TOOL_MANAGER initialization of tool '%s' failed" ),
662 tool->GetName() );
663
664 // Unregister the tool
665 setActiveState( nullptr );
666 m_toolState.erase( tool );
667 m_toolNameIndex.erase( tool->GetName() );
668 m_toolIdIndex.erase( tool->GetId() );
669 m_toolTypes.erase( typeid( *tool ).name() );
670
671 delete state;
672 delete tool;
673 }
674 }
675
676 m_actionMgr->UpdateHotKeys( true );
677
679}
680
681
682int TOOL_MANAGER::GetPriority( int aToolId ) const
683{
684 int priority = 0;
685
686 for( TOOL_ID tool : m_activeTools )
687 {
688 if( tool == aToolId )
689 return priority;
690
691 ++priority;
692 }
693
694 return -1;
695}
696
697
699 const TOOL_EVENT_LIST& aConditions )
700{
701 TOOL_STATE* st = m_toolState[aTool];
702
703 st->transitions.emplace_back( TRANSITION( aConditions, aHandler ) );
704}
705
706
708{
709 m_toolState[aTool]->transitions.clear();
710}
711
712
713void TOOL_MANAGER::RunMainStack( TOOL_BASE* aTool, std::function<void()> aFunc )
714{
715 TOOL_STATE* st = m_toolState[aTool];
716 setActiveState( st );
717 wxCHECK( st->cofunc, /* void */ );
718 st->cofunc->RunMainStack( std::move( aFunc ) );
719}
720
721
723{
724 TOOL_STATE* st = m_toolState[aTool];
725
726 wxCHECK( !st->pendingWait, nullptr ); // everything collapses on two KiYield() in a row
727
728 // indicate to the manager that we are going to sleep and we shall be
729 // woken up when an event matching aConditions arrive
730 st->pendingWait = true;
731 st->waitEvents = aConditions;
732
733 wxCHECK( st->cofunc, nullptr );
734
735 // switch context back to event dispatcher loop
736 st->cofunc->KiYield();
737
738 // If the tool should shutdown, it gets a null event to break the loop
739 if( st->shutdown )
740 return nullptr;
741 else
742 return &st->wakeupEvent;
743}
744
745
747{
748 bool handled = false;
749
750 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::dispatchInternal - received event: %s" ),
751 aEvent.Format() );
752
753 auto it = m_activeTools.begin();
754
755 // iterate over active tool stack
756 while( it != m_activeTools.end() )
757 {
758 TOOL_STATE* st = m_toolIdIndex[*it];
759 bool increment = true;
760
761 // forward context menu events to the tool that created the menu
762 if( aEvent.IsChoiceMenu() )
763 {
764 if( *it != m_menuOwner )
765 {
766 ++it;
767 continue;
768 }
769 }
770
771 // If we're pendingWait then we had better have a cofunc to process the wait.
772 wxASSERT( !st || !st->pendingWait || st->cofunc );
773
774 // the tool state handler is waiting for events (i.e. called Wait() method)
775 if( st && st->cofunc && st->pendingWait && st->waitEvents.Matches( aEvent ) )
776 {
777 if( !aEvent.FirstResponder() )
778 aEvent.SetFirstResponder( st->theTool );
779
780 // got matching event? clear wait list and wake up the coroutine
781 st->wakeupEvent = aEvent;
782 st->pendingWait = false;
783 st->waitEvents.clear();
784
785 wxLogTrace( kicadTraceToolStack,
786 wxS( "TOOL_MANAGER::dispatchInternal - Waking tool %s for event: %s" ),
787 st->theTool->GetName(), aEvent.Format() );
788
789 setActiveState( st );
790 bool end = !st->cofunc->Resume();
791
792 if( end )
793 {
794 it = finishTool( st );
795 increment = false;
796 }
797
798 // If the tool did not request the event be passed to other tools, we're done
799 if( !st->wakeupEvent.PassEvent() )
800 {
801 wxLogTrace( kicadTraceToolStack,
802 wxS( "TOOL_MANAGER::dispatchInternal - tool %s stopped passing "
803 "event: %s" ),
804 st->theTool->GetName(), aEvent.Format() );
805
806 return true;
807 }
808 }
809
810 if( increment )
811 ++it;
812 }
813
814 for( const auto& state : m_toolState )
815 {
816 TOOL_STATE* st = state.second;
817 bool finished = false;
818
819 // no state handler in progress - check if there are any transitions (defined by
820 // Go() method that match the event.
821 if( !st->transitions.empty() )
822 {
823 for( const TRANSITION& tr : st->transitions )
824 {
825 if( tr.first.Matches( aEvent ) )
826 {
827 auto func_copy = tr.second;
828
829 if( !aEvent.FirstResponder() )
830 aEvent.SetFirstResponder( st->theTool );
831
832 // if there is already a context, then push it on the stack
833 // and transfer the previous view control settings to the new context
834 if( st->cofunc )
835 {
836 KIGFX::VC_SETTINGS viewControlSettings = st->vcSettings;
837 st->Push();
838 st->vcSettings = std::move( viewControlSettings );
839 }
840
841 st->cofunc = new COROUTINE<int, const TOOL_EVENT&>( std::move( func_copy ) );
842
843 wxLogTrace( kicadTraceToolStack,
844 wxS( "TOOL_MANAGER::dispatchInternal - Running tool %s for "
845 "event: %s" ),
846 st->theTool->GetName(), aEvent.Format() );
847
848 // got match? Run the handler.
849 setActiveState( st );
850 st->idle = false;
851 st->initialEvent = aEvent;
852 st->cofunc->Call( st->initialEvent );
853 handled = true;
854
855 if( !st->cofunc->Running() )
856 finishTool( st ); // The coroutine has finished immediately?
857
858 // if it is a message, continue processing
859 finished = !( aEvent.Category() == TC_MESSAGE );
860
861 // there is no point in further checking, as transitions got cleared
862 break;
863 }
864 }
865 }
866
867 if( finished )
868 break; // only the first tool gets the event
869 }
870
871 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::dispatchInternal - %s handle event: %s" ),
872 ( handled ? wxS( "Did" ) : wxS( "Did not" ) ), aEvent.Format() );
873
874 return handled;
875}
876
877
879{
880 if( aEvent.Action() == TA_KEY_PRESSED )
881 return m_actionMgr->RunHotKey( aEvent.Modifier() | aEvent.KeyCode() );
882
883 return false;
884}
885
886
888{
889 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::dispatchActivation - Received event: %s" ),
890 aEvent.Format() );
891
892 if( aEvent.IsActivate() )
893 {
894 auto tool = m_toolNameIndex.find( aEvent.getCommandStr() );
895
896 if( tool != m_toolNameIndex.end() )
897 {
898 wxLogTrace( kicadTraceToolStack,
899 wxS( "TOOL_MANAGER::dispatchActivation - Running tool %s for event: %s" ),
900 tool->second->theTool->GetName(), aEvent.Format() );
901
902 runTool( tool->second->theTool );
903 return true;
904 }
905 }
906
907 return false;
908}
909
910
912{
913 for( TOOL_ID toolId : m_activeTools )
914 {
915 TOOL_STATE* st = m_toolIdIndex[toolId];
916
917 // the tool requested a context menu. The menu is activated on RMB click (CMENU_BUTTON mode)
918 // or immediately (CMENU_NOW) mode. The latter is used for clarification lists.
919 if( st->contextMenuTrigger == CMENU_OFF )
920 continue;
921
922 if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( BUT_RIGHT ) )
923 break;
924
925 if( st->cofunc )
926 {
927 st->pendingWait = true;
929 }
930
931 // Store the menu pointer in case it is changed by the TOOL when handling menu events
932 ACTION_MENU* m = st->contextMenu;
933
934 if( st->contextMenuTrigger == CMENU_NOW )
936
937 // Store the cursor position, so the tools could execute actions
938 // using the point where the user has invoked a context menu
939 if( m_viewControls )
941
942 // Save all tools cursor settings, as they will be overridden
943 for( const std::pair<const TOOL_ID, TOOL_STATE*>& idState : m_toolIdIndex )
944 {
945 TOOL_STATE* s = idState.second;
946 const auto& vc = s->vcSettings;
947
948 if( vc.m_forceCursorPosition )
949 m_cursorSettings[idState.first] = vc.m_forcedPosition;
950 else
951 m_cursorSettings[idState.first] = std::nullopt;
952 }
953
954 if( m_viewControls )
956
957 // Display a copy of menu
958 std::unique_ptr<ACTION_MENU> menu( m->Clone() );
959
960 m_menuOwner = toolId;
961 m_menuActive = true;
962
963 if( wxWindow* frame = dynamic_cast<wxWindow*>( m_frame ) )
964 frame->PopupMenu( menu.get() );
965
966 // Warp the cursor if a menu item was selected
967 if( menu->GetSelected() >= 0 )
968 {
971 }
972 // Otherwise notify the tool of a canceled menu
973 else
974 {
976 evt.SetHasPosition( false );
977 evt.SetParameter( m );
978 dispatchInternal( evt );
979 }
980
981 // Restore setting in case it was vetoed
983
984 // Notify the tools that menu has been closed
986 evt.SetHasPosition( false );
987 evt.SetParameter( m );
988 dispatchInternal( evt );
989
990 m_menuActive = false;
991 m_menuOwner = -1;
992
993 // Restore cursor settings
994 for( const std::pair<const TOOL_ID,
995 std::optional<VECTOR2D>>& cursorSetting : m_cursorSettings )
996 {
997 auto it = m_toolIdIndex.find( cursorSetting.first );
998 wxASSERT( it != m_toolIdIndex.end() );
999
1000 if( it == m_toolIdIndex.end() )
1001 continue;
1002
1003 KIGFX::VC_SETTINGS& vc = it->second->vcSettings;
1004 vc.m_forceCursorPosition = (bool) cursorSetting.second;
1005 vc.m_forcedPosition = cursorSetting.second ? *cursorSetting.second : VECTOR2D( 0, 0 );
1006 }
1007
1008 m_cursorSettings.clear();
1009 break;
1010 }
1011}
1012
1013
1015{
1018
1019 // Don't warp again when the menu is closed
1021}
1022
1023
1024TOOL_MANAGER::ID_LIST::iterator TOOL_MANAGER::finishTool( TOOL_STATE* aState )
1025{
1026 auto it = std::find( m_activeTools.begin(), m_activeTools.end(), aState->theTool->GetId() );
1027
1028 if( !aState->Pop() )
1029 {
1030 // Deactivate the tool if there are no other contexts saved on the stack
1031 if( it != m_activeTools.end() )
1032 it = m_activeTools.erase( it );
1033
1034 aState->idle = true;
1035 }
1036
1037 if( aState == m_activeState )
1038 setActiveState( nullptr );
1039
1040 return it;
1041}
1042
1043
1045{
1046 // Once the tool manager is shutting down, don't start
1047 // activating more tools
1048 if( m_shuttingDown )
1049 return true;
1050
1051 bool handled = processEvent( aEvent );
1052
1053 TOOL_STATE* activeTool = GetCurrentToolState();
1054
1055 if( activeTool )
1056 setActiveState( activeTool );
1057
1058 if( m_view && m_view->IsDirty() )
1059 {
1060#if defined( __WXMAC__ )
1061 wxTheApp->ProcessPendingEvents(); // required for updating brightening behind a popup menu
1062#endif
1063 }
1064
1065 UpdateUI( aEvent );
1066
1067 return handled;
1068}
1069
1070
1072 CONTEXT_MENU_TRIGGER aTrigger )
1073{
1074 TOOL_STATE* st = m_toolState[aTool];
1075
1076 st->contextMenu = aMenu;
1077 st->contextMenuTrigger = aTrigger;
1078}
1079
1080
1082{
1083 if( TOOL_STATE* active = GetCurrentToolState() )
1084 return active->vcSettings;
1085
1086 return m_viewControls->GetSettings();
1087}
1088
1089
1090TOOL_ID TOOL_MANAGER::MakeToolId( const std::string& aToolName )
1091{
1092 static int currentId;
1093
1094 return currentId++;
1095}
1096
1097
1099 KIGFX::VIEW_CONTROLS* aViewControls,
1100 APP_SETTINGS_BASE* aSettings, TOOLS_HOLDER* aFrame )
1101{
1102 m_model = aModel;
1103 m_view = aView;
1104 m_viewControls = aViewControls;
1105 m_frame = aFrame;
1106 m_settings = aSettings;
1107}
1108
1109
1111{
1112 if( !isRegistered( aTool ) )
1113 return false;
1114
1115 // Just check if the tool is on the active tools stack
1116 return alg::contains( m_activeTools, aTool->GetId() );
1117}
1118
1119
1121{
1123
1124 if( m_menuActive )
1125 {
1126 // Context menu is active, so the cursor settings are overridden (see DispatchContextMenu())
1127 auto it = m_cursorSettings.find( aState->theTool->GetId() );
1128
1129 if( it != m_cursorSettings.end() )
1130 {
1132
1133 // Tool has overridden the cursor position, so store the new settings
1135 {
1136 if( !curr.m_forceCursorPosition )
1137 it->second = std::nullopt;
1138 else
1139 it->second = curr.m_forcedPosition;
1140 }
1141 else
1142 {
1143 std::optional<VECTOR2D> cursor = it->second;
1144
1145 if( cursor )
1146 {
1147 aState->vcSettings.m_forceCursorPosition = true;
1149 }
1150 else
1151 {
1152 aState->vcSettings.m_forceCursorPosition = false;
1153 }
1154 }
1155 }
1156 }
1157}
1158
1159
1161{
1163}
1164
1165
1167{
1168 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::processEvent - %s" ), aEvent.Format() );
1169
1170 // First try to dispatch the action associated with the event if it is a key press event
1171 bool handled = DispatchHotKey( aEvent );
1172
1173 if( !handled )
1174 {
1175 TOOL_EVENT mod_event( aEvent );
1176
1177 // Only immediate actions get the position. Otherwise clear for tool activation
1178 if( GetToolHolder() && !GetToolHolder()->GetDoImmediateActions() )
1179 {
1180 // An tool-selection-event has no position
1181 if( !mod_event.getCommandStr().empty()
1182 && mod_event.getCommandStr() != GetToolHolder()->CurrentToolName()
1183 && !mod_event.ForceImmediate() )
1184 {
1185 mod_event.SetHasPosition( false );
1186 }
1187 }
1188
1189 // If the event is not handled through a hotkey activation, pass it to the currently
1190 // running tool loops
1191 handled |= dispatchInternal( mod_event );
1192 handled |= dispatchActivation( mod_event );
1193
1194 // Open the context menu if requested by a tool
1195 DispatchContextMenu( mod_event );
1196
1197 // Dispatch any remaining events in the event queue
1198 while( !m_eventQueue.empty() )
1199 {
1200 TOOL_EVENT event = m_eventQueue.front();
1201 m_eventQueue.pop_front();
1202 processEvent( event );
1203 }
1204 }
1205
1206 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::processEvent - %s handle event: %s" ),
1207 ( handled ? "Did" : "Did not" ), aEvent.Format() );
1208
1209 return handled;
1210}
1211
1212
1214{
1217
1218 m_activeState = aState;
1219
1221 applyViewControls( aState );
1222}
1223
1224
1226{
1227 auto it = m_toolIdIndex.find( aId );
1228
1229 if( it == m_toolIdIndex.end() )
1230 return false;
1231
1232 return !it->second->idle;
1233}
1234
1235
1237{
1238 EDA_BASE_FRAME* frame = dynamic_cast<EDA_BASE_FRAME*>( GetToolHolder() );
1239
1240 if( frame )
1241 frame->UpdateStatusBar();
1242}
Manage TOOL_ACTION objects.
bool RunHotKey(int aHotKey) const
Run an action associated with a hotkey (if there is one available).
TOOL_ACTION * FindAction(const std::string &aActionName) const
Find an action with a given name (if there is one available).
int GetHotKey(const TOOL_ACTION &aAction) const
Return the hot key associated with a given action or 0 if there is none.
void UpdateHotKeys(bool aFullUpdate)
Optionally read the hotkey config files and then rebuilds the internal hotkey maps.
Define the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
ACTION_MENU * Clone() const
Create a deep, recursive copy of this ACTION_MENU.
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
Definition: app_settings.h:108
Represent a set of changes (additions, deletions or modifications) of a data model (e....
Definition: commit.h:73
Implement a coroutine.
Definition: coroutine.h:114
bool Call(ArgType aArg)
Start execution of a coroutine, passing args as its arguments.
Definition: coroutine.h:322
void KiYield()
Stop execution of the coroutine and returns control to the caller.
Definition: coroutine.h:285
bool Resume()
Resume execution of a previously yielded coroutine.
Definition: coroutine.h:362
bool Running() const
Definition: coroutine.h:405
void RunMainStack(std::function< void()> func)
Run a functor inside the application main stack context.
Definition: coroutine.h:308
The base frame for deriving all KiCad main window classes.
virtual void UpdateStatusBar()
Update the status bar information.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:98
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void WarpMouseCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
If enabled (.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
void ApplySettings(const VC_SETTINGS &aSettings)
Apply VIEW_CONTROLS settings from an object.
const VC_SETTINGS & GetSettings() const
Return the current VIEW_CONTROLS settings.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:66
bool IsDirty() const
Return true if any of the VIEW layers needs to be refreshened.
Definition: view.h:611
Represent a single user action.
Definition: tool_action.h:304
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
Base abstract interface for all kinds of tools.
Definition: tool_base.h:66
virtual void Reset(RESET_REASON aReason)=0
Bring the tool to a known, initial state.
virtual bool Init()
Init() is called once upon a registration of the tool.
Definition: tool_base.h:92
const std::string & GetName() const
Return the name of the tool.
Definition: tool_base.h:136
TOOL_TYPE GetType() const
Return the type of the tool.
Definition: tool_base.h:111
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ REDRAW
Full drawing refresh.
Definition: tool_base.h:83
@ RUN
Tool is invoked after being inactive.
Definition: tool_base.h:79
TOOL_ID GetId() const
Return the unique identifier of the tool.
Definition: tool_base.h:123
void attachManager(TOOL_MANAGER *aManager)
Set the TOOL_MANAGER the tool will belong to.
Definition: tool_base.cpp:62
A list of TOOL_EVENTs, with overloaded || operators allowing for concatenating TOOL_EVENTs with littl...
Definition: tool_event.h:640
OPT_TOOL_EVENT Matches(const TOOL_EVENT &aEvent) const
Definition: tool_event.h:679
Generic, UI-independent tool event.
Definition: tool_event.h:168
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:252
TOOL_ACTIONS Action() const
Returns more specific information about the type of an event.
Definition: tool_event.h:247
void SetMousePosition(const VECTOR2D &aP)
Definition: tool_event.h:530
int KeyCode() const
Definition: tool_event.h:373
TOOL_BASE * FirstResponder() const
Definition: tool_event.h:265
bool IsActivate() const
Definition: tool_event.h:342
void SetFirstResponder(TOOL_BASE *aTool)
Definition: tool_event.h:266
bool IsSimulator() const
Indicate if the event is from the simulator.
Definition: tool_event.cpp:257
void SetParameter(T aParam)
Set a non-standard parameter assigned to the event.
Definition: tool_event.h:520
bool ForceImmediate() const
Returns if the action associated with this event should be treated as immediate regardless of the cur...
Definition: tool_event.h:262
bool IsClick(int aButtonMask=BUT_ANY) const
Definition: tool_event.cpp:209
TOOL_EVENT_CATEGORY Category() const
Return the category (eg. mouse/keyboard/action) of an event.
Definition: tool_event.h:244
int Modifier(int aMask=MD_MODIFIER_MASK) const
Return information about key modifiers state (Ctrl, Alt, etc.).
Definition: tool_event.h:363
void SetHasPosition(bool aHasPosition)
Definition: tool_event.h:258
const std::string & getCommandStr() const
Definition: tool_event.h:550
bool IsChoiceMenu() const
Definition: tool_event.h:352
const std::string Format() const
Return information about event in form of a human-readable string.
Definition: tool_event.cpp:97
void applyViewControls(const TOOL_STATE *aState)
Apply #VIEW_CONTROLS settings stored in a #TOOL_STATE object.
int GetPriority(int aToolId) const
Return priority of a given tool.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
TOOL_STATE * m_activeState
Pointer to the state object corresponding to the currently executed tool.
Definition: tool_manager.h:691
void UpdateUI(const TOOL_EVENT &aEvent)
Update the status bar and synchronizes toolbars.
std::map< TOOL_ID, std::optional< VECTOR2D > > m_cursorSettings
Original cursor position, if overridden by the context menu handler.
Definition: tool_manager.h:668
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
void ScheduleNextState(TOOL_BASE *aTool, TOOL_STATE_FUNC &aHandler, const TOOL_EVENT_LIST &aConditions)
Define a state transition.
std::map< const char *, TOOL_BASE * > m_toolTypes
Index of the registered tools to easily lookup by their type.
Definition: tool_manager.h:659
bool isRegistered(TOOL_BASE *aTool) const
Return information about a tool registration status.
Definition: tool_manager.h:605
APP_SETTINGS_BASE * m_settings
Definition: tool_manager.h:674
TOOL_STATE * GetCurrentToolState() const
Return the #TOOL_STATE object representing the state of the active tool.
Definition: tool_manager.h:434
VECTOR2D GetCursorPosition() const
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:677
std::pair< TOOL_EVENT_LIST, TOOL_STATE_FUNC > TRANSITION
Definition: tool_manager.h:548
void setActiveState(TOOL_STATE *aState)
Save the previous active state and sets a new one.
void DeactivateTool()
Deactivate the currently active tool.
bool dispatchInternal(TOOL_EVENT &aEvent)
Pass an event at first to the active tools, then to all others.
void PrimeTool(const VECTOR2D &aPosition)
"Prime" a tool by sending a cursor left-click event with the mouse position set to the passed in posi...
bool runTool(TOOL_BASE *aTool)
Make a tool active, so it can receive events and react to them.
bool InvokeTool(TOOL_ID aToolId)
Call a tool by sending a tool activation event to tool of given ID.
NAME_STATE_MAP m_toolNameIndex
Index of the registered tools current states, associated by tools' names.
Definition: tool_manager.h:653
TOOLS_HOLDER * m_frame
Definition: tool_manager.h:673
void CancelTool()
Send a cancel event to the tool currently at the top of the tool stack.
bool m_warpMouseAfterContextMenu
Definition: tool_manager.h:682
KIGFX::VIEW_CONTROLS * m_viewControls
Definition: tool_manager.h:672
void WarpAfterContextMenu()
Normally we warp the mouse after the context menu action runs.
ACTION_MANAGER * m_actionMgr
Instance of ACTION_MANAGER that handles TOOL_ACTIONs.
Definition: tool_manager.h:665
const KIGFX::VC_SETTINGS & GetCurrentToolVC() const
Return the view controls settings for the current tool or the general settings if there is no active ...
void RunMainStack(TOOL_BASE *aTool, std::function< void()> aFunc)
TOOLS_HOLDER * GetToolHolder() const
Definition: tool_manager.h:406
VECTOR2D GetMousePosition() const
bool processEvent(const TOOL_EVENT &aEvent)
Main function for event processing.
std::list< TOOL_ID > ID_LIST
Definition: tool_manager.h:75
ID_LIST::iterator finishTool(TOOL_STATE *aState)
Deactivate a tool and does the necessary clean up.
bool doRunAction(const TOOL_ACTION &aAction, bool aNow, const ki::any &aParam, COMMIT *aCommit, bool aFromAPI=false)
Helper function to actually run an action.
bool dispatchActivation(const TOOL_EVENT &aEvent)
Check if it is a valid activation event and invokes a proper tool.
ID_STATE_MAP m_toolIdIndex
Index of the registered tools current states, associated by tools' ID numbers.
Definition: tool_manager.h:656
TOOL_ID m_menuOwner
Tool currently displaying a popup menu. It is negative when there is no menu displayed.
Definition: tool_manager.h:688
KIGFX::VIEW * m_view
Definition: tool_manager.h:671
void ClearTransitions(TOOL_BASE *aTool)
Clear the state transition map for a tool.
bool m_shuttingDown
True if the tool manager is shutting down (don't process additional events)
Definition: tool_manager.h:694
void saveViewControls(TOOL_STATE *aState)
Save the #VIEW_CONTROLS settings to the tool state object.
int GetHotKey(const TOOL_ACTION &aAction) const
Return the hot key associated with a given action or 0 if there is none.
bool m_menuActive
Flag indicating whether a context menu is currently displayed.
Definition: tool_manager.h:685
TOOL_STATE_MAP m_toolState
Index of registered tools current states, associated by tools' objects.
Definition: tool_manager.h:650
void ShutdownTool(TOOL_BASE *aTool)
Shutdown the specified tool by waking it up with a null event to terminate the processing loop.
ID_LIST m_activeTools
Stack of the active tools.
Definition: tool_manager.h:662
void ResetTools(TOOL_BASE::RESET_REASON aReason)
Reset all tools (i.e.
EDA_ITEM * m_model
Definition: tool_manager.h:670
bool DispatchHotKey(const TOOL_EVENT &aEvent)
Handle specific events, that are intended for TOOL_MANAGER rather than tools.
static TOOL_ID MakeToolId(const std::string &aToolName)
Generate a unique ID from for a tool with given name.
bool invokeTool(TOOL_BASE *aTool)
Invoke a tool by sending a proper event (in contrary to runTool, which makes the tool run for real).
void DispatchContextMenu(const TOOL_EVENT &aEvent)
Handle context menu related events.
std::vector< TOOL_BASE * > m_toolOrder
List of tools in the order they were registered.
Definition: tool_manager.h:647
TOOL_BASE * FindTool(int aId) const
Search for a tool with given ID.
void ScheduleContextMenu(TOOL_BASE *aTool, ACTION_MENU *aMenu, CONTEXT_MENU_TRIGGER aTrigger)
Set behavior of the tool's context popup menu.
TOOL_EVENT * ScheduleWait(TOOL_BASE *aTool, const TOOL_EVENT_LIST &aConditions)
Pause execution of a given tool until one or more events matching aConditions arrives.
bool IsToolActive(TOOL_ID aId) const
Return true if a tool with given id is active (executing)
bool isActive(TOOL_BASE *aTool) const
Return information about a tool activation status.
void RegisterTool(TOOL_BASE *aTool)
Add a tool to the manager set and sets it up.
void SetEnvironment(EDA_ITEM *aModel, KIGFX::VIEW *aView, KIGFX::VIEW_CONTROLS *aViewControls, APP_SETTINGS_BASE *aSettings, TOOLS_HOLDER *aFrame)
Set the work environment (model, view, view controls and the parent window).
void InitTools()
Initialize all registered tools.
VECTOR2D m_menuCursor
Right click context menu position.
Definition: tool_manager.h:680
void ShutdownAllTools()
Shutdown all tools with a currently registered event loop in this tool manager by waking them up with...
A type-safe container of any type.
Definition: ki_any.h:93
bool has_value() const noexcept
Report whether there is a contained object or not.
Definition: ki_any.h:312
Base window classes and related definitions.
const wxChar *const kicadTraceToolStack
Flag to enable tracing of the tool handling stack.
void AddTransactionBreadcrumb(const wxString &aMsg, const wxString &aCategory)
Add a transaction breadcrumb.
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: wxgtk/ui.cpp:683
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:100
Structure to keep VIEW_CONTROLS settings for easy store/restore operations.
Definition: view_controls.h:43
VECTOR2D m_forcedPosition
Forced cursor position (world coordinates).
Definition: view_controls.h:56
void Reset()
Restore the default settings.
bool m_forceCursorPosition
Is the forced cursor position enabled.
Definition: view_controls.h:59
Struct describing the current execution state of a TOOL.
bool operator!=(const TOOL_MANAGER::TOOL_STATE &aRhs) const
bool Pop()
Restore state of the tool from stack.
bool pendingWait
Flag defining if the tool is waiting for any event (i.e.
bool pendingContextMenu
Is there a context menu being displayed.
void Push()
Store the current state of the tool on stack.
CONTEXT_MENU_TRIGGER contextMenuTrigger
Defines when the context menu is opened.
TOOL_EVENT initialEvent
The first event that triggered activation of the tool.
KIGFX::VC_SETTINGS vcSettings
VIEW_CONTROLS settings to preserve settings when the tools are switched.
TOOL_STATE(const TOOL_STATE &aState)
TOOL_STATE(TOOL_BASE *aTool)
ACTION_MENU * contextMenu
Context menu currently used by the tool.
bool idle
Is the tool active (pending execution) or disabled at the moment.
std::vector< TRANSITION > transitions
List of possible transitions (ie.
void clear()
Restores the initial state.
TOOL_EVENT_LIST waitEvents
List of events the tool is currently waiting for.
COROUTINE< int, const TOOL_EVENT & > * cofunc
Tool execution context.
bool shutdown
Should the tool shutdown during next execution.
std::stack< std::unique_ptr< TOOL_STATE > > stateStack
Stack preserving previous states of a TOOL.
TOOL_BASE * theTool
The tool itself.
TOOL_EVENT wakeupEvent
The event that triggered the execution/wakeup of the tool after Wait() call.
TOOL_STATE & operator=(const TOOL_STATE &aState)
bool operator==(const TOOL_MANAGER::TOOL_STATE &aRhs) const
VECTOR2I end
std::function< int(const TOOL_EVENT &)> TOOL_STATE_FUNC
Definition: tool_base.h:58
int TOOL_ID
Unique identifier for tools.
Definition: tool_base.h:56
@ INTERACTIVE
Tool that interacts with the user.
Definition: tool_base.h:49
CONTEXT_MENU_TRIGGER
Defines when a context menu is opened.
Definition: tool_event.h:151
@ CMENU_NOW
Right now (after TOOL_INTERACTIVE::SetContextMenu).
Definition: tool_event.h:153
@ CMENU_OFF
Never.
Definition: tool_event.h:154
@ CMENU_BUTTON
On the right button.
Definition: tool_event.h:152
@ TA_ANY
Definition: tool_event.h:126
@ TA_CHOICE_MENU_CHOICE
Context menu choice.
Definition: tool_event.h:98
@ TA_ACTIVATE
Tool activation event.
Definition: tool_event.h:115
@ TA_CHOICE_MENU_CLOSED
Context menu is closed, no matter whether anything has been chosen or not.
Definition: tool_event.h:101
@ TA_PRIME
Tool priming event (a special mouse click).
Definition: tool_event.h:124
@ TA_KEY_PRESSED
Definition: tool_event.h:76
@ TA_CANCEL_TOOL
Tool cancel event.
Definition: tool_event.h:90
@ TC_ANY
Definition: tool_event.h:60
@ TC_COMMAND
Definition: tool_event.h:57
@ TC_MOUSE
Definition: tool_event.h:55
@ TC_MESSAGE
Definition: tool_event.h:58
@ STS_CANCELLED
Definition: tool_event.h:161
@ STS_FINISHED
Definition: tool_event.h:160
@ STS_RUNNING
Definition: tool_event.h:159
@ BUT_LEFT
Definition: tool_event.h:132
@ BUT_RIGHT
Definition: tool_event.h:133
wxLogTrace helper definitions.
VECTOR2D ToVECTOR2D(const wxPoint &aPoint)
Definition: vector2wx.h:40