mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-30 04:20:23 +00:00
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:
parent
44f65ad305
commit
edebb57f66
@ -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());
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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())) {
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user