mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-03 05:22:23 +00:00
Add 'x' and 'y' as input parameters to app.command.Paste()
This commit is contained in:
parent
de1fc581f2
commit
e70bbbd369
@ -1,4 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
|
// Copyright (C) 2024 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -10,6 +11,7 @@
|
|||||||
|
|
||||||
#include "app/app.h"
|
#include "app/app.h"
|
||||||
#include "app/commands/command.h"
|
#include "app/commands/command.h"
|
||||||
|
#include "app/commands/params.h"
|
||||||
#include "app/ui/input_chain.h"
|
#include "app/ui/input_chain.h"
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
@ -19,8 +21,11 @@ public:
|
|||||||
PasteCommand();
|
PasteCommand();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void onLoadParams(const Params& params) override;
|
||||||
bool onEnabled(Context* ctx) override;
|
bool onEnabled(Context* ctx) override;
|
||||||
void onExecute(Context* ctx) override;
|
void onExecute(Context* ctx) override;
|
||||||
|
private:
|
||||||
|
std::shared_ptr<gfx::Point> m_position;
|
||||||
};
|
};
|
||||||
|
|
||||||
PasteCommand::PasteCommand()
|
PasteCommand::PasteCommand()
|
||||||
@ -28,6 +33,16 @@ PasteCommand::PasteCommand()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PasteCommand::onLoadParams(const Params& params)
|
||||||
|
{
|
||||||
|
m_position.reset();
|
||||||
|
if (params.has_param("x") || params.has_param("y")) {
|
||||||
|
m_position.reset(new gfx::Point);
|
||||||
|
m_position->x = params.get_as<int>("x");
|
||||||
|
m_position->y = params.get_as<int>("y");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool PasteCommand::onEnabled(Context* ctx)
|
bool PasteCommand::onEnabled(Context* ctx)
|
||||||
{
|
{
|
||||||
return App::instance()->inputChain().canPaste(ctx);
|
return App::instance()->inputChain().canPaste(ctx);
|
||||||
@ -35,7 +50,7 @@ bool PasteCommand::onEnabled(Context* ctx)
|
|||||||
|
|
||||||
void PasteCommand::onExecute(Context* ctx)
|
void PasteCommand::onExecute(Context* ctx)
|
||||||
{
|
{
|
||||||
App::instance()->inputChain().paste(ctx);
|
App::instance()->inputChain().paste(ctx, m_position.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
Command* CommandFactory::createPasteCommand()
|
Command* CommandFactory::createPasteCommand()
|
||||||
|
@ -84,13 +84,14 @@ bool ScriptInputChain::onCopy(Context* ctx)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScriptInputChain::onPaste(Context* ctx)
|
bool ScriptInputChain::onPaste(Context* ctx,
|
||||||
|
const gfx::Point* position)
|
||||||
{
|
{
|
||||||
Clipboard* clipboard = ctx->clipboard();
|
Clipboard* clipboard = ctx->clipboard();
|
||||||
if (!clipboard)
|
if (!clipboard)
|
||||||
return false;
|
return false;
|
||||||
if (clipboard->format() == ClipboardFormat::Image) {
|
if (clipboard->format() == ClipboardFormat::Image) {
|
||||||
clipboard->paste(ctx, false);
|
clipboard->paste(ctx, false, position);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -27,7 +27,8 @@ namespace app {
|
|||||||
bool onCanClear(Context* ctx) override;
|
bool onCanClear(Context* ctx) override;
|
||||||
bool onCut(Context* ctx) override;
|
bool onCut(Context* ctx) override;
|
||||||
bool onCopy(Context* ctx) override;
|
bool onCopy(Context* ctx) override;
|
||||||
bool onPaste(Context* ctx) override;
|
bool onPaste(Context* ctx,
|
||||||
|
const gfx::Point* position) override;
|
||||||
bool onClear(Context* ctx) override;
|
bool onClear(Context* ctx) override;
|
||||||
void onCancel(Context* ctx) override;
|
void onCancel(Context* ctx) override;
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -1692,7 +1692,8 @@ bool ColorBar::onCopy(Context* ctx)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ColorBar::onPaste(Context* ctx)
|
bool ColorBar::onPaste(Context* ctx,
|
||||||
|
const gfx::Point* position)
|
||||||
{
|
{
|
||||||
if (m_tilemapMode == TilemapMode::Tiles) {
|
if (m_tilemapMode == TilemapMode::Tiles) {
|
||||||
showRemapTiles();
|
showRemapTiles();
|
||||||
|
@ -119,7 +119,8 @@ namespace app {
|
|||||||
bool onCanClear(Context* ctx) override;
|
bool onCanClear(Context* ctx) override;
|
||||||
bool onCut(Context* ctx) override;
|
bool onCut(Context* ctx) override;
|
||||||
bool onCopy(Context* ctx) override;
|
bool onCopy(Context* ctx) override;
|
||||||
bool onPaste(Context* ctx) override;
|
bool onPaste(Context* ctx,
|
||||||
|
const gfx::Point* position) override;
|
||||||
bool onClear(Context* ctx) override;
|
bool onClear(Context* ctx) override;
|
||||||
void onCancel(Context* ctx) override;
|
void onCancel(Context* ctx) override;
|
||||||
|
|
||||||
|
@ -589,12 +589,13 @@ bool DocView::onCopy(Context* ctx)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DocView::onPaste(Context* ctx)
|
bool DocView::onPaste(Context* ctx,
|
||||||
|
const gfx::Point* position)
|
||||||
{
|
{
|
||||||
auto clipboard = ctx->clipboard();
|
auto clipboard = ctx->clipboard();
|
||||||
if (clipboard->format() == ClipboardFormat::Image ||
|
if (clipboard->format() == ClipboardFormat::Image ||
|
||||||
clipboard->format() == ClipboardFormat::Tilemap) {
|
clipboard->format() == ClipboardFormat::Tilemap) {
|
||||||
clipboard->paste(ctx, true);
|
clipboard->paste(ctx, true, position);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -102,7 +102,8 @@ namespace app {
|
|||||||
bool onCanClear(Context* ctx) override;
|
bool onCanClear(Context* ctx) override;
|
||||||
bool onCut(Context* ctx) override;
|
bool onCut(Context* ctx) override;
|
||||||
bool onCopy(Context* ctx) override;
|
bool onCopy(Context* ctx) override;
|
||||||
bool onPaste(Context* ctx) override;
|
bool onPaste(Context* ctx,
|
||||||
|
const gfx::Point* position) override;
|
||||||
bool onClear(Context* ctx) override;
|
bool onClear(Context* ctx) override;
|
||||||
void onCancel(Context* ctx) override;
|
void onCancel(Context* ctx) override;
|
||||||
|
|
||||||
|
@ -2654,7 +2654,9 @@ void Editor::setZoomAndCenterInMouse(const Zoom& zoom,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::pasteImage(const Image* image, const Mask* mask)
|
void Editor::pasteImage(const Image* image,
|
||||||
|
const Mask* mask,
|
||||||
|
const gfx::Point* position)
|
||||||
{
|
{
|
||||||
ASSERT(image);
|
ASSERT(image);
|
||||||
|
|
||||||
@ -2686,11 +2688,14 @@ void Editor::pasteImage(const Image* image, const Mask* mask)
|
|||||||
Sprite* sprite = this->sprite();
|
Sprite* sprite = this->sprite();
|
||||||
|
|
||||||
// Check bounds where the image will be pasted.
|
// Check bounds where the image will be pasted.
|
||||||
int x = mask->bounds().x;
|
int x = (position ? position->x : mask->bounds().x);
|
||||||
int y = mask->bounds().y;
|
int y = (position ? position->y : mask->bounds().y);
|
||||||
{
|
{
|
||||||
const Rect visibleBounds = getViewportBounds();
|
const Rect visibleBounds = getViewportBounds();
|
||||||
const Point maskCenter = mask->bounds().center();
|
const Point maskCenter = mask->bounds().center() +
|
||||||
|
(position ? gfx::Point(position->x - mask->bounds().x,
|
||||||
|
position->y - mask->bounds().y)
|
||||||
|
: gfx::Point());
|
||||||
|
|
||||||
// If the pasted image original location center point isn't
|
// If the pasted image original location center point isn't
|
||||||
// visible, we center the image in the editor's visible bounds.
|
// visible, we center the image in the editor's visible bounds.
|
||||||
@ -2743,7 +2748,8 @@ void Editor::pasteImage(const Image* image, const Mask* mask)
|
|||||||
m_brushPreview.hide();
|
m_brushPreview.hide();
|
||||||
|
|
||||||
Mask mask2(*mask);
|
Mask mask2(*mask);
|
||||||
mask2.setOrigin(x, y);
|
position ? mask2.setOrigin(position->x, position->y)
|
||||||
|
: mask2.setOrigin(x, y);
|
||||||
|
|
||||||
PixelsMovementPtr pixelsMovement(
|
PixelsMovementPtr pixelsMovement(
|
||||||
new PixelsMovement(UIContext::instance(), site,
|
new PixelsMovement(UIContext::instance(), site,
|
||||||
|
@ -252,7 +252,9 @@ namespace app {
|
|||||||
void setZoomAndCenterInMouse(const render::Zoom& zoom,
|
void setZoomAndCenterInMouse(const render::Zoom& zoom,
|
||||||
const gfx::Point& mousePos, ZoomBehavior zoomBehavior);
|
const gfx::Point& mousePos, ZoomBehavior zoomBehavior);
|
||||||
|
|
||||||
void pasteImage(const Image* image, const Mask* mask = nullptr);
|
void pasteImage(const Image* image,
|
||||||
|
const Mask* mask = nullptr,
|
||||||
|
const gfx::Point* position = nullptr);
|
||||||
|
|
||||||
void startSelectionTransformation(const gfx::Point& move, double angle);
|
void startSelectionTransformation(const gfx::Point& move, double angle);
|
||||||
void startFlipTransformation(doc::algorithm::FlipType flipType);
|
void startFlipTransformation(doc::algorithm::FlipType flipType);
|
||||||
|
@ -230,7 +230,8 @@ bool HomeView::onCopy(Context* ctx)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HomeView::onPaste(Context* ctx)
|
bool HomeView::onPaste(Context* ctx,
|
||||||
|
const gfx::Point* position)
|
||||||
{
|
{
|
||||||
auto clipboard = ctx->clipboard();
|
auto clipboard = ctx->clipboard();
|
||||||
if (clipboard->format() == ClipboardFormat::Image) {
|
if (clipboard->format() == ClipboardFormat::Image) {
|
||||||
|
@ -74,7 +74,8 @@ namespace app {
|
|||||||
bool onCanClear(Context* ctx) override;
|
bool onCanClear(Context* ctx) override;
|
||||||
bool onCut(Context* ctx) override;
|
bool onCut(Context* ctx) override;
|
||||||
bool onCopy(Context* ctx) override;
|
bool onCopy(Context* ctx) override;
|
||||||
bool onPaste(Context* ctx) override;
|
bool onPaste(Context* ctx,
|
||||||
|
const gfx::Point* position) override;
|
||||||
bool onClear(Context* ctx) override;
|
bool onClear(Context* ctx) override;
|
||||||
void onCancel(Context* ctx) override;
|
void onCancel(Context* ctx) override;
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
|
// Copyright (C) 2024 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -87,10 +88,11 @@ void InputChain::copy(Context* ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputChain::paste(Context* ctx)
|
void InputChain::paste(Context* ctx,
|
||||||
|
const gfx::Point* position)
|
||||||
{
|
{
|
||||||
for (auto e : m_elements) {
|
for (auto e : m_elements) {
|
||||||
if (e->onCanPaste(ctx) && e->onPaste(ctx))
|
if (e->onCanPaste(ctx) && e->onPaste(ctx, position))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
|
// Copyright (C) 2024 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -8,6 +9,8 @@
|
|||||||
#define APP_INPUT_CHAIN_H_INCLUDED
|
#define APP_INPUT_CHAIN_H_INCLUDED
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "gfx/point.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
@ -35,7 +38,8 @@ namespace app {
|
|||||||
|
|
||||||
void cut(Context* ctx);
|
void cut(Context* ctx);
|
||||||
void copy(Context* ctx);
|
void copy(Context* ctx);
|
||||||
void paste(Context* ctx);
|
void paste(Context* ctx,
|
||||||
|
const gfx::Point* position);
|
||||||
void clear(Context* ctx);
|
void clear(Context* ctx);
|
||||||
void cancel(Context* ctx);
|
void cancel(Context* ctx);
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
#define APP_INPUT_CHAIN_ELEMENT_H_INCLUDED
|
#define APP_INPUT_CHAIN_ELEMENT_H_INCLUDED
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "gfx/point.h"
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
class Message;
|
class Message;
|
||||||
}
|
}
|
||||||
@ -34,7 +36,8 @@ namespace app {
|
|||||||
// which catch any exception that is thrown.
|
// which catch any exception that is thrown.
|
||||||
virtual bool onCut(Context* ctx) = 0;
|
virtual bool onCut(Context* ctx) = 0;
|
||||||
virtual bool onCopy(Context* ctx) = 0;
|
virtual bool onCopy(Context* ctx) = 0;
|
||||||
virtual bool onPaste(Context* ctx) = 0;
|
virtual bool onPaste(Context* ctx,
|
||||||
|
const gfx::Point* position) = 0;
|
||||||
virtual bool onClear(Context* ctx) = 0;
|
virtual bool onClear(Context* ctx) = 0;
|
||||||
virtual void onCancel(Context* ctx) = 0;
|
virtual void onCancel(Context* ctx) = 0;
|
||||||
};
|
};
|
||||||
|
@ -4398,7 +4398,8 @@ bool Timeline::onCopy(Context* ctx)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Timeline::onPaste(Context* ctx)
|
bool Timeline::onPaste(Context* ctx,
|
||||||
|
const gfx::Point* position)
|
||||||
{
|
{
|
||||||
auto clipboard = ctx->clipboard();
|
auto clipboard = ctx->clipboard();
|
||||||
if (clipboard->format() == ClipboardFormat::DocRange) {
|
if (clipboard->format() == ClipboardFormat::DocRange) {
|
||||||
|
@ -190,7 +190,8 @@ namespace app {
|
|||||||
bool onCanClear(Context* ctx) override;
|
bool onCanClear(Context* ctx) override;
|
||||||
bool onCut(Context* ctx) override;
|
bool onCut(Context* ctx) override;
|
||||||
bool onCopy(Context* ctx) override;
|
bool onCopy(Context* ctx) override;
|
||||||
bool onPaste(Context* ctx) override;
|
bool onPaste(Context* ctx,
|
||||||
|
const gfx::Point* position) override;
|
||||||
bool onClear(Context* ctx) override;
|
bool onClear(Context* ctx) override;
|
||||||
void onCancel(Context* ctx) override;
|
void onCancel(Context* ctx) override;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -381,12 +381,13 @@ bool Workspace::onCopy(Context* ctx)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Workspace::onPaste(Context* ctx)
|
bool Workspace::onPaste(Context* ctx,
|
||||||
|
const gfx::Point* position)
|
||||||
{
|
{
|
||||||
WorkspaceView* view = activeView();
|
WorkspaceView* view = activeView();
|
||||||
InputChainElement* activeElement = (view ? view->onGetInputChainElement(): nullptr);
|
InputChainElement* activeElement = (view ? view->onGetInputChainElement(): nullptr);
|
||||||
if (activeElement)
|
if (activeElement)
|
||||||
return activeElement->onPaste(ctx);
|
return activeElement->onPaste(ctx, position);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2022 Igara Studio S.A.
|
// Copyright (C) 2022-2024 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -71,7 +71,8 @@ namespace app {
|
|||||||
bool onCanClear(Context* ctx) override;
|
bool onCanClear(Context* ctx) override;
|
||||||
bool onCut(Context* ctx) override;
|
bool onCut(Context* ctx) override;
|
||||||
bool onCopy(Context* ctx) override;
|
bool onCopy(Context* ctx) override;
|
||||||
bool onPaste(Context* ctx) override;
|
bool onPaste(Context* ctx,
|
||||||
|
const gfx::Point* position) override;
|
||||||
bool onClear(Context* ctx) override;
|
bool onClear(Context* ctx) override;
|
||||||
void onCancel(Context* ctx) override;
|
void onCancel(Context* ctx) override;
|
||||||
|
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
#include "app/util/new_image_from_mask.h"
|
#include "app/util/new_image_from_mask.h"
|
||||||
#include "app/util/range_utils.h"
|
#include "app/util/range_utils.h"
|
||||||
#include "clip/clip.h"
|
#include "clip/clip.h"
|
||||||
|
#include "doc/algorithm/shrink_bounds.h"
|
||||||
|
#include "doc/blend_image.h"
|
||||||
#include "doc/doc.h"
|
#include "doc/doc.h"
|
||||||
#include "render/dithering.h"
|
#include "render/dithering.h"
|
||||||
#include "render/ordered_dither.h"
|
#include "render/ordered_dither.h"
|
||||||
@ -425,7 +427,7 @@ void Clipboard::copyImage(const Image* image,
|
|||||||
(mask ? new Mask(*mask): nullptr),
|
(mask ? new Mask(*mask): nullptr),
|
||||||
(pal ? new Palette(*pal): nullptr),
|
(pal ? new Palette(*pal): nullptr),
|
||||||
nullptr,
|
nullptr,
|
||||||
true, false);
|
App::instance()->isGui(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clipboard::copyTilemap(const Image* image,
|
void Clipboard::copyTilemap(const Image* image,
|
||||||
@ -463,7 +465,8 @@ void Clipboard::copyPalette(const Palette* palette,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Clipboard::paste(Context* ctx,
|
void Clipboard::paste(Context* ctx,
|
||||||
const bool interactive)
|
const bool interactive,
|
||||||
|
const gfx::Point* position)
|
||||||
{
|
{
|
||||||
const Site site = ctx->activeSite();
|
const Site site = ctx->activeSite();
|
||||||
Doc* dstDoc = site.document();
|
Doc* dstDoc = site.document();
|
||||||
@ -518,38 +521,94 @@ void Clipboard::paste(Context* ctx,
|
|||||||
|
|
||||||
// Change to MovingPixelsState
|
// Change to MovingPixelsState
|
||||||
editor->pasteImage(src_image.get(),
|
editor->pasteImage(src_image.get(),
|
||||||
m_data->mask.get());
|
m_data->mask.get(),
|
||||||
|
position);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Non-interactive version (just copy the image to the cel)
|
// CLI version:
|
||||||
|
// Paste the image according the position param.
|
||||||
|
// If there are no parameters, we assume the origin
|
||||||
|
// of the pasted image mask is the position.
|
||||||
|
// If there is no mask, x=0, y=0 is taken as position.
|
||||||
|
// TODO Support 'paste' command between images
|
||||||
|
// that do not match their pixel format.
|
||||||
Layer* dstLayer = site.layer();
|
Layer* dstLayer = site.layer();
|
||||||
ASSERT(dstLayer);
|
ASSERT(dstLayer);
|
||||||
if (!dstLayer || !dstLayer->isImage())
|
if (!dstLayer ||
|
||||||
|
!dstLayer->isImage() ||
|
||||||
|
(src_image->pixelFormat() != dstSpr->pixelFormat()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ImageRef result;
|
||||||
|
// resultBounds starts with the same bounds as source image,
|
||||||
|
// but it'll be merged with the active cel bounds (if any).
|
||||||
|
gfx::Rect resultBounds =
|
||||||
|
gfx::Rect(position ? *position
|
||||||
|
: (m_data->mask ? m_data->mask->origin()
|
||||||
|
: gfx::Point()),
|
||||||
|
src_image->size());
|
||||||
|
const bool isAnImageOnDstCel =
|
||||||
|
ctx->activeSite().cel() && ctx->activeSite().cel()->image();
|
||||||
|
ASSERT(!ctx->activeSite().cel() || ctx->activeSite().cel()->image());
|
||||||
|
if (isAnImageOnDstCel) {
|
||||||
|
Cel* cel = ctx->activeSite().cel();
|
||||||
|
resultBounds = cel->bounds().createUnion(resultBounds);
|
||||||
|
// Create a new image (result) as a blend of the active cel image +
|
||||||
|
// the source image (clipboard image).
|
||||||
|
result.reset(Image::create(dstSpr->pixelFormat(), resultBounds.w, resultBounds.h));
|
||||||
|
doc::blend_image(result.get(), cel->image(),
|
||||||
|
gfx::Clip(cel->bounds().origin() - resultBounds.origin(),
|
||||||
|
cel->image()->bounds()),
|
||||||
|
site.palette(),
|
||||||
|
255, BlendMode::NORMAL);
|
||||||
|
doc::blend_image(result.get(), src_image.get(),
|
||||||
|
gfx::Clip(*position - resultBounds.origin(),
|
||||||
|
src_image->bounds()),
|
||||||
|
site.palette(),
|
||||||
|
255, BlendMode::NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
ContextWriter writer(ctx);
|
ContextWriter writer(ctx);
|
||||||
Tx tx(writer, "Paste Image");
|
Tx tx(writer, "Paste Image");
|
||||||
DocApi api = dstDoc->getApi(tx);
|
DocApi api = dstDoc->getApi(tx);
|
||||||
Cel* dstCel = api.addCel(
|
Cel* dstCel;
|
||||||
static_cast<LayerImage*>(dstLayer), site.frame(),
|
if (isAnImageOnDstCel)
|
||||||
ImageRef(Image::createCopy(src_image.get())));
|
api.clearCel(ctx->activeSite().cel());
|
||||||
|
else
|
||||||
|
result.reset(Image::createCopy(src_image.get()));
|
||||||
|
|
||||||
// Adjust bounds
|
// Calculate the active image + pasted image bounds
|
||||||
|
const gfx::Rect startBounds(gfx::Point(), result->size());
|
||||||
|
const gfx::Point startOrigin(resultBounds.origin());
|
||||||
|
doc::algorithm::shrink_bounds(result.get(),
|
||||||
|
result->maskColor(),
|
||||||
|
dstLayer,
|
||||||
|
startBounds,
|
||||||
|
resultBounds);
|
||||||
|
// Cropped image according the shrink bounds
|
||||||
|
result.reset(crop_image(result.get(),
|
||||||
|
resultBounds,
|
||||||
|
result->maskColor()));
|
||||||
|
resultBounds.x = startOrigin.x + resultBounds.x;
|
||||||
|
resultBounds.y = startOrigin.y + resultBounds.y;
|
||||||
|
|
||||||
|
// Set image on the new Cel
|
||||||
|
dstCel = api.addCel(static_cast<LayerImage*>(dstLayer),
|
||||||
|
site.frame(),
|
||||||
|
result);
|
||||||
|
// Set cel bounds
|
||||||
if (dstCel) {
|
if (dstCel) {
|
||||||
if (m_data->mask) {
|
const Mask emptyMask;
|
||||||
if (dstLayer->isReference()) {
|
if (dstLayer->isReference()) {
|
||||||
dstCel->setBounds(dstSpr->bounds());
|
dstCel->setBounds(dstSpr->bounds());
|
||||||
|
tx(new cmd::SetMask(dstDoc, &emptyMask));
|
||||||
Mask emptyMask;
|
}
|
||||||
tx(new cmd::SetMask(dstDoc, &emptyMask));
|
else {
|
||||||
}
|
dstCel->setBounds(resultBounds);
|
||||||
else {
|
tx(new cmd::SetMask(dstDoc, m_data->mask ? m_data->mask.get()
|
||||||
dstCel->setBounds(m_data->mask->bounds());
|
: &emptyMask));
|
||||||
tx(new cmd::SetMask(dstDoc, m_data->mask.get()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tx.commit();
|
tx.commit();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -562,7 +621,8 @@ void Clipboard::paste(Context* ctx,
|
|||||||
|
|
||||||
// Change to MovingTilemapState
|
// Change to MovingTilemapState
|
||||||
editor->pasteImage(m_data->tilemap.get(),
|
editor->pasteImage(m_data->tilemap.get(),
|
||||||
m_data->mask.get());
|
m_data->mask.get(),
|
||||||
|
position);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO non-interactive version (for scripts)
|
// TODO non-interactive version (for scripts)
|
||||||
|
@ -75,7 +75,8 @@ namespace app {
|
|||||||
void copyPalette(const doc::Palette* palette,
|
void copyPalette(const doc::Palette* palette,
|
||||||
const doc::PalettePicks& picks);
|
const doc::PalettePicks& picks);
|
||||||
void paste(Context* ctx,
|
void paste(Context* ctx,
|
||||||
const bool interactive);
|
const bool interactive,
|
||||||
|
const gfx::Point* position = nullptr);
|
||||||
|
|
||||||
doc::ImageRef getImage(doc::Palette* palette);
|
doc::ImageRef getImage(doc::Palette* palette);
|
||||||
|
|
||||||
|
@ -28,19 +28,10 @@ do
|
|||||||
{ 2, 2,
|
{ 2, 2,
|
||||||
2, 2 })
|
2, 2 })
|
||||||
|
|
||||||
-- TO DO: Fix this difference between running this script with
|
|
||||||
-- 'UI Available' versus 'UI Not Available'
|
|
||||||
app.layer = sprite.layers[3]
|
app.layer = sprite.layers[3]
|
||||||
if (app.isUIAvailable) then
|
assert(app.cel.position == Point(1, 1))
|
||||||
assert(app.cel.position == Point(1, 1))
|
expect_img(app.activeImage,
|
||||||
expect_img(app.activeImage,
|
{ 1, 1 })
|
||||||
{ 1, 1 })
|
|
||||||
else
|
|
||||||
assert(app.cel.position == Point(0, 1))
|
|
||||||
expect_img(app.activeImage,
|
|
||||||
{ 0, 1, 1, 0, 0 })
|
|
||||||
end
|
|
||||||
|
|
||||||
app.command.FlattenLayers()
|
app.command.FlattenLayers()
|
||||||
assert(app.cel.position == Point(1, 1))
|
assert(app.cel.position == Point(1, 1))
|
||||||
expect_img(app.activeImage,
|
expect_img(app.activeImage,
|
||||||
@ -53,6 +44,18 @@ do
|
|||||||
app.undo() -- New Layer
|
app.undo() -- New Layer
|
||||||
app.undo() -- Cut
|
app.undo() -- Cut
|
||||||
|
|
||||||
|
app.layer = sprite.layers[1]
|
||||||
|
assert(app.cel.position == Point(1, 1))
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 1, 1,
|
||||||
|
1, 1 })
|
||||||
|
app.layer = sprite.layers[2]
|
||||||
|
assert(app.cel.position == Point(2, 2))
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 2, 2,
|
||||||
|
2, 2 })
|
||||||
|
assert(#sprite.layers == 2)
|
||||||
|
|
||||||
-- Another test
|
-- Another test
|
||||||
app.layer = sprite.layers[1]
|
app.layer = sprite.layers[1]
|
||||||
app.useTool {
|
app.useTool {
|
||||||
@ -62,30 +65,21 @@ do
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.command.Cut()
|
app.command.Cut()
|
||||||
|
assert(app.cel.position == Point(1, 1))
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 1, 1,
|
||||||
|
1, 0 })
|
||||||
sprite:newLayer()
|
sprite:newLayer()
|
||||||
app.command.Paste()
|
app.command.Paste()
|
||||||
|
|
||||||
-- TO DO: Fix this difference between running this script with
|
|
||||||
-- 'UI Available' versus 'UI Not Available'
|
|
||||||
app.layer = sprite.layers[3]
|
app.layer = sprite.layers[3]
|
||||||
if (app.isUIAvailable) then
|
assert(app.cel.position == Point(2, 2))
|
||||||
assert(app.cel.position == Point(2, 2))
|
expect_img(app.activeImage,
|
||||||
expect_img(app.activeImage,
|
{ 1 })
|
||||||
{ 1 })
|
|
||||||
else
|
|
||||||
assert(app.cel.position == Point(2, 2))
|
|
||||||
expect_img(app.activeImage,
|
|
||||||
{ 1, 0, 0 })
|
|
||||||
end
|
|
||||||
|
|
||||||
app.undo() -- Paste
|
app.undo() -- Paste
|
||||||
app.undo() -- New Layer
|
app.undo() -- New Layer
|
||||||
app.undo() -- Cut
|
app.undo() -- Cut
|
||||||
app.undo() -- MoveMask
|
|
||||||
-- TO DO: at the moment useTool requires double undo to undo
|
|
||||||
-- the selection action (Just one undo should be enough).
|
|
||||||
app.undo() -- useTool
|
|
||||||
app.undo() -- useTool
|
|
||||||
|
|
||||||
-- Test app.command.Copy
|
-- Test app.command.Copy
|
||||||
app.layer = sprite.layers[1]
|
app.layer = sprite.layers[1]
|
||||||
@ -108,19 +102,10 @@ do
|
|||||||
expect_img(app.activeImage,
|
expect_img(app.activeImage,
|
||||||
{ 2, 2,
|
{ 2, 2,
|
||||||
2, 2 })
|
2, 2 })
|
||||||
|
|
||||||
-- TO DO: Fix this difference between running this script with
|
|
||||||
-- 'UI Available' versus 'UI Not Available'
|
|
||||||
app.layer = sprite.layers[3]
|
app.layer = sprite.layers[3]
|
||||||
if (app.isUIAvailable) then
|
assert(app.cel.position == Point(1, 1))
|
||||||
assert(app.cel.position == Point(1, 1))
|
expect_img(app.activeImage,
|
||||||
expect_img(app.activeImage,
|
{ 1, 1 })
|
||||||
{ 1, 1 })
|
|
||||||
else
|
|
||||||
assert(app.cel.position == Point(0, 1))
|
|
||||||
expect_img(app.activeImage,
|
|
||||||
{ 0, 1, 1, 0, 0 })
|
|
||||||
end
|
|
||||||
|
|
||||||
app.command.FlattenLayers()
|
app.command.FlattenLayers()
|
||||||
assert(app.cel.position == Point(1, 1))
|
assert(app.cel.position == Point(1, 1))
|
||||||
@ -130,6 +115,17 @@ do
|
|||||||
0, 2, 2 })
|
0, 2, 2 })
|
||||||
|
|
||||||
-- Test app.command.Clear()
|
-- Test app.command.Clear()
|
||||||
|
app.useTool {
|
||||||
|
tool = "rectangular_marquee",
|
||||||
|
points = {Point(2,2), Point(4,2)},
|
||||||
|
selection = SelectionMode.REPLACE
|
||||||
|
}
|
||||||
|
app.command.Clear()
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 1, 1, 0,
|
||||||
|
1, 0, 0,
|
||||||
|
0, 2, 2 })
|
||||||
|
|
||||||
app.useTool {
|
app.useTool {
|
||||||
tool = "rectangular_marquee",
|
tool = "rectangular_marquee",
|
||||||
points = {Point(0,1), Point(4,2)},
|
points = {Point(0,1), Point(4,2)},
|
||||||
@ -141,6 +137,8 @@ do
|
|||||||
{ 2, 2 })
|
{ 2, 2 })
|
||||||
|
|
||||||
app.undo()
|
app.undo()
|
||||||
|
app.undo()
|
||||||
|
app.undo()
|
||||||
|
|
||||||
assert(app.cel.position == Point(1, 1))
|
assert(app.cel.position == Point(1, 1))
|
||||||
expect_img(app.activeImage,
|
expect_img(app.activeImage,
|
||||||
@ -151,7 +149,7 @@ do
|
|||||||
-- Test app.command.Cancel()
|
-- Test app.command.Cancel()
|
||||||
app.useTool {
|
app.useTool {
|
||||||
tool = "rectangular_marquee",
|
tool = "rectangular_marquee",
|
||||||
points = {Point(0,1), Point(4,2)},
|
points = {Point(2,2), Point(4,2)},
|
||||||
selection = SelectionMode.REPLACE
|
selection = SelectionMode.REPLACE
|
||||||
}
|
}
|
||||||
app.command.Cancel()
|
app.command.Cancel()
|
||||||
@ -161,4 +159,20 @@ do
|
|||||||
{ 1, 1, 0,
|
{ 1, 1, 0,
|
||||||
1, 2, 2,
|
1, 2, 2,
|
||||||
0, 2, 2 })
|
0, 2, 2 })
|
||||||
|
|
||||||
|
app.useTool {
|
||||||
|
tool = "rectangular_marquee",
|
||||||
|
points = {Point(2,0), Point(4,1)},
|
||||||
|
selection = SelectionMode.REPLACE
|
||||||
|
}
|
||||||
|
app.command.Copy()
|
||||||
|
sprite:newLayer()
|
||||||
|
app.command.Paste { x=3, y=3 }
|
||||||
|
app.command.FlattenLayers()
|
||||||
|
assert(app.cel.position == Point(1, 1))
|
||||||
|
expect_img(app.activeImage,
|
||||||
|
{ 1, 1, 0,
|
||||||
|
1, 2, 2,
|
||||||
|
0, 2, 2,
|
||||||
|
0, 0, 1, })
|
||||||
end
|
end
|
Loading…
Reference in New Issue
Block a user