2013-08-06 08:30:09 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
2023-11-08 21:34:14 +00:00
|
|
|
* Copyright (C) 2013-2023 CERN
|
2023-01-17 12:59:09 +00:00
|
|
|
* Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
2013-08-06 08:30:09 +00:00
|
|
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
2013-09-27 16:51:21 +00:00
|
|
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
2013-08-06 08:30:09 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
2020-10-24 12:53:11 +00:00
|
|
|
#include <core/kicad_algo.h>
|
2022-08-25 22:50:47 +00:00
|
|
|
#include <optional>
|
2019-07-27 14:11:41 +00:00
|
|
|
#include <map>
|
|
|
|
#include <stack>
|
|
|
|
#include <trace_helpers.h>
|
2023-09-18 03:13:09 +00:00
|
|
|
#include <kiplatform/ui.h>
|
2013-08-02 14:46:53 +00:00
|
|
|
|
|
|
|
#include <wx/event.h>
|
2014-07-09 12:01:07 +00:00
|
|
|
#include <wx/clipbrd.h>
|
2021-05-01 21:25:41 +00:00
|
|
|
#include <wx/app.h>
|
2013-08-02 14:46:53 +00:00
|
|
|
|
2023-02-19 03:40:07 +00:00
|
|
|
#include <math/vector2wx.h>
|
|
|
|
|
2013-08-02 14:46:53 +00:00
|
|
|
#include <view/view.h>
|
2024-04-27 19:57:24 +00:00
|
|
|
#include <view/view_controls.h>
|
2019-06-09 12:18:11 +00:00
|
|
|
#include <eda_base_frame.h>
|
2013-08-02 14:46:53 +00:00
|
|
|
#include <tool/tool_base.h>
|
|
|
|
#include <tool/tool_interactive.h>
|
|
|
|
#include <tool/tool_manager.h>
|
2019-05-14 11:14:00 +00:00
|
|
|
#include <tool/action_menu.h>
|
2013-08-02 14:46:53 +00:00
|
|
|
#include <tool/coroutine.h>
|
2013-09-27 16:51:21 +00:00
|
|
|
#include <tool/action_manager.h>
|
2013-08-02 14:46:53 +00:00
|
|
|
|
2014-04-04 09:56:04 +00:00
|
|
|
#include <class_draw_panel_gal.h>
|
2013-08-02 14:46:53 +00:00
|
|
|
|
2013-09-27 16:51:21 +00:00
|
|
|
/// Struct describing the current execution state of a TOOL
|
2013-09-02 12:21:12 +00:00
|
|
|
struct TOOL_MANAGER::TOOL_STATE
|
2013-08-02 14:46:53 +00:00
|
|
|
{
|
2014-07-09 11:50:27 +00:00
|
|
|
TOOL_STATE( TOOL_BASE* aTool ) :
|
|
|
|
theTool( aTool )
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
TOOL_STATE( const TOOL_STATE& aState )
|
|
|
|
{
|
2020-02-03 14:00:48 +00:00
|
|
|
theTool = aState.theTool;
|
|
|
|
idle = aState.idle;
|
|
|
|
shutdown = aState.shutdown;
|
|
|
|
pendingWait = aState.pendingWait;
|
2014-07-09 11:50:27 +00:00
|
|
|
pendingContextMenu = aState.pendingContextMenu;
|
2020-02-03 14:00:48 +00:00
|
|
|
contextMenu = aState.contextMenu;
|
2014-07-09 11:50:27 +00:00
|
|
|
contextMenuTrigger = aState.contextMenuTrigger;
|
2020-02-03 14:00:48 +00:00
|
|
|
cofunc = aState.cofunc;
|
2022-09-15 14:20:27 +00:00
|
|
|
initialEvent = aState.initialEvent;
|
2020-02-03 14:00:48 +00:00
|
|
|
wakeupEvent = aState.wakeupEvent;
|
|
|
|
waitEvents = aState.waitEvents;
|
|
|
|
transitions = aState.transitions;
|
|
|
|
vcSettings = aState.vcSettings;
|
2014-07-09 11:50:27 +00:00
|
|
|
// do not copy stateStack
|
|
|
|
}
|
|
|
|
|
|
|
|
~TOOL_STATE()
|
|
|
|
{
|
2019-05-10 10:12:12 +00:00
|
|
|
if( !stateStack.empty() )
|
|
|
|
wxFAIL;
|
2014-07-09 11:50:27 +00:00
|
|
|
}
|
|
|
|
|
2013-09-02 12:21:12 +00:00
|
|
|
/// The tool itself
|
2013-10-14 11:43:57 +00:00
|
|
|
TOOL_BASE* theTool;
|
2013-09-02 12:21:12 +00:00
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
/// Is the tool active (pending execution) or disabled at the moment
|
|
|
|
bool idle;
|
2013-09-02 12:21:12 +00:00
|
|
|
|
2020-02-03 14:00:48 +00:00
|
|
|
/// Should the tool shutdown during next execution
|
|
|
|
bool shutdown;
|
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
/// Flag defining if the tool is waiting for any event (i.e. if it
|
|
|
|
/// issued a Wait() call).
|
|
|
|
bool pendingWait;
|
2013-08-02 14:46:53 +00:00
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
/// Is there a context menu being displayed
|
|
|
|
bool pendingContextMenu;
|
2013-08-02 14:46:53 +00:00
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
/// Context menu currently used by the tool
|
2019-05-14 11:14:00 +00:00
|
|
|
ACTION_MENU* contextMenu;
|
2013-09-02 12:21:12 +00:00
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
/// Defines when the context menu is opened
|
|
|
|
CONTEXT_MENU_TRIGGER contextMenuTrigger;
|
2013-09-02 12:21:12 +00:00
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
/// Tool execution context
|
2015-02-14 20:28:47 +00:00
|
|
|
COROUTINE<int, const TOOL_EVENT&>* cofunc;
|
2013-08-02 14:46:53 +00:00
|
|
|
|
2022-09-15 14:20:27 +00:00
|
|
|
/// The first event that triggered activation of the tool.
|
|
|
|
TOOL_EVENT initialEvent;
|
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
/// The event that triggered the execution/wakeup of the tool after Wait() call
|
|
|
|
TOOL_EVENT wakeupEvent;
|
2013-09-24 13:47:07 +00:00
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
/// List of events the tool is currently waiting for
|
|
|
|
TOOL_EVENT_LIST waitEvents;
|
|
|
|
|
|
|
|
/// List of possible transitions (ie. association of events and state handlers that are executed
|
|
|
|
/// upon the event reception
|
|
|
|
std::vector<TRANSITION> transitions;
|
|
|
|
|
2017-02-11 20:26:08 +00:00
|
|
|
/// VIEW_CONTROLS settings to preserve settings when the tools are switched
|
2017-03-06 10:41:06 +00:00
|
|
|
KIGFX::VC_SETTINGS vcSettings;
|
2017-02-11 20:26:08 +00:00
|
|
|
|
2018-09-21 03:15:47 +00:00
|
|
|
TOOL_STATE& operator=( const TOOL_STATE& aState )
|
2014-07-09 11:50:27 +00:00
|
|
|
{
|
2020-02-03 14:00:48 +00:00
|
|
|
theTool = aState.theTool;
|
|
|
|
idle = aState.idle;
|
|
|
|
shutdown = aState.shutdown;
|
|
|
|
pendingWait = aState.pendingWait;
|
2014-07-09 11:50:27 +00:00
|
|
|
pendingContextMenu = aState.pendingContextMenu;
|
2020-02-03 14:00:48 +00:00
|
|
|
contextMenu = aState.contextMenu;
|
2014-07-09 11:50:27 +00:00
|
|
|
contextMenuTrigger = aState.contextMenuTrigger;
|
2020-02-03 14:00:48 +00:00
|
|
|
cofunc = aState.cofunc;
|
2022-09-15 14:20:27 +00:00
|
|
|
initialEvent = aState.initialEvent;
|
2020-02-03 14:00:48 +00:00
|
|
|
wakeupEvent = aState.wakeupEvent;
|
|
|
|
waitEvents = aState.waitEvents;
|
|
|
|
transitions = aState.transitions;
|
|
|
|
vcSettings = aState.vcSettings;
|
2014-07-09 11:50:27 +00:00
|
|
|
// do not copy stateStack
|
2018-09-21 11:12:59 +00:00
|
|
|
return *this;
|
2014-07-09 11:50:27 +00:00
|
|
|
}
|
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
bool operator==( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
|
2013-09-24 13:47:07 +00:00
|
|
|
{
|
2021-02-09 16:35:43 +00:00
|
|
|
return aRhs.theTool == theTool;
|
2013-09-24 13:47:07 +00:00
|
|
|
}
|
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
bool operator!=( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
|
2013-09-24 13:47:07 +00:00
|
|
|
{
|
2021-02-09 16:35:43 +00:00
|
|
|
return aRhs.theTool != theTool;
|
2013-09-24 13:47:07 +00:00
|
|
|
}
|
2014-07-09 11:50:27 +00:00
|
|
|
|
2014-07-09 12:23:13 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Store the current state of the tool on stack. Stacks are stored internally and are not
|
2014-07-09 12:23:13 +00:00
|
|
|
* shared between different TOOL_STATE objects.
|
|
|
|
*/
|
2014-07-09 11:50:27 +00:00
|
|
|
void Push()
|
|
|
|
{
|
2017-02-11 20:26:08 +00:00
|
|
|
auto state = std::make_unique<TOOL_STATE>( *this );
|
|
|
|
stateStack.push( std::move( state ) );
|
2014-07-09 11:50:27 +00:00
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
2014-07-09 12:23:13 +00:00
|
|
|
/**
|
2021-01-25 12:42:36 +00:00
|
|
|
* Restore state of the tool from stack. Stacks are stored internally and are not
|
2014-07-09 12:23:13 +00:00
|
|
|
* shared between different TOOL_STATE objects.
|
2021-01-25 12:42:36 +00:00
|
|
|
*
|
2014-07-09 12:23:13 +00:00
|
|
|
* @return True if state was restored, false if the stack was empty.
|
|
|
|
*/
|
2014-07-09 11:50:27 +00:00
|
|
|
bool Pop()
|
|
|
|
{
|
|
|
|
delete cofunc;
|
|
|
|
|
|
|
|
if( !stateStack.empty() )
|
|
|
|
{
|
2017-02-11 20:26:08 +00:00
|
|
|
*this = *stateStack.top().get();
|
2014-07-09 11:50:27 +00:00
|
|
|
stateStack.pop();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-07-15 19:26:35 +00:00
|
|
|
cofunc = nullptr;
|
2014-07-09 11:50:27 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2021-01-25 12:42:36 +00:00
|
|
|
///< Stack preserving previous states of a TOOL.
|
2017-02-11 20:26:08 +00:00
|
|
|
std::stack<std::unique_ptr<TOOL_STATE>> stateStack;
|
2014-07-09 11:50:27 +00:00
|
|
|
|
2021-01-25 12:42:36 +00:00
|
|
|
///< Restores the initial state.
|
2014-07-09 11:50:27 +00:00
|
|
|
void clear()
|
|
|
|
{
|
2020-02-03 14:00:48 +00:00
|
|
|
idle = true;
|
|
|
|
shutdown = false;
|
|
|
|
pendingWait = false;
|
2014-07-09 11:50:27 +00:00
|
|
|
pendingContextMenu = false;
|
2021-07-15 19:26:35 +00:00
|
|
|
cofunc = nullptr;
|
|
|
|
contextMenu = nullptr;
|
2014-07-09 11:50:27 +00:00
|
|
|
contextMenuTrigger = CMENU_OFF;
|
2017-02-11 20:26:08 +00:00
|
|
|
vcSettings.Reset();
|
2014-07-09 11:50:27 +00:00
|
|
|
transitions.clear();
|
|
|
|
}
|
2013-08-02 14:46:53 +00:00
|
|
|
};
|
|
|
|
|
2013-08-08 12:59:59 +00:00
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
TOOL_MANAGER::TOOL_MANAGER() :
|
2020-07-18 22:56:39 +00:00
|
|
|
m_model( nullptr ),
|
|
|
|
m_view( nullptr ),
|
|
|
|
m_viewControls( nullptr ),
|
|
|
|
m_frame( nullptr ),
|
|
|
|
m_settings( nullptr ),
|
2019-06-19 20:04:34 +00:00
|
|
|
m_warpMouseAfterContextMenu( true ),
|
2019-06-09 12:18:11 +00:00
|
|
|
m_menuActive( false ),
|
|
|
|
m_menuOwner( -1 ),
|
2022-07-15 23:37:33 +00:00
|
|
|
m_activeState( nullptr ),
|
|
|
|
m_shuttingDown( false )
|
2013-08-02 14:46:53 +00:00
|
|
|
{
|
2013-09-27 16:51:21 +00:00
|
|
|
m_actionMgr = new ACTION_MANAGER( this );
|
2013-08-02 14:46:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-08 12:59:59 +00:00
|
|
|
|
2013-09-11 17:37:52 +00:00
|
|
|
TOOL_MANAGER::~TOOL_MANAGER()
|
|
|
|
{
|
2014-07-09 11:50:27 +00:00
|
|
|
std::map<TOOL_BASE*, TOOL_STATE*>::iterator it, it_end;
|
2013-09-11 17:37:52 +00:00
|
|
|
|
|
|
|
for( it = m_toolState.begin(), it_end = m_toolState.end(); it != it_end; ++it )
|
|
|
|
{
|
|
|
|
delete it->second->cofunc; // delete cofunction
|
|
|
|
delete it->second; // delete TOOL_STATE
|
|
|
|
delete it->first; // delete the tool itself
|
|
|
|
}
|
2013-09-27 16:51:21 +00:00
|
|
|
|
2014-05-14 14:29:53 +00:00
|
|
|
delete m_actionMgr;
|
2013-09-11 17:37:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-08 12:50:32 +00:00
|
|
|
void TOOL_MANAGER::RegisterTool( TOOL_BASE* aTool )
|
2013-08-02 14:46:53 +00:00
|
|
|
{
|
2013-12-03 14:17:43 +00:00
|
|
|
wxASSERT_MSG( m_toolNameIndex.find( aTool->GetName() ) == m_toolNameIndex.end(),
|
2021-07-15 19:26:35 +00:00
|
|
|
wxT( "Adding two tools with the same name may result in unexpected behavior.") );
|
2013-12-03 14:17:43 +00:00
|
|
|
wxASSERT_MSG( m_toolIdIndex.find( aTool->GetId() ) == m_toolIdIndex.end(),
|
2021-07-15 19:26:35 +00:00
|
|
|
wxT( "Adding two tools with the same ID may result in unexpected behavior.") );
|
2014-07-09 09:59:24 +00:00
|
|
|
wxASSERT_MSG( m_toolTypes.find( typeid( *aTool ).name() ) == m_toolTypes.end(),
|
2021-07-15 19:26:35 +00:00
|
|
|
wxT( "Adding two tools of the same type may result in unexpected behavior.") );
|
2013-12-03 14:17:43 +00:00
|
|
|
|
2023-12-28 17:42:39 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::RegisterTool: Registering tool %s with ID %d" ),
|
|
|
|
aTool->GetName(), aTool->GetId() );
|
|
|
|
|
2020-10-02 20:09:15 +00:00
|
|
|
m_toolOrder.push_back( aTool );
|
|
|
|
|
2014-07-09 11:50:27 +00:00
|
|
|
TOOL_STATE* st = new TOOL_STATE( aTool );
|
2013-10-14 11:43:57 +00:00
|
|
|
|
|
|
|
m_toolState[aTool] = st;
|
|
|
|
m_toolNameIndex[aTool->GetName()] = st;
|
|
|
|
m_toolIdIndex[aTool->GetId()] = st;
|
2014-07-09 09:59:24 +00:00
|
|
|
m_toolTypes[typeid( *aTool ).name()] = st->theTool;
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2015-07-02 14:09:51 +00:00
|
|
|
aTool->attachManager( this );
|
2013-08-02 14:46:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-06 08:30:09 +00:00
|
|
|
|
2013-08-30 08:37:26 +00:00
|
|
|
bool TOOL_MANAGER::InvokeTool( TOOL_ID aToolId )
|
2013-08-20 12:49:08 +00:00
|
|
|
{
|
|
|
|
TOOL_BASE* tool = FindTool( aToolId );
|
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
if( tool && tool->GetType() == INTERACTIVE )
|
2013-09-19 15:02:57 +00:00
|
|
|
return invokeTool( tool );
|
2013-08-30 08:37:26 +00:00
|
|
|
|
2023-01-17 12:42:30 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::InvokeTool - no tool with ID %d" ),
|
2020-12-05 18:03:03 +00:00
|
|
|
aToolId );
|
2020-04-23 22:51:47 +00:00
|
|
|
|
2013-09-27 16:51:21 +00:00
|
|
|
return false; // there is no tool with the given id
|
2013-09-19 15:02:57 +00:00
|
|
|
}
|
2013-08-22 13:07:34 +00:00
|
|
|
|
2013-08-30 08:37:26 +00:00
|
|
|
|
2013-09-19 15:02:57 +00:00
|
|
|
bool TOOL_MANAGER::InvokeTool( const std::string& aToolName )
|
|
|
|
{
|
|
|
|
TOOL_BASE* tool = FindTool( aToolName );
|
2013-08-30 08:37:26 +00:00
|
|
|
|
2013-10-14 18:40:36 +00:00
|
|
|
if( tool && tool->GetType() == INTERACTIVE )
|
2013-09-19 15:02:57 +00:00
|
|
|
return invokeTool( tool );
|
2013-08-30 08:37:26 +00:00
|
|
|
|
2023-01-17 12:42:30 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::InvokeTool - no tool with name %s" ),
|
2020-12-05 18:03:03 +00:00
|
|
|
aToolName );
|
2020-04-23 22:51:47 +00:00
|
|
|
|
2013-09-27 16:51:21 +00:00
|
|
|
return false; // there is no tool with the given name
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-07-02 21:18:24 +00:00
|
|
|
bool TOOL_MANAGER::doRunAction( const std::string& aActionName, bool aNow, const std::any& aParam,
|
2023-06-26 23:57:09 +00:00
|
|
|
COMMIT* aCommit )
|
2013-12-03 14:41:41 +00:00
|
|
|
{
|
2014-07-09 14:25:50 +00:00
|
|
|
TOOL_ACTION* action = m_actionMgr->FindAction( aActionName );
|
|
|
|
|
2017-03-03 13:53:55 +00:00
|
|
|
if( !action )
|
2014-07-09 14:25:50 +00:00
|
|
|
{
|
2020-12-05 18:03:03 +00:00
|
|
|
wxASSERT_MSG( false, wxString::Format( "Could not find action %s.", aActionName ) );
|
2017-03-03 13:53:55 +00:00
|
|
|
return false;
|
2014-07-09 14:25:50 +00:00
|
|
|
}
|
|
|
|
|
2023-06-26 23:57:09 +00:00
|
|
|
doRunAction( *action, aNow, aParam, aCommit );
|
2015-04-30 08:46:08 +00:00
|
|
|
|
2023-01-29 18:06:05 +00:00
|
|
|
return true;
|
2013-12-03 14:41:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
VECTOR2D TOOL_MANAGER::GetMousePosition() const
|
2019-10-03 20:36:11 +00:00
|
|
|
{
|
|
|
|
if( m_viewControls )
|
|
|
|
return m_viewControls->GetMousePosition();
|
|
|
|
else
|
2023-09-18 03:13:09 +00:00
|
|
|
return ToVECTOR2D( KIPLATFORM::UI::GetMousePosition() );
|
2019-10-03 20:36:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
VECTOR2D TOOL_MANAGER::GetCursorPosition() const
|
2019-10-03 20:36:11 +00:00
|
|
|
{
|
|
|
|
if( m_viewControls )
|
|
|
|
return m_viewControls->GetCursorPosition();
|
|
|
|
else
|
2023-09-18 03:13:09 +00:00
|
|
|
return ToVECTOR2D( KIPLATFORM::UI::GetMousePosition() );
|
2019-10-03 20:36:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-07-02 21:18:24 +00:00
|
|
|
bool TOOL_MANAGER::doRunAction( const TOOL_ACTION& aAction, bool aNow, const std::any& aParam,
|
2023-06-26 23:57:09 +00:00
|
|
|
COMMIT* aCommit )
|
2014-02-28 14:46:05 +00:00
|
|
|
{
|
2022-07-15 23:37:33 +00:00
|
|
|
if( m_shuttingDown )
|
|
|
|
return true;
|
|
|
|
|
2023-06-30 17:57:01 +00:00
|
|
|
bool retVal = false;
|
2014-11-21 10:28:34 +00:00
|
|
|
TOOL_EVENT event = aAction.MakeEvent();
|
2015-04-30 08:46:01 +00:00
|
|
|
|
2023-06-30 17:57:01 +00:00
|
|
|
// We initialize the SYNCHRONOUS state to finished so that tools that don't have an event
|
|
|
|
// loop won't hang if someone forgets to set the state.
|
|
|
|
std::atomic<SYNCRONOUS_TOOL_STATE> synchronousControl = STS_FINISHED;
|
|
|
|
|
2019-10-03 15:55:05 +00:00
|
|
|
if( event.Category() == TC_COMMAND )
|
2019-10-03 20:36:11 +00:00
|
|
|
event.SetMousePosition( GetCursorPosition() );
|
2019-10-03 15:55:05 +00:00
|
|
|
|
2015-04-30 08:46:01 +00:00
|
|
|
// Allow to override the action parameter
|
2022-09-28 22:13:32 +00:00
|
|
|
if( aParam.has_value() )
|
2015-04-30 08:46:01 +00:00
|
|
|
event.SetParameter( aParam );
|
2014-11-21 10:28:34 +00:00
|
|
|
|
2023-06-26 23:57:09 +00:00
|
|
|
// Pass the commit (if any)
|
|
|
|
if( aCommit )
|
2023-06-30 17:57:01 +00:00
|
|
|
{
|
|
|
|
event.SetSynchronous( &synchronousControl );
|
2023-06-26 23:57:09 +00:00
|
|
|
event.SetCommit( aCommit );
|
2023-06-30 17:57:01 +00:00
|
|
|
}
|
2023-06-26 23:57:09 +00:00
|
|
|
|
2014-07-09 14:25:50 +00:00
|
|
|
if( aNow )
|
2018-02-14 14:09:10 +00:00
|
|
|
{
|
|
|
|
TOOL_STATE* current = m_activeState;
|
2023-06-30 17:57:01 +00:00
|
|
|
|
|
|
|
if( aCommit )
|
|
|
|
{
|
|
|
|
// An event with a commit must be run synchronously
|
|
|
|
processEvent( event );
|
|
|
|
|
|
|
|
while( synchronousControl == STS_RUNNING )
|
|
|
|
{
|
2024-05-11 10:53:04 +00:00
|
|
|
wxYield(); // Needed to honor mouse (and other) events during editing
|
|
|
|
wxMilliSleep( 1 ); // Needed to avoid 100% use of one cpu core.
|
|
|
|
// The sleeping time must be must be small to avoid
|
|
|
|
// noticeable lag in mouse and editing events
|
|
|
|
// (1 to 5 ms is a good value)
|
2023-06-30 17:57:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
retVal = synchronousControl != STS_CANCELLED;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
retVal = processEvent( event );
|
|
|
|
}
|
|
|
|
|
2018-02-14 14:09:10 +00:00
|
|
|
setActiveState( current );
|
2019-06-11 08:47:47 +00:00
|
|
|
UpdateUI( event );
|
2018-02-14 14:09:10 +00:00
|
|
|
}
|
2014-07-09 14:25:50 +00:00
|
|
|
else
|
2018-02-14 14:09:10 +00:00
|
|
|
{
|
2014-11-21 10:28:34 +00:00
|
|
|
PostEvent( event );
|
2018-02-14 14:09:10 +00:00
|
|
|
}
|
2019-08-05 12:19:44 +00:00
|
|
|
|
2023-06-30 17:57:01 +00:00
|
|
|
return retVal;
|
2014-02-28 14:46:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-05 00:48:22 +00:00
|
|
|
void TOOL_MANAGER::CancelTool()
|
|
|
|
{
|
|
|
|
TOOL_EVENT evt( TC_COMMAND, TA_CANCEL_TOOL );
|
|
|
|
|
|
|
|
processEvent( evt );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-10-03 15:55:05 +00:00
|
|
|
void TOOL_MANAGER::PrimeTool( const VECTOR2D& aPosition )
|
|
|
|
{
|
|
|
|
int modifiers = 0;
|
2022-05-16 09:22:55 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't include any modifiers. They're part of the hotkey, not part of the resulting
|
|
|
|
* click.
|
|
|
|
*
|
|
|
|
* modifiers |= wxGetKeyState( WXK_SHIFT ) ? MD_SHIFT : 0;
|
|
|
|
* modifiers |= wxGetKeyState( WXK_CONTROL ) ? MD_CTRL : 0;
|
|
|
|
* modifiers |= wxGetKeyState( WXK_ALT ) ? MD_ALT : 0;
|
|
|
|
*/
|
2019-10-03 15:55:05 +00:00
|
|
|
|
|
|
|
TOOL_EVENT evt( TC_MOUSE, TA_PRIME, BUT_LEFT | modifiers );
|
|
|
|
evt.SetMousePosition( aPosition );
|
|
|
|
|
|
|
|
PostEvent( evt );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-06 17:26:26 +00:00
|
|
|
void TOOL_MANAGER::PostEvent( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
// Horrific hack, but it's a crash bug. Don't let inter-frame commands stack up
|
|
|
|
// waiting to be processed.
|
|
|
|
if( aEvent.IsSimulator() && m_eventQueue.size() > 0 && m_eventQueue.back().IsSimulator() )
|
|
|
|
m_eventQueue.pop_back();
|
|
|
|
|
|
|
|
m_eventQueue.push_back( aEvent );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
int TOOL_MANAGER::GetHotKey( const TOOL_ACTION& aAction ) const
|
2015-07-28 08:29:00 +00:00
|
|
|
{
|
|
|
|
return m_actionMgr->GetHotKey( aAction );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-19 15:02:57 +00:00
|
|
|
bool TOOL_MANAGER::invokeTool( TOOL_BASE* aTool )
|
2013-08-20 12:49:08 +00:00
|
|
|
{
|
2021-07-15 19:26:35 +00:00
|
|
|
wxASSERT( aTool != nullptr );
|
2013-08-20 12:49:08 +00:00
|
|
|
|
2014-07-09 11:50:27 +00:00
|
|
|
TOOL_EVENT evt( TC_COMMAND, TA_ACTIVATE, aTool->GetName() );
|
2019-10-06 09:12:17 +00:00
|
|
|
evt.SetMousePosition( GetCursorPosition() );
|
2017-03-06 10:49:52 +00:00
|
|
|
processEvent( evt );
|
2013-09-19 15:02:57 +00:00
|
|
|
|
2018-02-14 14:09:10 +00:00
|
|
|
if( TOOL_STATE* active = GetCurrentToolState() )
|
|
|
|
setActiveState( active );
|
|
|
|
|
2013-09-19 15:02:57 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool TOOL_MANAGER::runTool( TOOL_BASE* aTool )
|
|
|
|
{
|
2021-07-15 19:26:35 +00:00
|
|
|
wxASSERT( aTool != nullptr );
|
2013-09-19 15:02:57 +00:00
|
|
|
|
|
|
|
if( !isRegistered( aTool ) )
|
2013-12-03 14:17:43 +00:00
|
|
|
{
|
|
|
|
wxASSERT_MSG( false, wxT( "You cannot run unregistered tools" ) );
|
2013-09-19 15:02:57 +00:00
|
|
|
return false;
|
2013-12-03 14:17:43 +00:00
|
|
|
}
|
2013-09-19 15:02:57 +00:00
|
|
|
|
2017-02-11 20:26:08 +00:00
|
|
|
TOOL_ID id = aTool->GetId();
|
|
|
|
|
2023-01-17 12:42:30 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::runTool - running tool %s" ),
|
2021-07-15 19:26:35 +00:00
|
|
|
aTool->GetName() );
|
2021-04-16 16:40:56 +00:00
|
|
|
|
2017-11-27 01:21:00 +00:00
|
|
|
if( aTool->GetType() == INTERACTIVE )
|
|
|
|
static_cast<TOOL_INTERACTIVE*>( aTool )->resetTransitions();
|
|
|
|
|
2014-04-01 12:35:09 +00:00
|
|
|
// If the tool is already active, bring it to the top of the active tools stack
|
2019-06-16 00:47:18 +00:00
|
|
|
if( isActive( aTool ) && m_activeTools.size() > 1 )
|
2014-04-01 12:35:09 +00:00
|
|
|
{
|
2019-06-16 00:47:18 +00:00
|
|
|
auto it = std::find( m_activeTools.begin(), m_activeTools.end(), id );
|
|
|
|
|
|
|
|
if( it != m_activeTools.end() )
|
|
|
|
{
|
|
|
|
if( it != m_activeTools.begin() )
|
|
|
|
{
|
|
|
|
m_activeTools.erase( it );
|
|
|
|
m_activeTools.push_front( id );
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2014-04-01 12:35:09 +00:00
|
|
|
}
|
2013-10-14 14:13:35 +00:00
|
|
|
|
2018-02-14 14:09:10 +00:00
|
|
|
setActiveState( m_toolIdIndex[id] );
|
2013-12-09 09:42:38 +00:00
|
|
|
aTool->Reset( TOOL_INTERACTIVE::RUN );
|
2017-07-31 12:30:51 +00:00
|
|
|
|
2013-09-19 15:02:57 +00:00
|
|
|
// Add the tool on the front of the processing queue (it gets events first)
|
2017-02-11 20:26:08 +00:00
|
|
|
m_activeTools.push_front( id );
|
2013-09-19 15:02:57 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-03 14:00:48 +00:00
|
|
|
void TOOL_MANAGER::ShutdownAllTools()
|
|
|
|
{
|
2022-07-15 23:37:33 +00:00
|
|
|
m_shuttingDown = true;
|
|
|
|
|
2020-02-03 14:00:48 +00:00
|
|
|
// Create a temporary list of tools to iterate over since when the tools shutdown
|
|
|
|
// they remove themselves from the list automatically (invalidating the iterator)
|
|
|
|
ID_LIST tmpList = m_activeTools;
|
|
|
|
|
2022-07-15 23:37:33 +00:00
|
|
|
// Make sure each tool knows that it is shutting down, so that loops get shut down
|
|
|
|
// at the dispatcher
|
|
|
|
for( auto id : tmpList )
|
|
|
|
{
|
|
|
|
if( m_toolIdIndex.count( id ) == 0 )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
m_toolIdIndex[id]->shutdown = true;
|
|
|
|
}
|
|
|
|
|
2020-02-03 14:00:48 +00:00
|
|
|
for( auto id : tmpList )
|
|
|
|
{
|
|
|
|
ShutdownTool( id );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TOOL_MANAGER::ShutdownTool( TOOL_ID aToolId )
|
|
|
|
{
|
|
|
|
TOOL_BASE* tool = FindTool( aToolId );
|
|
|
|
|
|
|
|
if( tool && tool->GetType() == INTERACTIVE )
|
|
|
|
ShutdownTool( tool );
|
2020-04-23 22:51:47 +00:00
|
|
|
|
2023-01-17 12:42:30 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::ShutdownTool - no tool with ID %d" ),
|
2021-07-15 19:26:35 +00:00
|
|
|
aToolId );
|
2020-02-03 14:00:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TOOL_MANAGER::ShutdownTool( const std::string& aToolName )
|
|
|
|
{
|
|
|
|
TOOL_BASE* tool = FindTool( aToolName );
|
|
|
|
|
|
|
|
if( tool && tool->GetType() == INTERACTIVE )
|
|
|
|
ShutdownTool( tool );
|
2020-04-23 22:51:47 +00:00
|
|
|
|
2023-01-17 12:42:30 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::ShutdownTool - no tool with name %s" ),
|
2021-07-15 19:26:35 +00:00
|
|
|
aToolName );
|
2020-02-03 14:00:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TOOL_MANAGER::ShutdownTool( TOOL_BASE* aTool )
|
|
|
|
{
|
2021-07-15 19:26:35 +00:00
|
|
|
wxASSERT( aTool != nullptr );
|
2020-02-03 14:00:48 +00:00
|
|
|
|
|
|
|
TOOL_ID id = aTool->GetId();
|
|
|
|
|
|
|
|
if( isActive( aTool ) )
|
|
|
|
{
|
2021-07-15 19:26:35 +00:00
|
|
|
TOOL_MANAGER::ID_LIST::iterator it = std::find( m_activeTools.begin(),
|
|
|
|
m_activeTools.end(), id );
|
2020-02-03 14:00:48 +00:00
|
|
|
|
|
|
|
TOOL_STATE* st = m_toolIdIndex[*it];
|
|
|
|
|
|
|
|
// the tool state handler is waiting for events (i.e. called Wait() method)
|
|
|
|
if( st && st->pendingWait )
|
|
|
|
{
|
|
|
|
// Wake up the tool and tell it to shutdown
|
|
|
|
st->shutdown = true;
|
|
|
|
st->pendingWait = false;
|
|
|
|
st->waitEvents.clear();
|
|
|
|
|
|
|
|
if( st->cofunc )
|
|
|
|
{
|
2020-12-07 22:03:43 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack,
|
2023-01-17 12:42:30 +00:00
|
|
|
wxS( "TOOL_MANAGER::ShutdownTool - Shutting down tool %s" ),
|
2020-12-07 22:03:43 +00:00
|
|
|
st->theTool->GetName() );
|
2020-02-03 14:00:48 +00:00
|
|
|
|
|
|
|
setActiveState( st );
|
|
|
|
bool end = !st->cofunc->Resume();
|
|
|
|
|
|
|
|
if( end )
|
2020-04-16 20:57:19 +00:00
|
|
|
finishTool( st );
|
2020-02-03 14:00:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-20 12:49:08 +00:00
|
|
|
TOOL_BASE* TOOL_MANAGER::FindTool( int aId ) const
|
|
|
|
{
|
2014-07-09 11:50:27 +00:00
|
|
|
std::map<TOOL_ID, TOOL_STATE*>::const_iterator it = m_toolIdIndex.find( aId );
|
2013-08-20 12:49:08 +00:00
|
|
|
|
|
|
|
if( it != m_toolIdIndex.end() )
|
|
|
|
return it->second->theTool;
|
|
|
|
|
2021-07-15 19:26:35 +00:00
|
|
|
return nullptr;
|
2013-08-20 12:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TOOL_BASE* TOOL_MANAGER::FindTool( const std::string& aName ) const
|
|
|
|
{
|
2014-07-09 11:50:27 +00:00
|
|
|
std::map<std::string, TOOL_STATE*>::const_iterator it = m_toolNameIndex.find( aName );
|
2013-08-20 12:49:08 +00:00
|
|
|
|
|
|
|
if( it != m_toolNameIndex.end() )
|
|
|
|
return it->second->theTool;
|
|
|
|
|
2021-07-15 19:26:35 +00:00
|
|
|
return nullptr;
|
2013-08-20 12:49:08 +00:00
|
|
|
}
|
|
|
|
|
2017-01-30 10:38:02 +00:00
|
|
|
|
2016-08-05 17:45:14 +00:00
|
|
|
void TOOL_MANAGER::DeactivateTool()
|
2013-12-09 09:42:38 +00:00
|
|
|
{
|
2017-02-11 20:26:08 +00:00
|
|
|
// Deactivate the active tool, but do not run anything new
|
|
|
|
TOOL_EVENT evt( TC_COMMAND, TA_CANCEL_TOOL );
|
2017-03-06 10:49:52 +00:00
|
|
|
processEvent( evt );
|
2016-08-05 17:45:14 +00:00
|
|
|
}
|
|
|
|
|
2017-01-30 10:38:02 +00:00
|
|
|
|
2016-08-05 17:45:14 +00:00
|
|
|
void TOOL_MANAGER::ResetTools( TOOL_BASE::RESET_REASON aReason )
|
|
|
|
{
|
2022-12-26 16:23:44 +00:00
|
|
|
if( aReason != TOOL_BASE::REDRAW )
|
|
|
|
DeactivateTool();
|
2014-12-09 23:50:31 +00:00
|
|
|
|
2017-03-07 16:18:22 +00:00
|
|
|
for( auto& state : m_toolState )
|
2015-04-30 08:46:03 +00:00
|
|
|
{
|
2017-07-31 12:30:51 +00:00
|
|
|
TOOL_BASE* tool = state.first;
|
2023-12-28 17:42:39 +00:00
|
|
|
|
|
|
|
wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::ResetTools: Resetting tool '%s'" ),
|
|
|
|
tool->GetName() );
|
|
|
|
|
2018-02-14 14:09:10 +00:00
|
|
|
setActiveState( state.second );
|
2017-07-31 12:30:51 +00:00
|
|
|
tool->Reset( aReason );
|
|
|
|
|
|
|
|
if( tool->GetType() == INTERACTIVE )
|
|
|
|
static_cast<TOOL_INTERACTIVE*>( tool )->resetTransitions();
|
2015-04-30 08:46:03 +00:00
|
|
|
}
|
2013-12-09 09:42:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-30 10:38:02 +00:00
|
|
|
void TOOL_MANAGER::InitTools()
|
|
|
|
{
|
2022-02-24 09:59:54 +00:00
|
|
|
for( auto it = m_toolOrder.begin(); it != m_toolOrder.end(); /* iter inside */ )
|
2017-01-30 10:38:02 +00:00
|
|
|
{
|
2020-10-02 20:09:15 +00:00
|
|
|
TOOL_BASE* tool = *it;
|
|
|
|
wxASSERT( m_toolState.count( tool ) );
|
|
|
|
TOOL_STATE* state = m_toolState[tool];
|
2018-02-14 14:09:10 +00:00
|
|
|
setActiveState( state );
|
2017-01-30 10:38:02 +00:00
|
|
|
++it; // keep the iterator valid if the element is going to be erased
|
|
|
|
|
|
|
|
if( !tool->Init() )
|
|
|
|
{
|
2023-01-17 12:42:30 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER initialization of tool '%s' failed" ),
|
2020-12-05 18:03:03 +00:00
|
|
|
tool->GetName() );
|
2017-01-30 10:38:02 +00:00
|
|
|
|
|
|
|
// Unregister the tool
|
2018-02-14 14:09:10 +00:00
|
|
|
setActiveState( nullptr );
|
2017-01-30 10:38:02 +00:00
|
|
|
m_toolState.erase( tool );
|
|
|
|
m_toolNameIndex.erase( tool->GetName() );
|
|
|
|
m_toolIdIndex.erase( tool->GetId() );
|
|
|
|
m_toolTypes.erase( typeid( *tool ).name() );
|
|
|
|
|
|
|
|
delete state;
|
|
|
|
delete tool;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-12 10:22:23 +00:00
|
|
|
m_actionMgr->UpdateHotKeys( true );
|
2019-07-06 12:48:53 +00:00
|
|
|
|
2017-01-30 10:38:02 +00:00
|
|
|
ResetTools( TOOL_BASE::RUN );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-09 15:05:05 +00:00
|
|
|
int TOOL_MANAGER::GetPriority( int aToolId ) const
|
|
|
|
{
|
|
|
|
int priority = 0;
|
|
|
|
|
2019-06-17 13:43:22 +00:00
|
|
|
for( TOOL_ID tool : m_activeTools )
|
2014-04-09 15:05:05 +00:00
|
|
|
{
|
2019-06-17 13:43:22 +00:00
|
|
|
if( tool == aToolId )
|
2014-04-09 15:05:05 +00:00
|
|
|
return priority;
|
|
|
|
|
|
|
|
++priority;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-20 12:49:08 +00:00
|
|
|
void TOOL_MANAGER::ScheduleNextState( TOOL_BASE* aTool, TOOL_STATE_FUNC& aHandler,
|
2013-08-06 08:30:09 +00:00
|
|
|
const TOOL_EVENT_LIST& aConditions )
|
2013-08-02 14:46:53 +00:00
|
|
|
{
|
2013-10-14 11:43:57 +00:00
|
|
|
TOOL_STATE* st = m_toolState[aTool];
|
2013-10-14 14:13:35 +00:00
|
|
|
|
2019-06-19 20:04:34 +00:00
|
|
|
st->transitions.emplace_back( TRANSITION( aConditions, aHandler ) );
|
2013-08-02 14:46:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-06 08:30:09 +00:00
|
|
|
|
2017-07-31 12:30:51 +00:00
|
|
|
void TOOL_MANAGER::ClearTransitions( TOOL_BASE* aTool )
|
|
|
|
{
|
|
|
|
m_toolState[aTool]->transitions.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-21 09:54:58 +00:00
|
|
|
void TOOL_MANAGER::RunMainStack( TOOL_BASE* aTool, std::function<void()> aFunc )
|
|
|
|
{
|
|
|
|
TOOL_STATE* st = m_toolState[aTool];
|
2018-02-14 14:09:10 +00:00
|
|
|
setActiveState( st );
|
2023-06-30 03:45:22 +00:00
|
|
|
wxCHECK( st->cofunc, /* void */ );
|
2016-09-21 09:54:58 +00:00
|
|
|
st->cofunc->RunMainStack( std::move( aFunc ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-17 13:43:22 +00:00
|
|
|
TOOL_EVENT* TOOL_MANAGER::ScheduleWait( TOOL_BASE* aTool, const TOOL_EVENT_LIST& aConditions )
|
2013-08-02 14:46:53 +00:00
|
|
|
{
|
2013-10-14 11:43:57 +00:00
|
|
|
TOOL_STATE* st = m_toolState[aTool];
|
2013-09-27 16:51:21 +00:00
|
|
|
|
2024-02-28 00:31:09 +00:00
|
|
|
wxCHECK( !st->pendingWait, nullptr ); // everything collapses on two KiYield() in a row
|
2014-07-09 14:25:50 +00:00
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
// indicate to the manager that we are going to sleep and we shall be
|
|
|
|
// woken up when an event matching aConditions arrive
|
|
|
|
st->pendingWait = true;
|
|
|
|
st->waitEvents = aConditions;
|
2013-08-02 14:46:53 +00:00
|
|
|
|
2023-06-30 03:45:22 +00:00
|
|
|
wxCHECK( st->cofunc, nullptr );
|
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
// switch context back to event dispatcher loop
|
2017-02-23 07:30:29 +00:00
|
|
|
st->cofunc->KiYield();
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2020-02-03 14:00:48 +00:00
|
|
|
// If the tool should shutdown, it gets a null event to break the loop
|
|
|
|
if( st->shutdown )
|
|
|
|
return nullptr;
|
|
|
|
else
|
|
|
|
return &st->wakeupEvent;
|
2013-08-02 14:46:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-06 08:30:09 +00:00
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
bool TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent )
|
2013-08-02 14:46:53 +00:00
|
|
|
{
|
2019-07-09 20:38:18 +00:00
|
|
|
bool handled = false;
|
|
|
|
|
2023-01-17 12:42:30 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::dispatchInternal - received event: %s" ),
|
2021-07-15 19:26:35 +00:00
|
|
|
aEvent.Format() );
|
2019-07-27 14:11:41 +00:00
|
|
|
|
2020-04-20 18:49:25 +00:00
|
|
|
auto it = m_activeTools.begin();
|
|
|
|
|
2019-07-07 23:01:08 +00:00
|
|
|
// iterate over active tool stack
|
2020-04-20 18:49:25 +00:00
|
|
|
while( it != m_activeTools.end() )
|
2013-08-30 08:37:26 +00:00
|
|
|
{
|
2016-07-04 14:12:21 +00:00
|
|
|
TOOL_STATE* st = m_toolIdIndex[*it];
|
2020-04-20 18:49:25 +00:00
|
|
|
bool increment = true;
|
2013-08-30 08:37:26 +00:00
|
|
|
|
2018-01-26 14:53:28 +00:00
|
|
|
// forward context menu events to the tool that created the menu
|
2019-06-15 00:29:42 +00:00
|
|
|
if( aEvent.IsChoiceMenu() )
|
2018-01-26 14:53:28 +00:00
|
|
|
{
|
|
|
|
if( *it != m_menuOwner )
|
2020-04-20 18:49:25 +00:00
|
|
|
{
|
|
|
|
++it;
|
2018-01-26 14:53:28 +00:00
|
|
|
continue;
|
2020-04-20 18:49:25 +00:00
|
|
|
}
|
2018-01-26 14:53:28 +00:00
|
|
|
}
|
|
|
|
|
2020-09-18 10:47:51 +00:00
|
|
|
// If we're pendingWait then we had better have a cofunc to process the wait.
|
|
|
|
wxASSERT( !st || !st->pendingWait || st->cofunc );
|
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
// the tool state handler is waiting for events (i.e. called Wait() method)
|
2020-09-18 10:47:51 +00:00
|
|
|
if( st && st->cofunc && st->pendingWait && st->waitEvents.Matches( aEvent ) )
|
2013-10-14 11:43:57 +00:00
|
|
|
{
|
2020-09-18 10:47:51 +00:00
|
|
|
if( !aEvent.FirstResponder() )
|
2021-03-06 09:27:41 +00:00
|
|
|
aEvent.SetFirstResponder( st->theTool );
|
2019-07-07 23:01:08 +00:00
|
|
|
|
2020-09-18 10:47:51 +00:00
|
|
|
// got matching event? clear wait list and wake up the coroutine
|
|
|
|
st->wakeupEvent = aEvent;
|
|
|
|
st->pendingWait = false;
|
|
|
|
st->waitEvents.clear();
|
2013-10-14 14:13:35 +00:00
|
|
|
|
2020-12-07 22:03:43 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack,
|
2023-01-17 12:42:30 +00:00
|
|
|
wxS( "TOOL_MANAGER::dispatchInternal - Waking tool %s for event: %s" ),
|
2020-12-07 22:03:43 +00:00
|
|
|
st->theTool->GetName(), aEvent.Format() );
|
2019-07-27 14:11:41 +00:00
|
|
|
|
2020-09-18 10:47:51 +00:00
|
|
|
setActiveState( st );
|
|
|
|
bool end = !st->cofunc->Resume();
|
2017-03-06 10:49:52 +00:00
|
|
|
|
2020-09-18 10:47:51 +00:00
|
|
|
if( end )
|
|
|
|
{
|
|
|
|
it = finishTool( st );
|
|
|
|
increment = false;
|
|
|
|
}
|
2013-10-14 11:43:57 +00:00
|
|
|
|
2020-09-18 10:47:51 +00:00
|
|
|
// If the tool did not request the event be passed to other tools, we're done
|
|
|
|
if( !st->wakeupEvent.PassEvent() )
|
|
|
|
{
|
2020-12-07 22:03:43 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack,
|
2023-01-17 12:42:30 +00:00
|
|
|
wxS( "TOOL_MANAGER::dispatchInternal - tool %s stopped passing event: %s" ),
|
2020-12-07 22:03:43 +00:00
|
|
|
st->theTool->GetName(), aEvent.Format() );
|
2019-07-27 14:11:41 +00:00
|
|
|
|
2020-09-18 10:47:51 +00:00
|
|
|
return true;
|
2013-10-14 11:43:57 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-20 18:49:25 +00:00
|
|
|
|
|
|
|
if( increment )
|
|
|
|
++it;
|
2013-08-30 08:37:26 +00:00
|
|
|
}
|
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
for( const auto& state : m_toolState )
|
2013-08-30 08:37:26 +00:00
|
|
|
{
|
2017-03-07 16:18:22 +00:00
|
|
|
TOOL_STATE* st = state.second;
|
2017-01-25 10:31:55 +00:00
|
|
|
bool finished = false;
|
2017-01-18 08:04:11 +00:00
|
|
|
|
2014-07-09 11:50:27 +00:00
|
|
|
// no state handler in progress - check if there are any transitions (defined by
|
|
|
|
// Go() method that match the event.
|
2017-01-18 08:04:11 +00:00
|
|
|
if( !st->transitions.empty() )
|
2013-10-14 11:43:57 +00:00
|
|
|
{
|
2021-03-06 09:27:41 +00:00
|
|
|
for( const TRANSITION& tr : st->transitions )
|
2013-10-14 11:43:57 +00:00
|
|
|
{
|
2014-07-09 11:50:27 +00:00
|
|
|
if( tr.first.Matches( aEvent ) )
|
2013-10-14 11:43:57 +00:00
|
|
|
{
|
2016-08-02 08:34:27 +00:00
|
|
|
auto func_copy = tr.second;
|
|
|
|
|
2019-07-07 23:01:08 +00:00
|
|
|
if( !aEvent.FirstResponder() )
|
2021-03-06 09:27:41 +00:00
|
|
|
aEvent.SetFirstResponder( st->theTool );
|
2019-07-07 23:01:08 +00:00
|
|
|
|
2018-02-14 14:09:10 +00:00
|
|
|
// if there is already a context, then push it on the stack
|
|
|
|
// and transfer the previous view control settings to the new context
|
2014-07-09 11:50:27 +00:00
|
|
|
if( st->cofunc )
|
2018-02-14 14:09:10 +00:00
|
|
|
{
|
2023-12-18 17:19:15 +00:00
|
|
|
KIGFX::VC_SETTINGS viewControlSettings = st->vcSettings;
|
2014-07-09 11:50:27 +00:00
|
|
|
st->Push();
|
2023-12-18 17:19:15 +00:00
|
|
|
st->vcSettings = std::move( viewControlSettings );
|
2018-02-14 14:09:10 +00:00
|
|
|
}
|
2014-07-09 11:50:27 +00:00
|
|
|
|
2016-08-02 08:34:27 +00:00
|
|
|
st->cofunc = new COROUTINE<int, const TOOL_EVENT&>( std::move( func_copy ) );
|
2016-07-04 22:14:32 +00:00
|
|
|
|
2020-12-07 22:03:43 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack,
|
2023-01-17 12:42:30 +00:00
|
|
|
wxS( "TOOL_MANAGER::dispatchInternal - Running tool %s for event: %s" ),
|
2020-12-07 22:03:43 +00:00
|
|
|
st->theTool->GetName(), aEvent.Format() );
|
2019-07-27 14:11:41 +00:00
|
|
|
|
2014-07-09 11:50:27 +00:00
|
|
|
// got match? Run the handler.
|
2018-02-14 14:09:10 +00:00
|
|
|
setActiveState( st );
|
2017-08-29 23:15:23 +00:00
|
|
|
st->idle = false;
|
2022-09-15 14:20:27 +00:00
|
|
|
st->initialEvent = aEvent;
|
|
|
|
st->cofunc->Call( st->initialEvent );
|
2019-07-09 20:38:18 +00:00
|
|
|
handled = true;
|
2014-07-09 11:50:27 +00:00
|
|
|
|
|
|
|
if( !st->cofunc->Running() )
|
2021-04-05 13:24:57 +00:00
|
|
|
finishTool( st ); // The coroutine has finished immediately?
|
2014-07-09 11:50:27 +00:00
|
|
|
|
2017-01-25 10:31:55 +00:00
|
|
|
// if it is a message, continue processing
|
|
|
|
finished = !( aEvent.Category() == TC_MESSAGE );
|
2017-01-18 08:04:11 +00:00
|
|
|
|
2014-07-09 11:50:27 +00:00
|
|
|
// there is no point in further checking, as transitions got cleared
|
|
|
|
break;
|
2013-10-14 11:43:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-01-18 08:04:11 +00:00
|
|
|
|
2017-01-25 10:31:55 +00:00
|
|
|
if( finished )
|
2017-01-18 08:04:11 +00:00
|
|
|
break; // only the first tool gets the event
|
2013-10-14 11:43:57 +00:00
|
|
|
}
|
2019-07-09 20:38:18 +00:00
|
|
|
|
2023-01-17 12:42:30 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::dispatchInternal - %s handle event: %s" ),
|
|
|
|
( handled ? wxS( "Did" ) : wxS( "Did not" ) ), aEvent.Format() );
|
2019-07-27 14:11:41 +00:00
|
|
|
|
2019-07-09 20:38:18 +00:00
|
|
|
return handled;
|
2013-08-02 14:46:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-06 08:30:09 +00:00
|
|
|
|
2020-06-23 10:21:16 +00:00
|
|
|
bool TOOL_MANAGER::DispatchHotKey( const TOOL_EVENT& aEvent )
|
2013-09-27 16:51:21 +00:00
|
|
|
{
|
2014-04-09 15:33:22 +00:00
|
|
|
if( aEvent.Action() == TA_KEY_PRESSED )
|
2020-06-23 10:21:16 +00:00
|
|
|
return m_actionMgr->RunHotKey( aEvent.Modifier() | aEvent.KeyCode() );
|
2013-09-27 16:51:21 +00:00
|
|
|
|
2019-07-09 20:38:18 +00:00
|
|
|
return false;
|
2013-09-27 16:51:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-14 20:28:47 +00:00
|
|
|
bool TOOL_MANAGER::dispatchActivation( const TOOL_EVENT& aEvent )
|
2013-09-19 15:02:57 +00:00
|
|
|
{
|
2023-01-17 12:42:30 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::dispatchActivation - Received event: %s" ),
|
2021-07-15 19:26:35 +00:00
|
|
|
aEvent.Format() );
|
2020-12-07 22:03:43 +00:00
|
|
|
|
2014-07-09 11:50:27 +00:00
|
|
|
if( aEvent.IsActivate() )
|
2013-09-19 15:02:57 +00:00
|
|
|
{
|
2022-09-14 17:31:56 +00:00
|
|
|
auto tool = m_toolNameIndex.find( aEvent.getCommandStr() );
|
2014-07-09 11:50:27 +00:00
|
|
|
|
|
|
|
if( tool != m_toolNameIndex.end() )
|
|
|
|
{
|
2020-12-07 22:03:43 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack,
|
2023-01-17 12:42:30 +00:00
|
|
|
wxS( "TOOL_MANAGER::dispatchActivation - Running tool %s for event: %s" ),
|
2020-12-07 22:03:43 +00:00
|
|
|
tool->second->theTool->GetName(), aEvent.Format() );
|
2019-07-27 14:11:41 +00:00
|
|
|
|
2014-07-09 11:50:27 +00:00
|
|
|
runTool( tool->second->theTool );
|
|
|
|
return true;
|
|
|
|
}
|
2013-09-19 15:02:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-05 19:15:57 +00:00
|
|
|
void TOOL_MANAGER::DispatchContextMenu( const TOOL_EVENT& aEvent )
|
2013-08-30 08:37:26 +00:00
|
|
|
{
|
2016-06-29 20:07:55 +00:00
|
|
|
for( TOOL_ID toolId : m_activeTools )
|
2013-08-30 08:37:26 +00:00
|
|
|
{
|
2013-09-02 12:21:12 +00:00
|
|
|
TOOL_STATE* st = m_toolIdIndex[toolId];
|
2013-08-30 08:37:26 +00:00
|
|
|
|
2013-09-27 16:51:21 +00:00
|
|
|
// the tool requested a context menu. The menu is activated on RMB click (CMENU_BUTTON mode)
|
|
|
|
// or immediately (CMENU_NOW) mode. The latter is used for clarification lists.
|
2017-02-24 15:39:52 +00:00
|
|
|
if( st->contextMenuTrigger == CMENU_OFF )
|
|
|
|
continue;
|
2013-09-26 12:09:18 +00:00
|
|
|
|
2017-02-24 15:39:52 +00:00
|
|
|
if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( BUT_RIGHT ) )
|
|
|
|
break;
|
2013-09-26 12:09:18 +00:00
|
|
|
|
2020-09-18 10:47:51 +00:00
|
|
|
if( st->cofunc )
|
|
|
|
{
|
|
|
|
st->pendingWait = true;
|
|
|
|
st->waitEvents = TOOL_EVENT( TC_ANY, TA_ANY );
|
|
|
|
}
|
2015-07-24 07:42:46 +00:00
|
|
|
|
2017-02-24 15:39:52 +00:00
|
|
|
// Store the menu pointer in case it is changed by the TOOL when handling menu events
|
2019-05-14 11:14:00 +00:00
|
|
|
ACTION_MENU* m = st->contextMenu;
|
2013-09-26 12:09:18 +00:00
|
|
|
|
2017-02-24 15:39:52 +00:00
|
|
|
if( st->contextMenuTrigger == CMENU_NOW )
|
|
|
|
st->contextMenuTrigger = CMENU_OFF;
|
2014-07-09 14:50:31 +00:00
|
|
|
|
2018-02-02 15:20:14 +00:00
|
|
|
// Store the cursor position, so the tools could execute actions
|
2017-02-24 15:39:52 +00:00
|
|
|
// using the point where the user has invoked a context menu
|
2020-03-18 22:48:36 +00:00
|
|
|
if( m_viewControls )
|
|
|
|
m_menuCursor = m_viewControls->GetCursorPosition();
|
2018-02-02 15:20:14 +00:00
|
|
|
|
|
|
|
// Save all tools cursor settings, as they will be overridden
|
2022-07-29 21:02:35 +00:00
|
|
|
for( const std::pair<const TOOL_ID, TOOL_STATE*>& idState : m_toolIdIndex )
|
2018-02-02 15:20:14 +00:00
|
|
|
{
|
|
|
|
TOOL_STATE* s = idState.second;
|
|
|
|
const auto& vc = s->vcSettings;
|
2013-08-02 14:46:53 +00:00
|
|
|
|
2018-02-02 15:20:14 +00:00
|
|
|
if( vc.m_forceCursorPosition )
|
|
|
|
m_cursorSettings[idState.first] = vc.m_forcedPosition;
|
|
|
|
else
|
2022-08-25 22:50:47 +00:00
|
|
|
m_cursorSettings[idState.first] = std::nullopt;
|
2018-02-02 15:20:14 +00:00
|
|
|
}
|
|
|
|
|
2020-03-18 22:48:36 +00:00
|
|
|
if( m_viewControls )
|
|
|
|
m_viewControls->ForceCursorPosition( true, m_menuCursor );
|
2013-08-02 14:46:53 +00:00
|
|
|
|
2017-02-24 15:39:52 +00:00
|
|
|
// Display a copy of menu
|
2019-05-14 11:14:00 +00:00
|
|
|
std::unique_ptr<ACTION_MENU> menu( m->Clone() );
|
2017-02-24 15:39:52 +00:00
|
|
|
|
2018-01-26 14:53:28 +00:00
|
|
|
m_menuOwner = toolId;
|
2017-03-06 10:49:52 +00:00
|
|
|
m_menuActive = true;
|
2017-10-31 11:01:59 +00:00
|
|
|
|
2020-03-24 01:01:23 +00:00
|
|
|
if( wxWindow* frame = dynamic_cast<wxWindow*>( m_frame ) )
|
2017-10-31 11:01:59 +00:00
|
|
|
frame->PopupMenu( menu.get() );
|
|
|
|
|
2024-02-15 13:06:55 +00:00
|
|
|
// Warp the cursor if a menu item was selected
|
|
|
|
if( menu->GetSelected() >= 0 )
|
|
|
|
{
|
|
|
|
if( m_viewControls && m_warpMouseAfterContextMenu )
|
|
|
|
m_viewControls->WarpMouseCursor( m_menuCursor, true, false );
|
|
|
|
}
|
|
|
|
// Otherwise notify the tool of a cancelled menu
|
2024-02-24 20:04:19 +00:00
|
|
|
else
|
2017-02-24 15:39:52 +00:00
|
|
|
{
|
2019-06-15 00:29:42 +00:00
|
|
|
TOOL_EVENT evt( TC_COMMAND, TA_CHOICE_MENU_CHOICE, -1 );
|
2019-10-03 15:55:05 +00:00
|
|
|
evt.SetHasPosition( false );
|
2015-07-24 07:42:46 +00:00
|
|
|
evt.SetParameter( m );
|
2015-04-30 08:46:07 +00:00
|
|
|
dispatchInternal( evt );
|
2017-02-24 15:39:52 +00:00
|
|
|
}
|
2015-04-30 08:46:07 +00:00
|
|
|
|
2019-04-13 15:22:48 +00:00
|
|
|
// Restore setting in case it was vetoed
|
|
|
|
m_warpMouseAfterContextMenu = true;
|
|
|
|
|
2017-02-24 15:39:52 +00:00
|
|
|
// Notify the tools that menu has been closed
|
2019-06-15 00:29:42 +00:00
|
|
|
TOOL_EVENT evt( TC_COMMAND, TA_CHOICE_MENU_CLOSED );
|
2019-10-03 15:55:05 +00:00
|
|
|
evt.SetHasPosition( false );
|
2017-02-24 15:39:52 +00:00
|
|
|
evt.SetParameter( m );
|
|
|
|
dispatchInternal( evt );
|
|
|
|
|
2018-01-26 14:53:28 +00:00
|
|
|
m_menuActive = false;
|
|
|
|
m_menuOwner = -1;
|
|
|
|
|
2018-02-02 15:20:14 +00:00
|
|
|
// Restore cursor settings
|
2022-08-25 22:50:47 +00:00
|
|
|
for( const std::pair<const TOOL_ID, std::optional<VECTOR2D>>& cursorSetting : m_cursorSettings )
|
2017-02-24 15:39:52 +00:00
|
|
|
{
|
2018-02-02 15:20:14 +00:00
|
|
|
auto it = m_toolIdIndex.find( cursorSetting.first );
|
|
|
|
wxASSERT( it != m_toolIdIndex.end() );
|
|
|
|
|
|
|
|
if( it == m_toolIdIndex.end() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
KIGFX::VC_SETTINGS& vc = it->second->vcSettings;
|
|
|
|
vc.m_forceCursorPosition = (bool) cursorSetting.second;
|
|
|
|
vc.m_forcedPosition = cursorSetting.second ? *cursorSetting.second : VECTOR2D( 0, 0 );
|
2013-10-14 11:43:57 +00:00
|
|
|
}
|
2017-02-24 15:39:52 +00:00
|
|
|
|
2018-02-02 15:20:14 +00:00
|
|
|
m_cursorSettings.clear();
|
2017-02-24 15:39:52 +00:00
|
|
|
break;
|
2013-10-14 11:43:57 +00:00
|
|
|
}
|
2014-07-09 11:50:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-11 20:26:08 +00:00
|
|
|
TOOL_MANAGER::ID_LIST::iterator TOOL_MANAGER::finishTool( TOOL_STATE* aState )
|
2014-07-09 11:50:27 +00:00
|
|
|
{
|
2017-02-11 20:26:08 +00:00
|
|
|
auto it = std::find( m_activeTools.begin(), m_activeTools.end(), aState->theTool->GetId() );
|
2016-07-04 14:12:21 +00:00
|
|
|
|
2017-02-11 20:26:08 +00:00
|
|
|
if( !aState->Pop() )
|
|
|
|
{
|
|
|
|
// Deactivate the tool if there are no other contexts saved on the stack
|
|
|
|
if( it != m_activeTools.end() )
|
|
|
|
it = m_activeTools.erase( it );
|
2018-05-17 14:04:52 +00:00
|
|
|
|
|
|
|
aState->idle = true;
|
2014-07-09 11:50:27 +00:00
|
|
|
}
|
2015-04-30 08:46:03 +00:00
|
|
|
|
2018-02-14 14:09:10 +00:00
|
|
|
if( aState == m_activeState )
|
|
|
|
setActiveState( nullptr );
|
|
|
|
|
2020-04-16 20:57:19 +00:00
|
|
|
return it;
|
2014-07-09 11:50:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-05-03 19:55:58 +00:00
|
|
|
bool TOOL_MANAGER::ProcessEvent( const TOOL_EVENT& aEvent )
|
2014-07-09 11:50:27 +00:00
|
|
|
{
|
2022-07-15 23:37:33 +00:00
|
|
|
// Once the tool manager is shutting down, don't start
|
|
|
|
// activating more tools
|
|
|
|
if( m_shuttingDown )
|
|
|
|
return true;
|
|
|
|
|
2020-05-03 19:55:58 +00:00
|
|
|
bool handled = processEvent( aEvent );
|
2013-08-02 14:46:53 +00:00
|
|
|
|
2019-07-09 20:38:18 +00:00
|
|
|
TOOL_STATE* activeTool = GetCurrentToolState();
|
|
|
|
|
|
|
|
if( activeTool )
|
|
|
|
setActiveState( activeTool );
|
2014-07-09 14:25:50 +00:00
|
|
|
|
2019-06-09 13:12:44 +00:00
|
|
|
if( m_view && m_view->IsDirty() )
|
2013-10-14 11:43:57 +00:00
|
|
|
{
|
2020-10-31 13:44:50 +00:00
|
|
|
#if defined( __WXMAC__ )
|
2017-12-12 17:16:24 +00:00
|
|
|
wxTheApp->ProcessPendingEvents(); // required for updating brightening behind a popup menu
|
|
|
|
#endif
|
2013-10-14 11:43:57 +00:00
|
|
|
}
|
2017-10-06 07:23:13 +00:00
|
|
|
|
2019-06-11 08:47:47 +00:00
|
|
|
UpdateUI( aEvent );
|
2019-05-14 19:21:10 +00:00
|
|
|
|
2019-07-09 20:38:18 +00:00
|
|
|
return handled;
|
2013-08-02 14:46:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-06 08:30:09 +00:00
|
|
|
|
2019-05-14 11:14:00 +00:00
|
|
|
void TOOL_MANAGER::ScheduleContextMenu( TOOL_BASE* aTool, ACTION_MENU* aMenu,
|
2013-09-02 12:21:12 +00:00
|
|
|
CONTEXT_MENU_TRIGGER aTrigger )
|
2013-08-02 14:46:53 +00:00
|
|
|
{
|
2013-10-14 11:43:57 +00:00
|
|
|
TOOL_STATE* st = m_toolState[aTool];
|
|
|
|
|
|
|
|
st->contextMenu = aMenu;
|
|
|
|
st->contextMenuTrigger = aTrigger;
|
2013-08-02 14:46:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-06 08:30:09 +00:00
|
|
|
|
2020-11-21 09:59:25 +00:00
|
|
|
bool TOOL_MANAGER::SaveClipboard( const std::string& aTextUTF8 )
|
2014-07-09 12:01:07 +00:00
|
|
|
{
|
2021-01-29 19:13:12 +00:00
|
|
|
wxLogNull doNotLog; // disable logging of failed clipboard actions
|
|
|
|
|
2014-07-09 12:01:07 +00:00
|
|
|
if( wxTheClipboard->Open() )
|
|
|
|
{
|
2021-07-15 19:26:35 +00:00
|
|
|
// Store the UTF8 string as Unicode string in clipboard:
|
2020-11-21 09:59:25 +00:00
|
|
|
wxTheClipboard->SetData( new wxTextDataObject( wxString( aTextUTF8.c_str(),
|
2020-12-05 18:03:03 +00:00
|
|
|
wxConvUTF8 ) ) );
|
2021-05-01 22:00:08 +00:00
|
|
|
|
|
|
|
wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
|
2014-07-09 12:01:07 +00:00
|
|
|
wxTheClipboard->Close();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-21 09:59:25 +00:00
|
|
|
std::string TOOL_MANAGER::GetClipboardUTF8() const
|
2014-07-09 12:01:07 +00:00
|
|
|
{
|
|
|
|
std::string result;
|
|
|
|
|
2021-01-29 19:13:12 +00:00
|
|
|
wxLogNull doNotLog; // disable logging of failed clipboard actions
|
|
|
|
|
2014-07-09 12:01:07 +00:00
|
|
|
if( wxTheClipboard->Open() )
|
|
|
|
{
|
2020-11-04 23:12:59 +00:00
|
|
|
if( wxTheClipboard->IsSupported( wxDF_TEXT )
|
|
|
|
|| wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
|
2014-07-09 12:01:07 +00:00
|
|
|
{
|
|
|
|
wxTextDataObject data;
|
|
|
|
wxTheClipboard->GetData( data );
|
|
|
|
|
2021-07-15 19:26:35 +00:00
|
|
|
// The clipboard is expected containing a Unicode string, so return it
|
2020-11-21 09:59:25 +00:00
|
|
|
// as UTF8 string
|
|
|
|
result = data.GetText().utf8_str();
|
2014-07-09 12:01:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
wxTheClipboard->Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-24 13:20:35 +00:00
|
|
|
const KIGFX::VC_SETTINGS& TOOL_MANAGER::GetCurrentToolVC() const
|
2018-04-24 10:55:33 +00:00
|
|
|
{
|
|
|
|
if( TOOL_STATE* active = GetCurrentToolState() )
|
|
|
|
return active->vcSettings;
|
|
|
|
|
|
|
|
return m_viewControls->GetSettings();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-06 08:30:09 +00:00
|
|
|
TOOL_ID TOOL_MANAGER::MakeToolId( const std::string& aToolName )
|
2013-08-02 14:46:53 +00:00
|
|
|
{
|
2013-10-14 11:43:57 +00:00
|
|
|
static int currentId;
|
2013-10-14 14:13:35 +00:00
|
|
|
|
2013-10-14 11:43:57 +00:00
|
|
|
return currentId++;
|
2013-08-02 14:46:53 +00:00
|
|
|
}
|
|
|
|
|
2013-08-07 08:52:50 +00:00
|
|
|
|
2013-10-14 14:13:35 +00:00
|
|
|
void TOOL_MANAGER::SetEnvironment( EDA_ITEM* aModel, KIGFX::VIEW* aView,
|
2020-06-12 10:58:56 +00:00
|
|
|
KIGFX::VIEW_CONTROLS* aViewControls,
|
|
|
|
APP_SETTINGS_BASE* aSettings, TOOLS_HOLDER* aFrame )
|
2013-08-02 14:46:53 +00:00
|
|
|
{
|
2013-10-14 11:43:57 +00:00
|
|
|
m_model = aModel;
|
|
|
|
m_view = aView;
|
|
|
|
m_viewControls = aViewControls;
|
2019-06-09 12:18:11 +00:00
|
|
|
m_frame = aFrame;
|
2020-06-12 10:58:56 +00:00
|
|
|
m_settings = aSettings;
|
2013-08-02 14:46:53 +00:00
|
|
|
}
|
2013-09-19 15:02:57 +00:00
|
|
|
|
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
bool TOOL_MANAGER::isActive( TOOL_BASE* aTool ) const
|
2013-09-19 15:02:57 +00:00
|
|
|
{
|
|
|
|
if( !isRegistered( aTool ) )
|
|
|
|
return false;
|
|
|
|
|
2014-01-07 13:11:53 +00:00
|
|
|
// Just check if the tool is on the active tools stack
|
2020-09-26 13:42:40 +00:00
|
|
|
return alg::contains( m_activeTools, aTool->GetId() );
|
2013-09-19 15:02:57 +00:00
|
|
|
}
|
2017-03-02 11:02:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
void TOOL_MANAGER::saveViewControls( TOOL_STATE* aState )
|
|
|
|
{
|
|
|
|
aState->vcSettings = m_viewControls->GetSettings();
|
|
|
|
|
2017-03-06 10:49:52 +00:00
|
|
|
if( m_menuActive )
|
2017-03-02 11:02:10 +00:00
|
|
|
{
|
2019-06-05 19:15:57 +00:00
|
|
|
// Context menu is active, so the cursor settings are overridden (see DispatchContextMenu())
|
2018-02-02 15:20:14 +00:00
|
|
|
auto it = m_cursorSettings.find( aState->theTool->GetId() );
|
|
|
|
|
|
|
|
if( it != m_cursorSettings.end() )
|
2017-03-06 10:49:52 +00:00
|
|
|
{
|
2018-02-02 15:20:14 +00:00
|
|
|
const KIGFX::VC_SETTINGS& curr = m_viewControls->GetSettings();
|
|
|
|
|
|
|
|
// Tool has overridden the cursor position, so store the new settings
|
|
|
|
if( !curr.m_forceCursorPosition || curr.m_forcedPosition != m_menuCursor )
|
|
|
|
{
|
|
|
|
if( !curr.m_forceCursorPosition )
|
2022-08-25 22:50:47 +00:00
|
|
|
it->second = std::nullopt;
|
2018-02-02 15:20:14 +00:00
|
|
|
else
|
|
|
|
it->second = curr.m_forcedPosition;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-08-25 22:50:47 +00:00
|
|
|
std::optional<VECTOR2D> cursor = it->second;
|
2018-02-02 15:20:14 +00:00
|
|
|
|
|
|
|
if( cursor )
|
|
|
|
{
|
|
|
|
aState->vcSettings.m_forceCursorPosition = true;
|
|
|
|
aState->vcSettings.m_forcedPosition = *cursor;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
aState->vcSettings.m_forceCursorPosition = false;
|
|
|
|
}
|
|
|
|
}
|
2017-03-06 10:49:52 +00:00
|
|
|
}
|
2017-03-02 11:02:10 +00:00
|
|
|
}
|
2017-03-06 10:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
void TOOL_MANAGER::applyViewControls( const TOOL_STATE* aState )
|
2017-03-06 10:49:52 +00:00
|
|
|
{
|
|
|
|
m_viewControls->ApplySettings( aState->vcSettings );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-05-03 19:55:58 +00:00
|
|
|
bool TOOL_MANAGER::processEvent( const TOOL_EVENT& aEvent )
|
2017-03-06 10:49:52 +00:00
|
|
|
{
|
2023-01-17 12:59:09 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::processEvent - %s" ), aEvent.Format() );
|
2019-07-27 14:11:41 +00:00
|
|
|
|
2019-08-05 12:19:44 +00:00
|
|
|
// First try to dispatch the action associated with the event if it is a key press event
|
2020-05-03 19:55:58 +00:00
|
|
|
bool handled = DispatchHotKey( aEvent );
|
2019-07-09 20:38:18 +00:00
|
|
|
|
2019-08-05 12:19:44 +00:00
|
|
|
if( !handled )
|
|
|
|
{
|
2020-02-11 15:12:36 +00:00
|
|
|
TOOL_EVENT mod_event( aEvent );
|
|
|
|
|
|
|
|
// Only immediate actions get the position. Otherwise clear for tool activation
|
2020-03-24 01:01:23 +00:00
|
|
|
if( GetToolHolder() && !GetToolHolder()->GetDoImmediateActions() )
|
2020-02-11 15:12:36 +00:00
|
|
|
{
|
|
|
|
// An tool-selection-event has no position
|
2022-09-19 23:07:49 +00:00
|
|
|
if( !mod_event.getCommandStr().empty()
|
|
|
|
&& mod_event.getCommandStr() != GetToolHolder()->CurrentToolName()
|
|
|
|
&& !mod_event.ForceImmediate() )
|
2020-02-11 15:12:36 +00:00
|
|
|
{
|
|
|
|
mod_event.SetHasPosition( false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-05 12:19:44 +00:00
|
|
|
// If the event is not handled through a hotkey activation, pass it to the currently
|
|
|
|
// running tool loops
|
2020-02-11 15:12:36 +00:00
|
|
|
handled |= dispatchInternal( mod_event );
|
|
|
|
handled |= dispatchActivation( mod_event );
|
2019-07-09 20:38:18 +00:00
|
|
|
|
2019-08-05 12:19:44 +00:00
|
|
|
// Open the context menu if requested by a tool
|
2020-02-11 15:12:36 +00:00
|
|
|
DispatchContextMenu( mod_event );
|
2017-03-06 10:49:52 +00:00
|
|
|
|
2019-08-05 12:19:44 +00:00
|
|
|
// Dispatch any remaining events in the event queue
|
|
|
|
while( !m_eventQueue.empty() )
|
|
|
|
{
|
|
|
|
TOOL_EVENT event = m_eventQueue.front();
|
|
|
|
m_eventQueue.pop_front();
|
|
|
|
processEvent( event );
|
|
|
|
}
|
2017-03-02 11:02:10 +00:00
|
|
|
}
|
2017-10-06 07:23:13 +00:00
|
|
|
|
2023-01-17 12:42:30 +00:00
|
|
|
wxLogTrace( kicadTraceToolStack, wxS( "TOOL_MANAGER::processEvent - %s handle event: %s" ),
|
2020-12-07 22:03:43 +00:00
|
|
|
( handled ? "Did" : "Did not" ), aEvent.Format() );
|
2019-07-27 14:11:41 +00:00
|
|
|
|
2019-07-09 20:38:18 +00:00
|
|
|
return handled;
|
2017-03-02 11:02:10 +00:00
|
|
|
}
|
2017-08-29 23:15:23 +00:00
|
|
|
|
2018-02-02 15:20:14 +00:00
|
|
|
|
2018-02-14 14:09:10 +00:00
|
|
|
void TOOL_MANAGER::setActiveState( TOOL_STATE* aState )
|
|
|
|
{
|
2019-06-09 13:12:44 +00:00
|
|
|
if( m_activeState && m_viewControls )
|
2018-02-14 14:09:10 +00:00
|
|
|
saveViewControls( m_activeState );
|
|
|
|
|
|
|
|
m_activeState = aState;
|
|
|
|
|
2019-06-09 13:12:44 +00:00
|
|
|
if( m_activeState && m_viewControls )
|
2018-02-14 14:09:10 +00:00
|
|
|
applyViewControls( aState );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-08-29 23:15:23 +00:00
|
|
|
bool TOOL_MANAGER::IsToolActive( TOOL_ID aId ) const
|
|
|
|
{
|
|
|
|
auto it = m_toolIdIndex.find( aId );
|
2023-06-03 11:28:03 +00:00
|
|
|
|
|
|
|
wxCHECK( it != m_toolIdIndex.end(), false );
|
|
|
|
|
2017-08-29 23:15:23 +00:00
|
|
|
return !it->second->idle;
|
|
|
|
}
|
2019-05-13 20:42:40 +00:00
|
|
|
|
|
|
|
|
2019-06-11 08:47:47 +00:00
|
|
|
void TOOL_MANAGER::UpdateUI( const TOOL_EVENT& aEvent )
|
2019-05-13 20:42:40 +00:00
|
|
|
{
|
2020-03-24 01:01:23 +00:00
|
|
|
EDA_BASE_FRAME* frame = dynamic_cast<EDA_BASE_FRAME*>( GetToolHolder() );
|
2019-05-13 20:42:40 +00:00
|
|
|
|
|
|
|
if( frame )
|
|
|
|
frame->UpdateStatusBar();
|
|
|
|
}
|