Make 3D view/toolbar/contextmenu command lists more consistent.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21347
This commit is contained in:
Jeff Young 2025-08-25 16:34:47 +01:00
parent 8c3026cf1a
commit 9808889c9c
4 changed files with 84 additions and 87 deletions

View File

@ -86,22 +86,39 @@ void EDA_3D_VIEWER_FRAME::doReCreateMenuBar()
viewMenu->Add( gridSubmenu ); viewMenu->Add( gridSubmenu );
viewMenu->AppendSeparator(); viewMenu->AppendSeparator();
viewMenu->Add( EDA_3D_ACTIONS::rotateXCW ); viewMenu->Add( EDA_3D_ACTIONS::viewTop );
viewMenu->Add( EDA_3D_ACTIONS::rotateXCCW ); viewMenu->Add( EDA_3D_ACTIONS::viewBottom );
viewMenu->Add( EDA_3D_ACTIONS::viewRight );
viewMenu->Add( EDA_3D_ACTIONS::viewLeft );
viewMenu->Add( EDA_3D_ACTIONS::viewFront );
viewMenu->Add( EDA_3D_ACTIONS::viewBack );
ACTION_MENU* rotateSubmenu = new ACTION_MENU( false, tool );
rotateSubmenu->SetTitle( _( "Rotate Board" ) );
rotateSubmenu->SetIcon( BITMAPS::rotate_cw );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateXCW );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateXCCW );
rotateSubmenu->AppendSeparator();
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateYCW );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateYCCW );
rotateSubmenu->AppendSeparator();
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateZCW );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateZCCW );
ACTION_MENU* moveSubmenu = new ACTION_MENU( false, tool );
moveSubmenu->SetTitle( _( "Move Board" ) );
moveSubmenu->SetIcon( BITMAPS::move );
moveSubmenu->Add( EDA_3D_ACTIONS::moveLeft );
moveSubmenu->Add( EDA_3D_ACTIONS::moveRight );
moveSubmenu->Add( EDA_3D_ACTIONS::moveUp );
moveSubmenu->Add( EDA_3D_ACTIONS::moveDown );
viewMenu->AppendSeparator(); viewMenu->AppendSeparator();
viewMenu->Add( EDA_3D_ACTIONS::rotateYCW ); viewMenu->Add( rotateSubmenu );
viewMenu->Add( EDA_3D_ACTIONS::rotateYCCW ); viewMenu->Add( EDA_3D_ACTIONS::flipView );
viewMenu->Add( moveSubmenu );
viewMenu->AppendSeparator();
viewMenu->Add( EDA_3D_ACTIONS::rotateZCW );
viewMenu->Add( EDA_3D_ACTIONS::rotateZCCW );
viewMenu->AppendSeparator();
viewMenu->Add( EDA_3D_ACTIONS::moveLeft );
viewMenu->Add( EDA_3D_ACTIONS::moveRight );
viewMenu->Add( EDA_3D_ACTIONS::moveUp );
viewMenu->Add( EDA_3D_ACTIONS::moveDown );
viewMenu->AppendSeparator(); viewMenu->AppendSeparator();
viewMenu->Add( EDA_3D_ACTIONS::showLayersManager, ACTION_MENU::CHECK ); viewMenu->Add( EDA_3D_ACTIONS::showLayersManager, ACTION_MENU::CHECK );

View File

