Library Editor: copy/cut/paste for graphical items

This commit is contained in:
Maciej Suminski 2017-11-20 14:11:50 +01:00
parent 4fe06656a6
commit 256276cf1c
5 changed files with 170 additions and 3 deletions

View File

@ -147,6 +147,31 @@ bool LIB_EDIT_FRAME::HandleBlockEnd( wxDC* aDC )
block->SetState( STATE_BLOCK_MOVE );
break;
case BLOCK_COPY: // Save a copy of items in the clipboard buffer
case BLOCK_CUT:
if( GetCurPart() )
ItemCount = GetCurPart()->SelectItems( *block, m_unit, m_convert,
m_editPinsPerPartOrConvert );
if( ItemCount )
{
copySelectedItems();
auto cmd = block->GetCommand();
if( cmd == BLOCK_COPY )
{
GetCurPart()->ClearSelectedItems();
block->ClearItemsList();
}
else if( cmd == BLOCK_CUT )
{
SaveCopyInUndoList( GetCurPart() );
GetCurPart()->DeleteSelectedItems();
OnModify();
}
}
break;
case BLOCK_DELETE: // Delete
if( GetCurPart() )
ItemCount = GetCurPart()->SelectItems( *block,
@ -162,8 +187,10 @@ bool LIB_EDIT_FRAME::HandleBlockEnd( wxDC* aDC )
}
break;
case BLOCK_COPY: // Save
case BLOCK_PASTE:
wxFAIL; // should not happen
break;
case BLOCK_FLIP:
break;
@ -208,7 +235,6 @@ bool LIB_EDIT_FRAME::HandleBlockEnd( wxDC* aDC )
case BLOCK_DUPLICATE_AND_INCREMENT: // not used in Eeschema
case BLOCK_MOVE_EXACT: // not used in Eeschema
case BLOCK_CUT: // not used in libedit
break;
}
@ -280,6 +306,14 @@ void LIB_EDIT_FRAME::HandleBlockPlace( wxDC* DC )
case BLOCK_PASTE: // Paste (recopy the last block saved)
block->ClearItemsList();
if( GetCurPart() )
SaveCopyInUndoList( GetCurPart() );
pt = block->GetMoveVector();
pt.y = -pt.y;
pasteClipboard( pt );
break;
case BLOCK_ROTATE: // Invert by popup menu, from block move
@ -324,6 +358,73 @@ void LIB_EDIT_FRAME::HandleBlockPlace( wxDC* DC )
}
void LIB_EDIT_FRAME::InitBlockPasteInfos()
{
BLOCK_SELECTOR& block = GetScreen()->m_BlockLocate;
// Copy the clipboard contents to the screen block selector
// (only the copy, the new instances will be appended to the part once the items are placed)
block.GetItems().CopyList( m_clipboard.GetItems() );
// Set the pate reference point
block.SetLastCursorPosition( m_clipboard.GetLastCursorPosition() );
m_canvas->SetMouseCaptureCallback( DrawMovingBlockOutlines );
}
void LIB_EDIT_FRAME::copySelectedItems()
{
LIB_PART* part = GetCurPart();
if( !part )
return;
m_clipboard.ClearListAndDeleteItems(); // delete previous saved list, if exists
m_clipboard.SetLastCursorPosition( GetScreen()->m_BlockLocate.GetEnd() ); // store the reference point
for( LIB_ITEM& item : part->GetDrawItems() )
{
// We *do not* copy fields because they are unique for the whole component
// so skip them (do not duplicate) if they are flagged selected.
if( item.Type() == LIB_FIELD_T )
item.ClearFlags( SELECTED );
if( !item.IsSelected() )
continue;
// Do not clear the 'selected' flag. It is required to have items drawn when they are pasted.
LIB_ITEM* copy = (LIB_ITEM*) item.Clone();
// In list the wrapper is owner of the schematic item, we can use the UR_DELETED
// status for the picker because pickers with this status are owner of the picked item
// (or TODO ?: create a new status like UR_DUPLICATE)
ITEM_PICKER picker( copy, UR_DELETED );
m_clipboard.PushItem( picker );
}
}
void LIB_EDIT_FRAME::pasteClipboard( const wxPoint& aOffset )
{
LIB_PART* part = GetCurPart();
if( !part || m_clipboard.GetCount() == 0 )
return;
for( unsigned int i = 0; i < m_clipboard.GetCount(); i++ )
{
// Append a copy to the current part, so the clipboard buffer might be pasted multiple times
LIB_ITEM* item = (LIB_ITEM*) m_clipboard.GetItem( i )->Clone();
item->SetParent( part );
item->SetSelected();
part->AddDrawItem( item );
}
GetCurPart()->MoveSelectedItems( aOffset );
OnModify();
}
/*
* Traces the outline of the search block structures
* The entire block follows the cursor
@ -353,6 +454,12 @@ void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint&
{
block->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, block->GetColor() );
component->Draw( aPanel, aDC, block->GetMoveVector(), unit, convert, opts );
for( unsigned ii = 0; ii < block->GetCount(); ii++ )
{
LIB_ITEM* libItem = (LIB_ITEM*) block->GetItem( ii );
libItem->Draw( aPanel, aDC, block->GetMoveVector(), g_GhostColor, g_XorMode, nullptr, opts.transform );
}
}
// Repaint new view
@ -361,5 +468,11 @@ void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint&
GRSetDrawMode( aDC, g_XorMode );
block->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, block->GetColor() );
for( unsigned ii = 0; ii < block->GetCount(); ii++ )
{
LIB_ITEM* libItem = (LIB_ITEM*) block->GetItem( ii );
libItem->Draw( aPanel, aDC, block->GetMoveVector(), g_GhostColor, g_XorMode, nullptr, opts.transform );
}
component->Draw( aPanel, aDC, block->GetMoveVector(), unit, convert, opts );
}

View File

@ -327,6 +327,9 @@ static EDA_HOTKEY* libEdit_Hotkey_List[] =
&HkMoveLibItem,
&HkMirrorX,
&HkMirrorY,
&HkCopyBlock,
&HkPasteBlock,
&HkCutBlock,
NULL
};
@ -703,6 +706,9 @@ bool LIB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition,
case HK_ZOOM_REDRAW:
case HK_ZOOM_CENTER:
case HK_ZOOM_AUTO:
case HK_PASTE_BLOCK:
case HK_COPY_BLOCK:
case HK_CUT_BLOCK:
cmd.SetId( hotKey->m_IdMenuEvent );
GetEventHandler()->ProcessEvent( cmd );
break;

View File

@ -337,6 +337,14 @@ void AddMenusForBlock( wxMenu* PopMenu, LIB_EDIT_FRAME* frame )
{
AddMenuItem( PopMenu, ID_POPUP_SELECT_ITEMS_BLOCK, _( "Select Items" ),
KiBitmap( green_xpm ) );
msg = AddHotkeyName( _( "Cut Block" ), g_Schematic_Hokeys_Descr,
HK_CUT_BLOCK );
AddMenuItem( PopMenu, wxID_CUT, msg, KiBitmap( cut_xpm ) );
msg = AddHotkeyName( _( "Copy Block" ), g_Schematic_Hokeys_Descr,
HK_COPY_BLOCK );
AddMenuItem( PopMenu, wxID_COPY, msg, KiBitmap( copy_xpm ) );
AddMenuItem( PopMenu, ID_POPUP_DUPLICATE_BLOCK, _( "Duplicate Block" ),
KiBitmap( duplicate_xpm ) );
AddMenuItem( PopMenu, ID_POPUP_DUPLICATE_BLOCK, _( "Duplicate Block" ), KiBitmap( duplicate_xpm ) );
msg = AddHotkeyName( _( "Flip Block Horizonal" ), g_Libedit_Hokeys_Descr, HK_MIRROR_Y );
AddMenuItem( PopMenu, ID_POPUP_MIRROR_Y_BLOCK, msg,

View File

@ -110,6 +110,9 @@ BEGIN_EVENT_TABLE( LIB_EDIT_FRAME, EDA_DRAW_FRAME )
// Main horizontal toolbar.
EVT_TOOL( ID_TO_LIBVIEW, LIB_EDIT_FRAME::OnOpenLibraryViewer )
EVT_TOOL( wxID_COPY, LIB_EDIT_FRAME::Process_Special_Functions )
EVT_TOOL( wxID_PASTE, LIB_EDIT_FRAME::Process_Special_Functions )
EVT_TOOL( wxID_CUT, LIB_EDIT_FRAME::Process_Special_Functions )
EVT_TOOL( wxID_UNDO, LIB_EDIT_FRAME::GetComponentFromUndoList )
EVT_TOOL( wxID_REDO, LIB_EDIT_FRAME::GetComponentFromRedoList )
EVT_TOOL( ID_LIBEDIT_GET_FRAME_EDIT_PART, LIB_EDIT_FRAME::OnEditComponentProperties )
@ -747,6 +750,8 @@ void LIB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
switch( id ) // Stop placement commands before handling new command.
{
case wxID_COPY:
case wxID_CUT:
case ID_POPUP_LIBEDIT_END_CREATE_ITEM:
case ID_LIBEDIT_EDIT_PIN:
case ID_POPUP_LIBEDIT_BODY_EDIT_ITEM:
@ -965,6 +970,25 @@ void LIB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
HandleBlockPlace( &dc );
break;
case wxID_COPY:
block.SetCommand( BLOCK_COPY );
block.SetMessageBlock( this );
HandleBlockEnd( &dc );
break;
case wxID_PASTE:
HandleBlockBegin( &dc, BLOCK_PASTE, GetCrossHairPosition() );
break;
case wxID_CUT:
if( block.GetCommand() != BLOCK_MOVE )
break;
block.SetCommand( BLOCK_CUT );
block.SetMessageBlock( this );
HandleBlockEnd( &dc );
break;
default:
DisplayError( this, "LIB_EDIT_FRAME::Process_Special_Functions error" );
break;

View File

@ -731,7 +731,23 @@ private:
///> Renames LIB_PART aliases to avoid conflicts before adding a component to a library
void fixDuplicateAliases( LIB_PART* aPart, const wxString& aLibrary );
// Copy/cut/paste buffer
void InitBlockPasteInfos() override;
/**
* Copies items selected in the current part to the internal clipboard.
*/
void copySelectedItems();
/**
* Pastes items from the internal clipboard to the current part.
* @param aOffset is the offset where the pasted items should be located.
*/
void pasteClipboard( const wxPoint& aOffset );
///> Clipboard buffer storing LIB_ITEMs
BLOCK_SELECTOR m_clipboard;
// Copy/cut/paste buffer to move parts between libraries
std::unique_ptr<LIB_PART> m_copiedPart;
DECLARE_EVENT_TABLE()