From 4be876a13afc6431dc9fc319aa81d17579806221 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 30 Apr 2015 10:46:04 +0200 Subject: [PATCH] Expandable CONTEXT_MENUs (GAL). Minor CONTEXT_MENU --- common/tool/context_menu.cpp | 139 +++++++++++++++++++------------- include/tool/context_menu.h | 41 +++++----- pcbnew/router/router_tool.cpp | 4 +- pcbnew/tools/selection_tool.cpp | 12 +-- pcbnew/tools/selection_tool.h | 4 +- 5 files changed, 114 insertions(+), 86 deletions(-) diff --git a/common/tool/context_menu.cpp b/common/tool/context_menu.cpp index 016911647f..08bada78e7 100644 --- a/common/tool/context_menu.cpp +++ b/common/tool/context_menu.cpp @@ -33,14 +33,11 @@ CONTEXT_MENU::CONTEXT_MENU() : m_titleSet( false ), m_selected( -1 ), m_tool( NULL ), m_icon( NULL ) { - setCustomEventHandler( boost::bind( &CONTEXT_MENU::handleCustomEvent, this, _1 ) ); setupEvents(); } -CONTEXT_MENU::CONTEXT_MENU( const CONTEXT_MENU& aMenu ) : - m_titleSet( aMenu.m_titleSet ), m_selected( -1 ), m_tool( aMenu.m_tool ), - m_toolActions( aMenu.m_toolActions ), m_customHandler( aMenu.m_customHandler ) +CONTEXT_MENU::CONTEXT_MENU( const CONTEXT_MENU& aMenu ) { copyFrom( aMenu ); setupEvents(); @@ -51,12 +48,6 @@ CONTEXT_MENU& CONTEXT_MENU::operator=( const CONTEXT_MENU& aMenu ) { Clear(); - m_titleSet = aMenu.m_titleSet; - m_selected = aMenu.m_selected; - m_tool = aMenu.m_tool; - m_toolActions = aMenu.m_toolActions; - m_customHandler = aMenu.m_customHandler; - copyFrom( aMenu ); setupEvents(); @@ -90,7 +81,7 @@ void CONTEXT_MENU::SetTitle( const wxString& aTitle ) } -void CONTEXT_MENU::Add( const wxString& aLabel, int aId, const BITMAP_OPAQUE* aIcon ) +wxMenuItem* CONTEXT_MENU::Add( const wxString& aLabel, int aId, const BITMAP_OPAQUE* aIcon ) { #ifdef DEBUG @@ -103,18 +94,18 @@ void CONTEXT_MENU::Add( const wxString& aLabel, int aId, const BITMAP_OPAQUE* aI if( aIcon ) item->SetBitmap( KiBitmap( aIcon ) ); - Append( item ); + return Append( item ); } -void CONTEXT_MENU::Add( const TOOL_ACTION& aAction ) +wxMenuItem* CONTEXT_MENU::Add( const TOOL_ACTION& aAction ) { - /// ID numbers for tool actions need to have a value higher than m_actionId - int id = m_actionId + aAction.GetId(); + /// ID numbers for tool actions need to have a value higher than ACTION_ID + int id = ACTION_ID + aAction.GetId(); const BITMAP_OPAQUE* icon = aAction.GetIcon(); - wxMenuItem* item = new wxMenuItem( this, id, - aAction.GetMenuItem(), aAction.GetDescription(), wxITEM_NORMAL ); + wxMenuItem* item = new wxMenuItem( this, id, aAction.GetMenuItem(), + aAction.GetDescription(), wxITEM_NORMAL ); if( icon ) item->SetBitmap( KiBitmap( icon ) ); @@ -136,24 +127,45 @@ void CONTEXT_MENU::Add( const TOOL_ACTION& aAction ) item->SetAccel( &accel ); } - Append( item ); m_toolActions[id] = &aAction; + + return Append( item ); } -void CONTEXT_MENU::Add( CONTEXT_MENU* aMenu, const wxString& aLabel ) +std::list CONTEXT_MENU::Add( CONTEXT_MENU* aMenu, const wxString& aLabel, bool aExpand ) { - if( aMenu->m_icon ) + std::list items; + + if( aExpand ) { - wxMenuItem* newItem = new wxMenuItem( this, -1, aLabel, wxEmptyString, wxITEM_NORMAL ); - newItem->SetBitmap( KiBitmap( aMenu->m_icon ) ); - newItem->SetSubMenu( aMenu ); - Append( newItem ); + unsigned int i = 0; + + for( i = 0; i < aMenu->GetMenuItemCount(); ++i ) + { + wxMenuItem* item = aMenu->FindItemByPosition( i ); + items.push_back( appendCopy( item ) ); + } } else { - AppendSubMenu( aMenu, aLabel ); + if( aMenu->m_icon ) + { + wxMenuItem* newItem = new wxMenuItem( this, -1, aLabel, wxEmptyString, wxITEM_NORMAL ); + newItem->SetBitmap( KiBitmap( aMenu->m_icon ) ); + newItem->SetSubMenu( aMenu ); + items.push_back( Append( newItem ) ); + } + else + { + items.push_back( AppendSubMenu( aMenu, aLabel ) ); + } } + + m_toolActions.insert( aMenu->m_toolActions.begin(), aMenu->m_toolActions.end() ); + m_handlers.insert( m_handlers.end(), aMenu->m_handlers.begin(), aMenu->m_handlers.end() ); + + return items; } @@ -164,6 +176,7 @@ void CONTEXT_MENU::Clear() GetMenuItems().DeleteContents( true ); GetMenuItems().Clear(); m_toolActions.clear(); + m_handlers.clear(); GetMenuItems().DeleteContents( false ); // restore the default so destructor does not go wild assert( GetMenuItemCount() == 0 ); @@ -211,7 +224,14 @@ void CONTEXT_MENU::onMenuEvent( wxMenuEvent& aEvent ) } } #endif - evt = m_customHandler( aEvent ); + for( std::list::iterator it = m_handlers.begin(); + it != m_handlers.end(); ++it ) + { + evt = (*it)( aEvent ); + + if( evt ) + break; + } // Handling non-action menu entries (e.g. items in clarification list) if( !evt ) @@ -244,49 +264,56 @@ void CONTEXT_MENU::setTool( TOOL_INTERACTIVE* aTool ) } -void CONTEXT_MENU::copyItem( const wxMenuItem* aSource, wxMenuItem* aDest ) const +wxMenuItem* CONTEXT_MENU::appendCopy( const wxMenuItem* aSource ) { - assert( !aSource->IsSubMenu() ); // it does not transfer submenus + wxMenuItem* newItem = new wxMenuItem( this, aSource->GetId(), aSource->GetItemLabel(), + aSource->GetHelp(), aSource->GetKind() ); - aDest->SetKind( aSource->GetKind() ); - aDest->SetHelp( aSource->GetHelp() ); - aDest->Enable( aSource->IsEnabled() ); + if( aSource->GetKind() == wxITEM_NORMAL ) + newItem->SetBitmap( aSource->GetBitmap() ); - if( aSource->IsCheckable() ) - aDest->Check( aSource->IsChecked() ); + if( aSource->IsSubMenu() ) + { +#ifdef DEBUG + // Submenus of a CONTEXT_MENU are supposed to be CONTEXT_MENUs as well + assert( dynamic_cast( aSource->GetSubMenu() ) ); +#endif + + CONTEXT_MENU* menu = new CONTEXT_MENU( static_cast( *aSource->GetSubMenu() ) ); + newItem->SetSubMenu( menu ); + Append( newItem ); + + m_toolActions.insert( menu->m_toolActions.begin(), menu->m_toolActions.end() ); + m_handlers.insert( m_handlers.end(), menu->m_handlers.begin(), menu->m_handlers.end() ); + } + else + { + Append( newItem ); + newItem->SetKind( aSource->GetKind() ); + newItem->SetHelp( aSource->GetHelp() ); + newItem->Enable( aSource->IsEnabled() ); + + if( aSource->IsCheckable() ) + newItem->Check( aSource->IsChecked() ); + } + + return newItem; } void CONTEXT_MENU::copyFrom( const CONTEXT_MENU& aMenu ) { m_icon = aMenu.m_icon; + m_titleSet = aMenu.m_titleSet; + m_selected = -1; // aMenu.m_selected; + m_tool = aMenu.m_tool; + m_toolActions = aMenu.m_toolActions; + m_handlers = aMenu.m_handlers; // Copy all the menu entries for( unsigned i = 0; i < aMenu.GetMenuItemCount(); ++i ) { wxMenuItem* item = aMenu.FindItemByPosition( i ); - - wxMenuItem* newItem = new wxMenuItem( this, item->GetId(), item->GetItemLabel(), - item->GetHelp(), item->GetKind() ); - - if( item->GetKind() == wxITEM_NORMAL ) - newItem->SetBitmap( item->GetBitmap() ); - - if( item->IsSubMenu() ) - { -#ifdef DEBUG - // Submenus of a CONTEXT_MENU are supposed to be CONTEXT_MENUs as well - assert( dynamic_cast( item->GetSubMenu() ) ); -#endif - - CONTEXT_MENU* menu = new CONTEXT_MENU( static_cast( *item->GetSubMenu() ) ); - newItem->SetSubMenu( menu ); - Append( newItem ); - } - else - { - Append( newItem ); - copyItem( item, newItem ); - } + appendCopy( item ); } } diff --git a/include/tool/context_menu.h b/include/tool/context_menu.h index 7d629d14eb..5acf177cb0 100644 --- a/include/tool/context_menu.h +++ b/include/tool/context_menu.h @@ -77,7 +77,7 @@ public: * @param aId is the ID that is sent in the TOOL_EVENT. It should be unique for every entry. * @param aIcon is an optional icon. */ - void Add( const wxString& aLabel, int aId, const BITMAP_OPAQUE* aIcon = NULL ); + wxMenuItem* Add( const wxString& aLabel, int aId, const BITMAP_OPAQUE* aIcon = NULL ); /** * Function Add() @@ -85,7 +85,7 @@ public: * a TOOL_EVENT command containing name of the action is sent. * @param aAction is the action to be added to menu entry. */ - void Add( const TOOL_ACTION& aAction ); + wxMenuItem* Add( const TOOL_ACTION& aAction ); /** * Function Add() @@ -93,8 +93,10 @@ public: * is the capability to handle icons. * @param aMenu is the submenu to be added. * @param aLabel is the caption displayed for the menu entry. + * @param aExpand allows to add all entries from the menu as individual entries rather than + * add everything as a submenu. */ - void Add( CONTEXT_MENU* aMenu, const wxString& aLabel ); + std::list Add( CONTEXT_MENU* aMenu, const wxString& aLabel, bool aExpand = false ); /** * Function Clear() @@ -114,23 +116,21 @@ public: return m_selected; } -protected: - void setCustomEventHandler( boost::function aHandler ) - { - m_customHandler = aHandler; - } + ///> Function type to handle menu events in a custom way. + typedef boost::function CUSTOM_MENU_HANDLER; - virtual OPT_TOOL_EVENT handleCustomEvent( const wxMenuEvent& aEvent ) + ///> Adds an event handler to the custom menu event handlers chain. + void AppendCustomEventHandler( CUSTOM_MENU_HANDLER aHandler ) { - return OPT_TOOL_EVENT(); + m_handlers.push_back( aHandler ); } private: /** - * Function copyItem - * Copies all properties of a menu entry to another. + * Function appendCopy + * Appends a copy of wxMenuItem. */ - void copyItem( const wxMenuItem* aSource, wxMenuItem* aDest ) const; + wxMenuItem* appendCopy( const wxMenuItem* aSource ); ///> Common part of copy constructor and assignment operator. void copyFrom( const CONTEXT_MENU& aMenu ); @@ -154,22 +154,19 @@ private: ///> Stores the id number of selected item. int m_selected; - ///> Instance of menu event handler. - //CMEventHandler m_handler; - ///> Creator of the menu TOOL_INTERACTIVE* m_tool; - /// Menu items with ID higher than that are considered TOOL_ACTIONs - static const int m_actionId = 10000; + ///> Menu items with ID higher than that are considered TOOL_ACTIONs + static const int ACTION_ID = 30000; - /// Associates tool actions with menu item IDs. Non-owning. + ///> Associates tool actions with menu item IDs. Non-owning. std::map m_toolActions; - /// Custom events handler, allows to translate wxEvents to TOOL_EVENTs. - boost::function m_customHandler; + ///> Chain of custom menu event handlers. + std::list m_handlers; - /// Optional icon + ///> Optional icon const BITMAP_OPAQUE* m_icon; friend class TOOL_INTERACTIVE; diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index 1710df9eac..644e6efe5a 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -96,8 +96,8 @@ public: { m_board = NULL; SetIcon( width_track_via_xpm ); - setCustomEventHandler( boost::bind( &CONTEXT_TRACK_WIDTH_MENU::handleCustomEvent, - this, _1 ) ); + AppendCustomEventHandler( boost::bind( &CONTEXT_TRACK_WIDTH_MENU::handleCustomEvent, + this, _1 ) ); } void SetBoard( BOARD* aBoard ) diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 04c3ef0a97..f60bd845fa 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -242,7 +242,7 @@ int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) void SELECTION_TOOL::AddMenuItem( const TOOL_ACTION& aAction, const SELECTION_CONDITION& aCondition ) { - assert( aAction.GetId() > 0 ); // Check if the action was registered before in ACTION_MANAGER + assert( aAction.GetId() > 0 ); // Check if action was previously registered in ACTION_MANAGER m_menu.Add( aAction ); m_menuConditions.push_back( aCondition ); @@ -250,10 +250,12 @@ void SELECTION_TOOL::AddMenuItem( const TOOL_ACTION& aAction, const SELECTION_CO void SELECTION_TOOL::AddSubMenu( CONTEXT_MENU* aMenu, const wxString& aLabel, - const SELECTION_CONDITION& aCondition ) + const SELECTION_CONDITION& aCondition, bool aExpand ) { - m_menu.Add( aMenu, aLabel ); - m_menuConditions.push_back( aCondition ); + std::list items = m_menu.Add( aMenu, aLabel, aExpand ); + + for( unsigned int i = 0; i < items.size(); ++i ) + m_menuConditions.push_back( aCondition ); } @@ -1285,7 +1287,7 @@ void SELECTION_TOOL::generateMenu() assert( m_menuCopy.GetMenuItemCount() == m_menuConditions.size() ); - // Filter out entries that does not apply to the current selection + // Filter out entries that do not comply with the current selection for( int i = m_menuCopy.GetMenuItemCount() - 1; i >= 0; --i ) { try diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 0c5b701d24..bc726ed8b1 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -141,9 +141,11 @@ public: * @param aMenu is the submenu to be added. * @param aLabel is the label of added submenu. * @param aCondition is a condition that has to be fulfilled to enable the submenu entry. + * @param aExpand determines if the added submenu items should be added as individual items. */ void AddSubMenu( CONTEXT_MENU* aMenu, const wxString& aLabel, - const SELECTION_CONDITION& aCondition = SELECTION_CONDITIONS::ShowAlways ); + const SELECTION_CONDITION& aCondition = SELECTION_CONDITIONS::ShowAlways, + bool aExpand = false ); /** * Function EditModules()