Improved copy/paste functionality by Kristoffer:

- added selection of reference point
- added snapping when pasting
- some minor code refactoring
- disabled pasting between footprint and pcb editors due to model incompatibility
This commit is contained in:
Tomasz Włostowski 2017-09-22 17:17:38 +02:00
parent 279ccd4fe2
commit 931a1ccaff
12 changed files with 279 additions and 154 deletions

View File

@ -170,7 +170,30 @@ public:
virtual const VIEW_GROUP::ITEMS updateDrawList() const override; virtual const VIEW_GROUP::ITEMS updateDrawList() const override;
bool HasReferencePoint() const
{
return m_referencePoint != boost::none;
}
VECTOR2I GetReferencePoint() const
{
return *m_referencePoint;
}
void SetReferencePoint( const VECTOR2I& aP )
{
m_referencePoint = aP;
}
void ClearReferencePoint()
{
m_referencePoint = boost::none;
}
private: private:
boost::optional<VECTOR2I> m_referencePoint;
/// Set of selected items /// Set of selected items
std::set<EDA_ITEM*> m_items; std::set<EDA_ITEM*> m_items;

View File

@ -132,6 +132,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry )
// modules inside modules are not supported yet // modules inside modules are not supported yet
assert( boardItem->Type() != PCB_MODULE_T ); assert( boardItem->Type() != PCB_MODULE_T );
boardItem->SetParent( board->m_Modules.GetFirst() );
if( !( changeFlags & CHT_DONE ) ) if( !( changeFlags & CHT_DONE ) )
board->m_Modules->Add( boardItem ); board->m_Modules->Add( boardItem );
} }

View File

@ -53,7 +53,7 @@ STRING_FORMATTER* CLIPBOARD_IO::GetFormatter()
return &m_formatter; return &m_formatter;
} }
void CLIPBOARD_IO::setBoard( BOARD* aBoard ) void CLIPBOARD_IO::SetBoard( BOARD* aBoard )
{ {
m_board = aBoard; m_board = aBoard;
} }
@ -61,11 +61,15 @@ void CLIPBOARD_IO::setBoard( BOARD* aBoard )
void CLIPBOARD_IO::SaveSelection( const SELECTION& aSelected ) void CLIPBOARD_IO::SaveSelection( const SELECTION& aSelected )
{ {
LOCALE_IO toggle; // toggles on, then off, the C locale. LOCALE_IO toggle; // toggles on, then off, the C locale.
VECTOR2I refPoint(0, 0);
// dont even start if the selection is empty // dont even start if the selection is empty
if( aSelected.Empty() ) if( aSelected.Empty() )
return; return;
if( aSelected.HasReferencePoint() )
refPoint = aSelected.GetReferencePoint();
// Prepare net mapping that assures that net codes saved in a file are consecutive integers // Prepare net mapping that assures that net codes saved in a file are consecutive integers
m_mapping->SetBoard( m_board ); m_mapping->SetBoard( m_board );
@ -100,6 +104,9 @@ void CLIPBOARD_IO::SaveSelection( const SELECTION& aSelected )
pad->SetNetCode( 0, 0 ); pad->SetNetCode( 0, 0 );
} }
// locate the reference point at (0, 0) in the copied items
newModule.Move( wxPoint(-refPoint.x, -refPoint.y ) );
Format( static_cast<BOARD_ITEM*>( &newModule ) ); Format( static_cast<BOARD_ITEM*>( &newModule ) );
} }
// partial module selected. // partial module selected.
@ -120,6 +127,9 @@ void CLIPBOARD_IO::SaveSelection( const SELECTION& aSelected )
pad->SetNetCode( 0, 0 ); pad->SetNetCode( 0, 0 );
} }
// locate the reference point at (0, 0) in the copied items
clone->Move( wxPoint(-refPoint.x, -refPoint.y ) );
partialModule.Add( clone ); partialModule.Add( clone );
} }
@ -157,7 +167,12 @@ void CLIPBOARD_IO::SaveSelection( const SELECTION& aSelected )
( i->Type() != PCB_PAD_T ) ) ( i->Type() != PCB_PAD_T ) )
{ {
auto item = static_cast<BOARD_ITEM*>( i ); auto item = static_cast<BOARD_ITEM*>( i );
Format( item, 1 ); std::unique_ptr<BOARD_ITEM> clone( static_cast<BOARD_ITEM*> ( item->Clone() ) );
// locate the reference point at (0, 0) in the copied items
clone->Move( wxPoint(-refPoint.x, -refPoint.y ) );
Format( clone.get(), 1 );
} }
} }
@ -187,7 +202,15 @@ BOARD_ITEM* CLIPBOARD_IO::Parse()
wxTheClipboard->Close(); wxTheClipboard->Close();
} }
return PCB_IO::Parse( result ); BOARD_ITEM *item;
try
{
item = PCB_IO::Parse( result );
} catch (...) {
item = nullptr;
}
return item;
} }
void CLIPBOARD_IO::Save( const wxString& aFileName, BOARD* aBoard, void CLIPBOARD_IO::Save( const wxString& aFileName, BOARD* aBoard,
@ -282,4 +305,3 @@ BOARD* CLIPBOARD_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, const
return board; return board;
} }

