Merge branch 'layer-folder' into beta (fix #454)

This commit is contained in:
David Capello 2016-08-31 18:49:34 -03:00
commit 5d00a6a737
117 changed files with 3978 additions and 2278 deletions

View File

@ -664,6 +664,9 @@
<item command="LayerVisibility" text="&amp;Visible" />
<separator />
<item command="NewLayer" text="&amp;New Layer" />
<item command="NewLayer" text="New &amp;Group">
<param name="group" value="true" />
</item>
<item command="RemoveLayer" text="&amp;Remove Layer" />
<item command="BackgroundFromLayer" text="&amp;Background from Layer" />
<item command="LayerFromBackground" text="&amp;Layer from Background" />

View File

@ -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

View File

@ -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" />

View File

@ -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="&amp;OK" closewindow="true" id="ok" magnet="true" />
<button text="&amp;Cancel" closewindow="true" />
</box>
</box>
<box horizontal="true" homogeneous="true">
<button text="&amp;OK" closewindow="true" id="ok" magnet="true" />
<button text="&amp;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="&amp;OK" closewindow="true" id="ok" magnet="true" />
<button text="&amp;Cancel" closewindow="true" />
</box>
</box>
</window>
</window>
</gui>

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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));

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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();
}
}
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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

View File

@ -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;
};

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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));

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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");
}

View File

@ -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 {

View File

@ -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());
}
}

View File

@ -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;

View File

@ -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)

View File

@ -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,

View File

@ -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()) {

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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()) {

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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)

View File

@ -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);

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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,
&current_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;
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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 ||

View File

@ -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));

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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"

View File

@ -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);

View File

@ -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

View File

@ -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()

View File

@ -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.)

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;
};

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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
View 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

View File

@ -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;
}

View File

@ -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.

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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
View 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

View File

@ -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

View 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();
}

View File

@ -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