kicad-source/common/dialogs/panel_toolbar_customization.cpp
Ian McInerney e202b00a74 Rework the toolbar settings storage and panel
This format is more extendable in the future, should separator and
spacer support be added to groups.

Also, this now has a working UI for modifying the toolbars.
2025-02-28 02:05:50 +00:00

838 lines
25 KiB
C++

/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <dialogs/panel_toolbar_customization.h>
#include <bitmaps.h>
#include <settings/app_settings.h>
#include <tool/ui/toolbar_configuration.h>
#include <widgets/split_button.h>
#include <widgets/std_bitmap_button.h>
#include <magic_enum.hpp>
#include <wx/listctrl.h>
#include <wx/menu.h>
// Simple IDs for the split button menu
enum
{
ID_SEPARATOR_MENU = ( wxID_HIGHEST + 5 ),
ID_SPACER_MENU,
ID_GROUP_MENU
};
static std::map<TOOLBAR_LOC, wxString> s_toolbarNameMap = {
{ TOOLBAR_LOC::LEFT, _( "Left" ) },
{ TOOLBAR_LOC::RIGHT, _( "Right" ) },
{ TOOLBAR_LOC::TOP_AUX, _( "Top main" ) },
{ TOOLBAR_LOC::TOP_MAIN, _( "Top auxillary" ) }
};
class TOOLBAR_TREE_ITEM_DATA : public wxTreeItemData
{
public:
TOOLBAR_TREE_ITEM_DATA()
{ }
TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE aType ) :
m_type( aType )
{ }
TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE aType, int aSize ) :
m_type( aType ),
m_size( aSize )
{
wxASSERT( aType == TOOLBAR_ITEM_TYPE::SPACER );
}
TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE aType, wxString aName ) :
m_type( aType ),
m_name( aName )
{
wxASSERT( aType == TOOLBAR_ITEM_TYPE::CONTROL
|| aType == TOOLBAR_ITEM_TYPE::GROUP );
}
TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE aType, TOOL_ACTION* aAction ) :
m_type( aType ),
m_action( aAction )
{
wxASSERT( aType == TOOLBAR_ITEM_TYPE::TOOL );
}
void SetAction( TOOL_ACTION* aAction ) { m_action = aAction; }
TOOL_ACTION* GetAction() const { return m_action; }
void SetName( const wxString& aName ) { m_name = aName; }
const wxString& GetName() const { return m_name; }
void SetSize( int aSize ) { m_size = aSize; }
int GetSize() const { return m_size; }
TOOLBAR_ITEM_TYPE GetType() const { return m_type; }
private:
// Item type
TOOLBAR_ITEM_TYPE m_type;
// Tool properties
TOOL_ACTION* m_action;
// Spacer properties
int m_size;
// Group/control properties
wxString m_name;
};
PANEL_TOOLBAR_CUSTOMIZATION::PANEL_TOOLBAR_CUSTOMIZATION( wxWindow* aParent, APP_SETTINGS_BASE* aCfg,
TOOLBAR_SETTINGS* aTbSettings,
std::vector<TOOL_ACTION*> aTools,
std::vector<ACTION_TOOLBAR_CONTROL*> aControls ) :
PANEL_TOOLBAR_CUSTOMIZATION_BASE( aParent ),
m_actionImageList( nullptr ),
m_appSettings( aCfg ),
m_appTbSettings( aTbSettings )
{
// Copy the tools and controls into the internal maps
for( auto& tool : aTools )
m_availableTools.emplace( tool->GetName(), tool );
for( auto& control : aControls )
m_availableControls.emplace( control->GetName(), control );
// Configure the Ui elements
m_btnToolDelete->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
m_btnToolMoveUp->SetBitmap( KiBitmapBundle( BITMAPS::small_up ) );
m_btnToolMoveDown->SetBitmap( KiBitmapBundle( BITMAPS::small_down ) );
m_btnAddTool->SetBitmap( KiBitmapBundle( BITMAPS::left ) );
m_insertButton->SetLabel( _( "Insert separator" ) );
//m_insertButton->SetWidthPadding( 4 );
// Populate the browse library options
wxMenu* insertMenu = m_insertButton->GetSplitButtonMenu();
insertMenu->Append( ID_SPACER_MENU, _( "Insert spacer" ) );
insertMenu->Append( ID_GROUP_MENU, _( "Insert group" ) );
insertMenu->Bind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_TOOLBAR_CUSTOMIZATION::onSpacerPress,
this, ID_SPACER_MENU );
insertMenu->Bind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_TOOLBAR_CUSTOMIZATION::onGroupPress,
this, ID_GROUP_MENU );
// This is the button only press for the browse button instead of the menu
m_insertButton->Bind( wxEVT_BUTTON, &PANEL_TOOLBAR_CUSTOMIZATION::onSeparatorPress, this );
// TODO (ISM): Enable moving up/down and draging
m_btnToolMoveDown->Enable( false );
m_btnToolMoveUp->Enable( false );
}
PANEL_TOOLBAR_CUSTOMIZATION::~PANEL_TOOLBAR_CUSTOMIZATION()
{
delete m_actionImageList;
}
void PANEL_TOOLBAR_CUSTOMIZATION::ResetPanel()
{
// Go over every toolbar and initialize things
for( auto& tb : magic_enum::enum_values<TOOLBAR_LOC>() )
{
// Create a shadow toolbar
auto tbConfig = m_appTbSettings->DefaultToolbarConfig( tb );
if( tbConfig.has_value() )
m_toolbars[tb] = tbConfig.value();
}
// Populate the toolbar view with the default toolbar
m_tbChoice->SetSelection( 0 );
auto firstTb = magic_enum::enum_cast<TOOLBAR_LOC>( 0 );
if( firstTb.has_value() )
m_currentToolbar = firstTb.value();
populateToolbarTree();
}
bool PANEL_TOOLBAR_CUSTOMIZATION::TransferDataToWindow()
{
wxArrayString tbChoices;
// Go over every toolbar and initialize things
for( auto& tb : magic_enum::enum_values<TOOLBAR_LOC>() )
{
// Create a shadow toolbar
auto tbConfig = m_appTbSettings->GetToolbarConfig( tb );
if( tbConfig.has_value() )
m_toolbars.emplace( tb, tbConfig.value() );
// Setup the UI name
const auto& tbName = s_toolbarNameMap.find( tb );
wxASSERT_MSG( tbName != s_toolbarNameMap.end(),
wxString::Format( "Unknown toolbar: %s", magic_enum::enum_name( tb ) ) );
tbChoices.Add( tbName->second );
}
m_tbChoice->Set( tbChoices );
// Always populate the actions before the toolbars, that way the icons are available
populateActions();
// Populate the toolbar view
m_tbChoice->SetSelection( 0 );
auto firstTb = magic_enum::enum_cast<TOOLBAR_LOC>( 0 );
if( firstTb.has_value() )
m_currentToolbar = firstTb.value();
populateToolbarTree();
// Sync the enable/disable control
enableCustomControls( m_appSettings->m_CustomToolbars );
m_customToolbars->SetValue( m_appSettings->m_CustomToolbars );
return true;
}
bool PANEL_TOOLBAR_CUSTOMIZATION::TransferDataFromWindow()
{
m_appSettings->m_CustomToolbars = m_customToolbars->GetValue();
// Store the current toolbar
auto currentTb = parseToolbarTree();
if( currentTb.has_value() )
m_toolbars[m_currentToolbar] = currentTb.value();
// Write the shadow toolbars with changes back to the app toolbar settings
for( auto& tb : m_toolbars )
m_appTbSettings->SetStoredToolbarConfig( tb.first, tb.second );
return true;
}
std::optional<TOOLBAR_CONFIGURATION> PANEL_TOOLBAR_CUSTOMIZATION::parseToolbarTree()
{
TOOLBAR_CONFIGURATION config;
wxTreeItemId mainId;
wxTreeItemId rootId = m_toolbarTree->GetRootItem();
wxTreeItemIdValue mainCookie;
if( !rootId.IsOk() )
return std::nullopt;
mainId = m_toolbarTree->GetFirstChild( rootId, mainCookie );
while( mainId.IsOk() )
{
wxTreeItemData* treeData = m_toolbarTree->GetItemData( mainId );
TOOLBAR_TREE_ITEM_DATA* tbData = dynamic_cast<TOOLBAR_TREE_ITEM_DATA*>( treeData );
wxASSERT( tbData );
switch( tbData->GetType() )
{
case TOOLBAR_ITEM_TYPE::SPACER:
config.AppendSpacer( tbData->GetSize() );
break;
case TOOLBAR_ITEM_TYPE::SEPARATOR:
config.AppendSeparator();
break;
case TOOLBAR_ITEM_TYPE::CONTROL:
config.AppendControl( tbData->GetName().ToStdString() );
break;
case TOOLBAR_ITEM_TYPE::TOOL:
config.AppendAction( *( tbData->GetAction() ) );
break;
case TOOLBAR_ITEM_TYPE::GROUP:
TOOLBAR_GROUP_CONFIG grpConfig( tbData->GetName() );
if( m_toolbarTree->ItemHasChildren( mainId ) )
{
wxTreeItemIdValue childCookie;
wxTreeItemId childId = m_toolbarTree->GetFirstChild( mainId, childCookie );
while( childId.IsOk() )
{
wxTreeItemData* childTreeData = m_toolbarTree->GetItemData( childId );
TOOLBAR_TREE_ITEM_DATA* childTbData = dynamic_cast<TOOLBAR_TREE_ITEM_DATA*>( childTreeData );
wxASSERT( childTbData );
switch( childTbData->GetType() )
{
case TOOLBAR_ITEM_TYPE::GROUP:
case TOOLBAR_ITEM_TYPE::SPACER:
case TOOLBAR_ITEM_TYPE::SEPARATOR:
case TOOLBAR_ITEM_TYPE::CONTROL:
wxASSERT_MSG( false, "Invalid entry in a group" );
break;
case TOOLBAR_ITEM_TYPE::TOOL:
grpConfig.AddAction( *( childTbData->GetAction() ) );
break;
}
childId = m_toolbarTree->GetNextChild( mainId, childCookie );
}
}
config.AppendGroup( grpConfig );
}
mainId = m_toolbarTree->GetNextChild( rootId, mainCookie );
}
return config;
}
void PANEL_TOOLBAR_CUSTOMIZATION::populateToolbarTree()
{
m_toolbarTree->DeleteAllItems();
m_toolbarTree->SetImageList( m_actionImageList );
const auto& it = m_toolbars.find( m_currentToolbar );
if( it == m_toolbars.end() )
{
// Disable the controls and bail out - no toolbar here
enableToolbarControls( false );
return;
}
// Ensure the controls are enabled
enableToolbarControls( true );
TOOLBAR_CONFIGURATION toolbar = it->second;
wxTreeItemId root = m_toolbarTree->AddRoot( "Toolbar" );
for( auto& item : toolbar.GetToolbarItems() )
{
switch( item.m_Type )
{
case TOOLBAR_ITEM_TYPE::SEPARATOR:
{
// Add a separator
TOOLBAR_TREE_ITEM_DATA* sepTreeItem = new TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE::SEPARATOR );
m_toolbarTree->AppendItem( root, "Separator", -1, -1, sepTreeItem );
break;
}
case TOOLBAR_ITEM_TYPE::SPACER:
{
// Add a spacer
TOOLBAR_TREE_ITEM_DATA* spacerTreeItem = new TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE::SPACER );
spacerTreeItem->SetSize( item.m_Size );
m_toolbarTree->AppendItem( root, wxString::Format( "Spacer: %i", item.m_Size ), -1, -1,
spacerTreeItem );
break;
}
case TOOLBAR_ITEM_TYPE::CONTROL:
{
// Add a control
TOOLBAR_TREE_ITEM_DATA* controlTreeItem = new TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE::CONTROL );
controlTreeItem->SetName( item.m_ControlName );
m_toolbarTree->AppendItem( root, item.m_ControlName, -1, -1,
controlTreeItem );
break;
}
case TOOLBAR_ITEM_TYPE::TOOL:
{
// Add a tool
auto toolMap = m_availableTools.find( item.m_ActionName );
if( toolMap == m_availableTools.end() )
{
wxASSERT_MSG( false, wxString::Format( "Unable to find tool %s", item.m_ActionName ) );
continue;
}
TOOLBAR_TREE_ITEM_DATA* toolTreeItem = new TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE::TOOL );
toolTreeItem->SetAction( toolMap->second );
int imgIdx = -1;
auto imgMap = m_actionImageListMap.find( item.m_ActionName );
if( imgMap != m_actionImageListMap.end() )
imgIdx = imgMap->second;
m_toolbarTree->AppendItem( root, toolMap->second->GetFriendlyName(),
imgIdx, -1, toolTreeItem );
break;
}
case TOOLBAR_ITEM_TYPE::GROUP:
{
// Add a group of items to the toolbar
TOOLBAR_TREE_ITEM_DATA* groupTreeItem = new TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE::GROUP );
groupTreeItem->SetName( item.m_GroupName );
wxTreeItemId groupId = m_toolbarTree->AppendItem( root, item.m_GroupName, -1, -1,
groupTreeItem );
// Add the elements below the group
for( auto& groupItem : item.m_GroupItems )
{
auto toolMap = m_availableTools.find( groupItem.m_ActionName );
if( toolMap == m_availableTools.end() )
{
wxASSERT_MSG( false, wxString::Format( "Unable to find group tool %s", groupItem.m_ActionName ) );
continue;
}
TOOLBAR_TREE_ITEM_DATA* toolTreeItem = new TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE::TOOL );
toolTreeItem->SetAction( toolMap->second );
int imgIdx = -1;
auto imgMap = m_actionImageListMap.find( groupItem.m_ActionName );
if( imgMap != m_actionImageListMap.end() )
imgIdx = imgMap->second;
m_toolbarTree->AppendItem( groupId, toolMap->second->GetFriendlyName(),
imgIdx, -1, toolTreeItem );
}
break;
}
}
}
m_toolbarTree->ExpandAll();
wxTreeItemIdValue temp;
wxTreeItemId firstItem = m_toolbarTree->GetFirstChild( root, temp );
if( firstItem.IsOk() )
{
m_toolbarTree->SelectItem( firstItem );
m_toolbarTree->EnsureVisible( firstItem );
}
}
void PANEL_TOOLBAR_CUSTOMIZATION::populateActions()
{
// Clear all existing information for the actions
delete m_actionImageList;
m_actionImageListMap.clear();
m_actionImageBundleVector.clear();
// Prep the control
m_actionsList->DeleteAllItems();
m_actionsList->DeleteAllColumns();
m_actionsList->InsertColumn( 0, "", wxLIST_FORMAT_LEFT, wxLIST_AUTOSIZE );
// Prepare the image list (taken from project_tree.cpp)
int logicSize = 24 * GetDPIScaleFactor() / GetContentScaleFactor(); // Cross-platform way
int physSize = ToPhys( logicSize ); // aka *GetContentScaleFactor()
if( physSize >= 64 )
physSize = 64;
else if( physSize >= 48 )
physSize = 48;
else if( physSize >= 32 )
physSize = 32;
else
physSize = 24;
logicSize = std::min( logicSize, physSize );
int bmpsf = std::max( 1, physSize / logicSize );
logicSize = physSize / bmpsf;
auto toBitmap = [&]( BITMAPS aBmps )
{
wxBitmap bmp = KiBitmap( aBmps, physSize );
bmp.SetScaleFactor( bmpsf );
wxASSERT(bmp.IsOk());
return bmp;
};
m_actionImageList = new wxImageList( logicSize, logicSize, true,
static_cast<int>( m_availableTools.size() ) );
// Populate the various image lists for the action icons, and the actual control
int itemIdx = 0;
for( auto [k, tool] : m_availableTools )
{
if( tool->CheckToolbarState( TOOLBAR_STATE::HIDDEN ) )
continue;
wxListItem item;
item.SetText( tool->GetFriendlyName() );
item.SetData( static_cast<void*>( tool ) );
item.SetId( itemIdx++ );
if( tool->GetIcon() != BITMAPS::INVALID_BITMAP )
{
int idx = m_actionImageList->Add( toBitmap( tool->GetIcon() ) );
// If the image list throws away the image, then we shouldn't show the image anywhere.
// TODO: Make sure all images have all possible sizes so the image list doesn't get grumpy.
if( idx != -1 )
{
m_actionImageBundleVector.push_back( KiBitmapBundle( tool->GetIcon() ) );
m_actionImageListMap.emplace( tool->GetName(), idx );
item.SetImage( idx );
}
}
m_actionsList->InsertItem( item );
}
m_actionsList->SetSmallImages( m_actionImageBundleVector );
// This must be done after adding everything to the list to make the columns wide enough
m_actionsList->SetColumnWidth( 0, wxLIST_AUTOSIZE );
}
void PANEL_TOOLBAR_CUSTOMIZATION::onGroupPress( wxCommandEvent& aEvent )
{
TOOLBAR_TREE_ITEM_DATA* treeItem = new TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE::GROUP,
_( "Group" ) );
wxTreeItemId newItem;
wxTreeItemId selItem = m_toolbarTree->GetSelection();
if( selItem.IsOk() )
{
// Can't add a group onto a group
wxTreeItemId parent = m_toolbarTree->GetItemParent( selItem );
if( parent.IsOk() )
{
wxTreeItemId secondParent = m_toolbarTree->GetItemParent( parent );
if( secondParent.IsOk() )
{
delete treeItem;
return;
}
}
newItem = m_toolbarTree->InsertItem( m_toolbarTree->GetRootItem(), selItem, treeItem->GetName(),
-1, -1, treeItem );
}
else
{
newItem = m_toolbarTree->AppendItem( m_toolbarTree->GetRootItem(), treeItem->GetName(), -1, -1,
treeItem );
}
if( newItem.IsOk() )
{
m_toolbarTree->SelectItem( newItem );
m_toolbarTree->EnsureVisible( newItem );
}
}
void PANEL_TOOLBAR_CUSTOMIZATION::onSpacerPress( wxCommandEvent& aEvent )
{
TOOLBAR_TREE_ITEM_DATA* treeItem = new TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE::SPACER, 5 );
wxString label = wxString::Format( "Spacer: %i", treeItem->GetSize() );
wxTreeItemId newItem;
wxTreeItemId selItem = m_toolbarTree->GetSelection();
if( selItem.IsOk() )
{
// Insert after the current selection at the same level
wxTreeItemId parent = m_toolbarTree->GetItemParent( selItem );
// Can't insert a spacer in a group yet
if( parent.IsOk() )
{
wxTreeItemId secondParent = m_toolbarTree->GetItemParent( parent );
if( secondParent.IsOk() )
{
delete treeItem;
return;
}
}
newItem = m_toolbarTree->InsertItem( parent, selItem, label, -1, -1, treeItem );
}
else
newItem = m_toolbarTree->AppendItem( m_toolbarTree->GetRootItem(), label, -1, -1, treeItem );
if( newItem.IsOk() )
{
m_toolbarTree->SelectItem( newItem );
m_toolbarTree->EnsureVisible( newItem );
}
}
void PANEL_TOOLBAR_CUSTOMIZATION::onSeparatorPress( wxCommandEvent& aEvent )
{
TOOLBAR_TREE_ITEM_DATA* treeItem = new TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE::SEPARATOR );
wxTreeItemId newItem;
wxTreeItemId selItem = m_toolbarTree->GetSelection();
if( selItem.IsOk() )
{
// Insert after the current selection at the same level
wxTreeItemId parent = m_toolbarTree->GetItemParent( selItem );
// Can't insert a separator in a group yet
if( parent.IsOk() )
{
wxTreeItemId secondParent = m_toolbarTree->GetItemParent( parent );
if( secondParent.IsOk() )
{
delete treeItem;
return;
}
}
newItem = m_toolbarTree->InsertItem( parent, selItem, "Separator", -1, -1, treeItem );
}
else
{
newItem = m_toolbarTree->AppendItem( m_toolbarTree->GetRootItem(), "Separator", -1, -1,
treeItem );
}
if( newItem.IsOk() )
{
m_toolbarTree->SelectItem( newItem );
m_toolbarTree->EnsureVisible( newItem );
}
}
void PANEL_TOOLBAR_CUSTOMIZATION::onCustomizeTbCb( wxCommandEvent& event )
{
enableCustomControls( event.IsChecked() );
}
void PANEL_TOOLBAR_CUSTOMIZATION::enableCustomControls( bool enable )
{
m_tbChoice->Enable( enable );
enableToolbarControls( enable );
}
void PANEL_TOOLBAR_CUSTOMIZATION::enableToolbarControls( bool enable )
{
m_toolbarTree->Enable( enable );
m_btnAddTool->Enable( enable );
m_btnToolDelete->Enable( enable );
// TODO (ISM): Enable moving up/down
//m_btnToolMoveDown->Enable( enable );
//m_btnToolMoveUp->Enable( enable );
m_actionsList->Enable( enable );
m_insertButton->Enable( enable );
}
void PANEL_TOOLBAR_CUSTOMIZATION::onToolDelete( wxCommandEvent& event )
{
wxTreeItemId item = m_toolbarTree->GetSelection();
if( !item.IsOk() )
return;
// The tree control defaults to nothing selected if you delete the item
// at the last place, so we have to manually get the itme immediately before
// the one we will delete, and then select it if nothing is selected.
wxTreeItemId prev = m_toolbarTree->GetPrevSibling( item );
m_toolbarTree->Delete( item );
item = m_toolbarTree->GetSelection();
if( !item.IsOk() && prev.IsOk() )
{
m_toolbarTree->SelectItem( prev );
m_toolbarTree->EnsureVisible( prev );
}
}
void PANEL_TOOLBAR_CUSTOMIZATION::onToolMoveUp( wxCommandEvent& event )
{
}
void PANEL_TOOLBAR_CUSTOMIZATION::onToolMoveDown( wxCommandEvent& event )
{
}
void PANEL_TOOLBAR_CUSTOMIZATION::onBtnAddAction( wxCommandEvent& event )
{
// Get the selected item
long actionIdx = m_actionsList->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
// Nothing is selected, bail out
if( actionIdx < 0 )
return;
// This is needed because GetItemData returns a wxUIntPtr, which is actually size_t...
void* v = ( void* ) m_actionsList->GetItemData( actionIdx );
TOOL_ACTION* action = static_cast<TOOL_ACTION*>( v );
// Build the item to add
TOOLBAR_TREE_ITEM_DATA* toolTreeItem = new TOOLBAR_TREE_ITEM_DATA( TOOLBAR_ITEM_TYPE::TOOL );
toolTreeItem->SetAction( action );
int imgIdx = -1;
auto imgMap = m_actionImageListMap.find( action->GetName() );
if( imgMap != m_actionImageListMap.end() )
imgIdx = imgMap->second;
// Actually add the item
wxString label = action->GetFriendlyName();
wxTreeItemId selItem = m_toolbarTree->GetSelection();
wxTreeItemId newItem;
if( selItem.IsOk() )
{
TOOLBAR_TREE_ITEM_DATA* data =
dynamic_cast<TOOLBAR_TREE_ITEM_DATA*>( m_toolbarTree->GetItemData( selItem ) );
if( data && data->GetType() == TOOLBAR_ITEM_TYPE::GROUP )
{
// Insert into the end of the group
newItem = m_toolbarTree->AppendItem( selItem, label, imgIdx, -1, toolTreeItem );
}
else
{
// Insert after the current selection at the same level
wxTreeItemId parent = m_toolbarTree->GetItemParent( selItem );
newItem = m_toolbarTree->InsertItem( parent, selItem, label, imgIdx, -1, toolTreeItem );
}
}
else
{
// Insert at the root level if there is no selection
newItem = m_toolbarTree->AppendItem( m_toolbarTree->GetRootItem(), label, imgIdx, -1,
toolTreeItem );
}
if( newItem.IsOk() )
{
m_toolbarTree->SelectItem( newItem );
m_toolbarTree->EnsureVisible( newItem );
// Move the action to the next available one, to be nice
if( ++actionIdx < m_actionsList->GetItemCount() )
m_actionsList->SetItemState( actionIdx, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
}
}
void PANEL_TOOLBAR_CUSTOMIZATION::onTreeBeginLabelEdit( wxTreeEvent& event )
{
wxTreeItemId id = event.GetItem();
if( id.IsOk() )
{
wxTreeItemData* treeData = m_toolbarTree->GetItemData( id );
TOOLBAR_TREE_ITEM_DATA* tbData = dynamic_cast<TOOLBAR_TREE_ITEM_DATA*>( treeData );
switch( tbData->GetType() )
{
case TOOLBAR_ITEM_TYPE::TOOL:
case TOOLBAR_ITEM_TYPE::CONTROL:
case TOOLBAR_ITEM_TYPE::SEPARATOR:
// Don't let these be edited
event.Veto();
break;
case TOOLBAR_ITEM_TYPE::GROUP:
case TOOLBAR_ITEM_TYPE::SPACER:
// Do nothing here
break;
}
}
}
void PANEL_TOOLBAR_CUSTOMIZATION::onTreeEndLabelEdit( wxTreeEvent& event )
{
}
void PANEL_TOOLBAR_CUSTOMIZATION::onTbChoiceSelect( wxCommandEvent& event )
{
// Store the current toolbar
auto currentTb = parseToolbarTree();
if( currentTb.has_value() )
m_toolbars[m_currentToolbar] = currentTb.value();
// Populate the new one
auto newTb = magic_enum::enum_cast<TOOLBAR_LOC>( event.GetInt() );
if( newTb.has_value() )
{
m_currentToolbar = newTb.value();
populateToolbarTree();
}
}