@ -38,6 +38,30 @@
bool EDA_3D_CONTROLLER::Init() bool EDA_3D_CONTROLLER::Init()
{ {
std::shared_ptr<ACTION_MENU> rotateSubmenu = std::make_shared<ACTION_MENU>( true, this );
rotateSubmenu->SetTitle( _( "Rotate Board" ) );
rotateSubmenu->SetIcon( BITMAPS::rotate_cw );
m_menu->RegisterSubMenu( rotateSubmenu );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateXCW );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateXCCW );
rotateSubmenu->AppendSeparator();
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateYCW );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateYCCW );
rotateSubmenu->AppendSeparator();
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateZCW );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateZCCW );
std::shared_ptr<ACTION_MENU> moveSubmenu = std::make_shared<ACTION_MENU>( true, this );
moveSubmenu->SetTitle( _( "Move Board" ) );
moveSubmenu->SetIcon( BITMAPS::move );
m_menu->RegisterSubMenu( moveSubmenu );
moveSubmenu->Add( EDA_3D_ACTIONS::moveLeft );
moveSubmenu->Add( EDA_3D_ACTIONS::moveRight );
moveSubmenu->Add( EDA_3D_ACTIONS::moveUp );
moveSubmenu->Add( EDA_3D_ACTIONS::moveDown );
CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu(); CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
ctxMenu.AddItem( ACTIONS::zoomInCenter, SELECTION_CONDITIONS::ShowAlways ); ctxMenu.AddItem( ACTIONS::zoomInCenter, SELECTION_CONDITIONS::ShowAlways );
@ -46,23 +70,15 @@ bool EDA_3D_CONTROLLER::Init()
ctxMenu.AddSeparator(); ctxMenu.AddSeparator();
ctxMenu.AddItem( EDA_3D_ACTIONS::viewTop, SELECTION_CONDITIONS::ShowAlways ); ctxMenu.AddItem( EDA_3D_ACTIONS::viewTop, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::viewBottom, SELECTION_CONDITIONS::ShowAlways ); ctxMenu.AddItem( EDA_3D_ACTIONS::viewBottom, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddSeparator();
ctxMenu.AddItem( EDA_3D_ACTIONS::viewRight, SELECTION_CONDITIONS::ShowAlways ); ctxMenu.AddItem( EDA_3D_ACTIONS::viewRight, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::viewLeft, SELECTION_CONDITIONS::ShowAlways ); ctxMenu.AddItem( EDA_3D_ACTIONS::viewLeft, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddSeparator();
ctxMenu.AddItem( EDA_3D_ACTIONS::viewFront, SELECTION_CONDITIONS::ShowAlways ); ctxMenu.AddItem( EDA_3D_ACTIONS::viewFront, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::viewBack, SELECTION_CONDITIONS::ShowAlways ); ctxMenu.AddItem( EDA_3D_ACTIONS::viewBack, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddSeparator(); ctxMenu.AddSeparator();
ctxMenu.AddMenu( rotateSubmenu.get(), SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::flipView, SELECTION_CONDITIONS::ShowAlways ); ctxMenu.AddItem( EDA_3D_ACTIONS::flipView, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddMenu( moveSubmenu.get(), SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddSeparator();
ctxMenu.AddItem( EDA_3D_ACTIONS::moveLeft, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::moveRight, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::moveUp, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::moveDown, SELECTION_CONDITIONS::ShowAlways );
return true; return true;
} }
@ -116,12 +132,6 @@ int EDA_3D_CONTROLLER::UpdateMenu( const TOOL_EVENT& aEvent )
int EDA_3D_CONTROLLER::Main( const TOOL_EVENT& aEvent ) int EDA_3D_CONTROLLER::Main( const TOOL_EVENT& aEvent )
{ {
// Track right mouse button state and movement
VECTOR2D rightButtonDownPos;
const int DRAG_THRESHOLD = 4; // pixels
bool rightButtonDragged = false;
// Main loop: keep receiving events // Main loop: keep receiving events
while( TOOL_EVENT* evt = Wait() ) while( TOOL_EVENT* evt = Wait() )
{ {
@ -247,8 +257,7 @@ int EDA_3D_CONTROLLER::ToggleVisibility( const TOOL_EVENT& aEvent )
auto flipLayer = auto flipLayer =
[&]( int layer ) [&]( int layer )
{ {
appearanceManager->OnLayerVisibilityChanged( layer, appearanceManager->OnLayerVisibilityChanged( layer, !visibilityFlags.test( layer ) );
!visibilityFlags.test( layer ) );
}; };
EDA_BASE_FRAME* frame = dynamic_cast<EDA_BASE_FRAME*>( m_toolMgr->GetToolHolder() ); EDA_BASE_FRAME* frame = dynamic_cast<EDA_BASE_FRAME*>( m_toolMgr->GetToolHolder() );
@ -258,20 +267,13 @@ int EDA_3D_CONTROLLER::ToggleVisibility( const TOOL_EVENT& aEvent )
if( appearanceManager ) if( appearanceManager )
{ {
if( aEvent.IsAction( &EDA_3D_ACTIONS::showTHT ) ) if( aEvent.IsAction( &EDA_3D_ACTIONS::showTHT ) ) flipLayer( LAYER_3D_TH_MODELS );
flipLayer( LAYER_3D_TH_MODELS ); else if( aEvent.IsAction( &EDA_3D_ACTIONS::showSMD ) ) flipLayer( LAYER_3D_SMD_MODELS );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showSMD ) ) else if( aEvent.IsAction( &EDA_3D_ACTIONS::showVirtual ) ) flipLayer( LAYER_3D_VIRTUAL_MODELS );
flipLayer( LAYER_3D_SMD_MODELS ); else if( aEvent.IsAction( &EDA_3D_ACTIONS::showNotInPosFile ) ) flipLayer( LAYER_3D_MODELS_NOT_IN_POS );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showVirtual ) ) else if( aEvent.IsAction( &EDA_3D_ACTIONS::showDNP ) ) flipLayer( LAYER_3D_MODELS_MARKED_DNP );
flipLayer( LAYER_3D_VIRTUAL_MODELS ); else if( aEvent.IsAction( &EDA_3D_ACTIONS::showNavigator ) ) flipLayer( LAYER_3D_NAVIGATOR );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showNotInPosFile ) ) else if( aEvent.IsAction( &EDA_3D_ACTIONS::showBBoxes ) ) flipLayer( LAYER_3D_BOUNDING_BOXES );
flipLayer( LAYER_3D_MODELS_NOT_IN_POS );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showDNP ) )
flipLayer( LAYER_3D_MODELS_MARKED_DNP );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showNavigator ) )
flipLayer( LAYER_3D_NAVIGATOR );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showBBoxes ) )
flipLayer( LAYER_3D_BOUNDING_BOXES );
} }
return 0; return 0;
@ -325,8 +327,7 @@ int EDA_3D_CONTROLLER::doZoomInOut( bool aDirection, bool aCenterOnCursor )
{ {
if( m_canvas ) if( m_canvas )
{ {
m_canvas->SetView3D( aDirection ? VIEW3D_TYPE::VIEW3D_ZOOM_IN m_canvas->SetView3D( aDirection ? VIEW3D_TYPE::VIEW3D_ZOOM_IN : VIEW3D_TYPE::VIEW3D_ZOOM_OUT );
: VIEW3D_TYPE::VIEW3D_ZOOM_OUT );
m_canvas->DisplayStatus(); m_canvas->DisplayStatus();
} }

View File

@ -22,8 +22,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#ifndef _3D_VIEWER_CONTROL_H #pragma once
#define _3D_VIEWER_CONTROL_H
#include <tool/tool_interactive.h> #include <tool/tool_interactive.h>
@ -38,8 +37,8 @@ class BOARD_ADAPTER;
class EDA_3D_CONTROLLER : public TOOL_INTERACTIVE class EDA_3D_CONTROLLER : public TOOL_INTERACTIVE
{ {
public: public:
EDA_3D_CONTROLLER() EDA_3D_CONTROLLER() :
: TOOL_INTERACTIVE( "3DViewer.Control" ), TOOL_INTERACTIVE( "3DViewer.Control" ),
m_canvas( nullptr ), m_canvas( nullptr ),
m_boardAdapter( nullptr ), m_boardAdapter( nullptr ),
m_camera( nullptr ), m_camera( nullptr ),
@ -63,20 +62,8 @@ public:
* *
* @param aRotIncrement is the rotation increment in degrees * @param aRotIncrement is the rotation increment in degrees
*/ */
void SetRotationIncrement( double aRotIncrement ) void SetRotationIncrement( double aRotIncrement ) { m_rotationIncrement = aRotIncrement; }
{ double GetRotationIncrement() { return m_rotationIncrement; }
m_rotationIncrement = aRotIncrement;
}
/**
* Get the increment used by the RotateView actions.
*
* @return the rotation increment in degrees
*/
double GetRotationIncrement()
{
return m_rotationIncrement;
}
// View controls // View controls
int ZoomRedraw( const TOOL_EVENT& aEvent ); int ZoomRedraw( const TOOL_EVENT& aEvent );
@ -112,5 +99,3 @@ private:
CAMERA* m_camera; CAMERA* m_camera;
double m_rotationIncrement; ///< Rotation increment for the rotate actions (degrees) double m_rotationIncrement; ///< Rotation increment for the rotate actions (degrees)
}; };
#endif

View File

@ -63,8 +63,7 @@ ACTION_MENU::ACTION_MENU( bool isContextMenu, TOOL_INTERACTIVE* aTool ) :
ACTION_MENU::~ACTION_MENU() ACTION_MENU::~ACTION_MENU()
{ {
Disconnect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ACTION_MENU::OnMenuEvent ), Disconnect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ACTION_MENU::OnMenuEvent ), nullptr, this );
nullptr, this );
Disconnect( wxEVT_IDLE, wxIdleEventHandler( ACTION_MENU::OnIdle ), nullptr, this ); Disconnect( wxEVT_IDLE, wxIdleEventHandler( ACTION_MENU::OnIdle ), nullptr, this );
// Set parent to NULL to prevent submenus from unregistering from a nonexistent object // Set parent to NULL to prevent submenus from unregistering from a nonexistent object
@ -86,8 +85,7 @@ void ACTION_MENU::SetIcon( BITMAPS aIcon )
void ACTION_MENU::setupEvents() void ACTION_MENU::setupEvents()
{ {
Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ACTION_MENU::OnMenuEvent ), nullptr, Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ACTION_MENU::OnMenuEvent ), nullptr, this );
this );
Connect( wxEVT_IDLE, wxIdleEventHandler( ACTION_MENU::OnIdle ), nullptr, this ); Connect( wxEVT_IDLE, wxIdleEventHandler( ACTION_MENU::OnIdle ), nullptr, this );
} }
@ -159,8 +157,8 @@ wxMenuItem* ACTION_MENU::Add( const wxString& aLabel, const wxString& aTooltip,
{ {
wxASSERT_MSG( FindItem( aId ) == nullptr, wxS( "Duplicate menu IDs!" ) ); wxASSERT_MSG( FindItem( aId ) == nullptr, wxS( "Duplicate menu IDs!" ) );
wxMenuItem* item = new wxMenuItem( this, aId, aLabel, aTooltip, wxMenuItem* item = new wxMenuItem( this, aId, aLabel, aTooltip, aIsCheckmarkEntry ? wxITEM_CHECK
aIsCheckmarkEntry ? wxITEM_CHECK : wxITEM_NORMAL ); : wxITEM_NORMAL );
if( !!aIcon ) if( !!aIcon )
KIUI::AddBitmapToMenuItem( item, KiBitmapBundle( aIcon ) ); KIUI::AddBitmapToMenuItem( item, KiBitmapBundle( aIcon ) );
@ -178,8 +176,7 @@ wxMenuItem* ACTION_MENU::Add( const TOOL_ACTION& aAction, bool aIsCheckmarkEntry
// Allow the label to be overridden at point of use // Allow the label to be overridden at point of use
wxString menuLabel = aOverrideLabel.IsEmpty() ? aAction.GetMenuItem() : aOverrideLabel; wxString menuLabel = aOverrideLabel.IsEmpty() ? aAction.GetMenuItem() : aOverrideLabel;
wxMenuItem* item = new wxMenuItem( this, aAction.GetUIId(), menuLabel, wxMenuItem* item = new wxMenuItem( this, aAction.GetUIId(), menuLabel, aAction.GetTooltip(),
aAction.GetTooltip(),
aIsCheckmarkEntry ? wxITEM_CHECK : wxITEM_NORMAL ); aIsCheckmarkEntry ? wxITEM_CHECK : wxITEM_NORMAL );
if( !!icon ) if( !!icon )
KIUI::AddBitmapToMenuItem( item, KiBitmapBundle( icon ) ); KIUI::AddBitmapToMenuItem( item, KiBitmapBundle( icon ) );
@ -194,8 +191,7 @@ wxMenuItem* ACTION_MENU::Add( ACTION_MENU* aMenu )
{ {
m_submenus.push_back( aMenu ); m_submenus.push_back( aMenu );
wxASSERT_MSG( !aMenu->m_title.IsEmpty(), wxASSERT_MSG( !aMenu->m_title.IsEmpty(), wxS( "Set a title for ACTION_MENU using SetTitle()" ) );
wxS( "Set a title for ACTION_MENU using SetTitle()" ) );
if( !!aMenu->m_icon ) if( !!aMenu->m_icon )
{ {
@ -334,8 +330,7 @@ ACTION_MENU* ACTION_MENU::create() const
ACTION_MENU* menu = new ACTION_MENU( false ); ACTION_MENU* menu = new ACTION_MENU( false );
wxASSERT_MSG( typeid( *this ) == typeid( *menu ), wxASSERT_MSG( typeid( *this ) == typeid( *menu ),
wxString::Format( "You need to override create() method for class %s", wxString::Format( "You need to override create() method for class %s", typeid( *this ).name() ) );
typeid( *this ).name() ) );
return menu; return menu;
} }
@ -524,9 +519,8 @@ void ACTION_MENU::OnMenuEvent( wxMenuEvent& aEvent )
#define ID_CONTEXT_MENU_ID_MAX wxID_LOWEST /* = 100 should be plenty */ #define ID_CONTEXT_MENU_ID_MAX wxID_LOWEST /* = 100 should be plenty */
if( !evt && if( !evt && ( ( m_selected >= 0 && m_selected < ID_CONTEXT_MENU_ID_MAX )
( ( m_selected >= 0 && m_selected < ID_CONTEXT_MENU_ID_MAX ) || || ( m_selected >= ID_POPUP_MENU_START && m_selected <= ID_POPUP_MENU_END ) ) )
( m_selected >= ID_POPUP_MENU_START && m_selected <= ID_POPUP_MENU_END ) ) )
{ {
ACTION_MENU* actionMenu = dynamic_cast<ACTION_MENU*>( GetParent() ); ACTION_MENU* actionMenu = dynamic_cast<ACTION_MENU*>( GetParent() );