Pcbnew: Make point selection more reusable

This moves the interactive pick point/item tool action to
PCB_PICKER_TOOL, and add a parameter to allow it to be useful for other
tools that want to pick a point from the canvas.
This commit is contained in:
John Beard 2024-10-28 21:23:56 +08:00
parent 1dfe431c00
commit 9c0e4a3f66
9 changed files with 207 additions and 198 deletions

View File

@ -21,12 +21,15 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <dialogs/dialog_position_relative.h> #include "dialogs/dialog_position_relative.h"
#include <math/util.h> // for KiROUND #include <math/util.h> // for KiROUND
#include <tools/pcb_actions.h> #include <tools/pcb_actions.h>
#include <widgets/tab_traversal.h> #include <widgets/tab_traversal.h>
#include <pcb_edit_frame.h> #include <pcb_edit_frame.h>
#include <board_design_settings.h> #include <board_design_settings.h>
#include <tools/pcb_picker_tool.h>
#include <tools/position_relative_tool.h>
#include <trigo.h> #include <trigo.h>
// initialise statics // initialise statics
@ -213,9 +216,11 @@ void DIALOG_POSITION_RELATIVE::OnSelectItemClick( wxCommandEvent& event )
{ {
event.Skip(); event.Skip();
POSITION_RELATIVE_TOOL* posrelTool = m_toolMgr->GetTool<POSITION_RELATIVE_TOOL>(); PCB_PICKER_TOOL* pickerTool = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
wxASSERT( posrelTool ); wxCHECK( pickerTool, /* void */ );
m_toolMgr->RunAction( PCB_ACTIONS::selectPositionRelativeItem ); m_toolMgr->RunAction(
PCB_ACTIONS::selectItemInteractively,
PCB_PICKER_TOOL::INTERACTIVE_PARAMS{ this, _( "Select reference item..." ) } );
Hide(); Hide();
} }
@ -225,15 +230,17 @@ void DIALOG_POSITION_RELATIVE::OnSelectPointClick( wxCommandEvent& event )
{ {
event.Skip(); event.Skip();
POSITION_RELATIVE_TOOL* posrelTool = m_toolMgr->GetTool<POSITION_RELATIVE_TOOL>(); PCB_PICKER_TOOL* pickerTool = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
wxASSERT( posrelTool ); wxCHECK( pickerTool, /* void */ );
m_toolMgr->RunAction( PCB_ACTIONS::selectPositionRelativePoint ); m_toolMgr->RunAction(
PCB_ACTIONS::selectPointInteractively,
PCB_PICKER_TOOL::INTERACTIVE_PARAMS{ this, _( "Select reference point..." ) } );
Hide(); Hide();
} }
void DIALOG_POSITION_RELATIVE::updateAnchorInfo( BOARD_ITEM* aItem ) void DIALOG_POSITION_RELATIVE::updateAnchorInfo( const BOARD_ITEM* aItem )
{ {
switch( m_options.anchorType ) switch( m_options.anchorType )
{ {
@ -301,12 +308,12 @@ void DIALOG_POSITION_RELATIVE::OnUseUserOriginClick( wxCommandEvent& event )
} }
void DIALOG_POSITION_RELATIVE::UpdateAnchor( EDA_ITEM* aItem ) void DIALOG_POSITION_RELATIVE::UpdatePickedItem( const EDA_ITEM* aItem )
{ {
BOARD_ITEM* item = nullptr; const BOARD_ITEM* item = nullptr;
if( aItem && aItem->IsBOARD_ITEM() ) if( aItem && aItem->IsBOARD_ITEM() )
item = static_cast<BOARD_ITEM*>( aItem ); item = static_cast<const BOARD_ITEM*>( aItem );
m_options.anchorType = ANCHOR_ITEM; m_options.anchorType = ANCHOR_ITEM;
updateAnchorInfo( item ); updateAnchorInfo( item );
@ -318,7 +325,7 @@ void DIALOG_POSITION_RELATIVE::UpdateAnchor( EDA_ITEM* aItem )
} }
void DIALOG_POSITION_RELATIVE::UpdateAnchor( std::optional<VECTOR2I> aPoint ) void DIALOG_POSITION_RELATIVE::UpdatePickedPoint( const std::optional<VECTOR2I>& aPoint )
{ {
m_options.anchorType = ANCHOR_POINT; m_options.anchorType = ANCHOR_POINT;

View File

@ -30,17 +30,19 @@
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <widgets/unit_binder.h> #include <widgets/unit_binder.h>
#include "tools/position_relative_tool.h" #include <tools/pcb_picker_tool.h>
class DIALOG_POSITION_RELATIVE : public DIALOG_POSITION_RELATIVE_BASE class DIALOG_POSITION_RELATIVE : public DIALOG_POSITION_RELATIVE_BASE,
public PCB_PICKER_TOOL::RECEIVER
{ {
public: public:
// Constructor and destructor // Constructor and destructor
DIALOG_POSITION_RELATIVE( PCB_BASE_FRAME* aParent ); DIALOG_POSITION_RELATIVE( PCB_BASE_FRAME* aParent );
~DIALOG_POSITION_RELATIVE() { }; ~DIALOG_POSITION_RELATIVE() { };
void UpdateAnchor( EDA_ITEM* aItem ); // Implement the RECEIVER interface for the callback from the TOOL
void UpdateAnchor( std::optional<VECTOR2I> aPoint ); void UpdatePickedItem( const EDA_ITEM* aItem ) override;
void UpdatePickedPoint( const std::optional<VECTOR2I>& aPoint ) override;
private: private:
/** /**
@ -77,7 +79,7 @@ private:
void updateDialogControls( bool aPolar ); void updateDialogControls( bool aPolar );
// Update controls and labels after changing anchor type // Update controls and labels after changing anchor type
void updateAnchorInfo( BOARD_ITEM* aItem ); void updateAnchorInfo( const BOARD_ITEM* aItem );
// Get the current anchor position. // Get the current anchor position.
VECTOR2I getAnchorPos(); VECTOR2I getAnchorPos();

View File

@ -32,6 +32,7 @@
#include <microwave/microwave_tool.h> #include <microwave/microwave_tool.h>
#include <pcb_reference_image.h> #include <pcb_reference_image.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <tools/pcb_picker_tool.h>
#include <tools/pcb_selection_tool.h> #include <tools/pcb_selection_tool.h>
#include <router/pns_router.h> #include <router/pns_router.h>
#include <router/pns_routing_settings.h> #include <router/pns_routing_settings.h>
@ -2018,13 +2019,18 @@ TOOL_ACTION PCB_ACTIONS::positionRelative( TOOL_ACTION_ARGS()
.Tooltip( _( "Positions the selected item(s) by an exact amount relative to another" ) ) .Tooltip( _( "Positions the selected item(s) by an exact amount relative to another" ) )
.Icon( BITMAPS::move_relative ) ); .Icon( BITMAPS::move_relative ) );
TOOL_ACTION PCB_ACTIONS::selectPositionRelativeItem( TOOL_ACTION_ARGS()
.Name( "pcbnew.PositionRelative.selectpositionRelativeItem" )
.Scope( AS_GLOBAL ) );
TOOL_ACTION PCB_ACTIONS::selectPositionRelativePoint( TOOL_ACTION_ARGS() // PCIKER_TOOL
.Name( "pcbnew.PositionRelative.selectPositionRelativePoint" ) //
.Scope( AS_GLOBAL ) ); TOOL_ACTION PCB_ACTIONS::selectItemInteractively( TOOL_ACTION_ARGS()
.Name( "pcbnew.Picker.selectItemInteractively" )
.Scope( AS_GLOBAL )
.Parameter<PCB_PICKER_TOOL::INTERACTIVE_PARAMS>( {} ) );
TOOL_ACTION PCB_ACTIONS::selectPointInteractively( TOOL_ACTION_ARGS()
.Name( "pcbnew.Picker.selectPointInteractively" )
.Scope( AS_GLOBAL )
.Parameter<PCB_PICKER_TOOL::INTERACTIVE_PARAMS>( {} ));
// PCB_SELECTION_TOOL // PCB_SELECTION_TOOL

View File

@ -324,9 +324,9 @@ public:
/// Activation of the position relative tool /// Activation of the position relative tool
static TOOL_ACTION positionRelative; static TOOL_ACTION positionRelative;
/// Selection of anchor item for position relative tool /// Selection of reference points/items
static TOOL_ACTION selectPositionRelativeItem; static TOOL_ACTION selectItemInteractively;
static TOOL_ACTION selectPositionRelativePoint; static TOOL_ACTION selectPointInteractively;
// Display modes // Display modes
static TOOL_ACTION showRatsnest; static TOOL_ACTION showRatsnest;

View File

@ -24,11 +24,15 @@
*/ */
#include "pcb_picker_tool.h" #include "pcb_picker_tool.h"
#include "pcb_actions.h" #include "pcb_actions.h"
#include "pcb_grid_helper.h" #include "pcb_grid_helper.h"
#include <gal/graphics_abstraction_layer.h> #include <gal/graphics_abstraction_layer.h>
#include <view/view_controls.h> #include <kiplatform/ui.h>
#include <status_popup.h>
#include <tools/pcb_selection_tool.h>
#include <tools/zone_filler_tool.h> #include <tools/zone_filler_tool.h>
#include <view/view_controls.h>
PCB_PICKER_TOOL::PCB_PICKER_TOOL() : PCB_PICKER_TOOL::PCB_PICKER_TOOL() :
@ -233,10 +237,140 @@ void PCB_PICKER_TOOL::setControls()
} }
void PCB_PICKER_TOOL::setTransitions() int PCB_PICKER_TOOL::SelectPointInteractively( const TOOL_EVENT& aEvent )
{ {
Go( &PCB_PICKER_TOOL::Main, ACTIONS::pickerTool.MakeEvent() ); INTERACTIVE_PARAMS params = aEvent.Parameter<INTERACTIVE_PARAMS>();
Go( &PCB_PICKER_TOOL::Main, ACTIONS::pickerSubTool.MakeEvent() ); STATUS_TEXT_POPUP statusPopup( frame() );
bool done = false;
wxCHECK( params.m_Receiver, -1 );
PCB_GRID_HELPER grid_helper( m_toolMgr, frame()->GetMagneticItemsSettings() );
Activate();
statusPopup.SetText( _( params.m_Prompt ) );
const auto sendPoint = [&]( const std::optional<VECTOR2I>& aPoint )
{
statusPopup.Hide();
params.m_Receiver->UpdatePickedPoint( aPoint );
};
SetClickHandler(
[&]( const VECTOR2D& aPoint ) -> bool
{
std::optional<VECTOR2I> snapped = grid_helper.GetSnappedPoint();
sendPoint( snapped ? *snapped : VECTOR2I( aPoint ) );
return false; // got our item; don't need any more
} );
SetMotionHandler(
[&]( const VECTOR2D& aPos )
{
grid_helper.SetSnap( !( CurrentModifiers() & MD_SHIFT ) );
statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
} );
SetCancelHandler(
[&]()
{
sendPoint( std::nullopt );
} );
SetFinalizeHandler(
[&]( const int& aFinalState )
{
done = true;
} );
statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
statusPopup.Popup();
canvas()->SetStatusPopup( statusPopup.GetPanel() );
// Drop into the main event loop
Main( aEvent );
canvas()->SetStatusPopup( nullptr );
return 0;
}
int PCB_PICKER_TOOL::SelectItemInteractively( const TOOL_EVENT& aEvent )
{
INTERACTIVE_PARAMS params = aEvent.Parameter<INTERACTIVE_PARAMS>();
STATUS_TEXT_POPUP statusPopup( frame() );
bool done = false;
EDA_ITEM* anchor_item;
PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
Activate();
statusPopup.SetText( _( params.m_Prompt ) );
const auto sendItem = [&]( const EDA_ITEM* aItem )
{
statusPopup.Hide();
params.m_Receiver->UpdatePickedItem( aItem );
};
SetClickHandler(
[&]( const VECTOR2D& aPoint ) -> bool
{
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear );
const PCB_SELECTION& sel = selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector,
PCB_SELECTION_TOOL* sTool )
{
} );
if( sel.Empty() )
return true; // still looking for an item
anchor_item = sel.Front();
sendItem( sel.Front() );
return false; // got our item; don't need any more
} );
SetMotionHandler(
[&]( const VECTOR2D& aPos )
{
statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
} );
SetCancelHandler(
[&]()
{
sendItem( anchor_item );
} );
SetFinalizeHandler(
[&]( const int& aFinalState )
{
done = true;
} );
statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
statusPopup.Popup();
canvas()->SetStatusPopup( statusPopup.GetPanel() );
// Drop into the main event loop
Main( aEvent );
canvas()->SetStatusPopup( nullptr );
return 0;
} }
void PCB_PICKER_TOOL::setTransitions()
{
// clang-format off
Go( &PCB_PICKER_TOOL::Main, ACTIONS::pickerTool.MakeEvent() );
Go( &PCB_PICKER_TOOL::Main, ACTIONS::pickerSubTool.MakeEvent() );
Go( &PCB_PICKER_TOOL::SelectItemInteractively, PCB_ACTIONS::selectItemInteractively.MakeEvent() );
Go( &PCB_PICKER_TOOL::SelectPointInteractively, PCB_ACTIONS::selectPointInteractively.MakeEvent() );
// clang-format on
}

View File

@ -37,6 +37,27 @@
class PCB_PICKER_TOOL : public PCB_TOOL_BASE, public PICKER_TOOL_BASE class PCB_PICKER_TOOL : public PCB_TOOL_BASE, public PICKER_TOOL_BASE
{ {
public: public:
/**
* Interface class for something that receives picked points
* or items from this tool. Examples could be a dialog that's
* asking the user to pick a point.
*/
class RECEIVER
{
public:
virtual void UpdatePickedPoint( const std::optional<VECTOR2I>& aPoint ) = 0;
virtual void UpdatePickedItem( const EDA_ITEM* aItem ) = 0;
protected:
~RECEIVER() = default;
};
struct INTERACTIVE_PARAMS
{
RECEIVER* m_Receiver = nullptr;
wxString m_Prompt;
};
PCB_PICKER_TOOL(); PCB_PICKER_TOOL();
virtual ~PCB_PICKER_TOOL() = default; virtual ~PCB_PICKER_TOOL() = default;
@ -51,6 +72,9 @@ public:
*/ */
inline void SetLayerSet( LSET aLayerSet ) { m_layerMask = aLayerSet; } inline void SetLayerSet( LSET aLayerSet ) { m_layerMask = aLayerSet; }
int SelectPointInteractively( const TOOL_EVENT& aEvent );
int SelectItemInteractively( const TOOL_EVENT& aEvent );
protected: protected:
///< @copydoc TOOL_INTERACTIVE::setTransitions(); ///< @copydoc TOOL_INTERACTIVE::setTransitions();
void setTransitions() override; void setTransitions() override;

View File

@ -47,4 +47,4 @@ std::optional<int> GetBoardItemWidth( const BOARD_ITEM& aItem )
} }
return std::nullopt; return std::nullopt;
} }

