From 502c0f8bc1d11b2fbfa4bf6844c4c3fffffb4d8f Mon Sep 17 00:00:00 2001 From: Garux Date: Wed, 13 Mar 2019 19:45:51 +0300 Subject: [PATCH] * all plugins commands are bindable support detachable menus in submenus of plugins menus user_shortcuts_init() and user_shortcuts_save() are moved to not the most convenient spot, as init has to happen after plugins init and before menus creation --- radiant/main.cpp | 17 +----- radiant/mainframe.cpp | 20 ++++++- radiant/pluginmanager.cpp | 112 +++++++++++++++++++++----------------- radiant/pluginmanager.h | 19 ++++++- radiant/pluginmenu.cpp | 75 +++++++------------------ 5 files changed, 121 insertions(+), 122 deletions(-) diff --git a/radiant/main.cpp b/radiant/main.cpp index 21350379..2e67f1b3 100644 --- a/radiant/main.cpp +++ b/radiant/main.cpp @@ -531,19 +531,6 @@ void remove_local_pid(){ remove( g_pidGameFile.c_str() ); } -void user_shortcuts_init(){ - StringOutputStream path( 256 ); - path << SettingsPath_get() << g_pGameDescription->mGameFile.c_str() << '/'; - LoadCommandMap( path.c_str() ); - SaveCommandMap( path.c_str() ); -} - -void user_shortcuts_save(){ - StringOutputStream path( 256 ); - path << SettingsPath_get() << g_pGameDescription->mGameFile.c_str() << '/'; - SaveCommandMap( path.c_str() ); -} - void add_local_rc_files(){ { StringOutputStream path( 512 ); @@ -675,7 +662,7 @@ int main( int argc, char* argv[] ){ global_accel_init(); - user_shortcuts_init(); +// user_shortcuts_init(); g_pParentWnd = 0; g_pParentWnd = new MainFrame(); @@ -710,7 +697,7 @@ int main( int argc, char* argv[] ){ delete g_pParentWnd; - user_shortcuts_save(); +// user_shortcuts_save(); global_accel_destroy(); diff --git a/radiant/mainframe.cpp b/radiant/mainframe.cpp index 1faee4b8..61cb6b5e 100644 --- a/radiant/mainframe.cpp +++ b/radiant/mainframe.cpp @@ -2948,6 +2948,20 @@ gboolean toolbar_redirect_scroll( GtkWidget* widget, GdkEventScroll* event, gpoi } +void user_shortcuts_init(){ + StringOutputStream path( 256 ); + path << SettingsPath_get() << g_pGameDescription->mGameFile.c_str() << '/'; + LoadCommandMap( path.c_str() ); + SaveCommandMap( path.c_str() ); +} + +void user_shortcuts_save(){ + StringOutputStream path( 256 ); + path << SettingsPath_get() << g_pGameDescription->mGameFile.c_str() << '/'; + SaveCommandMap( path.c_str() ); +} + + void MainFrame::Create(){ GtkWindow* window = GTK_WINDOW( gtk_window_new( GTK_WINDOW_TOPLEVEL ) ); @@ -2976,8 +2990,10 @@ void MainFrame::Create(){ #endif g_MainWindowActive.connect( window ); - + /* GlobalCommands_insert plugins commands */ GetPlugInMgr().Init( GTK_WIDGET( window ) ); + /* then load shortcuts cfg */ + user_shortcuts_init(); GtkWidget* vbox = gtk_vbox_new( FALSE, 0 ); gtk_container_add( GTK_CONTAINER( window ), vbox ); @@ -3360,6 +3376,8 @@ void MainFrame::Shutdown(){ // destroying group-dialog last because it may contain texture-browser GroupDialog_destroyWindow(); + + user_shortcuts_save(); } void MainFrame::RedrawStatusText(){ diff --git a/radiant/pluginmanager.cpp b/radiant/pluginmanager.cpp index 30cc0c23..5e74eb02 100644 --- a/radiant/pluginmanager.cpp +++ b/radiant/pluginmanager.cpp @@ -38,6 +38,9 @@ #include "modulesystem.h" +#include "stream/stringstream.h" +#include "commands.h" + #include /* plugin manager --------------------------------------- */ @@ -47,7 +50,20 @@ CopiedString m_menu_name; const _QERPluginTable *mpTable; std::list m_CommandStrings; std::list m_CommandTitleStrings; -std::list m_CommandIDs; + +std::list m_globalCommandNames; +class PluginCaller +{ + CPluginSlot* slot; + const char* name; +public: + PluginCaller( CPluginSlot* slot_, const char* name_ ) : slot( slot_ ), name( name_ ){ + } + void operator()(){ + slot->Dispatch( name ); + } +}; +std::list m_callbacks; public: /*! @@ -64,9 +80,7 @@ const char* getMenuName(); std::size_t getCommandCount(); const char* getCommand( std::size_t n ); const char* getCommandTitle( std::size_t n ); -void addMenuID( std::size_t n ); -bool ownsCommandID( std::size_t n ); - +const char* getGlobalCommand( std::size_t n ); }; CPluginSlot::CPluginSlot( GtkWidget* main_window, const char* name, const _QERPluginTable& table ){ @@ -79,23 +93,50 @@ CPluginSlot::CPluginSlot( GtkWidget* main_window, const char* name, const _QERPl StringTokeniser commandTokeniser( commands, ",;" ); StringTokeniser titleTokeniser( titles, ",;" ); - const char* cmdToken = commandTokeniser.getToken(); - const char *titleToken = titleTokeniser.getToken(); - while ( !string_empty( cmdToken ) ) - { - if ( string_empty( titleToken ) ) { - m_CommandStrings.push_back( cmdToken ); + while ( 1 ) { + const char* cmdToken = commandTokeniser.getToken(); + const char *titleToken = titleTokeniser.getToken(); + if( string_empty( cmdToken ) ) + break; + m_CommandStrings.push_back( cmdToken ); + if ( string_empty( titleToken ) ) m_CommandTitleStrings.push_back( cmdToken ); - cmdToken = commandTokeniser.getToken(); - titleToken = ""; - } else - { - m_CommandStrings.push_back( cmdToken ); m_CommandTitleStrings.push_back( titleToken ); - cmdToken = commandTokeniser.getToken(); - titleToken = titleTokeniser.getToken(); + + m_callbacks.emplace_back( PluginCaller( this, m_CommandStrings.back().c_str() ) ); + StringOutputStream str( 64 ); + { + if( !string_equal_nocase_n( cmdToken, getMenuName(), string_length( getMenuName() ) ) ){ //plugin name is not part of command name + str << getMenuName() << "::"; + } + /* remove spaces + camelcasify */ + const char* p = cmdToken; + bool wasspace = false; + while( *p ){ + if( *p == ' ' ){ + wasspace = true; + } + else if( wasspace ){ + wasspace = false; + str << static_cast( std::toupper( *p ) ); + } + else{ + str << *p; + } + ++p; + } + /* del trailing periods */ + char* pp = &( *( str.end() - 1 ) ); + while( *pp == '.' ){ + *pp = '\0'; + --pp; + } + *str.c_str() = std::tolower( *str.c_str() ); //put to the end of the list this way } + m_globalCommandNames.emplace_back( str.c_str() ); + if ( !plugin_menu_special( cmdToken ) ) //ain't special + GlobalCommands_insert( str.c_str(), makeCallback( m_callbacks.back() ) ); } mpTable->m_pfnQERPlug_Init( 0, (void*)main_window ); } @@ -122,18 +163,11 @@ const char* CPluginSlot::getCommandTitle( std::size_t n ){ return ( *i ).c_str(); } -void CPluginSlot::addMenuID( std::size_t n ){ - m_CommandIDs.push_back( n ); -} - -bool CPluginSlot::ownsCommandID( std::size_t n ){ - for ( std::list::iterator i = m_CommandIDs.begin(); i != m_CommandIDs.end(); ++i ) - { - if ( *i == n ) { - return true; - } - } - return false; +const char* CPluginSlot::getGlobalCommand( std::size_t n ){ + std::list::iterator i = m_globalCommandNames.begin(); + while ( n-- != 0 ) + ++i; + return ( *i ).c_str(); } void CPluginSlot::Dispatch( const char *p ){ @@ -154,7 +188,6 @@ void AddPluginSlot( GtkWidget* main_window, const char* name, const _QERPluginTa } void PopulateMenu( PluginsVisitor& menu ); -bool Dispatch( std::size_t n, const char* p ); }; CPluginSlots::~CPluginSlots(){ @@ -174,19 +207,6 @@ void CPluginSlots::PopulateMenu( PluginsVisitor& menu ){ } } -bool CPluginSlots::Dispatch( std::size_t n, const char* p ){ - std::list::iterator iPlug; - for ( iPlug = mSlots.begin(); iPlug != mSlots.end(); ++iPlug ) - { - CPluginSlot *pPlug = *iPlug; - if ( pPlug->ownsCommandID( n ) ) { - pPlug->Dispatch( p ); - return true; - } - } - return false; -} - CPluginSlots g_plugin_slots; @@ -208,18 +228,12 @@ public: } -#include "pluginmanager.h" - CPlugInManager g_PlugInMgr; CPlugInManager& GetPlugInMgr(){ return g_PlugInMgr; } -void CPlugInManager::Dispatch( std::size_t n, const char * p ){ - g_plugin_slots.Dispatch( n, p ); -} - void CPlugInManager::Init( GtkWidget* main_window ){ FillPluginSlots( g_plugin_slots, main_window ); } diff --git a/radiant/pluginmanager.h b/radiant/pluginmanager.h index d7943fb3..03db4483 100644 --- a/radiant/pluginmanager.h +++ b/radiant/pluginmanager.h @@ -41,8 +41,7 @@ virtual const char* getMenuName() = 0; virtual std::size_t getCommandCount() = 0; virtual const char* getCommand( std::size_t ) = 0; virtual const char* getCommandTitle( std::size_t ) = 0; -virtual void addMenuID( std::size_t ) = 0; -virtual bool ownsCommandID( std::size_t n ) = 0; +virtual const char* getGlobalCommand( std::size_t ) = 0; }; class PluginsVisitor @@ -54,7 +53,6 @@ virtual void visit( IPlugIn& plugin ) = 0; class CPlugInManager { public: -void Dispatch( std::size_t n, const char *p ); void Init( GtkWidget* main_window ); void constructMenu( PluginsVisitor& menu ); void Shutdown(); @@ -62,4 +60,19 @@ void Shutdown(); CPlugInManager& GetPlugInMgr(); +inline bool plugin_submenu_in( const char* text ){ + return text[0] == '>' && text[1] == '\0'; +} +inline bool plugin_submenu_out( const char* text ){ + return text[0] == '<' && text[1] == '\0'; +} +inline bool plugin_menu_separator( const char* text ){ + return text[0] == '-' && text[1] == '\0'; +} +inline bool plugin_menu_special( const char* text ){ + return plugin_menu_separator( text ) + || plugin_submenu_in( text ) + || plugin_submenu_out( text ); +} + #endif diff --git a/radiant/pluginmenu.cpp b/radiant/pluginmenu.cpp index 4708a78c..eda7f9a3 100644 --- a/radiant/pluginmenu.cpp +++ b/radiant/pluginmenu.cpp @@ -33,61 +33,45 @@ #include "mainframe.h" #include "preferences.h" - -int m_nNextPlugInID = 0; - -void plugin_activated( GtkWidget* widget, gpointer data ){ - const char* str = (const char*)g_object_get_data( G_OBJECT( widget ),"command" ); - GetPlugInMgr().Dispatch( gpointer_to_int( data ), str ); -} +#include "gtkmisc.h" #include -typedef std::stack WidgetStack; +typedef std::stack MenuStack; void PlugInMenu_Add( GtkMenu* plugin_menu, IPlugIn* pPlugIn ){ - GtkWidget *menu, *item, *parent, *subMenu; - const char *menuText, *menuCommand; - WidgetStack menuStack; + GtkMenu *menu; + const char *menuText; + MenuStack menuStack; - parent = gtk_menu_item_new_with_label( pPlugIn->getMenuName() ); - gtk_widget_show( parent ); - gtk_container_add( GTK_CONTAINER( plugin_menu ), parent ); + menu = create_sub_menu_with_mnemonic( plugin_menu, pPlugIn->getMenuName() ); + if ( g_Layout_enableDetachableMenus.m_value ) { + menu_tearoff( menu ); + } std::size_t nCount = pPlugIn->getCommandCount(); - if ( nCount > 0 ) { - menu = gtk_menu_new(); - if ( g_Layout_enableDetachableMenus.m_value ) { - menu_tearoff( GTK_MENU( menu ) ); - } + { while ( nCount > 0 ) { menuText = pPlugIn->getCommandTitle( --nCount ); - menuCommand = pPlugIn->getCommand( nCount ); if ( menuText != 0 && strlen( menuText ) > 0 ) { - if ( !strcmp( menuText, "-" ) ) { - item = gtk_menu_item_new(); - gtk_widget_set_sensitive( item, FALSE ); + if ( plugin_menu_separator( menuText ) ) { + menu_separator( menu ); } - else if ( !strcmp( menuText, ">" ) ) { + else if ( plugin_submenu_in( menuText ) ) { menuText = pPlugIn->getCommandTitle( --nCount ); - menuCommand = pPlugIn->getCommand( nCount ); - if ( !strcmp( menuText, "-" ) || !strcmp( menuText, ">" ) || !strcmp( menuText, "<" ) ) { + if ( plugin_menu_special( menuText ) ) { globalErrorStream() << pPlugIn->getMenuName() << " Invalid title (" << menuText << ") for submenu.\n"; continue; } - - item = gtk_menu_item_new_with_label( menuText ); - gtk_widget_show( item ); - gtk_container_add( GTK_CONTAINER( menu ), item ); - - subMenu = gtk_menu_new(); - gtk_menu_item_set_submenu( GTK_MENU_ITEM( item ), subMenu ); menuStack.push( menu ); - menu = subMenu; + menu = create_sub_menu_with_mnemonic( menu, menuText ); + if ( g_Layout_enableDetachableMenus.m_value ) { + menu_tearoff( menu ); + } continue; } - else if ( !strcmp( menuText, "<" ) ) { + else if ( plugin_submenu_out( menuText ) ) { if ( !menuStack.empty() ) { menu = menuStack.top(); menuStack.pop(); @@ -100,28 +84,13 @@ void PlugInMenu_Add( GtkMenu* plugin_menu, IPlugIn* pPlugIn ){ } else { - item = gtk_menu_item_new_with_label( menuText ); - g_object_set_data( G_OBJECT( item ),"command", const_cast( static_cast( menuCommand ) ) ); - g_signal_connect( G_OBJECT( item ), "activate", G_CALLBACK( plugin_activated ), gint_to_pointer( m_nNextPlugInID ) ); + create_menu_item_with_mnemonic( menu, menuText, pPlugIn->getGlobalCommand( nCount ) ); } - gtk_widget_show( item ); - gtk_container_add( GTK_CONTAINER( menu ), item ); - pPlugIn->addMenuID( m_nNextPlugInID++ ); } } if ( !menuStack.empty() ) { - std::size_t size = menuStack.size(); - if ( size != 0 ) { - globalErrorStream() << pPlugIn->getMenuName() << " mismatched > <. " << Unsigned( size ) << " submenu(s) not closed.\n"; - } - for ( std::size_t i = 0; i < ( size - 1 ); i++ ) - { - menuStack.pop(); - } - menu = menuStack.top(); - menuStack.pop(); + globalErrorStream() << pPlugIn->getMenuName() << " mismatched > <. " << Unsigned( menuStack.size() ) << " submenu(s) not closed.\n"; } - gtk_menu_item_set_submenu( GTK_MENU_ITEM( parent ), menu ); } } @@ -145,8 +114,6 @@ public: } void PluginsMenu_clear(){ - m_nNextPlugInID = 0; - GList* lst = g_list_find( gtk_container_children( GTK_CONTAINER( g_plugins_menu ) ), GTK_WIDGET( g_plugins_menu_separator ) ); while ( lst->next ) {