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.
This commit is contained in:
Maciej Suminski 2013-09-26 18:38:58 +02:00
parent e6c20adc5a
commit 87b3f2e499
11 changed files with 175 additions and 49 deletions

View File

@ -26,6 +26,7 @@
#include <tool/tool_manager.h>
#include <tool/tool_event.h>
#include <tool/tool_action.h>
#include <cassert>
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;

View File

@ -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 );

View File

@ -129,7 +129,21 @@ void TOOL_MANAGER::RegisterTool( TOOL_BASE* aTool )
aTool->m_toolMgr = this;
if( aTool->GetType() == TOOL_Interactive )
static_cast<TOOL_INTERACTIVE*>( aTool )->Reset();
{
bool initState = static_cast<TOOL_INTERACTIVE*>( 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;
}
}
}

View File

@ -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()

View File

@ -27,6 +27,7 @@
#include <wx/menu.h>
#include <tool/tool_action.h>
#include <map>
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<int, const TOOL_ACTION*> m_toolActions;
};
#endif

View File

@ -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()
*

View File

@ -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<SELECTION_TOOL*>( 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;
}

View File

@ -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()
*

View File

@ -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 );

View File

@ -25,6 +25,7 @@
#include <boost/foreach.hpp>
#include <boost/optional.hpp>
#include <cassert>
#include <class_drawpanel_gal.h>
#include <class_board.h>
@ -37,7 +38,6 @@
#include <view/view_controls.h>
#include <painter.h>
#include <tool/context_menu.h>
#include <tool/tool_event.h>
#include <tool/tool_manager.h>
@ -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<BOARD>( 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<BRIGHT_BOX> 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;
}

View File

@ -31,6 +31,7 @@
#include <math/vector2d.h>
#include <tool/tool_interactive.h>
#include <tool/tool_action.h>
#include <tool/context_menu.h>
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