Refactor clipboard code

* Moved all clipboard:: functions inside app::Clipboard class
* Convert app:📋:ClipboardFormat enum to
  app::ClipboardFormat enum class
* Added app::Context::clipboard()
This commit is contained in:
David Capello 2020-09-25 11:13:52 -03:00
parent 44f65ad305
commit edebb57f66
15 changed files with 295 additions and 254 deletions

View File

@ -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());

View File

@ -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()

View File

@ -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;
}

View File

@ -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())) {

View File

@ -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);

View File

@ -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; }

View File

@ -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)

View File

@ -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<const Doc*>(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);

View File

@ -625,9 +625,10 @@ void MovingPixelsState::onBeforeCommandExecution(CommandExecutionEvent& ev)
std::unique_ptr<Mask> 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.

View File

@ -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) {

View File

@ -608,7 +608,7 @@ bool Timeline::onProcessMessage(Message* msg)
if (static_cast<TimerMessage*>(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

View File

@ -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<Palette> clipboard_palette;
static std::shared_ptr<Tileset> clipboard_tiles;
static PalettePicks clipboard_picks;
static ImageRef clipboard_image;
static std::shared_ptr<Mask> clipboard_mask;
static ClipboardRange clipboard_range;
// The palette of the image (or tileset) if it's indexed
std::shared_ptr<Palette> 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> tileset;
// Selected entries copied from the palette or the tileset
PalettePicks picks;
// Original selection used to copy the image
std::shared_ptr<Mask> 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<const Doc*>(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

View File

@ -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 <memory>
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<Data> m_data;
};
} // namespace clipboard
} // namespace app
#endif

View File

@ -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 <vector>
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

View File

@ -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