mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-28 16:11:35 +00:00
Move Timeline logic to drag-and-drop ranges to app::DocumentRange/move_range/copy_range
This fixes issue 433.
This commit is contained in:
parent
0f99c78174
commit
9fd60f1119
@ -105,6 +105,8 @@ add_library(app-lib
|
|||||||
document_api.cpp
|
document_api.cpp
|
||||||
document_exporter.cpp
|
document_exporter.cpp
|
||||||
document_location.cpp
|
document_location.cpp
|
||||||
|
document_range.cpp
|
||||||
|
document_range_ops.cpp
|
||||||
document_undo.cpp
|
document_undo.cpp
|
||||||
file/ase_format.cpp
|
file/ase_format.cpp
|
||||||
file/bmp_format.cpp
|
file/bmp_format.cpp
|
||||||
|
@ -399,8 +399,12 @@ int app_get_color_to_clear_layer(Layer* layer)
|
|||||||
app::Color color;
|
app::Color color;
|
||||||
|
|
||||||
// The `Background' is erased with the `Background Color'
|
// The `Background' is erased with the `Background Color'
|
||||||
if (layer->isBackground())
|
if (layer->isBackground()) {
|
||||||
color = ColorBar::instance()->getBgColor();
|
if (ColorBar::instance())
|
||||||
|
color = ColorBar::instance()->getBgColor();
|
||||||
|
else
|
||||||
|
color = app::Color::fromRgb(0, 0, 0); // TODO get background color color from doc::Settings
|
||||||
|
}
|
||||||
else // All transparent layers are cleared with the mask color
|
else // All transparent layers are cleared with the mask color
|
||||||
color = app::Color::fromMask();
|
color = app::Color::fromMask();
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ void DuplicateLayerCommand::onExecute(Context* context)
|
|||||||
{
|
{
|
||||||
UndoTransaction undo(writer.context(), "Layer Duplication");
|
UndoTransaction undo(writer.context(), "Layer Duplication");
|
||||||
LayerImage* sourceLayer = static_cast<LayerImage*>(writer.layer());
|
LayerImage* sourceLayer = static_cast<LayerImage*>(writer.layer());
|
||||||
api.duplicateLayer(sourceLayer, sourceLayer);
|
api.duplicateLayerAfter(sourceLayer, sourceLayer);
|
||||||
undo.commit();
|
undo.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,16 +58,14 @@ void Context::sendDocumentToTop(doc::Document* document)
|
|||||||
|
|
||||||
app::Document* Context::activeDocument() const
|
app::Document* Context::activeDocument() const
|
||||||
{
|
{
|
||||||
DocumentLocation location;
|
return static_cast<app::Document*>(doc::Context::activeDocument());
|
||||||
onGetActiveLocation(&location);
|
|
||||||
ASSERT(location.document() == doc::Context::activeDocument());
|
|
||||||
return location.document();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentLocation Context::activeLocation() const
|
DocumentLocation Context::activeLocation() const
|
||||||
{
|
{
|
||||||
DocumentLocation location;
|
DocumentLocation location;
|
||||||
onGetActiveLocation(&location);
|
onGetActiveLocation(&location);
|
||||||
|
ASSERT(location.document() == doc::Context::activeDocument());
|
||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,7 +407,7 @@ void DocumentApi::moveFrame(Sprite* sprite, FrameNumber frame, FrameNumber befor
|
|||||||
frame >= 0 &&
|
frame >= 0 &&
|
||||||
frame <= sprite->lastFrame() &&
|
frame <= sprite->lastFrame() &&
|
||||||
beforeFrame >= 0 &&
|
beforeFrame >= 0 &&
|
||||||
beforeFrame <= sprite->lastFrame()) {
|
beforeFrame <= sprite->lastFrame().next()) {
|
||||||
// Change the frame-lengths...
|
// Change the frame-lengths...
|
||||||
int frlen_aux = sprite->getFrameDuration(frame);
|
int frlen_aux = sprite->getFrameDuration(frame);
|
||||||
|
|
||||||
@ -817,6 +817,14 @@ void DocumentApi::restackLayerAfter(Layer* layer, Layer* afterThis)
|
|||||||
m_document->notifyObservers<doc::DocumentEvent&>(&doc::DocumentObserver::onLayerRestacked, ev);
|
m_document->notifyObservers<doc::DocumentEvent&>(&doc::DocumentObserver::onLayerRestacked, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DocumentApi::restackLayerBefore(Layer* layer, Layer* beforeThis)
|
||||||
|
{
|
||||||
|
LayerIndex beforeThisIdx = layer->sprite()->layerToIndex(beforeThis);
|
||||||
|
LayerIndex afterThisIdx = beforeThisIdx.previous();
|
||||||
|
|
||||||
|
restackLayerAfter(layer, layer->sprite()->indexToLayer(afterThisIdx));
|
||||||
|
}
|
||||||
|
|
||||||
void DocumentApi::cropLayer(Layer* layer, int x, int y, int w, int h, color_t bgcolor)
|
void DocumentApi::cropLayer(Layer* layer, int x, int y, int w, int h, color_t bgcolor)
|
||||||
{
|
{
|
||||||
if (!layer->isImage())
|
if (!layer->isImage())
|
||||||
@ -1016,7 +1024,7 @@ void DocumentApi::flattenLayers(Sprite* sprite, color_t bgcolor)
|
|||||||
removeLayer(*it);
|
removeLayer(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentApi::duplicateLayer(Layer* sourceLayer, Layer* afterLayer)
|
void DocumentApi::duplicateLayerAfter(Layer* sourceLayer, Layer* afterLayer)
|
||||||
{
|
{
|
||||||
base::UniquePtr<LayerImage> newLayerPtr(new LayerImage(sourceLayer->sprite()));
|
base::UniquePtr<LayerImage> newLayerPtr(new LayerImage(sourceLayer->sprite()));
|
||||||
|
|
||||||
@ -1030,6 +1038,14 @@ void DocumentApi::duplicateLayer(Layer* sourceLayer, Layer* afterLayer)
|
|||||||
newLayerPtr.release();
|
newLayerPtr.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DocumentApi::duplicateLayerBefore(Layer* sourceLayer, Layer* beforeLayer)
|
||||||
|
{
|
||||||
|
LayerIndex beforeThisIdx = sourceLayer->sprite()->layerToIndex(beforeLayer);
|
||||||
|
LayerIndex afterThisIdx = beforeThisIdx.previous();
|
||||||
|
|
||||||
|
duplicateLayerAfter(sourceLayer, sourceLayer->sprite()->indexToLayer(afterThisIdx));
|
||||||
|
}
|
||||||
|
|
||||||
// Adds a new image in the stock. Returns the image index in the
|
// Adds a new image in the stock. Returns the image index in the
|
||||||
// stock.
|
// stock.
|
||||||
int DocumentApi::addImageInStock(Sprite* sprite, Image* image)
|
int DocumentApi::addImageInStock(Sprite* sprite, Image* image)
|
||||||
|
@ -95,12 +95,14 @@ namespace app {
|
|||||||
void addLayer(LayerFolder* folder, Layer* newLayer, Layer* afterThis);
|
void addLayer(LayerFolder* folder, Layer* newLayer, Layer* afterThis);
|
||||||
void removeLayer(Layer* layer);
|
void removeLayer(Layer* layer);
|
||||||
void restackLayerAfter(Layer* layer, Layer* afterThis);
|
void restackLayerAfter(Layer* layer, Layer* afterThis);
|
||||||
|
void restackLayerBefore(Layer* layer, Layer* beforeThis);
|
||||||
void cropLayer(Layer* layer, int x, int y, int w, int h, color_t bgcolor);
|
void cropLayer(Layer* layer, int x, int y, int w, int h, color_t bgcolor);
|
||||||
void displaceLayers(Layer* layer, int dx, int dy);
|
void displaceLayers(Layer* layer, int dx, int dy);
|
||||||
void backgroundFromLayer(LayerImage* layer, color_t bgcolor);
|
void backgroundFromLayer(LayerImage* layer, color_t bgcolor);
|
||||||
void layerFromBackground(Layer* layer);
|
void layerFromBackground(Layer* layer);
|
||||||
void flattenLayers(Sprite* sprite, color_t bgcolor);
|
void flattenLayers(Sprite* sprite, color_t bgcolor);
|
||||||
void duplicateLayer(Layer* sourceLayer, Layer* afterLayer);
|
void duplicateLayerAfter(Layer* sourceLayer, Layer* afterLayer);
|
||||||
|
void duplicateLayerBefore(Layer* sourceLayer, Layer* beforeLayer);
|
||||||
|
|
||||||
// Images stock API
|
// Images stock API
|
||||||
int addImageInStock(Sprite* sprite, Image* image);
|
int addImageInStock(Sprite* sprite, Image* image);
|
||||||
|
89
src/app/document_range.cpp
Normal file
89
src/app/document_range.cpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/* Aseprite
|
||||||
|
* Copyright (C) 2001-2014 David Capello
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "app/document_range.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
using namespace raster;
|
||||||
|
|
||||||
|
void DocumentRange::startRange(LayerIndex layer, FrameNumber frame, Type type)
|
||||||
|
{
|
||||||
|
m_type = type;
|
||||||
|
m_layerBegin = m_layerEnd = layer;
|
||||||
|
m_frameBegin = m_frameEnd = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DocumentRange::endRange(LayerIndex layer, FrameNumber frame)
|
||||||
|
{
|
||||||
|
ASSERT(enabled());
|
||||||
|
m_layerEnd = layer;
|
||||||
|
m_frameEnd = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DocumentRange::disableRange()
|
||||||
|
{
|
||||||
|
m_type = kNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DocumentRange::inRange(LayerIndex layer) const
|
||||||
|
{
|
||||||
|
if (enabled())
|
||||||
|
return (layer >= layerBegin() && layer <= layerEnd());
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DocumentRange::inRange(FrameNumber frame) const
|
||||||
|
{
|
||||||
|
if (enabled())
|
||||||
|
return (frame >= frameBegin() && frame <= frameEnd());
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DocumentRange::inRange(LayerIndex layer, FrameNumber 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(FrameNumber frames)
|
||||||
|
{
|
||||||
|
if (m_frameBegin <= m_frameEnd) m_frameEnd = (m_frameBegin + frames).previous();
|
||||||
|
else m_frameBegin = (m_frameEnd + frames).previous();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DocumentRange::displace(int layerDelta, int frameDelta)
|
||||||
|
{
|
||||||
|
m_layerBegin += LayerIndex(layerDelta);
|
||||||
|
m_layerEnd += LayerIndex(layerDelta);
|
||||||
|
m_frameBegin += FrameNumber(frameDelta);
|
||||||
|
m_frameEnd += FrameNumber(frameDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
74
src/app/document_range.h
Normal file
74
src/app/document_range.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/* Aseprite
|
||||||
|
* Copyright (C) 2001-2014 David Capello
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef APP_DOCUMENT_RANGE_H_INCLUDED
|
||||||
|
#define APP_DOCUMENT_RANGE_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "raster/frame_number.h"
|
||||||
|
#include "raster/layer_index.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
using namespace raster;
|
||||||
|
|
||||||
|
class DocumentRange {
|
||||||
|
public:
|
||||||
|
enum Type { kNone, kCels, kFrames, kLayers };
|
||||||
|
|
||||||
|
DocumentRange() : m_type(kNone) { }
|
||||||
|
|
||||||
|
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); }
|
||||||
|
FrameNumber frameBegin() const { return std::min(m_frameBegin, m_frameEnd); }
|
||||||
|
FrameNumber frameEnd() const { return std::max(m_frameBegin, m_frameEnd); }
|
||||||
|
|
||||||
|
int layers() const { return layerEnd() - layerBegin() + 1; }
|
||||||
|
FrameNumber frames() const { return (frameEnd() - frameBegin()).next(); }
|
||||||
|
void setLayers(int layers);
|
||||||
|
void setFrames(FrameNumber frames);
|
||||||
|
void displace(int layerDelta, int frameDelta);
|
||||||
|
|
||||||
|
bool inRange(LayerIndex layer) const;
|
||||||
|
bool inRange(FrameNumber frame) const;
|
||||||
|
bool inRange(LayerIndex layer, FrameNumber frame) const;
|
||||||
|
|
||||||
|
void startRange(LayerIndex layer, FrameNumber frame, Type type);
|
||||||
|
void endRange(LayerIndex layer, FrameNumber 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type m_type;
|
||||||
|
LayerIndex m_layerBegin;
|
||||||
|
LayerIndex m_layerEnd;
|
||||||
|
FrameNumber m_frameBegin;
|
||||||
|
FrameNumber m_frameEnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif
|
332
src/app/document_range_ops.cpp
Normal file
332
src/app/document_range_ops.cpp
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
/* Aseprite
|
||||||
|
* Copyright (C) 2001-2014 David Capello
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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"
|
||||||
|
#include "app/undo_transaction.h"
|
||||||
|
#include "raster/layer.h"
|
||||||
|
#include "raster/sprite.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
enum Op { Move, Copy };
|
||||||
|
|
||||||
|
static DocumentRange drop_range_op(
|
||||||
|
Document* doc, Op op, const DocumentRange& from,
|
||||||
|
DocumentRangePlace place, const DocumentRange& to)
|
||||||
|
{
|
||||||
|
Sprite* sprite = doc->sprite();
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
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))
|
||||||
|
return from;
|
||||||
|
|
||||||
|
// We cannot move the background
|
||||||
|
for (LayerIndex i = from.layerBegin(); i <= from.layerEnd(); ++i)
|
||||||
|
if (sprite->indexToLayer(i)->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 something below the background layer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* undoLabel = NULL;
|
||||||
|
switch (op) {
|
||||||
|
case Move: undoLabel = "Move Range"; break;
|
||||||
|
case Copy: undoLabel = "Copy Range"; break;
|
||||||
|
}
|
||||||
|
DocumentRange resultRange;
|
||||||
|
|
||||||
|
{
|
||||||
|
const app::Context* context = static_cast<app::Context*>(doc->context());
|
||||||
|
const ContextReader reader(context);
|
||||||
|
ContextWriter writer(reader);
|
||||||
|
UndoTransaction undo(writer.context(), undoLabel, undo::ModifyDocument);
|
||||||
|
DocumentApi api = doc->getApi();
|
||||||
|
|
||||||
|
// TODO Try to add the range with just one call to DocumentApi
|
||||||
|
// methods, to avoid generating a lot of SetCelFrame undoers (see
|
||||||
|
// DocumentApi::setCelFramePosition).
|
||||||
|
|
||||||
|
switch (from.type()) {
|
||||||
|
|
||||||
|
case DocumentRange::kCels:
|
||||||
|
{
|
||||||
|
std::vector<Layer*> layers;
|
||||||
|
sprite->getLayersList(layers);
|
||||||
|
|
||||||
|
int srcLayerBegin, srcLayerStep, srcLayerEnd;
|
||||||
|
int dstLayerBegin, dstLayerStep;
|
||||||
|
FrameNumber srcFrameBegin, srcFrameStep, srcFrameEnd;
|
||||||
|
FrameNumber dstFrameBegin, dstFrameStep;
|
||||||
|
|
||||||
|
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 = FrameNumber(1);
|
||||||
|
srcFrameEnd = from.frameEnd().next();
|
||||||
|
dstFrameBegin = to.frameBegin();
|
||||||
|
dstFrameStep = FrameNumber(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
srcFrameBegin = from.frameEnd();
|
||||||
|
srcFrameStep = FrameNumber(-1);
|
||||||
|
srcFrameEnd = from.frameBegin().previous();
|
||||||
|
dstFrameBegin = to.frameEnd();
|
||||||
|
dstFrameStep = FrameNumber(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int srcLayerIdx = srcLayerBegin,
|
||||||
|
dstLayerIdx = dstLayerBegin; srcLayerIdx != srcLayerEnd; ) {
|
||||||
|
for (FrameNumber srcFrame = srcFrameBegin,
|
||||||
|
dstFrame = dstFrameBegin; srcFrame != srcFrameEnd; ) {
|
||||||
|
LayerImage* srcLayer = static_cast<LayerImage*>(layers[srcLayerIdx]);
|
||||||
|
LayerImage* dstLayer = static_cast<LayerImage*>(layers[dstLayerIdx]);
|
||||||
|
color_t bgcolor = app_get_color_to_clear_layer(dstLayer);
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case Move: api.moveCel(sprite, srcLayer, dstLayer, srcFrame, dstFrame, bgcolor); break;
|
||||||
|
case Copy: api.copyCel(sprite, srcLayer, dstLayer, srcFrame, dstFrame, bgcolor); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
srcFrame += srcFrameStep;
|
||||||
|
dstFrame += dstFrameStep;
|
||||||
|
}
|
||||||
|
srcLayerIdx += srcLayerStep;
|
||||||
|
dstLayerIdx += dstLayerStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultRange = to;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DocumentRange::kFrames:
|
||||||
|
{
|
||||||
|
FrameNumber srcFrameBegin, srcFrameStep, srcFrameEnd;
|
||||||
|
FrameNumber dstFrameBegin, dstFrameStep;
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
|
||||||
|
case Move:
|
||||||
|
if (place == kDocumentRangeBefore) {
|
||||||
|
if (to.frameBegin() <= from.frameBegin()) {
|
||||||
|
srcFrameBegin = from.frameBegin();
|
||||||
|
srcFrameStep = FrameNumber(1);
|
||||||
|
srcFrameEnd = from.frameEnd().next();
|
||||||
|
dstFrameBegin = to.frameBegin();
|
||||||
|
dstFrameStep = FrameNumber(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
srcFrameBegin = from.frameEnd();
|
||||||
|
srcFrameStep = FrameNumber(-1);
|
||||||
|
srcFrameEnd = from.frameBegin().previous();
|
||||||
|
dstFrameBegin = to.frameBegin();
|
||||||
|
dstFrameStep = FrameNumber(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (place == kDocumentRangeAfter) {
|
||||||
|
if (to.frameEnd() <= from.frameBegin()) {
|
||||||
|
srcFrameBegin = from.frameBegin();
|
||||||
|
srcFrameStep = FrameNumber(1);
|
||||||
|
srcFrameEnd = from.frameEnd().next();
|
||||||
|
dstFrameBegin = to.frameEnd();
|
||||||
|
dstFrameStep = FrameNumber(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
srcFrameBegin = from.frameEnd();
|
||||||
|
srcFrameStep = FrameNumber(-1);
|
||||||
|
srcFrameEnd = from.frameBegin().previous();
|
||||||
|
dstFrameBegin = to.frameEnd().next();
|
||||||
|
dstFrameStep = FrameNumber(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Copy:
|
||||||
|
if (to.frameBegin() <= from.frameBegin()) {
|
||||||
|
srcFrameBegin = from.frameBegin();
|
||||||
|
srcFrameStep = FrameNumber(2);
|
||||||
|
srcFrameEnd = from.frameBegin().next(2*from.frames());
|
||||||
|
dstFrameBegin = to.frameBegin();
|
||||||
|
dstFrameStep = FrameNumber(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
srcFrameBegin = from.frameEnd();
|
||||||
|
srcFrameStep = FrameNumber(-1);
|
||||||
|
srcFrameEnd = from.frameBegin().previous();
|
||||||
|
dstFrameBegin = to.frameBegin();
|
||||||
|
dstFrameStep = FrameNumber(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (place == kDocumentRangeAfter)
|
||||||
|
dstFrameBegin = dstFrameBegin.next();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FrameNumber 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, FrameNumber(to.frameBegin()), from.type());
|
||||||
|
resultRange.endRange(LayerIndex::NoLayer, FrameNumber(to.frameBegin()+from.frames()-1));
|
||||||
|
}
|
||||||
|
else if (place == kDocumentRangeAfter) {
|
||||||
|
resultRange.startRange(LayerIndex::NoLayer, FrameNumber(to.frameEnd()+1), from.type());
|
||||||
|
resultRange.endRange(LayerIndex::NoLayer, FrameNumber(to.frameEnd()+1+from.frames()-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op == Move && from.frameBegin() < to.frameBegin())
|
||||||
|
resultRange.displace(0, -from.frames());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DocumentRange::kLayers:
|
||||||
|
{
|
||||||
|
std::vector<Layer*> layers;
|
||||||
|
sprite->getLayersList(layers);
|
||||||
|
|
||||||
|
if (layers.empty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
Layer* firstLayer = layers.front();
|
||||||
|
Layer* lastLayer = layers.back();
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
|
||||||
|
case Move:
|
||||||
|
if (place == kDocumentRangeBefore) {
|
||||||
|
for (LayerIndex i = from.layerBegin(); i <= from.layerEnd(); ++i) {
|
||||||
|
api.restackLayerBefore(
|
||||||
|
layers[i],
|
||||||
|
layers[to.layerBegin()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (place == kDocumentRangeAfter) {
|
||||||
|
for (LayerIndex i = from.layerEnd(); i >= from.layerBegin(); --i) {
|
||||||
|
api.restackLayerAfter(
|
||||||
|
layers[i],
|
||||||
|
layers[to.layerEnd()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Copy:
|
||||||
|
if (place == kDocumentRangeBefore) {
|
||||||
|
for (LayerIndex i = from.layerBegin(); i <= from.layerEnd(); ++i) {
|
||||||
|
api.duplicateLayerBefore(
|
||||||
|
layers[i],
|
||||||
|
layers[to.layerBegin()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (place == kDocumentRangeAfter) {
|
||||||
|
for (LayerIndex i = from.layerEnd(); i >= from.layerBegin(); --i) {
|
||||||
|
api.duplicateLayerAfter(
|
||||||
|
layers[i],
|
||||||
|
layers[to.layerEnd()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (place == kDocumentRangeBefore) {
|
||||||
|
resultRange.startRange(LayerIndex(to.layerBegin()), FrameNumber(-1), from.type());
|
||||||
|
resultRange.endRange(LayerIndex(to.layerBegin()+from.layers()-1), FrameNumber(-1));
|
||||||
|
}
|
||||||
|
else if (place == kDocumentRangeAfter) {
|
||||||
|
resultRange.startRange(LayerIndex(to.layerEnd()+1), FrameNumber(-1), from.type());
|
||||||
|
resultRange.endRange(LayerIndex(to.layerEnd()+1+from.layers()-1), FrameNumber(-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op == Move && from.layerBegin() < to.layerBegin())
|
||||||
|
resultRange.displace(-from.layers(), 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
undo.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentRange move_range(Document* doc, const DocumentRange& from, const DocumentRange& to, DocumentRangePlace place)
|
||||||
|
{
|
||||||
|
return drop_range_op(doc, Move, from, place, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentRange copy_range(Document* doc, const DocumentRange& from, const DocumentRange& to, DocumentRangePlace place)
|
||||||
|
{
|
||||||
|
return drop_range_op(doc, Copy, from, place, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
42
src/app/document_range_ops.h
Normal file
42
src/app/document_range_ops.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/* Aseprite
|
||||||
|
* Copyright (C) 2001-2014 David Capello
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef APP_DOCUMENT_RANGE_OPS_H_INCLUDED
|
||||||
|
#define APP_DOCUMENT_RANGE_OPS_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
class Document;
|
||||||
|
class DocumentRange;
|
||||||
|
|
||||||
|
enum DocumentRangePlace {
|
||||||
|
kDocumentRangeBefore,
|
||||||
|
kDocumentRangeAfter,
|
||||||
|
};
|
||||||
|
|
||||||
|
// These functions returns the new location of the "from" range or
|
||||||
|
// throws an std::runtime_error() in case that the operation cannot
|
||||||
|
// be done. (E.g. the background layer cannot be moved.)
|
||||||
|
DocumentRange move_range(Document* doc, const DocumentRange& from, const DocumentRange& to, DocumentRangePlace place);
|
||||||
|
DocumentRange copy_range(Document* doc, const DocumentRange& from, const DocumentRange& to, DocumentRangePlace place);
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif
|
601
src/app/document_range_tests.cpp
Normal file
601
src/app/document_range_tests.cpp
Normal file
@ -0,0 +1,601 @@
|
|||||||
|
/* Aseprite
|
||||||
|
* Copyright (C) 2001-2014 David Capello
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tests/test.h"
|
||||||
|
|
||||||
|
#include "app/document.h"
|
||||||
|
#include "app/document_api.h"
|
||||||
|
#include "app/document_range.h"
|
||||||
|
#include "app/document_range_ops.h"
|
||||||
|
#include "app/document_undo.h"
|
||||||
|
#include "app/test_context.h"
|
||||||
|
#include "base/unique_ptr.h"
|
||||||
|
#include "raster/raster.h"
|
||||||
|
#include "undo/undo_history.h"
|
||||||
|
|
||||||
|
using namespace app;
|
||||||
|
using namespace raster;
|
||||||
|
|
||||||
|
typedef base::UniquePtr<Document> DocumentPtr;
|
||||||
|
|
||||||
|
#define EXPECT_LAYER_ORDER(a, b, c, d) \
|
||||||
|
EXPECT_EQ(a, sprite->indexToLayer(LayerIndex(0))); \
|
||||||
|
EXPECT_EQ(b, sprite->indexToLayer(LayerIndex(1))); \
|
||||||
|
EXPECT_EQ(c, sprite->indexToLayer(LayerIndex(2))); \
|
||||||
|
EXPECT_EQ(d, sprite->indexToLayer(LayerIndex(3)));
|
||||||
|
|
||||||
|
#define EXPECT_FRAME_ORDER(a, b, c, d) \
|
||||||
|
EXPECT_EQ((a+1), sprite->getFrameDuration(FrameNumber(0))); \
|
||||||
|
EXPECT_EQ((b+1), sprite->getFrameDuration(FrameNumber(1))); \
|
||||||
|
EXPECT_EQ((c+1), sprite->getFrameDuration(FrameNumber(2))); \
|
||||||
|
EXPECT_EQ((d+1), sprite->getFrameDuration(FrameNumber(3)));
|
||||||
|
|
||||||
|
class DocRangeOps : public ::testing::Test {
|
||||||
|
public:
|
||||||
|
DocRangeOps() {
|
||||||
|
doc.reset(static_cast<Document*>(ctx.documents().add(2, 2)));
|
||||||
|
sprite = doc->sprite();
|
||||||
|
layer1 = dynamic_cast<LayerImage*>(sprite->folder()->getFirstLayer());
|
||||||
|
layer2 = new LayerImage(sprite);
|
||||||
|
layer3 = new LayerImage(sprite);
|
||||||
|
layer4 = new LayerImage(sprite);
|
||||||
|
sprite->folder()->addLayer(layer2);
|
||||||
|
sprite->folder()->addLayer(layer3);
|
||||||
|
sprite->folder()->addLayer(layer4);
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
|
||||||
|
layer1->setName("layer1");
|
||||||
|
layer2->setName("layer2");
|
||||||
|
layer3->setName("layer3");
|
||||||
|
layer4->setName("layer4");
|
||||||
|
|
||||||
|
sprite->setTotalFrames(FrameNumber(4));
|
||||||
|
sprite->setFrameDuration(FrameNumber(0), 1); // These durations can be used to identify
|
||||||
|
sprite->setFrameDuration(FrameNumber(1), 2); // frames after a move operation
|
||||||
|
sprite->setFrameDuration(FrameNumber(2), 3);
|
||||||
|
sprite->setFrameDuration(FrameNumber(3), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
~DocRangeOps() {
|
||||||
|
doc->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TestContext ctx;
|
||||||
|
DocumentPtr doc;
|
||||||
|
Sprite* sprite;
|
||||||
|
LayerImage* layer1;
|
||||||
|
LayerImage* layer2;
|
||||||
|
LayerImage* layer3;
|
||||||
|
LayerImage* layer4;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline DocumentRange range(Layer* fromLayer, int fromFrNum, Layer* toLayer, int toFrNum, DocumentRange::Type type) {
|
||||||
|
DocumentRange r;
|
||||||
|
r.startRange(fromLayer->sprite()->layerToIndex(fromLayer), FrameNumber(fromFrNum), type);
|
||||||
|
r.endRange(toLayer->sprite()->layerToIndex(toLayer), FrameNumber(toFrNum));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DocumentRange range(int fromLayer, int fromFrNum, int toLayer, int toFrNum, DocumentRange::Type type) {
|
||||||
|
DocumentRange r;
|
||||||
|
r.startRange(LayerIndex(fromLayer), FrameNumber(fromFrNum), type);
|
||||||
|
r.endRange(LayerIndex(toLayer), FrameNumber(toFrNum));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DocumentRange layers_range(Layer* fromLayer, Layer* toLayer) {
|
||||||
|
return range(fromLayer, -1, toLayer, -1, DocumentRange::kLayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DocumentRange layers_range(int fromLayer, int toLayer) {
|
||||||
|
return range(fromLayer, -1, toLayer, -1, DocumentRange::kLayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DocumentRange layers_range(Layer* layer) {
|
||||||
|
return range(layer, -1, layer, -1, DocumentRange::kLayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DocumentRange layers_range(int layer) {
|
||||||
|
return range(layer, -1, layer, -1, DocumentRange::kLayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DocumentRange frames_range(int fromFrame, int toFrame) {
|
||||||
|
return range(0, fromFrame, 0, toFrame, DocumentRange::kFrames);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DocumentRange frames_range(int frame) {
|
||||||
|
return range(0, frame, 0, frame, DocumentRange::kFrames);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const DocumentRange& range) {
|
||||||
|
return os << "{ layers: [" << range.layerBegin() << ", " << range.layerEnd() << "]"
|
||||||
|
<< ", frames: [" << range.frameBegin() << ", " << range.frameEnd() << "] }";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DocRangeOps, MoveLayersNoOp) {
|
||||||
|
// Move one layer to the same place
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer1),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer1),
|
||||||
|
layers_range(layer1), kDocumentRangeAfter));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer1),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer1),
|
||||||
|
layers_range(layer2), kDocumentRangeBefore));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer4),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer4),
|
||||||
|
layers_range(layer4), kDocumentRangeAfter));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer4),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer4),
|
||||||
|
layers_range(layer4), kDocumentRangeBefore));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer4),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer4),
|
||||||
|
layers_range(layer3), kDocumentRangeAfter));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
// Move two layer to the same place
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer1, layer2),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer1, layer2),
|
||||||
|
layers_range(layer1), kDocumentRangeBefore));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer1, layer2),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer1, layer2),
|
||||||
|
layers_range(layer1), kDocumentRangeAfter));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer1, layer2),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer1, layer2),
|
||||||
|
layers_range(layer2), kDocumentRangeBefore));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer1, layer2),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer1, layer2),
|
||||||
|
layers_range(layer2), kDocumentRangeAfter));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer1, layer2),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer1, layer2),
|
||||||
|
layers_range(layer3), kDocumentRangeBefore));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer3, layer4),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer3, layer4),
|
||||||
|
layers_range(layer2), kDocumentRangeAfter));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer3, layer4),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer3, layer4),
|
||||||
|
layers_range(layer3), kDocumentRangeBefore));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer3, layer4),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer3, layer4),
|
||||||
|
layers_range(layer3), kDocumentRangeAfter));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer3, layer4),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer3, layer4),
|
||||||
|
layers_range(layer4), kDocumentRangeBefore));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer3, layer4),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer3, layer4),
|
||||||
|
layers_range(layer4), kDocumentRangeAfter));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
// Move four layers
|
||||||
|
|
||||||
|
DocumentRangePlace places[] = { kDocumentRangeBefore, kDocumentRangeAfter };
|
||||||
|
for (int i=0; i<2; ++i) {
|
||||||
|
for (int layer=0; layer<4; ++layer) {
|
||||||
|
EXPECT_EQ(layers_range(layer1, layer4),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer1, layer4),
|
||||||
|
layers_range(layer), places[i]));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int layer=0; layer<3; ++layer) {
|
||||||
|
EXPECT_EQ(layers_range(layer1, layer4),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer1, layer4),
|
||||||
|
layers_range(layer, layer+1), places[i]));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int layer=0; layer<2; ++layer) {
|
||||||
|
EXPECT_EQ(layers_range(layer1, layer4),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer1, layer4),
|
||||||
|
layers_range(layer, layer+2), places[i]));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(layers_range(layer1, layer4),
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer1, layer4),
|
||||||
|
layers_range(layer1, layer4), places[i]));
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DocRangeOps, MoveFramesNoOp) {
|
||||||
|
// Move one frame to the same place
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(0),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(0),
|
||||||
|
frames_range(0), kDocumentRangeAfter));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(0),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(0),
|
||||||
|
frames_range(1), kDocumentRangeBefore));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(3),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(3),
|
||||||
|
frames_range(3), kDocumentRangeAfter));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(3),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(3),
|
||||||
|
frames_range(3), kDocumentRangeBefore));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(3),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(3),
|
||||||
|
frames_range(2), kDocumentRangeAfter));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
// Move two frame to the same place
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(0, 1),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(0, 1),
|
||||||
|
frames_range(0), kDocumentRangeBefore));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(0, 1),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(0, 1),
|
||||||
|
frames_range(0), kDocumentRangeAfter));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(0, 1),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(0, 1),
|
||||||
|
frames_range(1), kDocumentRangeBefore));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(0, 1),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(0, 1),
|
||||||
|
frames_range(1), kDocumentRangeAfter));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(0, 1),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(0, 1),
|
||||||
|
frames_range(2), kDocumentRangeBefore));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(2, 3),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(2, 3),
|
||||||
|
frames_range(1), kDocumentRangeAfter));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(2, 3),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(2, 3),
|
||||||
|
frames_range(2), kDocumentRangeBefore));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(2, 3),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(2, 3),
|
||||||
|
frames_range(2), kDocumentRangeAfter));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(2, 3),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(2, 3),
|
||||||
|
frames_range(3), kDocumentRangeBefore));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(2, 3),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(2, 3),
|
||||||
|
frames_range(3), kDocumentRangeAfter));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
|
||||||
|
// Move four frames
|
||||||
|
|
||||||
|
DocumentRangePlace places[] = { kDocumentRangeBefore, kDocumentRangeAfter };
|
||||||
|
for (int i=0; i<2; ++i) {
|
||||||
|
for (int frame=0; frame<4; ++frame) {
|
||||||
|
EXPECT_EQ(frames_range(0, 3),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(0, 3),
|
||||||
|
frames_range(frame), places[i]));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int frame=0; frame<3; ++frame) {
|
||||||
|
EXPECT_EQ(frames_range(0, 3),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(0, 3),
|
||||||
|
frames_range(frame, frame+1), places[i]));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int frame=0; frame<2; ++frame) {
|
||||||
|
EXPECT_EQ(frames_range(0, 3),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(0, 3),
|
||||||
|
frames_range(frame, frame+2), places[i]));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(frames_range(0, 3),
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(0, 3),
|
||||||
|
frames_range(0, 3), places[i]));
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
EXPECT_FALSE(doc->getUndo()->canUndo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DocRangeOps, MoveCelsNoOp) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DocRangeOps, CopyCelsNoOp) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DocRangeOps, MoveLayers) {
|
||||||
|
DocumentRange result;
|
||||||
|
|
||||||
|
// One layer at the bottom of another
|
||||||
|
result = move_range(doc,
|
||||||
|
layers_range(layer1),
|
||||||
|
layers_range(layer2), kDocumentRangeAfter);
|
||||||
|
EXPECT_LAYER_ORDER(layer2, layer1, layer3, layer4);
|
||||||
|
EXPECT_EQ(layers_range(layer1), result);
|
||||||
|
|
||||||
|
doc->getUndo()->doUndo();
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
|
||||||
|
// One layer at the bottom
|
||||||
|
result = move_range(doc,
|
||||||
|
layers_range(layer2),
|
||||||
|
layers_range(layer1), kDocumentRangeBefore);
|
||||||
|
EXPECT_LAYER_ORDER(layer2, layer1, layer3, layer4);
|
||||||
|
EXPECT_EQ(layers_range(layer2), result);
|
||||||
|
|
||||||
|
doc->getUndo()->doUndo();
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
|
||||||
|
// Try with a background
|
||||||
|
layer1->setBackground(true);
|
||||||
|
EXPECT_ANY_THROW({
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer1),
|
||||||
|
layers_range(layer2), kDocumentRangeAfter);
|
||||||
|
});
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
layer1->setBackground(false);
|
||||||
|
|
||||||
|
// Move one layer to the top
|
||||||
|
result = move_range(doc,
|
||||||
|
layers_range(layer2),
|
||||||
|
layers_range(layer4), kDocumentRangeAfter);
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer3, layer4, layer2);
|
||||||
|
EXPECT_EQ(layers_range(layer2), result);
|
||||||
|
|
||||||
|
doc->getUndo()->doUndo();
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
|
||||||
|
// Move one layers before other
|
||||||
|
result = move_range(doc,
|
||||||
|
layers_range(layer2),
|
||||||
|
layers_range(layer4), kDocumentRangeBefore);
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer3, layer2, layer4);
|
||||||
|
EXPECT_EQ(layers_range(layer2), result);
|
||||||
|
|
||||||
|
doc->getUndo()->doUndo();
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
|
||||||
|
result = move_range(doc,
|
||||||
|
layers_range(layer1),
|
||||||
|
layers_range(layer3, layer4), kDocumentRangeBefore);
|
||||||
|
EXPECT_LAYER_ORDER(layer2, layer1, layer3, layer4);
|
||||||
|
EXPECT_EQ(layers_range(layer1), result);
|
||||||
|
|
||||||
|
doc->getUndo()->doUndo();
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
|
||||||
|
// Move two layers on top of other
|
||||||
|
result = move_range(doc,
|
||||||
|
layers_range(layer2, layer3),
|
||||||
|
layers_range(layer4), kDocumentRangeAfter);
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer4, layer2, layer3);
|
||||||
|
EXPECT_EQ(layers_range(layer2, layer3), result);
|
||||||
|
|
||||||
|
result = move_range(doc,
|
||||||
|
layers_range(layer2, layer3),
|
||||||
|
layers_range(layer1), kDocumentRangeAfter);
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
EXPECT_EQ(layers_range(layer2, layer3), result);
|
||||||
|
|
||||||
|
// Move three layers at the bottom (but we cannot because the bottom is a background layer)
|
||||||
|
layer1->setBackground(true);
|
||||||
|
EXPECT_ANY_THROW({
|
||||||
|
move_range(doc,
|
||||||
|
layers_range(layer2, layer4),
|
||||||
|
layers_range(layer1), kDocumentRangeBefore);
|
||||||
|
});
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
layer1->setBackground(false);
|
||||||
|
|
||||||
|
// Move three layers at the top
|
||||||
|
result = move_range(doc,
|
||||||
|
layers_range(layer1, layer3),
|
||||||
|
layers_range(layer4), kDocumentRangeAfter);
|
||||||
|
EXPECT_LAYER_ORDER(layer4, layer1, layer2, layer3);
|
||||||
|
EXPECT_EQ(layers_range(layer1, layer3), result);
|
||||||
|
|
||||||
|
doc->getUndo()->doUndo();
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
|
||||||
|
// Move three layers at the bottom
|
||||||
|
result = move_range(doc,
|
||||||
|
layers_range(layer2, layer4),
|
||||||
|
layers_range(layer1), kDocumentRangeBefore);
|
||||||
|
EXPECT_LAYER_ORDER(layer2, layer3, layer4, layer1);
|
||||||
|
EXPECT_EQ(layers_range(layer2, layer4), result);
|
||||||
|
|
||||||
|
doc->getUndo()->doUndo();
|
||||||
|
EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DocRangeOps, MoveFrames) {
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(0, 0),
|
||||||
|
frames_range(1, 1), kDocumentRangeAfter);
|
||||||
|
EXPECT_FRAME_ORDER(1, 0, 2, 3);
|
||||||
|
|
||||||
|
doc->getUndo()->doUndo();
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
|
||||||
|
// Move one frame at the end
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(1, 1),
|
||||||
|
frames_range(3, 3), kDocumentRangeAfter);
|
||||||
|
EXPECT_FRAME_ORDER(0, 2, 3, 1);
|
||||||
|
|
||||||
|
doc->getUndo()->doUndo();
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
|
||||||
|
// Move two frames after other
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(1, 2),
|
||||||
|
frames_range(3, 3), kDocumentRangeAfter);
|
||||||
|
EXPECT_FRAME_ORDER(0, 3, 1, 2);
|
||||||
|
|
||||||
|
doc->getUndo()->doUndo();
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(1, 2),
|
||||||
|
frames_range(0, 0), kDocumentRangeAfter);
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
|
||||||
|
// Move three frames at the beginning
|
||||||
|
move_range(doc,
|
||||||
|
frames_range(1, 3),
|
||||||
|
frames_range(0, 0), kDocumentRangeBefore);
|
||||||
|
EXPECT_FRAME_ORDER(1, 2, 3, 0);
|
||||||
|
|
||||||
|
doc->getUndo()->doUndo();
|
||||||
|
EXPECT_FRAME_ORDER(0, 1, 2, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DocRangeOps, MoveCels) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DocRangeOps, CopyLayers) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DocRangeOps, CopyFrames) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DocRangeOps, CopyCels) {
|
||||||
|
// TODO
|
||||||
|
}
|
@ -20,6 +20,7 @@
|
|||||||
#define APP_TEST_CONTEXT_H_INCLUDED
|
#define APP_TEST_CONTEXT_H_INCLUDED
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "app/context.h"
|
||||||
#include "app/document_location.h"
|
#include "app/document_location.h"
|
||||||
#include "doc/settings.h"
|
#include "doc/settings.h"
|
||||||
#include "raster/layer.h"
|
#include "raster/layer.h"
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "app/context_access.h"
|
#include "app/context_access.h"
|
||||||
#include "app/document.h"
|
#include "app/document.h"
|
||||||
#include "app/document_api.h"
|
#include "app/document_api.h"
|
||||||
|
#include "app/document_range_ops.h"
|
||||||
#include "app/document_undo.h"
|
#include "app/document_undo.h"
|
||||||
#include "app/modules/editors.h"
|
#include "app/modules/editors.h"
|
||||||
#include "app/modules/gfx.h"
|
#include "app/modules/gfx.h"
|
||||||
@ -1614,9 +1615,9 @@ void Timeline::updateStatusBar(ui::Message* msg)
|
|||||||
case Range::kLayers: {
|
case Range::kLayers: {
|
||||||
int layerIdx = -1;
|
int layerIdx = -1;
|
||||||
if (m_dropTarget.vhit == DropTarget::Bottom)
|
if (m_dropTarget.vhit == DropTarget::Bottom)
|
||||||
layerIdx = m_dropRange.layerEnd();
|
|
||||||
else if (m_dropTarget.vhit == DropTarget::Top)
|
|
||||||
layerIdx = m_dropRange.layerBegin();
|
layerIdx = m_dropRange.layerBegin();
|
||||||
|
else if (m_dropTarget.vhit == DropTarget::Top)
|
||||||
|
layerIdx = m_dropRange.layerEnd();
|
||||||
|
|
||||||
Layer* layer = ((layerIdx >= 0 && layerIdx < (int)m_layers.size()) ? m_layers[layerIdx]: NULL);
|
Layer* layer = ((layerIdx >= 0 && layerIdx < (int)m_layers.size()) ? m_layers[layerIdx]: NULL);
|
||||||
if (layer) {
|
if (layer) {
|
||||||
@ -1837,245 +1838,47 @@ bool Timeline::isFrameActive(FrameNumber frame) const
|
|||||||
return m_range.inRange(frame);
|
return m_range.inRange(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO This must be re-implemented
|
|
||||||
void Timeline::dropRange(DropOp op)
|
void Timeline::dropRange(DropOp op)
|
||||||
{
|
{
|
||||||
Range drop = m_dropRange;
|
bool copy = (op == Timeline::kCopy);
|
||||||
|
Range newFromRange;
|
||||||
|
DocumentRangePlace place = kDocumentRangeAfter;
|
||||||
|
|
||||||
// "Do nothing" cases. The user drops in the same place. (We don't
|
switch (m_range.type()) {
|
||||||
// even add the undo information.)
|
case Range::kFrames:
|
||||||
if (!doesDropModifySprite(drop, op))
|
if (m_dropTarget.hhit == DropTarget::Before)
|
||||||
return;
|
place = kDocumentRangeBefore;
|
||||||
|
break;
|
||||||
const char* undoLabel = NULL;
|
case Range::kLayers:
|
||||||
switch (op) {
|
if (m_dropTarget.vhit == DropTarget::Bottom)
|
||||||
case Timeline::kMove: undoLabel = "Move Range"; break;
|
place = kDocumentRangeBefore;
|
||||||
case Timeline::kCopy: undoLabel = "Copy Range"; break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ContextReader reader(m_context);
|
|
||||||
ContextWriter writer(reader);
|
|
||||||
UndoTransaction undo(writer.context(), undoLabel, undo::ModifyDocument);
|
|
||||||
int activeRelativeLayer = getLayerIndex(m_layer) - m_range.layerBegin();
|
int activeRelativeLayer = getLayerIndex(m_layer) - m_range.layerBegin();
|
||||||
FrameNumber activeRelativeFrame = m_frame - m_range.frameBegin();
|
FrameNumber activeRelativeFrame = m_frame - m_range.frameBegin();
|
||||||
|
|
||||||
switch (drop.type()) {
|
try {
|
||||||
case Range::kCels: dropCels(op, drop); break;
|
if (copy)
|
||||||
case Range::kFrames: dropFrames(op, drop); break;
|
newFromRange = copy_range(m_document, m_range, m_dropRange, place);
|
||||||
case Range::kLayers: dropLayers(op, drop); break;
|
else
|
||||||
|
newFromRange = move_range(m_document, m_range, m_dropRange, place);
|
||||||
|
|
||||||
|
regenerateLayers();
|
||||||
|
|
||||||
|
m_range = newFromRange;
|
||||||
|
if (m_range.layerBegin() >= LayerIndex(0))
|
||||||
|
setLayer(m_layers[m_range.layerBegin() + activeRelativeLayer]);
|
||||||
|
if (m_range.frameBegin() >= FrameNumber(0))
|
||||||
|
setFrame(m_range.frameBegin() + activeRelativeFrame);
|
||||||
}
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
undo.commit();
|
ui::Alert::show("Problem<<%s||&OK", e.what());
|
||||||
|
|
||||||
regenerateLayers();
|
|
||||||
|
|
||||||
// Adjust "drop" range so we can select the same selected range that
|
|
||||||
// the user had selected.
|
|
||||||
switch (drop.type()) {
|
|
||||||
|
|
||||||
case Range::kFrames:
|
|
||||||
if (op == Timeline::kMove && m_range.frameBegin() < drop.frameBegin()) {
|
|
||||||
drop.displace(firstLayer(), -m_range.frames());
|
|
||||||
}
|
|
||||||
drop.setFrames(m_range.frames());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Range::kLayers:
|
|
||||||
if (op == Timeline::kMove && m_range.layerBegin() < drop.layerBegin()) {
|
|
||||||
drop.displace(-m_range.layers(), 0);
|
|
||||||
}
|
|
||||||
drop.setLayers(m_range.layers());
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setLayer(m_layers[drop.layerBegin() + activeRelativeLayer]);
|
|
||||||
setFrame(drop.frameBegin() + activeRelativeFrame);
|
|
||||||
m_range = drop;
|
|
||||||
|
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::dropCels(DropOp op, const Range& drop)
|
|
||||||
{
|
|
||||||
ASSERT(validLayer(drop.layerBegin()));
|
|
||||||
ASSERT(validLayer(drop.layerEnd()));
|
|
||||||
ASSERT(validFrame(drop.frameBegin()));
|
|
||||||
ASSERT(validFrame(drop.frameEnd()));
|
|
||||||
|
|
||||||
int srcLayerBegin, srcLayerStep, srcLayerEnd;
|
|
||||||
int dstLayerBegin, dstLayerStep;
|
|
||||||
FrameNumber srcFrameBegin, srcFrameStep, srcFrameEnd;
|
|
||||||
FrameNumber dstFrameBegin, dstFrameStep;
|
|
||||||
|
|
||||||
if (drop.layerBegin() <= m_range.layerBegin()) {
|
|
||||||
srcLayerBegin = m_range.layerBegin();
|
|
||||||
srcLayerStep = 1;
|
|
||||||
srcLayerEnd = m_range.layerEnd()+1;
|
|
||||||
dstLayerBegin = drop.layerBegin();
|
|
||||||
dstLayerStep = 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
srcLayerBegin = m_range.layerEnd();
|
|
||||||
srcLayerStep = -1;
|
|
||||||
srcLayerEnd = m_range.layerBegin()-1;
|
|
||||||
dstLayerBegin = drop.layerEnd();
|
|
||||||
dstLayerStep = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drop.frameBegin() <= m_range.frameBegin()) {
|
|
||||||
srcFrameBegin = m_range.frameBegin();
|
|
||||||
srcFrameStep = FrameNumber(1);
|
|
||||||
srcFrameEnd = m_range.frameEnd().next();
|
|
||||||
dstFrameBegin = drop.frameBegin();
|
|
||||||
dstFrameStep = FrameNumber(1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
srcFrameBegin = m_range.frameEnd();
|
|
||||||
srcFrameStep = FrameNumber(-1);
|
|
||||||
srcFrameEnd = m_range.frameBegin().previous();
|
|
||||||
dstFrameBegin = drop.frameEnd();
|
|
||||||
dstFrameStep = FrameNumber(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
DocumentApi api = m_document->getApi();
|
|
||||||
|
|
||||||
for (int srcLayerIdx = srcLayerBegin,
|
|
||||||
dstLayerIdx = dstLayerBegin; srcLayerIdx != srcLayerEnd; ) {
|
|
||||||
for (FrameNumber srcFrame = srcFrameBegin,
|
|
||||||
dstFrame = dstFrameBegin; srcFrame != srcFrameEnd; ) {
|
|
||||||
LayerImage* srcLayer = static_cast<LayerImage*>(m_layers[srcLayerIdx]);
|
|
||||||
LayerImage* dstLayer = static_cast<LayerImage*>(m_layers[dstLayerIdx]);
|
|
||||||
color_t bgcolor = app_get_color_to_clear_layer(dstLayer);
|
|
||||||
|
|
||||||
switch (op) {
|
|
||||||
case Timeline::kMove: api.moveCel(m_sprite, srcLayer, dstLayer, srcFrame, dstFrame, bgcolor); break;
|
|
||||||
case Timeline::kCopy: api.copyCel(m_sprite, srcLayer, dstLayer, srcFrame, dstFrame, bgcolor); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
srcFrame += srcFrameStep;
|
|
||||||
dstFrame += dstFrameStep;
|
|
||||||
}
|
|
||||||
srcLayerIdx += srcLayerStep;
|
|
||||||
dstLayerIdx += dstLayerStep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timeline::dropFrames(DropOp op, const Range& drop)
|
|
||||||
{
|
|
||||||
FrameNumber srcFrameBegin, srcFrameStep, srcFrameEnd;
|
|
||||||
FrameNumber dstFrameBegin, dstFrameStep;
|
|
||||||
|
|
||||||
// TODO Try to add the range with just one call to DocumentApi
|
|
||||||
// methods, to avoid generating a lot of SetCelFrame undoers (see
|
|
||||||
// DocumentApi::setCelFramePosition).
|
|
||||||
|
|
||||||
switch (op) {
|
|
||||||
|
|
||||||
case Timeline::kMove:
|
|
||||||
if (drop.frameBegin() <= m_range.frameBegin()) {
|
|
||||||
srcFrameBegin = m_range.frameBegin();
|
|
||||||
srcFrameStep = FrameNumber(1);
|
|
||||||
srcFrameEnd = m_range.frameEnd().next();
|
|
||||||
dstFrameBegin = drop.frameBegin();
|
|
||||||
dstFrameStep = FrameNumber(1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
srcFrameBegin = m_range.frameEnd();
|
|
||||||
srcFrameStep = FrameNumber(-1);
|
|
||||||
srcFrameEnd = m_range.frameBegin().previous();
|
|
||||||
dstFrameBegin = drop.frameBegin();
|
|
||||||
dstFrameStep = FrameNumber(-1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Timeline::kCopy:
|
|
||||||
if (drop.frameBegin() <= m_range.frameBegin()) {
|
|
||||||
srcFrameBegin = m_range.frameBegin();
|
|
||||||
srcFrameStep = FrameNumber(2);
|
|
||||||
srcFrameEnd = m_range.frameBegin().next(2*m_range.frames());
|
|
||||||
dstFrameBegin = drop.frameBegin();
|
|
||||||
dstFrameStep = FrameNumber(1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
srcFrameBegin = m_range.frameEnd();
|
|
||||||
srcFrameStep = FrameNumber(-1);
|
|
||||||
srcFrameEnd = m_range.frameBegin().previous();
|
|
||||||
dstFrameBegin = drop.frameBegin();
|
|
||||||
dstFrameStep = firstFrame();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
DocumentApi api = m_document->getApi();
|
|
||||||
|
|
||||||
for (FrameNumber srcFrame = srcFrameBegin,
|
|
||||||
dstFrame = dstFrameBegin; srcFrame != srcFrameEnd; ) {
|
|
||||||
switch (op) {
|
|
||||||
case Timeline::kMove: api.moveFrame(m_sprite, srcFrame, dstFrame); break;
|
|
||||||
case Timeline::kCopy: api.copyFrame(m_sprite, srcFrame, dstFrame); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
srcFrame += srcFrameStep;
|
|
||||||
dstFrame += dstFrameStep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timeline::dropLayers(DropOp op, const Range& drop)
|
|
||||||
{
|
|
||||||
ASSERT(m_clk_layer >= 0 && m_clk_layer < (int)m_layers.size());
|
|
||||||
if (m_clk_layer < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_layers[m_clk_layer]->isBackground()) {
|
|
||||||
Alert::show(PACKAGE "<<You can't move the `Background' layer.||&OK");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Layer* firstLayer = m_layers[m_range.layerBegin()];
|
|
||||||
Layer* lastLayer = m_layers[m_range.layerEnd()];
|
|
||||||
|
|
||||||
std::vector<Layer*> layers = m_layers;
|
|
||||||
|
|
||||||
switch (op) {
|
|
||||||
|
|
||||||
case Timeline::kMove:
|
|
||||||
for (int i = m_range.layerBegin(); i <= m_range.layerEnd(); ++i) {
|
|
||||||
m_document->getApi().restackLayerAfter(
|
|
||||||
layers[i], layers[drop.layerBegin()]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Timeline::kCopy:
|
|
||||||
for (int i = m_range.layerBegin(); i <= m_range.layerEnd(); ++i) {
|
|
||||||
m_document->getApi().duplicateLayer(
|
|
||||||
layers[i], layers[drop.layerBegin()]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Timeline::doesDropModifySprite(const Range& drop, DropOp op) const
|
|
||||||
{
|
|
||||||
switch (drop.type()) {
|
|
||||||
case Range::kCels:
|
|
||||||
if (drop == m_range)
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
case Range::kFrames:
|
|
||||||
if (op == Timeline::kMove && drop.frameBegin() == m_range.frameBegin())
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
case Range::kLayers:
|
|
||||||
if (op == Timeline::kMove && drop.layerBegin() == m_range.layerBegin())
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ASSERT(false && "You shouldn't call dropRange() if the range is disabled");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timeline::updateDropRange(const gfx::Point& pt)
|
void Timeline::updateDropRange(const gfx::Point& pt)
|
||||||
{
|
{
|
||||||
DropTarget::HHit oldHHit = m_dropTarget.hhit;
|
DropTarget::HHit oldHHit = m_dropTarget.hhit;
|
||||||
@ -2165,64 +1968,4 @@ bool Timeline::isCopyKeyPressed(ui::Message* msg)
|
|||||||
return msg->ctrlPressed();
|
return msg->ctrlPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::Range::startRange(LayerIndex layer, FrameNumber frame, Type type)
|
|
||||||
{
|
|
||||||
m_type = type;
|
|
||||||
m_layerBegin = m_layerEnd = layer;
|
|
||||||
m_frameBegin = m_frameEnd = frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timeline::Range::endRange(LayerIndex layer, FrameNumber frame)
|
|
||||||
{
|
|
||||||
ASSERT(enabled());
|
|
||||||
m_layerEnd = layer;
|
|
||||||
m_frameEnd = frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timeline::Range::disableRange()
|
|
||||||
{
|
|
||||||
m_type = kNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Timeline::Range::inRange(LayerIndex layer) const
|
|
||||||
{
|
|
||||||
if (enabled())
|
|
||||||
return (layer >= layerBegin() && layer <= layerEnd());
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Timeline::Range::inRange(FrameNumber frame) const
|
|
||||||
{
|
|
||||||
if (enabled())
|
|
||||||
return (frame >= frameBegin() && frame <= frameEnd());
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Timeline::Range::inRange(LayerIndex layer, FrameNumber frame) const
|
|
||||||
{
|
|
||||||
return inRange(layer) && inRange(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timeline::Range::setLayers(int layers)
|
|
||||||
{
|
|
||||||
if (m_layerBegin <= m_layerEnd) m_layerEnd = m_layerBegin + LayerIndex(layers - 1);
|
|
||||||
else m_layerBegin = m_layerEnd + LayerIndex(layers - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timeline::Range::setFrames(FrameNumber frames)
|
|
||||||
{
|
|
||||||
if (m_frameBegin <= m_frameEnd) m_frameEnd = (m_frameBegin + frames).previous();
|
|
||||||
else m_frameBegin = (m_frameEnd + frames).previous();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timeline::Range::displace(int layerDelta, int frameDelta)
|
|
||||||
{
|
|
||||||
m_layerBegin += LayerIndex(layerDelta);
|
|
||||||
m_layerEnd += LayerIndex(layerDelta);
|
|
||||||
m_frameBegin += FrameNumber(frameDelta);
|
|
||||||
m_frameEnd += FrameNumber(frameDelta);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#define APP_UI_TIMELINE_H_INCLUDED
|
#define APP_UI_TIMELINE_H_INCLUDED
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "app/document_range.h"
|
||||||
#include "app/ui/editor/editor_observer.h"
|
#include "app/ui/editor/editor_observer.h"
|
||||||
#include "app/ui/skin/style.h"
|
#include "app/ui/skin/style.h"
|
||||||
#include "base/compiler_specific.h"
|
#include "base/compiler_specific.h"
|
||||||
@ -57,6 +58,8 @@ namespace app {
|
|||||||
, public doc::DocumentObserver
|
, public doc::DocumentObserver
|
||||||
, public app::EditorObserver {
|
, public app::EditorObserver {
|
||||||
public:
|
public:
|
||||||
|
typedef DocumentRange Range;
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
STATE_STANDBY,
|
STATE_STANDBY,
|
||||||
STATE_SCROLLING,
|
STATE_SCROLLING,
|
||||||
@ -69,46 +72,6 @@ namespace app {
|
|||||||
STATE_MOVING_ONIONSKIN_RANGE_RIGHT
|
STATE_MOVING_ONIONSKIN_RANGE_RIGHT
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Range {
|
|
||||||
enum Type { kNone, kCels, kFrames, kLayers };
|
|
||||||
|
|
||||||
Range() : m_type(kNone) { }
|
|
||||||
|
|
||||||
Type type() const { return m_type; }
|
|
||||||
bool enabled() const { return m_type != kNone; }
|
|
||||||
LayerIndex layerBegin() const { return MIN(m_layerBegin, m_layerEnd); }
|
|
||||||
LayerIndex layerEnd() const { return MAX(m_layerBegin, m_layerEnd); }
|
|
||||||
FrameNumber frameBegin() const { return MIN(m_frameBegin, m_frameEnd); }
|
|
||||||
FrameNumber frameEnd() const { return MAX(m_frameBegin, m_frameEnd); }
|
|
||||||
|
|
||||||
int layers() const { return layerEnd() - layerBegin() + 1; }
|
|
||||||
FrameNumber frames() const { return (frameEnd() - frameBegin()).next(); }
|
|
||||||
void setLayers(int layers);
|
|
||||||
void setFrames(FrameNumber frames);
|
|
||||||
void displace(int layerDelta, int frameDelta);
|
|
||||||
|
|
||||||
bool inRange(LayerIndex layer) const;
|
|
||||||
bool inRange(FrameNumber frame) const;
|
|
||||||
bool inRange(LayerIndex layer, FrameNumber frame) const;
|
|
||||||
|
|
||||||
void startRange(LayerIndex layer, FrameNumber frame, Type type);
|
|
||||||
void endRange(LayerIndex layer, FrameNumber frame);
|
|
||||||
void disableRange();
|
|
||||||
|
|
||||||
bool operator==(const Range& o) const {
|
|
||||||
return m_type == o.m_type &&
|
|
||||||
layerBegin() == o.layerBegin() && layerEnd() == o.layerEnd() &&
|
|
||||||
frameBegin() == o.frameBegin() && frameEnd() == o.frameEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Type m_type;
|
|
||||||
LayerIndex m_layerBegin;
|
|
||||||
LayerIndex m_layerEnd;
|
|
||||||
FrameNumber m_frameBegin;
|
|
||||||
FrameNumber m_frameEnd;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum DropOp { kMove, kCopy };
|
enum DropOp { kMove, kCopy };
|
||||||
|
|
||||||
Timeline();
|
Timeline();
|
||||||
@ -211,13 +174,8 @@ namespace app {
|
|||||||
bool isLayerActive(LayerIndex layerIdx) const;
|
bool isLayerActive(LayerIndex layerIdx) const;
|
||||||
bool isFrameActive(FrameNumber frame) const;
|
bool isFrameActive(FrameNumber frame) const;
|
||||||
void updateStatusBar(ui::Message* msg);
|
void updateStatusBar(ui::Message* msg);
|
||||||
bool doesDropModifySprite(const Range& drop, DropOp op) const;
|
|
||||||
void updateDropRange(const gfx::Point& pt);
|
void updateDropRange(const gfx::Point& pt);
|
||||||
|
|
||||||
void dropCels(DropOp op, const Range& drop);
|
|
||||||
void dropFrames(DropOp op, const Range& drop);
|
|
||||||
void dropLayers(DropOp op, const Range& drop);
|
|
||||||
|
|
||||||
bool isCopyKeyPressed(ui::Message* msg);
|
bool isCopyKeyPressed(ui::Message* msg);
|
||||||
|
|
||||||
// The layer of the bottom (e.g. Background layer)
|
// The layer of the bottom (e.g. Background layer)
|
||||||
|
@ -287,6 +287,10 @@ void LayerFolder::removeLayer(Layer* layer)
|
|||||||
|
|
||||||
void LayerFolder::stackLayer(Layer* layer, Layer* after)
|
void LayerFolder::stackLayer(Layer* layer, Layer* after)
|
||||||
{
|
{
|
||||||
|
ASSERT(layer != after);
|
||||||
|
if (layer == after)
|
||||||
|
return;
|
||||||
|
|
||||||
LayerIterator it = std::find(m_layers.begin(), m_layers.end(), layer);
|
LayerIterator it = std::find(m_layers.begin(), m_layers.end(), layer);
|
||||||
ASSERT(it != m_layers.end());
|
ASSERT(it != m_layers.end());
|
||||||
m_layers.erase(it);
|
m_layers.erase(it);
|
||||||
@ -299,14 +303,6 @@ void LayerFolder::stackLayer(Layer* layer, Layer* after)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_layers.push_front(layer);
|
m_layers.push_front(layer);
|
||||||
|
|
||||||
// TODO
|
|
||||||
// if (after) {
|
|
||||||
// JLink before = jlist_find(m_layers, after)->next;
|
|
||||||
// jlist_insert_before(m_layers, before, layer);
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// jlist_prepend(m_layers, layer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void layer_render(const Layer* layer, Image* image, int x, int y, FrameNumber frame)
|
void layer_render(const Layer* layer, Image* image, int x, int y, FrameNumber frame)
|
||||||
|
@ -227,6 +227,9 @@ LayerIndex Sprite::countLayers() const
|
|||||||
|
|
||||||
Layer* Sprite::indexToLayer(LayerIndex index) const
|
Layer* Sprite::indexToLayer(LayerIndex index) const
|
||||||
{
|
{
|
||||||
|
if (index < LayerIndex(0))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
int index_count = -1;
|
int index_count = -1;
|
||||||
return index2layer(folder(), index, &index_count);
|
return index2layer(folder(), index, &index_count);
|
||||||
}
|
}
|
||||||
@ -237,6 +240,17 @@ LayerIndex Sprite::layerToIndex(const Layer* layer) const
|
|||||||
return layer2index(folder(), layer, &index_count);
|
return layer2index(folder(), layer, &index_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sprite::getLayersList(std::vector<Layer*>& layers) const
|
||||||
|
{
|
||||||
|
// TODO support subfolders
|
||||||
|
LayerConstIterator it = m_folder->getLayerBegin();
|
||||||
|
LayerConstIterator end = m_folder->getLayerEnd();
|
||||||
|
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
layers.push_back(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Palettes
|
// Palettes
|
||||||
|
|
||||||
|
@ -88,6 +88,8 @@ namespace raster {
|
|||||||
Layer* indexToLayer(LayerIndex index) const;
|
Layer* indexToLayer(LayerIndex index) const;
|
||||||
LayerIndex layerToIndex(const Layer* layer) const;
|
LayerIndex layerToIndex(const Layer* layer) const;
|
||||||
|
|
||||||
|
void getLayersList(std::vector<Layer*>& layers) const;
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
// Palettes
|
// Palettes
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user