7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-20 21:01:22 +00:00

Handle pasting of image data from the clipboard

Also move some clipboard functions out of TOOL_MANAGER,
as they had no dependency on that class, and are just free
functions around wxTheClipboard.
This commit is contained in:
John Beard 2024-10-13 16:32:20 +08:00
parent a367073f20
commit c799966774
15 changed files with 306 additions and 140 deletions

View File

@ -555,6 +555,7 @@ set( COMMON_SRCS
bin_mod.cpp
bitmap_base.cpp
board_printout.cpp
clipboard.cpp
cli_progress_reporter.cpp
commit.cpp
draw_panel_gal.cpp

View File

@ -139,18 +139,7 @@ bool BITMAP_BASE::ReadImageFile( wxInputStream& aInStream )
if( !new_image->LoadFile( mem_stream ) )
return false;
delete m_image;
m_imageType = new_image->GetType();
m_image = new_image.release();
// Create a new wxImage object from m_image
delete m_originalImage;
m_originalImage = new wxImage( *m_image );
rebuildBitmap();
updatePPI();
return true;
return SetImage( *new_image );
}
@ -167,18 +156,7 @@ bool BITMAP_BASE::ReadImageFile( wxMemoryBuffer& aBuf )
if( !new_image->LoadFile( mem_stream ) )
return false;
delete m_image;
m_imageType = new_image->GetType();
m_image = new_image.release();
// Create a new wxImage object from m_image
delete m_originalImage;
m_originalImage = new wxImage( *m_image );
rebuildBitmap();
updatePPI();
return true;
return SetImage( *new_image );
}
@ -194,6 +172,25 @@ bool BITMAP_BASE::ReadImageFile(const wxString& aFullFilename)
}
bool BITMAP_BASE::SetImage( const wxImage& aImage )
{
if( !aImage.IsOk() || aImage.GetWidth() == 0 || aImage.GetHeight() == 0 )
return false;
delete m_image;
m_image = new wxImage( aImage );
// Create a new wxImage object from m_image
delete m_originalImage;
m_originalImage = new wxImage( *m_image );
rebuildBitmap();
updatePPI();
return true;
}
bool BITMAP_BASE::SaveImageData( wxOutputStream& aOutStream ) const
{
if( m_imageData.IsEmpty() )

109
common/clipboard.cpp Normal file
View File

@ -0,0 +1,109 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "clipboard.h"
#include <wx/clipbrd.h>
#include <wx/image.h>
#include <wx/log.h>
bool SaveClipboard( const std::string& aTextUTF8 )
{
wxLogNull doNotLog; // disable logging of failed clipboard actions
if( wxTheClipboard->Open() )
{
// Store the UTF8 string as Unicode string in clipboard:
wxTheClipboard->SetData(
new wxTextDataObject( wxString( aTextUTF8.c_str(), wxConvUTF8 ) ) );
wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
wxTheClipboard->Close();
return true;
}
return false;
}
std::string GetClipboardUTF8()
{
std::string result;
wxLogNull doNotLog; // disable logging of failed clipboard actions
if( wxTheClipboard->Open() )
{
if( wxTheClipboard->IsSupported( wxDF_TEXT )
|| wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
{
wxTextDataObject data;
wxTheClipboard->GetData( data );
// The clipboard is expected containing a Unicode string, so return it
// as UTF8 string
result = data.GetText().utf8_str();
}
wxTheClipboard->Close();
}
return result;
}
std::unique_ptr<wxImage> GetImageFromClipboard()
{
std::unique_ptr<wxImage> image;
wxLogNull doNotLog; // disable logging of failed clipboard actions
// First try for an image
if( wxTheClipboard->Open() )
{
if( wxTheClipboard->IsSupported( wxDF_BITMAP ) )
{
wxImageDataObject data;
if( wxTheClipboard->GetData( data ) )
{
image = std::make_unique<wxImage>( data.GetImage() );
}
}
else if( wxTheClipboard->IsSupported( wxDF_FILENAME ) )
{
wxFileDataObject data;
if( wxTheClipboard->GetData( data ) && data.GetFilenames().size() == 1 )
{
image = std::make_unique<wxImage>( data.GetFilenames()[0] );
if( !image->IsOk() )
image.reset();
}
}
wxTheClipboard->Close();
}
return image;
}

View File

@ -259,6 +259,18 @@ bool REFERENCE_IMAGE::ReadImageFile( wxMemoryBuffer& aBuffer )
}
bool REFERENCE_IMAGE::SetImage( const wxImage& aImage )
{
if( m_bitmapBase->SetImage( aImage ) )
{
updatePixelSizeInIU();
return true;
}
return false;
}
const BITMAP_BASE& REFERENCE_IMAGE::GetImage() const
{
// This cannot be null after construction

View File

@ -1050,52 +1050,6 @@ void TOOL_MANAGER::ScheduleContextMenu( TOOL_BASE* aTool, ACTION_MENU* aMenu,
}
bool TOOL_MANAGER::SaveClipboard( const std::string& aTextUTF8 )
{
wxLogNull doNotLog; // disable logging of failed clipboard actions
if( wxTheClipboard->Open() )
{
// Store the UTF8 string as Unicode string in clipboard:
wxTheClipboard->SetData( new wxTextDataObject( wxString( aTextUTF8.c_str(),
wxConvUTF8 ) ) );
wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
wxTheClipboard->Close();
return true;
}
return false;
}
std::string TOOL_MANAGER::GetClipboardUTF8() const
{
std::string result;
wxLogNull doNotLog; // disable logging of failed clipboard actions
if( wxTheClipboard->Open() )
{
if( wxTheClipboard->IsSupported( wxDF_TEXT )
|| wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
{
wxTextDataObject data;
wxTheClipboard->GetData( data );
// The clipboard is expected containing a Unicode string, so return it
// as UTF8 string
result = data.GetText().utf8_str();
}
wxTheClipboard->Close();
}
return result;
}
const KIGFX::VC_SETTINGS& TOOL_MANAGER::GetCurrentToolVC() const
{
if( TOOL_STATE* active = GetCurrentToolState() )

View File

@ -24,6 +24,7 @@
*/
#include <pgm_base.h>
#include <clipboard.h>
#include <confirm.h>
#include <kidialog.h>
#include <kiway.h>
@ -1227,7 +1228,7 @@ void SYMBOL_EDIT_FRAME::DuplicateSymbol( bool aFromClipboard )
if( aFromClipboard )
{
std::string clipboardData = m_toolManager->GetClipboardUTF8();
std::string clipboardData = GetClipboardUTF8();
try
{

View File

@ -24,6 +24,7 @@
#include "tools/sch_editor_control.h"
#include <clipboard.h>
#include <confirm.h>
#include <connection_graph.h>
#include <dialogs/dialog_symbol_fields_table.h>
@ -48,6 +49,7 @@
#include <project_sch.h>
#include <sch_edit_frame.h>
#include <sch_io/kicad_sexpr/sch_io_kicad_sexpr.h>
#include <sch_bitmap.h>
#include <sch_line.h>
#include <sch_junction.h>
#include <sch_bus_entry.h>
@ -1339,7 +1341,7 @@ bool SCH_EDITOR_CONTROL::doCopy( bool aUseDuplicateClipboard )
return true;
}
return m_toolMgr->SaveClipboard( formatter.GetString() );
return SaveClipboard( formatter.GetString() );
}
@ -1411,7 +1413,7 @@ int SCH_EDITOR_CONTROL::CopyAsText( const TOOL_EVENT& aEvent )
if( selection.IsHover() )
m_toolMgr->RunAction( EE_ACTIONS::clearSelection );
return m_toolMgr->SaveClipboard( itemsAsText.ToStdString() );
return SaveClipboard( itemsAsText.ToStdString() );
}
@ -1613,38 +1615,46 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
std::string content;
VECTOR2I eventPos;
if( aEvent.IsAction( &ACTIONS::duplicate ) )
content = m_duplicateClipboard;
else
content = m_toolMgr->GetClipboardUTF8();
SCH_SHEET tempSheet;
SCH_SCREEN* tempScreen = new SCH_SCREEN( &m_frame->Schematic() );
if( content.empty() )
return 0;
if( aEvent.IsAction( &ACTIONS::duplicate ) )
eventPos = getViewControls()->GetCursorPosition( false );
STRING_LINE_READER reader( content, "Clipboard" );
SCH_IO_KICAD_SEXPR plugin;
SCH_SHEET tempSheet;
SCH_SCREEN* tempScreen = new SCH_SCREEN( &m_frame->Schematic() );
EESCHEMA_SETTINGS::PANEL_ANNOTATE& annotate = m_frame->eeconfig()->m_AnnotatePanel;
int annotateStartNum = m_frame->Schematic().Settings().m_AnnotateStartNum;
// Screen object on heap is owned by the sheet.
tempSheet.SetScreen( tempScreen );
try
if( std::unique_ptr<wxImage> clipImg = GetImageFromClipboard() )
{
plugin.LoadContent( reader, &tempSheet );
// Just image data
auto bitmap = std::make_unique<SCH_BITMAP>();
bitmap->GetReferenceImage().SetImage( *clipImg );
tempScreen->Append( bitmap.release() );
}
catch( IO_ERROR& )
else
{
// If it wasn't content, then paste as text object.
SCH_TEXT* text_item = new SCH_TEXT( VECTOR2I( 0, 0 ), content );
tempScreen->Append( text_item );
if( aEvent.IsAction( &ACTIONS::duplicate ) )
content = m_duplicateClipboard;
else
content = GetClipboardUTF8();
if( content.empty() )
return 0;
if( aEvent.IsAction( &ACTIONS::duplicate ) )
eventPos = getViewControls()->GetCursorPosition( false );
STRING_LINE_READER reader( content, "Clipboard" );
SCH_IO_KICAD_SEXPR plugin;
// Screen object on heap is owned by the sheet.
tempSheet.SetScreen( tempScreen );
try
{
plugin.LoadContent( reader, &tempSheet );
}
catch( IO_ERROR& )
{
// If it wasn't content, then paste as a text object.
SCH_TEXT* text_item = new SCH_TEXT( VECTOR2I( 0, 0 ), content );
tempScreen->Append( text_item );
}
}
m_pastedSymbols.clear();
@ -1655,6 +1665,9 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
tempScreen->MigrateSimModels();
EESCHEMA_SETTINGS::PANEL_ANNOTATE& annotate = m_frame->eeconfig()->m_AnnotatePanel;
int annotateStartNum = m_frame->Schematic().Settings().m_AnnotateStartNum;
PASTE_MODE pasteMode = annotate.automatic ? PASTE_MODE::RESPECT_OPTIONS
: PASTE_MODE::REMOVE_ANNOTATIONS;

View File

@ -30,6 +30,7 @@
#include <tools/symbol_editor_pin_tool.h>
#include <tools/symbol_editor_drawing_tools.h>
#include <tools/symbol_editor_move_tool.h>
#include <clipboard.h>
#include <ee_actions.h>
#include <string_utils.h>
#include <symbol_edit_frame.h>
@ -903,7 +904,7 @@ int SYMBOL_EDITOR_EDIT_TOOL::Copy( const TOOL_EVENT& aEvent )
for( SCH_ITEM& item : symbol->GetDrawItems() )
item.ClearFlags( STRUCT_DELETED );
if( m_toolMgr->SaveClipboard( formatter.GetString() ) )
if( SaveClipboard( formatter.GetString() ) )
return 0;
else
return -1;
@ -923,7 +924,7 @@ int SYMBOL_EDITOR_EDIT_TOOL::CopyAsText( const TOOL_EVENT& aEvent )
if( selection.IsHover() )
m_toolMgr->RunAction( EE_ACTIONS::clearSelection );
return m_toolMgr->SaveClipboard( itemsAsText.ToStdString() );
return SaveClipboard( itemsAsText.ToStdString() );
}
@ -935,7 +936,7 @@ int SYMBOL_EDITOR_EDIT_TOOL::Paste( const TOOL_EVENT& aEvent )
if( !symbol || symbol->IsAlias() )
return 0;
std::string clipboardData = m_toolMgr->GetClipboardUTF8();
std::string clipboardData = GetClipboardUTF8();
try
{

View File

@ -170,6 +170,11 @@ public:
*/
bool ReadImageFile( wxMemoryBuffer& aBuf );
/**
* Set the image from an existing wxImage.
*/
bool SetImage( const wxImage& aImage );
/**
* Write the bitmap data to \a aOutStream.
*

55
include/clipboard.h Normal file
View File

@ -0,0 +1,55 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#pragma once
#include <memory>
#include <string>
class wxImage;
/**
* Store information to the system clipboard.
*
* @param aText is the information to be stored, expected UTF8 encoding. The text will be
* stored as Unicode string (not stored as UTF8 string).
* @return False if error occurred.
*/
bool SaveClipboard( const std::string& aTextUTF8 );
/**
* Return the information currently stored in the system clipboard.
*
* If data stored in the clipboard is in non-text format, empty string is returned.
*
* @note The clipboard is expected containing Unicode chars, not only ASCII7 chars.
* The returned string is UTF8 encoded
*/
std::string GetClipboardUTF8();
/**
* Get image data from the clipboard, if there is any.
*
* If there's a filename there, and it can be loaded as an image, do that.
*/
std::unique_ptr<wxImage> GetImageFromClipboard();

View File

@ -33,6 +33,7 @@
class BITMAP_BASE;
class wxMemoryBuffer;
class wxImage;
/**
* A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is
@ -103,6 +104,11 @@ public:
*/
bool ReadImageFile( wxMemoryBuffer& aBuf );
/**
* Set the image from an existing wxImage.
*/
bool SetImage( const wxImage& aImage );
void SwapData( REFERENCE_IMAGE& aItem );
/**

View File

@ -488,25 +488,6 @@ public:
*/
void ScheduleContextMenu( TOOL_BASE* aTool, ACTION_MENU* aMenu, CONTEXT_MENU_TRIGGER aTrigger );
/**
* Store information to the system clipboard.
*
* @param aText is the information to be stored, expected UTF8 encoding. The text will be
* stored as Unicode string (not stored as UTF8 string).
* @return False if error occurred.
*/
bool SaveClipboard( const std::string& aTextUTF8 );
/**
* Return the information currently stored in the system clipboard.
*
* If data stored in the clipboard is in non-text format, empty string is returned.
*
* @note The clipboard is expected containing Unicode chars, not only ASCII7 chars.
* The returned string is UTF8 encoded
*/
std::string GetClipboardUTF8() const;
/**
* Return the view controls settings for the current tool or the general settings if there is
* no active tool.

View File

@ -32,6 +32,7 @@
#include <drawing_sheet/ds_data_model.h>
#include <drawing_sheet/ds_draw_item.h>
#include <bitmaps.h>
#include <clipboard.h>
#include <confirm.h>
#include <eda_item.h>
#include <macros.h>
@ -532,7 +533,7 @@ int PL_EDIT_TOOL::Copy( const TOOL_EVENT& aEvent )
wxMessageBox( ioe.What(), _( "Error writing objects to clipboard" ) );
}
if( m_toolMgr->SaveClipboard( TO_UTF8( sexpr ) ) )
if( SaveClipboard( TO_UTF8( sexpr ) ) )
return 0;
else
return -1;
@ -543,11 +544,29 @@ int PL_EDIT_TOOL::Paste( const TOOL_EVENT& aEvent )
{
PL_SELECTION& selection = m_selectionTool->GetSelection();
DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
std::string sexpr = m_toolMgr->GetClipboardUTF8();
bool createdAnything = false;
m_selectionTool->ClearSelection();
if( std::unique_ptr<wxImage> clipImg = GetImageFromClipboard() )
{
auto image = std::make_unique<BITMAP_BASE>();
image->SetImage( *clipImg );
auto dataItem = std::make_unique<DS_DATA_ITEM_BITMAP>( image.release() );
model.Append( dataItem.release() );
model.SetPageLayout( sexpr.c_str(), true, wxT( "clipboard" ) );
createdAnything = true;
}
else
{
m_selectionTool->ClearSelection();
const std::string clipText = GetClipboardUTF8();
model.SetPageLayout( clipText.c_str(), true, wxT( "clipboard" ) );
createdAnything = true;
}
// Nothing pasteable
if( !createdAnything )
return 0;
// Build out draw items and select the first of each data item
for( DS_DATA_ITEM* dataItem : model.GetItems() )

View File

@ -26,6 +26,7 @@
#include <macros.h>
#include <advanced_config.h>
#include <clipboard.h>
#include <limits>
#include <kiplatform/ui.h>
#include <gal/graphics_abstraction_layer.h>
@ -3299,7 +3300,7 @@ int EDIT_TOOL::copyToClipboardAsText( const TOOL_EVENT& aEvent )
// Send the text to the clipboard
if( !itemTexts.empty() )
{
m_toolMgr->SaveClipboard( wxJoin( itemTexts, '\n', '\0' ).ToStdString() );
SaveClipboard( wxJoin( itemTexts, '\n', '\0' ).ToStdString() );
}
return 0;

View File

@ -38,6 +38,7 @@
#include <board.h>
#include <board_design_settings.h>
#include <board_item.h>
#include <clipboard.h>
#include <dialogs/dialog_paste_special.h>
#include <pcb_dimension.h>
#include <gal/graphics_abstraction_layer.h>
@ -45,6 +46,7 @@
#include <layer_pairs.h>
#include <pcb_group.h>
#include <pcb_layer_presentation.h>
#include <pcb_reference_image.h>
#include <pcb_textbox.h>
#include <pcb_track.h>
#include <pcb_generator.h>
@ -1024,23 +1026,32 @@ int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
if( !clipItem )
{
// When the clipboard doesn't parse, create a PCB textual item with the clipboard contents
const wxString clipText = m_toolMgr->GetClipboardUTF8();
// When the clipboard doesn't parse, create a PCB item with the clipboard contents
std::vector<BOARD_ITEM*> newItems;
if( clipText.empty() )
return 0;
if( std::unique_ptr<wxImage> clipImg = GetImageFromClipboard() )
{
auto refImg = std::make_unique<PCB_REFERENCE_IMAGE>( m_frame->GetModel() );
std::unique_ptr<PCB_TEXT> item;
if( refImg->GetReferenceImage().SetImage( *clipImg ) )
newItems.push_back( refImg.release() );
}
else
{
const wxString clipText = GetClipboardUTF8();
item = std::make_unique<PCB_TEXT>( m_frame->GetModel() );
item->SetText( clipText );
item->SetPosition( getViewControls()->GetCursorPosition() );
if( clipText.empty() )
return 0;
std::vector<BOARD_ITEM*> items{
item.release(),
};
std::unique_ptr<PCB_TEXT> item;
bool cancelled = !placeBoardItems( &commit, items, true, false, false );
item = std::make_unique<PCB_TEXT>( m_frame->GetModel() );
item->SetText( clipText );
newItems.push_back( item.release() );
}
bool cancelled = !placeBoardItems( &commit, newItems, true, false, false );
if( cancelled )
commit.Revert();