Bring PICKER_TOOL in line with other tools.

Use standard Magnetize() to handle grid and magnetic pads.

Use the standard menu from PCB_TOOL.  Delegating the menu to
the SELECTION_TOOL just caused grief.

Also brings clients (such as Position Relative To) into line,
and implements better Cancel behaviour.

Also improves visibility of modal status messages:
- moves Select Anchor message from status bar to popup
- moves Select Reference message from dialog to popup

Fixes: lp:1786727
* https://bugs.launchpad.net/kicad/+bug/1786727
This commit is contained in:
Jeff Young 2018-08-22 19:05:40 +01:00
parent 24149a87fa
commit 30bb911154
13 changed files with 185 additions and 213 deletions

View File

@ -101,6 +101,8 @@ void STATUS_POPUP::onExpire( wxTimerEvent& aEvent )
STATUS_TEXT_POPUP::STATUS_TEXT_POPUP( EDA_DRAW_FRAME* aParent ) :
STATUS_POPUP( aParent )
{
m_panel->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNSHADOW ) );
m_statusLine = new wxStaticText( m_panel, wxID_ANY, wxEmptyString ) ;
m_topSizer->Add( m_statusLine, 1, wxALL | wxEXPAND, 5 );
}

View File

@ -30,12 +30,12 @@
DIALOG_POSITION_RELATIVE::POSITION_RELATIVE_OPTIONS DIALOG_POSITION_RELATIVE::m_options;
DIALOG_POSITION_RELATIVE::DIALOG_POSITION_RELATIVE( PCB_BASE_FRAME* aParent, TOOL_MANAGER* toolMgr,
wxPoint& translation, wxPoint& anchorPosition ) :
DIALOG_POSITION_RELATIVE::DIALOG_POSITION_RELATIVE( PCB_BASE_FRAME* aParent, wxPoint& translation,
wxPoint& anchor ) :
DIALOG_POSITION_RELATIVE_BASE( aParent ),
m_toolMgr( toolMgr ),
m_toolMgr( aParent->GetToolManager() ),
m_translation( translation ),
m_anchor_position( anchorPosition ),
m_anchor_position( anchor ),
m_xOffset( aParent, m_xLabel, m_xEntry, m_xUnit ),
m_yOffset( aParent, m_yLabel, m_yEntry, m_yUnit )
{
@ -115,7 +115,6 @@ void DIALOG_POSITION_RELATIVE::OnPolarChanged( wxCommandEvent& event )
m_xOffset.SetValue( KiROUND( val.x / 10.0 ) * 10 );
m_yOffset.SetValue( KiROUND( val.y / 10.0 ) * 10 );
}
}
@ -157,25 +156,25 @@ void DIALOG_POSITION_RELATIVE::OnSelectItemClick( wxCommandEvent& event )
POSITION_RELATIVE_TOOL* posrelTool = m_toolMgr->GetTool<POSITION_RELATIVE_TOOL>();
wxASSERT( posrelTool );
m_referenceInfo->SetLabel( _( "Reference item: <click item on canvas to select>" ) );
m_toolMgr->RunAction( PCB_ACTIONS::selectpositionRelativeItem, true );
Hide();
}
void DIALOG_POSITION_RELATIVE::UpdateAnchor( BOARD_ITEM* aItem )
void DIALOG_POSITION_RELATIVE::UpdateAnchor( EDA_ITEM* aItem )
{
wxString reference = _( "<none selected>" );
if( aItem )
{
m_anchor_position = aItem->GetPosition();
m_anchor_position = dynamic_cast<BOARD_ITEM*>( aItem )->GetPosition();
reference = aItem->GetSelectMenuText( GetUserUnits() );
}
m_referenceInfo->SetLabel( _( "Reference item: " ) + reference );
Raise(); // required at least on OSX
Show( true );
}

View File

