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 (C) 2019-2023 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
34#include <wx/event.h>
35#include <wx/clipbrd.h>
36#include <wx/app.h>
37
38#include <math/vector2wx.h>
39
40#include <view/view.h>
41#include <eda_base_frame.h>
42#include <tool/tool_base.h>
44#include <tool/tool_manager.h>
45#include <tool/action_menu.h>
46#include <tool/coroutine.h>
47#include <tool/action_manager.h>
48
50
53{
55 theTool( aTool )
56 {
57 clear();
58 }
59
60 TOOL_STATE( const TOOL_STATE& aState )
61 {
62 theTool = aState.theTool;
63 idle = aState.idle;
64 shutdown = aState.shutdown;
65 pendingWait = aState.pendingWait;
67 contextMenu = aState.contextMenu;
69 cofunc = aState.cofunc;
71 wakeupEvent = aState.wakeupEvent;
72 waitEvents = aState.waitEvents;
73 transitions = aState.transitions;
74 vcSettings = aState.vcSettings;
75 // do not copy stateStack
76 }
77
79 {
80 if( !stateStack.empty() )
81 wxFAIL;
82 }
83
86
88 bool idle;
89
92
96
99
102
105
108
111
114
117
120 std::vector<TRANSITION> transitions;
121
124
126 {
127 theTool = aState.theTool;
128 idle = aState.idle;
129 shutdown = aState.shutdown;
130 pendingWait = aState.pendingWait;
132 contextMenu = aState.contextMenu;
134 cofunc = aState.cofunc;
135 initialEvent = aState.initialEvent;
136 wakeupEvent = aState.wakeupEvent;
137 waitEvents = aState.waitEvents;
138 transitions = aState.transitions;
139 vcSettings = aState.vcSettings;
140 // do not copy stateStack
141 return *this;
142 }
143
144 bool operator==( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
145 {
146 return aRhs.theTool == theTool;
147 }
148
149 bool operator!=( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
150 {
151 return aRhs.theTool != theTool;
152 }
153
158 void Push()
159 {
160 auto state = std::make_unique<TOOL_STATE>( *this );
161 stateStack.push( std::move( state ) );
162 clear();
163 }
164
171 bool Pop()
172 {
173 delete cofunc;
174
175 if( !stateStack.empty() )
176 {
177 *this = *stateStack.top().get();
178 stateStack.pop();
179 return true;
180 }
181 else
182 {
183 cofunc = nullptr;
184 return false;
185 }
186 }
187
188private:
190 std::stack<std::unique_ptr<TOOL_STATE>> stateStack;
191
193 void clear()
194 {
195 idle = true;
196 shutdown = false;
197 pendingWait = false;
198 pendingContextMenu = false;
199 cofunc = nullptr;
200 contextMenu = nullptr;
203 transitions.clear();
204 }
205};
206
207
209 m_model( nullptr ),
210 m_view( nullptr ),
211 m_viewControls( nullptr ),
212 m_frame( nullptr ),
213 m_settings( nullptr ),
214 m_warpMouseAfterContextMenu( true ),
215 m_menuActive( false ),
216 m_menuOwner( -1 ),
217 m_activeState( nullptr ),
218 m_shuttingDown( false )
219{
220 m_actionMgr = new ACTION_MANAGER( this );
221}
222
223
225{
226 std::map<TOOL_BASE*, TOOL_STATE*>::iterator it, it_end;
227
228 for( it = m_toolState.begin(), it_end = m_toolState.end(); it != it_end; ++it )
229 {
230 delete it->second->cofunc; // delete cofunction
231 delete it->second; // delete TOOL_STATE
232 delete it->first; // delete the tool itself
233 }
234
235 delete m_actionMgr;
236}
237
238
240{
241 wxASSERT_MSG( m_toolNameIndex.find( aTool->GetName() ) == m_toolNameIndex.end(),
242 wxT( "Adding two tools with the same name may result in unexpected behavior.") );
243 wxASSERT_MSG( m_toolIdIndex.find( aTool->GetId() ) == m_toolIdIndex.end(),
244 wxT( "Adding two tools with the same ID may result in unexpected behavior.") );
245 wxASSERT_MSG( m_toolTypes.find( typeid( *aTool ).name() ) == m_toolTypes.end(),
246 wxT( "Adding two tools of the same type may result in unexpected behavior.") );
247
248 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::RegisterTool: Registering tool %s with ID %d" ),
249 aTool->GetName(), aTool->GetId() );
250
251 m_toolOrder.push_back( aTool );
252
253 TOOL_STATE* st = new TOOL_STATE( aTool );
254
255 m_toolState[aTool] = st;
256 m_toolNameIndex[aTool->GetName()] = st;
257 m_toolIdIndex[aTool->GetId()] = st;
258 m_toolTypes[typeid( *aTool ).name()] = st->theTool;
259
260 aTool->attachManager( this );
261}
262
263
265{
266 TOOL_BASE* tool = FindTool( aToolId );
267
268 if( tool && tool->GetType() == INTERACTIVE )
269 return invokeTool( tool );
270
271 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::InvokeTool - no tool with ID %d" ),
272 aToolId );
273
274 return false; // there is no tool with the given id
275}
276
277
278bool TOOL_MANAGER::InvokeTool( const std::string& aToolName )
279{
280 TOOL_BASE* tool = FindTool( aToolName );
281
282 if( tool && tool->GetType() == INTERACTIVE )
283 return invokeTool( tool );
284
285 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::InvokeTool - no tool with name %s" ),
286 aToolName );
287
288 return false; // there is no tool with the given name
289}
290
291
292bool TOOL_MANAGER::doRunAction( const std::string& aActionName, bool aNow, const std::any& aParam,
293 COMMIT* aCommit )
294{
295 TOOL_ACTION* action = m_actionMgr->FindAction( aActionName );
296
297 if( !action )
298 {
299 wxASSERT_MSG( false, wxString::Format( "Could not find action %s.", aActionName ) );
300 return false;
301 }
302
303 doRunAction( *action, aNow, aParam, aCommit );
304
305 return false;
306}
307
308
310{
311 if( m_viewControls )
313 else
315}
316
317
319{
320 if( m_viewControls )
322 else
324}
325
326
327bool TOOL_MANAGER::doRunAction( const TOOL_ACTION& aAction, bool aNow, const std::any& aParam,
328 COMMIT* aCommit )
329{
330 if( m_shuttingDown )
331 return true;
332
333 bool retVal = false;
334 TOOL_EVENT event = aAction.MakeEvent();
335
336 // We initialize the SYNCHRONOUS state to finished so that tools that don't have an event
337 // loop won't hang if someone forgets to set the state.
338 std::atomic<SYNCRONOUS_TOOL_STATE> synchronousControl = STS_FINISHED;
339
340 if( event.Category() == TC_COMMAND )
341 event.SetMousePosition( GetCursorPosition() );
342
343 // Allow to override the action parameter
344 if( aParam.has_value() )
345 event.SetParameter( aParam );
346
347 // Pass the commit (if any)
348 if( aCommit )
349 {
350 event.SetSynchronous( &synchronousControl );
351 event.SetCommit( aCommit );
352 }
353
354 if( aNow )
355 {
356 TOOL_STATE* current = m_activeState;
357
358 if( aCommit )
359 {
360 // An event with a commit must be run synchronously
361 processEvent( event );
362
363 while( synchronousControl == STS_RUNNING )
364 {
365 wxYield();
366 }
367
368 retVal = synchronousControl != STS_CANCELLED;
369 }
370 else
371 {
372 retVal = processEvent( event );
373 }
374
375 setActiveState( current );
376 UpdateUI( event );
377 }
378 else
379 {
380 PostEvent( event );
381 }
382
383 return retVal;
384}
385
386
388{
390
391 processEvent( evt );
392}
393
394
395void TOOL_MANAGER::PrimeTool( const VECTOR2D& aPosition )
396{
397 int modifiers = 0;
398
399 /*
400 * Don't include any modifiers. They're part of the hotkey, not part of the resulting
401 * click.
402 *
403 * modifiers |= wxGetKeyState( WXK_SHIFT ) ? MD_SHIFT : 0;
404 * modifiers |= wxGetKeyState( WXK_CONTROL ) ? MD_CTRL : 0;
405 * modifiers |= wxGetKeyState( WXK_ALT ) ? MD_ALT : 0;
406 */
407
408 TOOL_EVENT evt( TC_MOUSE, TA_PRIME, BUT_LEFT | modifiers );
409 evt.SetMousePosition( aPosition );
410
411 PostEvent( evt );
412}
413
414
416{
417 // Horrific hack, but it's a crash bug. Don't let inter-frame commands stack up
418 // waiting to be processed.
419 if( aEvent.IsSimulator() && m_eventQueue.size() > 0 && m_eventQueue.back().IsSimulator() )
420 m_eventQueue.pop_back();
421
422 m_eventQueue.push_back( aEvent );
423}
424
425
426int TOOL_MANAGER::GetHotKey( const TOOL_ACTION& aAction ) const
427{
428 return m_actionMgr->GetHotKey( aAction );
429}
430
431
433{
434 wxASSERT( aTool != nullptr );
435
436 TOOL_EVENT evt( TC_COMMAND, TA_ACTIVATE, aTool->GetName() );
438 processEvent( evt );
439
440 if( TOOL_STATE* active = GetCurrentToolState() )
441 setActiveState( active );
442
443 return true;
444}
445
446
448{
449 wxASSERT( aTool != nullptr );
450
451 if( !isRegistered( aTool ) )
452 {
453 wxASSERT_MSG( false, wxT( "You cannot run unregistered tools" ) );
454 return false;
455 }
456
457 TOOL_ID id = aTool->GetId();
458
459 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::runTool - running tool %s" ),
460 aTool->GetName() );
461
462 if( aTool->GetType() == INTERACTIVE )
463 static_cast<TOOL_INTERACTIVE*>( aTool )->resetTransitions();
464
465 // If the tool is already active, bring it to the top of the active tools stack
466 if( isActive( aTool ) && m_activeTools.size() > 1 )
467 {
468 auto it = std::find( m_activeTools.begin(), m_activeTools.end(), id );
469
470 if( it != m_activeTools.end() )
471 {
472 if( it != m_activeTools.begin() )
473 {
474 m_activeTools.erase( it );
475 m_activeTools.push_front( id );
476 }
477
478 return false;
479 }
480 }
481
484
485 // Add the tool on the front of the processing queue (it gets events first)
486 m_activeTools.push_front( id );
487
488 return true;
489}
490
491
493{
494 m_shuttingDown = true;
495
496 // Create a temporary list of tools to iterate over since when the tools shutdown
497 // they remove themselves from the list automatically (invalidating the iterator)
498 ID_LIST tmpList = m_activeTools;
499
500 // Make sure each tool knows that it is shutting down, so that loops get shut down
501 // at the dispatcher
502 for( auto id : tmpList )
503 {
504 if( m_toolIdIndex.count( id ) == 0 )
505 continue;
506
507 m_toolIdIndex[id]->shutdown = true;
508 }
509
510 for( auto id : tmpList )
511 {
512 ShutdownTool( id );
513 }
514}
515
516
518{
519 TOOL_BASE* tool = FindTool( aToolId );
520
521 if( tool && tool->GetType() == INTERACTIVE )
522 ShutdownTool( tool );
523
524 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::ShutdownTool - no tool with ID %d" ),
525 aToolId );
526}
527
528
529void TOOL_MANAGER::ShutdownTool( const std::string& aToolName )
530{
531 TOOL_BASE* tool = FindTool( aToolName );
532
533 if( tool && tool->GetType() == INTERACTIVE )
534 ShutdownTool( tool );
535
536 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::ShutdownTool - no tool with name %s" ),
537 aToolName );
538}
539
540
542{
543 wxASSERT( aTool != nullptr );
544
545 TOOL_ID id = aTool->GetId();
546
547 if( isActive( aTool ) )
548 {
549 TOOL_MANAGER::ID_LIST::iterator it = std::find( m_activeTools.begin(),
550 m_activeTools.end(), id );
551
552 TOOL_STATE* st = m_toolIdIndex[*it];
553
554 // the tool state handler is waiting for events (i.e. called Wait() method)
555 if( st && st->pendingWait )
556 {
557 // Wake up the tool and tell it to shutdown
558 st->shutdown = true;
559 st->pendingWait = false;
560 st->waitEvents.clear();
561
562 if( st->cofunc )
563 {
564 wxLogTrace( kicadTraceToolStack,
565 wxS( "TOOL_MANAGER::ShutdownTool - Shutting down tool %s" ),
566 st->theTool->GetName() );
567
568 setActiveState( st );
569 bool end = !st->cofunc->Resume();
570
571 if( end )
572 finishTool( st );
573 }
574 }
575 }
576}
577
578
580{
581 std::map<TOOL_ID, TOOL_STATE*>::const_iterator it = m_toolIdIndex.find( aId );
582
583 if( it != m_toolIdIndex.end() )
584 return it->second->theTool;
585
586 return nullptr;
587}
588
589
590TOOL_BASE* TOOL_MANAGER::FindTool( const std::string& aName ) const
591{
592 std::map<std::string, TOOL_STATE*>::const_iterator it = m_toolNameIndex.find( aName );
593
594 if( it != m_toolNameIndex.end() )
595 return it->second->theTool;
596
597 return nullptr;
598}
599
600
602{
603 // Deactivate the active tool, but do not run anything new
605 processEvent( evt );
606}
607
608
610{
611 if( aReason != TOOL_BASE::REDRAW )
613
614 for( auto& state : m_toolState )
615 {
616 TOOL_BASE* tool = state.first;
617
618 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::ResetTools: Resetting tool '%s'" ),
619 tool->GetName() );
620
621 setActiveState( state.second );
622 tool->Reset( aReason );
623
624 if( tool->GetType() == INTERACTIVE )
625 static_cast<TOOL_INTERACTIVE*>( tool )->resetTransitions();
626 }
627}
628
629
631{
632 for( auto it = m_toolOrder.begin(); it != m_toolOrder.end(); /* iter inside */ )
633 {
634 TOOL_BASE* tool = *it;
635 wxASSERT( m_toolState.count( tool ) );
636 TOOL_STATE* state = m_toolState[tool];
637 setActiveState( state );
638 ++it; // keep the iterator valid if the element is going to be erased
639
640 if( !tool->Init() )
641 {
642 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER initialization of tool '%s' failed" ),
643 tool->GetName() );
644
645 // Unregister the tool
646 setActiveState( nullptr );
647 m_toolState.erase( tool );
648 m_toolNameIndex.erase( tool->GetName() );
649 m_toolIdIndex.erase( tool->GetId() );
650 m_toolTypes.erase( typeid( *tool ).name() );
651
652 delete state;
653 delete tool;
654 }
655 }
656
657 m_actionMgr->UpdateHotKeys( true );
658
660}
661
662
663int TOOL_MANAGER::GetPriority( int aToolId ) const
664{
665 int priority = 0;
666
667 for( TOOL_ID tool : m_activeTools )
668 {
669 if( tool == aToolId )
670 return priority;
671
672 ++priority;
673 }
674
675 return -1;
676}
677
678
680 const TOOL_EVENT_LIST& aConditions )
681{
682 TOOL_STATE* st = m_toolState[aTool];
683
684 st->transitions.emplace_back( TRANSITION( aConditions, aHandler ) );
685}
686
687
689{
690 m_toolState[aTool]->transitions.clear();
691}
692
693
694void TOOL_MANAGER::RunMainStack( TOOL_BASE* aTool, std::function<void()> aFunc )
695{
696 TOOL_STATE* st = m_toolState[aTool];
697 setActiveState( st );
698 wxCHECK( st->cofunc, /* void */ );
699 st->cofunc->RunMainStack( std::move( aFunc ) );
700}
701
702
704{
705 TOOL_STATE* st = m_toolState[aTool];
706
707 wxCHECK( !st->pendingWait, nullptr ); // everything collapses on two KiYield() in a row
708
709 // indicate to the manager that we are going to sleep and we shall be
710 // woken up when an event matching aConditions arrive
711 st->pendingWait = true;
712 st->waitEvents = aConditions;
713
714 wxCHECK( st->cofunc, nullptr );
715
716 // switch context back to event dispatcher loop
717 st->cofunc->KiYield();
718
719 // If the tool should shutdown, it gets a null event to break the loop
720 if( st->shutdown )
721 return nullptr;
722 else
723 return &st->wakeupEvent;
724}
725
726
728{
729 bool handled = false;
730
731 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::dispatchInternal - received event: %s" ),
732 aEvent.Format() );
733
734 auto it = m_activeTools.begin();
735
736 // iterate over active tool stack
737 while( it != m_activeTools.end() )
738 {
739 TOOL_STATE* st = m_toolIdIndex[*it];
740 bool increment = true;
741
742 // forward context menu events to the tool that created the menu
743 if( aEvent.IsChoiceMenu() )
744 {
745 if( *it != m_menuOwner )
746 {
747 ++it;
748 continue;
749 }
750 }
751
752 // If we're pendingWait then we had better have a cofunc to process the wait.
753 wxASSERT( !st || !st->pendingWait || st->cofunc );
754
755 // the tool state handler is waiting for events (i.e. called Wait() method)
756 if( st && st->cofunc && st->pendingWait && st->waitEvents.Matches( aEvent ) )
757 {
758 if( !aEvent.FirstResponder() )
759 aEvent.SetFirstResponder( st->theTool );
760
761 // got matching event? clear wait list and wake up the coroutine
762 st->wakeupEvent = aEvent;
763 st->pendingWait = false;
764 st->waitEvents.clear();
765
766 wxLogTrace( kicadTraceToolStack,
767 wxS( "TOOL_MANAGER::dispatchInternal - Waking tool %s for event: %s" ),
768 st->theTool->GetName(), aEvent.Format() );
769
770 setActiveState( st );
771 bool end = !st->cofunc->Resume();
772
773 if( end )
774 {
775 it = finishTool( st );
776 increment = false;
777 }
778
779 // If the tool did not request the event be passed to other tools, we're done
780 if( !st->wakeupEvent.PassEvent() )
781 {
782 wxLogTrace( kicadTraceToolStack,
783 wxS( "TOOL_MANAGER::dispatchInternal - tool %s stopped passing event: %s" ),
784 st->theTool->GetName(), aEvent.Format() );
785
786 return true;
787 }
788 }
789
790 if( increment )
791 ++it;
792 }
793
794 for( const auto& state : m_toolState )
795 {
796 TOOL_STATE* st = state.second;
797 bool finished = false;
798
799 // no state handler in progress - check if there are any transitions (defined by
800 // Go() method that match the event.
801 if( !st->transitions.empty() )
802 {
803 for( const TRANSITION& tr : st->transitions )
804 {
805 if( tr.first.Matches( aEvent ) )
806 {
807 auto func_copy = tr.second;
808
809 if( !aEvent.FirstResponder() )
810 aEvent.SetFirstResponder( st->theTool );
811
812 // if there is already a context, then push it on the stack
813 // and transfer the previous view control settings to the new context
814 if( st->cofunc )
815 {
816 KIGFX::VC_SETTINGS viewControlSettings = st->vcSettings;
817 st->Push();
818 st->vcSettings = std::move( viewControlSettings );
819 }
820
821 st->cofunc = new COROUTINE<int, const TOOL_EVENT&>( std::move( func_copy ) );
822
823 wxLogTrace( kicadTraceToolStack,
824 wxS( "TOOL_MANAGER::dispatchInternal - Running tool %s for event: %s" ),
825 st->theTool->GetName(), aEvent.Format() );
826
827 // got match? Run the handler.
828 setActiveState( st );
829 st->idle = false;
830 st->initialEvent = aEvent;
831 st->cofunc->Call( st->initialEvent );
832 handled = true;
833
834 if( !st->cofunc->Running() )
835 finishTool( st ); // The coroutine has finished immediately?
836
837 // if it is a message, continue processing
838 finished = !( aEvent.Category() == TC_MESSAGE );
839
840 // there is no point in further checking, as transitions got cleared
841 break;
842 }
843 }
844 }
845
846 if( finished )
847 break; // only the first tool gets the event
848 }
849
850 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::dispatchInternal - %s handle event: %s" ),
851 ( handled ? wxS( "Did" ) : wxS( "Did not" ) ), aEvent.Format() );
852
853 return handled;
854}
855
856
858{
859 if( aEvent.Action() == TA_KEY_PRESSED )
860 return m_actionMgr->RunHotKey( aEvent.Modifier() | aEvent.KeyCode() );
861
862 return false;
863}
864
865
867{
868 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::dispatchActivation - Received event: %s" ),
869 aEvent.Format() );
870
871 if( aEvent.IsActivate() )
872 {
873 auto tool = m_toolNameIndex.find( aEvent.getCommandStr() );
874
875 if( tool != m_toolNameIndex.end() )
876 {
877 wxLogTrace( kicadTraceToolStack,
878 wxS( "TOOL_MANAGER::dispatchActivation - Running tool %s for event: %s" ),
879 tool->second->theTool->GetName(), aEvent.Format() );
880
881 runTool( tool->second->theTool );
882 return true;
883 }
884 }
885
886 return false;
887}
888
890{
891 for( TOOL_ID toolId : m_activeTools )
892 {
893 TOOL_STATE* st = m_toolIdIndex[toolId];
894
895 // the tool requested a context menu. The menu is activated on RMB click (CMENU_BUTTON mode)
896 // or immediately (CMENU_NOW) mode. The latter is used for clarification lists.
897 if( st->contextMenuTrigger == CMENU_OFF )
898 continue;
899
900 if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( BUT_RIGHT ) )
901 break;
902
903 if( st->cofunc )
904 {
905 st->pendingWait = true;
907 }
908
909 // Store the menu pointer in case it is changed by the TOOL when handling menu events
910 ACTION_MENU* m = st->contextMenu;
911
912 if( st->contextMenuTrigger == CMENU_NOW )
914
915 // Store the cursor position, so the tools could execute actions
916 // using the point where the user has invoked a context menu
917 if( m_viewControls )
919
920 // Save all tools cursor settings, as they will be overridden
921 for( const std::pair<const TOOL_ID, TOOL_STATE*>& idState : m_toolIdIndex )
922 {
923 TOOL_STATE* s = idState.second;
924 const auto& vc = s->vcSettings;
925
926 if( vc.m_forceCursorPosition )
927 m_cursorSettings[idState.first] = vc.m_forcedPosition;
928 else
929 m_cursorSettings[idState.first] = std::nullopt;
930 }
931
932 if( m_viewControls )
934
935 // Display a copy of menu
936 std::unique_ptr<ACTION_MENU> menu( m->Clone() );
937
938 m_menuOwner = toolId;
939 m_menuActive = true;
940
941 if( wxWindow* frame = dynamic_cast<wxWindow*>( m_frame ) )
942 frame->PopupMenu( menu.get() );
943
944 // Warp the cursor if a menu item was selected
945 if( menu->GetSelected() >= 0 )
946 {
949 }
950 // Otherwise notify the tool of a cancelled menu
951 else
952 {
954 evt.SetHasPosition( false );
955 evt.SetParameter( m );
956 dispatchInternal( evt );
957 }
958
959 // Restore setting in case it was vetoed
961
962 // Notify the tools that menu has been closed
964 evt.SetHasPosition( false );
965 evt.SetParameter( m );
966 dispatchInternal( evt );
967
968 m_menuActive = false;
969 m_menuOwner = -1;
970
971 // Restore cursor settings
972 for( const std::pair<const TOOL_ID, std::optional<VECTOR2D>>& cursorSetting : m_cursorSettings )
973 {
974 auto it = m_toolIdIndex.find( cursorSetting.first );
975 wxASSERT( it != m_toolIdIndex.end() );
976
977 if( it == m_toolIdIndex.end() )
978 continue;
979
980 KIGFX::VC_SETTINGS& vc = it->second->vcSettings;
981 vc.m_forceCursorPosition = (bool) cursorSetting.second;
982 vc.m_forcedPosition = cursorSetting.second ? *cursorSetting.second : VECTOR2D( 0, 0 );
983 }
984
985 m_cursorSettings.clear();
986 break;
987 }
988}
989
990
991TOOL_MANAGER::ID_LIST::iterator TOOL_MANAGER::finishTool( TOOL_STATE* aState )
992{
993 auto it = std::find( m_activeTools.begin(), m_activeTools.end(), aState->theTool->GetId() );
994
995 if( !aState->Pop() )
996 {
997 // Deactivate the tool if there are no other contexts saved on the stack
998 if( it != m_activeTools.end() )
999 it = m_activeTools.erase( it );
1000
1001 aState->idle = true;
1002 }
1003
1004 if( aState == m_activeState )
1005 setActiveState( nullptr );
1006
1007 return it;
1008}
1009
1010
1012{
1013 // Once the tool manager is shutting down, don't start
1014 // activating more tools
1015 if( m_shuttingDown )
1016 return true;
1017
1018 bool handled = processEvent( aEvent );
1019
1020 TOOL_STATE* activeTool = GetCurrentToolState();
1021
1022 if( activeTool )
1023 setActiveState( activeTool );
1024
1025 if( m_view && m_view->IsDirty() )
1026 {
1027#if defined( __WXMAC__ )
1028 wxTheApp->ProcessPendingEvents(); // required for updating brightening behind a popup menu
1029#endif
1030 }
1031
1032 UpdateUI( aEvent );
1033
1034 return handled;
1035}
1036
1037
1039 CONTEXT_MENU_TRIGGER aTrigger )
1040{
1041 TOOL_STATE* st = m_toolState[aTool];
1042
1043 st->contextMenu = aMenu;
1044 st->contextMenuTrigger = aTrigger;
1045}
1046
1047
1048bool TOOL_MANAGER::SaveClipboard( const std::string& aTextUTF8 )
1049{
1050 wxLogNull doNotLog; // disable logging of failed clipboard actions
1051
1052 if( wxTheClipboard->Open() )
1053 {
1054 // Store the UTF8 string as Unicode string in clipboard:
1055 wxTheClipboard->SetData( new wxTextDataObject( wxString( aTextUTF8.c_str(),
1056 wxConvUTF8 ) ) );
1057
1058 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
1059 wxTheClipboard->Close();
1060
1061 return true;
1062 }
1063
1064 return false;
1065}
1066
1067
1069{
1070 std::string result;
1071
1072 wxLogNull doNotLog; // disable logging of failed clipboard actions
1073
1074 if( wxTheClipboard->Open() )
1075 {
1076 if( wxTheClipboard->IsSupported( wxDF_TEXT )
1077 || wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
1078 {
1079 wxTextDataObject data;
1080 wxTheClipboard->GetData( data );
1081
1082 // The clipboard is expected containing a Unicode string, so return it
1083 // as UTF8 string
1084 result = data.GetText().utf8_str();
1085 }
1086
1087 wxTheClipboard->Close();
1088 }
1089
1090 return result;
1091}
1092
1093
1095{
1096 if( TOOL_STATE* active = GetCurrentToolState() )
1097 return active->vcSettings;
1098
1099 return m_viewControls->GetSettings();
1100}
1101
1102
1103TOOL_ID TOOL_MANAGER::MakeToolId( const std::string& aToolName )
1104{
1105 static int currentId;
1106
1107 return currentId++;
1108}
1109
1110
1112 KIGFX::VIEW_CONTROLS* aViewControls,
1113 APP_SETTINGS_BASE* aSettings, TOOLS_HOLDER* aFrame )
1114{
1115 m_model = aModel;
1116 m_view = aView;
1117 m_viewControls = aViewControls;
1118 m_frame = aFrame;
1119 m_settings = aSettings;
1120}
1121
1122
1124{
1125 if( !isRegistered( aTool ) )
1126 return false;
1127
1128 // Just check if the tool is on the active tools stack
1129 return alg::contains( m_activeTools, aTool->GetId() );
1130}
1131
1132
1134{
1136
1137 if( m_menuActive )
1138 {
1139 // Context menu is active, so the cursor settings are overridden (see DispatchContextMenu())
1140 auto it = m_cursorSettings.find( aState->theTool->GetId() );
1141
1142 if( it != m_cursorSettings.end() )
1143 {
1145
1146 // Tool has overridden the cursor position, so store the new settings
1148 {
1149 if( !curr.m_forceCursorPosition )
1150 it->second = std::nullopt;
1151 else
1152 it->second = curr.m_forcedPosition;
1153 }
1154 else
1155 {
1156 std::optional<VECTOR2D> cursor = it->second;
1157
1158 if( cursor )
1159 {
1160 aState->vcSettings.m_forceCursorPosition = true;
1162 }
1163 else
1164 {
1165 aState->vcSettings.m_forceCursorPosition = false;
1166 }
1167 }
1168 }
1169 }
1170}
1171
1172
1174{
1176}
1177
1178
1180{
1181 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::processEvent - %s" ), aEvent.Format() );
1182
1183 // First try to dispatch the action associated with the event if it is a key press event
1184 bool handled = DispatchHotKey( aEvent );
1185
1186 if( !handled )
1187 {
1188 TOOL_EVENT mod_event( aEvent );
1189
1190 // Only immediate actions get the position. Otherwise clear for tool activation
1191 if( GetToolHolder() && !GetToolHolder()->GetDoImmediateActions() )
1192 {
1193 // An tool-selection-event has no position
1194 if( !mod_event.getCommandStr().empty()
1195 && mod_event.getCommandStr() != GetToolHolder()->CurrentToolName()
1196 && !mod_event.ForceImmediate() )
1197 {
1198 mod_event.SetHasPosition( false );
1199 }
1200 }
1201
1202 // If the event is not handled through a hotkey activation, pass it to the currently
1203 // running tool loops
1204 handled |= dispatchInternal( mod_event );
1205 handled |= dispatchActivation( mod_event );
1206
1207 // Open the context menu if requested by a tool
1208 DispatchContextMenu( mod_event );
1209
1210 // Dispatch any remaining events in the event queue
1211 while( !m_eventQueue.empty() )
1212 {
1213 TOOL_EVENT event = m_eventQueue.front();
1214 m_eventQueue.pop_front();
1215 processEvent( event );
1216 }
1217 }
1218
1219 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::processEvent - %s handle event: %s" ),
1220 ( handled ? "Did" : "Did not" ), aEvent.Format() );
1221
1222 return handled;
1223}
1224
1225
1227{
1230
1231 m_activeState = aState;
1232
1234 applyViewControls( aState );
1235}
1236
1237
1239{
1240 auto it = m_toolIdIndex.find( aId );
1241
1242 wxCHECK( it != m_toolIdIndex.end(), false );
1243
1244 return !it->second->idle;
1245}
1246
1247
1249{
1250 EDA_BASE_FRAME* frame = dynamic_cast<EDA_BASE_FRAME*>( GetToolHolder() );
1251
1252 if( frame )
1253 frame->UpdateStatusBar();
1254}
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.
Defines 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:92
Represent a set of changes (additions, deletions or modifications) of a data model (e....
Definition: commit.h:74
Implement a coroutine.
Definition: coroutine.h:84
bool Call(ArgType aArg)
Start execution of a coroutine, passing args as its arguments.
Definition: coroutine.h:272
void KiYield()
Stop execution of the coroutine and returns control to the caller.
Definition: coroutine.h:235
bool Resume()
Resume execution of a previously yielded coroutine.
Definition: coroutine.h:318
bool Running() const
Definition: coroutine.h:367
void RunMainStack(std::function< void()> func)
Run a functor inside the application main stack context.
Definition: coroutine.h:258
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:85
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)
Load new settings from program common settings.
const VC_SETTINGS & GetSettings() const
Apply VIEW_CONTROLS settings from an object.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
bool IsDirty() const
Return true if any of the VIEW layers needs to be refreshened.
Definition: view.h:591
Represent a single user action.
Definition: tool_action.h:269
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:91
const std::string & GetName() const
Return the name of the tool.
Definition: tool_base.h:135
TOOL_TYPE GetType() const
Return the type of the tool.
Definition: tool_base.h:110
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:122
void attachManager(TOOL_MANAGER *aManager)
Set the TOOL_MANAGER the tool will belong to.
Definition: tool_base.cpp:60
A list of TOOL_EVENTs, with overloaded || operators allowing for concatenating TOOL_EVENTs with littl...
Definition: tool_event.h:636
OPT_TOOL_EVENT Matches(const TOOL_EVENT &aEvent) const
Definition: tool_event.h:676
Generic, UI-independent tool event.
Definition: tool_event.h:167
bool PassEvent() const
Definition: tool_event.h:251
TOOL_ACTIONS Action() const
These give a tool a method of informing the TOOL_MANAGER that a particular event should be passed on ...
Definition: tool_event.h:246
void SetMousePosition(const VECTOR2D &aP)
Definition: tool_event.h:525
int KeyCode() const
Definition: tool_event.h:368
TOOL_BASE * FirstResponder() const
Definition: tool_event.h:264
bool IsActivate() const
Definition: tool_event.h:337
void SetFirstResponder(TOOL_BASE *aTool)
Controls whether the tool is first being pushed to the stack or being reactivated after a pause.
Definition: tool_event.h:265
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:515
bool ForceImmediate() const
Definition: tool_event.h:261
bool IsClick(int aButtonMask=BUT_ANY) const
Definition: tool_event.cpp:209
TOOL_EVENT_CATEGORY Category() const
Returns more specific information about the type of an event.
Definition: tool_event.h:243
int Modifier(int aMask=MD_MODIFIER_MASK) const
Definition: tool_event.h:358
void SetHasPosition(bool aHasPosition)
Returns if the action associated with this event should be treated as immediate regardless of the cur...
Definition: tool_event.h:257
const std::string & getCommandStr() const
Definition: tool_event.h:545
bool IsChoiceMenu() const
Definition: tool_event.h:347
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
True if the tool manager is shutting down (don't process additional events)
Definition: tool_manager.h:681
void UpdateUI(const TOOL_EVENT &aEvent)
Update the status bar and synchronizes toolbars.
std::map< TOOL_ID, std::optional< VECTOR2D > > m_cursorSettings
Definition: tool_manager.h:658
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
Stack of the active tools.
Definition: tool_manager.h:649
bool isRegistered(TOOL_BASE *aTool) const
Return information about a tool registration status.
Definition: tool_manager.h:596
APP_SETTINGS_BASE * m_settings
Queue that stores events to be processed at the end of the event processing cycle.
Definition: tool_manager.h:664
TOOL_STATE * GetCurrentToolState() const
Return the #TOOL_STATE object representing the state of the active tool.
Definition: tool_manager.h:417
VECTOR2D GetCursorPosition() const
std::list< TOOL_EVENT > m_eventQueue
Right click context menu position.
Definition: tool_manager.h:667
std::pair< TOOL_EVENT_LIST, TOOL_STATE_FUNC > TRANSITION
Definition: tool_manager.h:541
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' ID numbers.
Definition: tool_manager.h:643
TOOLS_HOLDER * m_frame
Definition: tool_manager.h:663
std::string GetClipboardUTF8() const
Return the information currently stored in the system clipboard.
void CancelTool()
Send a cancel event to the tool currently at the top of the tool stack.
bool m_warpMouseAfterContextMenu
Flag indicating whether a context menu is currently displayed.
Definition: tool_manager.h:672
KIGFX::VIEW_CONTROLS * m_viewControls
Definition: tool_manager.h:662
bool doRunAction(const TOOL_ACTION &aAction, bool aNow, const std::any &aParam, COMMIT *aCommit)
Helper function to actually run an action.
ACTION_MANAGER * m_actionMgr
Original cursor position, if overridden by the context menu handler.
Definition: tool_manager.h:655
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:389
VECTOR2D GetMousePosition() const
bool processEvent(const TOOL_EVENT &aEvent)
Main function for event processing.
std::list< TOOL_ID > ID_LIST
Definition: tool_manager.h:70
ID_LIST::iterator finishTool(TOOL_STATE *aState)
Deactivate a tool and does the necessary clean up.
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 to easily lookup by their type.
Definition: tool_manager.h:646
TOOL_ID m_menuOwner
Pointer to the state object corresponding to the currently executed tool.
Definition: tool_manager.h:678
KIGFX::VIEW * m_view
Definition: tool_manager.h:661
void ClearTransitions(TOOL_BASE *aTool)
Clear the state transition map for a tool.
bool SaveClipboard(const std::string &aTextUTF8)
Store information to the system clipboard.
bool m_shuttingDown
Definition: tool_manager.h:684
void saveViewControls(TOOL_STATE *aState)
Save the #VIEW_CONTROLS settings to the tool state object.
int GetHotKey(const TOOL_ACTION &aAction) const
bool m_menuActive
Tool currently displaying a popup menu. It is negative when there is no menu displayed.
Definition: tool_manager.h:675
TOOL_STATE_MAP m_toolState
Index of the registered tools current states, associated by tools' names.
Definition: tool_manager.h:640
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
Instance of ACTION_MANAGER that handles TOOL_ACTIONs.
Definition: tool_manager.h:652
void ResetTools(TOOL_BASE::RESET_REASON aReason)
Reset all tools (i.e.
EDA_ITEM * m_model
Definition: tool_manager.h:660
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)
Generates 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
Index of registered tools current states, associated by tools' objects.
Definition: tool_manager.h:637
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()
Initializes all registered tools.
VECTOR2D m_menuCursor
Definition: tool_manager.h:670
void ShutdownAllTools()
Shutdown all tools with a currently registered event loop in this tool manager by waking them up with...
Base window classes and related definitions.
const wxChar *const kicadTraceToolStack
Flag to enable tracing of the tool handling stack.
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: gtk/ui.cpp:601
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
Is the forced cursor position enabled.
Definition: view_controls.h:56
void Reset()
Flag determining the cursor visibility.
bool m_forceCursorPosition
Should the cursor be locked within the parent window area.
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.
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
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:150
@ CMENU_NOW
Definition: tool_event.h:152
@ CMENU_OFF
Definition: tool_event.h:153
@ CMENU_BUTTON
Definition: tool_event.h:151
@ TA_ANY
Definition: tool_event.h:125
@ TA_CHOICE_MENU_CHOICE
Definition: tool_event.h:97
@ TA_ACTIVATE
Definition: tool_event.h:114
@ TA_CHOICE_MENU_CLOSED
Definition: tool_event.h:100
@ TA_PRIME
Definition: tool_event.h:123
@ TA_KEY_PRESSED
Definition: tool_event.h:75
@ TA_CANCEL_TOOL
Definition: tool_event.h:89
@ TC_ANY
Definition: tool_event.h:59
@ TC_COMMAND
Definition: tool_event.h:56
@ TC_MOUSE
Definition: tool_event.h:54
@ TC_MESSAGE
Definition: tool_event.h:57
@ STS_CANCELLED
Definition: tool_event.h:160
@ STS_FINISHED
Definition: tool_event.h:159
@ STS_RUNNING
Definition: tool_event.h:158
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
wxLogTrace helper definitions.
VECTOR2D ToVECTOR2D(const wxPoint &aPoint)
Definition: vector2wx.h:40