View File

@ -25,14 +25,12 @@
#include <memory> #include <memory>
using namespace std::placeholders; using namespace std::placeholders;
#include <kiplatform/ui.h>
#include <tools/position_relative_tool.h> #include <tools/position_relative_tool.h>
#include <tools/pcb_actions.h> #include <tools/pcb_actions.h>
#include <tools/pcb_grid_helper.h> #include <tools/pcb_grid_helper.h>
#include <tools/pcb_selection_tool.h> #include <tools/pcb_selection_tool.h>
#include <tools/pcb_picker_tool.h> #include <tools/pcb_picker_tool.h>
#include <dialogs/dialog_position_relative.h> #include <dialogs/dialog_position_relative.h>
#include <status_popup.h>
#include <board_commit.h> #include <board_commit.h>
#include <confirm.h> #include <confirm.h>
#include <collectors.h> #include <collectors.h>
@ -44,8 +42,7 @@ using namespace std::placeholders;
POSITION_RELATIVE_TOOL::POSITION_RELATIVE_TOOL() : POSITION_RELATIVE_TOOL::POSITION_RELATIVE_TOOL() :
PCB_TOOL_BASE( "pcbnew.PositionRelative" ), PCB_TOOL_BASE( "pcbnew.PositionRelative" ),
m_dialog( nullptr ), m_dialog( nullptr ),
m_selectionTool( nullptr ), m_selectionTool( nullptr )
m_anchor_item( nullptr )
{ {
} }
@ -158,153 +155,7 @@ int POSITION_RELATIVE_TOOL::RelativeItemSelectionMove( const VECTOR2I& aPosAncho
} }
int POSITION_RELATIVE_TOOL::SelectPositionRelativeItem( const TOOL_EVENT& aEvent )
{
PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
STATUS_TEXT_POPUP statusPopup( frame() );
bool done = false;
Activate();
statusPopup.SetText( _( "Click on reference item..." ) );
picker->SetClickHandler(
[&]( const VECTOR2D& aPoint ) -> bool
{
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear );
const PCB_SELECTION& sel = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector,
PCB_SELECTION_TOOL* sTool )
{
} );
if( sel.Empty() )
return true; // still looking for an item
m_anchor_item = sel.Front();
statusPopup.Hide();
if( m_dialog )
m_dialog->UpdateAnchor( sel.Front() );
return false; // got our item; don't need any more
} );
picker->SetMotionHandler(
[&] ( const VECTOR2D& aPos )
{
statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
} );
picker->SetCancelHandler(
[&]()
{
statusPopup.Hide();
if( m_dialog )
m_dialog->UpdateAnchor( m_anchor_item );
} );
picker->SetFinalizeHandler(
[&]( const int& aFinalState )
{
done = true;
} );
statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
statusPopup.Popup();
canvas()->SetStatusPopup( statusPopup.GetPanel() );
m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
while( !done )
{
// Pass events unless we receive a null event, then we must shut down
if( TOOL_EVENT* evt = Wait() )
evt->SetPassEvent();
else
break;
}
canvas()->SetStatusPopup( nullptr );
return 0;
}
int POSITION_RELATIVE_TOOL::SelectPositionRelativePoint( const TOOL_EVENT& aEvent )
{
PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
STATUS_TEXT_POPUP statusPopup( frame() );
bool done = false;
PCB_GRID_HELPER grid_helper( m_toolMgr, frame()->GetMagneticItemsSettings() );
Activate();
statusPopup.SetText( _( "Click on reference point..." ) );
picker->SetClickHandler(
[&]( const VECTOR2D& aPoint ) -> bool
{
std::optional<VECTOR2I> snapped = grid_helper.GetSnappedPoint();
statusPopup.Hide();
if( m_dialog )
m_dialog->UpdateAnchor( snapped ? *snapped : VECTOR2I( aPoint ) );
return false; // got our item; don't need any more
} );
picker->SetMotionHandler(
[&] ( const VECTOR2D& aPos )
{
grid_helper.SetSnap( !( picker->CurrentModifiers() & MD_SHIFT ) );
statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
} );
picker->SetCancelHandler(
[&]()
{
statusPopup.Hide();
if( m_dialog )
m_dialog->UpdateAnchor( std::nullopt );
} );
picker->SetFinalizeHandler(
[&]( const int& aFinalState )
{
done = true;
} );
statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
statusPopup.Popup();
canvas()->SetStatusPopup( statusPopup.GetPanel() );
m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
while( !done )
{
// Pass events unless we receive a null event, then we must shut down
if( TOOL_EVENT* evt = Wait() )
evt->SetPassEvent();
else
break;
}
canvas()->SetStatusPopup( nullptr );
return 0;
}
void POSITION_RELATIVE_TOOL::setTransitions() void POSITION_RELATIVE_TOOL::setTransitions()
{ {
Go( &POSITION_RELATIVE_TOOL::PositionRelative, PCB_ACTIONS::positionRelative.MakeEvent() ); Go( &POSITION_RELATIVE_TOOL::PositionRelative, PCB_ACTIONS::positionRelative.MakeEvent() );
Go( &POSITION_RELATIVE_TOOL::SelectPositionRelativeItem,
PCB_ACTIONS::selectPositionRelativeItem.MakeEvent() );
Go( &POSITION_RELATIVE_TOOL::SelectPositionRelativePoint,
PCB_ACTIONS::selectPositionRelativePoint.MakeEvent() );
} }

View File

@ -26,15 +26,14 @@
#include <math/vector2d.h> #include <math/vector2d.h>
#include <tools/pcb_tool_base.h> #include <tools/pcb_tool_base.h>
#include "pcb_selection_tool.h" #include <tools/pcb_selection_tool.h>
#include "dialogs/dialog_position_relative.h"
#include "dialogs/dialog_position_relative_base.h"
class BOARD_COMMIT; class BOARD_COMMIT;
class BOARD_ITEM; class BOARD_ITEM;
class PCB_SELECTION_TOOL; class PCB_SELECTION_TOOL;
class DIALOG_POSITION_RELATIVE; class DIALOG_POSITION_RELATIVE;
/** /**
* The interactive edit tool. * The interactive edit tool.
* *
@ -57,18 +56,6 @@ public:
*/ */
int PositionRelative( const TOOL_EVENT& aEvent ); int PositionRelative( const TOOL_EVENT& aEvent );
/**
* Invoke the picker tool to select the item to which the previous selection will be placed
* relative to.
*/
int SelectPositionRelativeItem( const TOOL_EVENT& aEvent );
/**
* Invoke the picker tool to select the point to which the previous selection will be placed
* relative to.
*/
int SelectPositionRelativePoint( const TOOL_EVENT& aEvent );
/** /**
* Return the position of the selected item(s) * Return the position of the selected item(s)
*/ */
@ -91,8 +78,6 @@ private:
VECTOR2I m_selectionAnchor; VECTOR2I m_selectionAnchor;
std::unique_ptr<BOARD_COMMIT> m_commit; std::unique_ptr<BOARD_COMMIT> m_commit;
EDA_ITEM* m_anchor_item;
}; };
#endif #endif