From eea78c37f35f516fb4bcd2ada73df8b628e97fc0 Mon Sep 17 00:00:00 2001 From: Garux Date: Sun, 14 Sep 2025 03:43:39 +0500 Subject: [PATCH] * context menu for toolbar buttons configuration --- contrib/bobtoolz/bobToolz-GTK.cpp | 32 +++--- contrib/ufoaiplug/ufoai.cpp | 2 +- contrib/ufoaiplug/ufoai_gtk.cpp | 16 +-- docs/changelog-custom.txt | 1 + radiant/filterbar.cpp | 8 +- radiant/gtkmisc.cpp | 168 +++++++++++++++++++++++++++++- radiant/gtkmisc.h | 10 +- radiant/mainframe.cpp | 41 +++++--- radiant/pluginmanager.cpp | 64 ++++++------ radiant/pluginmanager.h | 4 + radiant/plugintoolbar.cpp | 29 ++++-- 11 files changed, 288 insertions(+), 87 deletions(-) diff --git a/contrib/bobtoolz/bobToolz-GTK.cpp b/contrib/bobtoolz/bobToolz-GTK.cpp index 6e5a3e67..d0e466ce 100644 --- a/contrib/bobtoolz/bobToolz-GTK.cpp +++ b/contrib/bobtoolz/bobToolz-GTK.cpp @@ -73,10 +73,10 @@ constexpr char PLUGIN_COMMANDS[] = "About...," "Plot Splines," "-," "Merge Patches," - "Split patches," - "Split patches cols," - "Split patches rows," - "Turn edge" + "Split patch," + "Split patch columns," + "Split patch rows," + "Flip terrain" ; // globals @@ -126,16 +126,16 @@ extern "C" void QERPlug_Dispatch( const char *p, vec3_t vMin, vec3_t vMax, bool else if ( string_equal_nocase( p, "merge patches" ) ) { DoMergePatches(); } - else if ( string_equal_nocase( p, "split patches" ) ) { + else if ( string_equal_nocase( p, "split patch" ) ) { DoSplitPatch(); } - else if ( string_equal_nocase( p, "split patches rows" ) ) { + else if ( string_equal_nocase( p, "split patch rows" ) ) { DoSplitPatchRows(); } - else if ( string_equal_nocase( p, "split patches cols" ) ) { + else if ( string_equal_nocase( p, "split patch columns" ) ) { DoSplitPatchCols(); } - else if ( string_equal_nocase( p, "turn edge" ) ) { + else if ( string_equal_nocase( p, "flip terrain" ) ) { DoFlipTerrain(); } else if ( string_equal_nocase( p, "reset textures..." ) ) { @@ -192,7 +192,8 @@ class CBobtoolzToolbarButton : public IToolbarButton public: virtual const char* getImage() const override { switch ( mIndex ) { - case 0: return "bobtoolz_cleanup.png"; + // case 0: return "bobtoolz_cleanup.png"; + case 0: return ""; case 1: return "bobtoolz_poly.png"; // case 2: return "bobtoolz_caulk.png"; case 2: return ""; @@ -211,6 +212,7 @@ public: } virtual EType getType() const override { switch ( mIndex ) { + case 0: return eSpace; case 2: return eSpace; case 3: return eToggleButton; case 6: return eSpace; @@ -220,13 +222,13 @@ public: } virtual const char* getText() const override { switch ( mIndex ) { - case 0: return "Cleanup"; - case 1: return "Polygons"; + // case 0: return "Cleanup"; + case 1: return "Polygon Builder"; // case 2: return "Caulk"; case 3: return "Tree Planter"; case 4: return "Plot Splines"; case 5: return "Drop Entity"; - case 7: return "Merge 2 Patches"; + case 7: return "Merge Patches"; case 8: return "Split Patch"; case 9: return "Split Patch Rows"; case 10: return "Split Patch Columns"; @@ -236,13 +238,13 @@ public: } virtual const char* getTooltip() const override { switch ( mIndex ) { - case 0: return "Brush Cleanup"; + // case 0: return "Brush Cleanup"; case 1: return "Polygons"; // case 2: return "Caulk selection"; case 3: return "Tree Planter"; case 4: return "Plot Splines"; case 5: return "Drop Entity"; - case 7: return "Merge 2 Patches"; + case 7: return "Merge Patches"; case 8: return "Split Patch"; case 9: return "Split Patch Rows"; case 10: return "Split Patch Columns"; @@ -255,7 +257,7 @@ public: LoadLists(); switch ( mIndex ) { - case 0: DoFixBrushes(); break; + // case 0: DoFixBrushes(); break; case 1: DoPolygonsTB(); break; // case 2: DoCaulkSelection(); break; case 3: DoTreePlanter(); break; diff --git a/contrib/ufoaiplug/ufoai.cpp b/contrib/ufoaiplug/ufoai.cpp index c70f22b1..7c93eb66 100644 --- a/contrib/ufoaiplug/ufoai.cpp +++ b/contrib/ufoaiplug/ufoai.cpp @@ -68,7 +68,7 @@ const char* getName(){ } const char* getCommandList(){ /*GlobalRadiant().getGameName()*/ - return "About;-;Worldspawn reset;Worldspawn;Perform check;-;Level 1;Level 2;Level 3;Level 4;Level 5;Level 6;Level 7;Level 8;-;StepOn;ActorClip;WeaponClip;Nodraw"; + return "About;-;Worldspawn reset;Worldspawn;Perform check;-;Level 1;Level 2;Level 3;Level 4;Level 5;Level 6;Level 7;Level 8;-;StepOn;ActorClip;WeaponClip;NoDraw"; } const char* getCommandTitleList(){ return ""; diff --git a/contrib/ufoaiplug/ufoai_gtk.cpp b/contrib/ufoaiplug/ufoai_gtk.cpp index 3fa4fcf7..208ca798 100644 --- a/contrib/ufoaiplug/ufoai_gtk.cpp +++ b/contrib/ufoaiplug/ufoai_gtk.cpp @@ -84,10 +84,10 @@ public: case 5: return "Level 6"; case 6: return "Level 7"; case 7: return "Level 8"; - case 8: return "Stepon"; - case 9: return "Actorclip"; - case 10: return "Weaponclip"; - case 11: return "Nodraw"; + case 8: return "StepOn"; + case 9: return "ActorClip"; + case 10: return "WeaponClip"; + case 11: return "NoDraw"; } return NULL; } @@ -102,10 +102,10 @@ public: case 5: return "Show only level 6"; case 6: return "Show only level 7"; case 7: return "Show only level 8"; - case 8: return "Hide stepon brushes"; - case 9: return "Hide actorclip brushes"; - case 10: return "Hide weaponclip brushes"; - case 11: return "Hide nodraw brushes"; + case 8: return "Hide stepOn brushes"; + case 9: return "Hide actorClip brushes"; + case 10: return "Hide weaponClip brushes"; + case 11: return "Hide noDraw brushes"; } return NULL; } diff --git a/docs/changelog-custom.txt b/docs/changelog-custom.txt index c0cb89d2..b8cc776f 100644 --- a/docs/changelog-custom.txt +++ b/docs/changelog-custom.txt @@ -372,6 +372,7 @@ menus... * View->Layers Browser (L) * Edit->Expand Selection To Layers (ctrl + q) * shift + q: move-to LayersMenu + * context menu for toolbar buttons configuration misc... * removed note to save before going to preferences, project settings diff --git a/radiant/filterbar.cpp b/radiant/filterbar.cpp index 1bf2a565..6d84f74b 100644 --- a/radiant/filterbar.cpp +++ b/radiant/filterbar.cpp @@ -144,7 +144,7 @@ void create_filter_toolbar( QToolBar *toolbar ){ g_filter_toolbar_handler.m_actions.emplace( button, new CommonFunc_group ); toolbar_append_toggle_button( toolbar, "Patches", "f-patches.png", "FilterPatches" ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); // if ( g_pGameDescription->mGameType == "doom3" ) { // button = toolbar_append_toggle_button( toolbar, "Visportals", "f-areaportal.png", "FilterVisportals" ); @@ -171,7 +171,7 @@ void create_filter_toolbar( QToolBar *toolbar ){ button = toolbar_append_toggle_button( toolbar, "Sky", "f-sky.png", "FilterSky" ); //toolbar_append_toggle_button( toolbar, "Paths", "texture_lock.png", "FilterPaths" ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); toolbar_append_toggle_button( toolbar, "Entities", "f-entities.png", "FilterEntities" ); toolbar_append_toggle_button( toolbar, "Point Entities", "f-pointentities.png", "FilterPointEntities" ); toolbar_append_toggle_button( toolbar, "Lights", "f-lights.png", "FilterLights" ); @@ -181,12 +181,12 @@ void create_filter_toolbar( QToolBar *toolbar ){ g_filter_toolbar_handler.m_actions.emplace( button, new CommonFunc_tex( std::vector{ "trigger" } ) ); //toolbar_append_toggle_button( toolbar, "Decals", "f-decals.png", "FilterDecals" ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); //toolbar_append_button( toolbar, "InvertFilters", "f-invert.png", "InvertFilters" ); toolbar_append_button( toolbar, "ResetFilters", "f-reset.png", "ResetFilters" ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); button = toolbar_append_toggle_button( toolbar, "Region Set Selection\nRightClick: Region Off", "f-region.png", "RegionSetSelection" ); g_filter_toolbar_handler.m_actions.emplace( button, new CommonFunc_command( "RegionOff" ) ); diff --git a/radiant/gtkmisc.cpp b/radiant/gtkmisc.cpp index 0fa9064d..252d9691 100644 --- a/radiant/gtkmisc.cpp +++ b/radiant/gtkmisc.cpp @@ -41,10 +41,13 @@ #include "gtkutil/filechooser.h" #include "gtkutil/image.h" #include "commands.h" +#include "stream/stringstream.h" +#include "stream/textstream.h" #include #include #include +#include void process_gui(){ @@ -97,7 +100,7 @@ typedef ReferenceCaller Action inline QAction* toggle_add_accelerator_( const char* name ){ GlobalShortcuts_register( name, 2 ); const Toggle& toggle = GlobalToggles_find( name ); - auto action = command_connect_accelerator( toggle.m_command ); + auto *action = command_connect_accelerator( toggle.m_command ); action->setCheckable( true ); toggle.m_exportCallback( ActionSetCheckedCaller( *action ) ); return action; @@ -129,6 +132,156 @@ QAction* create_menu_item_with_mnemonic( QMenu *menu, const char *mnemonic, cons } +struct ToolbarItem +{ + ToolbarItem( QToolBar *toolbar, QAction *action, const char *commandName, bool separator ) + : m_toolbar( toolbar ), m_action( action ), m_commandName( commandName ), m_separator( separator ) { + } + QToolBar *m_toolbar; + QAction *m_action; + CopiedString m_commandName; // empty for separator + const bool m_separator; + bool m_enabled = true; +}; + +CopiedString g_toolbarHiddenButtons = + "%OpenMap%" + "%SaveMap%" + "%Undo%" + "%Redo%" + "%SelectTouching%" + "%SelectInside%" + "%NextView%" + "%ToggleCubicClip%" + "%CapCurrentCurve%" + "%ToggleEntityInspector%" + "%ToggleConsole%" + "%ToggleTextures%" + "%RefreshReferences%" + "%bobToolz::PolygonBuilder%" + "%bobToolz::TreePlanter%" + "%bobToolz::PlotSplines%" + "%bobToolz::DropEntity%" + "%bobToolz::FlipTerrain%"; + +class ToolbarItems +{ + std::vector m_toolbarItems; + using iterator = decltype( m_toolbarItems )::iterator; + using reverse_iterator = decltype( m_toolbarItems )::reverse_iterator; + iterator begin(){ + return m_toolbarItems.begin(); + } + iterator end(){ + return m_toolbarItems.end(); + } + + void item_enable( iterator item, bool enable ){ + if( ( item->m_enabled = enable ) ){ + for( auto it = item + 1; it != end() && item->m_toolbar == it->m_toolbar; ++it ) + if( it->m_enabled ) + return item->m_toolbar->insertAction( it->m_action, item->m_action ); // insert before next visible toolbar item + item->m_toolbar->addAction( item->m_action ); // or end + } + else + item->m_toolbar->removeAction( item->m_action ); + } + void update_separators_visibility(){ + for( auto item = begin(); item != end(); ++item ) + { + if( item->m_separator ){ + const bool enable = + [&](){ // check that there are visible items up to the next separator or toolbar end + for( auto it = item + 1; item != end() && item->m_toolbar == it->m_toolbar && !it->m_separator; ++it ) + if( it->m_enabled ) + return true; + return false; + }() && + [&](){ // check if any item before is visible // &*rev == &*(it - 1) + for( auto it = reverse_iterator( item ); it != m_toolbarItems.rend() && item->m_toolbar == it->m_toolbar; ++it ) + if( it->m_enabled ) + return true; + return false; + }(); + + if( item->m_enabled != enable ) + item_enable( item, enable ); + } + } + } + // modify particular entires, so that layout dependent entries will not be wiped, when toggling buttons visibility in different layout + void exportState( const char *commandName, bool enable ){ + auto& entries = g_toolbarHiddenButtons; + const auto entry = StringStream<64>( '%', commandName, '%' ); + const char *found = strstr( entries.c_str(), entry ); + if( enable && found != nullptr ) // enable = wipe + entries = StringStream( StringRange( entries.c_str(), found ), found + string_length( entry ) ); + if( !enable && found == nullptr ) // disable = add + entries = StringStream( entries, entry ); + } +public: + void importState( const char *commandNames ){ + StringOutputStream str( 64 ); + for( auto& item : *this ) + { + if( !item.m_separator && strstr( commandNames, str( '%', item.m_commandName, '%' ) ) != nullptr ){ + item.m_toolbar->removeAction( item.m_action ); + item.m_enabled = false; + } + } + update_separators_visibility(); + } + void construct_control_menu( QMenu *menu ){ + for( auto item = begin(); item != end(); ++item ) + { + if( !item->m_separator ){ + auto *action = menu->addAction( item->m_action->icon(), item->m_commandName.c_str(), [item, this]( bool checked ){ + item_enable( item, checked ); + update_separators_visibility(); + exportState( item->m_commandName.c_str(), checked ); + } ); + action->setCheckable( true ); + action->setChecked( item->m_enabled ); + // separate different toolbars + if( auto next = item + 1; next != end() && item->m_toolbar != next->m_toolbar ) + menu->addSeparator(); + } + } + // prevent closing the menu on clicks (note: click to detach menu closes it) + class Filter : public QObject + { + using QObject::QObject; + protected: + bool eventFilter( QObject *obj, QEvent *event ) override { + if( event->type() == QEvent::MouseButtonRelease ) { + auto *mouseEvent = static_cast( event ); + auto *menu = static_cast( obj ); + if( QAction *action = menu->actionAt( mouseEvent->pos() ) ){ + action->trigger(); + } + event->accept(); + return true; + } + return QObject::eventFilter( obj, event ); // standard event processing + } + }; + menu->installEventFilter( new Filter( menu ) ); + + } + void push_back( ToolbarItem&& item ){ + m_toolbarItems.push_back( std::move( item ) ); + } +}; +static ToolbarItems s_toolbarItems; + +void toolbar_importState( const char *commandNames ){ + s_toolbarItems.importState( commandNames ); +} +void toolbar_construct_control_menu( QMenu *menu ){ + s_toolbarItems.construct_control_menu( menu ); +} + + // can update this on QAction::changed() signal, but it's called too often and even on setChecked(); let's only have this on construction static void toolbar_action_set_tooltip( QAction *action, const char *description ){ if( QKeySequence_valid( action->shortcut() ) ){ @@ -148,22 +301,31 @@ static void toolbar_action_set_tooltip( QAction *action, const char *description } } -QAction* toolbar_append_button( QToolBar* toolbar, const char* description, const char* icon, const char* commandName ){ +QAction* toolbar_append_button( QToolBar* toolbar, const char* description, const QIcon& icon, const char* commandName ){ auto *action = command_connect_accelerator_( commandName ); - action->setIcon( new_local_icon( icon ) ); + action->setIcon( icon ); toolbar_action_set_tooltip( action, description ); toolbar->addAction( action ); + s_toolbarItems.push_back( { toolbar, action, commandName, false } ); return action; } +QAction* toolbar_append_button( QToolBar* toolbar, const char* description, const char* icon, const char* commandName ){ + return toolbar_append_button( toolbar, description, new_local_icon( icon ), commandName ); +} QAction* toolbar_append_toggle_button( QToolBar* toolbar, const char* description, const char* icon, const char* commandName ){ auto *action = toggle_add_accelerator_( commandName ); action->setIcon( new_local_icon( icon ) ); toolbar_action_set_tooltip( action, description ); toolbar->addAction( action ); + s_toolbarItems.push_back( { toolbar, action, commandName, false } ); return action; } +void toolbar_append_separator( QToolBar* toolbar ){ + s_toolbarItems.push_back( { toolbar, toolbar->addSeparator(), "", true } ); +} + #include bool color_dialog( QWidget *parent, Vector3& color, const char* title ){ const QColor clr = QColorDialog::getColor( QColor::fromRgbF( color[0], color[1], color[2] ), parent, title ); diff --git a/radiant/gtkmisc.h b/radiant/gtkmisc.h index c29a7358..b2adcd00 100644 --- a/radiant/gtkmisc.h +++ b/radiant/gtkmisc.h @@ -32,6 +32,8 @@ #include #include +#include "math/vectorfwd.h" +#include "string/stringfwd.h" void process_gui(); @@ -49,14 +51,18 @@ QAction* create_check_menu_item_with_mnemonic( QMenu* menu, const char* mnemonic // this also sets up the shortcut using command_connect_accelerator QAction* toolbar_append_button( QToolBar* toolbar, const char* description, const char* icon, const char* commandName ); +QAction* toolbar_append_button( QToolBar* toolbar, const char* description, const class QIcon& icon, const char* commandName ); // this also sets up the shortcut using command_connect_accelerator QAction* toolbar_append_toggle_button( QToolBar* toolbar, const char* description, const char* icon, const char* commandName ); -#include "math/vectorfwd.h" +void toolbar_append_separator( QToolBar* toolbar ); + +void toolbar_construct_control_menu( QMenu *menu ); +void toolbar_importState( const char *commandNames ); + bool color_dialog( QWidget *parent, Vector3& color, const char* title = "Choose Color" ); -#include "string/stringfwd.h" bool OpenGLFont_dialog( QWidget *parent, const char* font, const int size, CopiedString &newfont, int &newsize ); class QLineEdit; diff --git a/radiant/mainframe.cpp b/radiant/mainframe.cpp index 5ca3554a..aa3d961c 100644 --- a/radiant/mainframe.cpp +++ b/radiant/mainframe.cpp @@ -884,8 +884,6 @@ void create_file_menu( QMenuBar *menubar ){ create_menu_item_with_mnemonic( menu, "Save s&elected...", "SaveSelected" ); create_menu_item_with_mnemonic( menu, "Save re&gion...", "SaveRegion" ); menu->addSeparator(); -// create_menu_item_with_mnemonic( menu, "&Refresh models", "RefreshReferences" ); -// menu->addSeparator(); create_menu_item_with_mnemonic( menu, "&Pointfile", "TogglePointfile" ); menu->addSeparator(); MRU_constructMenu( menu ); @@ -1176,6 +1174,7 @@ void create_misc_menu( QMenuBar *menubar ){ create_menu_item_with_mnemonic( menu, "Find brush...", "FindBrush" ); create_menu_item_with_mnemonic( menu, "Map Info...", "MapInfo" ); + create_menu_item_with_mnemonic( menu, "&Refresh models", "RefreshReferences" ); create_menu_item_with_mnemonic( menu, "Set 2D &Background image...", makeCallbackF( WXY_SetBackgroundImage ) ); create_menu_item_with_mnemonic( menu, "Fullscreen", "Fullscreen" ); create_menu_item_with_mnemonic( menu, "Maximize view", "MaximizeView" ); @@ -1383,47 +1382,49 @@ void Manipulators_constructToolbar( QToolBar* toolbar ){ toolbar_append_toggle_button( toolbar, "UV Tool", "select_mouseuv.png", "MouseUV" ); } +extern CopiedString g_toolbarHiddenButtons; + #include void create_main_toolbar( QToolBar *toolbar, MainFrame::EViewStyle style ){ QSvgGenerator dummy; // reference symbol, so that Qt5Svg.dll required dependency is explicit, also install-dlls-msys2-mingw.sh will find it File_constructToolbar( toolbar ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); UndoRedo_constructToolbar( toolbar ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); RotateFlip_constructToolbar( toolbar ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); Select_constructToolbar( toolbar ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); CSG_constructToolbar( toolbar ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); ComponentModes_constructToolbar( toolbar ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); if ( style != MainFrame::eSplit ) { XYWnd_constructToolbar( toolbar ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); } CamWnd_constructToolbar( toolbar ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); Manipulators_constructToolbar( toolbar ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); if ( !string_equal( g_pGameDescription->getKeyValue( "no_patch" ), "1" ) ) { Patch_constructToolbar( toolbar ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); } toolbar_append_toggle_button( toolbar, "Texture Lock", "texture_lock.png", "TogTexLock" ); toolbar_append_toggle_button( toolbar, "Texture Vertex Lock", "texture_vertexlock.png", "TogTexVertexLock" ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); toolbar_append_button( toolbar, "Entities", "entities.png", "ToggleEntityInspector" ); // disable the console and texture button in the regular layouts @@ -1437,7 +1438,7 @@ void create_main_toolbar( QToolBar *toolbar, MainFrame::EViewStyle style ){ // TODO: call light inspector //QAction* g_view_lightinspector_button = toolbar_append_button( toolbar, "Light Inspector", "lightinspector.png", "ToggleLightInspector" ); - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); toolbar_append_button( toolbar, "Refresh Models", "refresh_models.png", "RefreshReferences" ); } @@ -1614,6 +1615,16 @@ protected: } return QMainWindow::event( event ); } +public: + QMenu* createPopupMenu() override { + auto *menu = QMainWindow::createPopupMenu(); + if( menu == nullptr ) + menu = new QMenu; + else + menu->addSeparator(); + toolbar_construct_control_menu( menu ); + return menu; + } }; @@ -1867,6 +1878,7 @@ void MainFrame::Create(){ s_qe_every_second_timer.enable(); + toolbar_importState( g_toolbarHiddenButtons.c_str() ); RestoreGuiState(); //GlobalShortcuts_reportUnregistered(); @@ -2096,6 +2108,7 @@ void MainFrame_Construct(){ GlobalPreferenceSystem().registerPreference( "DetachableMenus", makeBoolStringImportCallback( LatchedAssignCaller( g_Layout_enableDetachableMenus ) ), BoolExportStringCaller( g_Layout_enableDetachableMenus.m_latched ) ); GlobalPreferenceSystem().registerPreference( "QE4StyleWindows", makeIntStringImportCallback( LatchedAssignCaller( g_Layout_viewStyle ) ), IntExportStringCaller( g_Layout_viewStyle.m_latched ) ); GlobalPreferenceSystem().registerPreference( "BuiltInGroupDialog", makeBoolStringImportCallback( LatchedAssignCaller( g_Layout_builtInGroupDialog ) ), BoolExportStringCaller( g_Layout_builtInGroupDialog.m_latched ) ); + GlobalPreferenceSystem().registerPreference( "ToolbarHiddenButtons", CopiedStringImportStringCaller( g_toolbarHiddenButtons ), CopiedStringExportStringCaller( g_toolbarHiddenButtons ) ); GlobalPreferenceSystem().registerPreference( "OpenGLFont", CopiedStringImportStringCaller( g_OpenGLFont ), CopiedStringExportStringCaller( g_OpenGLFont ) ); GlobalPreferenceSystem().registerPreference( "OpenGLFontSize", IntImportStringCaller( g_OpenGLFontSize ), IntExportStringCaller( g_OpenGLFontSize ) ); diff --git a/radiant/pluginmanager.cpp b/radiant/pluginmanager.cpp index 4c8c271f..bfdbd2db 100644 --- a/radiant/pluginmanager.cpp +++ b/radiant/pluginmanager.cpp @@ -40,6 +40,38 @@ #include +StringBuffer plugin_construct_command_name( const char *pluginName, const char *commandName ){ + StringBuffer str( 64 ); + + if( !string_equal_prefix_nocase( commandName, pluginName ) ){ //plugin name is not part of command name + str.push_string( pluginName ); + str.push_string( "::" ); + } + /* remove spaces + camelcasify */ + const char* p = commandName; + bool wasspace = false; + while( *p ){ + if( *p == ' ' ){ + wasspace = true; + } + else if( wasspace ){ + wasspace = false; + str.push_back( std::toupper( *p ) ); + } + else{ + str.push_back( *p ); + } + ++p; + } + /* del trailing periods */ + while( !str.empty() && str.back() == '.' ){ + str.pop_back(); + } + *str.c_str() = std::tolower( *str.c_str() ); //put to the end of the list this way //not in Qt 🤔 + + return str; +} + /* plugin manager --------------------------------------- */ class CPluginSlot final : public IPlugIn { @@ -90,7 +122,7 @@ CPluginSlot::CPluginSlot( QWidget* main_window, const char* name, const _QERPlug StringTokeniser commandTokeniser( commands, ",;" ); StringTokeniser titleTokeniser( titles, ",;" ); - while ( 1 ) { + while ( true ) { const char* cmdToken = commandTokeniser.getToken(); const char *titleToken = titleTokeniser.getToken(); if( string_empty( cmdToken ) ) @@ -102,34 +134,8 @@ CPluginSlot::CPluginSlot( QWidget* main_window, const char* name, const _QERPlug m_CommandTitleStrings.push_back( titleToken ); m_callbacks.emplace_back( PluginCaller( this, m_CommandStrings.back().c_str() ) ); - StringBuffer str( 64 ); - { - if( !string_equal_prefix_nocase( cmdToken, getMenuName() ) ){ //plugin name is not part of command name - str.push_string( getMenuName() ); - str.push_string( "::" ); - } - /* remove spaces + camelcasify */ - const char* p = cmdToken; - bool wasspace = false; - while( *p ){ - if( *p == ' ' ){ - wasspace = true; - } - else if( wasspace ){ - wasspace = false; - str.push_back( std::toupper( *p ) ); - } - else{ - str.push_back( *p ); - } - ++p; - } - /* del trailing periods */ - while( !str.empty() && str.back() == '.' ){ - str.pop_back(); - } - *str.c_str() = std::tolower( *str.c_str() ); //put to the end of the list this way //not in Qt 🤔 - } + + const auto str = plugin_construct_command_name( getMenuName(), cmdToken ); m_globalCommandNames.emplace_back( str.c_str() ); if ( !plugin_menu_special( cmdToken ) ) //ain't special GlobalCommands_insert( str.c_str(), makeCallback( m_callbacks.back() ) ); diff --git a/radiant/pluginmanager.h b/radiant/pluginmanager.h index 10813ebf..be417337 100644 --- a/radiant/pluginmanager.h +++ b/radiant/pluginmanager.h @@ -68,3 +68,7 @@ inline bool plugin_menu_special( const char* text ){ || plugin_submenu_in( text ) || plugin_submenu_out( text ); } + +#include "stream/stringstream.h" + +StringBuffer plugin_construct_command_name( const char *pluginName, const char *commandName ); diff --git a/radiant/plugintoolbar.cpp b/radiant/plugintoolbar.cpp index 8fa65ae5..86b8cce8 100644 --- a/radiant/plugintoolbar.cpp +++ b/radiant/plugintoolbar.cpp @@ -23,15 +23,16 @@ #include "itoolbar.h" +#include "gtkmisc.h" #include "modulesystem.h" #include "stream/stringstream.h" #include "os/file.h" #include "os/path.h" -#include #include "mainframe.h" #include "plugin.h" +#include "pluginmanager.h" QIcon new_plugin_icon( const char* filename ){ StringOutputStream fullpath( 256 ); @@ -46,23 +47,29 @@ QIcon new_plugin_icon( const char* filename ){ return {}; } -void toolbar_insert( QToolBar *toolbar, const char* icon, const char* text, const char* tooltip, IToolbarButton::EType type, const IToolbarButton* ibutton ){ +void toolbar_insert( QToolBar *toolbar, const char* icon, const char* text, const char* tooltip, IToolbarButton::EType type, const IToolbarButton* ibutton, const char *pluginName ){ switch ( type ) { case IToolbarButton::eSpace: - toolbar->addSeparator(); + toolbar_append_separator( toolbar ); return; case IToolbarButton::eButton: { - QAction *button = toolbar->addAction( new_plugin_icon( icon ), text, [ibutton](){ ibutton->activate(); } ); - button->setToolTip( tooltip ); + toolbar_append_button( toolbar, tooltip, new_plugin_icon( icon ), plugin_construct_command_name( pluginName, text ).c_str() ); + // QAction *button = toolbar->addAction( new_plugin_icon( icon ), text, [ibutton](){ ibutton->activate(); } ); + // button->setToolTip( tooltip ); } return; case IToolbarButton::eToggleButton: { - QAction *button = toolbar->addAction( new_plugin_icon( icon ), text, [ibutton](){ ibutton->activate(); } ); - button->setToolTip( tooltip ); - button->setCheckable( true ); + //. fixme need consistent plugin command names (same in menu and toolbar) for the current command system + // now they are defined in 3 places, also must be used in menu to work in toolbar + // also no defined toggle menu item support (->setCheckable( true ) is some workaround now) + toolbar_append_button( toolbar, tooltip, new_plugin_icon( icon ), plugin_construct_command_name( pluginName, text ).c_str() )->setCheckable( true ); + // toolbar_append_toggle_button( toolbar, tooltip, new_plugin_icon( icon ), plugin_construct_command_name( pluginName, text ).c_str() ); + // QAction *button = toolbar->addAction( new_plugin_icon( icon ), text, [ibutton](){ ibutton->activate(); } ); + // button->setToolTip( tooltip ); + // button->setCheckable( true ); } return; case IToolbarButton::eRadioButton: @@ -74,8 +81,8 @@ void toolbar_insert( QToolBar *toolbar, const char* icon, const char* text, cons } } -void PlugInToolbar_AddButton( QToolBar* toolbar, const IToolbarButton* button ){ - toolbar_insert( toolbar, button->getImage(), button->getText(), button->getTooltip(), button->getType(), button ); +void PlugInToolbar_AddButton( QToolBar* toolbar, const IToolbarButton* button, const char *pluginName ){ + toolbar_insert( toolbar, button->getImage(), button->getText(), button->getTooltip(), button->getType(), button, pluginName ); } QToolBar* g_plugin_toolbar = 0; @@ -92,7 +99,7 @@ void PluginToolbar_populate(){ const std::size_t count = table.m_pfnToolbarButtonCount(); for ( std::size_t i = 0; i < count; ++i ) { - PlugInToolbar_AddButton( m_toolbar, table.m_pfnGetToolbarButton( i ) ); + PlugInToolbar_AddButton( m_toolbar, table.m_pfnGetToolbarButton( i ), name ); } }