From 87b3f2e499f473c9124ee7a21c2a6c421aac12b8 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 26 Sep 2013 18:38:58 +0200 Subject: [PATCH] Added Init() to TOOL_INTERACTIVE, allowing to set up things that are needed to be initialized only once. TOOL_ACTIONs can be run from CONTEXT_MENU after adding them. Move tool actions are available to be run from CONTEXT_MENU displayed after right mouse button click on selected items. Added some asserts to check the code. --- common/tool/action_manager.cpp | 11 +++---- common/tool/context_menu.cpp | 34 +++++++++++++++++---- common/tool/tool_manager.cpp | 16 +++++++++- include/tool/action_manager.h | 1 - include/tool/context_menu.h | 9 +++++- include/tool/tool_interactive.h | 11 +++++++ pcbnew/tools/move_tool.cpp | 29 ++++++++++++------ pcbnew/tools/move_tool.h | 9 +++--- pcbnew/tools/pcb_tools.cpp | 2 +- pcbnew/tools/selection_tool.cpp | 50 ++++++++++++++++++++++--------- pcbnew/tools/selection_tool.h | 52 +++++++++++++++++++++++++++++---- 11 files changed, 175 insertions(+), 49 deletions(-) diff --git a/common/tool/action_manager.cpp b/common/tool/action_manager.cpp index 2cd67b8464..0c56199711 100644 --- a/common/tool/action_manager.cpp +++ b/common/tool/action_manager.cpp @@ -26,6 +26,7 @@ #include #include #include +#include ACTION_MANAGER::ACTION_MANAGER( TOOL_MANAGER* aToolManager ) : m_toolMgr( aToolManager ) @@ -33,15 +34,11 @@ ACTION_MANAGER::ACTION_MANAGER( TOOL_MANAGER* aToolManager ) : } -ACTION_MANAGER::~ACTION_MANAGER() -{ -} - - void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction ) { - int aId = MakeActionId( aAction->m_name ); - aAction->setId( aId ); + assert( aAction->GetId() == -1 ); // Check if the TOOL_ACTION was not registered before + + aAction->setId( MakeActionId( aAction->m_name ) ); m_actionNameIndex[aAction->m_name] = aAction; m_actionIdIndex[aAction->m_id] = aAction; diff --git a/common/tool/context_menu.cpp b/common/tool/context_menu.cpp index 1751bde93b..25ef5b0a0f 100644 --- a/common/tool/context_menu.cpp +++ b/common/tool/context_menu.cpp @@ -61,6 +61,9 @@ CONTEXT_MENU::CONTEXT_MENU( const CONTEXT_MENU& aMenu ) : m_menu.Append( new wxMenuItem( &m_menu, item->GetId(), item->GetItemLabel(), wxEmptyString, wxITEM_NORMAL ) ); } + + // Copy tool actions that are available to choose from menu + m_toolActions = aMenu.m_toolActions; } @@ -86,11 +89,20 @@ void CONTEXT_MENU::Add( const wxString& aLabel, int aId ) } -void CONTEXT_MENU::Add( const TOOL_ACTION& aAction, int aId ) +void CONTEXT_MENU::Add( const TOOL_ACTION& aAction ) { - m_menu.Append( new wxMenuItem( &m_menu, aId, - wxString( aAction.GetDescription() + '\t' + getHotKeyDescription( aAction ) ), - wxEmptyString, wxITEM_NORMAL ) ); + int id = m_actionId + aAction.GetId(); + wxString menuEntry; + + if( aAction.HasHotKey() ) + menuEntry = wxString( aAction.GetMenuItem() + '\t' + getHotKeyDescription( aAction ) ); + else + menuEntry = wxString( aAction.GetMenuItem() ); + + m_menu.Append( new wxMenuItem( &m_menu, id, menuEntry, + wxString( aAction.GetDescription() ), wxITEM_NORMAL ) ); + + m_toolActions[id] = &aAction; } @@ -100,6 +112,8 @@ void CONTEXT_MENU::Clear() for( unsigned i = 0; i < m_menu.GetMenuItemCount(); ++i ) m_menu.Destroy( m_menu.FindItemByPosition( 0 ) ); + + m_toolActions.clear(); } @@ -131,7 +145,17 @@ void CONTEXT_MENU::CMEventHandler::onEvent( wxEvent& aEvent ) if( type == wxEVT_MENU_HIGHLIGHT ) evt = TOOL_EVENT( TC_Command, TA_ContextMenuUpdate, aEvent.GetId() ); else if( type == wxEVT_COMMAND_MENU_SELECTED ) - evt = TOOL_EVENT( TC_Command, TA_ContextMenuChoice, aEvent.GetId() ); + { + if( aEvent.GetId() > m_actionId ) + { + if( m_menu->m_toolActions.count( aEvent.GetId() ) == 1 ) + evt = m_menu->m_toolActions[aEvent.GetId()]->GetEvent(); + } + else + { + evt = TOOL_EVENT( TC_Command, TA_ContextMenuChoice, aEvent.GetId() ); + } + } if( m_menu->m_tool ) m_menu->m_tool->GetManager()->ProcessEvent( evt ); diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp index 20333af66d..e261e37c2c 100644 --- a/common/tool/tool_manager.cpp +++ b/common/tool/tool_manager.cpp @@ -129,7 +129,21 @@ void TOOL_MANAGER::RegisterTool( TOOL_BASE* aTool ) aTool->m_toolMgr = this; if( aTool->GetType() == TOOL_Interactive ) - static_cast( aTool )->Reset(); + { + bool initState = static_cast( aTool )->Init(); + if( !initState ) + { + wxLogError( wxT( "Initialization of the %s tool failed" ), aTool->GetName() ); + + // Unregister the tool + m_toolState.erase( aTool ); + m_toolNameIndex.erase( aTool->GetName() ); + m_toolIdIndex.erase( aTool->GetId() ); + + delete st; + delete aTool; + } + } } diff --git a/include/tool/action_manager.h b/include/tool/action_manager.h index c21d8f33ae..78943a92fa 100644 --- a/include/tool/action_manager.h +++ b/include/tool/action_manager.h @@ -40,7 +40,6 @@ public: * @param aToolManager is a tool manager instance that is used to pass events to tools. */ ACTION_MANAGER( TOOL_MANAGER* aToolManager ); - ~ACTION_MANAGER(); /** * Function RegisterAction() diff --git a/include/tool/context_menu.h b/include/tool/context_menu.h index cb518feb69..cf4d752405 100644 --- a/include/tool/context_menu.h +++ b/include/tool/context_menu.h @@ -27,6 +27,7 @@ #include #include +#include class wxMenu; class TOOL_INTERACTIVE; @@ -46,7 +47,7 @@ public: void SetTitle( const wxString& aTitle ); void Add( const wxString& aLabel, int aId ); - void Add( const TOOL_ACTION& aAction, int aId = -1 ); + void Add( const TOOL_ACTION& aAction ); void Clear(); wxMenu* GetMenu() const @@ -87,6 +88,12 @@ private: wxMenu m_menu; CMEventHandler m_handler; TOOL_INTERACTIVE* m_tool; + + /// Menu items with ID higher than that are considered TOOL_ACTIONs + static const int m_actionId = 10000; + + /// Stores tool actions that are choosable from the menu. Does not take the ownership. + std::map m_toolActions; }; #endif diff --git a/include/tool/tool_interactive.h b/include/tool/tool_interactive.h index 0a2be56f10..14fd2dccbb 100644 --- a/include/tool/tool_interactive.h +++ b/include/tool/tool_interactive.h @@ -51,6 +51,17 @@ public: */ virtual void Reset() = 0; + /** + * Function Init() + * Init() is called once upon a registration of the tool. + * + * @return True if the initialization went fine, false - otherwise. + */ + virtual bool Init() + { + return true; + } + /** * Function SetContextMenu() * diff --git a/pcbnew/tools/move_tool.cpp b/pcbnew/tools/move_tool.cpp index b1fdd28c0b..96e348a941 100644 --- a/pcbnew/tools/move_tool.cpp +++ b/pcbnew/tools/move_tool.cpp @@ -49,27 +49,38 @@ MOVE_TOOL::~MOVE_TOOL() void MOVE_TOOL::Reset() +{ + // The tool launches upon reception of action event ("pcbnew.InteractiveMove") + Go( &MOVE_TOOL::Main, m_activate.GetEvent() ); +} + + +bool MOVE_TOOL::Init() { // Find the selection tool, so they can cooperate - TOOL_BASE* selectionTool = m_toolMgr->FindTool( std::string( "pcbnew.InteractiveSelection" ) ); + TOOL_BASE* selectionTool = m_toolMgr->FindTool( "pcbnew.InteractiveSelection" ); if( selectionTool ) { m_selectionTool = static_cast( selectionTool ); + + // Activate hot keys + m_toolMgr->RegisterAction( &m_activate ); + m_toolMgr->RegisterAction( &m_rotate ); + m_toolMgr->RegisterAction( &m_flip ); + + // Add context menu entries for the selection tool + m_selectionTool->AddMenuItem( m_activate ); + m_selectionTool->AddMenuItem( m_rotate ); + m_selectionTool->AddMenuItem( m_flip ); } else { wxLogError( "pcbnew.InteractiveSelection tool is not available" ); - return; + return false; } - // Activate hotkeys - m_toolMgr->RegisterAction( &m_activate ); - m_toolMgr->RegisterAction( &m_rotate ); - m_toolMgr->RegisterAction( &m_flip ); - - // the tool launches upon reception of action event ("pcbnew.InteractiveMove") - Go( &MOVE_TOOL::Main, m_activate.GetEvent() ); + return true; } diff --git a/pcbnew/tools/move_tool.h b/pcbnew/tools/move_tool.h index 400af0d077..fdb0e2e450 100644 --- a/pcbnew/tools/move_tool.h +++ b/pcbnew/tools/move_tool.h @@ -51,13 +51,12 @@ public: MOVE_TOOL(); ~MOVE_TOOL(); - /** - * Function Reset() - * - * Resets the tool and initializes it. - */ + /// @copydoc TOOL_INTERACTIVE::Reset() void Reset(); + /// @copydoc TOOL_INTERACTIVE::Init() + bool Init(); + /** * Function Main() * diff --git a/pcbnew/tools/pcb_tools.cpp b/pcbnew/tools/pcb_tools.cpp index 9d2457c5ec..0cece9dffd 100644 --- a/pcbnew/tools/pcb_tools.cpp +++ b/pcbnew/tools/pcb_tools.cpp @@ -45,7 +45,7 @@ void PCB_EDIT_FRAME::setupTools() m_toolDispatcher = new TOOL_DISPATCHER( m_toolManager, this ); m_galCanvas->SetEventDispatcher( m_toolDispatcher ); - // Register tools. + // Register tools m_toolManager->RegisterTool( new SELECTION_TOOL ); m_toolManager->RegisterTool( new ROUTER_TOOL ); m_toolManager->RegisterTool( new MOVE_TOOL ); diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index c3c1467f74..72cc54a1be 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -37,7 +38,6 @@ #include #include -#include #include #include @@ -65,7 +65,6 @@ SELECTION_TOOL::~SELECTION_TOOL() void SELECTION_TOOL::Reset() { - m_toolMgr->RegisterAction( &m_activate ); m_selectedItems.clear(); // The tool launches upon reception of action event ("pcbnew.InteractiveSelection") @@ -73,11 +72,19 @@ void SELECTION_TOOL::Reset() } +bool SELECTION_TOOL::Init() +{ + m_toolMgr->RegisterAction( &m_activate ); + + return true; +} + + int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) { BOARD* board = getModel( PCB_T ); - wxASSERT( board != NULL ); + assert( board != NULL ); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) @@ -91,7 +98,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) if( !m_selectedItems.empty() ) // Cancel event deselects items... clearSelection(); else // ...unless there is nothing selected - break; + break; // then exit the tool } // single click? Select single object @@ -126,12 +133,19 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) } +void SELECTION_TOOL::AddMenuItem( const TOOL_ACTION& aAction ) +{ + assert( aAction.GetId() > 0 ); // Check if the action was registered before + + m_menu.Add( aAction ); +} + + void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) { if( m_selectedItems.find( aItem ) != m_selectedItems.end() ) { - aItem->ClearSelected(); - m_selectedItems.erase( aItem ); + deselectItem( aItem ); } else { @@ -140,10 +154,7 @@ void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) // Prevent selection of invisible or inactive items if( selectable( aItem ) ) - { - aItem->SetSelected(); - m_selectedItems.insert( aItem ); - } + selectItem( aItem ); } } @@ -156,6 +167,9 @@ void SELECTION_TOOL::clearSelection() } m_selectedItems.clear(); + + // Do not show the context menu when there is nothing selected + SetContextMenu( &m_menu, CMENU_OFF ); } @@ -198,6 +212,7 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) else if( collector.GetCount() > 1 ) { item = disambiguationMenu( &collector ); + if( item ) toggleSelection( item ); } @@ -296,6 +311,10 @@ bool SELECTION_TOOL::selectMultiple() m_selectedItems.insert( item ); } } + + // Now the context menu should be enabled + if( !m_selectedItems.empty() ) + SetContextMenu( &m_menu, CMENU_BUTTON ); break; } } @@ -312,7 +331,7 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) { BOARD_ITEM* current = NULL; boost::shared_ptr brightBox; - CONTEXT_MENU m_menu; + CONTEXT_MENU menu; int limit = std::min( 10, aCollector->GetCount() ); for( int i = 0; i < limit; ++i ) @@ -320,11 +339,11 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) wxString text; BOARD_ITEM* item = ( *aCollector )[i]; text = item->GetSelectMenuText(); - m_menu.Add( text, i ); + menu.Add( text, i ); } - m_menu.SetTitle( _( "Clarify selection" ) ); - SetContextMenu( &m_menu, CMENU_NOW ); + menu.SetTitle( _( "Clarify selection" ) ); + SetContextMenu( &menu, CMENU_NOW ); while( OPT_TOOL_EVENT evt = Wait() ) { @@ -364,6 +383,9 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) getView()->MarkTargetDirty( TARGET_OVERLAY ); + // Restore the original menu + SetContextMenu( &m_menu, CMENU_BUTTON ); + return current; } diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 6540a57c99..928aa4bf6f 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -31,6 +31,7 @@ #include #include #include +#include class SELECTION_AREA; class BOARD_ITEM; @@ -54,13 +55,12 @@ public: SELECTION_TOOL(); ~SELECTION_TOOL(); - /** - * Function Reset() - * - * Initializes the selection tool. - */ + /// @copydoc TOOL_INTERACTIVE::Reset() void Reset(); + /// @copydoc TOOL_INTERACTIVE::Init() + bool Init(); + /** * Function Main() * @@ -78,6 +78,14 @@ public: return m_selectedItems; } + /** + * Function AddAction() + * + * Adds a menu entry to run a TOOL_ACTION on selected items. + * @param aAction is a menu entry to be added. + */ + void AddMenuItem( const TOOL_ACTION& aAction ); + private: /** * Function selectSingle() @@ -135,6 +143,37 @@ private: */ bool selectable( const BOARD_ITEM* aItem ) const; + /** + * Function selectItem() + * Takes necessary action mark an item as selected. + * + * @param aItem is an item to be selected. + */ + void selectItem( BOARD_ITEM* aItem ) + { + aItem->SetSelected(); + m_selectedItems.insert( aItem ); + + // Now the context menu should be enabled + SetContextMenu( &m_menu, CMENU_BUTTON ); + } + + /** + * Function deselectItem() + * Takes necessary action mark an item as deselected. + * + * @param aItem is an item to be deselected. + */ + void deselectItem( BOARD_ITEM* aItem ) + { + aItem->ClearSelected(); + m_selectedItems.erase( aItem ); + + if( m_selectedItems.empty() ) + // If there is nothing selected, disable the context menu + SetContextMenu( &m_menu, CMENU_OFF ); + } + /** * Function containsSelected() * Checks if the given point is placed within any of selected items' bounding box. @@ -157,6 +196,9 @@ private: /// Register hotkey fot activation of the selection tool TOOL_ACTION m_activate; + + /// Right click popup menu + CONTEXT_MENU m_menu; }; #endif