Refactored CONTEXT_MENU, added handler for updating.
This commit is contained in:
parent
dfb0443b67
commit
06b978b829
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013 CERN
|
||||
* Copyright (C) 2013-2015 CERN
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -31,7 +32,9 @@
|
|||
#include <cassert>
|
||||
|
||||
CONTEXT_MENU::CONTEXT_MENU() :
|
||||
m_titleSet( false ), m_selected( -1 ), m_tool( NULL ), m_icon( NULL )
|
||||
m_titleSet( false ), m_selected( -1 ), m_tool( NULL ), m_parent( NULL ), m_icon( NULL ),
|
||||
m_menu_handler( CONTEXT_MENU::menuHandlerStub ),
|
||||
m_update_handler( CONTEXT_MENU::updateHandlerStub )
|
||||
{
|
||||
setupEvents();
|
||||
}
|
||||
|
@ -44,12 +47,22 @@ CONTEXT_MENU::CONTEXT_MENU( const CONTEXT_MENU& aMenu )
|
|||
}
|
||||
|
||||
|
||||
CONTEXT_MENU::~CONTEXT_MENU()
|
||||
{
|
||||
// Set parent to NULL to prevent submenus from unregistering from a notexisting object
|
||||
for( std::list<CONTEXT_MENU*>::iterator it = m_submenus.begin(); it != m_submenus.end(); ++it )
|
||||
(*it)->m_parent = NULL;
|
||||
|
||||
if( m_parent )
|
||||
m_parent->m_submenus.remove( this );
|
||||
}
|
||||
|
||||
|
||||
CONTEXT_MENU& CONTEXT_MENU::operator=( const CONTEXT_MENU& aMenu )
|
||||
{
|
||||
Clear();
|
||||
|
||||
copyFrom( aMenu );
|
||||
setupEvents();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -84,11 +97,11 @@ void CONTEXT_MENU::SetTitle( const wxString& aTitle )
|
|||
wxMenuItem* CONTEXT_MENU::Add( const wxString& aLabel, int aId, const BITMAP_OPAQUE* aIcon )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
|
||||
if( FindItem( aId ) != NULL )
|
||||
wxLogWarning( wxT( "Adding more than one menu entry with the same ID may result in"
|
||||
"undefined behaviour" ) );
|
||||
#endif
|
||||
|
||||
wxMenuItem* item = new wxMenuItem( this, aId, aLabel, wxEmptyString, wxITEM_NORMAL );
|
||||
|
||||
if( aIcon )
|
||||
|
@ -139,9 +152,7 @@ std::list<wxMenuItem*> CONTEXT_MENU::Add( CONTEXT_MENU* aMenu, const wxString& a
|
|||
|
||||
if( aExpand )
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
for( i = 0; i < aMenu->GetMenuItemCount(); ++i )
|
||||
for( unsigned int i = 0; i < aMenu->GetMenuItemCount(); ++i )
|
||||
{
|
||||
wxMenuItem* item = aMenu->FindItemByPosition( i );
|
||||
items.push_back( appendCopy( item ) );
|
||||
|
@ -162,8 +173,8 @@ std::list<wxMenuItem*> CONTEXT_MENU::Add( CONTEXT_MENU* aMenu, const wxString& a
|
|||
}
|
||||
}
|
||||
|
||||
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() );
|
||||
m_submenus.push_back( aMenu );
|
||||
aMenu->m_parent = this;
|
||||
|
||||
return items;
|
||||
}
|
||||
|
@ -176,13 +187,22 @@ 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
|
||||
m_submenus.clear();
|
||||
m_parent = NULL;
|
||||
|
||||
assert( GetMenuItemCount() == 0 );
|
||||
}
|
||||
|
||||
|
||||
void CONTEXT_MENU::UpdateAll()
|
||||
{
|
||||
m_update_handler();
|
||||
|
||||
runOnSubmenus( boost::bind( &CONTEXT_MENU::UpdateAll, _1 ) );
|
||||
}
|
||||
|
||||
|
||||
void CONTEXT_MENU::onMenuEvent( wxMenuEvent& aEvent )
|
||||
{
|
||||
OPT_TOOL_EVENT evt;
|
||||
|
@ -208,6 +228,8 @@ void CONTEXT_MENU::onMenuEvent( wxMenuEvent& aEvent )
|
|||
}
|
||||
else
|
||||
{
|
||||
runEventHandlers( aEvent, evt );
|
||||
|
||||
// Under Linux, every submenu can have a separate event handler, under
|
||||
// Windows all submenus are handled by the main menu.
|
||||
#ifdef __WINDOWS__
|
||||
|
@ -224,14 +246,6 @@ void CONTEXT_MENU::onMenuEvent( wxMenuEvent& aEvent )
|
|||
}
|
||||
}
|
||||
#endif
|
||||
for( std::list<CUSTOM_MENU_HANDLER>::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 )
|
||||
|
@ -251,16 +265,22 @@ void CONTEXT_MENU::setTool( TOOL_INTERACTIVE* aTool )
|
|||
{
|
||||
m_tool = aTool;
|
||||
|
||||
for( unsigned i = 0; i < GetMenuItemCount(); ++i )
|
||||
{
|
||||
wxMenuItem* item = FindItemByPosition( i );
|
||||
runOnSubmenus( boost::bind( &CONTEXT_MENU::setTool, _1, aTool ) );
|
||||
}
|
||||
|
||||
if( item->IsSubMenu() )
|
||||
{
|
||||
CONTEXT_MENU* menu = static_cast<CONTEXT_MENU*>( item->GetSubMenu() );
|
||||
menu->setTool( aTool );
|
||||
}
|
||||
}
|
||||
|
||||
void CONTEXT_MENU::runEventHandlers( const wxMenuEvent& aMenuEvent, OPT_TOOL_EVENT& aToolEvent )
|
||||
{
|
||||
aToolEvent = m_menu_handler( aMenuEvent );
|
||||
|
||||
if( !aToolEvent )
|
||||
runOnSubmenus( boost::bind( &CONTEXT_MENU::runEventHandlers, _1, aMenuEvent, aToolEvent ) );
|
||||
}
|
||||
|
||||
|
||||
void CONTEXT_MENU::runOnSubmenus( boost::function<void(CONTEXT_MENU*)> aFunction )
|
||||
{
|
||||
std::for_each( m_submenus.begin(), m_submenus.end(), aFunction );
|
||||
}
|
||||
|
||||
|
||||
|
@ -283,8 +303,8 @@ wxMenuItem* CONTEXT_MENU::appendCopy( const wxMenuItem* aSource )
|
|||
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() );
|
||||
m_submenus.push_back( menu );
|
||||
menu->m_parent = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -308,7 +328,9 @@ void CONTEXT_MENU::copyFrom( const CONTEXT_MENU& aMenu )
|
|||
m_selected = -1; // aMenu.m_selected;
|
||||
m_tool = aMenu.m_tool;
|
||||
m_toolActions = aMenu.m_toolActions;
|
||||
m_handlers = aMenu.m_handlers;
|
||||
m_parent = NULL; // aMenu.m_parent;
|
||||
m_menu_handler = aMenu.m_menu_handler;
|
||||
m_update_handler = aMenu.m_update_handler;
|
||||
|
||||
// Copy all the menu entries
|
||||
for( unsigned i = 0; i < aMenu.GetMenuItemCount(); ++i )
|
||||
|
@ -317,3 +339,14 @@ void CONTEXT_MENU::copyFrom( const CONTEXT_MENU& aMenu )
|
|||
appendCopy( item );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OPT_TOOL_EVENT CONTEXT_MENU::menuHandlerStub( const wxMenuEvent& )
|
||||
{
|
||||
return OPT_TOOL_EVENT();
|
||||
}
|
||||
|
||||
|
||||
void CONTEXT_MENU::updateHandlerStub()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -596,6 +596,9 @@ void TOOL_MANAGER::dispatchContextMenu( const TOOL_EVENT& aEvent )
|
|||
// using the point where the user has invoked a context menu
|
||||
m_viewControls->ForceCursorPosition( true, m_viewControls->GetCursorPosition() );
|
||||
|
||||
// Run update handlers
|
||||
st->contextMenu->UpdateAll();
|
||||
|
||||
boost::scoped_ptr<CONTEXT_MENU> menu( new CONTEXT_MENU( *st->contextMenu ) );
|
||||
GetEditFrame()->PopupMenu( menu.get() );
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013 CERN
|
||||
* Copyright (C) 2013-2015 CERN
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -47,9 +48,9 @@ public:
|
|||
///> Copy constructor
|
||||
CONTEXT_MENU( const CONTEXT_MENU& aMenu );
|
||||
|
||||
CONTEXT_MENU& operator=( const CONTEXT_MENU& aMenu );
|
||||
virtual ~CONTEXT_MENU();
|
||||
|
||||
virtual ~CONTEXT_MENU() {}
|
||||
CONTEXT_MENU& operator=( const CONTEXT_MENU& aMenu );
|
||||
|
||||
/**
|
||||
* Function SetTitle()
|
||||
|
@ -64,7 +65,7 @@ public:
|
|||
* Assigns an icon for the entry.
|
||||
* @param aIcon is the icon to be assigned. NULL is used to remove icon.
|
||||
*/
|
||||
void SetIcon( const BITMAP_OPAQUE* aIcon )
|
||||
inline void SetIcon( const BITMAP_OPAQUE* aIcon )
|
||||
{
|
||||
m_icon = aIcon;
|
||||
}
|
||||
|
@ -111,21 +112,43 @@ public:
|
|||
* menu was dismissed.
|
||||
* @return The position of selected item in the context menu.
|
||||
*/
|
||||
int GetSelected() const
|
||||
inline int GetSelected() const
|
||||
{
|
||||
return m_selected;
|
||||
}
|
||||
|
||||
///> Function type to handle menu events in a custom way.
|
||||
typedef boost::function<OPT_TOOL_EVENT(const wxMenuEvent&)> CUSTOM_MENU_HANDLER;
|
||||
/**
|
||||
* Function UpdateAll()
|
||||
* Runs update handlers for the menu and its submenus.
|
||||
*/
|
||||
void UpdateAll();
|
||||
|
||||
///> Adds an event handler to the custom menu event handlers chain.
|
||||
void AppendCustomEventHandler( CUSTOM_MENU_HANDLER aHandler )
|
||||
typedef boost::function<OPT_TOOL_EVENT(const wxMenuEvent&)> MENU_HANDLER;
|
||||
typedef boost::function<void()> UPDATE_HANDLER;
|
||||
|
||||
/**
|
||||
* Function SetMenuHandler()
|
||||
* Sets the menu event handler to another function.
|
||||
*/
|
||||
inline void SetMenuHandler( MENU_HANDLER aMenuHandler )
|
||||
{
|
||||
m_handlers.push_back( aHandler );
|
||||
m_menu_handler = aMenuHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function SetUpdateHandler()
|
||||
* Sets the update handler to a different function.
|
||||
*/
|
||||
inline void SetUpdateHandler( UPDATE_HANDLER aUpdateHandler )
|
||||
{
|
||||
m_update_handler = aUpdateHandler;
|
||||
}
|
||||
|
||||
private:
|
||||
// Empty stubs used by the default constructor
|
||||
static OPT_TOOL_EVENT menuHandlerStub(const wxMenuEvent& );
|
||||
static void updateHandlerStub();
|
||||
|
||||
/**
|
||||
* Function appendCopy
|
||||
* Appends a copy of wxMenuItem.
|
||||
|
@ -138,7 +161,7 @@ private:
|
|||
///> Initializes handlers for events.
|
||||
void setupEvents();
|
||||
|
||||
///> Event handler.
|
||||
///> The default menu event handler.
|
||||
void onMenuEvent( wxMenuEvent& aEvent );
|
||||
|
||||
/**
|
||||
|
@ -148,6 +171,13 @@ private:
|
|||
*/
|
||||
void setTool( TOOL_INTERACTIVE* aTool );
|
||||
|
||||
///> Traverses the submenus tree looking for a submenu capable of handling a particular menu
|
||||
///> event. In case it is handled, it is returned the aToolEvent parameter.
|
||||
void runEventHandlers( const wxMenuEvent& aMenuEvent, OPT_TOOL_EVENT& aToolEvent );
|
||||
|
||||
///> Runs a function on the menu and all its submenus.
|
||||
void runOnSubmenus( boost::function<void(CONTEXT_MENU*)> aFunction );
|
||||
|
||||
///> Flag indicating that the menu title was set up.
|
||||
bool m_titleSet;
|
||||
|
||||
|
@ -163,12 +193,21 @@ private:
|
|||
///> Associates tool actions with menu item IDs. Non-owning.
|
||||
std::map<int, const TOOL_ACTION*> m_toolActions;
|
||||
|
||||
///> Chain of custom menu event handlers.
|
||||
std::list<CUSTOM_MENU_HANDLER> m_handlers;
|
||||
///> List of submenus.
|
||||
std::list<CONTEXT_MENU*> m_submenus;
|
||||
|
||||
///> Parent CONTEXT_MENU.
|
||||
CONTEXT_MENU* m_parent;
|
||||
|
||||
///> Optional icon
|
||||
const BITMAP_OPAQUE* m_icon;
|
||||
|
||||
///> Optional callback to translate wxMenuEvents to TOOL_EVENTs.
|
||||
MENU_HANDLER m_menu_handler;
|
||||
|
||||
///> Optional callback to update the menu state before it is displayed.
|
||||
UPDATE_HANDLER m_update_handler;
|
||||
|
||||
friend class TOOL_INTERACTIVE;
|
||||
};
|
||||
|
||||
|
|
|
@ -96,8 +96,7 @@ public:
|
|||
{
|
||||
m_board = NULL;
|
||||
SetIcon( width_track_via_xpm );
|
||||
AppendCustomEventHandler( boost::bind( &CONTEXT_TRACK_WIDTH_MENU::handleCustomEvent,
|
||||
this, _1 ) );
|
||||
SetMenuHandler( boost::bind( &CONTEXT_TRACK_WIDTH_MENU::EventHandler, this, _1 ) );
|
||||
}
|
||||
|
||||
void SetBoard( BOARD* aBoard )
|
||||
|
@ -153,8 +152,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
OPT_TOOL_EVENT handleCustomEvent( const wxMenuEvent& aEvent )
|
||||
OPT_TOOL_EVENT EventHandler( const wxMenuEvent& aEvent )
|
||||
{
|
||||
#if ID_POPUP_PCB_SELECT_VIASIZE1 < ID_POPUP_PCB_SELECT_WIDTH1
|
||||
#error You have changed event ids order, it breaks code. Check the source code for more details.
|
||||
|
|
|
@ -1282,6 +1282,10 @@ bool SELECTION_TOOL::SanitizeSelection()
|
|||
|
||||
void SELECTION_TOOL::generateMenu()
|
||||
{
|
||||
// Menu has to be updated before its copy is created. Copying does not preserve subtypes of the
|
||||
// stored menus, so updating may not work correctly.
|
||||
m_menu.UpdateAll();
|
||||
|
||||
// Create a copy of the master context menu
|
||||
m_menuCopy = m_menu;
|
||||
|
||||
|
|
Loading…
Reference in New Issue