diff --git a/src/app/app.cpp b/src/app/app.cpp index 7afd09495..1d7f7b6f9 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -139,7 +139,7 @@ public: #ifdef ENABLE_UI RecentFiles m_recent_files; InputChain m_inputChain; - clipboard::ClipboardManager m_clipboardManager; + Clipboard m_clipboard; #endif // This is a raw pointer because we want to delete it explicitly. // (e.g. if an exception occurs, the ~Modules() doesn't have to @@ -296,7 +296,7 @@ int App::initialize(const AppOptions& options) // Set the ClipboardDelegate impl to copy/paste text in the native // clipboard from the ui::Entry control. - m_uiSystem->setClipboardDelegate(&m_modules->m_clipboardManager); + m_uiSystem->setClipboardDelegate(&m_modules->m_clipboard); // Setup the GUI cursor and redraw screen ui::set_use_native_cursors(preferences().cursor.useNativeCursor()); diff --git a/src/app/commands/cmd_copy_merged.cpp b/src/app/commands/cmd_copy_merged.cpp index cb909981b..42bda76ba 100644 --- a/src/app/commands/cmd_copy_merged.cpp +++ b/src/app/commands/cmd_copy_merged.cpp @@ -1,4 +1,5 @@ // Aseprite +// Copyright (C) 2020 Igara Studio S.A. // Copyright (C) 2016-2017 David Capello // // This program is distributed under the terms of @@ -37,7 +38,7 @@ bool CopyMergedCommand::onEnabled(Context* ctx) void CopyMergedCommand::onExecute(Context* ctx) { ContextReader reader(ctx); - clipboard::copy_merged(reader); + ctx->clipboard()->copyMerged(reader); } Command* CommandFactory::createCopyMergedCommand() diff --git a/src/app/commands/cmd_new_file.cpp b/src/app/commands/cmd_new_file.cpp index c5a914033..8aa20d13b 100644 --- a/src/app/commands/cmd_new_file.cpp +++ b/src/app/commands/cmd_new_file.cpp @@ -25,7 +25,6 @@ #include "app/ui/workspace.h" #include "app/ui_context.h" #include "app/util/clipboard.h" -#include "app/util/clipboard.h" #include "app/util/pixel_ratio.h" #include "base/clamp.h" #include "doc/cel.h" @@ -72,12 +71,12 @@ NewFileCommand::NewFileCommand() { } -bool NewFileCommand::onEnabled(Context* context) +bool NewFileCommand::onEnabled(Context* ctx) { return (!params().fromClipboard() #ifdef ENABLE_UI - || (clipboard::get_current_format() == clipboard::ClipboardImage) + || (ctx->clipboard()->format() == ClipboardFormat::Image) #endif ); } @@ -97,7 +96,7 @@ void NewFileCommand::onExecute(Context* ctx) #ifdef ENABLE_UI if (params().fromClipboard()) { - clipboardImage = clipboard::get_image(&clipboardPalette); + clipboardImage = ctx->clipboard()->getImage(&clipboardPalette); if (!clipboardImage) return; @@ -133,7 +132,7 @@ void NewFileCommand::onExecute(Context* ctx) // If the clipboard contains an image, we can show the size of the // clipboard as default image size. gfx::Size clipboardSize; - if (clipboard::get_image_size(clipboardSize)) { + if (ctx->clipboard()->getImageSize(clipboardSize)) { w = clipboardSize.w; h = clipboardSize.h; } diff --git a/src/app/commands/cmd_new_layer.cpp b/src/app/commands/cmd_new_layer.cpp index 18cb3ab2b..ff1eaaca9 100644 --- a/src/app/commands/cmd_new_layer.cpp +++ b/src/app/commands/cmd_new_layer.cpp @@ -118,21 +118,21 @@ void NewLayerCommand::onLoadParams(const Params& commandParams) m_place = Place::BeforeActiveLayer; } -bool NewLayerCommand::onEnabled(Context* context) +bool NewLayerCommand::onEnabled(Context* ctx) { - if (!context->checkFlags(ContextFlags::ActiveDocumentIsWritable | - ContextFlags::HasActiveSprite)) + if (!ctx->checkFlags(ContextFlags::ActiveDocumentIsWritable | + ContextFlags::HasActiveSprite)) return false; #ifdef ENABLE_UI if (params().fromClipboard() && - clipboard::get_current_format() != clipboard::ClipboardImage) + ctx->clipboard()->format() != ClipboardFormat::Image) return false; #endif if ((params().viaCut() || params().viaCopy()) && - !context->checkFlags(ContextFlags::HasVisibleMask)) + !ctx->checkFlags(ContextFlags::HasVisibleMask)) return false; return true; @@ -392,7 +392,7 @@ void NewLayerCommand::onExecute(Context* context) #ifdef ENABLE_UI // Paste new layer from clipboard else if (params().fromClipboard() && layer->isImage()) { - clipboard::paste(context, false); + context->clipboard()->paste(context, false); if (layer->isReference()) { if (Cel* cel = layer->cel(site.frame())) { diff --git a/src/app/context.cpp b/src/app/context.cpp index ab3f62f59..7f49f660f 100644 --- a/src/app/context.cpp +++ b/src/app/context.cpp @@ -19,6 +19,7 @@ #include "app/doc.h" #include "app/pref/preferences.h" #include "app/site.h" +#include "app/util/clipboard.h" #include "base/scoped_value.h" #include "doc/layer.h" #include "ui/system.h" @@ -59,6 +60,16 @@ Preferences& Context::preferences() const return *m_preferences; } +Clipboard* Context::clipboard() const +{ +#ifdef ENABLE_UI + return Clipboard::instance(); +#else + // TODO support clipboard when !ENABLE_UI + throw std::runtime_error("Clipboard not supported"); +#endif +} + void Context::sendDocumentToTop(Doc* document) { ASSERT(document != NULL); diff --git a/src/app/context.h b/src/app/context.h index 464bd4d49..751c8f0b2 100644 --- a/src/app/context.h +++ b/src/app/context.h @@ -30,6 +30,7 @@ namespace doc { namespace app { class ActiveSiteHandler; + class Clipboard; class Command; class Doc; class DocRange; @@ -72,6 +73,7 @@ namespace app { Docs& documents() { return m_docs; } Preferences& preferences() const; + Clipboard* clipboard() const; virtual bool isUIAvailable() const { return false; } virtual bool isRecordingMacro() const { return false; } diff --git a/src/app/ui/color_bar.cpp b/src/app/ui/color_bar.cpp index 66a36221f..7ce04da4e 100644 --- a/src/app/ui/color_bar.cpp +++ b/src/app/ui/color_bar.cpp @@ -1407,10 +1407,11 @@ bool ColorBar::onCanCopy(Context* ctx) bool ColorBar::onCanPaste(Context* ctx) { + auto format = ctx->clipboard()->format(); if (m_tilemapMode == TilemapMode::Tiles) - return (clipboard::get_current_format() == clipboard::ClipboardTiles); + return (format == ClipboardFormat::Tileset); else - return (clipboard::get_current_format() == clipboard::ClipboardPaletteEntries); + return (format == ClipboardFormat::PaletteEntries); } bool ColorBar::onCanClear(Context* ctx) diff --git a/src/app/ui/doc_view.cpp b/src/app/ui/doc_view.cpp index ba5da0beb..cdfeadf8d 100644 --- a/src/app/ui/doc_view.cpp +++ b/src/app/ui/doc_view.cpp @@ -499,7 +499,7 @@ bool DocView::onCanCopy(Context* ctx) bool DocView::onCanPaste(Context* ctx) { return - (clipboard::get_current_format() == clipboard::ClipboardImage + (ctx->clipboard()->format() == ClipboardFormat::Image && ctx->checkFlags(ContextFlags::ActiveDocumentIsWritable | ContextFlags::ActiveLayerIsVisible | ContextFlags::ActiveLayerIsEditable | @@ -526,7 +526,7 @@ bool DocView::onCanClear(Context* ctx) bool DocView::onCut(Context* ctx) { ContextWriter writer(ctx); - clipboard::cut(writer); + ctx->clipboard()->cut(writer); return true; } @@ -536,7 +536,7 @@ bool DocView::onCopy(Context* ctx) if (reader.site()->document() && static_cast(reader.site()->document())->isMaskVisible() && reader.site()->image()) { - clipboard::copy(reader); + ctx->clipboard()->copy(reader); return true; } else @@ -545,8 +545,9 @@ bool DocView::onCopy(Context* ctx) bool DocView::onPaste(Context* ctx) { - if (clipboard::get_current_format() == clipboard::ClipboardImage) { - clipboard::paste(ctx, true); + auto clipboard = ctx->clipboard(); + if (clipboard->format() == ClipboardFormat::Image) { + clipboard->paste(ctx, true); return true; } else @@ -587,7 +588,7 @@ bool DocView::onClear(Context* ctx) (visibleMask && !Preferences::instance().selection.keepSelectionAfterClear()); - clipboard::clear_mask_from_cels( + ctx->clipboard()->clearMaskFromCels( tx, document, cels, deselectMask); diff --git a/src/app/ui/editor/moving_pixels_state.cpp b/src/app/ui/editor/moving_pixels_state.cpp index b230c304f..6ac723245 100644 --- a/src/app/ui/editor/moving_pixels_state.cpp +++ b/src/app/ui/editor/moving_pixels_state.cpp @@ -625,9 +625,10 @@ void MovingPixelsState::onBeforeCommandExecution(CommandExecutionEvent& ev) std::unique_ptr floatingMask; m_pixelsMovement->getDraggedImageCopy(floatingImage, floatingMask); - clipboard::copy_image(floatingImage.get(), - floatingMask.get(), - document->sprite()->palette(m_editor->frame())); + Clipboard::instance()-> + copyImage(floatingImage.get(), + floatingMask.get(), + document->sprite()->palette(m_editor->frame())); } // Clear floating pixels on Cut/Clear. diff --git a/src/app/ui/palette_view.cpp b/src/app/ui/palette_view.cpp index 91e4c330b..b9e7b58b8 100644 --- a/src/app/ui/palette_view.cpp +++ b/src/app/ui/palette_view.cpp @@ -534,7 +534,7 @@ void PaletteView::cutToClipboard() if (!m_selectedEntries.picks()) return; - clipboard::copy_palette(currentPalette(), m_selectedEntries); + Clipboard::instance()->copyPalette(currentPalette(), m_selectedEntries); clearSelection(); } @@ -544,7 +544,7 @@ void PaletteView::copyToClipboard() if (!m_selectedEntries.picks()) return; - clipboard::copy_palette(currentPalette(), m_selectedEntries); + Clipboard::instance()->copyPalette(currentPalette(), m_selectedEntries); startMarchingAnts(); invalidate(); @@ -552,11 +552,12 @@ void PaletteView::copyToClipboard() void PaletteView::pasteFromClipboard() { - if (clipboard::get_current_format() == clipboard::ClipboardPaletteEntries) { + auto clipboard = Clipboard::instance(); + if (clipboard->format() == ClipboardFormat::PaletteEntries) { if (m_delegate) m_delegate->onPaletteViewPasteColors( - clipboard::get_palette(), - clipboard::get_palette_picks(), + clipboard->getPalette(), + clipboard->getPalettePicks(), m_selectedEntries); // We just hide the marching ants, the user can paste multiple @@ -886,9 +887,10 @@ void PaletteView::onPaint(ui::PaintEvent& ev) // Draw marching ants if ((m_state == State::WAITING) && (isMarchingAntsRunning()) && - (clipboard::get_current_format() == clipboard::ClipboardPaletteEntries)) { - Palette* clipboardPalette = clipboard::get_palette(); - const PalettePicks& clipboardPicks = clipboard::get_palette_picks(); + (Clipboard::instance()->format() == ClipboardFormat::PaletteEntries)) { + auto clipboard = Clipboard::instance(); + Palette* clipboardPalette = clipboard->getPalette(); + const PalettePicks& clipboardPicks = clipboard->getPalettePicks(); if (clipboardPalette && clipboardPalette->countDiff(palette, nullptr, nullptr) == 0) { diff --git a/src/app/ui/timeline/timeline.cpp b/src/app/ui/timeline/timeline.cpp index 40bde387c..34121c7fa 100644 --- a/src/app/ui/timeline/timeline.cpp +++ b/src/app/ui/timeline/timeline.cpp @@ -608,7 +608,7 @@ bool Timeline::onProcessMessage(Message* msg) if (static_cast(msg)->timer() == &m_clipboard_timer) { Doc* clipboard_document; DocRange clipboard_range; - clipboard::get_document_range_info( + Clipboard::instance()->getDocumentRangeInfo( &clipboard_document, &clipboard_range); @@ -1944,7 +1944,7 @@ void Timeline::drawClipboardRange(ui::Graphics* g) { Doc* clipboard_document; DocRange clipboard_range; - clipboard::get_document_range_info( + Clipboard::instance()->getDocumentRangeInfo( &clipboard_document, &clipboard_range); @@ -3865,14 +3865,15 @@ void Timeline::clearClipboardRange() { Doc* clipboard_document; DocRange clipboard_range; - clipboard::get_document_range_info( + auto clipboard = Clipboard::instance(); + clipboard->getDocumentRangeInfo( &clipboard_document, &clipboard_range); if (!m_document || clipboard_document != m_document) return; - clipboard::clear_content(); + clipboard->clearContent(); m_clipboard_timer.stop(); } @@ -4012,7 +4013,7 @@ bool Timeline::onCanCopy(Context* ctx) bool Timeline::onCanPaste(Context* ctx) { return - (clipboard::get_current_format() == clipboard::ClipboardDocRange && + (ctx->clipboard()->format() == ClipboardFormat::DocRange && ctx->checkFlags(ContextFlags::ActiveDocumentIsWritable)); } @@ -4031,7 +4032,7 @@ bool Timeline::onCopy(Context* ctx) if (m_range.enabled()) { const ContextReader reader(ctx); if (reader.document()) { - clipboard::copy_range(reader, m_range); + ctx->clipboard()->copyRange(reader, m_range); return true; } } @@ -4040,8 +4041,9 @@ bool Timeline::onCopy(Context* ctx) bool Timeline::onPaste(Context* ctx) { - if (clipboard::get_current_format() == clipboard::ClipboardDocRange) { - clipboard::paste(ctx, true); + auto clipboard = ctx->clipboard(); + if (clipboard->format() == ClipboardFormat::DocRange) { + clipboard->paste(ctx, true); return true; } else diff --git a/src/app/util/clipboard.cpp b/src/app/util/clipboard.cpp index b75ca1b7f..6ff6ed865 100644 --- a/src/app/util/clipboard.cpp +++ b/src/app/util/clipboard.cpp @@ -32,7 +32,6 @@ #include "app/ui_context.h" #include "app/util/cel_ops.h" #include "app/util/clipboard.h" -#include "app/util/clipboard_native.h" #include "app/util/new_image_from_mask.h" #include "app/util/range_utils.h" #include "clip/clip.h" @@ -46,6 +45,8 @@ namespace app { +using namespace doc; + namespace { class ClipboardRange : public DocsObserver { @@ -65,7 +66,7 @@ namespace { UIContext::instance()->documents().remove_observer(this); } - bool valid() { + bool valid() const { return (m_doc != nullptr); } @@ -94,84 +95,127 @@ namespace { } -namespace clipboard { +// Data in the clipboard +struct Clipboard::Data { + // Text used when the native clipboard is disabled + std::string text; -using namespace doc; + // RGB/Grayscale/Indexed image + ImageRef image; -static std::shared_ptr clipboard_palette; -static std::shared_ptr clipboard_tiles; -static PalettePicks clipboard_picks; -static ImageRef clipboard_image; -static std::shared_ptr clipboard_mask; -static ClipboardRange clipboard_range; + // The palette of the image (or tileset) if it's indexed + std::shared_ptr palette; -static ClipboardManager* g_instance = nullptr; + // In case we copy a tilemap information + ImageRef tilemap; + + // Tileset for the tilemap or a set of tiles if we are copying tiles + // in the color bar + std::shared_ptr tileset; + + // Selected entries copied from the palette or the tileset + PalettePicks picks; + + // Original selection used to copy the image + std::shared_ptr mask; + + // Selected set of layers/layers/cels + ClipboardRange range; + + Data() { + range.observeUIContext(); + } + + ~Data() { + clear(); + range.unobserveUIContext(); + } + + void clear() { + text.clear(); + image.reset(); + palette.reset(); + tilemap.reset(); + tileset.reset(); + picks.clear(); + mask.reset(); + range.invalidate(); + } + + ClipboardFormat format() const { + if (image) + return ClipboardFormat::Image; + else if (tilemap) + return ClipboardFormat::Tilemap; + else if (range.valid()) + return ClipboardFormat::DocRange; + else if (palette && picks.picks()) + return ClipboardFormat::PaletteEntries; + else if (tileset && picks.picks()) + return ClipboardFormat::Tileset; + else + return ClipboardFormat::None; + } +}; static bool use_native_clipboard() { return Preferences::instance().experimental.useNativeClipboard(); } -ClipboardManager* ClipboardManager::instance() +static Clipboard* g_instance = nullptr; + +Clipboard* Clipboard::instance() { return g_instance; } -ClipboardManager::ClipboardManager() +Clipboard::Clipboard() + : m_data(new Data) { ASSERT(!g_instance); g_instance = this; - register_native_clipboard_formats(); - - clipboard_range.observeUIContext(); + registerNativeFormats(); } -ClipboardManager::~ClipboardManager() +Clipboard::~Clipboard() { - clipboard_range.invalidate(); - clipboard_range.unobserveUIContext(); - - // Clean the whole clipboard - clipboard_palette.reset(); - clipboard_image.reset(); - clipboard_mask.reset(); - ASSERT(g_instance == this); g_instance = nullptr; } -void ClipboardManager::setClipboardText(const std::string& text) +void Clipboard::setClipboardText(const std::string& text) { if (use_native_clipboard()) { clip::set_text(text); } else { - m_text = text; + m_data->text = text; } } -bool ClipboardManager::getClipboardText(std::string& text) +bool Clipboard::getClipboardText(std::string& text) { if (use_native_clipboard()) { return clip::get_text(text); } else { - text = m_text; + text = m_data->text; return true; } } -static void set_clipboard_image(Image* image, - Mask* mask, - Palette* palette, - bool set_system_clipboard, - bool image_source_is_transparent) +void Clipboard::setData(Image* image, + Mask* mask, + Palette* palette, + bool set_system_clipboard, + bool image_source_is_transparent) { - clipboard_palette.reset(palette); - clipboard_picks.clear(); - clipboard_image.reset(image); - clipboard_mask.reset(mask); + m_data->clear(); + m_data->palette.reset(palette); + m_data->image.reset(image); + m_data->mask.reset(mask); // Copy image to the native clipboard if (set_system_clipboard) { @@ -183,16 +227,14 @@ static void set_clipboard_image(Image* image, } if (use_native_clipboard()) - set_native_clipboard_bitmap(image, mask, palette); + setNativeBitmap(image, mask, palette); if (image && !image_source_is_transparent) image->setMaskColor(oldMask); } - - clipboard_range.invalidate(); } -static bool copy_from_document(const Site& site, bool merged = false) +bool Clipboard::copyFromDocument(const Site& site, bool merged) { const Doc* document = static_cast(site.document()); ASSERT(document); @@ -205,7 +247,7 @@ static bool copy_from_document(const Site& site, bool merged = false) return false; const Palette* pal = document->sprite()->palette(site.frame()); - set_clipboard_image( + setData( image, (mask ? new Mask(*mask): nullptr), (pal ? new Palette(*pal): nullptr), @@ -215,39 +257,30 @@ static bool copy_from_document(const Site& site, bool merged = false) return true; } -ClipboardFormat get_current_format() +ClipboardFormat Clipboard::format() const { // Check if the native clipboard has an image - if (use_native_clipboard() && - has_native_clipboard_bitmap()) - return ClipboardImage; - else if (clipboard_image) - return ClipboardImage; - else if (clipboard_range.valid()) - return ClipboardDocRange; - else if (clipboard_palette && clipboard_picks.picks()) - return ClipboardPaletteEntries; - else if (clipboard_tiles && clipboard_picks.picks()) - return ClipboardTiles; + if (use_native_clipboard() && hasNativeBitmap()) + return ClipboardFormat::Image; else - return ClipboardNone; + return m_data->format(); } -void get_document_range_info(Doc** document, DocRange* range) +void Clipboard::getDocumentRangeInfo(Doc** document, DocRange* range) { - if (clipboard_range.valid()) { - *document = clipboard_range.document(); - *range = clipboard_range.range(); + if (m_data->range.valid()) { + *document = m_data->range.document(); + *range = m_data->range.range(); } else { *document = NULL; } } -void clear_mask_from_cels(Tx& tx, - Doc* doc, - const CelList& cels, - const bool deselectMask) +void Clipboard::clearMaskFromCels(Tx& tx, + Doc* doc, + const CelList& cels, + const bool deselectMask) { for (Cel* cel : cels) { ObjectId celId = cel->id(); @@ -272,18 +305,18 @@ void clear_mask_from_cels(Tx& tx, tx(new cmd::DeselectMask(doc)); } -void clear_content() +void Clipboard::clearContent() { - set_clipboard_image(nullptr, nullptr, nullptr, true, false); + m_data->clear(); } -void cut(ContextWriter& writer) +void Clipboard::cut(ContextWriter& writer) { ASSERT(writer.document() != NULL); ASSERT(writer.sprite() != NULL); ASSERT(writer.layer() != NULL); - if (!copy_from_document(*writer.site())) { + if (!copyFromDocument(*writer.site())) { Console console; console.printf("Can't copying an image portion from the current layer\n"); } @@ -299,10 +332,10 @@ void cut(ContextWriter& writer) else if (site.cel()) { cels.push_back(site.cel()); } - clear_mask_from_cels(tx, - writer.document(), - cels, - true); // Deselect mask + clearMaskFromCels(tx, + writer.document(), + cels, + true); // Deselect mask tx.commit(); } writer.document()->generateMaskBoundaries(); @@ -310,60 +343,60 @@ void cut(ContextWriter& writer) } } -void copy(const ContextReader& reader) +void Clipboard::copy(const ContextReader& reader) { ASSERT(reader.document() != NULL); - if (!copy_from_document(*reader.site())) { + if (!copyFromDocument(*reader.site())) { Console console; console.printf("Can't copying an image portion from the current layer\n"); return; } } -void copy_merged(const ContextReader& reader) +void Clipboard::copyMerged(const ContextReader& reader) { ASSERT(reader.document() != NULL); - copy_from_document(*reader.site(), true); + copyFromDocument(*reader.site(), true); } -void copy_range(const ContextReader& reader, const DocRange& range) +void Clipboard::copyRange(const ContextReader& reader, const DocRange& range) { ASSERT(reader.document() != NULL); ContextWriter writer(reader); - clear_content(); - clipboard_range.setRange(writer.document(), range); + clearContent(); + m_data->range.setRange(writer.document(), range); // TODO Replace this with a signal, because here the timeline // depends on the clipboard and the clipboard on the timeline. App::instance()->timeline()->activateClipboardRange(); } -void copy_image(const Image* image, const Mask* mask, const Palette* pal) +void Clipboard::copyImage(const Image* image, const Mask* mask, const Palette* pal) { - set_clipboard_image( + setData( Image::createCopy(image), (mask ? new Mask(*mask): nullptr), (pal ? new Palette(*pal): nullptr), true, false); } -void copy_palette(const Palette* palette, const doc::PalettePicks& picks) +void Clipboard::copyPalette(const Palette* palette, const doc::PalettePicks& picks) { if (!picks.picks()) return; // Do nothing case - set_clipboard_image(nullptr, - nullptr, - new Palette(*palette), - true, false); - clipboard_picks = picks; + setData(nullptr, + nullptr, + new Palette(*palette), + true, false); + m_data->picks = picks; } -void paste(Context* ctx, const bool interactive) +void Clipboard::paste(Context* ctx, const bool interactive) { Site site = ctx->activeSite(); Doc* dstDoc = site.document(); @@ -374,34 +407,34 @@ void paste(Context* ctx, const bool interactive) if (!dstSpr) return; - switch (get_current_format()) { + switch (format()) { - case clipboard::ClipboardImage: { + case ClipboardFormat::Image: { // Get the image from the native clipboard. - if (!get_image(nullptr)) + if (!getImage(nullptr)) return; - ASSERT(clipboard_image); + ASSERT(m_data->image); Palette* dst_palette = dstSpr->palette(site.frame()); // Source image (clipboard or a converted copy to the destination 'imgtype') ImageRef src_image; - if (clipboard_image->pixelFormat() == dstSpr->pixelFormat() && + if (m_data->image->pixelFormat() == dstSpr->pixelFormat() && // Indexed images can be copied directly only if both images // have the same palette. - (clipboard_image->pixelFormat() != IMAGE_INDEXED || - clipboard_palette->countDiff(dst_palette, NULL, NULL) == 0)) { - src_image = clipboard_image; + (m_data->image->pixelFormat() != IMAGE_INDEXED || + m_data->palette->countDiff(dst_palette, NULL, NULL) == 0)) { + src_image = m_data->image; } else { RgbMap* dst_rgbmap = dstSpr->rgbMap(site.frame()); src_image.reset( render::convert_pixel_format( - clipboard_image.get(), NULL, dstSpr->pixelFormat(), + m_data->image.get(), NULL, dstSpr->pixelFormat(), render::Dithering(), - dst_rgbmap, clipboard_palette.get(), + dst_rgbmap, m_data->palette.get(), false, 0)); } @@ -414,7 +447,7 @@ void paste(Context* ctx, const bool interactive) // Change to MovingPixelsState current_editor->pasteImage(src_image.get(), - clipboard_mask.get()); + m_data->mask.get()); } else { // Non-interactive version (just copy the image to the cel) @@ -431,7 +464,7 @@ void paste(Context* ctx, const bool interactive) // Adjust bounds if (dstCel) { - if (clipboard_mask) { + if (m_data->mask) { if (dstLayer->isReference()) { dstCel->setBounds(dstSpr->bounds()); @@ -439,8 +472,8 @@ void paste(Context* ctx, const bool interactive) tx(new cmd::SetMask(dstDoc, &emptyMask)); } else { - dstCel->setBounds(clipboard_mask->bounds()); - tx(new cmd::SetMask(dstDoc, clipboard_mask.get())); + dstCel->setBounds(m_data->mask->bounds()); + tx(new cmd::SetMask(dstDoc, m_data->mask.get())); } } } @@ -450,9 +483,9 @@ void paste(Context* ctx, const bool interactive) break; } - case clipboard::ClipboardDocRange: { - DocRange srcRange = clipboard_range.range(); - Doc* srcDoc = clipboard_range.document(); + case ClipboardFormat::DocRange: { + DocRange srcRange = m_data->range.range(); + Doc* srcDoc = m_data->range.document(); Sprite* srcSpr = srcDoc->sprite(); switch (srcRange.type()) { @@ -643,53 +676,54 @@ void paste(Context* ctx, const bool interactive) } } -ImageRef get_image(Palette* palette) +ImageRef Clipboard::getImage(Palette* palette) { // Get the image from the native clipboard. if (use_native_clipboard()) { Image* native_image = nullptr; Mask* native_mask = nullptr; Palette* native_palette = nullptr; - get_native_clipboard_bitmap(&native_image, &native_mask, &native_palette); + getNativeBitmap(&native_image, + &native_mask, + &native_palette); if (native_image) - set_clipboard_image(native_image, native_mask, native_palette, - false, false); + setData(native_image, + native_mask, + native_palette, + false, false); } - if (clipboard_palette && palette) - clipboard_palette->copyColorsTo(palette); - return clipboard_image; + if (m_data->palette && palette) + m_data->palette->copyColorsTo(palette); + return m_data->image; } -bool get_image_size(gfx::Size& size) +bool Clipboard::getImageSize(gfx::Size& size) { - if (use_native_clipboard() && - get_native_clipboard_bitmap_size(&size)) + if (use_native_clipboard() && getNativeBitmapSize(&size)) return true; - if (clipboard_image) { - size.w = clipboard_image->width(); - size.h = clipboard_image->height(); + if (m_data->image) { + size.w = m_data->image->width(); + size.h = m_data->image->height(); return true; } return false; } -Palette* get_palette() +Palette* Clipboard::getPalette() { - if (clipboard::get_current_format() == ClipboardPaletteEntries) { - ASSERT(clipboard_palette); - return clipboard_palette.get(); + if (format() == ClipboardFormat::PaletteEntries) { + ASSERT(m_data->palette); + return m_data->palette.get(); } else return nullptr; } -const PalettePicks& get_palette_picks() +const PalettePicks& Clipboard::getPalettePicks() { - return clipboard_picks; + return m_data->picks; } -} // namespace clipboard - } // namespace app diff --git a/src/app/util/clipboard.h b/src/app/util/clipboard.h index f3289e0ef..cfe458012 100644 --- a/src/app/util/clipboard.h +++ b/src/app/util/clipboard.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2019 Igara Studio S.A. +// Copyright (C) 2019-2020 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -10,11 +10,14 @@ #pragma once #include "doc/cel_list.h" +#include "doc/image_ref.h" #include "gfx/point.h" #include "gfx/size.h" #include "ui/base.h" #include "ui/clipboard_delegate.h" +#include + namespace doc { class Image; class Mask; @@ -28,62 +31,82 @@ namespace app { class ContextWriter; class Doc; class DocRange; + class Site; class Tx; - namespace clipboard { - using namespace doc; + enum class ClipboardFormat { + None, + Image, + DocRange, + PaletteEntries, + Tilemap, + Tileset, + }; - enum ClipboardFormat { - ClipboardNone, - ClipboardImage, - ClipboardDocRange, - ClipboardPaletteEntries, - ClipboardTiles, - }; + class Clipboard : public ui::ClipboardDelegate { + public: + static Clipboard* instance(); - // TODO Horrible API: refactor it (maybe a merge with os::clipboard). + Clipboard(); + ~Clipboard(); - class ClipboardManager : public ui::ClipboardDelegate { - public: - static ClipboardManager* instance(); + ClipboardFormat format() const; + void getDocumentRangeInfo(Doc** document, DocRange* range); - ClipboardManager(); - ~ClipboardManager(); + void clearMaskFromCels(Tx& tx, + Doc* doc, + const doc::CelList& cels, + const bool deselectMask); - void setClipboardText(const std::string& text) override; - bool getClipboardText(std::string& text) override; - private: - std::string m_text; // Text used when the native clipboard is disabled - }; - - ClipboardFormat get_current_format(); - void get_document_range_info(Doc** document, DocRange* range); - - void clear_mask_from_cels(Tx& tx, - Doc* doc, - const doc::CelList& cels, - const bool deselectMask); - - void clear_content(); + void clearContent(); void cut(ContextWriter& context); void copy(const ContextReader& context); - void copy_merged(const ContextReader& context); - void copy_range(const ContextReader& context, const DocRange& range); - void copy_image(const Image* image, const Mask* mask, const Palette* palette); - void copy_palette(const Palette* palette, const PalettePicks& picks); + void copyMerged(const ContextReader& context); + void copyRange(const ContextReader& context, const DocRange& range); + void copyImage(const doc::Image* image, + const doc::Mask* mask, + const doc::Palette* palette); + void copyPalette(const doc::Palette* palette, + const doc::PalettePicks& picks); void paste(Context* ctx, const bool interactive); - ImageRef get_image(Palette* palette); + doc::ImageRef getImage(doc::Palette* palette); // Returns true and fills the specified "size"" with the image's // size in the clipboard, or return false in case that the clipboard // doesn't contain an image at all. - bool get_image_size(gfx::Size& size); + bool getImageSize(gfx::Size& size); - Palette* get_palette(); - const PalettePicks& get_palette_picks(); + doc::Palette* getPalette(); + const doc::PalettePicks& getPalettePicks(); + + // ui::ClipboardDelegate impl + void setClipboardText(const std::string& text) override; + bool getClipboardText(std::string& text) override; + + private: + void setData(doc::Image* image, + doc::Mask* mask, + doc::Palette* palette, + bool set_system_clipboard, + bool image_source_is_transparent); + bool copyFromDocument(const Site& site, bool merged = false); + + // Native clipboard + void registerNativeFormats(); + bool hasNativeBitmap() const; + bool setNativeBitmap(const doc::Image* image, + const doc::Mask* mask, + const doc::Palette* palette); + bool getNativeBitmap(doc::Image** image, + doc::Mask** mask, + doc::Palette** palette); + bool getNativeBitmapSize(gfx::Size* size); + + struct Data; + std::unique_ptr m_data; + }; - } // namespace clipboard } // namespace app #endif diff --git a/src/app/util/clipboard_native.cpp b/src/app/util/clipboard_native.cpp index 212421eaa..dc6ac8f64 100644 --- a/src/app/util/clipboard_native.cpp +++ b/src/app/util/clipboard_native.cpp @@ -1,4 +1,5 @@ // Aseprite +// Copyright (C) 2020 Igara Studio S.A. // Copyright (C) 2016-2018 David Capello // // This program is distributed under the terms of @@ -8,7 +9,7 @@ #include "config.h" #endif -#include "app/util/clipboard_native.h" +#include "app/util/clipboard.h" #include "app/i18n/strings.h" #include "base/serialization.h" @@ -28,7 +29,6 @@ #include namespace app { -namespace clipboard { using namespace base::serialization; using namespace base::serialization::little_endian; @@ -53,20 +53,20 @@ namespace { } -void register_native_clipboard_formats() +void Clipboard::registerNativeFormats() { clip::set_error_handler(custom_error_handler); custom_image_format = clip::register_format("org.aseprite.Image"); } -bool has_native_clipboard_bitmap() +bool Clipboard::hasNativeBitmap() const { return clip::has(clip::image_format()); } -bool set_native_clipboard_bitmap(const doc::Image* image, - const doc::Mask* mask, - const doc::Palette* palette) +bool Clipboard::setNativeBitmap(const doc::Image* image, + const doc::Mask* mask, + const doc::Palette* palette) { clip::lock l(native_display_handle()); if (!l.locked()) @@ -163,9 +163,9 @@ bool set_native_clipboard_bitmap(const doc::Image* image, return true; } -bool get_native_clipboard_bitmap(doc::Image** image, - doc::Mask** mask, - doc::Palette** palette) +bool Clipboard::getNativeBitmap(doc::Image** image, + doc::Mask** mask, + doc::Palette** palette) { *image = nullptr; *mask = nullptr; @@ -286,7 +286,7 @@ bool get_native_clipboard_bitmap(doc::Image** image, return true; } -bool get_native_clipboard_bitmap_size(gfx::Size* size) +bool Clipboard::getNativeBitmapSize(gfx::Size* size) { clip::image_spec spec; if (clip::get_image_spec(spec)) { @@ -298,5 +298,4 @@ bool get_native_clipboard_bitmap_size(gfx::Size* size) return false; } -} // namespace clipboard } // namespace app diff --git a/src/app/util/clipboard_native.h b/src/app/util/clipboard_native.h deleted file mode 100644 index 9d2a1f1d2..000000000 --- a/src/app/util/clipboard_native.h +++ /dev/null @@ -1,35 +0,0 @@ -// Aseprite -// Copyright (C) 2016 David Capello -// -// This program is distributed under the terms of -// the End-User License Agreement for Aseprite. - -#ifndef APP_UTIL_CLIPBOARD_NATIVE_H_INCLUDED -#define APP_UTIL_CLIPBOARD_NATIVE_H_INCLUDED -#pragma once - -#include "gfx/fwd.h" - -namespace doc { - class Image; - class Mask; - class Palette; -} - -namespace app { -namespace clipboard { - -void register_native_clipboard_formats(); -bool has_native_clipboard_bitmap(); -bool set_native_clipboard_bitmap(const doc::Image* image, - const doc::Mask* mask, - const doc::Palette* palette); -bool get_native_clipboard_bitmap(doc::Image** image, - doc::Mask** mask, - doc::Palette** palette); -bool get_native_clipboard_bitmap_size(gfx::Size* size); - -} // namespace clipboard -} // namespace app - -#endif