View File

@ -55,8 +55,6 @@ public:
class CLIPBOARD_IO : public PCB_IO class CLIPBOARD_IO : public PCB_IO
{ {
STRING_FORMATTER m_formatter;
CLIPBOARD_PARSER* m_parser;
public: public:
/* Saves the entire board to the clipboard formatted using the PCB_IO formatting */ /* Saves the entire board to the clipboard formatted using the PCB_IO formatting */
@ -73,10 +71,14 @@ public:
CLIPBOARD_IO(); CLIPBOARD_IO();
~CLIPBOARD_IO(); ~CLIPBOARD_IO();
void setBoard( BOARD* aBoard ); void SetBoard( BOARD* aBoard );
void writeHeader( BOARD* aBoard );
STRING_FORMATTER* GetFormatter(); STRING_FORMATTER* GetFormatter();
private:
void writeHeader( BOARD* aBoard );
STRING_FORMATTER m_formatter;
CLIPBOARD_PARSER* m_parser;
}; };

View File

@ -54,6 +54,7 @@ using namespace std::placeholders;
#include "pcb_actions.h" #include "pcb_actions.h"
#include "selection_tool.h" #include "selection_tool.h"
#include "edit_tool.h" #include "edit_tool.h"
#include "picker_tool.h"
#include "grid_helper.h" #include "grid_helper.h"
#include "kicad_clipboard.h" #include "kicad_clipboard.h"
#include "pcbnew_control.h" #include "pcbnew_control.h"
@ -173,7 +174,6 @@ TOOL_ACTION PCB_ACTIONS::cutToClipboard( "pcbnew.InteractiveEdit.CutToClipboard"
_( "Cut" ), _( "Cut selected content to clipboard" ), _( "Cut" ), _( "Cut selected content to clipboard" ),
cut_xpm ); cut_xpm );
static wxPoint getAnchorPoint( const SELECTION &selection, const MOVE_PARAMETERS &params ) static wxPoint getAnchorPoint( const SELECTION &selection, const MOVE_PARAMETERS &params )
{ {
wxPoint anchorPoint; wxPoint anchorPoint;
@ -393,10 +393,10 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
controls->SetAutoPan( true ); controls->SetAutoPan( true );
// cumulative translation // cumulative translation
wxPoint totalMovement( 0, 0 ); VECTOR2I totalMovement;
GRID_HELPER grid( editFrame ); GRID_HELPER grid( editFrame );
OPT_TOOL_EVENT evt = aEvent; OPT_TOOL_EVENT evt = aEvent;
VECTOR2I prevPos;
// Main loop: keep receiving events // Main loop: keep receiving events
do do
@ -415,14 +415,20 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
if( m_dragging && evt->Category() == TC_MOUSE ) if( m_dragging && evt->Category() == TC_MOUSE )
{ {
m_cursor = grid.BestSnapAnchor( evt->Position(), curr_item ); m_cursor = grid.BestSnapAnchor( evt->Position(), curr_item );
controls->ForceCursorPosition( true, m_cursor ); controls->ForceCursorPosition( true, m_cursor );
wxPoint movement = wxPoint( m_cursor.x, m_cursor.y ) - curr_item->GetPosition(); VECTOR2I movement( m_cursor - prevPos );// - curr_item->GetPosition();
totalMovement += movement; totalMovement += movement;
prevPos = m_cursor;
auto delta = movement + m_offset;
// Drag items to the current cursor position // Drag items to the current cursor position
for( auto item : selection ) for( auto item : selection )
static_cast<BOARD_ITEM*>( item )->Move( movement + m_offset ); static_cast<BOARD_ITEM*>( item )->Move( wxPoint( delta.x, delta.y ) );
m_offset = VECTOR2I(0, 0);
} }
else if( !m_dragging ) // Prepare to start dragging else if( !m_dragging ) // Prepare to start dragging
{ {
@ -446,8 +452,25 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
m_commit->Modify( item ); m_commit->Modify( item );
m_cursor = controls->GetCursorPosition(); m_cursor = controls->GetCursorPosition();
m_offset = VECTOR2I(0, 0);
if( selection.Size() == 1 ) auto refPoint = VECTOR2I( curr_item->GetPosition() );
if ( selection.HasReferencePoint() )
{
// start moving with the reference point attached to the cursor
refPoint = selection.GetReferencePoint();
grid.SetAuxAxes( false );
auto delta = m_cursor - selection.GetReferencePoint();
// Drag items to the current cursor position
for( auto item : selection )
static_cast<BOARD_ITEM*>( item )->Move( wxPoint( delta.x, delta.y ) );
selection.ClearReferencePoint();
}
else if( selection.Size() == 1 )
{ {
// Set the current cursor position to the first dragged item origin, so the // Set the current cursor position to the first dragged item origin, so the
// movement vector could be computed later // movement vector could be computed later
@ -461,10 +484,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
controls->SetCursorPosition( m_cursor, false ); controls->SetCursorPosition( m_cursor, false );
VECTOR2I o = VECTOR2I( curr_item->GetPosition() ); prevPos = m_cursor;
m_offset.x = o.x - m_cursor.x;
m_offset.y = o.y - m_cursor.y;
controls->SetAutoPan( true ); controls->SetAutoPan( true );
m_dragging = true; m_dragging = true;
} }
@ -512,7 +532,8 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
for( auto item : selection ) for( auto item : selection )
{ {
BOARD_ITEM* i = static_cast<BOARD_ITEM*>( item ); BOARD_ITEM* i = static_cast<BOARD_ITEM*>( item );
i->SetPosition( i->GetPosition() - totalMovement ); auto delta = VECTOR2I( i->GetPosition() ) - totalMovement;
i->SetPosition( wxPoint( delta.x, delta.y ) );
// And what about flipping and rotation? // And what about flipping and rotation?
// for now, they won't be undone, but maybe that is how // for now, they won't be undone, but maybe that is how
@ -1239,7 +1260,9 @@ wxPoint EDIT_TOOL::getModificationPoint( const SELECTION& aSelection )
{ {
if( aSelection.Size() == 1 ) if( aSelection.Size() == 1 )
{ {
return static_cast<BOARD_ITEM*>( aSelection.Front() )->GetPosition() - m_offset; auto item = static_cast<BOARD_ITEM*>( aSelection.Front() );
auto pos = item->GetPosition();
return wxPoint( pos.x - m_offset.x, pos.y - m_offset.y );
} }
else else
{ {
@ -1289,13 +1312,38 @@ int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent )
return 0; return 0;
} }
bool EDIT_TOOL::pickCopyReferencePoint( VECTOR2I& aP )
{
PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
assert( picker );
picker->Activate();
while ( picker->IsPicking() )
Wait();
if( !picker->GetPoint() )
return false;
aP = *picker->GetPoint();
return true;
}
int EDIT_TOOL::copyToClipboard( const TOOL_EVENT& aEvent ) int EDIT_TOOL::copyToClipboard( const TOOL_EVENT& aEvent )
{ {
CLIPBOARD_IO io; CLIPBOARD_IO io;
BOARD* board = getModel<BOARD>(); BOARD* board = getModel<BOARD>();
VECTOR2I refPoint;
io.setBoard( board ); Activate();
auto& selection = m_selectionTool->RequestSelection();
SELECTION selection = m_selectionTool->RequestSelection();
if( !pickCopyReferencePoint( refPoint ) )
return 0;
selection.SetReferencePoint( refPoint );
io.SetBoard( board );
io.SaveSelection( selection ); io.SaveSelection( selection );
return 0; return 0;

View File

@ -155,6 +155,12 @@ public:
*/ */
int cutToClipboard( const TOOL_EVENT& aEvent ); int cutToClipboard( const TOOL_EVENT& aEvent );
BOARD_COMMIT* GetCurrentCommit() const
{
return m_commit.get();
}
private: private:
///> Selection tool used for obtaining selected items ///> Selection tool used for obtaining selected items
SELECTION_TOOL* m_selectionTool; SELECTION_TOOL* m_selectionTool;
@ -163,7 +169,7 @@ private:
bool m_dragging; bool m_dragging;
///> Offset from the dragged item's center (anchor) ///> Offset from the dragged item's center (anchor)
wxPoint m_offset; VECTOR2I m_offset;
///> Last cursor position (needed for getModificationPoint() to avoid changes ///> Last cursor position (needed for getModificationPoint() to avoid changes
///> of edit reference point). ///> of edit reference point).
@ -179,6 +185,7 @@ private:
bool isInteractiveDragEnabled() const; bool isInteractiveDragEnabled() const;
bool changeTrackWidthOnClick( const SELECTION& selection ); bool changeTrackWidthOnClick( const SELECTION& selection );
bool pickCopyReferencePoint( VECTOR2I& aP );
/** /**

View File

@ -251,7 +251,13 @@ VECTOR2I GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, BOARD_ITEM* aDrag
computeAnchors( item, aOrigin ); computeAnchors( item, aOrigin );
} }
LSET layers( aDraggedItem->GetLayer() ); LSET layers;
if( aDraggedItem )
layers = aDraggedItem->GetLayer();
else
layers = LSET::AllLayersMask();
ANCHOR* nearest = nearestAnchor( aOrigin, CORNER | SNAPPABLE, layers ); ANCHOR* nearest = nearestAnchor( aOrigin, CORNER | SNAPPABLE, layers );
VECTOR2I nearestGrid = Align( aOrigin ); VECTOR2I nearestGrid = Align( aOrigin );

View File

@ -124,6 +124,8 @@ protected:
KIGFX::VIEW_CONTROLS* controls() const { return getViewControls(); } KIGFX::VIEW_CONTROLS* controls() const { return getViewControls(); }
PCB_EDIT_FRAME* frame() const { return getEditFrame<PCB_EDIT_FRAME>(); } PCB_EDIT_FRAME* frame() const { return getEditFrame<PCB_EDIT_FRAME>(); }
BOARD* board() const { return getModel<BOARD>(); } BOARD* board() const { return getModel<BOARD>(); }
MODULE* module() const { return board()->m_Modules; }
bool m_editModules; bool m_editModules;
}; };

View File

@ -27,6 +27,7 @@
#include "pcbnew_control.h" #include "pcbnew_control.h"
#include "pcb_actions.h" #include "pcb_actions.h"
#include "selection_tool.h" #include "selection_tool.h"
#include "edit_tool.h"
#include "picker_tool.h" #include "picker_tool.h"
#include "pcb_editor_control.h" #include "pcb_editor_control.h"
#include "grid_helper.h" #include "grid_helper.h"
@ -232,7 +233,7 @@ TOOL_ACTION PCB_ACTIONS::pasteFromClipboard( "pcbnew.InteractiveEdit.pasteFromCl
PCBNEW_CONTROL::PCBNEW_CONTROL() : PCBNEW_CONTROL::PCBNEW_CONTROL() :
TOOL_INTERACTIVE( "pcbnew.Control" ), m_frame( NULL ) PCB_TOOL( "pcbnew.Control" ), m_frame( NULL )
{ {
m_gridOrigin.reset( new KIGFX::ORIGIN_VIEWITEM() ); m_gridOrigin.reset( new KIGFX::ORIGIN_VIEWITEM() );
} }
@ -249,7 +250,7 @@ void PCBNEW_CONTROL::Reset( RESET_REASON aReason )
if( aReason == MODEL_RELOAD || aReason == GAL_SWITCH ) if( aReason == MODEL_RELOAD || aReason == GAL_SWITCH )
{ {
m_gridOrigin->SetPosition( getModel<BOARD>()->GetGridOrigin() ); m_gridOrigin->SetPosition( board()->GetGridOrigin() );
getView()->Remove( m_gridOrigin.get() ); getView()->Remove( m_gridOrigin.get() );
getView()->Add( m_gridOrigin.get() ); getView()->Add( m_gridOrigin.get() );
} }
@ -266,10 +267,10 @@ int PCBNEW_CONTROL::TrackDisplayMode( const TOOL_EVENT& aEvent )
displ_opts->m_DisplayPcbTrackFill = !displ_opts->m_DisplayPcbTrackFill; displ_opts->m_DisplayPcbTrackFill = !displ_opts->m_DisplayPcbTrackFill;
settings->LoadDisplayOptions( displ_opts ); settings->LoadDisplayOptions( displ_opts );
for( TRACK* track = getModel<BOARD>()->m_Track; track; track = track->Next() ) for( auto track : board()->Tracks() )
{ {
if( track->Type() == PCB_TRACE_T ) if( track->Type() == PCB_TRACE_T )
getView()->Update( track, KIGFX::GEOMETRY ); view()->Update( track, KIGFX::GEOMETRY );
} }
m_frame->GetGalCanvas()->Refresh(); m_frame->GetGalCanvas()->Refresh();
@ -289,7 +290,7 @@ int PCBNEW_CONTROL::PadDisplayMode( const TOOL_EVENT& aEvent )
displ_opts->m_DisplayPadFill = !displ_opts->m_DisplayPadFill; displ_opts->m_DisplayPadFill = !displ_opts->m_DisplayPadFill;
settings->LoadDisplayOptions( displ_opts ); settings->LoadDisplayOptions( displ_opts );
for( MODULE* module = getModel<BOARD>()->m_Modules; module; module = module->Next() ) for( auto module : board()->Modules() )
{ {
for( auto pad : module->Pads() ) for( auto pad : module->Pads() )
getView()->Update( pad, KIGFX::GEOMETRY ); getView()->Update( pad, KIGFX::GEOMETRY );
@ -311,7 +312,7 @@ int PCBNEW_CONTROL::ViaDisplayMode( const TOOL_EVENT& aEvent )
displ_opts->m_DisplayViaFill = !displ_opts->m_DisplayViaFill; displ_opts->m_DisplayViaFill = !displ_opts->m_DisplayViaFill;
settings->LoadDisplayOptions( displ_opts ); settings->LoadDisplayOptions( displ_opts );
for( TRACK* track = getModel<BOARD>()->m_Track; track; track = track->Next() ) for( auto track : board()->Tracks() )
{ {
if( track->Type() == PCB_TRACE_T || track->Type() == PCB_VIA_T ) if( track->Type() == PCB_TRACE_T || track->Type() == PCB_VIA_T )
getView()->Update( track, KIGFX::GEOMETRY ); getView()->Update( track, KIGFX::GEOMETRY );
@ -341,9 +342,8 @@ int PCBNEW_CONTROL::ZoneDisplayMode( const TOOL_EVENT& aEvent )
settings->LoadDisplayOptions( displ_opts ); settings->LoadDisplayOptions( displ_opts );
BOARD* board = getModel<BOARD>(); for( int i = 0; i < board()->GetAreaCount(); ++i )
for( int i = 0; i < board->GetAreaCount(); ++i ) view()->Update( board()->GetArea( i ), KIGFX::GEOMETRY );
getView()->Update( board->GetArea( i ), KIGFX::GEOMETRY );
m_frame->GetGalCanvas()->Refresh(); m_frame->GetGalCanvas()->Refresh();
@ -394,7 +394,7 @@ int PCBNEW_CONTROL::LayerNext( const TOOL_EVENT& aEvent )
if( layer < F_Cu || layer > B_Cu ) if( layer < F_Cu || layer > B_Cu )
return 0; return 0;
int layerCount = getModel<BOARD>()->GetCopperLayerCount(); int layerCount = board()->GetCopperLayerCount();
if( layer == layerCount - 2 || layerCount < 2 ) if( layer == layerCount - 2 || layerCount < 2 )
layer = B_Cu; layer = B_Cu;
@ -418,7 +418,7 @@ int PCBNEW_CONTROL::LayerPrev( const TOOL_EVENT& aEvent )
if( layer < F_Cu || layer > B_Cu ) if( layer < F_Cu || layer > B_Cu )
return 0; return 0;
int layerCount = getModel<BOARD>()->GetCopperLayerCount(); int layerCount = board()->GetCopperLayerCount();
if( layer == F_Cu || layerCount < 2 ) if( layer == F_Cu || layerCount < 2 )
layer = B_Cu; layer = B_Cu;
@ -649,7 +649,7 @@ int PCBNEW_CONTROL::GridSetOrigin( const TOOL_EVENT& aEvent )
int PCBNEW_CONTROL::GridResetOrigin( const TOOL_EVENT& aEvent ) int PCBNEW_CONTROL::GridResetOrigin( const TOOL_EVENT& aEvent )
{ {
getModel<BOARD>()->SetGridOrigin( wxPoint( 0, 0 ) ); board()->SetGridOrigin( wxPoint( 0, 0 ) );
m_gridOrigin->SetPosition( VECTOR2D( 0, 0 ) ); m_gridOrigin->SetPosition( VECTOR2D( 0, 0 ) );
return 0; return 0;
@ -737,52 +737,73 @@ int PCBNEW_CONTROL::DeleteItemCursor( const TOOL_EVENT& aEvent )
return 0; return 0;
} }
int PCBNEW_CONTROL::AppendBoardFromClipboard( const TOOL_EVENT& aEvent ) int PCBNEW_CONTROL::PasteItemsFromClipboard( const TOOL_EVENT& aEvent )
{ {
CLIPBOARD_IO pi; CLIPBOARD_IO pi;
wxString noString( "" );
BOARD* board = getModel<BOARD>();
pi.setBoard( board );
pi.SetBoard( board() );
BOARD_ITEM* clipItem = pi.Parse(); BOARD_ITEM* clipItem = pi.Parse();
TOOL_EVENT event;
if(!clipItem )
{
return 0;
}
bool editModules = m_editModules || frame()->IsType( FRAME_PCB_MODULE_EDITOR );
// The clipboard can contain two different things, an entire kicad_pcb // The clipboard can contain two different things, an entire kicad_pcb
// or a single module // or a single module
PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>(); if ( editModules && ( !board() || !module() ) )
if( !( frame->IsType( FRAME_PCB ) ) && !( frame->IsType( FRAME_PCB_MODULE_EDITOR ) ) )
{ {
return 1; wxLogDebug( wxT( "Attempting to paste to empty module editor window\n") );
return 0;
} }
switch( clipItem->Type() ) switch( clipItem->Type() )
{ {
case PCB_T: case PCB_T:
if(frame->IsType( FRAME_PCB ) )
{ {
if( AppendBoard( pi, noString ) ) if( editModules )
{ {
wxLogDebug( wxT( "attempting to paste a pcb in the footprint editor\n") );
return 0; return 0;
} }
}
placeBoardItems( static_cast<BOARD*>( clipItem ) );
break; break;
}
case PCB_MODULE_T: case PCB_MODULE_T:
clipItem->SetParent( board );
if(frame->IsType( FRAME_PCB) )
{ {
m_toolMgr->RunAction( "pcbnew.EditorControl.placeModule", true, std::vector<BOARD_ITEM *> items;
static_cast<MODULE*>( clipItem ) );
return 0; clipItem->SetParent( board() );
}
else if( frame->IsType( FRAME_PCB_MODULE_EDITOR ) ) if( editModules )
{ {
m_toolMgr->RunAction( "pcbnew.ModuleEditor.pasteItems", true, auto mod = static_cast<MODULE *>( clipItem );
static_cast<MODULE*>( clipItem ) );
return 0; for ( auto pad : mod->Pads() )
{
pad->SetParent ( board()->m_Modules.GetFirst() );
items.push_back( pad );
} }
for ( auto item : mod->GraphicalItems() )
{
item->SetParent ( board()->m_Modules.GetFirst() );
items.push_back( item );
}
}
else
{
items.push_back( clipItem );
}
placeBoardItems( items );
break; break;
}
default: default:
m_frame->DisplayToolMsg( _( "Invalid clipboard contents" ) ); m_frame->DisplayToolMsg( _( "Invalid clipboard contents" ) );
// FAILED // FAILED
@ -811,6 +832,57 @@ int PCBNEW_CONTROL::AppendBoardFromFile( const TOOL_EVENT& aEvent )
return AppendBoard( *pi, fileName ); return AppendBoard( *pi, fileName );
} }
int PCBNEW_CONTROL::placeBoardItems( BOARD* aBoard )
{
std::vector<BOARD_ITEM*> items;
for( auto track : aBoard->Tracks() )
{
items.push_back( track );
}
for( auto module : aBoard->Modules() )
{
items.push_back( module );
}
for( auto drawing : aBoard->Drawings() )
{
items.push_back( drawing );
}
for( auto zone : aBoard->Zones() )
{
items.push_back( zone );
}
return placeBoardItems( items );
}
int PCBNEW_CONTROL::placeBoardItems( std::vector<BOARD_ITEM*>& aItems )
{
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
auto selectionTool = m_toolMgr->GetTool<SELECTION_TOOL>();
auto editTool = m_toolMgr->GetTool<EDIT_TOOL>();
SELECTION& selection = selectionTool->GetSelection();
for ( auto item : aItems )
{
selection.Add( item );
editTool->GetCurrentCommit()->Add( item );
}
selection.SetReferencePoint( VECTOR2I( 0, 0 ) );
m_toolMgr->ProcessEvent( SELECTION_TOOL::SelectedEvent );
m_toolMgr->RunAction( PCB_ACTIONS::move, true );
return 0;
}
int PCBNEW_CONTROL::AppendBoard( PLUGIN& pi, wxString& fileName ) int PCBNEW_CONTROL::AppendBoard( PLUGIN& pi, wxString& fileName )
{ {
@ -821,21 +893,16 @@ int PCBNEW_CONTROL::AppendBoard( PLUGIN& pi, wxString& fileName )
// Mark existing tracks, in order to know what are the new tracks // Mark existing tracks, in order to know what are the new tracks
// Tracks are inserted, not appended, so mark existing tracks to be // Tracks are inserted, not appended, so mark existing tracks to be
// able to select the new tracks only later // able to select the new tracks only later
BOARD* board = getModel<BOARD>(); BOARD* brd = board();
if( !board ) if( !brd )
return 1; return 1;
for( TRACK* track = board->m_Track; track; track = track->Next() ) for( auto track : brd->Tracks() )
track->SetFlags( FLAG0 ); track->SetFlags( FLAG0 );
// Other items are appended to the item list, so keep trace to the last existing item is enough
MODULE* module = board->m_Modules.GetLast();
BOARD_ITEM* drawing = board->DrawingsList().GetLast();
int zonescount = board->GetAreaCount();
// Keep also the count of copper layers, to adjust if necessary // Keep also the count of copper layers, to adjust if necessary
int initialCopperLayerCount = board->GetCopperLayerCount(); int initialCopperLayerCount = brd->GetCopperLayerCount();
LSET initialEnabledLayers = board->GetEnabledLayers(); LSET initialEnabledLayers = brd->GetEnabledLayers();
// Load the data // Load the data
try try
@ -852,7 +919,7 @@ int PCBNEW_CONTROL::AppendBoard( PLUGIN& pi, wxString& fileName )
props["page_height"] = ybuf; props["page_height"] = ybuf;
editFrame->GetDesignSettings().m_NetClasses.Clear(); editFrame->GetDesignSettings().m_NetClasses.Clear();
pi.Load( fileName, board, &props ); pi.Load( fileName, brd, &props );
} }
catch( const IO_ERROR& ioe ) catch( const IO_ERROR& ioe )
{ {
@ -863,86 +930,25 @@ int PCBNEW_CONTROL::AppendBoard( PLUGIN& pi, wxString& fileName )
} }
// rebuild nets and ratsnest before any use of nets // rebuild nets and ratsnest before any use of nets
board->BuildListOfNets(); brd->BuildListOfNets();
board->SynchronizeNetsAndNetClasses(); brd->SynchronizeNetsAndNetClasses();
board->GetConnectivity()->Build( board );
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SELECTION_TOOL>();
SELECTION& selection = selectionTool->GetSelection();
BOARD_COMMIT commit( editFrame );
// Process the new items
for( TRACK* track = board->m_Track; track; track = track->Next() )
{
if( track->GetFlags() & FLAG0 )
{
track->ClearFlags( FLAG0 );
continue;
}
commit.Added( track );
selection.Add( track );
}
module = module ? module->Next() : board->m_Modules;
for( ; module; module = module->Next() )
{
commit.Added( module );
selection.Add( module );
}
drawing = drawing ? drawing->Next() : board->DrawingsList();
for( ; drawing; drawing = drawing->Next() )
{
commit.Added( drawing );
selection.Add( drawing );
}
for( ZONE_CONTAINER* zone = board->GetArea( zonescount ); zone;
zone = board->GetArea( zonescount ) )
{
++zonescount;
commit.Added( zone );
selection.Add( zone );
}
if( commit.Empty() )
return 0;
commit.Push( _( "Append a board" ) );
// Synchronize layers // Synchronize layers
// we should not ask PLUGINs to do these items: // we should not ask PLUGINs to do these items:
int copperLayerCount = board->GetCopperLayerCount(); int copperLayerCount = brd->GetCopperLayerCount();
if( copperLayerCount > initialCopperLayerCount ) if( copperLayerCount > initialCopperLayerCount )
board->SetCopperLayerCount( copperLayerCount ); brd->SetCopperLayerCount( copperLayerCount );
// Enable all used layers, and make them visible: // Enable all used layers, and make them visible:
LSET enabledLayers = board->GetEnabledLayers(); LSET enabledLayers = brd->GetEnabledLayers();
enabledLayers |= initialEnabledLayers; enabledLayers |= initialEnabledLayers;
board->SetEnabledLayers( enabledLayers ); brd->SetEnabledLayers( enabledLayers );
board->SetVisibleLayers( enabledLayers ); brd->SetVisibleLayers( enabledLayers );
editFrame->ReCreateLayerBox();
editFrame->ReFillLayerWidget();
static_cast<PCB_DRAW_PANEL_GAL*>( editFrame->GetGalCanvas() )->SyncLayersVisibility( board );
// Start dragging the appended board
if( selection.Size() ) // be sure at least one item is loaded
{
// Inform other potentially interested tools
m_toolMgr->ProcessEvent( SELECTION_TOOL::SelectedEvent );
VECTOR2D v( static_cast<BOARD_ITEM*>( selection.Front() )->GetPosition() ); return placeBoardItems( brd );
getViewControls()->WarpCursor( v, true, true );
m_toolMgr->InvokeTool( "pcbnew.InteractiveEdit" );
}
return 0;
} }
@ -1026,7 +1032,7 @@ void PCBNEW_CONTROL::setTransitions()
Go( &PCBNEW_CONTROL::AppendBoardFromFile, Go( &PCBNEW_CONTROL::AppendBoardFromFile,
PCB_ACTIONS::appendBoard.MakeEvent() ); PCB_ACTIONS::appendBoard.MakeEvent() );
Go( &PCBNEW_CONTROL::AppendBoardFromClipboard, Go( &PCBNEW_CONTROL::PasteItemsFromClipboard,
PCB_ACTIONS::pasteFromClipboard.MakeEvent() ); PCB_ACTIONS::pasteFromClipboard.MakeEvent() );
} }

View File

@ -25,22 +25,23 @@
#ifndef PCBNEW_CONTROL_H #ifndef PCBNEW_CONTROL_H
#define PCBNEW_CONTROL_H #define PCBNEW_CONTROL_H
#include <tool/tool_interactive.h>
#include <io_mgr.h> #include <io_mgr.h>
#include <memory> #include <memory>
#include <tools/pcb_tool.h>
namespace KIGFX { namespace KIGFX {
class ORIGIN_VIEWITEM; class ORIGIN_VIEWITEM;
} }
class PCB_BASE_FRAME;
class PCB_BASE_FRAME;
class BOARD_ITEM;
/** /**
* Class PCBNEW_CONTROL * Class PCBNEW_CONTROL
* *
* Handles actions that are shared between different frames in pcbnew. * Handles actions that are shared between different frames in pcbnew.
*/ */
class PCBNEW_CONTROL : public TOOL_INTERACTIVE class PCBNEW_CONTROL : public PCB_TOOL
{ {
public: public:
PCBNEW_CONTROL(); PCBNEW_CONTROL();
@ -80,7 +81,7 @@ public:
int SwitchCursor( const TOOL_EVENT& aEvent ); int SwitchCursor( const TOOL_EVENT& aEvent );
int SwitchUnits( const TOOL_EVENT& aEvent ); int SwitchUnits( const TOOL_EVENT& aEvent );
int DeleteItemCursor( const TOOL_EVENT& aEvent ); int DeleteItemCursor( const TOOL_EVENT& aEvent );
int AppendBoardFromClipboard( const TOOL_EVENT& aEvent ); int PasteItemsFromClipboard( const TOOL_EVENT& aEvent );
int AppendBoardFromFile( const TOOL_EVENT& aEvent ); int AppendBoardFromFile( const TOOL_EVENT& aEvent );
int AppendBoard( PLUGIN& pi, wxString& fileName ); int AppendBoard( PLUGIN& pi, wxString& fileName );
int ShowHelp( const TOOL_EVENT& aEvent ); int ShowHelp( const TOOL_EVENT& aEvent );
@ -90,6 +91,10 @@ public:
void setTransitions() override; void setTransitions() override;
private: private:
int placeBoardItems( BOARD* aBoard );
int placeBoardItems( std::vector<BOARD_ITEM*>& aItems );
///> Pointer to the currently used edit frame. ///> Pointer to the currently used edit frame.
PCB_BASE_FRAME* m_frame; PCB_BASE_FRAME* m_frame;

View File

@ -24,6 +24,7 @@
#include "picker_tool.h" #include "picker_tool.h"
#include "pcb_actions.h" #include "pcb_actions.h"
#include "grid_helper.h"
#include <wxPcbStruct.h> #include <wxPcbStruct.h>
#include <view/view_controls.h> #include <view/view_controls.h>
@ -33,7 +34,7 @@ TOOL_ACTION PCB_ACTIONS::pickerTool( "pcbnew.Picker", AS_GLOBAL, 0, "", "", NULL
PICKER_TOOL::PICKER_TOOL() PICKER_TOOL::PICKER_TOOL()
: TOOL_INTERACTIVE( "pcbnew.Picker" ) : PCB_TOOL( "pcbnew.Picker" )
{ {
reset(); reset();
} }
@ -42,6 +43,7 @@ PICKER_TOOL::PICKER_TOOL()
int PICKER_TOOL::Main( const TOOL_EVENT& aEvent ) int PICKER_TOOL::Main( const TOOL_EVENT& aEvent )
{ {
KIGFX::VIEW_CONTROLS* controls = getViewControls(); KIGFX::VIEW_CONTROLS* controls = getViewControls();
GRID_HELPER grid( frame() );
assert( !m_picking ); assert( !m_picking );
m_picking = true; m_picking = true;
@ -49,12 +51,14 @@ int PICKER_TOOL::Main( const TOOL_EVENT& aEvent )
setControls(); setControls();
while( OPT_TOOL_EVENT evt = Wait() ) while( OPT_TOOL_EVENT evt = Wait() )
{ {
if( evt->IsClick( BUT_LEFT ) ) if( evt->IsClick( BUT_LEFT ) )
{ {
bool getNext = false; bool getNext = false;
m_picked = controls->GetCursorPosition(); auto cursorPos = controls->GetCursorPosition();
m_picked = grid.BestSnapAnchor( cursorPos, nullptr );
if( m_clickHandler ) if( m_clickHandler )
{ {

View File

@ -25,21 +25,20 @@
#ifndef PICKER_TOOL_H #ifndef PICKER_TOOL_H
#define PICKER_TOOL_H #define PICKER_TOOL_H
#include <tool/tool_interactive.h>
#include <boost/optional/optional.hpp> #include <boost/optional/optional.hpp>
#include <boost/function.hpp>
#include "pcb_tool.h"
/** /**
* @brief Generic tool for picking a point. * @brief Generic tool for picking a point.
*/ */
class PICKER_TOOL : public TOOL_INTERACTIVE class PICKER_TOOL : public PCB_TOOL
{ {
public: public:
PICKER_TOOL(); PICKER_TOOL();
~PICKER_TOOL() {} ~PICKER_TOOL() {}
///> Mouse event click handler type. ///> Mouse event click handler type.
typedef boost::function<bool(const VECTOR2D&)> CLICK_HANDLER; typedef std::function<bool(const VECTOR2D&)> CLICK_HANDLER;
///> @copydoc TOOL_INTERACTIVE::Reset() ///> @copydoc TOOL_INTERACTIVE::Reset()
void Reset( RESET_REASON aReason ) override {} void Reset( RESET_REASON aReason ) override {}