mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-20 18:40:57 +00:00
Add new ConvertLayer command ("Layer > Convert To" menu item)
Now we have an easy way to convert between: Background <-> Layers <-> Tilemaps Deprecated (they are kept only for backward compatibility): BackgroundFromLayer LayerFromBackground
This commit is contained in:
parent
b6987a0262
commit
44437e0d1f
28
data/gui.xml
28
data/gui.xml
@ -840,9 +840,17 @@
|
|||||||
</item>
|
</item>
|
||||||
</menu>
|
</menu>
|
||||||
<item command="RemoveLayer" text="@.layer_delete_layer" group="layer_remove" />
|
<item command="RemoveLayer" text="@.layer_delete_layer" group="layer_remove" />
|
||||||
<menu text="@.layer_convert">
|
<menu text="@.layer_convert_to">
|
||||||
<item command="BackgroundFromLayer" text="@.layer_background_from_layer" />
|
<item command="ConvertLayer" text="@.layer_convert_to_background">
|
||||||
<item command="LayerFromBackground" text="@.layer_layer_from_background" group="layer_background" />
|
<param name="to" value="background" />
|
||||||
|
</item>
|
||||||
|
<item command="ConvertLayer" text="@.layer_convert_to_layer">
|
||||||
|
<param name="to" value="layer" />
|
||||||
|
</item>
|
||||||
|
<separator />
|
||||||
|
<item command="ConvertLayer" text="@.layer_convert_to_tilemap">
|
||||||
|
<param name="to" value="tilemap" />
|
||||||
|
</item>
|
||||||
</menu>
|
</menu>
|
||||||
<separator />
|
<separator />
|
||||||
<item command="DuplicateLayer" text="@.layer_duplicate" group="layer_duplicate" />
|
<item command="DuplicateLayer" text="@.layer_duplicate" group="layer_duplicate" />
|
||||||
@ -1018,9 +1026,17 @@
|
|||||||
<param name="group" value="true" />
|
<param name="group" value="true" />
|
||||||
</item>
|
</item>
|
||||||
<item command="RemoveLayer" text="@main_menu.layer_delete_layer" />
|
<item command="RemoveLayer" text="@main_menu.layer_delete_layer" />
|
||||||
<menu text="@main_menu.layer_convert">
|
<menu text="@main_menu.layer_convert_to">
|
||||||
<item command="BackgroundFromLayer" text="@main_menu.layer_background_from_layer" />
|
<item command="ConvertLayer" text="@main_menu.layer_convert_to_background">
|
||||||
<item command="LayerFromBackground" text="@main_menu.layer_layer_from_background" group="layer_popup_background" />
|
<param name="to" value="background" />
|
||||||
|
</item>
|
||||||
|
<item command="ConvertLayer" text="@main_menu.layer_convert_to_layer">
|
||||||
|
<param name="to" value="layer" />
|
||||||
|
</item>
|
||||||
|
<separator />
|
||||||
|
<item command="ConvertLayer" text="@main_menu.layer_convert_to_tilemap">
|
||||||
|
<param name="to" value="tilemap" />
|
||||||
|
</item>
|
||||||
</menu>
|
</menu>
|
||||||
<separator />
|
<separator />
|
||||||
<item command="DuplicateLayer" text="@main_menu.layer_duplicate" />
|
<item command="DuplicateLayer" text="@main_menu.layer_duplicate" />
|
||||||
|
@ -273,6 +273,10 @@ ClearCel = Clear Cel
|
|||||||
ClearRecentFiles = Clear Recent Files
|
ClearRecentFiles = Clear Recent Files
|
||||||
CloseAllFiles = Close All Files
|
CloseAllFiles = Close All Files
|
||||||
CloseFile = Close File
|
CloseFile = Close File
|
||||||
|
ConvertLayer = Convert Layer
|
||||||
|
ConvertLayer_Background = Convert to Background
|
||||||
|
ConvertLayer_Layer = Convert to Transparent Layer
|
||||||
|
ConvertLayer_Tilemap = Convert to Tilemap
|
||||||
ColorCurve = Color Curve
|
ColorCurve = Color Curve
|
||||||
ColorQuantization = Create Palette from Current Sprite (Color Quantization)
|
ColorQuantization = Create Palette from Current Sprite (Color Quantization)
|
||||||
ContiguousFill = Switch Contiguous Fill
|
ContiguousFill = Switch Contiguous Fill
|
||||||
@ -925,9 +929,10 @@ layer_new_layer_via_cut = New Layer via Cu&t
|
|||||||
layer_new_reference_layer_from_file = New &Reference Layer from File
|
layer_new_reference_layer_from_file = New &Reference Layer from File
|
||||||
layer_new_tilemap_layer = New Tilemap Layer
|
layer_new_tilemap_layer = New Tilemap Layer
|
||||||
layer_delete_layer = Delete Laye&r
|
layer_delete_layer = Delete Laye&r
|
||||||
layer_convert = Conv&ert
|
layer_convert_to = Conv&ert To...
|
||||||
layer_background_from_layer = &Background from Layer
|
layer_convert_to_background = &Background
|
||||||
layer_layer_from_background = &Layer from Background
|
layer_convert_to_layer = &Layer
|
||||||
|
layer_convert_to_tilemap = &Tilemap
|
||||||
layer_duplicate = &Duplicate
|
layer_duplicate = &Duplicate
|
||||||
layer_merge_down = &Merge Down
|
layer_merge_down = &Merge Down
|
||||||
layer_flatten = &Flatten
|
layer_flatten = &Flatten
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Aseprite
|
# Aseprite
|
||||||
# Copyright (C) 2018-2020 Igara Studio S.A.
|
# Copyright (C) 2018-2021 Igara Studio S.A.
|
||||||
# Copyright (C) 2001-2018 David Capello
|
# Copyright (C) 2001-2018 David Capello
|
||||||
|
|
||||||
# Generate a ui::Widget for each widget in a XML file
|
# Generate a ui::Widget for each widget in a XML file
|
||||||
@ -535,6 +535,7 @@ add_library(app-lib
|
|||||||
commands/cmd_undo.cpp
|
commands/cmd_undo.cpp
|
||||||
commands/command.cpp
|
commands/command.cpp
|
||||||
commands/commands.cpp
|
commands/commands.cpp
|
||||||
|
commands/convert_layer.cpp
|
||||||
commands/filters/cmd_brightness_contrast.cpp
|
commands/filters/cmd_brightness_contrast.cpp
|
||||||
commands/filters/cmd_color_curve.cpp
|
commands/filters/cmd_color_curve.cpp
|
||||||
commands/filters/cmd_convolution_matrix.cpp
|
commands/filters/cmd_convolution_matrix.cpp
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
// Copyright (C) 2018-2021 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
|
||||||
@ -14,6 +14,7 @@ FOR_EACH_COMMAND(CelOpacity)
|
|||||||
FOR_EACH_COMMAND(ChangePixelFormat)
|
FOR_EACH_COMMAND(ChangePixelFormat)
|
||||||
FOR_EACH_COMMAND(ColorCurve)
|
FOR_EACH_COMMAND(ColorCurve)
|
||||||
FOR_EACH_COMMAND(ColorQuantization)
|
FOR_EACH_COMMAND(ColorQuantization)
|
||||||
|
FOR_EACH_COMMAND(ConvertLayer)
|
||||||
FOR_EACH_COMMAND(ConvolutionMatrix)
|
FOR_EACH_COMMAND(ConvolutionMatrix)
|
||||||
FOR_EACH_COMMAND(CopyColors)
|
FOR_EACH_COMMAND(CopyColors)
|
||||||
FOR_EACH_COMMAND(CopyTiles)
|
FOR_EACH_COMMAND(CopyTiles)
|
||||||
|
258
src/app/commands/convert_layer.cpp
Normal file
258
src/app/commands/convert_layer.cpp
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2021 Igara Studio S.A.
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "app/cmd/add_cel.h"
|
||||||
|
#include "app/cmd/add_layer.h"
|
||||||
|
#include "app/cmd/add_tileset.h"
|
||||||
|
#include "app/cmd/background_from_layer.h"
|
||||||
|
#include "app/cmd/copy_cel.h"
|
||||||
|
#include "app/cmd/layer_from_background.h"
|
||||||
|
#include "app/cmd/remove_layer.h"
|
||||||
|
#include "app/commands/command.h"
|
||||||
|
#include "app/commands/new_params.h"
|
||||||
|
#include "app/context_access.h"
|
||||||
|
#include "app/i18n/strings.h"
|
||||||
|
#include "app/modules/gui.h"
|
||||||
|
#include "app/tx.h"
|
||||||
|
#include "app/util/cel_ops.h"
|
||||||
|
#include "doc/grid.h"
|
||||||
|
#include "doc/layer.h"
|
||||||
|
#include "doc/layer_tilemap.h"
|
||||||
|
#include "doc/tileset.h"
|
||||||
|
|
||||||
|
#ifdef ENABLE_SCRIPTING
|
||||||
|
#include "app/script/luacpp.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
enum class ConvertLayerParam { None, Background, Layer, Tilemap };
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void Param<ConvertLayerParam>::fromString(const std::string& value)
|
||||||
|
{
|
||||||
|
if (value == "background")
|
||||||
|
setValue(ConvertLayerParam::Background);
|
||||||
|
else if (value == "layer")
|
||||||
|
setValue(ConvertLayerParam::Layer);
|
||||||
|
else if (value == "tilemap")
|
||||||
|
setValue(ConvertLayerParam::Tilemap);
|
||||||
|
else
|
||||||
|
setValue(ConvertLayerParam::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_SCRIPTING
|
||||||
|
template<>
|
||||||
|
void Param<ConvertLayerParam>::fromLua(lua_State* L, int index)
|
||||||
|
{
|
||||||
|
fromString(lua_tostring(L, index));
|
||||||
|
}
|
||||||
|
#endif // ENABLE_SCRIPTING
|
||||||
|
|
||||||
|
struct ConvertLayerParams : public NewParams {
|
||||||
|
Param<ConvertLayerParam> to { this, ConvertLayerParam::None, "to" };
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertLayerCommand : public CommandWithNewParams<ConvertLayerParams> {
|
||||||
|
public:
|
||||||
|
ConvertLayerCommand();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool onEnabled(Context* context) override;
|
||||||
|
void onExecute(Context* context) override;
|
||||||
|
std::string onGetFriendlyName() const override;
|
||||||
|
|
||||||
|
void copyCels(Tx& tx,
|
||||||
|
Layer* srcLayer,
|
||||||
|
Layer* newLayer);
|
||||||
|
};
|
||||||
|
|
||||||
|
ConvertLayerCommand::ConvertLayerCommand()
|
||||||
|
: CommandWithNewParams<ConvertLayerParams>(CommandId::ConvertLayer(), CmdRecordableFlag)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConvertLayerCommand::onEnabled(Context* ctx)
|
||||||
|
{
|
||||||
|
if (!ctx->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
||||||
|
ContextFlags::HasActiveSprite |
|
||||||
|
ContextFlags::HasActiveLayer |
|
||||||
|
ContextFlags::ActiveLayerIsVisible |
|
||||||
|
ContextFlags::ActiveLayerIsEditable))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// TODO add support to convert reference layers into regular layers or tilemaps
|
||||||
|
if (ctx->checkFlags(ContextFlags::ActiveLayerIsReference))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (params().to()) {
|
||||||
|
|
||||||
|
case ConvertLayerParam::Background:
|
||||||
|
return
|
||||||
|
// Doesn't have a background layer
|
||||||
|
!ctx->checkFlags(ContextFlags::HasBackgroundLayer) &&
|
||||||
|
// Convert a regular layer or tilemap into background
|
||||||
|
ctx->checkFlags(ContextFlags::ActiveLayerIsImage) &&
|
||||||
|
// TODO add support for background tliemaps
|
||||||
|
!ctx->checkFlags(ContextFlags::ActiveLayerIsTilemap);
|
||||||
|
|
||||||
|
case ConvertLayerParam::Layer:
|
||||||
|
return
|
||||||
|
// Convert a background layer into a transparent layer
|
||||||
|
ctx->checkFlags(ContextFlags::ActiveLayerIsImage |
|
||||||
|
ContextFlags::ActiveLayerIsBackground) ||
|
||||||
|
// or a tilemap into a regular layer
|
||||||
|
ctx->checkFlags(ContextFlags::ActiveLayerIsTilemap);
|
||||||
|
|
||||||
|
case ConvertLayerParam::Tilemap:
|
||||||
|
return
|
||||||
|
ctx->checkFlags(ContextFlags::ActiveLayerIsImage) &&
|
||||||
|
!ctx->checkFlags(ContextFlags::ActiveLayerIsTilemap) &&
|
||||||
|
// TODO add support for background tliemaps
|
||||||
|
!ctx->checkFlags(ContextFlags::ActiveLayerIsBackground);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertLayerCommand::onExecute(Context* ctx)
|
||||||
|
{
|
||||||
|
ContextWriter writer(ctx);
|
||||||
|
Doc* document(writer.document());
|
||||||
|
{
|
||||||
|
Tx tx(ctx, friendlyName());
|
||||||
|
Site site = ctx->activeSite();
|
||||||
|
Sprite* sprite = site.sprite();
|
||||||
|
Layer* srcLayer = site.layer();
|
||||||
|
|
||||||
|
switch (params().to()) {
|
||||||
|
|
||||||
|
case ConvertLayerParam::Background:
|
||||||
|
// Layer -> Background
|
||||||
|
if (srcLayer->isTransparent()) {
|
||||||
|
ASSERT(srcLayer->isImage());
|
||||||
|
tx(new cmd::BackgroundFromLayer(static_cast<LayerImage*>(srcLayer)));
|
||||||
|
}
|
||||||
|
// Tilemap -> Background
|
||||||
|
else if (srcLayer->isTilemap()) {
|
||||||
|
auto newLayer = new LayerImage(sprite);
|
||||||
|
newLayer->configureAsBackground();
|
||||||
|
newLayer->setName(Strings::commands_NewFile_BackgroundLayer());
|
||||||
|
newLayer->setContinuous(srcLayer->isContinuous());
|
||||||
|
tx(new cmd::AddLayer(srcLayer->parent(), newLayer, srcLayer));
|
||||||
|
|
||||||
|
CelList srcCels;
|
||||||
|
srcLayer->getCels(srcCels);
|
||||||
|
for (Cel* srcCel : srcCels)
|
||||||
|
create_cel_copy(tx, srcCel, sprite, newLayer, srcCel->frame());
|
||||||
|
|
||||||
|
tx(new cmd::RemoveLayer(srcLayer));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ConvertLayerParam::Layer:
|
||||||
|
// Background -> Layer
|
||||||
|
if (srcLayer->isBackground()) {
|
||||||
|
tx(new cmd::LayerFromBackground(srcLayer));
|
||||||
|
}
|
||||||
|
// Background -> Tilemap
|
||||||
|
else if (srcLayer->isTilemap()) {
|
||||||
|
auto newLayer = new LayerImage(sprite);
|
||||||
|
newLayer->setName(srcLayer->name());
|
||||||
|
newLayer->setContinuous(srcLayer->isContinuous());
|
||||||
|
tx(new cmd::AddLayer(srcLayer->parent(), newLayer, srcLayer));
|
||||||
|
|
||||||
|
copyCels(tx, srcLayer, newLayer);
|
||||||
|
|
||||||
|
tx(new cmd::RemoveLayer(srcLayer));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ConvertLayerParam::Tilemap:
|
||||||
|
// Background or Transparent Layer -> Tilemap
|
||||||
|
if (srcLayer->isImage() &&
|
||||||
|
(srcLayer->isBackground() ||
|
||||||
|
srcLayer->isTransparent())) {
|
||||||
|
auto tileset = new Tileset(sprite, site.grid(), 1);
|
||||||
|
|
||||||
|
auto addTileset = new cmd::AddTileset(sprite, tileset);
|
||||||
|
tx(addTileset);
|
||||||
|
tileset_index tsi = addTileset->tilesetIndex();
|
||||||
|
|
||||||
|
auto newLayer = new LayerTilemap(sprite, tsi);
|
||||||
|
newLayer->setName(srcLayer->name());
|
||||||
|
newLayer->setContinuous(srcLayer->isContinuous());
|
||||||
|
tx(new cmd::AddLayer(srcLayer->parent(), newLayer, srcLayer));
|
||||||
|
|
||||||
|
copyCels(tx, srcLayer, newLayer);
|
||||||
|
|
||||||
|
tx(new cmd::RemoveLayer(srcLayer));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_UI
|
||||||
|
if (ctx->isUIAvailable())
|
||||||
|
update_screen_for_document(document);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertLayerCommand::copyCels(Tx& tx,
|
||||||
|
Layer* srcLayer,
|
||||||
|
Layer* newLayer)
|
||||||
|
{
|
||||||
|
std::map<doc::ObjectId, doc::Cel*> linkedCels;
|
||||||
|
|
||||||
|
CelList srcCels;
|
||||||
|
srcLayer->getCels(srcCels);
|
||||||
|
for (Cel* srcCel : srcCels) {
|
||||||
|
frame_t frame = srcCel->frame();
|
||||||
|
|
||||||
|
// Keep linked cels in the new layer
|
||||||
|
Cel* linkedSrcCel = srcCel->link();
|
||||||
|
if (linkedSrcCel) {
|
||||||
|
auto it = linkedCels.find(linkedSrcCel->id());
|
||||||
|
if (it != linkedCels.end()) {
|
||||||
|
tx(new cmd::CopyCel(
|
||||||
|
newLayer, linkedSrcCel->frame(),
|
||||||
|
newLayer, frame, true));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Cel* newCel = create_cel_copy(tx, srcCel, srcLayer->sprite(), newLayer, frame);
|
||||||
|
tx(new cmd::AddCel(newLayer, newCel));
|
||||||
|
|
||||||
|
linkedCels[srcCel->id()] = newCel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ConvertLayerCommand::onGetFriendlyName() const
|
||||||
|
{
|
||||||
|
switch (params().to()) {
|
||||||
|
case ConvertLayerParam::Background: return Strings::commands_ConvertLayer_Background(); break;
|
||||||
|
case ConvertLayerParam::Layer: return Strings::commands_ConvertLayer_Layer(); break;
|
||||||
|
case ConvertLayerParam::Tilemap: return Strings::commands_ConvertLayer_Tilemap(); break;
|
||||||
|
default: return getBaseFriendlyName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Command* CommandFactory::createConvertLayerCommand()
|
||||||
|
{
|
||||||
|
return new ConvertLayerCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
// Copyright (C) 2019-2021 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
|
||||||
@ -87,8 +87,12 @@ bool AppMenuItem::onProcessMessage(Message* msg)
|
|||||||
switch (msg->type()) {
|
switch (msg->type()) {
|
||||||
|
|
||||||
case kCloseMessage:
|
case kCloseMessage:
|
||||||
// disable the menu (the keyboard shortcuts are processed by "manager_msg_proc")
|
// Don't disable items with submenus
|
||||||
setEnabled(false);
|
if (!hasSubmenu()) {
|
||||||
|
// Disable the menu item (the keyboard shortcuts are processed
|
||||||
|
// by "manager_msg_proc")
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user