diff --git a/data/gui.xml b/data/gui.xml index 375a741d1..e55916c32 100644 --- a/data/gui.xml +++ b/data/gui.xml @@ -66,6 +66,7 @@ + @@ -503,7 +504,7 @@ - + @@ -521,6 +522,7 @@ + diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 5c8c21966..d6e9c544c 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -72,6 +72,7 @@ add_library(app-lib commands/cmd_remove_layer.cpp commands/cmd_repeat_last_export.cpp commands/cmd_reselect_mask.cpp + commands/cmd_reverse_frames.cpp commands/cmd_rotate.cpp commands/cmd_save_file.cpp commands/cmd_save_mask.cpp diff --git a/src/app/commands/cmd_reverse_frames.cpp b/src/app/commands/cmd_reverse_frames.cpp new file mode 100644 index 000000000..0432f3c1b --- /dev/null +++ b/src/app/commands/cmd_reverse_frames.cpp @@ -0,0 +1,73 @@ +/* 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/app.h" +#include "app/commands/command.h" +#include "app/context_access.h" +#include "app/modules/gui.h" +#include "app/ui/main_window.h" +#include "app/ui/timeline.h" +#include "app/document_range_ops.h" + +namespace app { + +class ReverseFramesCommand : public Command { +public: + ReverseFramesCommand(); + Command* clone() const override { return new ReverseFramesCommand(*this); } + +protected: + bool onEnabled(Context* context); + void onExecute(Context* context); +}; + +ReverseFramesCommand::ReverseFramesCommand() + : Command("ReverseFrames", + "Reverse Frames", + CmdUIOnlyFlag) +{ +} + +bool ReverseFramesCommand::onEnabled(Context* context) +{ + return context->checkFlags(ContextFlags::ActiveDocumentIsWritable); +} + +void ReverseFramesCommand::onExecute(Context* context) +{ + DocumentRange range = App::instance()->getMainWindow()->getTimeline()->range(); + if (!range.enabled()) + return; // Nothing to do + + Document* doc = context->activeDocument(); + + reverse_frames(doc, range); + + update_screen_for_document(doc); +} + +Command* CommandFactory::createReverseFramesCommand() +{ + return new ReverseFramesCommand; +} + +} // namespace app diff --git a/src/app/commands/commands_list.h b/src/app/commands/commands_list.h index 2b037be5e..67346ef6f 100644 --- a/src/app/commands/commands_list.h +++ b/src/app/commands/commands_list.h @@ -1,5 +1,5 @@ /* Aseprite - * Copyright (C) 2001-2013 David Capello + * 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 @@ -91,6 +91,7 @@ FOR_EACH_COMMAND(RemoveLayer) FOR_EACH_COMMAND(RepeatLastExport) FOR_EACH_COMMAND(ReplaceColor) FOR_EACH_COMMAND(ReselectMask) +FOR_EACH_COMMAND(ReverseFrames) FOR_EACH_COMMAND(Rotate) FOR_EACH_COMMAND(SaveFile) FOR_EACH_COMMAND(SaveFileAs) diff --git a/src/app/document_api.cpp b/src/app/document_api.cpp index 7f293739c..743bd212c 100644 --- a/src/app/document_api.cpp +++ b/src/app/document_api.cpp @@ -472,7 +472,7 @@ void DocumentApi::moveFrame(Sprite* sprite, FrameNumber frame, FrameNumber befor frame <= sprite->lastFrame() && beforeFrame >= 0 && beforeFrame <= sprite->lastFrame().next()) { - // Change the frame-lengths... + // Change the frame-lengths. int frlen_aux = sprite->getFrameDuration(frame); // Moving the frame to the future. @@ -490,7 +490,7 @@ void DocumentApi::moveFrame(Sprite* sprite, FrameNumber frame, FrameNumber befor setFrameDuration(sprite, beforeFrame, frlen_aux); } - // change the cels of position... + // Change cel positions. moveFrameLayer(sprite->folder(), frame, beforeFrame); } } @@ -818,6 +818,21 @@ void DocumentApi::copyCel( m_document->notifyCelCopied(srcLayer, srcFrame, dstLayer, dstFrame); } +void DocumentApi::swapCel( + LayerImage* layer, FrameNumber frame1, FrameNumber frame2) +{ + Sprite* sprite = layer->sprite(); + ASSERT(sprite != NULL); + ASSERT(frame1 >= 0 && frame1 < sprite->totalFrames()); + ASSERT(frame2 >= 0 && frame2 < sprite->totalFrames()); + + Cel* cel1 = layer->getCel(frame1); + Cel* cel2 = layer->getCel(frame2); + + if (cel1) setCelFramePosition(layer, cel1, frame2); + if (cel2) setCelFramePosition(layer, cel2, frame1); +} + LayerImage* DocumentApi::newLayer(Sprite* sprite) { LayerImage* layer = new LayerImage(sprite); diff --git a/src/app/document_api.h b/src/app/document_api.h index 876683a34..1ddfea1a5 100644 --- a/src/app/document_api.h +++ b/src/app/document_api.h @@ -1,5 +1,5 @@ /* Aseprite - * Copyright (C) 2001-2013 David Capello + * 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 @@ -91,6 +91,8 @@ namespace app { void copyCel( LayerImage* srcLayer, FrameNumber srcFrame, LayerImage* dstLayer, FrameNumber dstFrame); + void swapCel( + LayerImage* layer, FrameNumber frame1, FrameNumber frame2); // Layers API LayerImage* newLayer(Sprite* sprite); diff --git a/src/app/document_range_ops.cpp b/src/app/document_range_ops.cpp index 764328c02..7f407d95b 100644 --- a/src/app/document_range_ops.cpp +++ b/src/app/document_range_ops.cpp @@ -341,4 +341,62 @@ DocumentRange copy_range(Document* doc, const DocumentRange& from, const Documen return drop_range_op(doc, Copy, from, place, to); } +void reverse_frames(Document* doc, const DocumentRange& range) +{ + const app::Context* context = static_cast(doc->context()); + const ContextReader reader(context); + ContextWriter writer(reader); + UndoTransaction undo(writer.context(), "Reverse Frames"); + DocumentApi api = doc->getApi(); + Sprite* sprite = doc->sprite(); + FrameNumber frameBegin, frameEnd; + int layerBegin, layerEnd; + bool moveFrames = false; + + switch (range.type()) { + case DocumentRange::kCels: + frameBegin = range.frameBegin(); + frameEnd = range.frameEnd(); + layerBegin = range.layerBegin(); + layerEnd = range.layerEnd() + 1; + break; + case DocumentRange::kFrames: + frameBegin = range.frameBegin(); + frameEnd = range.frameEnd(); + moveFrames = true; + break; + case DocumentRange::kLayers: + frameBegin = FrameNumber(0); + frameEnd = sprite->totalFrames().previous(); + layerBegin = range.layerBegin(); + layerEnd = range.layerEnd() + 1; + break; + } + + if (moveFrames) { + for (FrameNumber frameRev = frameEnd.next(); + frameRev > frameBegin; + frameRev = frameRev.previous()) { + api.moveFrame(sprite, frameBegin, frameRev); + } + } + else { + std::vector layers; + sprite->getLayersList(layers); + + for (int layerIdx = layerBegin; layerIdx != layerEnd; ++layerIdx) { + for (FrameNumber frame = frameBegin, + frameRev = frameEnd; + frame != FrameNumber((frameBegin+frameEnd)/2).next(); + frame = frame.next(), + frameRev = frameRev.previous()) { + LayerImage* layer = static_cast(layers[layerIdx]); + api.swapCel(layer, frame, frameRev); + } + } + } + + undo.commit(); +} + } // namespace app diff --git a/src/app/document_range_ops.h b/src/app/document_range_ops.h index a6877eb15..7e67cca71 100644 --- a/src/app/document_range_ops.h +++ b/src/app/document_range_ops.h @@ -37,6 +37,8 @@ namespace app { 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); + void reverse_frames(Document* doc, const DocumentRange& range); + } // namespace app #endif diff --git a/src/app/document_range_tests.cpp b/src/app/document_range_tests.cpp index 3aff49e82..83931a247 100644 --- a/src/app/document_range_tests.cpp +++ b/src/app/document_range_tests.cpp @@ -764,3 +764,35 @@ TEST_F(DocRangeOps, CopyFrames) { TEST_F(DocRangeOps, CopyCels) { // TODO } + +TEST_F(DocRangeOps, ReverseFrames) { + reverse_frames(doc, frames_range(0, 0)); + EXPECT_FRAME_ORDER(0, 1, 2, 3); + + reverse_frames(doc, frames_range(1, 1)); + EXPECT_FRAME_ORDER(0, 1, 2, 3); + + reverse_frames(doc, frames_range(1, 2)); + EXPECT_FRAME_ORDER(0, 2, 1, 3); + doc->getUndo()->doUndo(); + EXPECT_FRAME_ORDER(0, 1, 2, 3); + + reverse_frames(doc, frames_range(0, 2)); + EXPECT_FRAME_ORDER(2, 1, 0, 3); + doc->getUndo()->doUndo(); + EXPECT_FRAME_ORDER(0, 1, 2, 3); + + reverse_frames(doc, frames_range(1, 3)); + EXPECT_FRAME_ORDER(0, 3, 2, 1); + doc->getUndo()->doUndo(); + EXPECT_FRAME_ORDER(0, 1, 2, 3); + + reverse_frames(doc, frames_range(0, 3)); + EXPECT_FRAME_ORDER(3, 2, 1, 0); + doc->getUndo()->doUndo(); + EXPECT_FRAME_ORDER(0, 1, 2, 3); +} + +TEST_F(DocRangeOps, ReverseCels) { + // TODO +}