mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-20 04:20:49 +00:00
Merge branch 'layer-folder' into beta (fix #454)
This commit is contained in:
commit
5d00a6a737
@ -664,6 +664,9 @@
|
||||
<item command="LayerVisibility" text="&Visible" />
|
||||
<separator />
|
||||
<item command="NewLayer" text="&New Layer" />
|
||||
<item command="NewLayer" text="New &Group">
|
||||
<param name="group" value="true" />
|
||||
</item>
|
||||
<item command="RemoveLayer" text="&Remove Layer" />
|
||||
<item command="BackgroundFromLayer" text="&Background from Layer" />
|
||||
<item command="LayerFromBackground" text="&Layer from Background" />
|
||||
|
@ -228,7 +228,7 @@
|
||||
<document>
|
||||
<section id="site">
|
||||
<option id="frame" type="doc::frame_t" default="doc::frame_t(0)" />
|
||||
<option id="layer" type="doc::LayerIndex" />
|
||||
<option id="layer" type="doc::layer_t" default="doc::layer_t(0)" />
|
||||
</section>
|
||||
<section id="tiled">
|
||||
<option id="mode" type="filters::TiledMode" default="filters::TiledMode::NONE" migrate="Tools.Tiled" />
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@ -329,6 +329,10 @@
|
||||
<part id="timeline_continuous_active" x="288" y="36" w="12" h="12" />
|
||||
<part id="timeline_discontinuous_normal" x="276" y="48" w="12" h="12" />
|
||||
<part id="timeline_discontinuous_active" x="288" y="48" w="12" h="12" />
|
||||
<part id="timeline_closed_group_normal" x="276" y="60" w="12" h="12" />
|
||||
<part id="timeline_closed_group_active" x="288" y="60" w="12" h="12" />
|
||||
<part id="timeline_open_group_normal" x="276" y="72" w="12" h="12" />
|
||||
<part id="timeline_open_group_active" x="288" y="72" w="12" h="12" />
|
||||
<part id="timeline_empty_frame_normal" x="240" y="60" w="12" h="12" />
|
||||
<part id="timeline_empty_frame_active" x="252" y="60" w="12" h="12" />
|
||||
<part id="timeline_keyframe_normal" x="240" y="72" w="12" h="12" />
|
||||
@ -525,12 +529,18 @@
|
||||
<style id="timeline_open_eye:active">
|
||||
<icon part="timeline_open_eye_active" />
|
||||
</style>
|
||||
<style id="timeline_open_eye:disabled">
|
||||
<icon color="disabled" />
|
||||
</style>
|
||||
<style id="timeline_closed_eye" base="timeline_box">
|
||||
<icon part="timeline_closed_eye_normal" align="center" valign="middle" />
|
||||
</style>
|
||||
<style id="timeline_closed_eye:active">
|
||||
<icon part="timeline_closed_eye_active" />
|
||||
</style>
|
||||
<style id="timeline_closed_eye:disabled">
|
||||
<icon color="disabled" />
|
||||
</style>
|
||||
|
||||
<!-- timeline_padlock -->
|
||||
<style id="timeline_open_padlock" base="timeline_box">
|
||||
@ -539,12 +549,18 @@
|
||||
<style id="timeline_open_padlock:active">
|
||||
<icon part="timeline_open_padlock_active" />
|
||||
</style>
|
||||
<style id="timeline_open_padlock:disabled">
|
||||
<icon color="disabled" />
|
||||
</style>
|
||||
<style id="timeline_closed_padlock" base="timeline_box">
|
||||
<icon part="timeline_closed_padlock_normal" align="center" valign="middle" />
|
||||
</style>
|
||||
<style id="timeline_closed_padlock:active">
|
||||
<icon part="timeline_closed_padlock_active" />
|
||||
</style>
|
||||
<style id="timeline_closed_padlock:disabled">
|
||||
<icon color="disabled" />
|
||||
</style>
|
||||
|
||||
<!-- timeline_continuous -->
|
||||
<style id="timeline_continuous" base="timeline_box">
|
||||
@ -560,6 +576,20 @@
|
||||
<icon part="timeline_discontinuous_active" />
|
||||
</style>
|
||||
|
||||
<!-- timeline_group -->
|
||||
<style id="timeline_closed_group" base="timeline_box">
|
||||
<icon part="timeline_closed_group_normal" align="center" valign="middle" />
|
||||
</style>
|
||||
<style id="timeline_closed_group:active">
|
||||
<icon part="timeline_closed_group_active" />
|
||||
</style>
|
||||
<style id="timeline_open_group" base="timeline_box">
|
||||
<icon part="timeline_open_group_normal" align="center" valign="middle" />
|
||||
</style>
|
||||
<style id="timeline_open_group:active">
|
||||
<icon part="timeline_open_group_active" />
|
||||
</style>
|
||||
|
||||
<!-- timeline_layer -->
|
||||
<style id="timeline_layer" base="timeline_box">
|
||||
<text align="left" valign="middle" padding-left="4" />
|
||||
|
@ -1,32 +1,20 @@
|
||||
<!-- ASEPRITE -->
|
||||
<!-- Copyright (C) 2001-2013 by David Capello -->
|
||||
<!-- Copyright (C) 2001-2016 by David Capello -->
|
||||
<gui>
|
||||
<window text="New Image Layer" id="new_layer">
|
||||
<box vertical="true">
|
||||
<box horizontal="true">
|
||||
<box vertical="true" homogeneous="true">
|
||||
<label text="Name:" />
|
||||
<window text="New Layer" id="new_layer">
|
||||
<box vertical="true">
|
||||
<box horizontal="true">
|
||||
<box vertical="true" homogeneous="true">
|
||||
<label text="Name:" />
|
||||
</box>
|
||||
<box vertical="true" homogeneous="true">
|
||||
<entry maxsize="256" text="New Layer" id="name" magnet="true" />
|
||||
</box>
|
||||
</box>
|
||||
<box vertical="true" homogeneous="true">
|
||||
<entry maxsize="256" text="New Layer" id="name" magnet="true" />
|
||||
<box horizontal="true" homogeneous="true">
|
||||
<button text="&OK" closewindow="true" id="ok" magnet="true" />
|
||||
<button text="&Cancel" closewindow="true" />
|
||||
</box>
|
||||
</box>
|
||||
<box horizontal="true" homogeneous="true">
|
||||
<button text="&OK" closewindow="true" id="ok" magnet="true" />
|
||||
<button text="&Cancel" closewindow="true" />
|
||||
</box>
|
||||
</box>
|
||||
</window>
|
||||
<window text="New Layer Set" id="new_layer_set">
|
||||
<box vertical="true">
|
||||
<box horizontal="true">
|
||||
<label text="Name:" />
|
||||
<entry maxsize="256" text="New Set" id="name" />
|
||||
</box>
|
||||
<box horizontal="true" homogeneous="true">
|
||||
<button text="&OK" closewindow="true" id="ok" magnet="true" />
|
||||
<button text="&Cancel" closewindow="true" />
|
||||
</box>
|
||||
</box>
|
||||
</window>
|
||||
</window>
|
||||
</gui>
|
||||
|
@ -156,6 +156,7 @@ Layer Chunk (0x2004)
|
||||
4 = Lock movement
|
||||
8 = Background
|
||||
16 = Prefer linked cels
|
||||
32 = The layer group should be displayed collapsed
|
||||
WORD Layer type (0=normal (image) layer, 1=layer set)
|
||||
WORD Layer child level (see NOTE.1)
|
||||
WORD Default layer width in pixels (ignored)
|
||||
|
@ -230,7 +230,6 @@ add_library(app-lib
|
||||
commands/cmd_new_frame.cpp
|
||||
commands/cmd_new_frame_tag.cpp
|
||||
commands/cmd_new_layer.cpp
|
||||
commands/cmd_new_layer_set.cpp
|
||||
commands/cmd_new_sprite_from_selection.cpp
|
||||
commands/cmd_onionskin.cpp
|
||||
commands/cmd_open_file.cpp
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "doc/frame_tag.h"
|
||||
#include "doc/frame_tags.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/layers_range.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
@ -332,7 +331,7 @@ bool CliProcessor::openFile(CliOpenFile& cof)
|
||||
if (doc) {
|
||||
// Show all layers
|
||||
if (cof.allLayers) {
|
||||
for (doc::Layer* layer : doc->sprite()->layers())
|
||||
for (doc::Layer* layer : doc->sprite()->allLayers())
|
||||
layer->setVisible(true);
|
||||
}
|
||||
|
||||
@ -360,7 +359,7 @@ bool CliProcessor::openFile(CliOpenFile& cof)
|
||||
|
||||
if (!cof.importLayer.empty()) {
|
||||
Layer* foundLayer = nullptr;
|
||||
for (Layer* layer : doc->sprite()->layers()) {
|
||||
for (Layer* layer : doc->sprite()->allLayers()) {
|
||||
if (layer->name() == cof.importLayer) {
|
||||
foundLayer = layer;
|
||||
break;
|
||||
@ -370,10 +369,8 @@ bool CliProcessor::openFile(CliOpenFile& cof)
|
||||
m_exporter->addDocument(doc, foundLayer, frameTag, isTemporalTag);
|
||||
}
|
||||
else if (cof.splitLayers) {
|
||||
for (auto layer : doc->sprite()->layers()) {
|
||||
if (layer->isVisible())
|
||||
m_exporter->addDocument(doc, layer, frameTag, isTemporalTag);
|
||||
}
|
||||
for (auto layer : doc->sprite()->allVisibleLayers())
|
||||
m_exporter->addDocument(doc, layer, frameTag, isTemporalTag);
|
||||
}
|
||||
else {
|
||||
m_exporter->addDocument(doc, nullptr, frameTag, isTemporalTag);
|
||||
@ -407,9 +404,10 @@ void CliProcessor::saveFile(const CliOpenFile& cof)
|
||||
}
|
||||
|
||||
// Store in "visibility" the original "visible" state of every layer.
|
||||
std::vector<bool> visibility(doc->sprite()->countLayers());
|
||||
LayerList allLayers = doc->sprite()->allLayers();
|
||||
std::vector<bool> visibility(allLayers.size());
|
||||
int i = 0;
|
||||
for (doc::Layer* layer : doc->sprite()->layers())
|
||||
for (doc::Layer* layer : allLayers)
|
||||
visibility[i++] = layer->isVisible();
|
||||
|
||||
std::string fn = cof.filename;
|
||||
@ -427,13 +425,13 @@ void CliProcessor::saveFile(const CliOpenFile& cof)
|
||||
std::vector<doc::Layer*> layers;
|
||||
// --save-as with --split-layers or --split-tags
|
||||
if (cof.splitLayers) {
|
||||
for (doc::Layer* layer : doc->sprite()->layers())
|
||||
for (doc::Layer* layer : doc->sprite()->allVisibleLayers())
|
||||
layers.push_back(layer);
|
||||
}
|
||||
else {
|
||||
// Show only one layer
|
||||
if (!cof.importLayer.empty()) {
|
||||
for (Layer* layer : doc->sprite()->layers()) {
|
||||
for (Layer* layer : allLayers) {
|
||||
if (layer->name() == cof.importLayer) {
|
||||
layer->setVisible(true);
|
||||
layers.push_back(layer);
|
||||
@ -481,7 +479,7 @@ void CliProcessor::saveFile(const CliOpenFile& cof)
|
||||
continue; // Just ignore this layer.
|
||||
|
||||
// Make this layer ("show") the only one visible.
|
||||
for (doc::Layer* hide : doc->sprite()->layers())
|
||||
for (doc::Layer* hide : allLayers)
|
||||
hide->setVisible(hide == layer);
|
||||
}
|
||||
|
||||
@ -521,7 +519,7 @@ void CliProcessor::saveFile(const CliOpenFile& cof)
|
||||
|
||||
// Restore layer visibility
|
||||
i = 0;
|
||||
for (Layer* layer : doc->sprite()->layers())
|
||||
for (Layer* layer : allLayers)
|
||||
layer->setVisible(visibility[i++]);
|
||||
|
||||
// Undo crop
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "base/convert_to.h"
|
||||
#include "doc/frame_tag.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/layers_range.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "script/engine_delegate.h"
|
||||
|
||||
@ -53,10 +52,8 @@ void DefaultCliDelegate::afterOpenFile(const CliOpenFile& cof)
|
||||
return;
|
||||
|
||||
if (cof.listLayers) {
|
||||
for (doc::Layer* layer : cof.document->sprite()->layers()) {
|
||||
if (layer->isVisible())
|
||||
std::cout << layer->name() << "\n";
|
||||
}
|
||||
for (doc::Layer* layer : cof.document->sprite()->allVisibleLayers())
|
||||
std::cout << layer->name() << "\n";
|
||||
}
|
||||
|
||||
if (cof.listTags) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -13,6 +13,9 @@
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
// Uncomment this in case you want to check what Cmd is being executed on each step
|
||||
//#define TRACE_CMD
|
||||
|
||||
namespace app {
|
||||
|
||||
Cmd::Cmd()
|
||||
@ -28,7 +31,9 @@ Cmd::~Cmd()
|
||||
|
||||
void Cmd::execute(Context* ctx)
|
||||
{
|
||||
#if TRACE_CMD
|
||||
TRACE("Cmd: Executing cmd '%s'\n", typeid(*this).name());
|
||||
#endif
|
||||
ASSERT(m_state == State::NotExecuted);
|
||||
|
||||
m_ctx = ctx;
|
||||
@ -43,7 +48,9 @@ void Cmd::execute(Context* ctx)
|
||||
|
||||
void Cmd::undo()
|
||||
{
|
||||
#if TRACE_CMD
|
||||
TRACE("Cmd: Undo cmd '%s'\n", typeid(*this).name());
|
||||
#endif
|
||||
ASSERT(m_state == State::Executed || m_state == State::Redone);
|
||||
|
||||
onUndo();
|
||||
@ -56,7 +63,9 @@ void Cmd::undo()
|
||||
|
||||
void Cmd::redo()
|
||||
{
|
||||
#if TRACE_CMD
|
||||
TRACE("Cmd: Redo cmd '%s'\n", typeid(*this).name());
|
||||
#endif
|
||||
ASSERT(m_state == State::Undone);
|
||||
|
||||
onRedo();
|
||||
|
@ -39,6 +39,8 @@ void AddCel::onExecute()
|
||||
{
|
||||
Layer* layer = this->layer();
|
||||
Cel* cel = this->cel();
|
||||
ASSERT(layer);
|
||||
ASSERT(cel);
|
||||
|
||||
addCel(layer, cel);
|
||||
}
|
||||
@ -47,6 +49,8 @@ void AddCel::onUndo()
|
||||
{
|
||||
Layer* layer = this->layer();
|
||||
Cel* cel = this->cel();
|
||||
ASSERT(layer);
|
||||
ASSERT(cel);
|
||||
|
||||
// Save the CelData only if the cel isn't linked
|
||||
bool has_data = (cel->links() == 0);
|
||||
@ -64,6 +68,7 @@ void AddCel::onUndo()
|
||||
void AddCel::onRedo()
|
||||
{
|
||||
Layer* layer = this->layer();
|
||||
ASSERT(layer);
|
||||
|
||||
SubObjectsFromSprite io(layer->sprite());
|
||||
bool has_data = (read8(m_stream) != 0);
|
||||
@ -75,6 +80,7 @@ void AddCel::onRedo()
|
||||
io.addCelDataRef(celdata);
|
||||
}
|
||||
Cel* cel = read_cel(m_stream, &io);
|
||||
ASSERT(cel);
|
||||
|
||||
addCel(layer, cel);
|
||||
|
||||
|
@ -22,8 +22,8 @@ namespace cmd {
|
||||
|
||||
using namespace doc;
|
||||
|
||||
AddLayer::AddLayer(Layer* folder, Layer* newLayer, Layer* afterThis)
|
||||
: m_folder(folder)
|
||||
AddLayer::AddLayer(Layer* group, Layer* newLayer, Layer* afterThis)
|
||||
: m_group(group)
|
||||
, m_newLayer(newLayer)
|
||||
, m_afterThis(afterThis)
|
||||
, m_size(0)
|
||||
@ -32,61 +32,62 @@ AddLayer::AddLayer(Layer* folder, Layer* newLayer, Layer* afterThis)
|
||||
|
||||
void AddLayer::onExecute()
|
||||
{
|
||||
Layer* folder = m_folder.layer();
|
||||
Layer* group = m_group.layer();
|
||||
Layer* newLayer = m_newLayer.layer();
|
||||
Layer* afterThis = m_afterThis.layer();
|
||||
|
||||
addLayer(folder, newLayer, afterThis);
|
||||
addLayer(group, newLayer, afterThis);
|
||||
}
|
||||
|
||||
void AddLayer::onUndo()
|
||||
{
|
||||
Layer* folder = m_folder.layer();
|
||||
Layer* group = m_group.layer();
|
||||
Layer* layer = m_newLayer.layer();
|
||||
|
||||
write_layer(m_stream, layer);
|
||||
m_size = size_t(m_stream.tellp());
|
||||
|
||||
removeLayer(folder, layer);
|
||||
removeLayer(group, layer);
|
||||
}
|
||||
|
||||
void AddLayer::onRedo()
|
||||
{
|
||||
Layer* folder = m_folder.layer();
|
||||
SubObjectsFromSprite io(folder->sprite());
|
||||
Layer* group = m_group.layer();
|
||||
SubObjectsFromSprite io(group->sprite());
|
||||
Layer* newLayer = read_layer(m_stream, &io);
|
||||
Layer* afterThis = m_afterThis.layer();
|
||||
|
||||
addLayer(folder, newLayer, afterThis);
|
||||
addLayer(group, newLayer, afterThis);
|
||||
|
||||
m_stream.str(std::string());
|
||||
m_stream.clear();
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
void AddLayer::addLayer(Layer* folder, Layer* newLayer, Layer* afterThis)
|
||||
void AddLayer::addLayer(Layer* group, Layer* newLayer, Layer* afterThis)
|
||||
{
|
||||
static_cast<LayerFolder*>(folder)->addLayer(newLayer);
|
||||
static_cast<LayerFolder*>(folder)->stackLayer(newLayer, afterThis);
|
||||
folder->incrementVersion();
|
||||
static_cast<LayerGroup*>(group)->insertLayer(newLayer, afterThis);
|
||||
group->incrementVersion();
|
||||
group->sprite()->incrementVersion();
|
||||
|
||||
Document* doc = folder->sprite()->document();
|
||||
Document* doc = group->sprite()->document();
|
||||
DocumentEvent ev(doc);
|
||||
ev.sprite(folder->sprite());
|
||||
ev.sprite(group->sprite());
|
||||
ev.layer(newLayer);
|
||||
doc->notifyObservers<DocumentEvent&>(&DocumentObserver::onAddLayer, ev);
|
||||
}
|
||||
|
||||
void AddLayer::removeLayer(Layer* folder, Layer* layer)
|
||||
void AddLayer::removeLayer(Layer* group, Layer* layer)
|
||||
{
|
||||
Document* doc = folder->sprite()->document();
|
||||
Document* doc = group->sprite()->document();
|
||||
DocumentEvent ev(doc);
|
||||
ev.sprite(layer->sprite());
|
||||
ev.layer(layer);
|
||||
doc->notifyObservers<DocumentEvent&>(&DocumentObserver::onBeforeRemoveLayer, ev);
|
||||
|
||||
static_cast<LayerFolder*>(folder)->removeLayer(layer);
|
||||
folder->incrementVersion();
|
||||
static_cast<LayerGroup*>(group)->removeLayer(layer);
|
||||
group->incrementVersion();
|
||||
layer->sprite()->incrementVersion();
|
||||
|
||||
doc->notifyObservers<DocumentEvent&>(&DocumentObserver::onAfterRemoveLayer, ev);
|
||||
|
||||
|
@ -24,7 +24,7 @@ namespace cmd {
|
||||
|
||||
class AddLayer : public Cmd {
|
||||
public:
|
||||
AddLayer(Layer* folder, Layer* newLayer, Layer* afterThis);
|
||||
AddLayer(Layer* group, Layer* newLayer, Layer* afterThis);
|
||||
|
||||
protected:
|
||||
void onExecute() override;
|
||||
@ -35,10 +35,10 @@ namespace cmd {
|
||||
}
|
||||
|
||||
private:
|
||||
void addLayer(Layer* folder, Layer* newLayer, Layer* afterThis);
|
||||
void removeLayer(Layer* folder, Layer* layer);
|
||||
void addLayer(Layer* group, Layer* newLayer, Layer* afterThis);
|
||||
void removeLayer(Layer* group, Layer* layer);
|
||||
|
||||
WithLayer m_folder;
|
||||
WithLayer m_group;
|
||||
WithLayer m_newLayer;
|
||||
WithLayer m_afterThis;
|
||||
size_t m_size;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -15,6 +15,7 @@
|
||||
#include "app/cmd/set_layer_flags.h"
|
||||
#include "app/cmd/set_layer_name.h"
|
||||
#include "app/cmd/set_layer_opacity.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
namespace app {
|
||||
namespace cmd {
|
||||
@ -33,7 +34,7 @@ ConfigureBackground::ConfigureBackground(Layer* layer)
|
||||
add(new cmd::SetLayerOpacity(static_cast<LayerImage*>(layer), 255));
|
||||
}
|
||||
|
||||
add(new cmd::MoveLayer(layer, nullptr));
|
||||
add(new cmd::MoveLayer(layer, layer->sprite()->root(), nullptr));
|
||||
}
|
||||
|
||||
} // namespace cmd
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -41,8 +41,7 @@ void CopyFrame::onExecute()
|
||||
if (fromFrame >= m_newFrame)
|
||||
++fromFrame;
|
||||
|
||||
for (int i=0; i<sprite->countLayers(); ++i) {
|
||||
Layer* layer = sprite->layer(i);
|
||||
for (Layer* layer : sprite->allLayers()) {
|
||||
if (layer->isImage()) {
|
||||
executeAndAdd(new cmd::CopyCel(
|
||||
static_cast<LayerImage*>(layer), fromFrame,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -56,7 +56,7 @@ void FlattenLayers::onExecute()
|
||||
// Create a new transparent layer to flatten everything onto.
|
||||
flatLayer = new LayerImage(sprite);
|
||||
ASSERT(flatLayer->isVisible());
|
||||
executeAndAdd(new cmd::AddLayer(sprite->folder(), flatLayer, nullptr));
|
||||
executeAndAdd(new cmd::AddLayer(sprite->root(), flatLayer, nullptr));
|
||||
executeAndAdd(new cmd::SetLayerName(flatLayer, "Flattened"));
|
||||
bgcolor = sprite->transparentColor();
|
||||
}
|
||||
@ -92,7 +92,7 @@ void FlattenLayers::onExecute()
|
||||
}
|
||||
|
||||
// Delete old layers.
|
||||
LayerList layers = sprite->folder()->getLayersList();
|
||||
LayerList layers = sprite->root()->layers();
|
||||
for (Layer* layer : layers)
|
||||
if (layer != flatLayer)
|
||||
executeAndAdd(new cmd::RemoveLayer(layer));
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -21,29 +21,53 @@ namespace cmd {
|
||||
|
||||
using namespace doc;
|
||||
|
||||
MoveLayer::MoveLayer(Layer* layer, Layer* afterThis)
|
||||
MoveLayer::MoveLayer(Layer* layer,
|
||||
Layer* newParent,
|
||||
Layer* afterThis)
|
||||
: m_layer(layer)
|
||||
, m_oldParent(layer->parent())
|
||||
, m_oldAfterThis(layer->getPrevious())
|
||||
, m_newAfterThis(afterThis)
|
||||
, m_newParent(newParent)
|
||||
, m_newAfterThis(afterThis == layer ? afterThis->getPrevious(): afterThis)
|
||||
{
|
||||
}
|
||||
|
||||
void MoveLayer::onExecute()
|
||||
{
|
||||
m_layer.layer()->parent()->stackLayer(
|
||||
m_layer.layer(),
|
||||
m_newAfterThis.layer());
|
||||
Layer* layer = m_layer.layer();
|
||||
Layer* afterThis = m_newAfterThis.layer();
|
||||
LayerGroup* oldParent = static_cast<LayerGroup*>(m_oldParent.layer());
|
||||
LayerGroup* newParent = static_cast<LayerGroup*>(m_newParent.layer());
|
||||
ASSERT(layer);
|
||||
ASSERT(oldParent);
|
||||
ASSERT(newParent);
|
||||
|
||||
m_layer.layer()->parent()->incrementVersion();
|
||||
oldParent->removeLayer(layer);
|
||||
newParent->insertLayer(layer, afterThis);
|
||||
|
||||
if (oldParent != newParent)
|
||||
oldParent->incrementVersion();
|
||||
newParent->incrementVersion();
|
||||
layer->sprite()->incrementVersion();
|
||||
}
|
||||
|
||||
void MoveLayer::onUndo()
|
||||
{
|
||||
m_layer.layer()->parent()->stackLayer(
|
||||
m_layer.layer(),
|
||||
m_oldAfterThis.layer());
|
||||
Layer* layer = m_layer.layer();
|
||||
Layer* afterThis = m_oldAfterThis.layer();
|
||||
LayerGroup* oldParent = static_cast<LayerGroup*>(m_oldParent.layer());
|
||||
LayerGroup* newParent = static_cast<LayerGroup*>(m_newParent.layer());
|
||||
ASSERT(layer);
|
||||
ASSERT(oldParent);
|
||||
ASSERT(newParent);
|
||||
|
||||
m_layer.layer()->parent()->incrementVersion();
|
||||
newParent->removeLayer(layer);
|
||||
oldParent->insertLayer(layer, afterThis);
|
||||
|
||||
if (oldParent != newParent)
|
||||
oldParent->incrementVersion();
|
||||
newParent->incrementVersion();
|
||||
layer->sprite()->incrementVersion();
|
||||
}
|
||||
|
||||
void MoveLayer::onFireNotifications()
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -18,7 +18,9 @@ namespace cmd {
|
||||
|
||||
class MoveLayer : public Cmd {
|
||||
public:
|
||||
MoveLayer(Layer* layer, Layer* afterThis);
|
||||
MoveLayer(Layer* layer,
|
||||
Layer* newParent,
|
||||
Layer* afterThis);
|
||||
|
||||
protected:
|
||||
void onExecute() override;
|
||||
@ -30,8 +32,8 @@ namespace cmd {
|
||||
|
||||
private:
|
||||
WithLayer m_layer;
|
||||
WithLayer m_oldAfterThis;
|
||||
WithLayer m_newAfterThis;
|
||||
WithLayer m_oldParent, m_oldAfterThis;
|
||||
WithLayer m_newParent, m_newAfterThis;
|
||||
};
|
||||
|
||||
} // namespace cmd
|
||||
|
@ -65,7 +65,7 @@ std::string CmdTransaction::onLabel() const
|
||||
doc::SpritePosition CmdTransaction::calcSpritePosition()
|
||||
{
|
||||
doc::Site site = context()->activeSite();
|
||||
return doc::SpritePosition(site.layerIndex(), site.frame());
|
||||
return doc::SpritePosition(site.layer(), site.frame());
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -108,9 +108,8 @@ private:
|
||||
else if (m_range.enabled()) {
|
||||
Sprite* sprite = m_document->sprite();
|
||||
int count = 0;
|
||||
for (Cel* cel : sprite->uniqueCels(m_range.frameBegin(),
|
||||
m_range.frameEnd())) {
|
||||
if (m_range.inRange(sprite->layerToIndex(cel->layer()))) {
|
||||
for (Cel* cel : sprite->uniqueCels(m_range.selectedFrames())) {
|
||||
if (m_range.contains(cel->layer())) {
|
||||
if (backgroundCount && cel->layer()->isBackground())
|
||||
++(*backgroundCount);
|
||||
++count;
|
||||
@ -170,37 +169,28 @@ private:
|
||||
ContextWriter writer(UIContext::instance());
|
||||
Transaction transaction(writer.context(), "Set Cel Properties");
|
||||
|
||||
if (count == 1 && m_cel) {
|
||||
if (!m_cel->layer()->isBackground() &&
|
||||
newOpacity != m_cel->opacity()) {
|
||||
transaction.execute(new cmd::SetCelOpacity(writer.cel(), newOpacity));
|
||||
}
|
||||
|
||||
if (m_userData != m_cel->data()->userData()) {
|
||||
transaction.execute(new cmd::SetUserData(writer.cel()->data(), m_userData));
|
||||
|
||||
// Redraw timeline because the cel's user data/color
|
||||
// might have changed.
|
||||
App::instance()->timeline()->invalidate();
|
||||
}
|
||||
DocumentRange range;
|
||||
if (m_range.enabled())
|
||||
range = m_range;
|
||||
else {
|
||||
range.startRange(m_cel->layer(), m_cel->frame(), DocumentRange::kCels);
|
||||
range.endRange(m_cel->layer(), m_cel->frame());
|
||||
}
|
||||
else if (m_range.enabled()) {
|
||||
Sprite* sprite = m_document->sprite();
|
||||
for (Cel* cel : sprite->uniqueCels(m_range.frameBegin(),
|
||||
m_range.frameEnd())) {
|
||||
if (m_range.inRange(sprite->layerToIndex(cel->layer()))) {
|
||||
if (!cel->layer()->isBackground() && newOpacity != cel->opacity()) {
|
||||
transaction.execute(new cmd::SetCelOpacity(cel, newOpacity));
|
||||
}
|
||||
|
||||
if (m_newUserData &&
|
||||
m_userData != cel->data()->userData()) {
|
||||
transaction.execute(new cmd::SetUserData(cel->data(), m_userData));
|
||||
Sprite* sprite = m_document->sprite();
|
||||
for (Cel* cel : sprite->uniqueCels(range.selectedFrames())) {
|
||||
if (range.contains(cel->layer())) {
|
||||
if (!cel->layer()->isBackground() && newOpacity != cel->opacity()) {
|
||||
transaction.execute(new cmd::SetCelOpacity(cel, newOpacity));
|
||||
}
|
||||
|
||||
// Redraw timeline because the cel's user data/color
|
||||
// might have changed.
|
||||
App::instance()->timeline()->invalidate();
|
||||
}
|
||||
if (m_newUserData &&
|
||||
m_userData != cel->data()->userData()) {
|
||||
transaction.execute(new cmd::SetUserData(cel->data(), m_userData));
|
||||
|
||||
// Redraw timeline because the cel's user data/color
|
||||
// might have changed.
|
||||
App::instance()->timeline()->invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
@ -53,33 +52,29 @@ void ClearCelCommand::onExecute(Context* context)
|
||||
{
|
||||
Transaction transaction(writer.context(), "Clear Cel");
|
||||
|
||||
// TODO the range of selected frames should be in doc::Site.
|
||||
auto range = App::instance()->timeline()->range();
|
||||
if (range.enabled()) {
|
||||
Sprite* sprite = writer.sprite();
|
||||
|
||||
for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) {
|
||||
Layer* layer = sprite->indexToLayer(layerIdx);
|
||||
const Site* site = writer.site();
|
||||
if (site->inTimeline() &&
|
||||
!site->selectedLayers().empty() &&
|
||||
!site->selectedFrames().empty()) {
|
||||
for (Layer* layer : site->selectedLayers()) {
|
||||
if (!layer->isImage())
|
||||
continue;
|
||||
|
||||
if (!layer->isEditableHierarchy()) {
|
||||
nonEditableLayers = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
LayerImage* layerImage = static_cast<LayerImage*>(layer);
|
||||
|
||||
for (frame_t frame = range.frameEnd(),
|
||||
begin = range.frameBegin()-1;
|
||||
frame != begin;
|
||||
--frame) {
|
||||
if (layerImage->cel(frame)) {
|
||||
if (layerImage->isEditable())
|
||||
document->getApi(transaction).clearCel(layerImage, frame);
|
||||
else
|
||||
nonEditableLayers = true;
|
||||
}
|
||||
for (frame_t frame : site->selectedFrames().reversed()) {
|
||||
if (layerImage->cel(frame))
|
||||
document->getApi(transaction).clearCel(layerImage, frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (writer.cel()) {
|
||||
if (writer.layer()->isEditable())
|
||||
if (writer.layer()->isEditableHierarchy())
|
||||
document->getApi(transaction).clearCel(writer.cel());
|
||||
else
|
||||
nonEditableLayers = true;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -58,7 +58,9 @@ void DuplicateLayerCommand::onExecute(Context* context)
|
||||
Transaction transaction(writer.context(), "Layer Duplication");
|
||||
LayerImage* sourceLayer = static_cast<LayerImage*>(writer.layer());
|
||||
DocumentApi api = document->getApi(transaction);
|
||||
api.duplicateLayerAfter(sourceLayer, sourceLayer);
|
||||
api.duplicateLayerAfter(sourceLayer,
|
||||
sourceLayer->parent(),
|
||||
sourceLayer);
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ namespace {
|
||||
// TODO the range of selected frames should be in doc::Site.
|
||||
auto range = App::instance()->timeline()->range();
|
||||
if (range.enabled()) {
|
||||
return range.frameBegin();
|
||||
return range.firstFrame();
|
||||
}
|
||||
else if (current_editor) {
|
||||
return current_editor->frame();
|
||||
@ -176,7 +176,7 @@ namespace {
|
||||
static frame_t To() {
|
||||
auto range = App::instance()->timeline()->range();
|
||||
if (range.enabled()) {
|
||||
return range.frameEnd();
|
||||
return range.lastFrame();
|
||||
}
|
||||
else if (current_editor) {
|
||||
return current_editor->frame();
|
||||
@ -218,20 +218,20 @@ namespace {
|
||||
if (!range.enabled()) {
|
||||
if (current_editor) {
|
||||
ASSERT(current_editor->sprite() == sprite);
|
||||
range.startRange(sprite->layerToIndex(current_editor->layer()),
|
||||
range.clearRange();
|
||||
range.startRange(current_editor->layer(),
|
||||
current_editor->frame(), DocumentRange::kCels);
|
||||
range.endRange(sprite->layerToIndex(current_editor->layer()),
|
||||
range.endRange(current_editor->layer(),
|
||||
current_editor->frame());
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Layer*> layers;
|
||||
sprite->getLayersList(layers);
|
||||
LayerList layers = sprite->allLayers();
|
||||
for (int i=0; i<int(layers.size()); ++i) {
|
||||
Layer* layer = layers[i];
|
||||
bool selected = range.inRange(LayerIndex(i));
|
||||
bool selected = range.contains(layer);
|
||||
|
||||
if (selected != layer->isVisible()) {
|
||||
m_restore.push_back(std::make_pair(layer, layer->isVisible()));
|
||||
@ -251,11 +251,23 @@ public:
|
||||
class LayerItem : public ListItem {
|
||||
public:
|
||||
LayerItem(Layer* layer)
|
||||
: ListItem("Layer: " + layer->name())
|
||||
: ListItem(buildName(layer))
|
||||
, m_layer(layer) {
|
||||
}
|
||||
Layer* layer() const { return m_layer; }
|
||||
private:
|
||||
static std::string buildName(const Layer* layer) {
|
||||
bool isGroup = layer->isGroup();
|
||||
std::string name;
|
||||
while (layer != layer->sprite()->root()) {
|
||||
if (!name.empty())
|
||||
name.insert(0, " > ");
|
||||
name.insert(0, layer->name());
|
||||
layer = layer->parent();
|
||||
}
|
||||
name.insert(0, isGroup ? "Group: ": "Layer: ");
|
||||
return name;
|
||||
}
|
||||
Layer* m_layer;
|
||||
};
|
||||
|
||||
@ -297,9 +309,9 @@ public:
|
||||
if (m_docPref.spriteSheet.layer() == kSelectedLayers)
|
||||
layers()->setSelectedItemIndex(i);
|
||||
{
|
||||
std::vector<Layer*> layersList;
|
||||
m_sprite->getLayersList(layersList);
|
||||
for (Layer* layer : layersList) {
|
||||
LayerList layersList = m_sprite->allLayers();
|
||||
for (auto it=layersList.rbegin(), end=layersList.rend(); it!=end; ++it) {
|
||||
Layer* layer = *it;
|
||||
i = layers()->addItem(new LayerItem(layer));
|
||||
if (m_docPref.spriteSheet.layer() == layer->name())
|
||||
layers()->setSelectedItemIndex(i);
|
||||
@ -837,8 +849,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
|
||||
}
|
||||
else {
|
||||
// TODO add a getLayerByName
|
||||
std::vector<Layer*> layers;
|
||||
sprite->getLayersList(layers);
|
||||
LayerList layers = sprite->allLayers();
|
||||
for (Layer* l : layers) {
|
||||
if (l->name() == layerName) {
|
||||
layer = l;
|
||||
|
@ -10,11 +10,11 @@
|
||||
#endif
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/context.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/commands/params.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/document_api.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "app/transaction.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "doc/sprite.h"
|
||||
@ -82,51 +82,58 @@ void FramePropertiesCommand::onExecute(Context* context)
|
||||
const Sprite* sprite = reader.sprite();
|
||||
|
||||
app::gen::FrameProperties window;
|
||||
frame_t firstFrame = 0;
|
||||
frame_t lastFrame = 0;
|
||||
SelectedFrames selFrames;
|
||||
|
||||
switch (m_target) {
|
||||
|
||||
case ALL_FRAMES:
|
||||
lastFrame = sprite->lastFrame();
|
||||
selFrames.insert(0, sprite->lastFrame());
|
||||
break;
|
||||
|
||||
case CURRENT_RANGE: {
|
||||
// TODO the range of selected frames should be in doc::Site.
|
||||
auto range = App::instance()->timeline()->range();
|
||||
if (range.enabled()) {
|
||||
firstFrame = range.frameBegin();
|
||||
lastFrame = range.frameEnd();
|
||||
Site site = context->activeSite();
|
||||
if (site.inTimeline()) {
|
||||
selFrames = site.selectedFrames();
|
||||
}
|
||||
else {
|
||||
firstFrame = lastFrame = reader.frame();
|
||||
selFrames.insert(site.frame());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SPECIFIC_FRAME:
|
||||
firstFrame = lastFrame = m_frame;
|
||||
selFrames.insert(m_frame);
|
||||
break;
|
||||
}
|
||||
|
||||
if (firstFrame != lastFrame)
|
||||
window.frame()->setTextf("[%d...%d]", (int)firstFrame+1, (int)lastFrame+1);
|
||||
else
|
||||
window.frame()->setTextf("%d", (int)firstFrame+1);
|
||||
ASSERT(!selFrames.empty());
|
||||
if (selFrames.empty())
|
||||
return;
|
||||
|
||||
window.frlen()->setTextf("%d", sprite->frameDuration(firstFrame));
|
||||
if (selFrames.size() == 1)
|
||||
window.frame()->setTextf("%d", selFrames.firstFrame()+1);
|
||||
else if (selFrames.ranges() == 1) {
|
||||
window.frame()->setTextf("[%d...%d]",
|
||||
selFrames.firstFrame()+1,
|
||||
selFrames.lastFrame()+1);
|
||||
}
|
||||
else
|
||||
window.frame()->setTextf("Multiple Frames");
|
||||
|
||||
window.frlen()->setTextf(
|
||||
"%d", sprite->frameDuration(selFrames.firstFrame()));
|
||||
|
||||
window.openWindowInForeground();
|
||||
if (window.closer() == window.ok()) {
|
||||
int num = window.frlen()->textInt();
|
||||
int newMsecs = window.frlen()->textInt();
|
||||
|
||||
ContextWriter writer(reader);
|
||||
Transaction transaction(writer.context(), "Frame Duration");
|
||||
DocumentApi api = writer.document()->getApi(transaction);
|
||||
if (firstFrame != lastFrame)
|
||||
api.setFrameRangeDuration(writer.sprite(), firstFrame, lastFrame, num);
|
||||
else
|
||||
api.setFrameDuration(writer.sprite(), firstFrame, num);
|
||||
|
||||
for (frame_t frame : selFrames)
|
||||
api.setFrameDuration(writer.sprite(), frame, newMsecs);
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -16,104 +16,98 @@
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
class GotoCommand : public Command {
|
||||
class GotoLayerCommand : public Command {
|
||||
public:
|
||||
GotoCommand(const char* short_name, const char* friendly_name, CommandFlags flags)
|
||||
: Command(short_name, friendly_name, flags) {
|
||||
GotoLayerCommand(int offset,
|
||||
const char* shortName,
|
||||
const char* friendlyName,
|
||||
CommandFlags flags)
|
||||
: Command(shortName, friendlyName, flags),
|
||||
m_offset(offset) {
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool onEnabled(Context* context) override {
|
||||
return (current_editor &&
|
||||
current_editor->document());
|
||||
}
|
||||
|
||||
void onExecute(Context* context) override {
|
||||
Site site = current_editor->getSite();
|
||||
|
||||
Layer* layer = site.layer();
|
||||
if (!layer)
|
||||
return;
|
||||
|
||||
if (m_offset > 0) {
|
||||
int i = m_offset;
|
||||
while (i-- > 0) {
|
||||
layer = layer->getNextInWholeHierarchy();
|
||||
if (!layer)
|
||||
layer = site.sprite()->firstBrowsableLayer();
|
||||
}
|
||||
}
|
||||
else if (m_offset < 0) {
|
||||
int i = m_offset;
|
||||
while (i++ < 0) {
|
||||
layer = layer->getPreviousInWholeHierarchy();
|
||||
if (!layer)
|
||||
layer = site.sprite()->root()->lastLayer();
|
||||
}
|
||||
}
|
||||
|
||||
site.layer(layer);
|
||||
|
||||
// Flash the current layer
|
||||
current_editor->setLayer(site.layer());
|
||||
current_editor->flashCurrentLayer();
|
||||
|
||||
updateStatusBar(site);
|
||||
}
|
||||
|
||||
void updateStatusBar(Site& site) {
|
||||
if (site.layer() != NULL)
|
||||
StatusBar::instance()
|
||||
->setStatusText(1000, "Layer `%s' selected",
|
||||
site.layer()->name().c_str());
|
||||
StatusBar::instance()->setStatusText(
|
||||
1000, "%s '%s' selected",
|
||||
(site.layer()->isGroup() ? "Group": "Layer"),
|
||||
site.layer()->name().c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
int m_offset;
|
||||
};
|
||||
|
||||
class GotoPreviousLayerCommand : public GotoLayerCommand {
|
||||
public:
|
||||
GotoPreviousLayerCommand()
|
||||
: GotoLayerCommand(-1, "GotoPreviousLayer",
|
||||
"Go to Previous Layer",
|
||||
CmdUIOnlyFlag) {
|
||||
}
|
||||
Command* clone() const override {
|
||||
return new GotoPreviousLayerCommand(*this);
|
||||
}
|
||||
};
|
||||
|
||||
class GotoPreviousLayerCommand : public GotoCommand {
|
||||
class GotoNextLayerCommand : public GotoLayerCommand {
|
||||
public:
|
||||
GotoPreviousLayerCommand();
|
||||
Command* clone() const override { return new GotoPreviousLayerCommand(*this); }
|
||||
|
||||
protected:
|
||||
bool onEnabled(Context* context) override;
|
||||
void onExecute(Context* context) override;
|
||||
GotoNextLayerCommand()
|
||||
: GotoLayerCommand(+1, "GotoNextLayer",
|
||||
"Go to Next Layer",
|
||||
CmdUIOnlyFlag) {
|
||||
}
|
||||
Command* clone() const override {
|
||||
return new GotoNextLayerCommand(*this);
|
||||
}
|
||||
};
|
||||
|
||||
GotoPreviousLayerCommand::GotoPreviousLayerCommand()
|
||||
: GotoCommand("GotoPreviousLayer",
|
||||
"Go to Previous Layer",
|
||||
CmdUIOnlyFlag)
|
||||
{
|
||||
}
|
||||
|
||||
bool GotoPreviousLayerCommand::onEnabled(Context* context)
|
||||
{
|
||||
return (current_editor != nullptr &&
|
||||
current_editor->document());
|
||||
}
|
||||
|
||||
void GotoPreviousLayerCommand::onExecute(Context* context)
|
||||
{
|
||||
Site site = current_editor->getSite();
|
||||
|
||||
if (site.layerIndex() > 0)
|
||||
site.layerIndex(site.layerIndex().previous());
|
||||
else
|
||||
site.layerIndex(LayerIndex(site.sprite()->countLayers()-1));
|
||||
|
||||
// Flash the current layer
|
||||
current_editor->setLayer(site.layer());
|
||||
current_editor->flashCurrentLayer();
|
||||
|
||||
updateStatusBar(site);
|
||||
}
|
||||
|
||||
class GotoNextLayerCommand : public GotoCommand {
|
||||
public:
|
||||
GotoNextLayerCommand();
|
||||
Command* clone() const override { return new GotoNextLayerCommand(*this); }
|
||||
|
||||
protected:
|
||||
bool onEnabled(Context* context) override;
|
||||
void onExecute(Context* context) override;
|
||||
};
|
||||
|
||||
GotoNextLayerCommand::GotoNextLayerCommand()
|
||||
: GotoCommand("GotoNextLayer",
|
||||
"Go to Next Layer",
|
||||
CmdUIOnlyFlag)
|
||||
{
|
||||
}
|
||||
|
||||
bool GotoNextLayerCommand::onEnabled(Context* context)
|
||||
{
|
||||
return (current_editor != nullptr &&
|
||||
current_editor->document());
|
||||
}
|
||||
|
||||
void GotoNextLayerCommand::onExecute(Context* context)
|
||||
{
|
||||
Site site = current_editor->getSite();
|
||||
|
||||
if (site.layerIndex() < site.sprite()->countLayers()-1)
|
||||
site.layerIndex(site.layerIndex().next());
|
||||
else
|
||||
site.layerIndex(LayerIndex(0));
|
||||
|
||||
// Flash the current layer
|
||||
current_editor->setLayer(site.layer());
|
||||
current_editor->flashCurrentLayer();
|
||||
|
||||
updateStatusBar(site);
|
||||
}
|
||||
|
||||
Command* CommandFactory::createGotoPreviousLayerCommand()
|
||||
{
|
||||
return new GotoPreviousLayerCommand;
|
||||
|
@ -394,7 +394,7 @@ void ImportSpriteSheetCommand::onExecute(Context* context)
|
||||
DocumentApi api = document->getApi(transaction);
|
||||
|
||||
// Add the layer in the sprite.
|
||||
LayerImage* resultLayer = api.newLayer(sprite, "Sprite Sheet");
|
||||
LayerImage* resultLayer = api.newLayer(sprite->root(), "Sprite Sheet");
|
||||
|
||||
// Add all frames+cels to the new layer
|
||||
for (size_t i=0; i<animation.size(); ++i) {
|
||||
@ -407,12 +407,12 @@ void ImportSpriteSheetCommand::onExecute(Context* context)
|
||||
}
|
||||
|
||||
// Copy the list of layers (because we will modify it in the iteration).
|
||||
LayerList layers = sprite->folder()->getLayersList();
|
||||
LayerList layers = sprite->root()->layers();
|
||||
|
||||
// Remove all other layers
|
||||
for (LayerIterator it=layers.begin(), end=layers.end(); it!=end; ++it) {
|
||||
if (*it != resultLayer)
|
||||
api.removeLayer(*it);
|
||||
for (Layer* child : layers) {
|
||||
if (child != resultLayer)
|
||||
api.removeLayer(child);
|
||||
}
|
||||
|
||||
// Change the number of frames
|
||||
|
@ -96,14 +96,14 @@ public:
|
||||
UIContext::instance()->removeObserver(this);
|
||||
}
|
||||
|
||||
void setLayer(LayerImage* layer) {
|
||||
void setLayer(Layer* layer) {
|
||||
if (m_layer) {
|
||||
document()->removeObserver(this);
|
||||
m_layer = nullptr;
|
||||
}
|
||||
|
||||
m_timer.stop();
|
||||
m_layer = const_cast<LayerImage*>(layer);
|
||||
m_layer = layer;
|
||||
|
||||
if (m_layer)
|
||||
document()->addObserver(this);
|
||||
@ -178,9 +178,10 @@ private:
|
||||
BlendMode newBlendMode = blendModeValue();
|
||||
|
||||
if (newName != m_layer->name() ||
|
||||
newOpacity != m_layer->opacity() ||
|
||||
newBlendMode != m_layer->blendMode() ||
|
||||
m_userData != m_layer->userData()) {
|
||||
m_userData != m_layer->userData() ||
|
||||
(m_layer->isImage() &&
|
||||
(newOpacity != static_cast<LayerImage*>(m_layer)->opacity() ||
|
||||
newBlendMode != static_cast<LayerImage*>(m_layer)->blendMode()))) {
|
||||
try {
|
||||
ContextWriter writer(UIContext::instance());
|
||||
Transaction transaction(writer.context(), "Set Layer Properties");
|
||||
@ -188,20 +189,21 @@ private:
|
||||
if (newName != m_layer->name())
|
||||
transaction.execute(new cmd::SetLayerName(writer.layer(), newName));
|
||||
|
||||
if (newOpacity != m_layer->opacity())
|
||||
transaction.execute(new cmd::SetLayerOpacity(static_cast<LayerImage*>(writer.layer()), newOpacity));
|
||||
|
||||
if (newBlendMode != m_layer->blendMode())
|
||||
transaction.execute(new cmd::SetLayerBlendMode(static_cast<LayerImage*>(writer.layer()), newBlendMode));
|
||||
|
||||
if (m_userData != m_layer->userData()) {
|
||||
if (m_userData != m_layer->userData())
|
||||
transaction.execute(new cmd::SetUserData(writer.layer(), m_userData));
|
||||
|
||||
// Redraw timeline because the layer's user data/color
|
||||
// might have changed.
|
||||
App::instance()->timeline()->invalidate();
|
||||
if (m_layer->isImage()) {
|
||||
if (newOpacity != static_cast<LayerImage*>(m_layer)->opacity())
|
||||
transaction.execute(new cmd::SetLayerOpacity(static_cast<LayerImage*>(writer.layer()), newOpacity));
|
||||
|
||||
if (newBlendMode != static_cast<LayerImage*>(m_layer)->blendMode())
|
||||
transaction.execute(new cmd::SetLayerBlendMode(static_cast<LayerImage*>(writer.layer()), newBlendMode));
|
||||
}
|
||||
|
||||
// Redraw timeline because the layer's name/user data/color
|
||||
// might have changed.
|
||||
App::instance()->timeline()->invalidate();
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
@ -215,7 +217,7 @@ private:
|
||||
// ContextObserver impl
|
||||
void onActiveSiteChange(const Site& site) override {
|
||||
if (isVisible())
|
||||
setLayer(dynamic_cast<LayerImage*>(const_cast<Layer*>(site.layer())));
|
||||
setLayer(const_cast<Layer*>(site.layer()));
|
||||
else if (m_layer)
|
||||
setLayer(nullptr);
|
||||
}
|
||||
@ -256,10 +258,18 @@ private:
|
||||
if (m_layer) {
|
||||
name()->setText(m_layer->name().c_str());
|
||||
name()->setEnabled(true);
|
||||
mode()->setSelectedItemIndex((int)m_layer->blendMode());
|
||||
mode()->setEnabled(!m_layer->isBackground());
|
||||
opacity()->setValue(m_layer->opacity());
|
||||
opacity()->setEnabled(!m_layer->isBackground());
|
||||
|
||||
if (m_layer->isImage()) {
|
||||
mode()->setSelectedItemIndex((int)static_cast<LayerImage*>(m_layer)->blendMode());
|
||||
mode()->setEnabled(!m_layer->isBackground());
|
||||
opacity()->setValue(static_cast<LayerImage*>(m_layer)->opacity());
|
||||
opacity()->setEnabled(!m_layer->isBackground());
|
||||
}
|
||||
else {
|
||||
mode()->setEnabled(false);
|
||||
opacity()->setEnabled(false);
|
||||
}
|
||||
|
||||
m_userData = m_layer->userData();
|
||||
}
|
||||
else {
|
||||
@ -272,7 +282,7 @@ private:
|
||||
}
|
||||
|
||||
Timer m_timer;
|
||||
LayerImage* m_layer;
|
||||
Layer* m_layer;
|
||||
bool m_selfUpdate;
|
||||
UserData m_userData;
|
||||
};
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
@ -43,9 +42,9 @@ LinkCelsCommand::LinkCelsCommand()
|
||||
bool LinkCelsCommand::onEnabled(Context* context)
|
||||
{
|
||||
if (context->checkFlags(ContextFlags::ActiveDocumentIsWritable)) {
|
||||
// TODO the range of selected frames should be in doc::Site.
|
||||
auto range = App::instance()->timeline()->range();
|
||||
return (range.enabled() && range.frames() > 1);
|
||||
auto site = context->activeSite();
|
||||
return (site.inTimeline() &&
|
||||
site.selectedFrames().size() > 1);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
@ -57,36 +56,33 @@ void LinkCelsCommand::onExecute(Context* context)
|
||||
Document* document(writer.document());
|
||||
bool nonEditableLayers = false;
|
||||
{
|
||||
// TODO the range of selected frames should be in doc::Site.
|
||||
auto range = App::instance()->timeline()->range();
|
||||
if (!range.enabled())
|
||||
auto site = context->activeSite();
|
||||
if (!site.inTimeline())
|
||||
return;
|
||||
|
||||
Transaction transaction(writer.context(), friendlyName());
|
||||
Sprite* sprite = writer.sprite();
|
||||
frame_t begin = range.frameBegin();
|
||||
frame_t end = range.frameEnd();
|
||||
|
||||
for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) {
|
||||
Layer* layer = sprite->indexToLayer(layerIdx);
|
||||
for (Layer* layer : site.selectedLayers()) {
|
||||
if (!layer->isImage())
|
||||
continue;
|
||||
|
||||
if (!layer->isEditable()) {
|
||||
if (!layer->isEditableHierarchy()) {
|
||||
nonEditableLayers = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
LayerImage* layerImage = static_cast<LayerImage*>(layer);
|
||||
for (frame_t frame=begin; frame < end+1; ++frame) {
|
||||
|
||||
for (auto it=site.selectedFrames().begin(), end=site.selectedFrames().end();
|
||||
it != end; ++it) {
|
||||
frame_t frame = *it;
|
||||
Cel* cel = layerImage->cel(frame);
|
||||
if (cel) {
|
||||
for (frame = cel->frame()+1;
|
||||
frame < end+1; ++frame) {
|
||||
for (++it; it != end; ++it) {
|
||||
transaction.execute(
|
||||
new cmd::CopyCel(
|
||||
layerImage, cel->frame(),
|
||||
layerImage, frame,
|
||||
layerImage, *it,
|
||||
true)); // true = force links
|
||||
}
|
||||
break;
|
||||
|
@ -178,7 +178,7 @@ void NewFileCommand::onExecute(Context* context)
|
||||
// If the background color isn't transparent, we have to
|
||||
// convert the `Layer 1' in a `Background'
|
||||
if (color.getType() != app::Color::MaskType) {
|
||||
Layer* layer = sprite->folder()->getFirstLayer();
|
||||
Layer* layer = sprite->root()->firstLayer();
|
||||
|
||||
if (layer && layer->isImage()) {
|
||||
LayerImage* layerImage = static_cast<LayerImage*>(layer);
|
||||
|
@ -106,34 +106,37 @@ void NewFrameCommand::onExecute(Context* context)
|
||||
|
||||
case Content::DUPLICATE_CELS:
|
||||
case Content::DUPLICATE_CELS_BLOCK: {
|
||||
// TODO the range of selected frames should be in doc::Site.
|
||||
Timeline* timeline = App::instance()->timeline();
|
||||
Timeline::Range range = timeline->range();
|
||||
if (range.enabled()) {
|
||||
const Site* site = writer.site();
|
||||
if (site->inTimeline() &&
|
||||
!site->selectedLayers().empty() &&
|
||||
!site->selectedFrames().empty()) {
|
||||
std::map<CelData*, Cel*> relatedCels;
|
||||
|
||||
auto timeline = App::instance()->timeline();
|
||||
timeline->prepareToMoveRange();
|
||||
DocumentRange range = timeline->range();
|
||||
|
||||
LayerIndex layerBegin = range.layerBegin();
|
||||
LayerIndex layerEnd = range.layerEnd();
|
||||
SelectedLayers selLayers;
|
||||
if (site->inFrames())
|
||||
selLayers.selectAllLayers(writer.sprite()->root());
|
||||
else
|
||||
selLayers = site->selectedLayers();
|
||||
|
||||
if (range.type() == DocumentRange::kFrames) {
|
||||
layerBegin = writer.sprite()->firstLayer();
|
||||
layerEnd = writer.sprite()->lastLayer();
|
||||
}
|
||||
frame_t frameRange =
|
||||
(site->selectedFrames().lastFrame() -
|
||||
site->selectedFrames().firstFrame() + 1);
|
||||
|
||||
for (LayerIndex layer = layerBegin; layer <= layerEnd; ++layer) {
|
||||
Layer* layerPtr = writer.sprite()->indexToLayer(layer);
|
||||
if (layerPtr->isImage()) {
|
||||
for (frame_t frame = range.frameEnd(); frame >= range.frameBegin(); --frame) {
|
||||
frame_t srcFrame = frame;
|
||||
frame_t dstFrame = frame+range.frames();
|
||||
for (Layer* layer : selLayers) {
|
||||
if (layer->isImage()) {
|
||||
for (frame_t srcFrame : site->selectedFrames().reversed()) {
|
||||
frame_t dstFrame = srcFrame+frameRange;
|
||||
bool continuous;
|
||||
CelData* srcCelData = nullptr;
|
||||
|
||||
if (m_content == Content::DUPLICATE_CELS_BLOCK) {
|
||||
continuous = false;
|
||||
|
||||
Cel* srcCel = static_cast<LayerImage*>(layerPtr)->cel(srcFrame);
|
||||
Cel* srcCel = static_cast<LayerImage*>(layer)->cel(srcFrame);
|
||||
if (srcCel) {
|
||||
srcCelData = srcCel->data();
|
||||
|
||||
@ -145,19 +148,19 @@ void NewFrameCommand::onExecute(Context* context)
|
||||
}
|
||||
}
|
||||
else
|
||||
continuous = layerPtr->isContinuous();
|
||||
continuous = layer->isContinuous();
|
||||
|
||||
api.copyCel(
|
||||
static_cast<LayerImage*>(layerPtr), srcFrame,
|
||||
static_cast<LayerImage*>(layerPtr), dstFrame, continuous);
|
||||
static_cast<LayerImage*>(layer), srcFrame,
|
||||
static_cast<LayerImage*>(layer), dstFrame, continuous);
|
||||
|
||||
if (srcCelData && !relatedCels[srcCelData])
|
||||
relatedCels[srcCelData] = layerPtr->cel(dstFrame);
|
||||
relatedCels[srcCelData] = layer->cel(dstFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
range.displace(0, range.frames());
|
||||
range.displace(0, frameRange);
|
||||
timeline->moveRange(range);
|
||||
}
|
||||
else {
|
||||
|
@ -59,8 +59,8 @@ void NewFrameTagCommand::onExecute(Context* context)
|
||||
if (range.enabled() &&
|
||||
(range.type() == DocumentRange::kFrames ||
|
||||
range.type() == DocumentRange::kCels)) {
|
||||
from = range.frameBegin();
|
||||
to = range.frameEnd();
|
||||
from = range.selectedFrames().firstFrame();
|
||||
to = range.selectedFrames().lastFrame();
|
||||
}
|
||||
|
||||
base::UniquePtr<FrameTag> frameTag(new FrameTag(from, to));
|
||||
|
@ -10,6 +10,7 @@
|
||||
#endif
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/cmd/move_layer.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/commands/params.h"
|
||||
#include "app/context_access.h"
|
||||
@ -24,6 +25,8 @@
|
||||
#include "doc/sprite.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
#include "new_layer.xml.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
@ -42,14 +45,16 @@ protected:
|
||||
void onExecute(Context* context) override;
|
||||
|
||||
private:
|
||||
std::string getUniqueLayerName(const Sprite* sprite) const;
|
||||
int getMaxLayerNum(const Layer* layer) const;
|
||||
const char* layerPrefix() const;
|
||||
|
||||
bool m_ask;
|
||||
bool m_top;
|
||||
bool m_group;
|
||||
std::string m_name;
|
||||
};
|
||||
|
||||
static std::string get_unique_layer_name(Sprite* sprite);
|
||||
static int get_max_layer_num(Layer* layer);
|
||||
|
||||
NewLayerCommand::NewLayerCommand()
|
||||
: Command("NewLayer",
|
||||
"New Layer",
|
||||
@ -57,6 +62,7 @@ NewLayerCommand::NewLayerCommand()
|
||||
{
|
||||
m_ask = false;
|
||||
m_top = false;
|
||||
m_group = false;
|
||||
m_name = "";
|
||||
}
|
||||
|
||||
@ -64,6 +70,7 @@ void NewLayerCommand::onLoadParams(const Params& params)
|
||||
{
|
||||
m_ask = (params.get("ask") == "true");
|
||||
m_top = (params.get("top") == "true");
|
||||
m_group = (params.get("group") == "true");
|
||||
m_name = params.get("name");
|
||||
}
|
||||
|
||||
@ -84,66 +91,113 @@ void NewLayerCommand::onExecute(Context* context)
|
||||
if (!m_name.empty())
|
||||
name = m_name;
|
||||
else
|
||||
name = get_unique_layer_name(sprite);
|
||||
name = getUniqueLayerName(sprite);
|
||||
|
||||
// If params specify to ask the user about the name...
|
||||
if (m_ask) {
|
||||
// We open the window to ask the name
|
||||
base::UniquePtr<Window> window(app::load_widget<Window>("new_layer.xml", "new_layer"));
|
||||
Widget* name_widget = app::find_widget<Widget>(window, "name");
|
||||
name_widget->setText(name.c_str());
|
||||
name_widget->setMinSize(gfx::Size(128, 0));
|
||||
|
||||
window->openWindowInForeground();
|
||||
|
||||
if (window->closer() != window->findChild("ok"))
|
||||
app::gen::NewLayer window;
|
||||
window.name()->setText(name.c_str());
|
||||
window.name()->setMinSize(gfx::Size(128, 0));
|
||||
window.openWindowInForeground();
|
||||
if (window.closer() != window.ok())
|
||||
return;
|
||||
|
||||
name = window->findChild("name")->text();
|
||||
name = window.name()->text();
|
||||
}
|
||||
|
||||
LayerGroup* parent = sprite->root();
|
||||
Layer* activeLayer = writer.layer();
|
||||
SelectedLayers selLayers = writer.site()->selectedLayers();
|
||||
if (activeLayer) {
|
||||
if (activeLayer->isGroup() &&
|
||||
activeLayer->isExpanded() &&
|
||||
!m_group) {
|
||||
parent = static_cast<LayerGroup*>(activeLayer);
|
||||
activeLayer = nullptr;
|
||||
}
|
||||
else {
|
||||
parent = activeLayer->parent();
|
||||
}
|
||||
}
|
||||
|
||||
Layer* layer;
|
||||
{
|
||||
Transaction transaction(writer.context(), "New Layer");
|
||||
Transaction transaction(
|
||||
writer.context(),
|
||||
std::string("New ") + layerPrefix());
|
||||
DocumentApi api = document->getApi(transaction);
|
||||
layer = api.newLayer(sprite, name);
|
||||
|
||||
if (m_group)
|
||||
layer = api.newGroup(parent, name);
|
||||
else
|
||||
layer = api.newLayer(parent, name);
|
||||
|
||||
ASSERT(layer->parent());
|
||||
|
||||
// If "top" parameter is false, create the layer above the active
|
||||
// one.
|
||||
if (activeLayer && !m_top)
|
||||
api.restackLayerAfter(layer, activeLayer);
|
||||
if (activeLayer && !m_top) {
|
||||
api.restackLayerAfter(layer,
|
||||
activeLayer->parent(),
|
||||
activeLayer);
|
||||
|
||||
// Put all selected layers inside the group
|
||||
if (m_group && writer.site()->inTimeline()) {
|
||||
LayerGroup* commonParent = nullptr;
|
||||
layer_t sameParents = 0;
|
||||
for (Layer* l : selLayers) {
|
||||
if (!commonParent ||
|
||||
commonParent == l->parent()) {
|
||||
commonParent = l->parent();
|
||||
++sameParents;
|
||||
}
|
||||
}
|
||||
|
||||
if (sameParents == selLayers.size()) {
|
||||
for (Layer* newChild : selLayers.toLayerList()) {
|
||||
transaction.execute(
|
||||
new cmd::MoveLayer(newChild, layer,
|
||||
static_cast<LayerGroup*>(layer)->lastLayer()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
update_screen_for_document(document);
|
||||
|
||||
StatusBar::instance()->invalidate();
|
||||
StatusBar::instance()->showTip(1000, "Layer `%s' created", name.c_str());
|
||||
StatusBar::instance()->showTip(
|
||||
1000, "%s '%s' created",
|
||||
layerPrefix(),
|
||||
name.c_str());
|
||||
|
||||
App::instance()->mainWindow()->popTimeline();
|
||||
}
|
||||
|
||||
static std::string get_unique_layer_name(Sprite* sprite)
|
||||
std::string NewLayerCommand::getUniqueLayerName(const Sprite* sprite) const
|
||||
{
|
||||
char buf[1024];
|
||||
std::sprintf(buf, "Layer %d", get_max_layer_num(sprite->folder())+1);
|
||||
std::sprintf(buf, "%s %d",
|
||||
layerPrefix(),
|
||||
getMaxLayerNum(sprite->root())+1);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int get_max_layer_num(Layer* layer)
|
||||
int NewLayerCommand::getMaxLayerNum(const Layer* layer) const
|
||||
{
|
||||
std::string prefix = layerPrefix();
|
||||
prefix += " ";
|
||||
|
||||
int max = 0;
|
||||
if (std::strncmp(layer->name().c_str(), prefix.c_str(), prefix.size()) == 0)
|
||||
max = std::strtol(layer->name().c_str()+prefix.size(), NULL, 10);
|
||||
|
||||
if (std::strncmp(layer->name().c_str(), "Layer ", 6) == 0)
|
||||
max = std::strtol(layer->name().c_str()+6, NULL, 10);
|
||||
|
||||
if (layer->isFolder()) {
|
||||
LayerIterator it = static_cast<LayerFolder*>(layer)->getLayerBegin();
|
||||
LayerIterator end = static_cast<LayerFolder*>(layer)->getLayerEnd();
|
||||
|
||||
for (; it != end; ++it) {
|
||||
int tmp = get_max_layer_num(*it);
|
||||
if (layer->isGroup()) {
|
||||
for (const Layer* child : static_cast<const LayerGroup*>(layer)->layers()) {
|
||||
int tmp = getMaxLayerNum(child);
|
||||
max = MAX(tmp, max);
|
||||
}
|
||||
}
|
||||
@ -151,6 +205,11 @@ static int get_max_layer_num(Layer* layer)
|
||||
return max;
|
||||
}
|
||||
|
||||
const char* NewLayerCommand::layerPrefix() const
|
||||
{
|
||||
return (m_group ? "Group": "Layer");
|
||||
}
|
||||
|
||||
Command* CommandFactory::createNewLayerCommand()
|
||||
{
|
||||
return new NewLayerCommand;
|
||||
|
@ -1,87 +0,0 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/document_api.h"
|
||||
#include "app/document_api.h"
|
||||
#include "app/find_widget.h"
|
||||
#include "app/load_widget.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/transaction.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace ui;
|
||||
|
||||
class NewLayerSetCommand : public Command {
|
||||
public:
|
||||
NewLayerSetCommand();
|
||||
Command* clone() const override { return new NewLayerSetCommand(*this); }
|
||||
|
||||
protected:
|
||||
bool onEnabled(Context* context) override;
|
||||
void onExecute(Context* context) override;
|
||||
};
|
||||
|
||||
NewLayerSetCommand::NewLayerSetCommand()
|
||||
: Command("NewLayerSet",
|
||||
"New Layer Set",
|
||||
CmdRecordableFlag)
|
||||
{
|
||||
}
|
||||
|
||||
bool NewLayerSetCommand::onEnabled(Context* context)
|
||||
{
|
||||
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
||||
ContextFlags::HasActiveSprite);
|
||||
}
|
||||
|
||||
void NewLayerSetCommand::onExecute(Context* context)
|
||||
{
|
||||
ContextWriter writer(context);
|
||||
Document* document(writer.document());
|
||||
Sprite* sprite(writer.sprite());
|
||||
|
||||
// load the window widget
|
||||
base::UniquePtr<Window> window(app::load_widget<Window>("new_layer.xml", "new_layer_set"));
|
||||
|
||||
window->openWindowInForeground();
|
||||
|
||||
if (window->closer() != window->findChild("ok"))
|
||||
return;
|
||||
|
||||
std::string name = window->findChild("name")->text();
|
||||
Layer* layer;
|
||||
{
|
||||
Transaction transaction(writer.context(), "New Layer");
|
||||
layer = document->getApi(transaction).newLayerFolder(sprite);
|
||||
transaction.commit();
|
||||
}
|
||||
layer->setName(name);
|
||||
|
||||
update_screen_for_document(document);
|
||||
|
||||
StatusBar::instance()->invalidate();
|
||||
StatusBar::instance()->showTip(1000, "Layer `%s' created", name.c_str());
|
||||
}
|
||||
|
||||
Command* CommandFactory::createNewLayerSetCommand()
|
||||
{
|
||||
return new NewLayerSetCommand;
|
||||
}
|
||||
|
||||
} // namespace app
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -72,7 +72,7 @@ void NewSpriteFromSelectionCommand::onExecute(Context* context)
|
||||
|
||||
palette->copyColorsTo(dstSprite->palette(frame_t(0)));
|
||||
|
||||
LayerImage* dstLayer = static_cast<LayerImage*>(dstSprite->folder()->getFirstLayer());
|
||||
LayerImage* dstLayer = static_cast<LayerImage*>(dstSprite->root()->firstLayer());
|
||||
if (site.layer()->isBackground())
|
||||
dstLayer->configureAsBackground(); // Configure layer name as background
|
||||
dstLayer->setFlags(site.layer()->flags()); // Copy all flags
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "app/context_access.h"
|
||||
#include "app/document_api.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "app/transaction.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "ui/ui.h"
|
||||
@ -55,14 +54,10 @@ void RemoveFrameCommand::onExecute(Context* context)
|
||||
{
|
||||
Transaction transaction(writer.context(), "Remove Frame");
|
||||
DocumentApi api = document->getApi(transaction);
|
||||
|
||||
// TODO the range of selected frames should be in doc::Site.
|
||||
auto range = App::instance()->timeline()->range();
|
||||
if (range.enabled()) {
|
||||
for (frame_t frame = range.frameEnd(),
|
||||
begin = range.frameBegin()-1;
|
||||
frame != begin;
|
||||
--frame) {
|
||||
const Site* site = writer.site();
|
||||
if (site->inTimeline() &&
|
||||
!site->selectedFrames().empty()) {
|
||||
for (frame_t frame : site->selectedFrames().reversed()) {
|
||||
api.removeFrame(sprite, frame);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "app/document_api.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "app/transaction.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
@ -52,34 +51,43 @@ bool RemoveLayerCommand::onEnabled(Context* context)
|
||||
|
||||
void RemoveLayerCommand::onExecute(Context* context)
|
||||
{
|
||||
std::string layer_name;
|
||||
std::string layerName;
|
||||
ContextWriter writer(context);
|
||||
Document* document(writer.document());
|
||||
Sprite* sprite(writer.sprite());
|
||||
Layer* layer(writer.layer());
|
||||
{
|
||||
Transaction transaction(writer.context(), "Remove Layer");
|
||||
DocumentApi api = document->getApi(transaction);
|
||||
|
||||
// TODO the range of selected layer should be in doc::Site.
|
||||
auto range = App::instance()->timeline()->range();
|
||||
if (range.enabled()) {
|
||||
if (range.layers() == sprite->countLayers()) {
|
||||
const Site* site = writer.site();
|
||||
if (site->inTimeline() &&
|
||||
!site->selectedLayers().empty()) {
|
||||
SelectedLayers selLayers = site->selectedLayers();
|
||||
selLayers.removeChildrenIfParentIsSelected();
|
||||
|
||||
layer_t deletedTopLevelLayers = 0;
|
||||
for (Layer* layer : selLayers) {
|
||||
if (layer->parent() == sprite->root())
|
||||
++deletedTopLevelLayers;
|
||||
}
|
||||
|
||||
if (deletedTopLevelLayers == sprite->root()->layersCount()) {
|
||||
ui::Alert::show("Error<<You cannot delete all layers.||&OK");
|
||||
return;
|
||||
}
|
||||
|
||||
for (LayerIndex layer = range.layerEnd(); layer >= range.layerBegin(); --layer) {
|
||||
api.removeLayer(sprite->indexToLayer(layer));
|
||||
for (Layer* layer : selLayers) {
|
||||
api.removeLayer(layer);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (sprite->countLayers() == 1) {
|
||||
if (sprite->allLayersCount() == 1) {
|
||||
ui::Alert::show("Error<<You cannot delete the last layer.||&OK");
|
||||
return;
|
||||
}
|
||||
|
||||
layer_name = layer->name();
|
||||
Layer* layer = writer.layer();
|
||||
layerName = layer->name();
|
||||
api.removeLayer(layer);
|
||||
}
|
||||
|
||||
@ -88,8 +96,8 @@ void RemoveLayerCommand::onExecute(Context* context)
|
||||
update_screen_for_document(document);
|
||||
|
||||
StatusBar::instance()->invalidate();
|
||||
if (!layer_name.empty())
|
||||
StatusBar::instance()->showTip(1000, "Layer `%s' removed", layer_name.c_str());
|
||||
if (!layerName.empty())
|
||||
StatusBar::instance()->showTip(1000, "Layer '%s' removed", layerName.c_str());
|
||||
else
|
||||
StatusBar::instance()->showTip(1000, "Layers removed");
|
||||
}
|
||||
|
@ -85,8 +85,8 @@ void SetLoopSectionCommand::onExecute(Context* ctx)
|
||||
case Action::Auto: {
|
||||
auto range = App::instance()->timeline()->range();
|
||||
if (range.enabled() && (range.frames() > 1)) {
|
||||
begin = range.frameBegin();
|
||||
end = range.frameEnd();
|
||||
begin = range.selectedFrames().firstFrame();
|
||||
end = range.selectedFrames().lastFrame();
|
||||
on = true;
|
||||
}
|
||||
else {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -71,7 +71,7 @@ void UndoCommand::onExecute(Context* context)
|
||||
Preferences::instance().undo.gotoModified();
|
||||
|
||||
if (gotoModified) {
|
||||
SpritePosition currentPosition(writer.site()->layerIndex(),
|
||||
SpritePosition currentPosition(writer.site()->layer(),
|
||||
writer.site()->frame());
|
||||
|
||||
if (m_type == Undo)
|
||||
@ -80,7 +80,9 @@ void UndoCommand::onExecute(Context* context)
|
||||
spritePosition = undo->nextRedoSpritePosition();
|
||||
|
||||
if (spritePosition != currentPosition) {
|
||||
current_editor->setLayer(sprite->indexToLayer(spritePosition.layerIndex()));
|
||||
Layer* selectLayer = spritePosition.layer();
|
||||
if (selectLayer)
|
||||
current_editor->setLayer(selectLayer);
|
||||
current_editor->setFrame(spritePosition.frame());
|
||||
|
||||
// Draw the current layer/frame (which is not undone yet) so the
|
||||
@ -112,11 +114,13 @@ void UndoCommand::onExecute(Context* context)
|
||||
// weren't able to reach before the undo).
|
||||
if (gotoModified) {
|
||||
SpritePosition currentPosition(
|
||||
writer.site()->layerIndex(),
|
||||
writer.site()->layer(),
|
||||
writer.site()->frame());
|
||||
|
||||
if (spritePosition != currentPosition) {
|
||||
current_editor->setLayer(sprite->indexToLayer(spritePosition.layerIndex()));
|
||||
Layer* selectLayer = spritePosition.layer();
|
||||
if (selectLayer)
|
||||
current_editor->setLayer(selectLayer);
|
||||
current_editor->setFrame(spritePosition.frame());
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
@ -53,36 +52,31 @@ void UnlinkCelCommand::onExecute(Context* context)
|
||||
{
|
||||
Transaction transaction(writer.context(), "Unlink Cel");
|
||||
|
||||
// TODO the range of selected frames should be in doc::Site.
|
||||
auto range = App::instance()->timeline()->range();
|
||||
if (range.enabled()) {
|
||||
Sprite* sprite = writer.sprite();
|
||||
|
||||
for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) {
|
||||
Layer* layer = sprite->indexToLayer(layerIdx);
|
||||
const Site* site = writer.site();
|
||||
if (site->inTimeline() &&
|
||||
!site->selectedLayers().empty()) {
|
||||
for (Layer* layer : site->selectedLayers()) {
|
||||
if (!layer->isImage())
|
||||
continue;
|
||||
|
||||
if (!layer->isEditableHierarchy()) {
|
||||
nonEditableLayers = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
LayerImage* layerImage = static_cast<LayerImage*>(layer);
|
||||
|
||||
for (frame_t frame = range.frameEnd(),
|
||||
begin = range.frameBegin()-1;
|
||||
frame != begin;
|
||||
--frame) {
|
||||
for (frame_t frame : site->selectedFrames().reversed()) {
|
||||
Cel* cel = layerImage->cel(frame);
|
||||
if (cel && cel->links()) {
|
||||
if (layerImage->isEditable())
|
||||
transaction.execute(new cmd::UnlinkCel(cel));
|
||||
else
|
||||
nonEditableLayers = true;
|
||||
}
|
||||
if (cel && cel->links())
|
||||
transaction.execute(new cmd::UnlinkCel(cel));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Cel* cel = writer.cel();
|
||||
if (cel && cel->links()) {
|
||||
if (cel->layer()->isEditable())
|
||||
if (cel->layer()->isEditableHierarchy())
|
||||
transaction.execute(new cmd::UnlinkCel(writer.cel()));
|
||||
else
|
||||
nonEditableLayers = true;
|
||||
|
@ -79,7 +79,6 @@ FOR_EACH_COMMAND(NewFile)
|
||||
FOR_EACH_COMMAND(NewFrame)
|
||||
FOR_EACH_COMMAND(NewFrameTag)
|
||||
FOR_EACH_COMMAND(NewLayer)
|
||||
FOR_EACH_COMMAND(NewLayerSet)
|
||||
FOR_EACH_COMMAND(NewSpriteFromSelection)
|
||||
FOR_EACH_COMMAND(OpenFile)
|
||||
FOR_EACH_COMMAND(OpenInFolder)
|
||||
|
@ -205,7 +205,7 @@ void FilterManagerImpl::applyToTarget()
|
||||
bool cancelled = false;
|
||||
|
||||
ImagesCollector images((m_target & TARGET_ALL_LAYERS ?
|
||||
m_site.sprite()->folder():
|
||||
m_site.sprite()->root():
|
||||
m_site.layer()),
|
||||
m_site.frame(),
|
||||
(m_target & TARGET_ALL_FRAMES) == TARGET_ALL_FRAMES,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -88,10 +88,10 @@ void ContextFlags::updateFlagsFromSite(const Site& site)
|
||||
if (layer->isBackground())
|
||||
m_flags |= ActiveLayerIsBackground;
|
||||
|
||||
if (layer->isVisible())
|
||||
if (layer->isVisibleHierarchy())
|
||||
m_flags |= ActiveLayerIsVisible;
|
||||
|
||||
if (layer->isEditable())
|
||||
if (layer->isEditableHierarchy())
|
||||
m_flags |= ActiveLayerIsEditable;
|
||||
|
||||
if (layer->isImage()) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -38,7 +38,10 @@ DataRecovery::DataRecovery(doc::Context* ctx)
|
||||
|
||||
SessionPtr session(new Session(itempath));
|
||||
if (!session->isRunning()) {
|
||||
if (!session->isEmpty()) {
|
||||
if (session->version() != VERSION) {
|
||||
TRACE("cannot be loaded (incompatible version)\n");
|
||||
}
|
||||
else if (!session->isEmpty()) {
|
||||
TRACE("to be loaded\n");
|
||||
m_sessions.push_back(session);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -240,11 +240,26 @@ private:
|
||||
// Read layers
|
||||
int nlayers = read32(s);
|
||||
if (nlayers >= 1 && nlayers < 0xfffff) {
|
||||
std::map<ObjectId, LayerGroup*> layersMap;
|
||||
layersMap[0] = spr->root(); // parentId = 0 is the root level
|
||||
|
||||
for (int i = 0; i < nlayers; ++i) {
|
||||
ObjectId layId = read32(s);
|
||||
ObjectId parentId = read32(s);
|
||||
|
||||
if (!layersMap[parentId]) {
|
||||
Console().printf("Inexistent parent #%d for layer #%d", parentId, layId);
|
||||
// Put this layer at the root level
|
||||
parentId = 0;
|
||||
}
|
||||
|
||||
Layer* lay = loadObject<Layer*>("lay", layId, &Reader::readLayer);
|
||||
if (lay)
|
||||
spr->folder()->addLayer(lay);
|
||||
if (lay) {
|
||||
if (lay->isGroup())
|
||||
layersMap[layId] = static_cast<LayerGroup*>(lay);
|
||||
|
||||
layersMap[parentId]->addLayer(lay);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -279,7 +294,8 @@ private:
|
||||
Layer* readLayer(std::ifstream& s) {
|
||||
LayerFlags flags = (LayerFlags)read32(s);
|
||||
ObjectType type = (ObjectType)read16(s);
|
||||
ASSERT(type == ObjectType::LayerImage);
|
||||
ASSERT(type == ObjectType::LayerImage ||
|
||||
type == ObjectType::LayerGroup);
|
||||
|
||||
std::string name = read_string(s);
|
||||
|
||||
@ -303,6 +319,12 @@ private:
|
||||
}
|
||||
return lay.release();
|
||||
}
|
||||
else if (type == ObjectType::LayerGroup) {
|
||||
base::UniquePtr<LayerGroup> lay(new LayerGroup(m_sprite));
|
||||
lay->setName(name);
|
||||
lay->setFlags(flags);
|
||||
return lay.release();
|
||||
}
|
||||
else {
|
||||
Console().printf("Unable to load layer named '%s', type #%d\n",
|
||||
name.c_str(), (int)type);
|
||||
@ -396,7 +418,7 @@ app::Document* read_document_with_raw_images(const std::string& dir,
|
||||
|
||||
// Load each image as a new frame
|
||||
auto lay = new LayerImage(spr);
|
||||
spr->folder()->addLayer(lay);
|
||||
spr->root()->addLayer(lay);
|
||||
|
||||
frame_t frame = 0;
|
||||
for (const auto& fn : base::list_files(dir)) {
|
||||
@ -421,7 +443,7 @@ app::Document* read_document_with_raw_images(const std::string& dir,
|
||||
break;
|
||||
case RawImagesAs::kLayers:
|
||||
lay = new LayerImage(spr);
|
||||
spr->folder()->addLayer(lay);
|
||||
spr->root()->addLayer(lay);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,19 @@ std::string Session::name() const
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string Session::version()
|
||||
{
|
||||
if (m_version.empty()) {
|
||||
std::string verfile = verFilename();
|
||||
if (base::is_file(verfile)) {
|
||||
std::ifstream pf(FSTREAM_PATH(verfile));
|
||||
if (pf)
|
||||
pf >> m_version;
|
||||
}
|
||||
}
|
||||
return m_version;
|
||||
}
|
||||
|
||||
const Session::Backups& Session::backups()
|
||||
{
|
||||
if (m_backups.empty()) {
|
||||
|
@ -41,6 +41,7 @@ namespace crash {
|
||||
~Session();
|
||||
|
||||
std::string name() const;
|
||||
std::string version();
|
||||
const Backups& backups();
|
||||
|
||||
bool isRunning();
|
||||
@ -65,8 +66,7 @@ namespace crash {
|
||||
|
||||
base::pid m_pid;
|
||||
std::string m_path;
|
||||
std::fstream m_log;
|
||||
std::fstream m_pidFile;
|
||||
std::string m_version;
|
||||
Backups m_backups;
|
||||
|
||||
DISABLE_COPYING(Session);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -76,8 +76,8 @@ public:
|
||||
for (Cel* cel : spr->cels())
|
||||
saveObject("cel", cel, &Writer::writeCel);
|
||||
|
||||
std::vector<Layer*> layers;
|
||||
spr->getLayersList(layers);
|
||||
// Save all layers (top level, groups, children, etc.)
|
||||
LayerList layers = spr->allLayers();
|
||||
for (Layer* lay : layers)
|
||||
saveObject("lay", lay, &Writer::writeLayerStructure);
|
||||
|
||||
@ -104,11 +104,8 @@ private:
|
||||
write32(s, spr->frameDuration(fr));
|
||||
|
||||
// IDs of all main layers
|
||||
std::vector<Layer*> layers;
|
||||
spr->getLayersList(layers);
|
||||
write32(s, layers.size());
|
||||
for (Layer* lay : layers)
|
||||
write32(s, lay->id());
|
||||
write32(s, spr->allLayersCount());
|
||||
writeAllLayersID(s, 0, spr->root());
|
||||
|
||||
// IDs of all palettes
|
||||
write32(s, spr->getPalettes().size());
|
||||
@ -121,21 +118,40 @@ private:
|
||||
write32(s, frtag->id());
|
||||
}
|
||||
|
||||
void writeAllLayersID(std::ofstream& s, ObjectId parentId, const LayerGroup* group) {
|
||||
for (const Layer* lay : group->layers()) {
|
||||
write32(s, lay->id());
|
||||
write32(s, parentId);
|
||||
|
||||
if (lay->isGroup())
|
||||
writeAllLayersID(s, lay->id(), static_cast<const LayerGroup*>(lay));
|
||||
}
|
||||
}
|
||||
|
||||
void writeLayerStructure(std::ofstream& s, Layer* lay) {
|
||||
write32(s, static_cast<int>(lay->flags())); // Flags
|
||||
write16(s, static_cast<int>(lay->type())); // Type
|
||||
write_string(s, lay->name());
|
||||
|
||||
if (lay->type() == ObjectType::LayerImage) {
|
||||
CelConstIterator it, begin = static_cast<const LayerImage*>(lay)->getCelBegin();
|
||||
CelConstIterator end = static_cast<const LayerImage*>(lay)->getCelEnd();
|
||||
switch (lay->type()) {
|
||||
|
||||
// Cels
|
||||
write32(s, static_cast<const LayerImage*>(lay)->getCelsCount());
|
||||
for (it=begin; it != end; ++it) {
|
||||
const Cel* cel = *it;
|
||||
write32(s, cel->id());
|
||||
case ObjectType::LayerImage: {
|
||||
CelConstIterator it, begin = static_cast<const LayerImage*>(lay)->getCelBegin();
|
||||
CelConstIterator end = static_cast<const LayerImage*>(lay)->getCelEnd();
|
||||
|
||||
// Cels
|
||||
write32(s, static_cast<const LayerImage*>(lay)->getCelsCount());
|
||||
for (it=begin; it != end; ++it) {
|
||||
const Cel* cel = *it;
|
||||
write32(s, cel->id());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ObjectType::LayerGroup:
|
||||
// Do nothing (the layer parent/children structure is saved in
|
||||
// writeSprite/writeAllLayersID() functions)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,23 +324,19 @@ void Document::copyLayerContent(const Layer* sourceLayer0, Document* destDoc, La
|
||||
newCel.release();
|
||||
}
|
||||
}
|
||||
else if (sourceLayer0->isFolder() && destLayer0->isFolder()) {
|
||||
const LayerFolder* sourceLayer = static_cast<const LayerFolder*>(sourceLayer0);
|
||||
LayerFolder* destLayer = static_cast<LayerFolder*>(destLayer0);
|
||||
else if (sourceLayer0->isGroup() && destLayer0->isGroup()) {
|
||||
const LayerGroup* sourceLayer = static_cast<const LayerGroup*>(sourceLayer0);
|
||||
LayerGroup* destLayer = static_cast<LayerGroup*>(destLayer0);
|
||||
|
||||
LayerConstIterator it = sourceLayer->getLayerBegin();
|
||||
LayerConstIterator end = sourceLayer->getLayerEnd();
|
||||
|
||||
for (; it != end; ++it) {
|
||||
Layer* sourceChild = *it;
|
||||
for (Layer* sourceChild : sourceLayer->layers()) {
|
||||
base::UniquePtr<Layer> destChild(NULL);
|
||||
|
||||
if (sourceChild->isImage()) {
|
||||
destChild.reset(new LayerImage(destLayer->sprite()));
|
||||
copyLayerContent(sourceChild, destDoc, destChild);
|
||||
}
|
||||
else if (sourceChild->isFolder()) {
|
||||
destChild.reset(new LayerFolder(destLayer->sprite()));
|
||||
else if (sourceChild->isGroup()) {
|
||||
destChild.reset(new LayerGroup(destLayer->sprite()));
|
||||
copyLayerContent(sourceChild, destDoc, destChild);
|
||||
}
|
||||
else {
|
||||
@ -352,7 +348,7 @@ void Document::copyLayerContent(const Layer* sourceLayer0, Document* destDoc, La
|
||||
// Add the new layer in the sprite.
|
||||
|
||||
Layer* newLayer = destChild.release();
|
||||
Layer* afterThis = destLayer->getLastLayer();
|
||||
Layer* afterThis = destLayer->lastLayer();
|
||||
|
||||
destLayer->addLayer(newLayer);
|
||||
destChild.release();
|
||||
@ -400,8 +396,8 @@ Document* Document::duplicate(DuplicateType type) const
|
||||
switch (type) {
|
||||
|
||||
case DuplicateExactCopy:
|
||||
// Copy the layer folder
|
||||
copyLayerContent(sourceSprite->folder(), documentCopy, spriteCopy->folder());
|
||||
// Copy the layer group
|
||||
copyLayerContent(sourceSprite->root(), documentCopy, spriteCopy->root());
|
||||
|
||||
ASSERT((spriteCopy->backgroundLayer() && sourceSprite->backgroundLayer()) ||
|
||||
(!spriteCopy->backgroundLayer() && !sourceSprite->backgroundLayer()));
|
||||
@ -410,16 +406,16 @@ Document* Document::duplicate(DuplicateType type) const
|
||||
case DuplicateWithFlattenLayers:
|
||||
{
|
||||
// Flatten layers
|
||||
ASSERT(sourceSprite->folder() != NULL);
|
||||
ASSERT(sourceSprite->root() != NULL);
|
||||
|
||||
LayerImage* flatLayer = create_flatten_layer_copy
|
||||
(spriteCopy,
|
||||
sourceSprite->folder(),
|
||||
sourceSprite->root(),
|
||||
gfx::Rect(0, 0, sourceSprite->width(), sourceSprite->height()),
|
||||
frame_t(0), sourceSprite->lastFrame());
|
||||
|
||||
// Add and select the new flat layer
|
||||
spriteCopy->folder()->addLayer(flatLayer);
|
||||
spriteCopy->root()->addLayer(flatLayer);
|
||||
|
||||
// Configure the layer as background only if the original
|
||||
// sprite has a background layer.
|
||||
|
@ -82,8 +82,7 @@ void DocumentApi::cropSprite(Sprite* sprite, const gfx::Rect& bounds)
|
||||
setSpriteSize(sprite, bounds.w, bounds.h);
|
||||
|
||||
app::Document* doc = static_cast<app::Document*>(sprite->document());
|
||||
std::vector<Layer*> layers;
|
||||
sprite->getLayersList(layers);
|
||||
LayerList layers = sprite->allLayers();
|
||||
for (Layer* layer : layers) {
|
||||
if (!layer->isImage())
|
||||
continue;
|
||||
@ -238,7 +237,7 @@ void DocumentApi::moveFrame(Sprite* sprite, frame_t frame, frame_t beforeFrame)
|
||||
adjustFrameTags(sprite, beforeFrame, +1, true);
|
||||
|
||||
// Change cel positions.
|
||||
moveFrameLayer(sprite->folder(), frame, beforeFrame);
|
||||
moveFrameLayer(sprite->root(), frame, beforeFrame);
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,12 +288,9 @@ void DocumentApi::moveFrameLayer(Layer* layer, frame_t frame, frame_t beforeFram
|
||||
break;
|
||||
}
|
||||
|
||||
case ObjectType::LayerFolder: {
|
||||
LayerIterator it = static_cast<LayerFolder*>(layer)->getLayerBegin();
|
||||
LayerIterator end = static_cast<LayerFolder*>(layer)->getLayerEnd();
|
||||
|
||||
for (; it != end; ++it)
|
||||
moveFrameLayer(*it, frame, beforeFrame);
|
||||
case ObjectType::LayerGroup: {
|
||||
for (Layer* child : static_cast<LayerGroup*>(layer)->layers())
|
||||
moveFrameLayer(child, frame, beforeFrame);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -396,30 +392,27 @@ void DocumentApi::swapCel(
|
||||
if (cel2) setCelFramePosition(cel2, frame1);
|
||||
}
|
||||
|
||||
LayerImage* DocumentApi::newLayer(Sprite* sprite, const std::string& name)
|
||||
LayerImage* DocumentApi::newLayer(LayerGroup* parent, const std::string& name)
|
||||
{
|
||||
LayerImage* layer = new LayerImage(sprite);
|
||||
LayerImage* layer = new LayerImage(parent->sprite());
|
||||
layer->setName(name);
|
||||
|
||||
addLayer(sprite->folder(), layer,
|
||||
sprite->folder()->getLastLayer());
|
||||
|
||||
addLayer(parent, layer, parent->lastLayer());
|
||||
return layer;
|
||||
}
|
||||
|
||||
LayerFolder* DocumentApi::newLayerFolder(Sprite* sprite)
|
||||
LayerGroup* DocumentApi::newGroup(LayerGroup* parent, const std::string& name)
|
||||
{
|
||||
LayerFolder* layer = new LayerFolder(sprite);
|
||||
|
||||
addLayer(sprite->folder(), layer,
|
||||
sprite->folder()->getLastLayer());
|
||||
LayerGroup* layer = new LayerGroup(parent->sprite());
|
||||
layer->setName(name);
|
||||
|
||||
addLayer(parent, layer, parent->lastLayer());
|
||||
return layer;
|
||||
}
|
||||
|
||||
void DocumentApi::addLayer(LayerFolder* folder, Layer* newLayer, Layer* afterThis)
|
||||
void DocumentApi::addLayer(LayerGroup* parent, Layer* newLayer, Layer* afterThis)
|
||||
{
|
||||
m_transaction.execute(new cmd::AddLayer(folder, newLayer, afterThis));
|
||||
m_transaction.execute(new cmd::AddLayer(parent, newLayer, afterThis));
|
||||
}
|
||||
|
||||
void DocumentApi::removeLayer(Layer* layer)
|
||||
@ -429,17 +422,30 @@ void DocumentApi::removeLayer(Layer* layer)
|
||||
m_transaction.execute(new cmd::RemoveLayer(layer));
|
||||
}
|
||||
|
||||
void DocumentApi::restackLayerAfter(Layer* layer, Layer* afterThis)
|
||||
void DocumentApi::restackLayerAfter(Layer* layer, LayerGroup* parent, Layer* afterThis)
|
||||
{
|
||||
m_transaction.execute(new cmd::MoveLayer(layer, afterThis));
|
||||
ASSERT(parent);
|
||||
|
||||
if (layer == afterThis)
|
||||
return;
|
||||
|
||||
m_transaction.execute(new cmd::MoveLayer(layer, parent, afterThis));
|
||||
}
|
||||
|
||||
void DocumentApi::restackLayerBefore(Layer* layer, Layer* beforeThis)
|
||||
void DocumentApi::restackLayerBefore(Layer* layer, LayerGroup* parent, Layer* beforeThis)
|
||||
{
|
||||
LayerIndex beforeThisIdx = layer->sprite()->layerToIndex(beforeThis);
|
||||
LayerIndex afterThisIdx = beforeThisIdx.previous();
|
||||
ASSERT(parent);
|
||||
|
||||
restackLayerAfter(layer, layer->sprite()->indexToLayer(afterThisIdx));
|
||||
if (layer == beforeThis)
|
||||
return;
|
||||
|
||||
Layer* afterThis;
|
||||
if (beforeThis)
|
||||
afterThis = beforeThis->getPrevious();
|
||||
else
|
||||
afterThis = parent->lastLayer();
|
||||
|
||||
restackLayerAfter(layer, parent, afterThis);
|
||||
}
|
||||
|
||||
void DocumentApi::backgroundFromLayer(Layer* layer)
|
||||
@ -457,26 +463,36 @@ void DocumentApi::flattenLayers(Sprite* sprite)
|
||||
m_transaction.execute(new cmd::FlattenLayers(sprite));
|
||||
}
|
||||
|
||||
void DocumentApi::duplicateLayerAfter(Layer* sourceLayer, Layer* afterLayer)
|
||||
Layer* DocumentApi::duplicateLayerAfter(Layer* sourceLayer, LayerGroup* parent, Layer* afterLayer)
|
||||
{
|
||||
base::UniquePtr<LayerImage> newLayerPtr(new LayerImage(sourceLayer->sprite()));
|
||||
ASSERT(parent);
|
||||
base::UniquePtr<Layer> newLayerPtr;
|
||||
|
||||
if (sourceLayer->isImage())
|
||||
newLayerPtr.reset(new LayerImage(sourceLayer->sprite()));
|
||||
else if (sourceLayer->isGroup())
|
||||
newLayerPtr.reset(new LayerGroup(sourceLayer->sprite()));
|
||||
else
|
||||
throw std::runtime_error("Invalid layer type");
|
||||
|
||||
m_document->copyLayerContent(sourceLayer, m_document, newLayerPtr);
|
||||
|
||||
newLayerPtr->setName(newLayerPtr->name() + " Copy");
|
||||
|
||||
addLayer(sourceLayer->parent(), newLayerPtr, afterLayer);
|
||||
addLayer(parent, newLayerPtr, afterLayer);
|
||||
|
||||
// Release the pointer as it is owned by the sprite now.
|
||||
newLayerPtr.release();
|
||||
return newLayerPtr.release();
|
||||
}
|
||||
|
||||
void DocumentApi::duplicateLayerBefore(Layer* sourceLayer, Layer* beforeLayer)
|
||||
Layer* DocumentApi::duplicateLayerBefore(Layer* sourceLayer, LayerGroup* parent, Layer* beforeLayer)
|
||||
{
|
||||
LayerIndex beforeThisIdx = sourceLayer->sprite()->layerToIndex(beforeLayer);
|
||||
LayerIndex afterThisIdx = beforeThisIdx.previous();
|
||||
|
||||
duplicateLayerAfter(sourceLayer, sourceLayer->sprite()->indexToLayer(afterThisIdx));
|
||||
ASSERT(parent);
|
||||
Layer* afterThis = (beforeLayer ? beforeLayer->getPreviousInWholeHierarchy(): nullptr);
|
||||
Layer* newLayer = duplicateLayerAfter(sourceLayer, parent, afterThis);
|
||||
if (newLayer)
|
||||
restackLayerBefore(newLayer, parent, beforeLayer);
|
||||
return newLayer;
|
||||
}
|
||||
|
||||
Cel* DocumentApi::addCel(LayerImage* layer, frame_t frameNumber, const ImageRef& image)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -21,7 +21,7 @@ namespace doc {
|
||||
class Cel;
|
||||
class Image;
|
||||
class Layer;
|
||||
class LayerFolder;
|
||||
class LayerGroup;
|
||||
class LayerImage;
|
||||
class Mask;
|
||||
class Palette;
|
||||
@ -80,17 +80,17 @@ namespace app {
|
||||
LayerImage* layer, frame_t frame1, frame_t frame2);
|
||||
|
||||
// Layers API
|
||||
LayerImage* newLayer(Sprite* sprite, const std::string& name);
|
||||
LayerFolder* newLayerFolder(Sprite* sprite);
|
||||
void addLayer(LayerFolder* folder, Layer* newLayer, Layer* afterThis);
|
||||
LayerImage* newLayer(LayerGroup* parent, const std::string& name);
|
||||
LayerGroup* newGroup(LayerGroup* parent, const std::string& name);
|
||||
void addLayer(LayerGroup* parent, Layer* newLayer, Layer* afterThis);
|
||||
void removeLayer(Layer* layer);
|
||||
void restackLayerAfter(Layer* layer, Layer* afterThis);
|
||||
void restackLayerBefore(Layer* layer, Layer* beforeThis);
|
||||
void restackLayerAfter(Layer* layer, LayerGroup* parent, Layer* afterThis);
|
||||
void restackLayerBefore(Layer* layer, LayerGroup* parent, Layer* beforeThis);
|
||||
void backgroundFromLayer(Layer* layer);
|
||||
void layerFromBackground(Layer* layer);
|
||||
void flattenLayers(Sprite* sprite);
|
||||
void duplicateLayerAfter(Layer* sourceLayer, Layer* afterLayer);
|
||||
void duplicateLayerBefore(Layer* sourceLayer, Layer* beforeLayer);
|
||||
Layer* duplicateLayerAfter(Layer* sourceLayer, LayerGroup* parent, Layer* afterLayer);
|
||||
Layer* duplicateLayerBefore(Layer* sourceLayer, LayerGroup* parent, Layer* beforeLayer);
|
||||
|
||||
// Images API
|
||||
void replaceImage(Sprite* sprite, const ImageRef& oldImage, const ImageRef& newImage);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -22,13 +22,103 @@ using namespace doc;
|
||||
|
||||
typedef base::UniquePtr<app::Document> DocumentPtr;
|
||||
|
||||
TEST(DocumentApi, MoveCel) {
|
||||
TestContextT<app::Context> ctx;
|
||||
DocumentPtr doc(static_cast<app::Document*>(ctx.documents().add(32, 16)));
|
||||
Sprite* sprite = doc->sprite();
|
||||
LayerImage* layer1 = dynamic_cast<LayerImage*>(sprite->folder()->getFirstLayer());
|
||||
LayerImage* layer2 = new LayerImage(sprite);
|
||||
class BasicDocApiTest : public ::testing::Test {
|
||||
public:
|
||||
BasicDocApiTest() :
|
||||
doc((static_cast<app::Document*>(ctx.documents().add(32, 16)))),
|
||||
sprite(doc->sprite()),
|
||||
root(sprite->root()),
|
||||
layer1(dynamic_cast<LayerImage*>(sprite->root()->firstLayer())),
|
||||
layer2(new LayerImage(sprite)),
|
||||
layer3(new LayerImage(sprite))
|
||||
{
|
||||
root->addLayer(layer2);
|
||||
root->addLayer(layer3);
|
||||
}
|
||||
|
||||
~BasicDocApiTest() {
|
||||
doc->close();
|
||||
}
|
||||
|
||||
TestContextT<app::Context> ctx;
|
||||
DocumentPtr doc;
|
||||
Sprite* sprite;
|
||||
LayerGroup* root;
|
||||
LayerImage* layer1;
|
||||
LayerImage* layer2;
|
||||
LayerImage* layer3;
|
||||
};
|
||||
|
||||
TEST_F(BasicDocApiTest, RestackLayerBefore)
|
||||
{
|
||||
EXPECT_EQ(layer1, root->firstLayer());
|
||||
{
|
||||
Transaction transaction(&ctx, "");
|
||||
// Do nothing
|
||||
doc->getApi(transaction).restackLayerBefore(layer1, layer1->parent(), layer1);
|
||||
EXPECT_EQ(layer1, root->firstLayer());
|
||||
EXPECT_EQ(layer2, root->firstLayer()->getNext());
|
||||
EXPECT_EQ(layer3, root->firstLayer()->getNext()->getNext());
|
||||
// Rollback
|
||||
}
|
||||
|
||||
EXPECT_EQ(layer1, root->firstLayer());
|
||||
{
|
||||
Transaction transaction(&ctx, "");
|
||||
doc->getApi(transaction).restackLayerBefore(layer1, layer3->parent(), layer3);
|
||||
EXPECT_EQ(layer2, root->firstLayer());
|
||||
EXPECT_EQ(layer1, root->firstLayer()->getNext());
|
||||
EXPECT_EQ(layer3, root->firstLayer()->getNext()->getNext());
|
||||
// Rollback
|
||||
}
|
||||
|
||||
EXPECT_EQ(layer1, root->firstLayer());
|
||||
{
|
||||
Transaction transaction(&ctx, "");
|
||||
doc->getApi(transaction).restackLayerBefore(layer1, layer1->parent(), nullptr);
|
||||
EXPECT_EQ(layer2, root->firstLayer());
|
||||
EXPECT_EQ(layer3, root->firstLayer()->getNext());
|
||||
EXPECT_EQ(layer1, root->firstLayer()->getNext()->getNext());
|
||||
// Rollback
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BasicDocApiTest, RestackLayerAfter)
|
||||
{
|
||||
EXPECT_EQ(layer1, root->firstLayer());
|
||||
{
|
||||
Transaction transaction(&ctx, "");
|
||||
// Do nothing
|
||||
doc->getApi(transaction).restackLayerAfter(layer1, layer1->parent(), layer1);
|
||||
EXPECT_EQ(layer1, root->firstLayer());
|
||||
EXPECT_EQ(layer2, root->firstLayer()->getNext());
|
||||
EXPECT_EQ(layer3, root->firstLayer()->getNext()->getNext());
|
||||
// Rollback
|
||||
}
|
||||
|
||||
EXPECT_EQ(layer1, root->firstLayer());
|
||||
{
|
||||
Transaction transaction(&ctx, "");
|
||||
doc->getApi(transaction).restackLayerAfter(layer1, layer3->parent(), layer3);
|
||||
EXPECT_EQ(layer2, root->firstLayer());
|
||||
EXPECT_EQ(layer3, root->firstLayer()->getNext());
|
||||
EXPECT_EQ(layer1, root->firstLayer()->getNext()->getNext());
|
||||
// Rollback
|
||||
}
|
||||
|
||||
EXPECT_EQ(layer1, root->firstLayer());
|
||||
{
|
||||
Transaction transaction(&ctx, "");
|
||||
doc->getApi(transaction).restackLayerAfter(layer3, layer3->parent(), nullptr);
|
||||
EXPECT_EQ(layer3, root->firstLayer());
|
||||
EXPECT_EQ(layer1, root->firstLayer()->getNext());
|
||||
EXPECT_EQ(layer2, root->firstLayer()->getNext()->getNext());
|
||||
// Rollback
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BasicDocApiTest, MoveCel)
|
||||
{
|
||||
Cel* cel1 = layer1->cel(frame_t(0));
|
||||
cel1->setPosition(2, -2);
|
||||
cel1->setOpacity(128);
|
||||
@ -61,6 +151,4 @@ TEST(DocumentApi, MoveCel) {
|
||||
EXPECT_EQ(2, cel2->x());
|
||||
EXPECT_EQ(-2, cel2->y());
|
||||
EXPECT_EQ(128, cel2->opacity());
|
||||
|
||||
doc->close();
|
||||
}
|
||||
|
@ -396,7 +396,7 @@ Document* DocumentExporter::exportSheet()
|
||||
createEmptyTexture(samples));
|
||||
|
||||
Sprite* texture = textureDocument->sprite();
|
||||
Image* textureImage = texture->folder()->getFirstLayer()
|
||||
Image* textureImage = texture->root()->firstLayer()
|
||||
->cel(frame_t(0))->image();
|
||||
|
||||
renderTexture(samples, textureImage);
|
||||
@ -758,10 +758,7 @@ void DocumentExporter::createDataFile(const Samples& samples, std::ostream& os,
|
||||
Document* doc = item.doc;
|
||||
Sprite* sprite = doc->sprite();
|
||||
|
||||
std::vector<Layer*> layers;
|
||||
sprite->getLayersList(layers);
|
||||
|
||||
for (Layer* layer : layers) {
|
||||
for (Layer* layer : sprite->allVisibleLayers()) {
|
||||
if (firstLayer)
|
||||
firstLayer = false;
|
||||
else
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -22,103 +22,139 @@ using namespace doc;
|
||||
|
||||
DocumentRange::DocumentRange()
|
||||
: m_type(kNone)
|
||||
, m_layerBegin(0)
|
||||
, m_layerEnd(-1)
|
||||
, m_frameBegin(0)
|
||||
, m_frameEnd(-1)
|
||||
, m_selectingFromLayer(nullptr)
|
||||
, m_selectingFromFrame(-1)
|
||||
{
|
||||
}
|
||||
|
||||
DocumentRange::DocumentRange(Cel* cel)
|
||||
: m_type(kCels)
|
||||
, m_layerBegin(cel->sprite()->layerToIndex(cel->layer()))
|
||||
, m_layerEnd(m_layerBegin)
|
||||
, m_frameBegin(cel->frame())
|
||||
, m_frameEnd(m_frameBegin)
|
||||
, m_selectingFromLayer(nullptr)
|
||||
, m_selectingFromFrame(-1)
|
||||
{
|
||||
m_selectedLayers.insert(cel->layer());
|
||||
m_selectedFrames.insert(cel->frame());
|
||||
}
|
||||
|
||||
void DocumentRange::startRange(LayerIndex layer, frame_t frame, Type type)
|
||||
{
|
||||
m_type = type;
|
||||
m_layerBegin = m_layerEnd = layer;
|
||||
m_frameBegin = m_frameEnd = frame;
|
||||
}
|
||||
|
||||
void DocumentRange::endRange(LayerIndex layer, frame_t frame)
|
||||
{
|
||||
ASSERT(enabled());
|
||||
m_layerEnd = layer;
|
||||
m_frameEnd = frame;
|
||||
}
|
||||
|
||||
void DocumentRange::disableRange()
|
||||
void DocumentRange::clearRange()
|
||||
{
|
||||
m_type = kNone;
|
||||
m_selectedLayers.clear();
|
||||
m_selectedFrames.clear();
|
||||
}
|
||||
|
||||
bool DocumentRange::inRange(LayerIndex layer) const
|
||||
void DocumentRange::startRange(Layer* fromLayer, frame_t fromFrame, Type type)
|
||||
{
|
||||
m_type = type;
|
||||
m_selectingFromLayer = fromLayer;
|
||||
m_selectingFromFrame = fromFrame;
|
||||
|
||||
if (fromLayer)
|
||||
m_selectedLayers.insert(fromLayer);
|
||||
if (fromFrame >= 0)
|
||||
m_selectedFrames.insert(fromFrame);
|
||||
}
|
||||
|
||||
void DocumentRange::endRange(Layer* toLayer, frame_t toFrame)
|
||||
{
|
||||
ASSERT(enabled());
|
||||
|
||||
if (m_selectingFromLayer && toLayer)
|
||||
selectLayerRange(m_selectingFromLayer, toLayer);
|
||||
|
||||
if (m_selectingFromFrame >= 0)
|
||||
selectFrameRange(m_selectingFromFrame, toFrame);
|
||||
}
|
||||
|
||||
bool DocumentRange::contains(Layer* layer) const
|
||||
{
|
||||
if (enabled())
|
||||
return (layer >= layerBegin() && layer <= layerEnd());
|
||||
return m_selectedLayers.contains(layer);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DocumentRange::inRange(frame_t frame) const
|
||||
void DocumentRange::displace(layer_t layerDelta, frame_t frameDelta)
|
||||
{
|
||||
if (enabled())
|
||||
return (frame >= frameBegin() && frame <= frameEnd());
|
||||
else
|
||||
return false;
|
||||
m_selectedLayers.displace(layerDelta);
|
||||
m_selectedFrames.displace(frameDelta);
|
||||
}
|
||||
|
||||
bool DocumentRange::inRange(LayerIndex layer, frame_t frame) const
|
||||
{
|
||||
return inRange(layer) && inRange(frame);
|
||||
}
|
||||
|
||||
void DocumentRange::setLayers(int layers)
|
||||
{
|
||||
if (m_layerBegin <= m_layerEnd) m_layerEnd = m_layerBegin + LayerIndex(layers - 1);
|
||||
else m_layerBegin = m_layerEnd + LayerIndex(layers - 1);
|
||||
}
|
||||
|
||||
void DocumentRange::setFrames(frame_t frames)
|
||||
{
|
||||
if (m_frameBegin <= m_frameEnd)
|
||||
m_frameEnd = (m_frameBegin + frames) - 1;
|
||||
else
|
||||
m_frameBegin = (m_frameEnd + frames) - 1;
|
||||
}
|
||||
|
||||
void DocumentRange::displace(int layerDelta, int frameDelta)
|
||||
{
|
||||
m_layerBegin += LayerIndex(layerDelta);
|
||||
m_layerEnd += LayerIndex(layerDelta);
|
||||
m_frameBegin += frame_t(frameDelta);
|
||||
m_frameEnd += frame_t(frameDelta);
|
||||
}
|
||||
|
||||
bool DocumentRange::convertToCels(Sprite* sprite)
|
||||
bool DocumentRange::convertToCels(const Sprite* sprite)
|
||||
{
|
||||
switch (m_type) {
|
||||
case DocumentRange::kNone:
|
||||
return false;
|
||||
case DocumentRange::kCels:
|
||||
break;
|
||||
case DocumentRange::kFrames:
|
||||
m_layerBegin = sprite->firstLayer();
|
||||
m_layerEnd = sprite->lastLayer();
|
||||
m_type = DocumentRange::kCels;
|
||||
case DocumentRange::kFrames: {
|
||||
LayerList layers = sprite->allBrowsableLayers();
|
||||
ASSERT(layers.empty());
|
||||
if (!layers.empty()) {
|
||||
selectLayerRange(layers.front(), layers.back());
|
||||
m_type = DocumentRange::kCels;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case DocumentRange::kLayers:
|
||||
m_frameBegin = frame_t(0);
|
||||
m_frameEnd = sprite->lastFrame();
|
||||
selectFrameRange(0, sprite->lastFrame());
|
||||
m_type = DocumentRange::kCels;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DocumentRange::selectLayerRange(Layer* fromLayer, Layer* toLayer)
|
||||
{
|
||||
ASSERT(fromLayer);
|
||||
ASSERT(toLayer);
|
||||
|
||||
bool goNext = false;
|
||||
bool goPrev = false;
|
||||
Layer* it;
|
||||
|
||||
if (fromLayer != toLayer) {
|
||||
it = m_selectingFromLayer;
|
||||
while (it) {
|
||||
if (it == toLayer) {
|
||||
goNext = true;
|
||||
break;
|
||||
}
|
||||
it = it->getNextInWholeHierarchy();
|
||||
}
|
||||
|
||||
if (!goNext) {
|
||||
it = m_selectingFromLayer;
|
||||
while (it) {
|
||||
if (it == toLayer) {
|
||||
goPrev = true;
|
||||
break;
|
||||
}
|
||||
it = it->getPreviousInWholeHierarchy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it = m_selectingFromLayer;
|
||||
do {
|
||||
m_selectedLayers.insert(it);
|
||||
if (it == toLayer)
|
||||
break;
|
||||
|
||||
if (goNext)
|
||||
it = it->getNextInWholeHierarchy();
|
||||
else if (goPrev)
|
||||
it = it->getPreviousInWholeHierarchy();
|
||||
else
|
||||
break;
|
||||
} while (it);
|
||||
}
|
||||
|
||||
void DocumentRange::selectFrameRange(frame_t fromFrame, frame_t toFrame)
|
||||
{
|
||||
m_selectedFrames.insert(fromFrame, toFrame);
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -10,9 +10,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "doc/frame.h"
|
||||
#include "doc/layer_index.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "doc/selected_frames.h"
|
||||
#include "doc/selected_layers.h"
|
||||
|
||||
namespace doc {
|
||||
class Cel;
|
||||
@ -31,39 +30,47 @@ namespace app {
|
||||
|
||||
Type type() const { return m_type; }
|
||||
bool enabled() const { return m_type != kNone; }
|
||||
LayerIndex layerBegin() const { return std::min(m_layerBegin, m_layerEnd); }
|
||||
LayerIndex layerEnd() const { return std::max(m_layerBegin, m_layerEnd); }
|
||||
frame_t frameBegin() const { return std::min(m_frameBegin, m_frameEnd); }
|
||||
frame_t frameEnd() const { return std::max(m_frameBegin, m_frameEnd); }
|
||||
layer_t layers() const { return int(m_selectedLayers.size()); }
|
||||
frame_t frames() const { return int(m_selectedFrames.size()); }
|
||||
const SelectedLayers& selectedLayers() const { return m_selectedLayers; }
|
||||
const SelectedFrames& selectedFrames() const { return m_selectedFrames; }
|
||||
|
||||
int layers() const { return layerEnd() - layerBegin() + 1; }
|
||||
frame_t frames() const { return frameEnd() - frameBegin() + 1; }
|
||||
void setLayers(int layers);
|
||||
void setFrames(frame_t frames);
|
||||
void displace(int layerDelta, int frameDelta);
|
||||
void displace(layer_t layerDelta, frame_t frameDelta);
|
||||
|
||||
bool inRange(LayerIndex layer) const;
|
||||
bool inRange(frame_t frame) const;
|
||||
bool inRange(LayerIndex layer, frame_t frame) const;
|
||||
bool contains(Layer* layer) const;
|
||||
|
||||
void startRange(LayerIndex layer, frame_t frame, Type type);
|
||||
void endRange(LayerIndex layer, frame_t frame);
|
||||
void disableRange();
|
||||
|
||||
bool operator==(const DocumentRange& o) const {
|
||||
return m_type == o.m_type &&
|
||||
layerBegin() == o.layerBegin() && layerEnd() == o.layerEnd() &&
|
||||
frameBegin() == o.frameBegin() && frameEnd() == o.frameEnd();
|
||||
bool contains(frame_t frame) const {
|
||||
return m_selectedFrames.contains(frame);
|
||||
}
|
||||
|
||||
bool convertToCels(Sprite* sprite);
|
||||
bool contains(Layer* layer, frame_t frame) const {
|
||||
return contains(layer) && contains(frame);
|
||||
}
|
||||
|
||||
void clearRange();
|
||||
void startRange(Layer* fromLayer, frame_t fromFrame, Type type);
|
||||
void endRange(Layer* toLayer, frame_t toFrame);
|
||||
|
||||
frame_t firstFrame() const { return m_selectedFrames.firstFrame(); }
|
||||
frame_t lastFrame() const { return m_selectedFrames.lastFrame(); }
|
||||
|
||||
bool operator==(const DocumentRange& o) const {
|
||||
return (m_type == o.m_type &&
|
||||
m_selectedLayers == o.m_selectedLayers &&
|
||||
m_selectedFrames == o.m_selectedFrames);
|
||||
}
|
||||
|
||||
bool convertToCels(const Sprite* sprite);
|
||||
|
||||
private:
|
||||
void selectLayerRange(Layer* fromLayer, Layer* toLayer);
|
||||
void selectFrameRange(frame_t fromFrame, frame_t toFrame);
|
||||
|
||||
Type m_type;
|
||||
LayerIndex m_layerBegin;
|
||||
LayerIndex m_layerEnd;
|
||||
frame_t m_frameBegin;
|
||||
frame_t m_frameEnd;
|
||||
SelectedLayers m_selectedLayers;
|
||||
SelectedFrames m_selectedFrames;
|
||||
Layer* m_selectingFromLayer;
|
||||
frame_t m_selectingFromFrame;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -5,13 +5,15 @@
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
// Uncomment this in case you want to debug range ops
|
||||
//#define TRACE_RANGE_OPS
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/document_range_ops.h"
|
||||
|
||||
#include "app/app.h" // TODO remove this dependency
|
||||
#include "app/context_access.h"
|
||||
#include "app/document_api.h"
|
||||
#include "app/document_range.h"
|
||||
@ -21,14 +23,172 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef TRACE_RANGE_OPS
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
namespace app {
|
||||
|
||||
enum Op { Move, Copy };
|
||||
|
||||
template<typename T>
|
||||
static void move_or_copy_cels(
|
||||
DocumentApi& api, Op op,
|
||||
LayerList& srcLayers,
|
||||
LayerList& dstLayers,
|
||||
T& srcFrames,
|
||||
T& dstFrames)
|
||||
{
|
||||
ASSERT(srcLayers.size() == dstLayers.size());
|
||||
|
||||
for (layer_t i=0; i<srcLayers.size(); ++i) {
|
||||
auto srcFrame = srcFrames.begin();
|
||||
auto dstFrame = dstFrames.begin();
|
||||
auto srcFrameEnd = srcFrames.end();
|
||||
auto dstFrameEnd = dstFrames.end();
|
||||
|
||||
for (; srcFrame != srcFrameEnd &&
|
||||
dstFrame != dstFrameEnd; ++srcFrame, ++dstFrame) {
|
||||
if (i >= 0 && i < srcLayers.size() && srcLayers[i]->isImage()) {
|
||||
LayerImage* srcLayer = static_cast<LayerImage*>(srcLayers[i]);
|
||||
|
||||
if (i < dstLayers.size() && dstLayers[i]->isImage()) {
|
||||
LayerImage* srcLayer = static_cast<LayerImage*>(srcLayers[i]);
|
||||
LayerImage* dstLayer = static_cast<LayerImage*>(dstLayers[i]);
|
||||
|
||||
#ifdef TRACE_RANGE_OPS
|
||||
std::clog << (op == Move ? "Moving": "Copying")
|
||||
<< " cel " << srcLayer->name() << "[" << *srcFrame << "]"
|
||||
<< " into " << dstLayer->name() << "[" << *dstFrame << "]\n";
|
||||
#endif
|
||||
|
||||
switch (op) {
|
||||
case Move: api.moveCel(srcLayer, *srcFrame, dstLayer, *dstFrame); break;
|
||||
case Copy: api.copyCel(srcLayer, *srcFrame, dstLayer, *dstFrame); break;
|
||||
}
|
||||
}
|
||||
else if (op == Move) {
|
||||
api.clearCel(srcLayer, *srcFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static DocumentRange move_or_copy_frames(
|
||||
DocumentApi& api, Op op,
|
||||
Sprite* sprite,
|
||||
T& srcFrames,
|
||||
frame_t dstFrame)
|
||||
{
|
||||
#ifdef TRACE_RANGE_OPS
|
||||
std::clog << "move_or_copy_frames frames[";
|
||||
for (auto srcFrame : srcFrames) {
|
||||
std::clog << srcFrame << ", ";
|
||||
}
|
||||
std::clog << "] => " << dstFrame << "\n";
|
||||
#endif
|
||||
|
||||
auto srcFrame = srcFrames.begin();
|
||||
auto srcFrameEnd = srcFrames.end();
|
||||
frame_t srcDelta = 0;
|
||||
frame_t firstCopiedBlock = 0;
|
||||
|
||||
for (; srcFrame != srcFrameEnd; ++srcFrame) {
|
||||
frame_t fromFrame = (*srcFrame)+srcDelta;
|
||||
|
||||
switch (op) {
|
||||
|
||||
case Move:
|
||||
if ((*srcFrame) >= dstFrame) {
|
||||
srcDelta = 0;
|
||||
fromFrame = *srcFrame;
|
||||
}
|
||||
break;
|
||||
|
||||
case Copy:
|
||||
if (fromFrame >= dstFrame-1 && firstCopiedBlock) {
|
||||
srcDelta += firstCopiedBlock;
|
||||
fromFrame += firstCopiedBlock;
|
||||
firstCopiedBlock = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef TRACE_RANGE_OPS
|
||||
std::clog << " [";
|
||||
for (frame_t i=0; i<=sprite->lastFrame(); ++i) {
|
||||
std::clog << (sprite->frameDuration(i)-1);
|
||||
}
|
||||
std::clog << "] => "
|
||||
<< (op == Move ? "Move": "Copy")
|
||||
<< " " << (*srcFrame) << "+" << (srcDelta) << " -> " << dstFrame << " => ";
|
||||
#endif
|
||||
|
||||
switch (op) {
|
||||
|
||||
case Move:
|
||||
api.moveFrame(sprite, fromFrame, dstFrame);
|
||||
|
||||
if (fromFrame < dstFrame-1) {
|
||||
--srcDelta;
|
||||
}
|
||||
else if (fromFrame > dstFrame-1) {
|
||||
++dstFrame;
|
||||
}
|
||||
break;
|
||||
|
||||
case Copy:
|
||||
api.copyFrame(sprite, fromFrame, dstFrame);
|
||||
|
||||
if (fromFrame < dstFrame-1) {
|
||||
++firstCopiedBlock;
|
||||
}
|
||||
else if (fromFrame >= dstFrame-1) {
|
||||
++srcDelta;
|
||||
}
|
||||
++dstFrame;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef TRACE_RANGE_OPS
|
||||
std::clog << " [";
|
||||
for (frame_t i=0; i<=sprite->lastFrame(); ++i) {
|
||||
std::clog << (sprite->frameDuration(i)-1);
|
||||
}
|
||||
std::clog << "]\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
DocumentRange result;
|
||||
result.startRange(nullptr, dstFrame-srcFrames.size(), DocumentRange::kFrames);
|
||||
result.endRange(nullptr, dstFrame-1);
|
||||
return result;
|
||||
}
|
||||
|
||||
static DocumentRange drop_range_op(
|
||||
Document* doc, Op op, const DocumentRange& from,
|
||||
DocumentRangePlace place, const DocumentRange& to)
|
||||
DocumentRangePlace place, DocumentRange to)
|
||||
{
|
||||
// Convert "first child" operation into a insert after last child.
|
||||
LayerGroup* parent = nullptr;
|
||||
if (to.type() == DocumentRange::kLayers &&
|
||||
!to.selectedLayers().empty()) {
|
||||
if (place == kDocumentRangeFirstChild &&
|
||||
(*to.selectedLayers().begin())->isGroup()) {
|
||||
place = kDocumentRangeAfter;
|
||||
parent = static_cast<LayerGroup*>((*to.selectedLayers().begin()));
|
||||
|
||||
to.clearRange();
|
||||
to.startRange(parent->lastLayer(), -1, DocumentRange::kLayers);
|
||||
to.endRange(parent->lastLayer(), -1);
|
||||
}
|
||||
else {
|
||||
parent = (*to.selectedLayers().begin())->parent();
|
||||
}
|
||||
}
|
||||
|
||||
if (place != kDocumentRangeBefore &&
|
||||
place != kDocumentRangeAfter) {
|
||||
ASSERT(false);
|
||||
@ -40,36 +200,69 @@ static DocumentRange drop_range_op(
|
||||
// Check noop/trivial/do nothing cases, i.e., move a range to the same place.
|
||||
// Also check invalid cases, like moving a Background layer.
|
||||
switch (from.type()) {
|
||||
|
||||
case DocumentRange::kCels:
|
||||
if (from == to)
|
||||
return from;
|
||||
break;
|
||||
|
||||
case DocumentRange::kFrames:
|
||||
if (op == Move) {
|
||||
if ((to.frameBegin() >= from.frameBegin() && to.frameEnd() <= from.frameEnd()) ||
|
||||
(place == kDocumentRangeBefore && to.frameBegin() == from.frameEnd()+1) ||
|
||||
(place == kDocumentRangeAfter && to.frameEnd() == from.frameBegin()-1))
|
||||
// Simple cases with one continuos range of frames that are a
|
||||
// no-op.
|
||||
if ((from.selectedFrames().ranges() == 1) &&
|
||||
((to.firstFrame() >= from.firstFrame() &&
|
||||
to.lastFrame() <= from.lastFrame()) ||
|
||||
(place == kDocumentRangeBefore && to.firstFrame() == from.lastFrame()+1) ||
|
||||
(place == kDocumentRangeAfter && to.lastFrame() == from.firstFrame()-1)))
|
||||
return from;
|
||||
}
|
||||
break;
|
||||
|
||||
case DocumentRange::kLayers:
|
||||
if (op == Move) {
|
||||
if ((to.layerBegin() >= from.layerBegin() && to.layerEnd() <= from.layerEnd()) ||
|
||||
(place == kDocumentRangeBefore && to.layerBegin() == from.layerEnd()+1) ||
|
||||
(place == kDocumentRangeAfter && to.layerEnd() == from.layerBegin()-1))
|
||||
SelectedLayers srcSelLayers = from.selectedLayers();
|
||||
SelectedLayers dstSelLayers = to.selectedLayers();
|
||||
LayerList srcLayers = srcSelLayers.toLayerList();
|
||||
LayerList dstLayers = dstSelLayers.toLayerList();
|
||||
ASSERT(!srcLayers.empty());
|
||||
if (srcLayers.empty())
|
||||
return from;
|
||||
|
||||
// dstLayers can be nullptr when we insert the first child in
|
||||
// a group.
|
||||
|
||||
// Check no-ops when we move layers at the same level (all
|
||||
// layers with the same parent), all adjacents, and which are
|
||||
// moved to the same place.
|
||||
if (!dstSelLayers.empty() &&
|
||||
srcSelLayers.hasSameParent() &&
|
||||
dstSelLayers.hasSameParent() &&
|
||||
are_layers_adjacent(srcLayers) &&
|
||||
are_layers_adjacent(dstLayers)) {
|
||||
for (Layer* srcLayer : srcLayers)
|
||||
if (dstSelLayers.contains(srcLayer))
|
||||
return from;
|
||||
|
||||
if ((place == kDocumentRangeBefore
|
||||
&& dstLayers.front() == srcLayers.back()->getNext()) ||
|
||||
(place == kDocumentRangeAfter
|
||||
&& dstLayers.back() == srcLayers.front()->getPrevious()))
|
||||
return from;
|
||||
}
|
||||
|
||||
// We cannot move the background
|
||||
for (LayerIndex i = from.layerBegin(); i <= from.layerEnd(); ++i)
|
||||
if (sprite->indexToLayer(i)->isBackground())
|
||||
for (Layer* layer : srcSelLayers)
|
||||
if (layer->isBackground())
|
||||
throw std::runtime_error("The background layer cannot be moved");
|
||||
}
|
||||
|
||||
// Before background
|
||||
if (place == kDocumentRangeBefore) {
|
||||
Layer* background = sprite->indexToLayer(to.layerBegin());
|
||||
if (background && background->isBackground())
|
||||
throw std::runtime_error("You cannot move or copy something below the background layer");
|
||||
for (Layer* background : to.selectedLayers()) {
|
||||
if (background && background->isBackground())
|
||||
throw std::runtime_error("You cannot move or copy something below the background layer");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -92,238 +285,122 @@ static DocumentRange drop_range_op(
|
||||
DocumentApi api = doc->getApi(transaction);
|
||||
|
||||
// TODO Try to add the range with just one call to DocumentApi
|
||||
// methods, to avoid generating a lot of SetCelFrame undoers (see
|
||||
// DocumentApi::setCelFramePosition).
|
||||
// methods, to avoid generating a lot of cmd::SetCelFrame (see
|
||||
// DocumentApi::setCelFramePosition() function).
|
||||
|
||||
switch (from.type()) {
|
||||
|
||||
case DocumentRange::kCels:
|
||||
{
|
||||
std::vector<Layer*> layers;
|
||||
sprite->getLayersList(layers);
|
||||
case DocumentRange::kCels: {
|
||||
LayerList allLayers = sprite->allBrowsableLayers();
|
||||
if (allLayers.empty())
|
||||
break;
|
||||
|
||||
int srcLayerBegin, srcLayerStep, srcLayerEnd;
|
||||
int dstLayerBegin, dstLayerStep;
|
||||
frame_t srcFrameBegin, srcFrameStep, srcFrameEnd;
|
||||
frame_t dstFrameBegin, dstFrameStep;
|
||||
LayerList srcLayers = from.selectedLayers().toLayerList();
|
||||
LayerList dstLayers = to.selectedLayers().toLayerList();
|
||||
if (srcLayers.empty())
|
||||
throw std::invalid_argument("You need to specify a non-empty cels range");
|
||||
|
||||
if (to.layerBegin() <= from.layerBegin()) {
|
||||
srcLayerBegin = from.layerBegin();
|
||||
srcLayerStep = 1;
|
||||
srcLayerEnd = from.layerEnd()+1;
|
||||
dstLayerBegin = to.layerBegin();
|
||||
dstLayerStep = 1;
|
||||
}
|
||||
else {
|
||||
srcLayerBegin = from.layerEnd();
|
||||
srcLayerStep = -1;
|
||||
srcLayerEnd = from.layerBegin()-1;
|
||||
dstLayerBegin = to.layerEnd();
|
||||
dstLayerStep = -1;
|
||||
}
|
||||
|
||||
if (to.frameBegin() <= from.frameBegin()) {
|
||||
srcFrameBegin = from.frameBegin();
|
||||
srcFrameStep = frame_t(1);
|
||||
srcFrameEnd = from.frameEnd()+1;
|
||||
dstFrameBegin = to.frameBegin();
|
||||
dstFrameStep = frame_t(1);
|
||||
}
|
||||
else {
|
||||
srcFrameBegin = from.frameEnd();
|
||||
srcFrameStep = frame_t(-1);
|
||||
srcFrameEnd = from.frameBegin()-1;
|
||||
dstFrameBegin = to.frameEnd();
|
||||
dstFrameStep = frame_t(-1);
|
||||
}
|
||||
|
||||
for (int srcLayerIdx = srcLayerBegin,
|
||||
dstLayerIdx = dstLayerBegin; srcLayerIdx != srcLayerEnd; ) {
|
||||
for (frame_t srcFrame = srcFrameBegin,
|
||||
dstFrame = dstFrameBegin; srcFrame != srcFrameEnd; ) {
|
||||
if (dstLayerIdx < 0 || dstLayerIdx >= int(layers.size()) ||
|
||||
srcLayerIdx < 0 || srcLayerIdx >= int(layers.size()))
|
||||
break;
|
||||
|
||||
LayerImage* srcLayer = static_cast<LayerImage*>(layers[srcLayerIdx]);
|
||||
LayerImage* dstLayer = static_cast<LayerImage*>(layers[dstLayerIdx]);
|
||||
|
||||
switch (op) {
|
||||
case Move: api.moveCel(srcLayer, srcFrame, dstLayer, dstFrame); break;
|
||||
case Copy: api.copyCel(srcLayer, srcFrame, dstLayer, dstFrame); break;
|
||||
}
|
||||
|
||||
srcFrame += srcFrameStep;
|
||||
dstFrame += dstFrameStep;
|
||||
}
|
||||
srcLayerIdx += srcLayerStep;
|
||||
dstLayerIdx += dstLayerStep;
|
||||
}
|
||||
|
||||
resultRange = to;
|
||||
if (find_layer_index(allLayers, srcLayers.front()) <
|
||||
find_layer_index(allLayers, dstLayers.front())) {
|
||||
std::reverse(srcLayers.begin(), srcLayers.end());
|
||||
std::reverse(dstLayers.begin(), dstLayers.end());
|
||||
}
|
||||
break;
|
||||
|
||||
case DocumentRange::kFrames:
|
||||
{
|
||||
frame_t srcFrameBegin = 0, srcFrameStep, srcFrameEnd = 0;
|
||||
frame_t dstFrameBegin = 0, dstFrameStep;
|
||||
if (from.firstFrame() < to.firstFrame()) {
|
||||
auto srcFrames = from.selectedFrames().reversed();
|
||||
auto dstFrames = to.selectedFrames().reversed();
|
||||
|
||||
switch (op) {
|
||||
|
||||
case Move:
|
||||
if (place == kDocumentRangeBefore) {
|
||||
if (to.frameBegin() <= from.frameBegin()) {
|
||||
srcFrameBegin = from.frameBegin();
|
||||
srcFrameStep = frame_t(1);
|
||||
srcFrameEnd = from.frameEnd()+1;
|
||||
dstFrameBegin = to.frameBegin();
|
||||
dstFrameStep = frame_t(1);
|
||||
}
|
||||
else {
|
||||
srcFrameBegin = from.frameEnd();
|
||||
srcFrameStep = frame_t(-1);
|
||||
srcFrameEnd = from.frameBegin()-1;
|
||||
dstFrameBegin = to.frameBegin();
|
||||
dstFrameStep = frame_t(-1);
|
||||
}
|
||||
}
|
||||
else if (place == kDocumentRangeAfter) {
|
||||
if (to.frameEnd() <= from.frameBegin()) {
|
||||
srcFrameBegin = from.frameBegin();
|
||||
srcFrameStep = frame_t(1);
|
||||
srcFrameEnd = from.frameEnd()+1;
|
||||
dstFrameBegin = to.frameEnd()+1;
|
||||
dstFrameStep = frame_t(1);
|
||||
}
|
||||
else {
|
||||
srcFrameBegin = from.frameEnd();
|
||||
srcFrameStep = frame_t(-1);
|
||||
srcFrameEnd = from.frameBegin()-1;
|
||||
dstFrameBegin = to.frameEnd()+1;
|
||||
dstFrameStep = frame_t(-1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Copy:
|
||||
if (place == kDocumentRangeBefore) {
|
||||
if (to.frameBegin() <= from.frameBegin()) {
|
||||
srcFrameBegin = from.frameBegin();
|
||||
srcFrameStep = frame_t(2);
|
||||
srcFrameEnd = from.frameBegin() + 2*from.frames();
|
||||
dstFrameBegin = to.frameBegin();
|
||||
dstFrameStep = frame_t(1);
|
||||
}
|
||||
else {
|
||||
srcFrameBegin = from.frameEnd();
|
||||
srcFrameStep = frame_t(-1);
|
||||
srcFrameEnd = from.frameBegin()-1;
|
||||
dstFrameBegin = to.frameBegin();
|
||||
dstFrameStep = frame_t(0);
|
||||
}
|
||||
}
|
||||
else if (place == kDocumentRangeAfter) {
|
||||
if (to.frameEnd() <= from.frameBegin()) {
|
||||
srcFrameBegin = from.frameBegin();
|
||||
srcFrameStep = frame_t(2);
|
||||
srcFrameEnd = from.frameBegin() + 2*from.frames();
|
||||
dstFrameBegin = to.frameEnd()+1;
|
||||
dstFrameStep = frame_t(1);
|
||||
}
|
||||
else {
|
||||
srcFrameBegin = from.frameEnd();
|
||||
srcFrameStep = frame_t(-1);
|
||||
srcFrameEnd = from.frameBegin()-1;
|
||||
dstFrameBegin = to.frameEnd()+1;
|
||||
dstFrameStep = frame_t(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (frame_t srcFrame = srcFrameBegin,
|
||||
dstFrame = dstFrameBegin; srcFrame != srcFrameEnd; ) {
|
||||
switch (op) {
|
||||
case Move: api.moveFrame(sprite, srcFrame, dstFrame); break;
|
||||
case Copy: api.copyFrame(sprite, srcFrame, dstFrame); break;
|
||||
}
|
||||
srcFrame += srcFrameStep;
|
||||
dstFrame += dstFrameStep;
|
||||
}
|
||||
|
||||
if (place == kDocumentRangeBefore) {
|
||||
resultRange.startRange(LayerIndex::NoLayer, frame_t(to.frameBegin()), from.type());
|
||||
resultRange.endRange(LayerIndex::NoLayer, frame_t(to.frameBegin()+from.frames()-1));
|
||||
}
|
||||
else if (place == kDocumentRangeAfter) {
|
||||
resultRange.startRange(LayerIndex::NoLayer, frame_t(to.frameEnd()+1), from.type());
|
||||
resultRange.endRange(LayerIndex::NoLayer, frame_t(to.frameEnd()+1+from.frames()-1));
|
||||
}
|
||||
|
||||
if (op == Move && from.frameBegin() < to.frameBegin())
|
||||
resultRange.displace(0, -from.frames());
|
||||
move_or_copy_cels(api, op, srcLayers, dstLayers, srcFrames, dstFrames);
|
||||
}
|
||||
else {
|
||||
const auto& srcFrames = from.selectedFrames();
|
||||
const auto& dstFrames = to.selectedFrames();
|
||||
|
||||
move_or_copy_cels(api, op, srcLayers, dstLayers, srcFrames, dstFrames);
|
||||
}
|
||||
|
||||
resultRange = to;
|
||||
break;
|
||||
}
|
||||
|
||||
case DocumentRange::kLayers:
|
||||
{
|
||||
std::vector<Layer*> layers;
|
||||
sprite->getLayersList(layers);
|
||||
case DocumentRange::kFrames: {
|
||||
frame_t dstFrame;
|
||||
if (place == kDocumentRangeBefore)
|
||||
dstFrame = to.firstFrame();
|
||||
else
|
||||
dstFrame = to.lastFrame()+1;
|
||||
|
||||
if (layers.empty())
|
||||
resultRange =
|
||||
move_or_copy_frames(api, op, sprite,
|
||||
from.selectedFrames(), dstFrame);
|
||||
break;
|
||||
}
|
||||
|
||||
case DocumentRange::kLayers: {
|
||||
LayerList allLayers = sprite->allBrowsableLayers();
|
||||
if (allLayers.empty())
|
||||
break;
|
||||
|
||||
LayerList srcLayers = from.selectedLayers().toLayerList();
|
||||
LayerList dstLayers = to.selectedLayers().toLayerList();
|
||||
ASSERT(!srcLayers.empty());
|
||||
|
||||
switch (op) {
|
||||
|
||||
case Move:
|
||||
if (place == kDocumentRangeBefore) {
|
||||
Layer* beforeThis = (!dstLayers.empty() ? dstLayers.front(): nullptr);
|
||||
Layer* afterThis = nullptr;
|
||||
|
||||
for (Layer* srcLayer : srcLayers) {
|
||||
if (afterThis)
|
||||
api.restackLayerAfter(srcLayer, parent, afterThis);
|
||||
else
|
||||
api.restackLayerBefore(srcLayer, parent, beforeThis);
|
||||
|
||||
afterThis = srcLayer;
|
||||
}
|
||||
}
|
||||
else if (place == kDocumentRangeAfter) {
|
||||
Layer* afterThis = (!dstLayers.empty() ? dstLayers.back(): nullptr);
|
||||
for (Layer* srcLayer : srcLayers) {
|
||||
api.restackLayerAfter(srcLayer, parent, afterThis);
|
||||
afterThis = srcLayer;
|
||||
}
|
||||
}
|
||||
|
||||
// Same set of layers than the "from" range
|
||||
resultRange = from;
|
||||
break;
|
||||
|
||||
switch (op) {
|
||||
case Copy: {
|
||||
if (place == kDocumentRangeBefore) {
|
||||
Layer* beforeThis = (!dstLayers.empty() ? dstLayers.front(): nullptr);
|
||||
for (Layer* srcLayer : srcLayers) {
|
||||
Layer* copiedLayer = api.duplicateLayerBefore(
|
||||
srcLayer, parent, beforeThis);
|
||||
|
||||
case Move:
|
||||
if (place == kDocumentRangeBefore) {
|
||||
for (LayerIndex i = from.layerBegin(); i <= from.layerEnd(); ++i) {
|
||||
api.restackLayerBefore(
|
||||
layers[i],
|
||||
layers[to.layerBegin()]);
|
||||
}
|
||||
resultRange.startRange(copiedLayer, -1, DocumentRange::kLayers);
|
||||
resultRange.endRange(copiedLayer, -1);
|
||||
}
|
||||
else if (place == kDocumentRangeAfter) {
|
||||
for (LayerIndex i = from.layerEnd(); i >= from.layerBegin(); --i) {
|
||||
api.restackLayerAfter(
|
||||
layers[i],
|
||||
layers[to.layerEnd()]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (place == kDocumentRangeAfter) {
|
||||
std::reverse(srcLayers.begin(), srcLayers.end());
|
||||
|
||||
case Copy:
|
||||
if (place == kDocumentRangeBefore) {
|
||||
for (LayerIndex i = from.layerBegin(); i <= from.layerEnd(); ++i) {
|
||||
api.duplicateLayerBefore(
|
||||
layers[i],
|
||||
layers[to.layerBegin()]);
|
||||
}
|
||||
Layer* afterThis = (!dstLayers.empty() ? dstLayers.back(): nullptr);
|
||||
for (Layer* srcLayer : srcLayers) {
|
||||
Layer* copiedLayer = api.duplicateLayerAfter(
|
||||
srcLayer, parent, afterThis);
|
||||
|
||||
resultRange.startRange(copiedLayer, -1, DocumentRange::kLayers);
|
||||
resultRange.endRange(copiedLayer, -1);
|
||||
}
|
||||
else if (place == kDocumentRangeAfter) {
|
||||
for (LayerIndex i = from.layerEnd(); i >= from.layerBegin(); --i) {
|
||||
api.duplicateLayerAfter(
|
||||
layers[i],
|
||||
layers[to.layerEnd()]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (place == kDocumentRangeBefore) {
|
||||
resultRange.startRange(LayerIndex(to.layerBegin()), frame_t(-1), from.type());
|
||||
resultRange.endRange(LayerIndex(to.layerBegin()+from.layers()-1), frame_t(-1));
|
||||
}
|
||||
else if (place == kDocumentRangeAfter) {
|
||||
resultRange.startRange(LayerIndex(to.layerEnd()+1), frame_t(-1), from.type());
|
||||
resultRange.endRange(LayerIndex(to.layerEnd()+1+from.layers()-1), frame_t(-1));
|
||||
}
|
||||
|
||||
if (op == Move && from.layerBegin() < to.layerBegin())
|
||||
resultRange.displace(-from.layers(), 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
@ -334,12 +411,12 @@ static DocumentRange drop_range_op(
|
||||
|
||||
DocumentRange move_range(Document* doc, const DocumentRange& from, const DocumentRange& to, DocumentRangePlace place)
|
||||
{
|
||||
return drop_range_op(doc, Move, from, place, to);
|
||||
return drop_range_op(doc, Move, from, place, DocumentRange(to));
|
||||
}
|
||||
|
||||
DocumentRange copy_range(Document* doc, const DocumentRange& from, const DocumentRange& to, DocumentRangePlace place)
|
||||
{
|
||||
return drop_range_op(doc, Copy, from, place, to);
|
||||
return drop_range_op(doc, Copy, from, place, DocumentRange(to));
|
||||
}
|
||||
|
||||
void reverse_frames(Document* doc, const DocumentRange& range)
|
||||
@ -350,29 +427,28 @@ void reverse_frames(Document* doc, const DocumentRange& range)
|
||||
Transaction transaction(writer.context(), "Reverse Frames");
|
||||
DocumentApi api = doc->getApi(transaction);
|
||||
Sprite* sprite = doc->sprite();
|
||||
LayerList layers;
|
||||
frame_t frameBegin, frameEnd;
|
||||
int layerBegin, layerEnd;
|
||||
bool moveFrames = false;
|
||||
bool swapCels = false;
|
||||
|
||||
switch (range.type()) {
|
||||
case DocumentRange::kCels:
|
||||
frameBegin = range.frameBegin();
|
||||
frameEnd = range.frameEnd();
|
||||
layerBegin = range.layerBegin();
|
||||
layerEnd = range.layerEnd() + 1;
|
||||
frameBegin = range.firstFrame();
|
||||
frameEnd = range.lastFrame();
|
||||
layers = range.selectedLayers().toLayerList();
|
||||
swapCels = true;
|
||||
break;
|
||||
case DocumentRange::kFrames:
|
||||
frameBegin = range.frameBegin();
|
||||
frameEnd = range.frameEnd();
|
||||
frameBegin = range.firstFrame();
|
||||
frameEnd = range.lastFrame();
|
||||
layers = sprite->allLayers();
|
||||
moveFrames = true;
|
||||
break;
|
||||
case DocumentRange::kLayers:
|
||||
frameBegin = frame_t(0);
|
||||
frameEnd = sprite->totalFrames()-1;
|
||||
layerBegin = range.layerBegin();
|
||||
layerEnd = range.layerEnd() + 1;
|
||||
layers = range.selectedLayers().toLayerList();
|
||||
swapCels = true;
|
||||
break;
|
||||
}
|
||||
@ -385,10 +461,10 @@ void reverse_frames(Document* doc, const DocumentRange& range)
|
||||
}
|
||||
}
|
||||
else if (swapCels) {
|
||||
std::vector<Layer*> layers;
|
||||
sprite->getLayersList(layers);
|
||||
for (Layer* layer : layers) {
|
||||
if (!layer->isImage())
|
||||
continue;
|
||||
|
||||
for (int layerIdx = layerBegin; layerIdx != layerEnd; ++layerIdx) {
|
||||
for (frame_t frame = frameBegin,
|
||||
frameRev = frameEnd;
|
||||
frame != (frameBegin+frameEnd)/2+1;
|
||||
@ -396,8 +472,8 @@ void reverse_frames(Document* doc, const DocumentRange& range)
|
||||
if (frame == frameRev)
|
||||
continue;
|
||||
|
||||
LayerImage* layer = static_cast<LayerImage*>(layers[layerIdx]);
|
||||
api.swapCel(layer, frame, frameRev);
|
||||
LayerImage* imageLayer = static_cast<LayerImage*>(layer);
|
||||
api.swapCel(imageLayer, frame, frameRev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -18,6 +18,7 @@ namespace app {
|
||||
enum DocumentRangePlace {
|
||||
kDocumentRangeBefore,
|
||||
kDocumentRangeAfter,
|
||||
kDocumentRangeFirstChild,
|
||||
};
|
||||
|
||||
// These functions returns the new location of the "from" range or
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -100,11 +100,12 @@ static void ase_file_read_frame_header(FILE* f, ASE_FrameHeader* frame_header);
|
||||
static void ase_file_prepare_frame_header(FILE* f, ASE_FrameHeader* frame_header);
|
||||
static void ase_file_write_frame_header(FILE* f, ASE_FrameHeader* frame_header);
|
||||
|
||||
static void ase_file_write_layers(FILE* f, ASE_FrameHeader* frame_header, const Layer* layer);
|
||||
static void ase_file_write_cels(FILE* f, ASE_FrameHeader* frame_header,
|
||||
const Sprite* sprite, const Layer* layer,
|
||||
const frame_t frame,
|
||||
const frame_t firstFrame);
|
||||
static void ase_file_write_layers(FILE* f, ASE_FrameHeader* frame_header, const Layer* layer, int child_level);
|
||||
static layer_t ase_file_write_cels(FILE* f, ASE_FrameHeader* frame_header,
|
||||
const Sprite* sprite, const Layer* layer,
|
||||
layer_t layer_index,
|
||||
const frame_t frame,
|
||||
const frame_t firstFrame);
|
||||
|
||||
static void ase_file_read_padding(FILE* f, int bytes);
|
||||
static void ase_file_write_padding(FILE* f, int bytes);
|
||||
@ -120,10 +121,12 @@ static Palette* ase_file_read_palette_chunk(FILE* f, Palette* prevPal, frame_t f
|
||||
static void ase_file_write_color2_chunk(FILE* f, ASE_FrameHeader* frame_header, const Palette* pal);
|
||||
static void ase_file_write_palette_chunk(FILE* f, ASE_FrameHeader* frame_header, const Palette* pal, int from, int to);
|
||||
static Layer* ase_file_read_layer_chunk(FILE* f, ASE_Header* header, Sprite* sprite, Layer** previous_layer, int* current_level);
|
||||
static void ase_file_write_layer_chunk(FILE* f, ASE_FrameHeader* frame_header, const Layer* layer);
|
||||
static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, frame_t frame, PixelFormat pixelFormat, FileOp* fop, ASE_Header* header, size_t chunk_end);
|
||||
static void ase_file_write_layer_chunk(FILE* f, ASE_FrameHeader* frame_header, const Layer* layer, int child_level);
|
||||
static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, LayerList& allLayers, frame_t frame, PixelFormat pixelFormat, FileOp* fop, ASE_Header* header, size_t chunk_end);
|
||||
static void ase_file_write_cel_chunk(FILE* f, ASE_FrameHeader* frame_header,
|
||||
const Cel* cel, const LayerImage* layer,
|
||||
const Cel* cel,
|
||||
const LayerImage* layer,
|
||||
const layer_t layer_index,
|
||||
const Sprite* sprite,
|
||||
const frame_t firstFrame);
|
||||
static Mask* ase_file_read_mask_chunk(FILE* f);
|
||||
@ -135,8 +138,8 @@ static void ase_file_write_frame_tags_chunk(FILE* f, ASE_FrameHeader* frame_head
|
||||
const frame_t fromFrame, const frame_t toFrame);
|
||||
static void ase_file_read_user_data_chunk(FILE* f, UserData* userData);
|
||||
static void ase_file_write_user_data_chunk(FILE* f, ASE_FrameHeader* frame_header, const UserData* userData);
|
||||
static bool ase_has_groups(LayerFolder* layer);
|
||||
static void ase_ungroup_all(LayerFolder* layer);
|
||||
static bool ase_has_groups(LayerGroup* group);
|
||||
static void ase_ungroup_all(LayerGroup* group);
|
||||
|
||||
class ChunkWriter {
|
||||
public:
|
||||
@ -213,9 +216,10 @@ bool AseFormat::onLoad(FileOp* fop)
|
||||
sprite->setPixelRatio(PixelRatio(header.pixel_width, header.pixel_height));
|
||||
|
||||
// Prepare variables for layer chunks
|
||||
Layer* last_layer = sprite->folder();
|
||||
Layer* last_layer = sprite->root();
|
||||
WithUserData* last_object_with_user_data = nullptr;
|
||||
int current_level = -1;
|
||||
LayerList allLayers;
|
||||
|
||||
// Read frame by frame to end-of-file
|
||||
for (frame_t frame(0); frame<sprite->totalFrames(); ++frame) {
|
||||
@ -235,7 +239,7 @@ bool AseFormat::onLoad(FileOp* fop)
|
||||
|
||||
// Read chunks
|
||||
for (int c=0; c<frame_header.chunks; c++) {
|
||||
/* start chunk position */
|
||||
// Start chunk position
|
||||
int chunk_pos = ftell(f);
|
||||
fop->setProgress((float)chunk_pos / (float)header.size);
|
||||
|
||||
@ -270,16 +274,20 @@ bool AseFormat::onLoad(FileOp* fop)
|
||||
}
|
||||
|
||||
case ASE_FILE_CHUNK_LAYER: {
|
||||
last_object_with_user_data =
|
||||
Layer* newLayer =
|
||||
ase_file_read_layer_chunk(f, &header, sprite,
|
||||
&last_layer,
|
||||
¤t_level);
|
||||
if (newLayer) {
|
||||
allLayers.push_back(newLayer);
|
||||
last_object_with_user_data = newLayer;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ASE_FILE_CHUNK_CEL: {
|
||||
Cel* cel =
|
||||
ase_file_read_cel_chunk(f, sprite, frame,
|
||||
ase_file_read_cel_chunk(f, sprite, allLayers, frame,
|
||||
sprite->pixelFormat(), fop, &header,
|
||||
chunk_pos+chunk_size);
|
||||
if (cel) {
|
||||
@ -348,7 +356,7 @@ bool AseFormat::onLoad(FileOp* fop)
|
||||
|
||||
bool AseFormat::onPostLoad(FileOp* fop)
|
||||
{
|
||||
LayerFolder* folder = fop->document()->sprite()->folder();
|
||||
LayerGroup* group = fop->document()->sprite()->root();
|
||||
|
||||
// Forward Compatibility: In 1.1 we convert a file with layer groups
|
||||
// (saved with 1.2) as top level layers
|
||||
@ -356,7 +364,7 @@ bool AseFormat::onPostLoad(FileOp* fop)
|
||||
bool flat = (ver[0] == '1' &&
|
||||
ver[1] == '.' &&
|
||||
ver[2] == '1');
|
||||
if (flat && ase_has_groups(folder)) {
|
||||
if (flat && ase_has_groups(group)) {
|
||||
if (fop->context() &&
|
||||
fop->context()->isUIAvailable() &&
|
||||
ui::Alert::show("Warning"
|
||||
@ -369,7 +377,7 @@ bool AseFormat::onPostLoad(FileOp* fop)
|
||||
PACKAGE, ver.c_str()) != 1) {
|
||||
return false;
|
||||
}
|
||||
ase_ungroup_all(folder);
|
||||
ase_ungroup_all(group);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -426,12 +434,9 @@ bool AseFormat::onSave(FileOp* fop)
|
||||
|
||||
// Write extra chunks in the first frame
|
||||
if (frame == fop->roi().fromFrame()) {
|
||||
LayerIterator it = sprite->folder()->getLayerBegin();
|
||||
LayerIterator end = sprite->folder()->getLayerEnd();
|
||||
|
||||
// Write layer chunks
|
||||
for (; it != end; ++it)
|
||||
ase_file_write_layers(f, &frame_header, *it);
|
||||
for (Layer* child : sprite->root()->layers())
|
||||
ase_file_write_layers(f, &frame_header, child, 0);
|
||||
|
||||
// Writer frame tags
|
||||
if (sprite->frameTags().size() > 0)
|
||||
@ -442,8 +447,8 @@ bool AseFormat::onSave(FileOp* fop)
|
||||
|
||||
// Write cel chunks
|
||||
ase_file_write_cels(f, &frame_header,
|
||||
sprite, sprite->folder(),
|
||||
frame, fop->roi().fromFrame());
|
||||
sprite, sprite->root(),
|
||||
0, frame, fop->roi().fromFrame());
|
||||
|
||||
// Write the frame header
|
||||
ase_file_write_frame_header(f, &frame_header);
|
||||
@ -608,35 +613,30 @@ static void ase_file_write_frame_header(FILE* f, ASE_FrameHeader* frame_header)
|
||||
fseek(f, end, SEEK_SET);
|
||||
}
|
||||
|
||||
static void ase_file_write_layers(FILE* f, ASE_FrameHeader* frame_header, const Layer* layer)
|
||||
static void ase_file_write_layers(FILE* f, ASE_FrameHeader* frame_header, const Layer* layer, int child_index)
|
||||
{
|
||||
ase_file_write_layer_chunk(f, frame_header, layer);
|
||||
ase_file_write_layer_chunk(f, frame_header, layer, child_index);
|
||||
if (!layer->userData().isEmpty())
|
||||
ase_file_write_user_data_chunk(f, frame_header, &layer->userData());
|
||||
|
||||
if (layer->isFolder()) {
|
||||
auto it = static_cast<const LayerFolder*>(layer)->getLayerBegin(),
|
||||
end = static_cast<const LayerFolder*>(layer)->getLayerEnd();
|
||||
|
||||
for (; it != end; ++it)
|
||||
ase_file_write_layers(f, frame_header, *it);
|
||||
if (layer->isGroup()) {
|
||||
for (const Layer* child : static_cast<const LayerGroup*>(layer)->layers())
|
||||
ase_file_write_layers(f, frame_header, child, child_index+1);
|
||||
}
|
||||
}
|
||||
|
||||
static void ase_file_write_cels(FILE* f, ASE_FrameHeader* frame_header,
|
||||
const Sprite* sprite, const Layer* layer,
|
||||
const frame_t frame,
|
||||
const frame_t firstFrame)
|
||||
static layer_t ase_file_write_cels(FILE* f, ASE_FrameHeader* frame_header,
|
||||
const Sprite* sprite, const Layer* layer,
|
||||
layer_t layer_index,
|
||||
const frame_t frame,
|
||||
const frame_t firstFrame)
|
||||
{
|
||||
if (layer->isImage()) {
|
||||
const Cel* cel = layer->cel(frame);
|
||||
if (cel) {
|
||||
/* fop->setError("New cel in frame %d, in layer %d\n", */
|
||||
/* frame, sprite_layer2index(sprite, layer)); */
|
||||
|
||||
ase_file_write_cel_chunk(f, frame_header, cel,
|
||||
static_cast<const LayerImage*>(layer),
|
||||
sprite, firstFrame);
|
||||
layer_index, sprite, firstFrame);
|
||||
|
||||
if (!cel->link() &&
|
||||
!cel->data()->userData().isEmpty()) {
|
||||
@ -646,13 +646,18 @@ static void ase_file_write_cels(FILE* f, ASE_FrameHeader* frame_header,
|
||||
}
|
||||
}
|
||||
|
||||
if (layer->isFolder()) {
|
||||
auto it = static_cast<const LayerFolder*>(layer)->getLayerBegin(),
|
||||
end = static_cast<const LayerFolder*>(layer)->getLayerEnd();
|
||||
if (layer != sprite->root())
|
||||
++layer_index;
|
||||
|
||||
for (; it != end; ++it)
|
||||
ase_file_write_cels(f, frame_header, sprite, *it, frame, firstFrame);
|
||||
if (layer->isGroup()) {
|
||||
for (const Layer* child : static_cast<const LayerGroup*>(layer)->layers()) {
|
||||
layer_index =
|
||||
ase_file_write_cels(f, frame_header, sprite, child,
|
||||
layer_index, frame, firstFrame);
|
||||
}
|
||||
}
|
||||
|
||||
return layer_index;
|
||||
}
|
||||
|
||||
static void ase_file_read_padding(FILE* f, int bytes)
|
||||
@ -835,25 +840,19 @@ static void ase_file_write_palette_chunk(FILE* f, ASE_FrameHeader* frame_header,
|
||||
|
||||
static Layer* ase_file_read_layer_chunk(FILE* f, ASE_Header* header, Sprite* sprite, Layer** previous_layer, int* current_level)
|
||||
{
|
||||
std::string name;
|
||||
Layer* layer = NULL;
|
||||
/* read chunk data */
|
||||
int flags;
|
||||
int layer_type;
|
||||
int child_level;
|
||||
|
||||
flags = fgetw(f);
|
||||
layer_type = fgetw(f);
|
||||
child_level = fgetw(f);
|
||||
// Read chunk data
|
||||
int flags = fgetw(f);
|
||||
int layer_type = fgetw(f);
|
||||
int child_level = fgetw(f);
|
||||
fgetw(f); // default width
|
||||
fgetw(f); // default height
|
||||
int blendmode = fgetw(f); // blend mode
|
||||
int opacity = fgetc(f); // opacity
|
||||
|
||||
ase_file_read_padding(f, 3);
|
||||
name = ase_file_read_string(f);
|
||||
std::string name = ase_file_read_string(f);
|
||||
|
||||
// Image layer
|
||||
Layer* layer;
|
||||
if (layer_type == 0) {
|
||||
layer = new LayerImage(sprite);
|
||||
|
||||
@ -866,7 +865,10 @@ static Layer* ase_file_read_layer_chunk(FILE* f, ASE_Header* header, Sprite* spr
|
||||
}
|
||||
// Layer set
|
||||
else if (layer_type == 1) {
|
||||
layer = new LayerFolder(sprite);
|
||||
layer = new LayerGroup(sprite);
|
||||
}
|
||||
else {
|
||||
layer = nullptr;
|
||||
}
|
||||
|
||||
if (layer) {
|
||||
@ -880,7 +882,7 @@ static Layer* ase_file_read_layer_chunk(FILE* f, ASE_Header* header, Sprite* spr
|
||||
if (child_level == *current_level)
|
||||
(*previous_layer)->parent()->addLayer(layer);
|
||||
else if (child_level > *current_level)
|
||||
static_cast<LayerFolder*>(*previous_layer)->addLayer(layer);
|
||||
static_cast<LayerGroup*>(*previous_layer)->addLayer(layer);
|
||||
else if (child_level < *current_level)
|
||||
(*previous_layer)->parent()->parent()->addLayer(layer);
|
||||
|
||||
@ -891,7 +893,7 @@ static Layer* ase_file_read_layer_chunk(FILE* f, ASE_Header* header, Sprite* spr
|
||||
return layer;
|
||||
}
|
||||
|
||||
static void ase_file_write_layer_chunk(FILE* f, ASE_FrameHeader* frame_header, const Layer* layer)
|
||||
static void ase_file_write_layer_chunk(FILE* f, ASE_FrameHeader* frame_header, const Layer* layer, int child_level)
|
||||
{
|
||||
ChunkWriter chunk(f, frame_header, ASE_FILE_CHUNK_LAYER);
|
||||
|
||||
@ -899,15 +901,9 @@ static void ase_file_write_layer_chunk(FILE* f, ASE_FrameHeader* frame_header, c
|
||||
fputw(static_cast<int>(layer->flags()), f);
|
||||
|
||||
// Layer type
|
||||
fputw(layer->isImage() ? 0: (layer->isFolder() ? 1: -1), f);
|
||||
fputw(layer->isImage() ? 0: (layer->isGroup() ? 1: -1), f);
|
||||
|
||||
// Layer child level
|
||||
LayerFolder* parent = layer->parent();
|
||||
int child_level = -1;
|
||||
while (parent != NULL) {
|
||||
child_level++;
|
||||
parent = parent->parent();
|
||||
}
|
||||
fputw(child_level, f);
|
||||
|
||||
// Default width & height, and blend mode
|
||||
@ -916,13 +912,11 @@ static void ase_file_write_layer_chunk(FILE* f, ASE_FrameHeader* frame_header, c
|
||||
fputw(layer->isImage() ? (int)static_cast<const LayerImage*>(layer)->blendMode(): 0, f);
|
||||
fputc(layer->isImage() ? (int)static_cast<const LayerImage*>(layer)->opacity(): 0, f);
|
||||
|
||||
// padding
|
||||
// Padding
|
||||
ase_file_write_padding(f, 3);
|
||||
|
||||
/* layer name */
|
||||
// Layer name
|
||||
ase_file_write_string(f, layer->name());
|
||||
|
||||
/* fop->setError("Layer name \"%s\" child level: %d\n", layer->name, child_level); */
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -1189,21 +1183,25 @@ static void write_compressed_image(FILE* f, const Image* image)
|
||||
// Cel Chunk
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, frame_t frame,
|
||||
static Cel* ase_file_read_cel_chunk(FILE* f,
|
||||
Sprite* sprite,
|
||||
LayerList& allLayers,
|
||||
frame_t frame,
|
||||
PixelFormat pixelFormat,
|
||||
FileOp* fop, ASE_Header* header, size_t chunk_end)
|
||||
{
|
||||
/* read chunk data */
|
||||
LayerIndex layer_index = LayerIndex(fgetw(f));
|
||||
// Read chunk data
|
||||
layer_t layer_index = fgetw(f);
|
||||
int x = ((short)fgetw(f));
|
||||
int y = ((short)fgetw(f));
|
||||
int opacity = fgetc(f);
|
||||
int cel_type = fgetw(f);
|
||||
Layer* layer;
|
||||
|
||||
ase_file_read_padding(f, 7);
|
||||
|
||||
layer = sprite->indexToLayer(layer_index);
|
||||
Layer* layer = nullptr;
|
||||
if (layer_index >= 0 && layer_index < layer_t(allLayers.size()))
|
||||
layer = allLayers[layer_index];
|
||||
|
||||
if (!layer) {
|
||||
fop->setError("Frame %d didn't found layer with index %d\n",
|
||||
(int)frame, (int)layer_index);
|
||||
@ -1326,13 +1324,14 @@ static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, frame_t frame,
|
||||
}
|
||||
|
||||
static void ase_file_write_cel_chunk(FILE* f, ASE_FrameHeader* frame_header,
|
||||
const Cel* cel, const LayerImage* layer,
|
||||
const Cel* cel,
|
||||
const LayerImage* layer,
|
||||
const layer_t layer_index,
|
||||
const Sprite* sprite,
|
||||
const frame_t firstFrame)
|
||||
{
|
||||
ChunkWriter chunk(f, frame_header, ASE_FILE_CHUNK_CEL);
|
||||
|
||||
int layer_index = sprite->layerToIndex(layer);
|
||||
const Cel* link = cel->link();
|
||||
|
||||
// In case the original link is outside the ROI, we've to find the
|
||||
@ -1604,26 +1603,26 @@ static void ase_file_write_user_data_chunk(FILE* f, ASE_FrameHeader* frame_heade
|
||||
}
|
||||
}
|
||||
|
||||
static bool ase_has_groups(LayerFolder* folder)
|
||||
static bool ase_has_groups(LayerGroup* group)
|
||||
{
|
||||
for (Layer* child : folder->getLayersList()) {
|
||||
if (child->isFolder())
|
||||
for (Layer* child : group->layers()) {
|
||||
if (child->isGroup())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ase_ungroup_all(LayerFolder* folder)
|
||||
static void ase_ungroup_all(LayerGroup* group)
|
||||
{
|
||||
LayerFolder* root = folder->sprite()->folder();
|
||||
LayerList list = folder->getLayersList();
|
||||
LayerGroup* root = group->sprite()->root();
|
||||
LayerList list = group->layers();
|
||||
|
||||
for (Layer* child : list) {
|
||||
if (child->isFolder()) {
|
||||
ase_ungroup_all(static_cast<LayerFolder*>(child));
|
||||
folder->removeLayer(child);
|
||||
if (child->isGroup()) {
|
||||
ase_ungroup_all(static_cast<LayerGroup*>(child));
|
||||
group->removeLayer(child);
|
||||
}
|
||||
else if (folder != root) {
|
||||
else if (group != root) {
|
||||
// Create a new name adding all group layer names
|
||||
{
|
||||
std::string name;
|
||||
@ -1635,14 +1634,14 @@ static void ase_ungroup_all(LayerFolder* folder)
|
||||
child->setName(name);
|
||||
}
|
||||
|
||||
folder->removeLayer(child);
|
||||
group->removeLayer(child);
|
||||
root->addLayer(child);
|
||||
}
|
||||
}
|
||||
|
||||
if (folder != root) {
|
||||
ASSERT(folder->getLayersCount() == 0);
|
||||
delete folder;
|
||||
if (group != root) {
|
||||
ASSERT(group->layersCount() == 0);
|
||||
delete group;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -354,7 +354,7 @@ FileOp* FileOp::createSaveDocumentOperation(const Context* context,
|
||||
}
|
||||
|
||||
// Layers support
|
||||
if (fop->m_document->sprite()->folder()->getLayersCount() > 1) {
|
||||
if (fop->m_document->sprite()->root()->layersCount() > 1) {
|
||||
if (!(fop->m_format->support(FILE_SUPPORT_LAYERS))) {
|
||||
warnings += "<<- Layers";
|
||||
}
|
||||
@ -843,7 +843,7 @@ Image* FileOp::sequenceImage(PixelFormat pixelFormat, int w, int h)
|
||||
LayerImage* layer = new LayerImage(sprite);
|
||||
|
||||
// Add the layer
|
||||
sprite->folder()->addLayer(layer);
|
||||
sprite->root()->addLayer(layer);
|
||||
|
||||
// Done
|
||||
createDocument(sprite);
|
||||
|
@ -37,7 +37,7 @@ TEST(File, SeveralSizes)
|
||||
doc->setFilename(&fn[0]);
|
||||
|
||||
// Random pixels
|
||||
Layer* layer = doc->sprite()->folder()->getFirstLayer();
|
||||
Layer* layer = doc->sprite()->root()->firstLayer();
|
||||
ASSERT_TRUE(layer != NULL);
|
||||
Image* image = layer->cel(frame_t(0))->image();
|
||||
std::srand(w*h);
|
||||
@ -60,7 +60,7 @@ TEST(File, SeveralSizes)
|
||||
ASSERT_EQ(h, doc->sprite()->height());
|
||||
|
||||
// Same random pixels (see the seed)
|
||||
Layer* layer = doc->sprite()->folder()->getFirstLayer();
|
||||
Layer* layer = doc->sprite()->root()->firstLayer();
|
||||
ASSERT_TRUE(layer != nullptr);
|
||||
Image* image = layer->cel(frame_t(0))->image();
|
||||
std::srand(w*h);
|
||||
|
@ -74,7 +74,7 @@ bool FliFormat::onLoad(FileOp* fop)
|
||||
// Create the sprite
|
||||
Sprite* sprite = new Sprite(IMAGE_INDEXED, w, h, 256);
|
||||
LayerImage* layer = new LayerImage(sprite);
|
||||
sprite->folder()->addLayer(layer);
|
||||
sprite->root()->addLayer(layer);
|
||||
layer->configureAsBackground();
|
||||
|
||||
// Set frames and speed
|
||||
|
@ -679,7 +679,7 @@ private:
|
||||
clear_image(m_previousImage.get(), m_bgIndex);
|
||||
|
||||
m_layer = new LayerImage(m_sprite.get());
|
||||
m_sprite->folder()->addLayer(m_layer);
|
||||
m_sprite->root()->addLayer(m_layer);
|
||||
}
|
||||
|
||||
void resetRemap(int ncolors) {
|
||||
@ -838,9 +838,7 @@ public:
|
||||
m_sprite->getPalettes().size() == 1) {
|
||||
// If some layer has opacity < 255 or a different blend mode, we
|
||||
// need to create color palettes.
|
||||
std::vector<Layer*> layers;
|
||||
m_sprite->getLayersList(layers);
|
||||
for (const Layer* layer : layers) {
|
||||
for (const Layer* layer : m_sprite->allVisibleLayers()) {
|
||||
if (layer->isVisible() && layer->isImage()) {
|
||||
const LayerImage* imageLayer = static_cast<const LayerImage*>(layer);
|
||||
if (imageLayer->opacity() < 255 ||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -127,7 +127,7 @@ bool IcoFormat::onLoad(FileOp* fop)
|
||||
// Create the sprite with one background layer
|
||||
Sprite* sprite = new Sprite(pixelFormat, width, height, numcolors);
|
||||
LayerImage* layer = new LayerImage(sprite);
|
||||
sprite->folder()->addLayer(layer);
|
||||
sprite->root()->addLayer(layer);
|
||||
|
||||
// Create the first image/cel
|
||||
ImageRef image(Image::create(pixelFormat, width, height));
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -119,7 +119,7 @@ bool save_palette(const char *filename, const Palette* pal, int columns)
|
||||
Sprite* sprite = doc->sprite();
|
||||
doc->sprite()->setPalette(pal, false);
|
||||
|
||||
Layer* layer = sprite->folder()->getFirstLayer();
|
||||
Layer* layer = sprite->root()->firstLayer();
|
||||
Image* image = layer->cel(frame_t(0))->image();
|
||||
|
||||
int x, y, c;
|
||||
|
@ -15,8 +15,8 @@
|
||||
#include "app/file/file.h"
|
||||
#include "app/file/file_format.h"
|
||||
#include "app/xml_document.h"
|
||||
#include "base/file_handle.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/file_handle.h"
|
||||
#include "base/path.h"
|
||||
#include "doc/doc.h"
|
||||
#include "doc/algorithm/shrink_bounds.h"
|
||||
@ -85,7 +85,6 @@ template<typename Number> static Number check_number(const char* c_str) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PixlyFormat::onLoad(FileOp* fop)
|
||||
{
|
||||
try {
|
||||
@ -120,7 +119,7 @@ bool PixlyFormat::onLoad(FileOp* fop)
|
||||
sprite->setDurationForAllFrames(200);
|
||||
|
||||
for (int i=0; i<layerCount; i++) {
|
||||
sprite->folder()->addLayer(new LayerImage(sprite));
|
||||
sprite->root()->addLayer(new LayerImage(sprite));
|
||||
}
|
||||
|
||||
// load image sheet
|
||||
@ -131,16 +130,15 @@ bool PixlyFormat::onLoad(FileOp* fop)
|
||||
throw Exception("Pixly loader requires a valid PNG file");
|
||||
}
|
||||
|
||||
Image* sheet = sheet_doc->sprite()->layer(0)->cel(0)->image();
|
||||
|
||||
if (sheet->pixelFormat() != IMAGE_RGB) {
|
||||
Image* sheet = sheet_doc->sprite()->root()->firstLayer()->cel(0)->image();
|
||||
if (sheet->pixelFormat() != IMAGE_RGB)
|
||||
throw Exception("Pixly loader requires a RGBA PNG");
|
||||
}
|
||||
|
||||
int sheetWidth = sheet->width();
|
||||
int sheetHeight = sheet->height();
|
||||
|
||||
// slice cels from sheet
|
||||
LayerList layers = sprite->allLayers();
|
||||
std::vector<int> visible(layerCount, 0);
|
||||
|
||||
TiXmlElement* xmlFrame = check(xmlFrames->FirstChild("Frame"))->ToElement();
|
||||
@ -150,8 +148,8 @@ bool PixlyFormat::onLoad(FileOp* fop)
|
||||
|
||||
int index = check_number<int>(xmlIndex->Attribute("linear"));
|
||||
frame_t frame(index / layerCount);
|
||||
LayerIndex layer_index(index % layerCount);
|
||||
Layer *layer = sprite->indexToLayer(layer_index);
|
||||
layer_t layer_index(index % layerCount);
|
||||
Layer* layer = layers[layer_index];
|
||||
|
||||
const char * duration = xmlFrame->Attribute("duration");
|
||||
if (duration) {
|
||||
@ -215,16 +213,14 @@ bool PixlyFormat::onLoad(FileOp* fop)
|
||||
fop->setProgress(0.5 + 0.5 * ((float)(index+1) / (float)imageCount));
|
||||
}
|
||||
|
||||
for (int i=0; i<layerCount; i++) {
|
||||
LayerIndex layer_index(i);
|
||||
Layer *layer = sprite->indexToLayer(layer_index);
|
||||
layer->setVisible(visible[i] > frameCount/2);
|
||||
for (layer_t i=0; i<layerCount; i++) {
|
||||
layers[i]->setVisible(visible[i] > frameCount/2);
|
||||
}
|
||||
|
||||
fop->createDocument(sprite);
|
||||
sprite.release();
|
||||
}
|
||||
catch(Exception &e) {
|
||||
catch(Exception& e) {
|
||||
fop->setError((std::string("Pixly file format: ")+std::string(e.what())+"\n").c_str());
|
||||
return false;
|
||||
}
|
||||
@ -237,19 +233,16 @@ bool PixlyFormat::onSave(FileOp* fop)
|
||||
{
|
||||
const Sprite* sprite = fop->document()->sprite();
|
||||
|
||||
auto it = sprite->folder()->getLayerBegin(),
|
||||
end = sprite->folder()->getLayerEnd();
|
||||
for (; it != end; ++it) { // layers
|
||||
Layer *layer = *it;
|
||||
for (const Layer* layer : sprite->root()->layers()) {
|
||||
if (!layer->isImage()) {
|
||||
fop->setError("Pixly .anim file format does not support layer folders\n");
|
||||
fop->setError("Pixly .anim file format does not support layer groups\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// account sheet size
|
||||
int frameCount = sprite->totalFrames();
|
||||
int layerCount = sprite->folder()->getLayersCount();
|
||||
int layerCount = sprite->root()->layersCount();
|
||||
int imageCount = frameCount * layerCount;
|
||||
|
||||
int frameWidth = sprite->width();
|
||||
@ -263,7 +256,7 @@ bool PixlyFormat::onSave(FileOp* fop)
|
||||
// create PNG document
|
||||
Sprite* sheet_sprite = new Sprite(IMAGE_RGB, sheetWidth, sheetHeight, 256);
|
||||
LayerImage* sheet_layer = new LayerImage(sheet_sprite);
|
||||
sheet_sprite->folder()->addLayer(sheet_layer);
|
||||
sheet_sprite->root()->addLayer(sheet_layer);
|
||||
UniquePtr<Document> sheet_doc(new Document(sheet_sprite));
|
||||
ImageRef sheet_image(Image::create(IMAGE_RGB, sheetWidth, sheetHeight));
|
||||
Image* sheet = sheet_image.get();
|
||||
@ -291,11 +284,7 @@ bool PixlyFormat::onSave(FileOp* fop)
|
||||
// write cels on XML and PNG
|
||||
int index = 0;
|
||||
for (frame_t frame(0); frame<sprite->totalFrames(); ++frame) {
|
||||
auto it = sprite->folder()->getLayerBegin(),
|
||||
end = sprite->folder()->getLayerEnd();
|
||||
for (; it != end; ++it, ++index) { // layers
|
||||
Layer *layer = *it;
|
||||
|
||||
for (const Layer* layer : sprite->root()->layers()) { // layers
|
||||
int col = index % squareSide;
|
||||
int row = index / squareSide;
|
||||
|
||||
@ -337,8 +326,8 @@ bool PixlyFormat::onSave(FileOp* fop)
|
||||
} // image
|
||||
} // cel
|
||||
|
||||
fop->setProgress(0.25 + 0.5 * (double)(index+1) / (double)imageCount);
|
||||
|
||||
fop->setProgress(0.1 + 0.8 * (double)(index+1) / (double)imageCount);
|
||||
++index;
|
||||
} // layer
|
||||
} // frame
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -66,12 +66,9 @@ static bool has_cels(const Layer* layer, frame_t frame)
|
||||
case ObjectType::LayerImage:
|
||||
return (layer->cel(frame) ? true: false);
|
||||
|
||||
case ObjectType::LayerFolder: {
|
||||
LayerConstIterator it = static_cast<const LayerFolder*>(layer)->getLayerBegin();
|
||||
LayerConstIterator end = static_cast<const LayerFolder*>(layer)->getLayerEnd();
|
||||
|
||||
for (; it != end; ++it) {
|
||||
if (has_cels(*it, frame))
|
||||
case ObjectType::LayerGroup: {
|
||||
for (const Layer* child : static_cast<const LayerGroup*>(layer)->layers()) {
|
||||
if (has_cels(child, frame))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "doc/brush_pattern.h"
|
||||
#include "doc/documents_observer.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/layer_index.h"
|
||||
#include "doc/layer_list.h"
|
||||
#include "filters/tiled_mode.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "render/onionskin_position.h"
|
||||
|
@ -361,7 +361,7 @@ void DocumentView::onBeforeRemoveLayer(doc::DocumentEvent& ev)
|
||||
|
||||
// If the layer that was removed is the selected one
|
||||
if (layer == m_editor->layer()) {
|
||||
LayerFolder* parent = layer->parent();
|
||||
LayerGroup* parent = layer->parent();
|
||||
Layer* layer_select = NULL;
|
||||
|
||||
// Select previous layer, or next layer, or the parent (if it is
|
||||
@ -370,7 +370,7 @@ void DocumentView::onBeforeRemoveLayer(doc::DocumentEvent& ev)
|
||||
layer_select = layer->getPrevious();
|
||||
else if (layer->getNext())
|
||||
layer_select = layer->getNext();
|
||||
else if (parent != sprite->folder())
|
||||
else if (parent != sprite->root())
|
||||
layer_select = parent;
|
||||
|
||||
m_editor->setLayer(layer_select);
|
||||
|
@ -85,7 +85,9 @@ void BrushPreview::show(const gfx::Point& screenPos)
|
||||
|
||||
app::Document* document = m_editor->document();
|
||||
Sprite* sprite = m_editor->sprite();
|
||||
Layer* layer = m_editor->layer();
|
||||
Layer* layer = (m_editor->layer() &&
|
||||
m_editor->layer()->isImage() ? m_editor->layer():
|
||||
nullptr);
|
||||
ASSERT(sprite);
|
||||
|
||||
// Get drawable region
|
||||
|
@ -152,7 +152,7 @@ Editor::Editor(Document* document, EditorFlags flags)
|
||||
, m_decorator(NULL)
|
||||
, m_document(document)
|
||||
, m_sprite(m_document->sprite())
|
||||
, m_layer(m_sprite->folder()->getFirstLayer())
|
||||
, m_layer(m_sprite->root()->firstLayer())
|
||||
, m_frame(frame_t(0))
|
||||
, m_docPref(Preferences::instance().document(document))
|
||||
, m_brushPreview(this)
|
||||
@ -186,12 +186,16 @@ Editor::Editor(Document* document, EditorFlags flags)
|
||||
base::Bind<void>(&Editor::onContextBarBrushChange, this));
|
||||
|
||||
// Restore last site in preferences
|
||||
frame_t preferredFrame = m_docPref.site.frame();
|
||||
Layer* preferredLayer = m_sprite->indexToLayer(m_docPref.site.layer());
|
||||
if (preferredFrame >= 0 && preferredFrame <= m_sprite->lastFrame())
|
||||
setFrame(preferredFrame);
|
||||
if (preferredLayer)
|
||||
setLayer(preferredLayer);
|
||||
{
|
||||
frame_t preferredFrame = m_docPref.site.frame();
|
||||
if (preferredFrame >= 0 && preferredFrame <= m_sprite->lastFrame())
|
||||
setFrame(preferredFrame);
|
||||
|
||||
LayerList layers = m_sprite->allBrowsableLayers();
|
||||
layer_t layerIndex = m_docPref.site.layer();
|
||||
if (layerIndex >= 0 && layerIndex < int(layers.size()))
|
||||
setLayer(layers[layerIndex]);
|
||||
}
|
||||
|
||||
m_tiledConn = m_docPref.tiled.AfterChange.connect(base::Bind<void>(&Editor::invalidate, this));
|
||||
m_gridConn = m_docPref.grid.AfterChange.connect(base::Bind<void>(&Editor::invalidate, this));
|
||||
@ -211,8 +215,11 @@ Editor::Editor(Document* document, EditorFlags flags)
|
||||
Editor::~Editor()
|
||||
{
|
||||
if (m_document && m_sprite) {
|
||||
LayerList layers = m_sprite->allBrowsableLayers();
|
||||
layer_t layerIndex = doc::find_layer_index(layers, layer());
|
||||
|
||||
m_docPref.site.frame(frame());
|
||||
m_docPref.site.layer(m_sprite->layerToIndex(layer()));
|
||||
m_docPref.site.layer(layerIndex);
|
||||
}
|
||||
|
||||
m_observers.notifyDestroyEditor(this);
|
||||
@ -1442,8 +1449,8 @@ bool Editor::canDraw()
|
||||
{
|
||||
return (m_layer != NULL &&
|
||||
m_layer->isImage() &&
|
||||
m_layer->isVisible() &&
|
||||
m_layer->isEditable());
|
||||
m_layer->isVisibleHierarchy() &&
|
||||
m_layer->isEditableHierarchy());
|
||||
}
|
||||
|
||||
bool Editor::isInsideSelection()
|
||||
|
@ -209,11 +209,11 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
StatusBar::instance()->showTip(1000,
|
||||
"The background layer cannot be moved");
|
||||
}
|
||||
else if (!layer->isVisible()) {
|
||||
else if (!layer->isVisibleHierarchy()) {
|
||||
StatusBar::instance()->showTip(1000,
|
||||
"Layer '%s' is hidden", layer->name().c_str());
|
||||
}
|
||||
else if (!layer->isMovable() || !layer->isEditable()) {
|
||||
else if (!layer->isMovable() || !layer->isEditableHierarchy()) {
|
||||
StatusBar::instance()->showTip(1000,
|
||||
"Layer '%s' is locked", layer->name().c_str());
|
||||
}
|
||||
@ -253,7 +253,7 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
int x, y, opacity;
|
||||
Image* image = site.image(&x, &y, &opacity);
|
||||
if (layer && image) {
|
||||
if (!layer->isEditable()) {
|
||||
if (!layer->isEditableHierarchy()) {
|
||||
StatusBar::instance()->showTip(1000,
|
||||
"Layer '%s' is locked", layer->name().c_str());
|
||||
return true;
|
||||
@ -268,7 +268,7 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
|
||||
// Move selected pixels
|
||||
if (layer && editor->isInsideSelection() && msg->left()) {
|
||||
if (!layer->isEditable()) {
|
||||
if (!layer->isEditableHierarchy()) {
|
||||
StatusBar::instance()->showTip(1000,
|
||||
"Layer '%s' is locked", layer->name().c_str());
|
||||
return true;
|
||||
@ -297,7 +297,7 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
}
|
||||
|
||||
// Start the Tool-Loop
|
||||
if (layer) {
|
||||
if (layer && layer->isImage()) {
|
||||
// Disable layer edges to avoid showing the modified cel
|
||||
// information by ExpandCelCanvas (i.e. the cel origin is changed
|
||||
// to 0,0 coordinate.)
|
||||
|
@ -497,13 +497,13 @@ tools::ToolLoop* create_tool_loop(Editor* editor, Context* context)
|
||||
1000, "There is no active layer");
|
||||
return nullptr;
|
||||
}
|
||||
else if (!layer->isVisible()) {
|
||||
else if (!layer->isVisibleHierarchy()) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000, "Layer '%s' is hidden", layer->name().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
// If the active layer is read-only.
|
||||
else if (!layer->isEditable()) {
|
||||
else if (!layer->isEditableHierarchy()) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000, "Layer '%s' is locked", layer->name().c_str());
|
||||
return nullptr;
|
||||
@ -615,8 +615,8 @@ tools::ToolLoop* create_tool_loop_preview(
|
||||
|
||||
Layer* layer = editor->layer();
|
||||
if (!layer ||
|
||||
!layer->isVisible() ||
|
||||
!layer->isEditable()) {
|
||||
!layer->isVisibleHierarchy() ||
|
||||
!layer->isEditableHierarchy()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -459,10 +459,10 @@ void SkinTheme::loadXml(const std::string& skinId)
|
||||
else if (ruleName == "icon") {
|
||||
if (align) (*style)[StyleSheet::iconAlignRule()] = css::Value(align);
|
||||
if (part_id) (*style)[StyleSheet::iconPartRule()] = css::Value(part_id);
|
||||
if (color_id) (*style)[StyleSheet::iconColorRule()] = value_or_none(color_id);
|
||||
|
||||
const char* x = xmlRule->Attribute("x");
|
||||
const char* y = xmlRule->Attribute("y");
|
||||
|
||||
if (x) (*style)[StyleSheet::iconXRule()] = css::Value(strtol(x, NULL, 10));
|
||||
if (y) (*style)[StyleSheet::iconYRule()] = css::Value(strtol(y, NULL, 10));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -23,6 +23,7 @@ namespace skin {
|
||||
css::State Style::m_hoverState("hover");
|
||||
css::State Style::m_activeState("active");
|
||||
css::State Style::m_clickedState("clicked");
|
||||
css::State Style::m_disabledState("disabled");
|
||||
|
||||
Rule::~Rule()
|
||||
{
|
||||
@ -110,7 +111,10 @@ void IconRule::onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* tex
|
||||
x += m_x;
|
||||
y += m_y;
|
||||
|
||||
g->drawRgbaSurface(bmp, x, y);
|
||||
if (m_color == gfx::ColorNone)
|
||||
g->drawRgbaSurface(bmp, x, y);
|
||||
else
|
||||
g->drawColoredRgbaSurface(bmp, m_color, x, y);
|
||||
}
|
||||
|
||||
Rules::Rules(const css::Query& query) :
|
||||
@ -125,6 +129,7 @@ Rules::Rules(const css::Query& query) :
|
||||
css::Value iconPart = query[StyleSheet::iconPartRule()];
|
||||
css::Value iconX = query[StyleSheet::iconXRule()];
|
||||
css::Value iconY = query[StyleSheet::iconYRule()];
|
||||
css::Value iconColor = query[StyleSheet::iconColorRule()];
|
||||
css::Value textAlign = query[StyleSheet::textAlignRule()];
|
||||
css::Value textColor = query[StyleSheet::textColorRule()];
|
||||
css::Value paddingLeft = query[StyleSheet::paddingLeftRule()];
|
||||
@ -145,12 +150,14 @@ Rules::Rules(const css::Query& query) :
|
||||
if (iconAlign != none
|
||||
|| iconPart != none
|
||||
|| iconX != none
|
||||
|| iconY != none) {
|
||||
|| iconY != none
|
||||
|| iconColor != none) {
|
||||
m_icon = new IconRule();
|
||||
m_icon->setAlign((int)iconAlign.number());
|
||||
m_icon->setPart(StyleSheet::convertPart(iconPart));
|
||||
m_icon->setX((int)iconX.number()*ui::guiscale());
|
||||
m_icon->setY((int)iconY.number()*ui::guiscale());
|
||||
m_icon->setColor(StyleSheet::convertColor(iconColor));
|
||||
}
|
||||
|
||||
if (textAlign != none
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -84,12 +84,14 @@ namespace app {
|
||||
|
||||
class IconRule : public Rule {
|
||||
public:
|
||||
explicit IconRule() : m_align(0) { }
|
||||
explicit IconRule() : m_align(0),
|
||||
m_color(gfx::ColorNone) { }
|
||||
|
||||
void setAlign(int align) { m_align = align; }
|
||||
void setPart(const SkinPartPtr& part) { m_part = part; }
|
||||
void setX(int x) { m_x = x; }
|
||||
void setY(int y) { m_y = y; }
|
||||
void setColor(gfx::Color color) { m_color = color; }
|
||||
|
||||
SkinPartPtr getPart() { return m_part; }
|
||||
|
||||
@ -100,6 +102,7 @@ namespace app {
|
||||
int m_align;
|
||||
SkinPartPtr m_part;
|
||||
int m_x, m_y;
|
||||
gfx::Color m_color;
|
||||
};
|
||||
|
||||
class Rules {
|
||||
@ -128,6 +131,7 @@ namespace app {
|
||||
static const css::State& hover() { return m_hoverState; }
|
||||
static const css::State& active() { return m_activeState; }
|
||||
static const css::State& clicked() { return m_clickedState; }
|
||||
static const css::State& disabled() { return m_disabledState; }
|
||||
|
||||
Style(css::Sheet& sheet, const std::string& id);
|
||||
~Style();
|
||||
@ -156,6 +160,7 @@ namespace app {
|
||||
static css::State m_hoverState;
|
||||
static css::State m_activeState;
|
||||
static css::State m_clickedState;
|
||||
static css::State m_disabledState;
|
||||
};
|
||||
|
||||
} // namespace skin
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -28,6 +28,7 @@ css::Rule StyleSheet::m_iconAlignRule("icon-align");
|
||||
css::Rule StyleSheet::m_iconPartRule("icon-part");
|
||||
css::Rule StyleSheet::m_iconXRule("icon-x");
|
||||
css::Rule StyleSheet::m_iconYRule("icon-y");
|
||||
css::Rule StyleSheet::m_iconColorRule("icon-color");
|
||||
css::Rule StyleSheet::m_textAlignRule("text-align");
|
||||
css::Rule StyleSheet::m_textColorRule("text-color");
|
||||
css::Rule StyleSheet::m_paddingLeftRule("padding-left");
|
||||
@ -45,6 +46,7 @@ StyleSheet::StyleSheet()
|
||||
m_sheet->addRule(&m_iconPartRule);
|
||||
m_sheet->addRule(&m_iconXRule);
|
||||
m_sheet->addRule(&m_iconYRule);
|
||||
m_sheet->addRule(&m_iconColorRule);
|
||||
m_sheet->addRule(&m_textAlignRule);
|
||||
m_sheet->addRule(&m_textColorRule);
|
||||
m_sheet->addRule(&m_paddingLeftRule);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -43,6 +43,7 @@ namespace app {
|
||||
static css::Rule& iconPartRule() { return m_iconPartRule; }
|
||||
static css::Rule& iconXRule() { return m_iconXRule; }
|
||||
static css::Rule& iconYRule() { return m_iconYRule; }
|
||||
static css::Rule& iconColorRule() { return m_iconColorRule; }
|
||||
static css::Rule& textAlignRule() { return m_textAlignRule; }
|
||||
static css::Rule& textColorRule() { return m_textColorRule; }
|
||||
static css::Rule& paddingLeftRule() { return m_paddingLeftRule; }
|
||||
@ -69,6 +70,7 @@ namespace app {
|
||||
static css::Rule m_iconPartRule;
|
||||
static css::Rule m_iconXRule;
|
||||
static css::Rule m_iconYRule;
|
||||
static css::Rule m_iconColorRule;
|
||||
static css::Rule m_textAlignRule;
|
||||
static css::Rule m_textColorRule;
|
||||
static css::Rule m_paddingLeftRule;
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "doc/context_observer.h"
|
||||
#include "doc/document_observer.h"
|
||||
#include "doc/documents_observer.h"
|
||||
#include "doc/layer_index.h"
|
||||
#include "ui/base.h"
|
||||
#include "ui/box.h"
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,7 +18,8 @@
|
||||
#include "doc/document_observer.h"
|
||||
#include "doc/documents_observer.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/layer_index.h"
|
||||
#include "doc/selected_frames.h"
|
||||
#include "doc/selected_layers.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "ui/scroll_bar.h"
|
||||
#include "ui/timer.h"
|
||||
@ -88,6 +89,8 @@ namespace app {
|
||||
bool isMovingCel() const;
|
||||
|
||||
Range range() const { return m_range; }
|
||||
const SelectedLayers& selectedLayers() const { return m_range.selectedLayers(); }
|
||||
const SelectedFrames& selectedFrames() const { return m_range.selectedFrames(); }
|
||||
|
||||
void prepareToMoveRange();
|
||||
void moveRange(Range& range);
|
||||
@ -147,12 +150,13 @@ namespace app {
|
||||
|
||||
struct Hit {
|
||||
int part;
|
||||
LayerIndex layer;
|
||||
layer_t layer;
|
||||
frame_t frame;
|
||||
ObjectId frameTag;
|
||||
bool veryBottom;
|
||||
|
||||
Hit(int part = 0, LayerIndex layer = LayerIndex(0), frame_t frame = 0, ObjectId frameTag = NullId)
|
||||
: part(part), layer(layer), frame(frame), frameTag(frameTag) {
|
||||
Hit(int part = 0, layer_t layer = -1, frame_t frame = 0, ObjectId frameTag = NullId)
|
||||
: part(part), layer(layer), frame(frame), frameTag(frameTag), veryBottom(false) {
|
||||
}
|
||||
|
||||
bool operator!=(const Hit& other) const {
|
||||
@ -167,8 +171,20 @@ namespace app {
|
||||
};
|
||||
|
||||
struct DropTarget {
|
||||
enum HHit { HNone, Before, After };
|
||||
enum VHit { VNone, Bottom, Top };
|
||||
|
||||
enum HHit {
|
||||
HNone,
|
||||
Before,
|
||||
After
|
||||
};
|
||||
|
||||
enum VHit {
|
||||
VNone,
|
||||
Bottom,
|
||||
Top,
|
||||
FirstChild,
|
||||
VeryBottom
|
||||
};
|
||||
|
||||
DropTarget() {
|
||||
hhit = HNone;
|
||||
@ -178,11 +194,40 @@ namespace app {
|
||||
HHit hhit;
|
||||
VHit vhit;
|
||||
Layer* layer;
|
||||
LayerIndex layerIdx;
|
||||
ObjectId layerId;
|
||||
frame_t frame;
|
||||
int xpos, ypos;
|
||||
};
|
||||
|
||||
struct LayerInfo {
|
||||
Layer* layer;
|
||||
int level;
|
||||
LayerFlags inheritedFlags;
|
||||
|
||||
LayerInfo()
|
||||
: layer(nullptr),
|
||||
level(0),
|
||||
inheritedFlags(LayerFlags::None) {
|
||||
}
|
||||
|
||||
LayerInfo(Layer* layer, int level, LayerFlags inheritedFlags)
|
||||
: layer(layer),
|
||||
level(level),
|
||||
inheritedFlags(inheritedFlags) {
|
||||
}
|
||||
|
||||
bool parentVisible() const {
|
||||
return ((int(inheritedFlags) & int(LayerFlags::Visible)) != 0);
|
||||
}
|
||||
|
||||
bool parentEditable() const {
|
||||
return ((int(inheritedFlags) & int(LayerFlags::Editable)) != 0);
|
||||
}
|
||||
};
|
||||
|
||||
bool selectedLayersBounds(const SelectedLayers& layers,
|
||||
layer_t* first, layer_t* last) const;
|
||||
|
||||
void setLayer(Layer* layer);
|
||||
void setFrame(frame_t frame, bool byUser);
|
||||
bool allLayersVisible();
|
||||
@ -193,23 +238,24 @@ namespace app {
|
||||
bool allLayersDiscontinuous();
|
||||
void detachDocument();
|
||||
void setCursor(ui::Message* msg, const Hit& hit);
|
||||
void getDrawableLayers(ui::Graphics* g, LayerIndex* first_layer, LayerIndex* last_layer);
|
||||
void getDrawableFrames(ui::Graphics* g, frame_t* first_frame, frame_t* last_frame);
|
||||
void getDrawableLayers(ui::Graphics* g, layer_t* firstLayer, layer_t* lastLayer);
|
||||
void getDrawableFrames(ui::Graphics* g, frame_t* firstFrame, frame_t* lastFrame);
|
||||
void drawPart(ui::Graphics* g, const gfx::Rect& bounds,
|
||||
const char* text, skin::Style* style,
|
||||
bool is_active = false, bool is_hover = false, bool is_clicked = false);
|
||||
const char* text, skin::Style* style,
|
||||
bool is_active = false, bool is_hover = false,
|
||||
bool is_clicked = false, bool is_disabled = false);
|
||||
void drawTop(ui::Graphics* g);
|
||||
void drawHeader(ui::Graphics* g);
|
||||
void drawHeaderFrame(ui::Graphics* g, frame_t frame);
|
||||
void drawLayer(ui::Graphics* g, LayerIndex layerIdx);
|
||||
void drawCel(ui::Graphics* g, LayerIndex layerIdx, frame_t frame, Cel* cel, DrawCelData* data);
|
||||
void drawLayer(ui::Graphics* g, layer_t layerIdx);
|
||||
void drawCel(ui::Graphics* g, layer_t layerIdx, frame_t frame, Cel* cel, DrawCelData* data);
|
||||
void drawCelLinkDecorators(ui::Graphics* g, const gfx::Rect& bounds,
|
||||
Cel* cel, frame_t frame, bool is_active, bool is_hover,
|
||||
DrawCelData* data);
|
||||
void drawFrameTags(ui::Graphics* g);
|
||||
void drawRangeOutline(ui::Graphics* g);
|
||||
void drawPaddings(ui::Graphics* g);
|
||||
bool drawPart(ui::Graphics* g, int part, LayerIndex layer, frame_t frame);
|
||||
bool drawPart(ui::Graphics* g, int part, layer_t layer, frame_t frame);
|
||||
void drawClipboardRange(ui::Graphics* g);
|
||||
gfx::Rect getLayerHeadersBounds() const;
|
||||
gfx::Rect getFrameHeadersBounds() const;
|
||||
@ -224,14 +270,14 @@ namespace app {
|
||||
Hit hitTest(ui::Message* msg, const gfx::Point& mousePos);
|
||||
Hit hitTestCel(const gfx::Point& mousePos);
|
||||
void setHot(const Hit& hit);
|
||||
void showCel(LayerIndex layer, frame_t frame);
|
||||
void showCel(layer_t layer, frame_t frame);
|
||||
void showCurrentCel();
|
||||
void cleanClk();
|
||||
gfx::Size getScrollableSize() const;
|
||||
gfx::Point getMaxScrollablePos() const;
|
||||
LayerIndex getLayerIndex(const Layer* layer) const;
|
||||
bool isLayerActive(LayerIndex layerIdx) const;
|
||||
bool isFrameActive(frame_t frame) const;
|
||||
layer_t getLayerIndex(const Layer* layer) const;
|
||||
bool isLayerActive(const layer_t layerIdx) const;
|
||||
bool isFrameActive(const frame_t frame) const;
|
||||
void updateStatusBar(ui::Message* msg);
|
||||
void updateDropRange(const gfx::Point& pt);
|
||||
void clearClipboardRange();
|
||||
@ -239,15 +285,14 @@ namespace app {
|
||||
bool isCopyKeyPressed(ui::Message* msg);
|
||||
|
||||
// The layer of the bottom (e.g. Background layer)
|
||||
LayerIndex firstLayer() const { return LayerIndex(0); }
|
||||
|
||||
layer_t firstLayer() const { return 0; }
|
||||
// The layer of the top.
|
||||
LayerIndex lastLayer() const { return LayerIndex(m_layers.size()-1); }
|
||||
layer_t lastLayer() const { return m_layers.size()-1; }
|
||||
|
||||
frame_t firstFrame() const { return frame_t(0); }
|
||||
frame_t lastFrame() const { return m_sprite->lastFrame(); }
|
||||
|
||||
bool validLayer(LayerIndex layer) const { return layer >= firstLayer() && layer <= lastLayer(); }
|
||||
bool validLayer(layer_t layer) const { return layer >= firstLayer() && layer <= lastLayer(); }
|
||||
bool validFrame(frame_t frame) const { return frame >= firstFrame() && frame <= lastFrame(); }
|
||||
|
||||
int topHeight() const;
|
||||
@ -265,9 +310,10 @@ namespace app {
|
||||
Layer* m_layer;
|
||||
frame_t m_frame;
|
||||
Range m_range;
|
||||
Range m_startRange;
|
||||
Range m_dropRange;
|
||||
State m_state;
|
||||
std::vector<Layer*> m_layers;
|
||||
std::vector<LayerInfo> m_layers;
|
||||
int m_separator_x;
|
||||
int m_separator_w;
|
||||
int m_origFrames;
|
||||
@ -293,7 +339,7 @@ namespace app {
|
||||
|
||||
// Temporal data used to move the range.
|
||||
struct MoveRange {
|
||||
int activeRelativeLayer;
|
||||
layer_t activeRelativeLayer;
|
||||
frame_t activeRelativeFrame;
|
||||
} m_moveRangeData;
|
||||
};
|
||||
|
@ -221,13 +221,38 @@ void UIContext::onGetActiveSite(Site* site) const
|
||||
DocumentView* view = activeView();
|
||||
if (view) {
|
||||
view->getSite(site);
|
||||
|
||||
if (site->sprite()) {
|
||||
// Selected layers
|
||||
Timeline* timeline = App::instance()->timeline();
|
||||
if (timeline &&
|
||||
timeline->range().enabled()) {
|
||||
switch (timeline->range().type()) {
|
||||
case DocumentRange::kCels: site->focus(Site::InCels); break;
|
||||
case DocumentRange::kFrames: site->focus(Site::InFrames); break;
|
||||
case DocumentRange::kLayers: site->focus(Site::InLayers); break;
|
||||
}
|
||||
site->selectedLayers(timeline->selectedLayers());
|
||||
site->selectedFrames(timeline->selectedFrames());
|
||||
}
|
||||
else {
|
||||
ColorBar* colorBar = ColorBar::instance();
|
||||
if (colorBar &&
|
||||
colorBar->getPaletteView()->getSelectedEntriesCount() > 0) {
|
||||
site->focus(Site::InColorBar);
|
||||
}
|
||||
else {
|
||||
site->focus(Site::InEditor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Default/dummy site (maybe for batch/command line mode)
|
||||
else if (!isUIAvailable()) {
|
||||
if (Document* doc = m_lastSelectedDoc) {
|
||||
site->document(doc);
|
||||
site->sprite(doc->sprite());
|
||||
site->layer(doc->sprite()->indexToLayer(LayerIndex(0)));
|
||||
site->layer(doc->sprite()->root()->firstLayer());
|
||||
site->frame(0);
|
||||
}
|
||||
}
|
||||
|
@ -348,33 +348,28 @@ void paste()
|
||||
DocumentRange srcRange = clipboard_range.range();
|
||||
Document* srcDoc = clipboard_range.document();
|
||||
Sprite* srcSpr = srcDoc->sprite();
|
||||
std::vector<Layer*> srcLayers;
|
||||
std::vector<Layer*> dstLayers;
|
||||
srcSpr->getLayersList(srcLayers);
|
||||
dstSpr->getLayersList(dstLayers);
|
||||
|
||||
switch (srcRange.type()) {
|
||||
|
||||
case DocumentRange::kCels: {
|
||||
Layer* dstLayer = editor->layer();
|
||||
frame_t dstFrameFirst = editor->frame();
|
||||
|
||||
DocumentRange dstRange;
|
||||
dstRange.startRange(dstLayer, dstFrameFirst, DocumentRange::kCels);
|
||||
for (layer_t i=1; i<srcRange.layers(); ++i) {
|
||||
dstLayer = dstLayer->getPreviousInWholeHierarchy();
|
||||
if (dstLayer == nullptr)
|
||||
break;
|
||||
}
|
||||
dstRange.endRange(dstLayer, dstFrameFirst+srcRange.frames()-1);
|
||||
|
||||
// We can use a document range op (copy_range) to copy/paste
|
||||
// cels in the same document.
|
||||
if (srcDoc == dstDoc) {
|
||||
Timeline* timeline = App::instance()->timeline();
|
||||
DocumentRange dstRange = timeline->range();
|
||||
LayerIndex dstLayer = srcSpr->layerToIndex(editor->layer());
|
||||
frame_t dstFrame = editor->frame();
|
||||
|
||||
if (dstRange.enabled()) {
|
||||
dstLayer = dstRange.layerEnd();
|
||||
dstFrame = dstRange.frameBegin();
|
||||
}
|
||||
|
||||
LayerIndex dstLayer2(int(dstLayer)-srcRange.layers()+1);
|
||||
dstRange.startRange(dstLayer, dstFrame, DocumentRange::kCels);
|
||||
dstRange.endRange(dstLayer2, dstFrame+srcRange.frames()-1);
|
||||
|
||||
// This is the app::copy_range (not clipboard::copy_range()).
|
||||
app::copy_range(srcDoc, srcRange, dstRange, kDocumentRangeBefore);
|
||||
if (srcRange.layers() == dstRange.layers())
|
||||
app::copy_range(srcDoc, srcRange, dstRange, kDocumentRangeBefore);
|
||||
editor->invalidate();
|
||||
return;
|
||||
}
|
||||
@ -383,32 +378,36 @@ void paste()
|
||||
DocumentApi api = dstDoc->getApi(transaction);
|
||||
|
||||
// Add extra frames if needed
|
||||
frame_t dstFrameBegin = editor->frame();
|
||||
while (dstFrameBegin+srcRange.frames() > dstSpr->totalFrames())
|
||||
while (dstFrameFirst+srcRange.frames() > dstSpr->totalFrames())
|
||||
api.addFrame(dstSpr, dstSpr->totalFrames());
|
||||
|
||||
for (LayerIndex
|
||||
i = srcRange.layerEnd(),
|
||||
j = dstSpr->layerToIndex(editor->layer());
|
||||
i >= srcRange.layerBegin() &&
|
||||
i >= LayerIndex(0) &&
|
||||
j >= LayerIndex(0); --i, --j) {
|
||||
auto srcIt = srcRange.selectedLayers().begin();
|
||||
auto dstIt = dstRange.selectedLayers().begin();
|
||||
auto srcEnd = srcRange.selectedLayers().end();
|
||||
auto dstEnd = dstRange.selectedLayers().end();
|
||||
|
||||
for (; srcIt != srcEnd && dstIt != dstEnd; ++srcIt, ++dstIt) {
|
||||
auto srcLayer = *srcIt;
|
||||
auto dstLayer = *dstIt;
|
||||
|
||||
if (!srcLayer->isImage() ||
|
||||
!dstLayer->isImage())
|
||||
continue;
|
||||
|
||||
// Maps a linked Cel in the original sprite with its
|
||||
// corresponding copy in the new sprite. In this way
|
||||
// we can.
|
||||
std::map<Cel*, Cel*> relatedCels;
|
||||
|
||||
for (frame_t frame = srcRange.frameBegin(),
|
||||
dstFrame = dstFrameBegin;
|
||||
frame <= srcRange.frameEnd();
|
||||
++frame, ++dstFrame) {
|
||||
Cel* srcCel = srcLayers[i]->cel(frame);
|
||||
frame_t dstFrame = dstFrameFirst;
|
||||
for (frame_t srcFrame : srcRange.selectedFrames()) {
|
||||
Cel* srcCel = srcLayer->cel(srcFrame);
|
||||
Cel* srcLink = nullptr;
|
||||
|
||||
if (srcCel && srcCel->image()) {
|
||||
bool createCopy = true;
|
||||
|
||||
if (dstLayers[j]->isContinuous() &&
|
||||
if (dstLayer->isContinuous() &&
|
||||
srcCel->links()) {
|
||||
srcLink = srcCel->link();
|
||||
if (!srcLink)
|
||||
@ -421,28 +420,29 @@ void paste()
|
||||
|
||||
// Create a link from dstRelated
|
||||
api.copyCel(
|
||||
static_cast<LayerImage*>(dstLayers[j]), dstRelated->frame(),
|
||||
static_cast<LayerImage*>(dstLayers[j]), dstFrame);
|
||||
static_cast<LayerImage*>(dstLayer), dstRelated->frame(),
|
||||
static_cast<LayerImage*>(dstLayer), dstFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (createCopy) {
|
||||
api.copyCel(
|
||||
static_cast<LayerImage*>(srcLayers[i]), frame,
|
||||
static_cast<LayerImage*>(dstLayers[j]), dstFrame);
|
||||
static_cast<LayerImage*>(srcLayer), srcFrame,
|
||||
static_cast<LayerImage*>(dstLayer), dstFrame);
|
||||
|
||||
if (srcLink)
|
||||
relatedCels[srcLink] = dstLayers[j]->cel(dstFrame);
|
||||
relatedCels[srcLink] = dstLayer->cel(dstFrame);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Cel* dstCel = dstLayers[j]->cel(dstFrame);
|
||||
Cel* dstCel = dstLayer->cel(dstFrame);
|
||||
if (dstCel)
|
||||
api.clearCel(dstCel);
|
||||
}
|
||||
}
|
||||
|
||||
++dstFrame;
|
||||
}
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
@ -451,42 +451,49 @@ void paste()
|
||||
}
|
||||
|
||||
case DocumentRange::kFrames: {
|
||||
Transaction transaction(UIContext::instance(), "Paste Frames");
|
||||
DocumentApi api = dstDoc->getApi(transaction);
|
||||
frame_t dstFrame = editor->frame();
|
||||
|
||||
// We use a DocumentRange operation to copy frames inside
|
||||
// the same sprite.
|
||||
if (srcSpr == dstSpr) {
|
||||
if (srcRange.inRange(dstFrame))
|
||||
dstFrame = srcRange.frameEnd()+1;
|
||||
DocumentRange dstRange;
|
||||
dstRange.startRange(nullptr, dstFrame, DocumentRange::kFrames);
|
||||
dstRange.endRange(nullptr, dstFrame);
|
||||
app::copy_range(srcDoc, srcRange, dstRange, kDocumentRangeBefore);
|
||||
break;
|
||||
}
|
||||
|
||||
frame_t srcFrame = srcRange.frameBegin();
|
||||
for (frame_t frame = srcRange.frameBegin(); frame <= srcRange.frameEnd(); ++frame) {
|
||||
Transaction transaction(UIContext::instance(), "Paste Frames");
|
||||
DocumentApi api = dstDoc->getApi(transaction);
|
||||
|
||||
auto srcLayers = srcSpr->allBrowsableLayers();
|
||||
auto dstLayers = dstSpr->allBrowsableLayers();
|
||||
|
||||
for (frame_t srcFrame : srcRange.selectedFrames()) {
|
||||
api.addEmptyFrame(dstSpr, dstFrame);
|
||||
|
||||
// If we are copying frames from/to the same sprite, we
|
||||
// have to adjust the source frame.
|
||||
if (srcSpr == dstSpr) {
|
||||
if (dstFrame < srcFrame)
|
||||
++srcFrame;
|
||||
}
|
||||
|
||||
api.setFrameDuration(dstSpr, dstFrame, srcSpr->frameDuration(srcFrame));
|
||||
|
||||
for (LayerIndex
|
||||
i = LayerIndex(srcLayers.size()-1),
|
||||
j = LayerIndex(dstLayers.size()-1);
|
||||
i >= LayerIndex(0) &&
|
||||
j >= LayerIndex(0); --i, --j) {
|
||||
Cel* cel = static_cast<LayerImage*>(srcLayers[i])->cel(srcFrame);
|
||||
auto srcIt = srcLayers.begin();
|
||||
auto dstIt = dstLayers.begin();
|
||||
auto srcEnd = srcLayers.end();
|
||||
auto dstEnd = dstLayers.end();
|
||||
|
||||
for (; srcIt != srcEnd && dstIt != dstEnd; ++srcIt, ++dstIt) {
|
||||
auto srcLayer = *srcIt;
|
||||
auto dstLayer = *dstIt;
|
||||
|
||||
if (!srcLayer->isImage() ||
|
||||
!dstLayer->isImage())
|
||||
continue;
|
||||
|
||||
Cel* cel = static_cast<LayerImage*>(srcLayer)->cel(srcFrame);
|
||||
if (cel && cel->image()) {
|
||||
api.copyCel(
|
||||
static_cast<LayerImage*>(srcLayers[i]), srcFrame,
|
||||
static_cast<LayerImage*>(dstLayers[j]), dstFrame);
|
||||
static_cast<LayerImage*>(srcLayer), srcFrame,
|
||||
static_cast<LayerImage*>(dstLayer), dstFrame);
|
||||
}
|
||||
}
|
||||
|
||||
++srcFrame;
|
||||
++dstFrame;
|
||||
}
|
||||
|
||||
@ -502,39 +509,49 @@ void paste()
|
||||
Transaction transaction(UIContext::instance(), "Paste Layers");
|
||||
DocumentApi api = dstDoc->getApi(transaction);
|
||||
|
||||
// Remove children if their parent is selected so we only
|
||||
// copy the parent.
|
||||
SelectedLayers srcLayersSet = srcRange.selectedLayers();
|
||||
srcLayersSet.removeChildrenIfParentIsSelected();
|
||||
LayerList srcLayers = srcLayersSet.toLayerList();
|
||||
|
||||
// Expand frames of dstDoc if it's needed.
|
||||
frame_t maxFrame(0);
|
||||
for (LayerIndex i = srcRange.layerBegin();
|
||||
i <= srcRange.layerEnd() &&
|
||||
i < LayerIndex(srcLayers.size()); ++i) {
|
||||
Cel* lastCel = static_cast<LayerImage*>(srcLayers[i])->getLastCel();
|
||||
frame_t maxFrame = 0;
|
||||
for (Layer* srcLayer : srcLayers) {
|
||||
if (!srcLayer->isImage())
|
||||
continue;
|
||||
|
||||
Cel* lastCel = static_cast<LayerImage*>(srcLayer)->getLastCel();
|
||||
if (lastCel && maxFrame < lastCel->frame())
|
||||
maxFrame = lastCel->frame();
|
||||
}
|
||||
while (dstSpr->totalFrames() < maxFrame+1)
|
||||
api.addEmptyFrame(dstSpr, dstSpr->totalFrames());
|
||||
|
||||
for (LayerIndex i = srcRange.layerBegin(); i <= srcRange.layerEnd(); ++i) {
|
||||
for (Layer* srcLayer : srcLayers) {
|
||||
Layer* afterThis;
|
||||
if (srcLayers[i]->isBackground() &&
|
||||
!dstDoc->sprite()->backgroundLayer()) {
|
||||
if (srcLayer->isBackground() && !dstDoc->sprite()->backgroundLayer())
|
||||
afterThis = nullptr;
|
||||
}
|
||||
else
|
||||
afterThis = dstSpr->folder()->getLastLayer();
|
||||
afterThis = dstSpr->root()->lastLayer();
|
||||
|
||||
LayerImage* newLayer = new LayerImage(dstSpr);
|
||||
api.addLayer(dstSpr->folder(), newLayer, afterThis);
|
||||
Layer* newLayer = nullptr;
|
||||
if (srcLayer->isImage())
|
||||
newLayer = new LayerImage(dstSpr);
|
||||
else if (srcLayer->isGroup())
|
||||
newLayer = new LayerGroup(dstSpr);
|
||||
else
|
||||
continue;
|
||||
|
||||
srcDoc->copyLayerContent(
|
||||
srcLayers[i], dstDoc, newLayer);
|
||||
api.addLayer(dstSpr->root(), newLayer, afterThis);
|
||||
|
||||
srcDoc->copyLayerContent(srcLayer, dstDoc, newLayer);
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
editor->invalidate();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
@ -34,16 +34,12 @@ CelList get_unique_cels(Sprite* sprite, const DocumentRange& inrange)
|
||||
|
||||
std::set<ObjectId> visited;
|
||||
|
||||
for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) {
|
||||
Layer* layer = sprite->indexToLayer(layerIdx);
|
||||
for (Layer* layer : range.selectedLayers()) {
|
||||
if (!layer || !layer->isImage())
|
||||
continue;
|
||||
|
||||
LayerImage* layerImage = static_cast<LayerImage*>(layer);
|
||||
for (frame_t frame = range.frameEnd(),
|
||||
begin = range.frameBegin()-1;
|
||||
frame != begin;
|
||||
--frame) {
|
||||
for (frame_t frame : range.selectedFrames()) {
|
||||
Cel* cel = layerImage->cel(frame);
|
||||
if (!cel)
|
||||
continue;
|
||||
|
@ -42,9 +42,8 @@ add_library(doc-lib
|
||||
image_io.cpp
|
||||
images_collector.cpp
|
||||
layer.cpp
|
||||
layer_index.cpp
|
||||
layer_io.cpp
|
||||
layers_range.cpp
|
||||
layer_list.cpp
|
||||
mask.cpp
|
||||
mask_boundaries.cpp
|
||||
mask_io.cpp
|
||||
@ -55,6 +54,8 @@ add_library(doc-lib
|
||||
primitives.cpp
|
||||
remap.cpp
|
||||
rgbmap.cpp
|
||||
selected_frames.cpp
|
||||
selected_layers.cpp
|
||||
site.cpp
|
||||
sort_palette.cpp
|
||||
sprite.cpp
|
||||
|
@ -1,4 +1,4 @@
|
||||
Copyright (c) 2001-2015 David Capello
|
||||
Copyright (c) 2001-2016 David Capello
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Aseprite Document Library
|
||||
*Copyright (C) 2001-2015 David Capello*
|
||||
*Copyright (C) 2001-2016 David Capello*
|
||||
|
||||
> Distributed under [MIT license](LICENSE.txt)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
// Copyright (c) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -17,34 +17,46 @@
|
||||
namespace doc {
|
||||
|
||||
CelsRange::CelsRange(const Sprite* sprite,
|
||||
frame_t first, frame_t last, Flags flags)
|
||||
: m_begin(sprite, first, last, flags)
|
||||
, m_end()
|
||||
const SelectedFrames& selFrames,
|
||||
const Flags flags)
|
||||
: m_selFrames(selFrames)
|
||||
, m_begin(sprite, m_selFrames, flags)
|
||||
, m_end(m_selFrames)
|
||||
{
|
||||
}
|
||||
|
||||
CelsRange::iterator::iterator()
|
||||
CelsRange::iterator::iterator(const SelectedFrames& selFrames)
|
||||
: m_cel(nullptr)
|
||||
, m_selFrames(selFrames)
|
||||
, m_frameIterator(selFrames.begin())
|
||||
{
|
||||
}
|
||||
|
||||
CelsRange::iterator::iterator(const Sprite* sprite, frame_t first, frame_t last, CelsRange::Flags flags)
|
||||
CelsRange::iterator::iterator(const Sprite* sprite,
|
||||
const SelectedFrames& selFrames,
|
||||
const CelsRange::Flags flags)
|
||||
: m_cel(nullptr)
|
||||
, m_first(first)
|
||||
, m_last(last)
|
||||
, m_selFrames(selFrames)
|
||||
, m_frameIterator(selFrames.begin())
|
||||
, m_flags(flags)
|
||||
{
|
||||
// Get first cel
|
||||
Layer* layer = sprite->layer(sprite->firstLayer());
|
||||
Layer* layer = sprite->root()->firstLayer();
|
||||
while (layer && !m_cel) {
|
||||
for (frame_t f=first; f<=last; ++f) {
|
||||
m_cel = layer->cel(f);
|
||||
if (m_cel)
|
||||
break;
|
||||
m_cel = nullptr;
|
||||
if (layer->isImage()) {
|
||||
m_frameIterator = m_selFrames.begin();
|
||||
auto endFrame = m_selFrames.end();
|
||||
for (; m_frameIterator!=endFrame; ++m_frameIterator) {
|
||||
m_cel = layer->cel(*m_frameIterator);
|
||||
if (m_cel)
|
||||
break;
|
||||
}
|
||||
}
|
||||
layer = layer->getNext();
|
||||
|
||||
if (!m_cel)
|
||||
layer = layer->getNextInWholeHierarchy();
|
||||
}
|
||||
|
||||
if (m_cel && flags == CelsRange::UNIQUE)
|
||||
m_visited.insert(m_cel->data()->id());
|
||||
}
|
||||
@ -54,29 +66,35 @@ CelsRange::iterator& CelsRange::iterator::operator++()
|
||||
if (!m_cel)
|
||||
return *this;
|
||||
|
||||
// Get next cel
|
||||
Layer* layer = m_cel->layer();
|
||||
frame_t first = m_cel->frame()+1;
|
||||
m_cel = nullptr;
|
||||
auto endFrame = m_selFrames.end();
|
||||
if (m_frameIterator != endFrame)
|
||||
++m_frameIterator;
|
||||
|
||||
Layer* layer = m_cel->layer();
|
||||
m_cel = nullptr;
|
||||
while (layer && !m_cel) {
|
||||
for (frame_t f=first; f<=m_last; ++f) {
|
||||
m_cel = layer->cel(f);
|
||||
if (m_cel) {
|
||||
if (m_flags == CelsRange::UNIQUE) {
|
||||
if (m_visited.find(m_cel->data()->id()) == m_visited.end()) {
|
||||
m_visited.insert(m_cel->data()->id());
|
||||
break;
|
||||
if (layer->isImage()) {
|
||||
for (; m_frameIterator!=endFrame; ++m_frameIterator) {
|
||||
m_cel = layer->cel(*m_frameIterator);
|
||||
if (m_cel) {
|
||||
if (m_flags == CelsRange::UNIQUE) {
|
||||
if (m_visited.find(m_cel->data()->id()) == m_visited.end()) {
|
||||
m_visited.insert(m_cel->data()->id());
|
||||
break;
|
||||
}
|
||||
else
|
||||
m_cel = nullptr;
|
||||
}
|
||||
else
|
||||
m_cel = nullptr;
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
layer = layer->getNext();
|
||||
first = m_first;
|
||||
|
||||
if (!m_cel) {
|
||||
layer = layer->getNextInWholeHierarchy();
|
||||
m_frameIterator = m_selFrames.begin();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
// Copyright (c) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -10,11 +10,15 @@
|
||||
|
||||
#include "doc/frame.h"
|
||||
#include "doc/object_id.h"
|
||||
#include "doc/selected_frames.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace doc {
|
||||
|
||||
class Cel;
|
||||
class Layer;
|
||||
class SelectedFrames;
|
||||
class Sprite;
|
||||
|
||||
class CelsRange {
|
||||
@ -25,12 +29,15 @@ namespace doc {
|
||||
};
|
||||
|
||||
CelsRange(const Sprite* sprite,
|
||||
frame_t first, frame_t last, Flags flags = ALL);
|
||||
const SelectedFrames& selFrames,
|
||||
const Flags flags = ALL);
|
||||
|
||||
class iterator {
|
||||
public:
|
||||
iterator();
|
||||
iterator(const Sprite* sprite, frame_t first, frame_t last, Flags flags);
|
||||
iterator(const SelectedFrames& selFrames);
|
||||
iterator(const Sprite* sprite,
|
||||
const SelectedFrames& selFrames,
|
||||
const Flags flags);
|
||||
|
||||
bool operator==(const iterator& other) const {
|
||||
return m_cel == other.m_cel;
|
||||
@ -48,7 +55,8 @@ namespace doc {
|
||||
|
||||
private:
|
||||
Cel* m_cel;
|
||||
frame_t m_first, m_last;
|
||||
const SelectedFrames& m_selFrames;
|
||||
SelectedFrames::const_iterator m_frameIterator;
|
||||
Flags m_flags;
|
||||
std::set<ObjectId> m_visited;
|
||||
};
|
||||
@ -57,6 +65,7 @@ namespace doc {
|
||||
iterator end() { return m_end; }
|
||||
|
||||
private:
|
||||
SelectedFrames m_selFrames;
|
||||
iterator m_begin, m_end;
|
||||
};
|
||||
|
||||
|
40
src/doc/frame_range.h
Normal file
40
src/doc/frame_range.h
Normal file
@ -0,0 +1,40 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef DOC_FRAME_RANGE_H_INCLUDED
|
||||
#define DOC_FRAME_RANGE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/frame.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
struct FrameRange {
|
||||
frame_t fromFrame, toFrame;
|
||||
|
||||
FrameRange() : fromFrame(0), toFrame(0) {
|
||||
}
|
||||
|
||||
explicit FrameRange(frame_t frame)
|
||||
: fromFrame(frame), toFrame(frame) {
|
||||
}
|
||||
|
||||
FrameRange(frame_t fromFrame, frame_t toFrame)
|
||||
: fromFrame(fromFrame), toFrame(toFrame) {
|
||||
}
|
||||
|
||||
bool operator==(const FrameRange& o) const {
|
||||
return (fromFrame == o.fromFrame && toFrame == o.toFrame);
|
||||
}
|
||||
|
||||
bool operator!=(const FrameRange& o) const {
|
||||
return !operator==(o);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace doc
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2014 David Capello
|
||||
// Copyright (c) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -53,13 +53,9 @@ void ImagesCollector::collectFromLayer(Layer* layer, frame_t frame)
|
||||
break;
|
||||
}
|
||||
|
||||
case ObjectType::LayerFolder: {
|
||||
LayerIterator it = static_cast<LayerFolder*>(layer)->getLayerBegin();
|
||||
LayerIterator end = static_cast<LayerFolder*>(layer)->getLayerEnd();
|
||||
|
||||
for (; it != end; ++it)
|
||||
collectFromLayer(*it, frame);
|
||||
|
||||
case ObjectType::LayerGroup: {
|
||||
for (Layer* child : static_cast<LayerGroup*>(layer)->layers())
|
||||
collectFromLayer(child, frame);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
// Copyright (c) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
// Copyright (c) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -28,7 +28,7 @@ Layer::Layer(ObjectType type, Sprite* sprite)
|
||||
int(LayerFlags::Visible) |
|
||||
int(LayerFlags::Editable)))
|
||||
{
|
||||
ASSERT(type == ObjectType::LayerImage || type == ObjectType::LayerFolder);
|
||||
ASSERT(type == ObjectType::LayerImage || type == ObjectType::LayerGroup);
|
||||
|
||||
setName("Layer");
|
||||
}
|
||||
@ -44,39 +44,101 @@ int Layer::getMemSize() const
|
||||
|
||||
Layer* Layer::getPrevious() const
|
||||
{
|
||||
if (m_parent != NULL) {
|
||||
LayerConstIterator it =
|
||||
std::find(m_parent->getLayerBegin(),
|
||||
m_parent->getLayerEnd(), this);
|
||||
if (m_parent) {
|
||||
auto it =
|
||||
std::find(m_parent->layers().begin(),
|
||||
m_parent->layers().end(), this);
|
||||
|
||||
if (it != m_parent->getLayerEnd() &&
|
||||
it != m_parent->getLayerBegin()) {
|
||||
if (it != m_parent->layers().end() &&
|
||||
it != m_parent->layers().begin()) {
|
||||
it--;
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Layer* Layer::getNext() const
|
||||
{
|
||||
if (m_parent != NULL) {
|
||||
LayerConstIterator it =
|
||||
std::find(m_parent->getLayerBegin(),
|
||||
m_parent->getLayerEnd(), this);
|
||||
if (m_parent) {
|
||||
auto it =
|
||||
std::find(m_parent->layers().begin(),
|
||||
m_parent->layers().end(), this);
|
||||
|
||||
if (it != m_parent->getLayerEnd()) {
|
||||
if (it != m_parent->layers().end()) {
|
||||
it++;
|
||||
if (it != m_parent->getLayerEnd())
|
||||
if (it != m_parent->layers().end())
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Layer* Layer::getPreviousInWholeHierarchy() const
|
||||
{
|
||||
// Go to children
|
||||
if (isBrowsable())
|
||||
return static_cast<const LayerGroup*>(this)->lastLayer();
|
||||
|
||||
// Go to previous layer
|
||||
if (Layer* prev = getPrevious())
|
||||
return prev;
|
||||
|
||||
// Go to previous layer in the parent
|
||||
LayerGroup* parent = this->parent();
|
||||
while (parent != sprite()->root() &&
|
||||
!parent->getPrevious()) {
|
||||
parent = parent->parent();
|
||||
}
|
||||
return parent->getPrevious();
|
||||
}
|
||||
|
||||
Layer* Layer::getNextInWholeHierarchy() const
|
||||
{
|
||||
// Go to next layer
|
||||
if (Layer* next = getNext()) {
|
||||
// Go to children
|
||||
while (next->isBrowsable()) {
|
||||
Layer* firstChild = static_cast<const LayerGroup*>(next)->firstLayer();
|
||||
if (!firstChild)
|
||||
break;
|
||||
next = firstChild;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
// Go to parent
|
||||
if (m_sprite && parent() != m_sprite->root())
|
||||
return m_parent;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Layer::isVisibleHierarchy() const
|
||||
{
|
||||
const Layer* layer = this;
|
||||
while (layer) {
|
||||
if (!layer->isVisible())
|
||||
return false;
|
||||
layer = layer->parent();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Layer::isEditableHierarchy() const
|
||||
{
|
||||
const Layer* layer = this;
|
||||
while (layer) {
|
||||
if (!layer->isEditable())
|
||||
return false;
|
||||
layer = layer->parent();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Cel* Layer::cel(frame_t frame) const
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -242,7 +304,7 @@ void LayerImage::configureAsBackground()
|
||||
switchFlags(LayerFlags::BackgroundLayerFlags, true);
|
||||
setName("Background");
|
||||
|
||||
sprite()->folder()->stackLayer(this, NULL);
|
||||
sprite()->root()->stackLayer(this, NULL);
|
||||
}
|
||||
|
||||
void LayerImage::displaceFrames(frame_t fromThis, frame_t delta)
|
||||
@ -264,90 +326,126 @@ void LayerImage::displaceFrames(frame_t fromThis, frame_t delta)
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// LayerFolder class
|
||||
// LayerGroup class
|
||||
|
||||
LayerFolder::LayerFolder(Sprite* sprite)
|
||||
: Layer(ObjectType::LayerFolder, sprite)
|
||||
LayerGroup::LayerGroup(Sprite* sprite)
|
||||
: Layer(ObjectType::LayerGroup, sprite)
|
||||
{
|
||||
setName("Layer Set");
|
||||
}
|
||||
|
||||
LayerFolder::~LayerFolder()
|
||||
LayerGroup::~LayerGroup()
|
||||
{
|
||||
destroyAllLayers();
|
||||
}
|
||||
|
||||
void LayerFolder::destroyAllLayers()
|
||||
void LayerGroup::destroyAllLayers()
|
||||
{
|
||||
LayerIterator it = getLayerBegin();
|
||||
LayerIterator end = getLayerEnd();
|
||||
|
||||
for (; it != end; ++it) {
|
||||
Layer* layer = *it;
|
||||
for (Layer* layer : m_layers)
|
||||
delete layer;
|
||||
}
|
||||
m_layers.clear();
|
||||
}
|
||||
|
||||
int LayerFolder::getMemSize() const
|
||||
int LayerGroup::getMemSize() const
|
||||
{
|
||||
int size = sizeof(LayerFolder);
|
||||
LayerConstIterator it = getLayerBegin();
|
||||
LayerConstIterator end = getLayerEnd();
|
||||
int size = sizeof(LayerGroup);
|
||||
|
||||
for (; it != end; ++it) {
|
||||
const Layer* layer = *it;
|
||||
for (const Layer* layer : m_layers) {
|
||||
size += layer->getMemSize();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void LayerFolder::getCels(CelList& cels) const
|
||||
void LayerGroup::allLayers(LayerList& list) const
|
||||
{
|
||||
LayerConstIterator it = getLayerBegin();
|
||||
LayerConstIterator end = getLayerEnd();
|
||||
for (Layer* child : m_layers) {
|
||||
if (child->isGroup())
|
||||
static_cast<LayerGroup*>(child)->allLayers(list);
|
||||
|
||||
for (; it != end; ++it)
|
||||
(*it)->getCels(cels);
|
||||
list.push_back(child);
|
||||
}
|
||||
}
|
||||
|
||||
void LayerFolder::addLayer(Layer* layer)
|
||||
layer_t LayerGroup::allLayersCount() const
|
||||
{
|
||||
layer_t count = 0;
|
||||
for (Layer* child : m_layers) {
|
||||
if (child->isGroup())
|
||||
count += static_cast<LayerGroup*>(child)->allLayersCount();
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void LayerGroup::allVisibleLayers(LayerList& list) const
|
||||
{
|
||||
for (Layer* child : m_layers) {
|
||||
if (!child->isVisible())
|
||||
continue;
|
||||
|
||||
if (child->isGroup())
|
||||
static_cast<LayerGroup*>(child)->allVisibleLayers(list);
|
||||
|
||||
list.push_back(child);
|
||||
}
|
||||
}
|
||||
|
||||
void LayerGroup::allBrowsableLayers(LayerList& list) const
|
||||
{
|
||||
for (Layer* child : m_layers) {
|
||||
if (child->isBrowsable())
|
||||
static_cast<LayerGroup*>(child)->allBrowsableLayers(list);
|
||||
|
||||
list.push_back(child);
|
||||
}
|
||||
}
|
||||
|
||||
void LayerGroup::getCels(CelList& cels) const
|
||||
{
|
||||
for (const Layer* layer : m_layers)
|
||||
layer->getCels(cels);
|
||||
}
|
||||
|
||||
void LayerGroup::addLayer(Layer* layer)
|
||||
{
|
||||
m_layers.push_back(layer);
|
||||
layer->setParent(this);
|
||||
}
|
||||
|
||||
void LayerFolder::removeLayer(Layer* layer)
|
||||
void LayerGroup::removeLayer(Layer* layer)
|
||||
{
|
||||
LayerIterator it = std::find(m_layers.begin(), m_layers.end(), layer);
|
||||
auto it = std::find(m_layers.begin(), m_layers.end(), layer);
|
||||
ASSERT(it != m_layers.end());
|
||||
m_layers.erase(it);
|
||||
|
||||
layer->setParent(NULL);
|
||||
layer->setParent(nullptr);
|
||||
}
|
||||
|
||||
void LayerFolder::stackLayer(Layer* layer, Layer* after)
|
||||
void LayerGroup::insertLayer(Layer* layer, Layer* after)
|
||||
{
|
||||
auto after_it = m_layers.begin();
|
||||
if (after) {
|
||||
after_it = std::find(m_layers.begin(), m_layers.end(), after);
|
||||
if (after_it != m_layers.end())
|
||||
++after_it;
|
||||
}
|
||||
m_layers.insert(after_it, layer);
|
||||
|
||||
layer->setParent(this);
|
||||
}
|
||||
|
||||
void LayerGroup::stackLayer(Layer* layer, Layer* after)
|
||||
{
|
||||
ASSERT(layer != after);
|
||||
if (layer == after)
|
||||
return;
|
||||
|
||||
LayerIterator it = std::find(m_layers.begin(), m_layers.end(), layer);
|
||||
ASSERT(it != m_layers.end());
|
||||
m_layers.erase(it);
|
||||
|
||||
if (after) {
|
||||
LayerIterator after_it = std::find(m_layers.begin(), m_layers.end(), after);
|
||||
ASSERT(after_it != m_layers.end());
|
||||
after_it++;
|
||||
m_layers.insert(after_it, layer);
|
||||
}
|
||||
else
|
||||
m_layers.insert(m_layers.begin(), layer);
|
||||
removeLayer(layer);
|
||||
insertLayer(layer, after);
|
||||
}
|
||||
|
||||
void LayerFolder::displaceFrames(frame_t fromThis, frame_t delta)
|
||||
void LayerGroup::displaceFrames(frame_t fromThis, frame_t delta)
|
||||
{
|
||||
for (Layer* layer : m_layers)
|
||||
layer->displaceFrames(fromThis, delta);
|
||||
|
@ -24,17 +24,19 @@ namespace doc {
|
||||
class Sprite;
|
||||
class Layer;
|
||||
class LayerImage;
|
||||
class LayerFolder;
|
||||
class LayerGroup;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Layer class
|
||||
|
||||
enum class LayerFlags {
|
||||
None = 0,
|
||||
Visible = 1, // Can be read
|
||||
Editable = 2, // Can be written
|
||||
LockMove = 4, // Cannot be moved
|
||||
Background = 8, // Stack order cannot be changed
|
||||
Continuous = 16, // Prefer to link cels when the user copy them
|
||||
Collapsed = 32, // Prefer to show this group layer collapsed
|
||||
|
||||
BackgroundLayerFlags = LockMove | Background,
|
||||
};
|
||||
@ -52,15 +54,19 @@ namespace doc {
|
||||
void setName(const std::string& name) { m_name = name; }
|
||||
|
||||
Sprite* sprite() const { return m_sprite; }
|
||||
LayerFolder* parent() const { return m_parent; }
|
||||
void setParent(LayerFolder* folder) { m_parent = folder; }
|
||||
LayerGroup* parent() const { return m_parent; }
|
||||
void setParent(LayerGroup* group) { m_parent = group; }
|
||||
|
||||
// Gets the previous sibling of this layer.
|
||||
Layer* getPrevious() const;
|
||||
Layer* getNext() const;
|
||||
|
||||
Layer* getPreviousInWholeHierarchy() const;
|
||||
Layer* getNextInWholeHierarchy() const;
|
||||
|
||||
bool isImage() const { return type() == ObjectType::LayerImage; }
|
||||
bool isFolder() const { return type() == ObjectType::LayerFolder; }
|
||||
bool isGroup() const { return type() == ObjectType::LayerGroup; }
|
||||
virtual bool isBrowsable() const { return false; }
|
||||
|
||||
bool isBackground() const { return hasFlags(LayerFlags::Background); }
|
||||
bool isTransparent() const { return !hasFlags(LayerFlags::Background); }
|
||||
@ -68,12 +74,18 @@ namespace doc {
|
||||
bool isEditable() const { return hasFlags(LayerFlags::Editable); }
|
||||
bool isMovable() const { return !hasFlags(LayerFlags::LockMove); }
|
||||
bool isContinuous() const { return hasFlags(LayerFlags::Continuous); }
|
||||
bool isCollapsed() const { return hasFlags(LayerFlags::Collapsed); }
|
||||
bool isExpanded() const { return !hasFlags(LayerFlags::Collapsed); }
|
||||
|
||||
bool isVisibleHierarchy() const;
|
||||
bool isEditableHierarchy() const;
|
||||
|
||||
void setBackground(bool state) { switchFlags(LayerFlags::Background, state); }
|
||||
void setVisible (bool state) { switchFlags(LayerFlags::Visible, state); }
|
||||
void setEditable (bool state) { switchFlags(LayerFlags::Editable, state); }
|
||||
void setMovable (bool state) { switchFlags(LayerFlags::LockMove, !state); }
|
||||
void setContinuous(bool state) { switchFlags(LayerFlags::Continuous, state); }
|
||||
void setCollapsed (bool state) { switchFlags(LayerFlags::Collapsed, state); }
|
||||
|
||||
LayerFlags flags() const {
|
||||
return m_flags;
|
||||
@ -101,7 +113,7 @@ namespace doc {
|
||||
private:
|
||||
std::string m_name; // layer name
|
||||
Sprite* m_sprite; // owner of the layer
|
||||
LayerFolder* m_parent; // parent layer
|
||||
LayerGroup* m_parent; // parent layer
|
||||
LayerFlags m_flags; // stack order cannot be changed
|
||||
|
||||
// Disable assigment
|
||||
@ -154,32 +166,38 @@ namespace doc {
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// LayerFolder class
|
||||
// LayerGroup class
|
||||
|
||||
class LayerFolder : public Layer {
|
||||
class LayerGroup : public Layer {
|
||||
public:
|
||||
explicit LayerFolder(Sprite* sprite);
|
||||
virtual ~LayerFolder();
|
||||
explicit LayerGroup(Sprite* sprite);
|
||||
virtual ~LayerGroup();
|
||||
|
||||
virtual int getMemSize() const override;
|
||||
|
||||
const LayerList& getLayersList() { return m_layers; }
|
||||
LayerIterator getLayerBegin() { return m_layers.begin(); }
|
||||
LayerIterator getLayerEnd() { return m_layers.end(); }
|
||||
LayerConstIterator getLayerBegin() const { return m_layers.begin(); }
|
||||
LayerConstIterator getLayerEnd() const { return m_layers.end(); }
|
||||
int getLayersCount() const { return (int)m_layers.size(); }
|
||||
const LayerList& layers() const { return m_layers; }
|
||||
int layersCount() const { return (int)m_layers.size(); }
|
||||
|
||||
void addLayer(Layer* layer);
|
||||
void removeLayer(Layer* layer);
|
||||
void insertLayer(Layer* layer, Layer* after);
|
||||
void stackLayer(Layer* layer, Layer* after);
|
||||
|
||||
Layer* getFirstLayer() { return (m_layers.empty() ? NULL: m_layers.front()); }
|
||||
Layer* getLastLayer() { return (m_layers.empty() ? NULL: m_layers.back()); }
|
||||
Layer* firstLayer() const { return (m_layers.empty() ? nullptr: m_layers.front()); }
|
||||
Layer* lastLayer() const { return (m_layers.empty() ? nullptr: m_layers.back()); }
|
||||
|
||||
void allLayers(LayerList& list) const;
|
||||
layer_t allLayersCount() const;
|
||||
void allVisibleLayers(LayerList& list) const;
|
||||
void allBrowsableLayers(LayerList& list) const;
|
||||
|
||||
void getCels(CelList& cels) const override;
|
||||
void displaceFrames(frame_t fromThis, frame_t delta) override;
|
||||
|
||||
bool isBrowsable() const override {
|
||||
return isGroup() && isExpanded() && !m_layers.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
void destroyAllLayers();
|
||||
|
||||
|
@ -1,17 +0,0 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2014 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "doc/layer_index.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
const LayerIndex LayerIndex::NoLayer(-1);
|
||||
|
||||
} // namespace doc
|
@ -1,54 +0,0 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2014 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef DOC_LAYER_INDEX_H_INCLUDED
|
||||
#define DOC_LAYER_INDEX_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
namespace doc {
|
||||
|
||||
class LayerIndex {
|
||||
public:
|
||||
static const LayerIndex NoLayer;
|
||||
|
||||
LayerIndex() : m_value(0) { }
|
||||
explicit LayerIndex(int value) : m_value(value) { }
|
||||
|
||||
LayerIndex next(int i = 1) const { return LayerIndex(m_value+i); };
|
||||
LayerIndex previous(int i = 1) const { return LayerIndex(m_value-i); };
|
||||
|
||||
operator int() { return m_value; }
|
||||
operator const int() const { return m_value; }
|
||||
|
||||
LayerIndex& operator=(const LayerIndex& o) { m_value = o.m_value; return *this; }
|
||||
LayerIndex& operator++() { ++m_value; return *this; }
|
||||
LayerIndex& operator--() { --m_value; return *this; }
|
||||
LayerIndex operator++(int) { LayerIndex old(*this); ++m_value; return old; }
|
||||
LayerIndex operator--(int) { LayerIndex old(*this); --m_value; return old; }
|
||||
LayerIndex& operator+=(const LayerIndex& o) { m_value += o.m_value; return *this; }
|
||||
LayerIndex& operator-=(const LayerIndex& o) { m_value -= o.m_value; return *this; }
|
||||
bool operator<(const LayerIndex& o) const { return m_value < o.m_value; }
|
||||
bool operator>(const LayerIndex& o) const { return m_value > o.m_value; }
|
||||
bool operator<=(const LayerIndex& o) const { return m_value <= o.m_value; }
|
||||
bool operator>=(const LayerIndex& o) const { return m_value >= o.m_value; }
|
||||
bool operator==(const LayerIndex& o) const { return m_value == o.m_value; }
|
||||
bool operator!=(const LayerIndex& o) const { return m_value != o.m_value; }
|
||||
|
||||
private:
|
||||
int m_value;
|
||||
};
|
||||
|
||||
inline LayerIndex operator+(const LayerIndex& x, const LayerIndex& y) {
|
||||
return LayerIndex((int)x + (int)y);
|
||||
}
|
||||
|
||||
inline LayerIndex operator-(const LayerIndex& x, const LayerIndex& y) {
|
||||
return LayerIndex((int)x - (int)y);
|
||||
}
|
||||
|
||||
} // namespace doc
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
// Copyright (c) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -87,15 +87,12 @@ void write_layer(std::ostream& os, const Layer* layer)
|
||||
break;
|
||||
}
|
||||
|
||||
case ObjectType::LayerFolder: {
|
||||
LayerConstIterator it = static_cast<const LayerFolder*>(layer)->getLayerBegin();
|
||||
LayerConstIterator end = static_cast<const LayerFolder*>(layer)->getLayerEnd();
|
||||
|
||||
case ObjectType::LayerGroup: {
|
||||
// Number of sub-layers
|
||||
write16(os, static_cast<const LayerFolder*>(layer)->getLayersCount());
|
||||
write16(os, static_cast<const LayerGroup*>(layer)->layersCount());
|
||||
|
||||
for (; it != end; ++it)
|
||||
write_layer(os, *it);
|
||||
for (const Layer* child : static_cast<const LayerGroup*>(layer)->layers())
|
||||
write_layer(os, child);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -150,16 +147,16 @@ Layer* read_layer(std::istream& is, SubObjectsFromSprite* subObjects)
|
||||
break;
|
||||
}
|
||||
|
||||
case ObjectType::LayerFolder: {
|
||||
case ObjectType::LayerGroup: {
|
||||
// Create the layer set
|
||||
layer.reset(new LayerFolder(subObjects->sprite()));
|
||||
layer.reset(new LayerGroup(subObjects->sprite()));
|
||||
|
||||
// Number of sub-layers
|
||||
int layers = read16(is);
|
||||
for (int c=0; c<layers; c++) {
|
||||
Layer* child = read_layer(is, subObjects);
|
||||
if (child)
|
||||
static_cast<LayerFolder*>(layer.get())->addLayer(child);
|
||||
static_cast<LayerGroup*>(layer.get())->addLayer(child);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
54
src/doc/layer_list.cpp
Normal file
54
src/doc/layer_list.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "doc/layer.h"
|
||||
#include "doc/layer_list.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace doc {
|
||||
|
||||
layer_t find_layer_index(const LayerList& layers, const Layer* layer)
|
||||
{
|
||||
auto it = std::find(layers.begin(), layers.end(), layer);
|
||||
if (it != layers.end())
|
||||
return it - layers.begin();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool are_layers_adjacent(const LayerList& layers)
|
||||
{
|
||||
layer_t count = 0;
|
||||
Layer* prev = nullptr;
|
||||
for (auto layer : layers) {
|
||||
if (prev && prev != layer->getPrevious())
|
||||
break;
|
||||
prev = layer;
|
||||
++count;
|
||||
}
|
||||
if (count == layers.size())
|
||||
return true;
|
||||
|
||||
count = 0;
|
||||
prev = nullptr;
|
||||
for (auto layer : layers) {
|
||||
if (prev && prev != layer->getNext())
|
||||
break;
|
||||
prev = layer;
|
||||
++count;
|
||||
}
|
||||
if (count == layers.size())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace doc
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
// Copyright (c) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -15,8 +15,10 @@ namespace doc {
|
||||
class Layer;
|
||||
|
||||
typedef std::vector<Layer*> LayerList;
|
||||
typedef LayerList::iterator LayerIterator;
|
||||
typedef LayerList::const_iterator LayerConstIterator;
|
||||
typedef int layer_t;
|
||||
|
||||
layer_t find_layer_index(const LayerList& layers, const Layer* layer);
|
||||
bool are_layers_adjacent(const LayerList& layers);
|
||||
|
||||
} // namespace doc
|
||||
|
||||
|
65
src/doc/layer_list_tests.cpp
Normal file
65
src/doc/layer_list_tests.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "base/unique_ptr.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/layer_list.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace doc;
|
||||
|
||||
TEST(LayerList, AreLayersAdjacent)
|
||||
{
|
||||
base::UniquePtr<Sprite> spr(new Sprite(IMAGE_RGB, 32, 32, 256));
|
||||
LayerGroup* root = spr->root();
|
||||
Layer* layer1 = new LayerImage(spr);
|
||||
Layer* layer2 = new LayerImage(spr);
|
||||
Layer* layer3 = new LayerImage(spr);
|
||||
Layer* layer4 = new LayerImage(spr);
|
||||
root->addLayer(layer1);
|
||||
root->addLayer(layer2);
|
||||
root->addLayer(layer3);
|
||||
root->addLayer(layer4);
|
||||
|
||||
LayerList layers;
|
||||
root->allLayers(layers);
|
||||
EXPECT_EQ(4, layers.size());
|
||||
EXPECT_TRUE(are_layers_adjacent(layers));
|
||||
|
||||
std::reverse(layers.begin(), layers.end());
|
||||
EXPECT_EQ(4, layers.size());
|
||||
EXPECT_TRUE(are_layers_adjacent(layers));
|
||||
|
||||
layers.erase(layers.begin());
|
||||
EXPECT_EQ(3, layers.size());
|
||||
EXPECT_TRUE(are_layers_adjacent(layers));
|
||||
|
||||
layers.erase(layers.begin()+1);
|
||||
EXPECT_EQ(2, layers.size());
|
||||
EXPECT_FALSE(are_layers_adjacent(layers));
|
||||
|
||||
std::reverse(layers.begin(), layers.end());
|
||||
EXPECT_EQ(2, layers.size());
|
||||
EXPECT_FALSE(are_layers_adjacent(layers));
|
||||
|
||||
layers.erase(layers.begin());
|
||||
EXPECT_EQ(1, layers.size());
|
||||
EXPECT_TRUE(are_layers_adjacent(layers));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "doc/layers_range.h"
|
||||
|
||||
#include "doc/cel.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
LayersRange::LayersRange(const Sprite* sprite,
|
||||
LayerIndex first, LayerIndex last)
|
||||
: m_begin(sprite, first, last)
|
||||
, m_end()
|
||||
{
|
||||
}
|
||||
|
||||
LayersRange::iterator::iterator()
|
||||
: m_layer(nullptr)
|
||||
, m_cur(-1)
|
||||
, m_last(-1)
|
||||
{
|
||||
}
|
||||
|
||||
LayersRange::iterator::iterator(const Sprite* sprite,
|
||||
LayerIndex first, LayerIndex last)
|
||||
: m_layer(nullptr)
|
||||
, m_cur(first)
|
||||
, m_last(last)
|
||||
{
|
||||
m_layer = sprite->layer(first);
|
||||
}
|
||||
|
||||
LayersRange::iterator& LayersRange::iterator::operator++()
|
||||
{
|
||||
if (!m_layer)
|
||||
return *this;
|
||||
|
||||
++m_cur;
|
||||
if (m_cur > m_last)
|
||||
m_layer = nullptr;
|
||||
else
|
||||
m_layer = m_layer->getNext();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace doc
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user