@ -45,11 +45,10 @@ private:
public:
// Constructor and destructor
DIALOG_POSITION_RELATIVE( PCB_BASE_FRAME* aParent, TOOL_MANAGER* toolMgr,
wxPoint& translation, wxPoint& anchorposition );
DIALOG_POSITION_RELATIVE( PCB_BASE_FRAME* aParent, wxPoint& translation, wxPoint& anchor );
~DIALOG_POSITION_RELATIVE() { };
void UpdateAnchor( BOARD_ITEM* aItem );
void UpdateAnchor( EDA_ITEM* aItem );
private:

View File

@ -24,13 +24,6 @@
#include "pns_router.h"
#include "pns_meander_placer.h"
PNS_TUNE_STATUS_POPUP::PNS_TUNE_STATUS_POPUP( EDA_DRAW_FRAME* aParent ) :
STATUS_TEXT_POPUP( aParent )
{
m_panel->SetBackgroundColour( wxColour( 64, 64, 64 ) );
}
void PNS_TUNE_STATUS_POPUP::UpdateStatus( PNS::ROUTER* aRouter )
{
PNS::MEANDER_PLACER_BASE* placer = dynamic_cast<PNS::MEANDER_PLACER_BASE*>( aRouter->Placer() );

View File

@ -37,7 +37,9 @@ class ROUTER;
class PNS_TUNE_STATUS_POPUP : public STATUS_TEXT_POPUP
{
public:
PNS_TUNE_STATUS_POPUP( EDA_DRAW_FRAME* aParent );
PNS_TUNE_STATUS_POPUP( EDA_DRAW_FRAME* aParent ) :
STATUS_TEXT_POPUP( aParent )
{ }
void UpdateStatus( PNS::ROUTER* aRouter );
};

View File

@ -192,11 +192,6 @@ private:
GRAPHIC_POLYGON
};
///> Shows the context menu for the drawing tool
///> This menu consists of normal UI functions (zoom, grid, etc)
///> And any suitable global functions for the active drawing type.
void showContextMenu();
///> Starts drawing a selected shape (i.e. DRAWSEGMENT).
///> @param aShape is the type of created shape (@see STROKE_T).
///> @param aGraphic is an object that is going to be used by the tool for drawing. It has to

View File

@ -37,7 +37,7 @@
#include <footprint_edit_frame.h>
#include <array_creator.h>
#include <pcbnew_id.h>
#include <status_popup.h>
#include <tool/tool_manager.h>
#include <view/view_controls.h>
#include <view/view.h>
@ -83,22 +83,6 @@ TOOL_ACTION PCB_ACTIONS::editFootprintInFpEditor( "pcbnew.InteractiveEdit.editFo
_( "Opens the selected footprint in the Footprint Editor" ),
module_editor_xpm );
TOOL_ACTION PCB_ACTIONS::copyPadToSettings( "pcbnew.InteractiveEdit.copyPadToSettings",
AS_GLOBAL, 0,
_( "Copy Pad Properties to Default Pad Properties" ),
_( "Copies the properties of the selected pad to the default pad properties." ) );
TOOL_ACTION PCB_ACTIONS::copySettingsToPads( "pcbnew.InteractiveEdit.copySettingsToPads",
AS_GLOBAL, 0,
_( "Copy Default Pad Properties to Pads" ),
_( "Copies the default pad properties to the selected pad(s)." ) );
TOOL_ACTION PCB_ACTIONS::globalEditPads( "pcbnew.InteractiveEdit.globalPadEdit",
AS_GLOBAL, 0,
_( "Push Pad Settings..." ),
_( "Copies the selected pad's properties to all pads in its footprint (or similar footprints)." ),
push_pad_settings_xpm );
TOOL_ACTION PCB_ACTIONS::editActivate( "pcbnew.InteractiveEdit",
AS_GLOBAL, 0,
_( "Edit Activate" ), "", move_xpm, AF_ACTIVATE );
@ -1395,47 +1379,66 @@ int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent )
bool EDIT_TOOL::pickCopyReferencePoint( VECTOR2I& aP )
{
STATUS_TEXT_POPUP statusPopup( frame() );
PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
assert( picker );
bool picking = true;
bool retVal = true;
statusPopup.SetText( _( "Select reference point for the copy..." ) );
picker->Activate();
picker->SetClickHandler( [&]( const VECTOR2D& aPoint ) -> bool
{
aP = aPoint;
statusPopup.SetText( _( "Selection copied." ) );
statusPopup.Expire( 800 );
picking = false;
return false; // we don't need any more points
} );
picker->SetCancelHandler( [&]()
{
statusPopup.SetText( _( "Copy cancelled." ) );
statusPopup.Expire( 800 );
picking = false;
retVal = false;
} );
while ( picker->IsPicking() )
statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
statusPopup.Popup();
while( picking )
{
statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
Wait();
}
if( !picker->GetPoint() )
return false;
aP = *picker->GetPoint();
return true;
statusPopup.Hide();
return retVal;
}
int EDIT_TOOL::copyToClipboard( const TOOL_EVENT& aEvent )
int EDIT_TOOL::doCopyToClipboard( bool withAnchor )
{
CLIPBOARD_IO io;
VECTOR2I refPoint;
Activate();
auto item1 = MSG_PANEL_ITEM( "", _( "Select reference point for the block being copied..." ),
COLOR4D::BLACK );
std::vector<MSG_PANEL_ITEM> msgItems = { item1 };
SELECTION& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter );
if( selection.Empty() )
return 1;
frame()->SetMsgPanel( msgItems );
bool rv = pickCopyReferencePoint( refPoint );
frame()->SetMsgPanel( board() );
if( withAnchor )
{
VECTOR2I refPoint;
bool rv = pickCopyReferencePoint( refPoint );
frame()->SetMsgPanel( board() );
if( !rv )
return 1;
if( !rv )
return 1;
selection.SetReferencePoint( refPoint );
}
selection.SetReferencePoint( refPoint );
io.SetBoard( board() );
io.SaveSelection( selection );
@ -1443,6 +1446,18 @@ int EDIT_TOOL::copyToClipboard( const TOOL_EVENT& aEvent )
}
int EDIT_TOOL::copyToClipboard( const TOOL_EVENT& aEvent )
{
return doCopyToClipboard( true );
}
int EDIT_TOOL::copyToClipboardWithAnchor( const TOOL_EVENT& aEvent )
{
return doCopyToClipboard( true );
}
int EDIT_TOOL::cutToClipboard( const TOOL_EVENT& aEvent )
{
if( !copyToClipboard( aEvent ) )

View File

@ -168,6 +168,10 @@ public:
*/
int copyToClipboard( const TOOL_EVENT& aEvent );
int copyToClipboardWithAnchor( const TOOL_EVENT& aEvent );
int doCopyToClipboard( bool withAnchor );
/**
* Function cutToClipboard()
* Cuts the current selection to the clipboard by formatting it as a fake pcb

View File

@ -402,9 +402,6 @@ public:
static TOOL_ACTION findMove;
static TOOL_ACTION editFootprintInFpEditor;
static TOOL_ACTION copyPadToSettings;
static TOOL_ACTION copySettingsToPads;
static TOOL_ACTION globalEditPads;
///> @copydoc COMMON_ACTIONS::TranslateLegacyId()

View File

@ -25,7 +25,7 @@
#include "picker_tool.h"
#include "pcb_actions.h"
#include "grid_helper.h"
#include <pcbnew_id.h>
#include <pcb_edit_frame.h>
#include <view/view_controls.h>
#include <tool/tool_manager.h>
@ -33,6 +33,10 @@
#include "selection_tool.h"
extern bool Magnetize( PCB_BASE_EDIT_FRAME* frame, int aCurrentTool,
wxSize aGridSize, wxPoint on_grid, wxPoint* curpos );
TOOL_ACTION PCB_ACTIONS::pickerTool( "pcbnew.Picker", AS_GLOBAL, 0, "", "", NULL, AF_ACTIVATE );
@ -43,51 +47,34 @@ PICKER_TOOL::PICKER_TOOL()
}
bool PICKER_TOOL::Init()
{
auto activeToolCondition = [ this ] ( const SELECTION& aSel ) {
return ( frame()->GetToolId() != ID_NO_TOOL_SELECTED );
};
SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
// We delegate our context menu to the Selection tool, so make sure it has a
// "Cancel" item at the top.
if( selTool )
{
auto& toolMenu = selTool->GetToolMenu();
auto& menu = toolMenu.GetMenu();
menu.AddItem( ACTIONS::cancelInteractive, activeToolCondition, 1000 );
menu.AddSeparator( activeToolCondition, 1000 );
}
return true;
}
int PICKER_TOOL::Main( const TOOL_EVENT& aEvent )
{
KIGFX::VIEW_CONTROLS* controls = getViewControls();
GRID_HELPER grid( frame() );
assert( !m_picking );
m_picking = true;
m_picked = NULLOPT;
setControls();
while( OPT_TOOL_EVENT evt = Wait() )
{
auto mousePos = controls->GetMousePosition();
auto p = grid.BestSnapAnchor( mousePos, nullptr );
controls->ForceCursorPosition( true, p );
// TODO: magnetic pad & track processing needs to move to VIEW_CONTROLS.
wxPoint pos( controls->GetMousePosition().x, controls->GetMousePosition().y );
frame()->SetMousePosition( pos );
wxRealPoint gridSize = frame()->GetScreen()->GetGridSize();
wxSize igridsize;
igridsize.x = KiROUND( gridSize.x );
igridsize.y = KiROUND( gridSize.y );
if( Magnetize( frame(), ID_PCB_HIGHLIGHT_BUTT, igridsize, pos, &pos ) )
controls->ForceCursorPosition( true, pos );
else
controls->ForceCursorPosition( false );
if( evt->IsClick( BUT_LEFT ) )
{
bool getNext = false;
m_picked = VECTOR2D( p );
m_picked = VECTOR2D( controls->GetCursorPosition() );
if( m_clickHandler )
{
@ -109,7 +96,24 @@ int PICKER_TOOL::Main( const TOOL_EVENT& aEvent )
}
else if( evt->IsCancel() || TOOL_EVT_UTILS::IsCancelInteractive( *evt ) || evt->IsActivate() )
{
if( m_cancelHandler )
{
try
{
(*m_cancelHandler)();
}
catch( std::exception& e )
{
std::cerr << "PICKER_TOOL cancel handler error: " << e.what() << std::endl;
}
}
break;
}
else if( evt->IsClick( BUT_RIGHT ) )
m_menu.ShowContextMenu();
else
m_toolMgr->PassEvent();
@ -136,8 +140,9 @@ void PICKER_TOOL::reset()
m_cursorCapture = false;
m_autoPanning = false;
m_picking = false;
m_picked = NULLOPT;
m_clickHandler = NULLOPT;
m_cancelHandler = NULLOPT;
}

View File

@ -37,11 +37,9 @@ public:
PICKER_TOOL();
~PICKER_TOOL() {}
///> Mouse event click handler type.
///> Event handler types.
typedef std::function<bool(const VECTOR2D&)> CLICK_HANDLER;
/// @copydoc TOOL_INTERACTIVE::Init()
bool Init() override;
typedef std::function<void(void)> CANCEL_HANDLER;
///> @copydoc TOOL_INTERACTIVE::Reset()
void Reset( RESET_REASON aReason ) override {}
@ -73,22 +71,6 @@ public:
*/
inline void SetCursorCapture( bool aEnable ) { m_cursorCapture = aEnable; }
/**
* Function GetPoint()
* Returns picked point.
*/
inline OPT<VECTOR2D> GetPoint() const
{
assert( !m_picking );
return m_picked;
}
/**
* Function IsPicking()
* Returns information whether the tool is still active.
*/
bool IsPicking() const { return m_picking; }
/**
* Function SetClickHandler()
* Sets a handler for mouse click event. Handler may decide to receive further click by
@ -100,6 +82,16 @@ public:
m_clickHandler = aHandler;
}
/**
* Function SetCancelHandler()
* Sets a handler for cancel events (ESC or context-menu Cancel).
*/
inline void SetCancelHandler( CANCEL_HANDLER aHandler )
{
assert( !m_cancelHandler );
m_cancelHandler = aHandler;
}
///> @copydoc TOOL_INTERACTIVE::setTransitions();
void setTransitions() override;
@ -110,15 +102,13 @@ private:
bool m_cursorCapture;
bool m_autoPanning;
///> Optional mouse click event handler.
///> Optional event handlers.
OPT<CLICK_HANDLER> m_clickHandler;
OPT<CANCEL_HANDLER> m_cancelHandler;
///> Picked point (if any).
OPT<VECTOR2D> m_picked;
///> Activity status.
bool m_picking;
///> Reinitializes tool to its initial state.
void reset();

View File

@ -31,7 +31,7 @@ using namespace std::placeholders;
#include "picker_tool.h"
#include <dialogs/dialog_position_relative.h>
#include <status_popup.h>
#include <board_commit.h>
#include <hotkeys.h>
#include <bitmaps.h>
@ -54,7 +54,7 @@ TOOL_ACTION PCB_ACTIONS::selectpositionRelativeItem(
POSITION_RELATIVE_TOOL::POSITION_RELATIVE_TOOL() :
PCB_TOOL( "pcbnew.PositionRelative" ),
m_position_relative_dialog( NULL ),
m_dialog( NULL ),
m_selectionTool( NULL ),
m_anchor_item( NULL )
{
@ -71,16 +71,9 @@ void POSITION_RELATIVE_TOOL::Reset( RESET_REASON aReason )
bool POSITION_RELATIVE_TOOL::Init()
{
// Find the selection tool, so they can cooperate
m_selectionTool =
static_cast<SELECTION_TOOL*>( m_toolMgr->FindTool( "pcbnew.InteractiveSelection" ) );
m_selectionTool = m_toolMgr->GetTool<SELECTION_TOOL>();
if( !m_selectionTool )
{
DisplayError( NULL, wxT( "pcbnew.InteractiveSelection tool is not available" ) );
return false;
}
return true;
return m_selectionTool != nullptr;
}
@ -95,55 +88,28 @@ int POSITION_RELATIVE_TOOL::PositionRelative( const TOOL_EVENT& aEvent )
const auto& selection = m_selectionTool->RequestSelection( filter );
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
if( m_selectionTool->CheckLock() == SELECTION_LOCKED || selection.Empty() )
return 0;
if( selection.Empty() )
return 0;
m_selection = selection;
m_position_relative_selection = selection;
if( !m_dialog )
m_dialog = new DIALOG_POSITION_RELATIVE( editFrame, m_translation, m_anchor );
if( !m_position_relative_dialog )
m_position_relative_dialog = new DIALOG_POSITION_RELATIVE( editFrame,
m_toolMgr,
m_position_relative_translation,
m_anchor_position );
m_position_relative_dialog->Show( true );
m_dialog->Show( true );
return 0;
}
static bool selectPRitem( TOOL_MANAGER* aToolMgr, const VECTOR2D& aPosition )
int POSITION_RELATIVE_TOOL::RelativeItemSelectionMove( wxPoint anchor, wxPoint relativePosition,
double rotation )
{
SELECTION_TOOL* selectionTool = aToolMgr->GetTool<SELECTION_TOOL>();
POSITION_RELATIVE_TOOL* positionRelativeTool = aToolMgr->GetTool<POSITION_RELATIVE_TOOL>();
wxCHECK( selectionTool, false );
wxCHECK( positionRelativeTool, false );
aToolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
const SELECTION& selection = selectionTool->RequestSelection( EnsureEditableFilter );
if( selection.Empty() )
return true;
positionRelativeTool->UpdateAnchor( static_cast<BOARD_ITEM*>( selection.Front() ) );
return true;
}
int POSITION_RELATIVE_TOOL::RelativeItemSelectionMove( wxPoint anchorPosition,
wxPoint relativePosition,
double rotation )
{
VECTOR2I rp = m_position_relative_selection.GetCenter();
VECTOR2I rp = m_selection.GetCenter();
wxPoint rotPoint( rp.x, rp.y );
wxPoint translation = anchorPosition + relativePosition - rotPoint;
wxPoint translation = anchor + relativePosition - rotPoint;
for( auto item : m_position_relative_selection )
for( auto item : m_selection )
{
m_commit->Modify( item );
@ -153,7 +119,7 @@ int POSITION_RELATIVE_TOOL::RelativeItemSelectionMove( wxPoint anchorPosition,
m_commit->Push( _( "Position Relative" ) );
if( m_position_relative_selection.IsHover() )
if( m_selection.IsHover() )
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
m_toolMgr->RunAction( PCB_ACTIONS::selectionModified, true );
@ -166,26 +132,54 @@ int POSITION_RELATIVE_TOOL::SelectPositionRelativeItem( const TOOL_EVENT& aEvent
Activate();
PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
assert( picker );
STATUS_TEXT_POPUP statusPopup( frame() );
bool picking = true;
statusPopup.SetText( _( "Select reference item..." ) );
picker->SetSnapping( false );
picker->SetClickHandler( std::bind( selectPRitem, m_toolMgr, _1 ) );
picker->Activate();
Wait();
picker->SetClickHandler( [&]( const VECTOR2D& aPoint ) -> bool
{
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
const SELECTION& sel = m_selectionTool->RequestSelection( EnsureEditableFilter );
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() );
picking = false;
return false; // got our item; don't need any more
} );
picker->SetCancelHandler( [&]()
{
statusPopup.Hide();
if( m_dialog )
m_dialog->UpdateAnchor( m_anchor_item );
picking = false;
} );
statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
statusPopup.Popup();
while( picking )
{
statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
Wait();
}
return 0;
}
void POSITION_RELATIVE_TOOL::UpdateAnchor( BOARD_ITEM* aItem )
{
m_anchor_item = aItem;
if( m_position_relative_dialog )
m_position_relative_dialog->UpdateAnchor( aItem );
}
void POSITION_RELATIVE_TOOL::setTransitions()
{
Go( &POSITION_RELATIVE_TOOL::PositionRelative, PCB_ACTIONS::positionRelative.MakeEvent() );

View File

@ -72,47 +72,24 @@ public:
* Positions the m_position_relative_selection selection relative to anchorpostion using the given translation and rotation.
* Rotation is around the center of the selection.
*/
int RelativeItemSelectionMove( wxPoint anchorposition, wxPoint translation, double rotation );
/**
* Function GetAnchorItem()
*
* Gets the last selected anchor item.
*/
BOARD_ITEM* GetAnchorItem()
{
return m_anchor_item;
}
/**
* Function UpdateAnchor()
*
* Selects the item to be used as the reference for relative move operation.
*/
void UpdateAnchor( BOARD_ITEM* aItem );
int RelativeItemSelectionMove( wxPoint anchor, wxPoint translation, double rotation );
///> Sets up handlers for various events.
void setTransitions() override;
private:
DIALOG_POSITION_RELATIVE* m_position_relative_dialog;
DIALOG_POSITION_RELATIVE* m_dialog;
///> Selection tool used for obtaining selected items
SELECTION_TOOL* m_selectionTool;
SELECTION m_selection;
std::unique_ptr<BOARD_COMMIT> m_commit;
///> Last anchor item selected by Position Relative To function.
BOARD_ITEM* m_anchor_item;
EDA_ITEM* m_anchor_item;
wxPoint m_anchor;
///> Translation for Position Relative To function.
wxPoint m_position_relative_translation;
///> Anchor position for Position Relative To function.
wxPoint m_anchor_position;
///> Selection that will be moved by Position Relative To function.
SELECTION m_position_relative_selection;
wxPoint m_translation;
};
#endif