mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-06 03:39:51 +00:00
This commit is contained in:
parent
056eb28670
commit
ff6538a68e
14
data/gui.xml
14
data/gui.xml
@ -39,6 +39,9 @@
|
||||
<key command="CopyMerged" shortcut="Ctrl+Shift+C" mac="Cmd+Shift+C" />
|
||||
<key command="Paste" shortcut="Ctrl+V" mac="Cmd+V" />
|
||||
<key command="Paste" shortcut="Shift+Ins" />
|
||||
<key command="NewLayer" shortcut="Ctrl+Shift+V" mac="Cmd+Shift+V">
|
||||
<param name="fromClipboard" value="true" />
|
||||
</key>
|
||||
<key command="Clear" shortcut="Del" />
|
||||
<key command="Clear" shortcut="Backspace" />
|
||||
<key command="Fill" shortcut="F" />
|
||||
@ -623,6 +626,15 @@
|
||||
<item command="Copy" text="@.edit_copy" />
|
||||
<item command="CopyMerged" text="@.edit_copy_merged" />
|
||||
<item command="Paste" text="@.edit_paste" />
|
||||
<menu text="@.edit_paste_special">
|
||||
<item command="NewLayer" text="@.edit_paste_special_new_layer">
|
||||
<param name="fromClipboard" value="true" />
|
||||
</item>
|
||||
<item command="NewLayer" text="@.edit_paste_special_new_ref_layer">
|
||||
<param name="reference" value="true" />
|
||||
<param name="fromClipboard" value="true" />
|
||||
</item>
|
||||
</menu>
|
||||
<item command="Clear" text="@.edit_clear" />
|
||||
<separator />
|
||||
<item command="Fill" text="@.edit_fill" />
|
||||
@ -772,7 +784,7 @@
|
||||
<separator />
|
||||
<item command="NewLayer" text="@.layer_add_reference_layer">
|
||||
<param name="reference" value="true" />
|
||||
<param name="from-file" value="true" />
|
||||
<param name="fromFile" value="true" />
|
||||
</item>
|
||||
</menu>
|
||||
<menu text="@.frame">
|
||||
|
@ -337,10 +337,12 @@ NewFrame_NewEmptyFrame = New Empty Frame
|
||||
NewFrame_DuplicateCels = Duplicate Linked Cels
|
||||
NewFrame_DuplicateCelsBlock = Duplicate Cels
|
||||
NewFrameTag = New Frame Tag
|
||||
NewLayer = New Layer
|
||||
NewLayer_BeforeActiveLayer = New Layer Below
|
||||
NewLayer_Group = New Group
|
||||
NewLayer_ReferenceLayer = New Reference Layer
|
||||
NewLayer = New {}
|
||||
NewLayer_BeforeActiveLayer = New {} Below
|
||||
NewLayer_Layer = Layer
|
||||
NewLayer_Group = Group
|
||||
NewLayer_ReferenceLayer = Reference Layer
|
||||
NewLayer_FromClipboard = {} (From Clipboard)
|
||||
NewSpriteFromSelection = New Sprite From Selection
|
||||
OpenBrowser = Open Browser
|
||||
OpenFile = Open Sprite
|
||||
@ -716,6 +718,9 @@ edit_cut = Cu&t
|
||||
edit_copy = &Copy
|
||||
edit_copy_merged = Copy Mer&ged
|
||||
edit_paste = &Paste
|
||||
edit_paste_special = Paste Specia&l
|
||||
edit_paste_special_new_layer = Paste as New &Layer
|
||||
edit_paste_special_new_ref_layer = Paste as New &Reference Layer
|
||||
edit_clear = &Delete
|
||||
edit_fill = &Fill
|
||||
edit_stroke = Stroke
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "app/cmd/move_layer.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/commands/new_params.h"
|
||||
#include "app/commands/params.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/doc_api.h"
|
||||
@ -24,9 +25,11 @@
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "app/util/clipboard.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/primitives.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "fmt/format.h"
|
||||
#include "render/dithering.h"
|
||||
#include "render/ordered_dither.h"
|
||||
#include "render/quantization.h"
|
||||
@ -42,7 +45,18 @@ namespace app {
|
||||
|
||||
using namespace ui;
|
||||
|
||||
class NewLayerCommand : public Command {
|
||||
struct NewLayerParams : public NewParams {
|
||||
Param<std::string> name { this, std::string(), "name" };
|
||||
Param<bool> group { this, false, "group" };
|
||||
Param<bool> reference { this, false, "reference" };
|
||||
Param<bool> ask { this, false, "ask" };
|
||||
Param<bool> fromFile { this, false, { "fromFile", "from-file" } };
|
||||
Param<bool> fromClipboard { this, false, "fromClipboard" };
|
||||
Param<bool> top { this, false, "top" };
|
||||
Param<bool> before { this, false, "before" };
|
||||
};
|
||||
|
||||
class NewLayerCommand : public CommandWithNewParams<NewLayerParams> {
|
||||
public:
|
||||
enum class Type { Layer, Group, ReferenceLayer };
|
||||
enum class Place { AfterActiveLayer, BeforeActiveLayer, Top };
|
||||
@ -58,46 +72,40 @@ protected:
|
||||
private:
|
||||
std::string getUniqueLayerName(const Sprite* sprite) const;
|
||||
int getMaxLayerNum(const Layer* layer) const;
|
||||
const char* layerPrefix() const;
|
||||
std::string layerPrefix() const;
|
||||
|
||||
std::string m_name;
|
||||
Type m_type;
|
||||
Place m_place;
|
||||
bool m_ask;
|
||||
bool m_fromFile;
|
||||
};
|
||||
|
||||
NewLayerCommand::NewLayerCommand()
|
||||
: Command(CommandId::NewLayer(), CmdRecordableFlag)
|
||||
: CommandWithNewParams(CommandId::NewLayer(), CmdRecordableFlag)
|
||||
{
|
||||
m_name = "";
|
||||
m_type = Type::Layer;
|
||||
m_place = Place::AfterActiveLayer;
|
||||
m_ask = false;
|
||||
}
|
||||
|
||||
void NewLayerCommand::onLoadParams(const Params& params)
|
||||
void NewLayerCommand::onLoadParams(const Params& commandParams)
|
||||
{
|
||||
m_name = params.get("name");
|
||||
CommandWithNewParams<NewLayerParams>::onLoadParams(commandParams);
|
||||
|
||||
m_type = Type::Layer;
|
||||
if (params.get_as<bool>("group"))
|
||||
if (params().group())
|
||||
m_type = Type::Group;
|
||||
else if (params.get_as<bool>("reference"))
|
||||
else if (params().reference())
|
||||
m_type = Type::ReferenceLayer;
|
||||
|
||||
m_ask = params.get_as<bool>("ask");
|
||||
m_fromFile = params.get_as<bool>("from-file");
|
||||
m_place = Place::AfterActiveLayer;
|
||||
if (params.get_as<bool>("top"))
|
||||
if (params().top())
|
||||
m_place = Place::Top;
|
||||
else if (params.get_as<bool>("before"))
|
||||
else if (params().before())
|
||||
m_place = Place::BeforeActiveLayer;
|
||||
}
|
||||
|
||||
bool NewLayerCommand::onEnabled(Context* context)
|
||||
{
|
||||
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
||||
ContextFlags::HasActiveSprite);
|
||||
ContextFlags::HasActiveSprite)
|
||||
&& (!params().fromClipboard() ||
|
||||
(clipboard::get_current_format() == clipboard::ClipboardImage));
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -126,14 +134,14 @@ void NewLayerCommand::onExecute(Context* context)
|
||||
}
|
||||
});
|
||||
|
||||
// Default name (m_name is a name specified in params)
|
||||
if (!m_name.empty())
|
||||
name = m_name;
|
||||
// Default name
|
||||
if (params().name.isSet())
|
||||
name = params().name();
|
||||
else
|
||||
name = getUniqueLayerName(sprite);
|
||||
|
||||
// Select a file to copy its content
|
||||
if (m_fromFile) {
|
||||
if (params().fromFile()) {
|
||||
Doc* oldActiveDocument = context->activeDocument();
|
||||
Command* openFile = Commands::instance()->byId(CommandId::OpenFile());
|
||||
Params params;
|
||||
@ -154,7 +162,7 @@ void NewLayerCommand::onExecute(Context* context)
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
// If params specify to ask the user about the name...
|
||||
if (m_ask) {
|
||||
if (params().ask()) {
|
||||
// We open the window to ask the name
|
||||
app::gen::NewLayer window;
|
||||
window.name()->setText(name.c_str());
|
||||
@ -186,7 +194,7 @@ void NewLayerCommand::onExecute(Context* context)
|
||||
{
|
||||
Tx tx(
|
||||
writer.context(),
|
||||
std::string("New ") + layerPrefix());
|
||||
fmt::format(Strings::commands_NewLayer(), layerPrefix()));
|
||||
DocApi api = document->getApi(tx);
|
||||
bool afterBackground = false;
|
||||
|
||||
@ -319,6 +327,10 @@ void NewLayerCommand::onExecute(Context* context)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Paste new layer from clipboard
|
||||
else if (params().fromClipboard() && layer->isImage()) {
|
||||
clipboard::paste(context, false);
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
}
|
||||
@ -330,7 +342,7 @@ void NewLayerCommand::onExecute(Context* context)
|
||||
StatusBar::instance()->invalidate();
|
||||
StatusBar::instance()->showTip(
|
||||
1000, "%s '%s' created",
|
||||
layerPrefix(),
|
||||
layerPrefix().c_str(),
|
||||
name.c_str());
|
||||
|
||||
App::instance()->mainWindow()->popTimeline();
|
||||
@ -341,32 +353,20 @@ void NewLayerCommand::onExecute(Context* context)
|
||||
std::string NewLayerCommand::onGetFriendlyName() const
|
||||
{
|
||||
std::string text;
|
||||
|
||||
switch (m_type) {
|
||||
case Type::Layer:
|
||||
if (m_place == Place::BeforeActiveLayer)
|
||||
text = Strings::commands_NewLayer_BeforeActiveLayer();
|
||||
else
|
||||
text = Strings::commands_NewLayer();
|
||||
break;
|
||||
case Type::Group:
|
||||
text = Strings::commands_NewLayer_Group();
|
||||
break;
|
||||
case Type::ReferenceLayer:
|
||||
text = Strings::commands_NewLayer_ReferenceLayer();
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_place == Place::BeforeActiveLayer)
|
||||
text = fmt::format(Strings::commands_NewLayer_BeforeActiveLayer(), layerPrefix());
|
||||
else
|
||||
text = fmt::format(Strings::commands_NewLayer(), layerPrefix());
|
||||
if (params().fromClipboard())
|
||||
text = fmt::format(Strings::commands_NewLayer_FromClipboard(), text);
|
||||
return text;
|
||||
}
|
||||
|
||||
std::string NewLayerCommand::getUniqueLayerName(const Sprite* sprite) const
|
||||
{
|
||||
char buf[1024];
|
||||
std::sprintf(buf, "%s %d",
|
||||
layerPrefix(),
|
||||
getMaxLayerNum(sprite->root())+1);
|
||||
return buf;
|
||||
return fmt::format("{} {}",
|
||||
layerPrefix(),
|
||||
getMaxLayerNum(sprite->root())+1);
|
||||
}
|
||||
|
||||
int NewLayerCommand::getMaxLayerNum(const Layer* layer) const
|
||||
@ -388,12 +388,12 @@ int NewLayerCommand::getMaxLayerNum(const Layer* layer) const
|
||||
return max;
|
||||
}
|
||||
|
||||
const char* NewLayerCommand::layerPrefix() const
|
||||
std::string NewLayerCommand::layerPrefix() const
|
||||
{
|
||||
switch (m_type) {
|
||||
case Type::Layer: return "Layer";
|
||||
case Type::Group: return "Group";
|
||||
case Type::ReferenceLayer: return "Reference Layer";
|
||||
case Type::Layer: return Strings::commands_NewLayer_Layer();
|
||||
case Type::Group: return Strings::commands_NewLayer_Group();
|
||||
case Type::ReferenceLayer: return Strings::commands_NewLayer_ReferenceLayer();
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
@ -136,9 +136,8 @@ namespace app {
|
||||
CommandWithNewParams(Args&&...args)
|
||||
: CommandWithNewParamsBase(std::forward<Args>(args)...) { }
|
||||
|
||||
T& params() {
|
||||
return m_params;
|
||||
}
|
||||
T& params() { return m_params; }
|
||||
const T& params() const { return m_params; }
|
||||
|
||||
private:
|
||||
void onResetValues() override {
|
||||
|
@ -552,7 +552,7 @@ bool DocView::onCopy(Context* ctx)
|
||||
bool DocView::onPaste(Context* ctx)
|
||||
{
|
||||
if (clipboard::get_current_format() == clipboard::ClipboardImage) {
|
||||
clipboard::paste();
|
||||
clipboard::paste(ctx, true);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
@ -4017,7 +4017,7 @@ bool Timeline::onCopy(Context* ctx)
|
||||
bool Timeline::onPaste(Context* ctx)
|
||||
{
|
||||
if (clipboard::get_current_format() == clipboard::ClipboardDocRange) {
|
||||
clipboard::paste();
|
||||
clipboard::paste(ctx, true);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "app/app.h"
|
||||
#include "app/cmd/clear_mask.h"
|
||||
#include "app/cmd/deselect_mask.h"
|
||||
#include "app/cmd/set_mask.h"
|
||||
#include "app/cmd/trim_cel.h"
|
||||
#include "app/console.h"
|
||||
#include "app/context_access.h"
|
||||
@ -324,14 +325,16 @@ void copy_palette(const Palette* palette, const doc::PalettePicks& picks)
|
||||
clipboard_picks = picks;
|
||||
}
|
||||
|
||||
void paste()
|
||||
void paste(Context* ctx, const bool interactive)
|
||||
{
|
||||
Editor* editor = current_editor;
|
||||
if (editor == NULL)
|
||||
Site site = ctx->activeSite();
|
||||
Doc* dstDoc = site.document();
|
||||
if (!dstDoc)
|
||||
return;
|
||||
|
||||
Doc* dstDoc = editor->document();
|
||||
Sprite* dstSpr = dstDoc->sprite();
|
||||
Sprite* dstSpr = site.sprite();
|
||||
if (!dstSpr)
|
||||
return;
|
||||
|
||||
switch (get_current_format()) {
|
||||
|
||||
@ -350,7 +353,7 @@ void paste()
|
||||
if (!clipboard_image)
|
||||
return;
|
||||
|
||||
Palette* dst_palette = dstSpr->palette(editor->frame());
|
||||
Palette* dst_palette = dstSpr->palette(site.frame());
|
||||
|
||||
// Source image (clipboard or a converted copy to the destination 'imgtype')
|
||||
ImageRef src_image;
|
||||
@ -362,7 +365,7 @@ void paste()
|
||||
src_image = clipboard_image;
|
||||
}
|
||||
else {
|
||||
RgbMap* dst_rgbmap = dstSpr->rgbMap(editor->frame());
|
||||
RgbMap* dst_rgbmap = dstSpr->rgbMap(site.frame());
|
||||
|
||||
src_image.reset(
|
||||
render::convert_pixel_format(
|
||||
@ -373,9 +376,42 @@ void paste()
|
||||
0));
|
||||
}
|
||||
|
||||
// Change to MovingPixelsState
|
||||
editor->pasteImage(src_image.get(),
|
||||
clipboard_mask.get());
|
||||
if (current_editor && interactive) {
|
||||
// Change to MovingPixelsState
|
||||
current_editor->pasteImage(src_image.get(),
|
||||
clipboard_mask.get());
|
||||
}
|
||||
else {
|
||||
// Non-interactive version (just copy the image to the cel)
|
||||
Layer* dstLayer = site.layer();
|
||||
ASSERT(dstLayer);
|
||||
if (!dstLayer || !dstLayer->isImage())
|
||||
return;
|
||||
|
||||
Tx tx(ctx, "Paste Image");
|
||||
DocApi api = dstDoc->getApi(tx);
|
||||
Cel* dstCel = api.addCel(
|
||||
static_cast<LayerImage*>(dstLayer), site.frame(),
|
||||
ImageRef(Image::createCopy(src_image.get())));
|
||||
|
||||
// Adjust bounds
|
||||
if (dstCel) {
|
||||
if (clipboard_mask) {
|
||||
if (dstLayer->isReference()) {
|
||||
dstCel->setBounds(dstSpr->bounds());
|
||||
|
||||
Mask emptyMask;
|
||||
tx(new cmd::SetMask(dstDoc, &emptyMask));
|
||||
}
|
||||
else {
|
||||
dstCel->setBounds(clipboard_mask->bounds());
|
||||
tx(new cmd::SetMask(dstDoc, clipboard_mask.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -387,8 +423,12 @@ void paste()
|
||||
switch (srcRange.type()) {
|
||||
|
||||
case DocRange::kCels: {
|
||||
Layer* dstLayer = editor->layer();
|
||||
frame_t dstFrameFirst = editor->frame();
|
||||
Layer* dstLayer = site.layer();
|
||||
ASSERT(dstLayer);
|
||||
if (!dstLayer)
|
||||
return;
|
||||
|
||||
frame_t dstFrameFirst = site.frame();
|
||||
|
||||
DocRange dstRange;
|
||||
dstRange.startRange(dstLayer, dstFrameFirst, DocRange::kCels);
|
||||
@ -405,11 +445,12 @@ void paste()
|
||||
// This is the app::copy_range (not clipboard::copy_range()).
|
||||
if (srcRange.layers() == dstRange.layers())
|
||||
app::copy_range(srcDoc, srcRange, dstRange, kDocRangeBefore);
|
||||
editor->invalidate();
|
||||
if (current_editor)
|
||||
current_editor->invalidate(); // TODO check if this is necessary
|
||||
return;
|
||||
}
|
||||
|
||||
Tx tx(UIContext::instance(), "Paste Cels");
|
||||
Tx tx(ctx, "Paste Cels");
|
||||
DocApi api = dstDoc->getApi(tx);
|
||||
|
||||
// Add extra frames if needed
|
||||
@ -484,12 +525,13 @@ void paste()
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
editor->invalidate();
|
||||
if (current_editor)
|
||||
current_editor->invalidate(); // TODO check if this is necessary
|
||||
break;
|
||||
}
|
||||
|
||||
case DocRange::kFrames: {
|
||||
frame_t dstFrame = editor->frame();
|
||||
frame_t dstFrame = site.frame();
|
||||
|
||||
// We use a DocRange operation to copy frames inside
|
||||
// the same sprite.
|
||||
@ -501,7 +543,7 @@ void paste()
|
||||
break;
|
||||
}
|
||||
|
||||
Tx tx(UIContext::instance(), "Paste Frames");
|
||||
Tx tx(ctx, "Paste Frames");
|
||||
DocApi api = dstDoc->getApi(tx);
|
||||
|
||||
auto srcLayers = srcSpr->allBrowsableLayers();
|
||||
@ -536,7 +578,8 @@ void paste()
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
editor->invalidate();
|
||||
if (current_editor)
|
||||
current_editor->invalidate(); // TODO check if this is necessary
|
||||
break;
|
||||
}
|
||||
|
||||
@ -544,7 +587,7 @@ void paste()
|
||||
if (srcDoc->colorMode() != dstDoc->colorMode())
|
||||
throw std::runtime_error("You cannot copy layers of document with different color modes");
|
||||
|
||||
Tx tx(UIContext::instance(), "Paste Layers");
|
||||
Tx tx(ctx, "Paste Layers");
|
||||
DocApi api = dstDoc->getApi(tx);
|
||||
|
||||
// Remove children if their parent is selected so we only
|
||||
@ -587,7 +630,8 @@ void paste()
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
editor->invalidate();
|
||||
if (current_editor)
|
||||
current_editor->invalidate(); // TODO check if this is necessary
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -22,6 +23,7 @@ namespace doc {
|
||||
|
||||
namespace app {
|
||||
class Doc;
|
||||
class Context;
|
||||
class ContextReader;
|
||||
class ContextWriter;
|
||||
class DocRange;
|
||||
@ -61,7 +63,7 @@ namespace app {
|
||||
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 paste();
|
||||
void paste(Context* ctx, const bool interactive);
|
||||
|
||||
// Returns true and fills the specified "size"" with the image's
|
||||
// size in the clipboard, or return false in case that the clipboard
|
||||
|
Loading…
x
Reference in New Issue
Block a user