From 05ee03d6b0b739c2a56920277c9919d89a930254 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 13 May 2014 11:22:51 +0200 Subject: [PATCH] Recursive copy constructor for CONTEXT_MENU. --- common/tool/context_menu.cpp | 142 ++++++++++++++++++++++++----------- common/tool/tool_manager.cpp | 4 +- include/tool/context_menu.h | 50 ++++++------ 3 files changed, 123 insertions(+), 73 deletions(-) diff --git a/common/tool/context_menu.cpp b/common/tool/context_menu.cpp index 827d1080e0..400193a16b 100644 --- a/common/tool/context_menu.cpp +++ b/common/tool/context_menu.cpp @@ -29,41 +29,32 @@ #include CONTEXT_MENU::CONTEXT_MENU() : - m_titleSet( false ), m_selected( -1 ), m_handler( this ), m_tool( NULL ) + m_titleSet( false ), m_selected( -1 ), m_tool( NULL ) { - m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ), - NULL, &m_handler ); - m_menu.Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CMEventHandler::onEvent ), - NULL, &m_handler ); - - // Workaround for the case when mouse cursor never reaches menu (it hangs up tools using menu) - wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, -1, &m_menu ); - m_menu.AddPendingEvent( menuEvent ); + setupEvents(); } CONTEXT_MENU::CONTEXT_MENU( const CONTEXT_MENU& aMenu ) : - m_titleSet( aMenu.m_titleSet ), m_selected( -1 ), m_handler( this ), m_tool( aMenu.m_tool ) + m_titleSet( aMenu.m_titleSet ), m_selected( -1 ), m_tool( aMenu.m_tool ) { - m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ), - NULL, &m_handler ); - m_menu.Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CMEventHandler::onEvent ), - NULL, &m_handler ); - - // Workaround for the case when mouse cursor never reaches menu (it hangs up tools using menu) - wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, -1, &m_menu ); - m_menu.AddPendingEvent( menuEvent ); + setupEvents(); // Copy all the menu entries - for( unsigned i = 0; i < aMenu.m_menu.GetMenuItemCount(); ++i ) - { - wxMenuItem* item = aMenu.m_menu.FindItemByPosition( i ); - m_menu.Append( new wxMenuItem( &m_menu, item->GetId(), item->GetItemLabel(), - wxEmptyString, wxITEM_NORMAL ) ); - } + copyMenu( &aMenu, this ); +} - // Copy tool actions that are available to choose from context menu - m_toolActions = aMenu.m_toolActions; + +void CONTEXT_MENU::setupEvents() +{ + Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CONTEXT_MENU::onMenuEvent ), + NULL, this ); + Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CONTEXT_MENU::onMenuEvent ), + NULL, this ); + + // Workaround for the case when mouse cursor never reaches menu (it hangs up tools using menu) + wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, -1, this ); + AddPendingEvent( menuEvent ); } @@ -71,15 +62,16 @@ void CONTEXT_MENU::SetTitle( const wxString& aTitle ) { // TODO handle an empty string (remove title and separator) - // Unfortunately wxMenu::SetTitle() does nothing.. + // Unfortunately wxMenu::SetTitle() does nothing.. (at least wxGTK) + if( m_titleSet ) { - m_menu.FindItemByPosition( 0 )->SetItemLabel( aTitle ); + FindItemByPosition( 0 )->SetItemLabel( aTitle ); } else { - m_menu.InsertSeparator( 0 ); - m_menu.Insert( 0, new wxMenuItem( &m_menu, -1, aTitle, wxEmptyString, wxITEM_NORMAL ) ); + InsertSeparator( 0 ); + Insert( 0, new wxMenuItem( this, -1, aTitle, wxEmptyString, wxITEM_NORMAL ) ); m_titleSet = true; } } @@ -89,11 +81,11 @@ void CONTEXT_MENU::Add( const wxString& aLabel, int aId ) { #ifdef DEBUG - if( m_menu.FindItem( aId ) != NULL ) + if( FindItem( aId ) != NULL ) wxLogWarning( wxT( "Adding more than one menu entry with the same ID may result in" "undefined behaviour" ) ); #endif - m_menu.Append( new wxMenuItem( &m_menu, aId, aLabel, wxEmptyString, wxITEM_NORMAL ) ); + Append( new wxMenuItem( this, aId, aLabel, wxEmptyString, wxITEM_NORMAL ) ); } @@ -102,7 +94,7 @@ void 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(); - wxMenuItem* item = new wxMenuItem( &m_menu, id, + wxMenuItem* item = new wxMenuItem( this, id, wxString( aAction.GetMenuItem().c_str(), wxConvUTF8 ), wxString( aAction.GetDescription().c_str(), wxConvUTF8 ), wxITEM_NORMAL ); @@ -123,7 +115,7 @@ void CONTEXT_MENU::Add( const TOOL_ACTION& aAction ) item->SetAccel( &accel ); } - m_menu.Append( item ); + Append( item ); m_toolActions[id] = &aAction; } @@ -133,14 +125,14 @@ void CONTEXT_MENU::Clear() m_titleSet = false; // Remove all the entries from context menu - for( unsigned i = 0; i < m_menu.GetMenuItemCount(); ++i ) - m_menu.Destroy( m_menu.FindItemByPosition( 0 ) ); + for( unsigned i = 0; i < GetMenuItemCount(); ++i ) + Destroy( FindItemByPosition( 0 ) ); m_toolActions.clear(); } -void CONTEXT_MENU::CMEventHandler::onEvent( wxEvent& aEvent ) +void CONTEXT_MENU::onMenuEvent( wxEvent& aEvent ) { TOOL_EVENT evt; wxEventType type = aEvent.GetEventType(); @@ -155,21 +147,83 @@ void CONTEXT_MENU::CMEventHandler::onEvent( wxEvent& aEvent ) else if( type == wxEVT_COMMAND_MENU_SELECTED ) { // Store the selected position - m_menu->m_selected = aEvent.GetId(); + m_selected = aEvent.GetId(); // Check if there is a TOOL_ACTION for the given ID - if( m_menu->m_toolActions.count( aEvent.GetId() ) == 1 ) + if( m_toolActions.count( aEvent.GetId() ) == 1 ) { - evt = m_menu->m_toolActions[aEvent.GetId()]->MakeEvent(); + evt = m_toolActions[aEvent.GetId()]->MakeEvent(); } else { - // Handling non-action menu entries (e.g. items in clarification list) - evt = TOOL_EVENT( TC_COMMAND, TA_CONTEXT_MENU_CHOICE, aEvent.GetId() ); + OPT_TOOL_EVENT custom = handleCustomEvent( aEvent ); + if(custom) + evt = *custom; + else { + // Handling non-action menu entries (e.g. items in clarification list) + evt = TOOL_EVENT( TC_COMMAND, TA_CONTEXT_MENU_CHOICE, aEvent.GetId() ); + } } } // forward the action/update event to the TOOL_MANAGER - if( m_menu->m_tool ) - m_menu->m_tool->GetManager()->ProcessEvent( evt ); + if( m_tool ) + m_tool->GetManager()->ProcessEvent( evt ); +} + + +void CONTEXT_MENU::copyMenu( const CONTEXT_MENU* aParent, CONTEXT_MENU* aTarget ) const +{ + // Copy all the menu entries + for( unsigned i = 0; i < aParent->GetMenuItemCount(); ++i ) + { + wxMenuItem* item = aParent->FindItemByPosition( i ); + + 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; + copyMenu( static_cast( item->GetSubMenu() ), menu ); + aTarget->AppendSubMenu( menu, item->GetItemLabel(), wxT( "" ) ); + } + else + { + wxMenuItem* newItem = new wxMenuItem( aTarget, item->GetId(), item->GetItemLabel(), + wxEmptyString, item->GetKind() ); + + aTarget->Append( newItem ); + copyItem( item, newItem ); + } + } + + // Copy tool actions that are available to choose from context menu + aTarget->m_toolActions = aParent->m_toolActions; +} + + +void CONTEXT_MENU::copyItem( const wxMenuItem* aSource, wxMenuItem* aDest ) const +{ + assert( !aSource->IsSubMenu() ); + + aDest->SetKind( aSource->GetKind() ); + aDest->SetHelp( aSource->GetHelp() ); + aDest->Enable( aSource->IsEnabled() ); + + if( aSource->IsCheckable() ) + aDest->Check( aSource->IsChecked() ); + + if( aSource->GetKind() == wxITEM_NORMAL ) + aDest->SetBitmap( aSource->GetBitmap() ); + + if( aSource->IsSubMenu() ) + { + CONTEXT_MENU* newMenu = new CONTEXT_MENU; + + copyMenu( static_cast( aSource->GetSubMenu() ), newMenu ); + aDest->SetSubMenu( newMenu ); + } } diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp index 0f0ee83533..dd77425a0c 100644 --- a/common/tool/tool_manager.cpp +++ b/common/tool/tool_manager.cpp @@ -308,8 +308,6 @@ int TOOL_MANAGER::GetPriority( int aToolId ) const for( std::deque::const_iterator it = m_activeTools.begin(), itEnd = m_activeTools.end(); it != itEnd; ++it ) { - std::cout << FindTool( *it )->GetName() << std::endl; - if( *it == aToolId ) return priority; @@ -497,7 +495,7 @@ bool TOOL_MANAGER::ProcessEvent( TOOL_EVENT& aEvent ) st->contextMenuTrigger = CMENU_OFF; boost::scoped_ptr menu( new CONTEXT_MENU( *st->contextMenu ) ); - GetEditFrame()->PopupMenu( menu->GetMenu() ); + GetEditFrame()->PopupMenu( menu.get() ); // If nothing was chosen from the context menu, we must notify the tool as well if( menu->GetSelected() < 0 ) diff --git a/include/tool/context_menu.h b/include/tool/context_menu.h index e181b576bb..a0a57b3d0b 100644 --- a/include/tool/context_menu.h +++ b/include/tool/context_menu.h @@ -37,7 +37,7 @@ class TOOL_INTERACTIVE; * Defines the structure of a context (usually right-click) popup menu * for a given tool. */ -class CONTEXT_MENU +class CONTEXT_MENU : public wxMenu { public: ///> Default constructor @@ -71,6 +71,7 @@ public: */ void Add( const TOOL_ACTION& aAction ); + /** * Function Clear() * Removes all the entries from the menu (as well as its title). It leaves the menu in the @@ -89,32 +90,32 @@ public: return m_selected; } - /** - * Function GetMenu() - * Returns the instance of wxMenu object used to display the menu. - */ - wxMenu* GetMenu() const + +protected: + virtual OPT_TOOL_EVENT handleCustomEvent ( wxEvent& aEvent ) { - return const_cast( &m_menu ); - } + return OPT_TOOL_EVENT(); + }; private: - ///> Class CMEventHandler takes care of handling menu events. After reception of particular - ///> events, it translates them to TOOL_EVENTs that may control tools. - class CMEventHandler : public wxEvtHandler - { - public: - ///> Default constructor - ///> aMenu is the CONTEXT_MENU instance for which it handles events. - CMEventHandler( CONTEXT_MENU* aMenu ) : m_menu( aMenu ) {}; + /** + * Function copyMenu + * Copies recursively all entries and submenus. + * @param aParent is the source. + * @param aTarget is the destination. + */ + void copyMenu( const CONTEXT_MENU* aParent, CONTEXT_MENU* aTarget ) const; - ///> Handler for menu events. - void onEvent( wxEvent& aEvent ); + /** + * Function copyItem + * Copies all properties of a menu entry. + */ + void copyItem( const wxMenuItem* aSource, wxMenuItem* aDest ) const; - private: - ///> CONTEXT_MENU instance for which it handles events. - CONTEXT_MENU* m_menu; - }; + void setupEvents(); + + ///> Event handler. + void onMenuEvent( wxEvent& aEvent ); friend class TOOL_INTERACTIVE; @@ -131,14 +132,11 @@ private: ///> Flag indicating that the menu title was set up. bool m_titleSet; - ///> Instance of wxMenu used for display of the context menu. - wxMenu m_menu; - ///> Stores the id number of selected item. int m_selected; ///> Instance of menu event handler. - CMEventHandler m_handler; + //CMEventHandler m_handler; ///> Creator of the menu TOOL_INTERACTIVE* m_tool;