From 256276cf1c866c598e6780196fca518fd5e59c04 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 20 Nov 2017 14:11:50 +0100 Subject: [PATCH] Library Editor: copy/cut/paste for graphical items --- eeschema/block_libedit.cpp | 117 +++++++++++++++++++++++++++++- eeschema/hotkeys.cpp | 6 ++ eeschema/libedit_onrightclick.cpp | 8 ++ eeschema/libeditframe.cpp | 24 ++++++ eeschema/libeditframe.h | 18 ++++- 5 files changed, 170 insertions(+), 3 deletions(-) diff --git a/eeschema/block_libedit.cpp b/eeschema/block_libedit.cpp index cbf5f6718b..2e8a7d2bd2 100644 --- a/eeschema/block_libedit.cpp +++ b/eeschema/block_libedit.cpp @@ -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 ); } diff --git a/eeschema/hotkeys.cpp b/eeschema/hotkeys.cpp index c765ffbf43..f0d62a642d 100644 --- a/eeschema/hotkeys.cpp +++ b/eeschema/hotkeys.cpp @@ -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; diff --git a/eeschema/libedit_onrightclick.cpp b/eeschema/libedit_onrightclick.cpp index 3e6870e000..b135541a9d 100644 --- a/eeschema/libedit_onrightclick.cpp +++ b/eeschema/libedit_onrightclick.cpp @@ -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, diff --git a/eeschema/libeditframe.cpp b/eeschema/libeditframe.cpp index 35d2762779..560c60d521 100644 --- a/eeschema/libeditframe.cpp +++ b/eeschema/libeditframe.cpp @@ -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; diff --git a/eeschema/libeditframe.h b/eeschema/libeditframe.h index dc5e68c5fe..cb48d8da65 100644 --- a/eeschema/libeditframe.h +++ b/eeschema/libeditframe.h @@ -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 m_copiedPart; DECLARE_EVENT_TABLE()