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.
|
* 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 Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -31,7 +32,9 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
CONTEXT_MENU::CONTEXT_MENU() :
|
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();
|
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 )
|
CONTEXT_MENU& CONTEXT_MENU::operator=( const CONTEXT_MENU& aMenu )
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
copyFrom( aMenu );
|
copyFrom( aMenu );
|
||||||
setupEvents();
|
|
||||||
|
|
||||||
return *this;
|
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 )
|
wxMenuItem* CONTEXT_MENU::Add( const wxString& aLabel, int aId, const BITMAP_OPAQUE* aIcon )
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
||||||
if( FindItem( aId ) != NULL )
|
if( FindItem( aId ) != NULL )
|
||||||
wxLogWarning( wxT( "Adding more than one menu entry with the same ID may result in"
|
wxLogWarning( wxT( "Adding more than one menu entry with the same ID may result in"
|
||||||
"undefined behaviour" ) );
|
"undefined behaviour" ) );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
wxMenuItem* item = new wxMenuItem( this, aId, aLabel, wxEmptyString, wxITEM_NORMAL );
|
wxMenuItem* item = new wxMenuItem( this, aId, aLabel, wxEmptyString, wxITEM_NORMAL );
|
||||||
|
|
||||||
if( aIcon )
|
if( aIcon )
|
||||||
|
@ -139,9 +152,7 @@ std::list<wxMenuItem*> CONTEXT_MENU::Add( CONTEXT_MENU* aMenu, const wxString& a
|
||||||
|
|
||||||
if( aExpand )
|
if( aExpand )
|
||||||
{
|
{
|
||||||
unsigned int i = 0;
|
for( unsigned int i = 0; i < aMenu->GetMenuItemCount(); ++i )
|
||||||
|
|
||||||
for( i = 0; i < aMenu->GetMenuItemCount(); ++i )
|
|
||||||
{
|
{
|
||||||
wxMenuItem* item = aMenu->FindItemByPosition( i );
|
wxMenuItem* item = aMenu->FindItemByPosition( i );
|
||||||
items.push_back( appendCopy( item ) );
|
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_submenus.push_back( aMenu );
|
||||||
m_handlers.insert( m_handlers.end(), aMenu->m_handlers.begin(), aMenu->m_handlers.end() );
|
aMenu->m_parent = this;
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
@ -176,13 +187,22 @@ void CONTEXT_MENU::Clear()
|
||||||
GetMenuItems().DeleteContents( true );
|
GetMenuItems().DeleteContents( true );
|
||||||
GetMenuItems().Clear();
|
GetMenuItems().Clear();
|
||||||
m_toolActions.clear();
|
m_toolActions.clear();
|
||||||
m_handlers.clear();
|
|
||||||
GetMenuItems().DeleteContents( false ); // restore the default so destructor does not go wild
|
GetMenuItems().DeleteContents( false ); // restore the default so destructor does not go wild
|
||||||
|
m_submenus.clear();
|
||||||
|
m_parent = NULL;
|
||||||
|
|
||||||
assert( GetMenuItemCount() == 0 );
|
assert( GetMenuItemCount() == 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CONTEXT_MENU::UpdateAll()
|
||||||
|
{
|
||||||
|
m_update_handler();
|
||||||
|
|
||||||
|
runOnSubmenus( boost::bind( &CONTEXT_MENU::UpdateAll, _1 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CONTEXT_MENU::onMenuEvent( wxMenuEvent& aEvent )
|
void CONTEXT_MENU::onMenuEvent( wxMenuEvent& aEvent )
|
||||||
{
|
{
|
||||||
OPT_TOOL_EVENT evt;
|
OPT_TOOL_EVENT evt;
|
||||||
|
@ -208,8 +228,10 @@ void CONTEXT_MENU::onMenuEvent( wxMenuEvent& aEvent )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Under Linux, every submenu can have a separate event handler, under
|
runEventHandlers( aEvent, evt );
|
||||||
// Windows all submenus are handled by the main menu.
|
|
||||||
|
// Under Linux, every submenu can have a separate event handler, under
|
||||||
|
// Windows all submenus are handled by the main menu.
|
||||||
#ifdef __WINDOWS__
|
#ifdef __WINDOWS__
|
||||||
if( !evt )
|
if( !evt )
|
||||||
{
|
{
|
||||||
|
@ -224,14 +246,6 @@ void CONTEXT_MENU::onMenuEvent( wxMenuEvent& aEvent )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
// Handling non-action menu entries (e.g. items in clarification list)
|
||||||
if( !evt )
|
if( !evt )
|
||||||
|
@ -251,16 +265,22 @@ void CONTEXT_MENU::setTool( TOOL_INTERACTIVE* aTool )
|
||||||
{
|
{
|
||||||
m_tool = aTool;
|
m_tool = aTool;
|
||||||
|
|
||||||
for( unsigned i = 0; i < GetMenuItemCount(); ++i )
|
runOnSubmenus( boost::bind( &CONTEXT_MENU::setTool, _1, aTool ) );
|
||||||
{
|
}
|
||||||
wxMenuItem* item = FindItemByPosition( i );
|
|
||||||
|
|
||||||
if( item->IsSubMenu() )
|
|
||||||
{
|
void CONTEXT_MENU::runEventHandlers( const wxMenuEvent& aMenuEvent, OPT_TOOL_EVENT& aToolEvent )
|
||||||
CONTEXT_MENU* menu = static_cast<CONTEXT_MENU*>( item->GetSubMenu() );
|
{
|
||||||
menu->setTool( aTool );
|
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 );
|
newItem->SetSubMenu( menu );
|
||||||
Append( newItem );
|
Append( newItem );
|
||||||
|
|
||||||
m_toolActions.insert( menu->m_toolActions.begin(), menu->m_toolActions.end() );
|
m_submenus.push_back( menu );
|
||||||
m_handlers.insert( m_handlers.end(), menu->m_handlers.begin(), menu->m_handlers.end() );
|
menu->m_parent = this;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -308,7 +328,9 @@ void CONTEXT_MENU::copyFrom( const CONTEXT_MENU& aMenu )
|
||||||
m_selected = -1; // aMenu.m_selected;
|
m_selected = -1; // aMenu.m_selected;
|
||||||
m_tool = aMenu.m_tool;
|
m_tool = aMenu.m_tool;
|
||||||
m_toolActions = aMenu.m_toolActions;
|
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
|
// Copy all the menu entries
|
||||||
for( unsigned i = 0; i < aMenu.GetMenuItemCount(); ++i )
|
for( unsigned i = 0; i < aMenu.GetMenuItemCount(); ++i )
|
||||||
|
@ -317,3 +339,14 @@ void CONTEXT_MENU::copyFrom( const CONTEXT_MENU& aMenu )
|
||||||
appendCopy( item );
|
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
|
// using the point where the user has invoked a context menu
|
||||||
m_viewControls->ForceCursorPosition( true, m_viewControls->GetCursorPosition() );
|
m_viewControls->ForceCursorPosition( true, m_viewControls->GetCursorPosition() );
|
||||||
|
|
||||||
|
// Run update handlers
|
||||||
|
st->contextMenu->UpdateAll();
|
||||||
|
|
||||||
boost::scoped_ptr<CONTEXT_MENU> menu( new CONTEXT_MENU( *st->contextMenu ) );
|
boost::scoped_ptr<CONTEXT_MENU> menu( new CONTEXT_MENU( *st->contextMenu ) );
|
||||||
GetEditFrame()->PopupMenu( menu.get() );
|
GetEditFrame()->PopupMenu( menu.get() );
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* 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 Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -47,9 +48,9 @@ public:
|
||||||
///> Copy constructor
|
///> Copy constructor
|
||||||
CONTEXT_MENU( const CONTEXT_MENU& aMenu );
|
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()
|
* Function SetTitle()
|
||||||
|
@ -64,7 +65,7 @@ public:
|
||||||
* Assigns an icon for the entry.
|
* Assigns an icon for the entry.
|
||||||
* @param aIcon is the icon to be assigned. NULL is used to remove icon.
|
* @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;
|
m_icon = aIcon;
|
||||||
}
|
}
|
||||||
|
@ -111,21 +112,43 @@ public:
|
||||||
* menu was dismissed.
|
* menu was dismissed.
|
||||||
* @return The position of selected item in the context menu.
|
* @return The position of selected item in the context menu.
|
||||||
*/
|
*/
|
||||||
int GetSelected() const
|
inline int GetSelected() const
|
||||||
{
|
{
|
||||||
return m_selected;
|
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.
|
typedef boost::function<OPT_TOOL_EVENT(const wxMenuEvent&)> MENU_HANDLER;
|
||||||
void AppendCustomEventHandler( CUSTOM_MENU_HANDLER aHandler )
|
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:
|
private:
|
||||||
|
// Empty stubs used by the default constructor
|
||||||
|
static OPT_TOOL_EVENT menuHandlerStub(const wxMenuEvent& );
|
||||||
|
static void updateHandlerStub();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function appendCopy
|
* Function appendCopy
|
||||||
* Appends a copy of wxMenuItem.
|
* Appends a copy of wxMenuItem.
|
||||||
|
@ -138,7 +161,7 @@ private:
|
||||||
///> Initializes handlers for events.
|
///> Initializes handlers for events.
|
||||||
void setupEvents();
|
void setupEvents();
|
||||||
|
|
||||||
///> Event handler.
|
///> The default menu event handler.
|
||||||
void onMenuEvent( wxMenuEvent& aEvent );
|
void onMenuEvent( wxMenuEvent& aEvent );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -148,6 +171,13 @@ private:
|
||||||
*/
|
*/
|
||||||
void setTool( TOOL_INTERACTIVE* aTool );
|
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.
|
///> Flag indicating that the menu title was set up.
|
||||||
bool m_titleSet;
|
bool m_titleSet;
|
||||||
|
|
||||||
|
@ -163,12 +193,21 @@ private:
|
||||||
///> Associates tool actions with menu item IDs. Non-owning.
|
///> Associates tool actions with menu item IDs. Non-owning.
|
||||||
std::map<int, const TOOL_ACTION*> m_toolActions;
|
std::map<int, const TOOL_ACTION*> m_toolActions;
|
||||||
|
|
||||||
///> Chain of custom menu event handlers.
|
///> List of submenus.
|
||||||
std::list<CUSTOM_MENU_HANDLER> m_handlers;
|
std::list<CONTEXT_MENU*> m_submenus;
|
||||||
|
|
||||||
|
///> Parent CONTEXT_MENU.
|
||||||
|
CONTEXT_MENU* m_parent;
|
||||||
|
|
||||||
///> Optional icon
|
///> Optional icon
|
||||||
const BITMAP_OPAQUE* m_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;
|
friend class TOOL_INTERACTIVE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -96,8 +96,7 @@ public:
|
||||||
{
|
{
|
||||||
m_board = NULL;
|
m_board = NULL;
|
||||||
SetIcon( width_track_via_xpm );
|
SetIcon( width_track_via_xpm );
|
||||||
AppendCustomEventHandler( boost::bind( &CONTEXT_TRACK_WIDTH_MENU::handleCustomEvent,
|
SetMenuHandler( boost::bind( &CONTEXT_TRACK_WIDTH_MENU::EventHandler, this, _1 ) );
|
||||||
this, _1 ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetBoard( BOARD* aBoard )
|
void SetBoard( BOARD* aBoard )
|
||||||
|
@ -153,8 +152,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
OPT_TOOL_EVENT EventHandler( const wxMenuEvent& aEvent )
|
||||||
OPT_TOOL_EVENT handleCustomEvent( const wxMenuEvent& aEvent )
|
|
||||||
{
|
{
|
||||||
#if ID_POPUP_PCB_SELECT_VIASIZE1 < ID_POPUP_PCB_SELECT_WIDTH1
|
#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.
|
#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()
|
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
|
// Create a copy of the master context menu
|
||||||
m_menuCopy = m_menu;
|
m_menuCopy = m_menu;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue