mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-30 04:20:23 +00:00
Added Undoable class.
This commit is contained in:
parent
c35c452a80
commit
c327a740d7
21
ChangeLog
21
ChangeLog
@ -1,5 +1,26 @@
|
||||
2008-10-01 David A. Capello <davidcapello@gmail.com>
|
||||
|
||||
* src/raster/undo.cpp: Renamed undo_undo and undo_redo to
|
||||
undo_do_undo and undo_do_redo.
|
||||
(undo_clear_redo): Added (used by Undoable when the final result
|
||||
isn't committed).
|
||||
|
||||
* src/dialogs/aniedit.cpp (anieditor_msg_proc): Uses Undoable to
|
||||
move frames, and move layers.
|
||||
|
||||
* src/commands/cmd_new_layer.cpp (cmd_new_layer_execute):
|
||||
* src/commands/cmd_remove_cel.cpp (cmd_remove_cel_execute):
|
||||
* src/commands/cmd_remove_frame.cpp (cmd_remove_frame_execute):
|
||||
* src/commands/cmd_new_frame.cpp (cmd_new_frame_execute):
|
||||
Changed to use Undoable.
|
||||
|
||||
* src/raster/undoable.h (class Undoable): Added.
|
||||
|
||||
2008-09-30 David A. Capello <davidcapello@gmail.com>
|
||||
|
||||
* src/raster/gfxobj.h (GfxObj): Converted to a class (and all the
|
||||
hierarchy of graphics objects).
|
||||
|
||||
* src/tests/: Renamed src/test to src/tests
|
||||
|
||||
* makefile.lst: Project converted to C++
|
||||
|
@ -178,6 +178,10 @@ tests: $(TESTS)
|
||||
|
||||
runtests: $(AUTOTESTS)
|
||||
@-$(foreach TEST, $(AUTOTESTS), \
|
||||
echo ./$(TEST) "=====================" ; \
|
||||
./$(TEST) ; \
|
||||
echo Running ./$(TEST) ... ; \
|
||||
if ./$(TEST) ; then \
|
||||
echo " - OK" ; \
|
||||
else \
|
||||
echo " - *FAIL*" ; \
|
||||
fi ; \
|
||||
)
|
||||
|
@ -182,6 +182,7 @@ COMMON_SOURCES = \
|
||||
src/raster/sprite.cpp \
|
||||
src/raster/stock.cpp \
|
||||
src/raster/undo.cpp \
|
||||
src/raster/undoable.cpp \
|
||||
src/util/autocrop.cpp \
|
||||
src/util/boundary.cpp \
|
||||
src/util/celmove.cpp \
|
||||
|
@ -31,11 +31,11 @@
|
||||
#include "raster/image.h"
|
||||
#include "raster/layer.h"
|
||||
#include "raster/sprite.h"
|
||||
#include "raster/stock.h"
|
||||
#include "raster/undo.h"
|
||||
#include "util/functions.h"
|
||||
#include "raster/undoable.h"
|
||||
#include "widgets/statebar.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
static bool cmd_new_frame_enabled(const char *argument)
|
||||
{
|
||||
return
|
||||
@ -48,18 +48,17 @@ static bool cmd_new_frame_enabled(const char *argument)
|
||||
|
||||
static void cmd_new_frame_execute(const char *argument)
|
||||
{
|
||||
Sprite *sprite = current_sprite;
|
||||
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_set_label(sprite->undo, "New Frame");
|
||||
|
||||
NewFrame(sprite);
|
||||
|
||||
Sprite* sprite = current_sprite;
|
||||
{
|
||||
Undoable undoable(sprite, "New Frame");
|
||||
undoable.new_frame();
|
||||
undoable.commit();
|
||||
}
|
||||
update_screen_for_sprite(sprite);
|
||||
|
||||
statusbar_show_tip(app_get_statusbar(), 1000,
|
||||
_("New frame %d/%d"),
|
||||
sprite->frame+1, sprite->frames);
|
||||
sprite->frame+1,
|
||||
sprite->frames);
|
||||
}
|
||||
|
||||
Command cmd_new_frame = {
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "modules/sprites.h"
|
||||
#include "raster/layer.h"
|
||||
#include "raster/sprite.h"
|
||||
#include "raster/undo.h"
|
||||
#include "raster/undoable.h"
|
||||
#include "util/functions.h"
|
||||
|
||||
static bool cmd_new_layer_enabled(const char *argument)
|
||||
@ -37,7 +37,7 @@ static bool cmd_new_layer_enabled(const char *argument)
|
||||
static void cmd_new_layer_execute(const char *argument)
|
||||
{
|
||||
JWidget window, name_widget;
|
||||
Sprite *sprite = current_sprite; /* get current sprite */
|
||||
Sprite* sprite = current_sprite; /* get current sprite */
|
||||
|
||||
/* load the window widget */
|
||||
window = load_widget("newlay.jid", "new_layer");
|
||||
@ -55,16 +55,12 @@ static void cmd_new_layer_execute(const char *argument)
|
||||
jwindow_open_fg(window);
|
||||
|
||||
if (jwindow_get_killer(window) == jwidget_find_name(window, "ok")) {
|
||||
const char *name = jwidget_get_text(jwidget_find_name(window, "name"));
|
||||
Layer *layer;
|
||||
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_set_label(sprite->undo, "New Layer");
|
||||
|
||||
layer = NewLayer(sprite);
|
||||
if (!layer) {
|
||||
jalert(_("Error<<Not enough memory||&Close"));
|
||||
return;
|
||||
const char* name = jwidget_get_text(jwidget_find_name(window, "name"));
|
||||
Layer* layer;
|
||||
{
|
||||
Undoable undoable(sprite, "New Layer");
|
||||
layer = undoable.new_layer();
|
||||
undoable.commit();
|
||||
}
|
||||
layer_set_name(layer, name);
|
||||
update_screen_for_sprite(sprite);
|
||||
|
@ -37,7 +37,7 @@ static void cmd_redo_execute(const char *argument)
|
||||
_("Redid %s"),
|
||||
undo_get_next_redo_label(current_sprite->undo));
|
||||
|
||||
undo_redo(current_sprite->undo);
|
||||
undo_do_redo(current_sprite->undo);
|
||||
sprite_generate_mask_boundaries(current_sprite);
|
||||
update_screen_for_sprite(current_sprite);
|
||||
}
|
||||
|
@ -23,9 +23,8 @@
|
||||
#include "modules/sprites.h"
|
||||
#include "raster/cel.h"
|
||||
#include "raster/layer.h"
|
||||
#include "raster/undo.h"
|
||||
#include "raster/sprite.h"
|
||||
#include "util/functions.h"
|
||||
#include "raster/undoable.h"
|
||||
|
||||
static bool cmd_remove_cel_enabled(const char *argument)
|
||||
{
|
||||
@ -40,13 +39,13 @@ static bool cmd_remove_cel_enabled(const char *argument)
|
||||
|
||||
static void cmd_remove_cel_execute(const char *argument)
|
||||
{
|
||||
Sprite *sprite = current_sprite;
|
||||
Cel *cel = layer_get_cel(sprite->layer, sprite->frame);
|
||||
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_set_label(sprite->undo, "Remove Cel");
|
||||
|
||||
RemoveCel(sprite->layer, cel);
|
||||
Sprite* sprite = current_sprite;
|
||||
Cel* cel = layer_get_cel(sprite->layer, sprite->frame);
|
||||
{
|
||||
Undoable undoable(sprite, "Remove Cel");
|
||||
undoable.remove_cel(sprite->layer, cel);
|
||||
undoable.commit();
|
||||
}
|
||||
update_screen_for_sprite(sprite);
|
||||
}
|
||||
|
||||
|
@ -23,11 +23,8 @@
|
||||
#include "commands/commands.h"
|
||||
#include "modules/gui.h"
|
||||
#include "modules/sprites.h"
|
||||
#include "raster/cel.h"
|
||||
#include "raster/layer.h"
|
||||
#include "raster/sprite.h"
|
||||
#include "raster/undo.h"
|
||||
#include "util/functions.h"
|
||||
#include "raster/undoable.h"
|
||||
|
||||
static bool cmd_remove_frame_enabled(const char *argument)
|
||||
{
|
||||
@ -39,13 +36,12 @@ static bool cmd_remove_frame_enabled(const char *argument)
|
||||
static void cmd_remove_frame_execute(const char *argument)
|
||||
{
|
||||
Sprite *sprite = current_sprite;
|
||||
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_set_label(sprite->undo, "Remove Frame");
|
||||
|
||||
RemoveFrame(sprite, sprite->frame);
|
||||
|
||||
update_screen_for_sprite(current_sprite);
|
||||
{
|
||||
Undoable undoable(sprite, "Remove Frame");
|
||||
undoable.remove_frame(sprite->frame);
|
||||
undoable.commit();
|
||||
}
|
||||
update_screen_for_sprite(sprite);
|
||||
}
|
||||
|
||||
Command cmd_remove_frame = {
|
||||
|
@ -37,7 +37,7 @@ static void cmd_undo_execute(const char *argument)
|
||||
_("Undid %s"),
|
||||
undo_get_next_undo_label(current_sprite->undo));
|
||||
|
||||
undo_undo(current_sprite->undo);
|
||||
undo_do_undo(current_sprite->undo);
|
||||
sprite_generate_mask_boundaries(current_sprite);
|
||||
update_screen_for_sprite(current_sprite);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
/* #include <stdio.h> */
|
||||
#include <string.h>
|
||||
#include <allegro/unicode.h>
|
||||
#include <exception>
|
||||
|
||||
#include "jinete/jinete.h"
|
||||
|
||||
@ -265,9 +266,17 @@ void command_execute(Command *command, const char *argument)
|
||||
{
|
||||
console_open();
|
||||
|
||||
if (command && command->execute &&
|
||||
command_is_enabled(command, argument)) {
|
||||
(*command->execute)(argument);
|
||||
try {
|
||||
if (command && command->execute &&
|
||||
command_is_enabled(command, argument)) {
|
||||
(*command->execute)(argument);
|
||||
}
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
jalert("Error"
|
||||
"<<Uncaught exception:"
|
||||
"<<%s"
|
||||
"||&OK", e.what());
|
||||
}
|
||||
|
||||
console_close();
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "modules/rootmenu.h"
|
||||
#include "modules/sprites.h"
|
||||
#include "raster/raster.h"
|
||||
#include "raster/undoable.h"
|
||||
#include "util/celmove.h"
|
||||
#include "util/functions.h"
|
||||
#include "util/thmbnail.h"
|
||||
@ -535,11 +536,11 @@ static bool anieditor_msg_proc(JWidget widget, JMessage msg)
|
||||
if (anieditor->hot_frame >= 0 &&
|
||||
anieditor->hot_frame < anieditor->sprite->frames &&
|
||||
anieditor->hot_frame != anieditor->clk_frame+1) {
|
||||
if (undo_is_enabled(anieditor->sprite->undo))
|
||||
undo_set_label(anieditor->sprite->undo, "Move Frame");
|
||||
|
||||
/* TODO warning MoveFrameBefore uses the current_sprite, not 'anieditor->sprite' */
|
||||
MoveFrameBefore(anieditor->clk_frame, anieditor->hot_frame);
|
||||
{
|
||||
Undoable undoable(anieditor->sprite, "Move Frame");
|
||||
undoable.move_frame_before(anieditor->clk_frame, anieditor->hot_frame);
|
||||
undoable.commit();
|
||||
}
|
||||
jwidget_dirty(widget);
|
||||
}
|
||||
}
|
||||
@ -566,12 +567,13 @@ static bool anieditor_msg_proc(JWidget widget, JMessage msg)
|
||||
anieditor->hot_layer != anieditor->clk_layer &&
|
||||
anieditor->hot_layer != anieditor->clk_layer+1) {
|
||||
if (!layer_is_background(anieditor->layers[anieditor->clk_layer])) {
|
||||
if (undo_is_enabled(anieditor->sprite->undo))
|
||||
undo_set_label(anieditor->sprite->undo, "Move Layer");
|
||||
|
||||
/* move the clicked-layer after the hot-layer */
|
||||
MoveLayerAfter(anieditor->layers[anieditor->clk_layer],
|
||||
anieditor->layers[anieditor->hot_layer]);
|
||||
// move the clicked-layer after the hot-layer
|
||||
{
|
||||
Undoable undoable(anieditor->sprite, "Move Layer");
|
||||
undoable.move_layer_after(anieditor->layers[anieditor->clk_layer],
|
||||
anieditor->layers[anieditor->hot_layer]);
|
||||
undoable.commit();
|
||||
}
|
||||
|
||||
/* select the new layer */
|
||||
anieditor->sprite->layer = anieditor->layers[anieditor->clk_layer];
|
||||
@ -678,7 +680,7 @@ static bool anieditor_msg_proc(JWidget widget, JMessage msg)
|
||||
/* undo */
|
||||
if (command && strcmp(command->name, CMD_UNDO) == 0) {
|
||||
if (undo_can_undo(sprite->undo)) {
|
||||
undo_undo(sprite->undo);
|
||||
undo_do_undo(sprite->undo);
|
||||
|
||||
destroy_thumbnails();
|
||||
anieditor_regenerate_layers(widget);
|
||||
@ -691,7 +693,7 @@ static bool anieditor_msg_proc(JWidget widget, JMessage msg)
|
||||
/* redo */
|
||||
if (command && strcmp(command->name, CMD_REDO) == 0) {
|
||||
if (undo_can_redo(sprite->undo)) {
|
||||
undo_redo(sprite->undo);
|
||||
undo_do_redo(sprite->undo);
|
||||
|
||||
destroy_thumbnails();
|
||||
anieditor_regenerate_layers(widget);
|
||||
|
@ -23,6 +23,7 @@
|
||||
/* #include <allegro/color.h> */
|
||||
/* #include <allegro/gfx.h> */
|
||||
#include <string.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "raster/algo.h"
|
||||
#include "raster/blend.h"
|
||||
@ -141,14 +142,10 @@ void image_merge(Image* dst, const Image* src, int x, int y, int opacity, int bl
|
||||
|
||||
Image* image_crop(const Image* image, int x, int y, int w, int h, int bgcolor)
|
||||
{
|
||||
Image* trim;
|
||||
if (w < 1) throw std::invalid_argument("image_crop: Width is less than 1");
|
||||
if (h < 1) throw std::invalid_argument("image_crop: Height is less than 1");
|
||||
|
||||
if ((w < 1) || (h < 1))
|
||||
return NULL;
|
||||
|
||||
trim = image_new(image->imgtype, w, h);
|
||||
if (!trim)
|
||||
return NULL;
|
||||
Image* trim = image_new(image->imgtype, w, h);
|
||||
|
||||
image_clear(trim, bgcolor);
|
||||
image_copy(trim, image, -x, -y);
|
||||
|
@ -392,10 +392,16 @@ void layer_add_cel(Layer* layer, Cel* cel)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the cel from the layer.
|
||||
*
|
||||
* It doesn't destroy the cel, you have to delete it after calling
|
||||
* this routine.
|
||||
*/
|
||||
void layer_remove_cel(Layer* layer, Cel* cel)
|
||||
{
|
||||
if (layer_is_image(layer))
|
||||
jlist_remove(layer->cels, cel);
|
||||
assert(layer_is_image(layer));
|
||||
jlist_remove(layer->cels, cel);
|
||||
}
|
||||
|
||||
Cel* layer_get_cel(const Layer* layer, int frame)
|
||||
|
@ -113,7 +113,7 @@ typedef struct UndoAction
|
||||
void (*invert)(UndoStream* stream, UndoChunk* chunk, int state);
|
||||
} UndoAction;
|
||||
|
||||
static void run_undo(Undo* undo, int state, int discard);
|
||||
static void run_undo(Undo* undo, int state, bool discard);
|
||||
static int count_undo_groups(UndoStream* undo_stream);
|
||||
static void update_undo(Undo* undo);
|
||||
|
||||
@ -263,11 +263,13 @@ Undo* undo_new(Sprite *sprite)
|
||||
|
||||
void undo_free(Undo* undo)
|
||||
{
|
||||
assert(undo);
|
||||
delete undo;
|
||||
}
|
||||
|
||||
int undo_get_memsize(Undo* undo)
|
||||
{
|
||||
assert(undo);
|
||||
return
|
||||
undo->undo_stream->size +
|
||||
undo->redo_stream->size;
|
||||
@ -275,44 +277,61 @@ int undo_get_memsize(Undo* undo)
|
||||
|
||||
void undo_enable(Undo* undo)
|
||||
{
|
||||
assert(undo);
|
||||
undo->enabled = TRUE;
|
||||
}
|
||||
|
||||
void undo_disable(Undo* undo)
|
||||
{
|
||||
assert(undo);
|
||||
undo->enabled = FALSE;
|
||||
}
|
||||
|
||||
bool undo_is_enabled(Undo* undo)
|
||||
{
|
||||
assert(undo);
|
||||
return undo->enabled ? TRUE: FALSE;
|
||||
}
|
||||
|
||||
bool undo_is_disabled(Undo* undo)
|
||||
{
|
||||
assert(undo);
|
||||
return !undo_is_enabled(undo);
|
||||
}
|
||||
|
||||
bool undo_can_undo(Undo* undo)
|
||||
{
|
||||
assert(undo);
|
||||
return !jlist_empty(undo->undo_stream->chunks);
|
||||
}
|
||||
|
||||
bool undo_can_redo(Undo* undo)
|
||||
{
|
||||
assert(undo);
|
||||
return !jlist_empty(undo->redo_stream->chunks);
|
||||
}
|
||||
|
||||
void undo_undo(Undo* undo)
|
||||
void undo_do_undo(Undo* undo)
|
||||
{
|
||||
assert(undo);
|
||||
run_undo(undo, DO_UNDO, FALSE);
|
||||
}
|
||||
|
||||
void undo_redo(Undo* undo)
|
||||
void undo_do_redo(Undo* undo)
|
||||
{
|
||||
assert(undo);
|
||||
run_undo(undo, DO_REDO, FALSE);
|
||||
}
|
||||
|
||||
void undo_clear_redo(Undo* undo)
|
||||
{
|
||||
assert(undo);
|
||||
if (!jlist_empty(undo->redo_stream->chunks)) {
|
||||
undo_stream_free(undo->redo_stream);
|
||||
undo->redo_stream = undo_stream_new(undo);
|
||||
}
|
||||
}
|
||||
|
||||
void undo_set_label(Undo* undo, const char *label)
|
||||
{
|
||||
undo->label = label;
|
||||
@ -338,7 +357,7 @@ const char *undo_get_next_redo_label(Undo* undo)
|
||||
return chunk->label;
|
||||
}
|
||||
|
||||
static void run_undo(Undo* undo, int state, int discard_tail)
|
||||
static void run_undo(Undo* undo, int state, bool discard_tail)
|
||||
{
|
||||
UndoStream* undo_stream = ((state == DO_UNDO)? undo->undo_stream:
|
||||
undo->redo_stream);
|
||||
@ -431,10 +450,7 @@ static void update_undo(Undo* undo)
|
||||
undo->diff_count++;
|
||||
|
||||
/* reset the "redo" stream */
|
||||
if (!jlist_empty(undo->redo_stream->chunks)) {
|
||||
undo_stream_free(undo->redo_stream);
|
||||
undo->redo_stream = undo_stream_new(undo);
|
||||
}
|
||||
undo_clear_redo(undo);
|
||||
|
||||
/* "undo" is too big? */
|
||||
while (groups > 1 && undo->undo_stream->size > undo_size_limit) {
|
||||
|
@ -63,8 +63,10 @@ bool undo_is_disabled(Undo* undo);
|
||||
bool undo_can_undo(Undo* undo);
|
||||
bool undo_can_redo(Undo* undo);
|
||||
|
||||
void undo_undo(Undo* undo);
|
||||
void undo_redo(Undo* undo);
|
||||
void undo_do_undo(Undo* undo);
|
||||
void undo_do_redo(Undo* undo);
|
||||
|
||||
void undo_clear_redo(Undo* undo);
|
||||
|
||||
void undo_set_label(Undo* undo, const char *label);
|
||||
const char* undo_get_next_undo_label(Undo* undo);
|
||||
|
450
src/raster/undoable.cpp
Normal file
450
src/raster/undoable.cpp
Normal file
@ -0,0 +1,450 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2008 David A. 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 "config.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "jinete/jlist.h"
|
||||
|
||||
#include "raster/blend.h"
|
||||
#include "raster/cel.h"
|
||||
#include "raster/image.h"
|
||||
#include "raster/layer.h"
|
||||
#include "raster/sprite.h"
|
||||
#include "raster/stock.h"
|
||||
#include "raster/undo.h"
|
||||
#include "raster/undoable.h"
|
||||
|
||||
/**
|
||||
* Starts a undoable sequence of operations.
|
||||
*
|
||||
* All the operations will be grouped in the sprite's undo as an
|
||||
* atomic operation.
|
||||
*/
|
||||
Undoable::Undoable(Sprite* sprite, const char* label)
|
||||
{
|
||||
assert(sprite);
|
||||
assert(label);
|
||||
|
||||
this->sprite = sprite;
|
||||
committed = false;
|
||||
enabled_flag = undo_is_enabled(sprite->undo);
|
||||
|
||||
if (is_enabled()) {
|
||||
undo_set_label(sprite->undo, label);
|
||||
undo_open(sprite->undo);
|
||||
}
|
||||
}
|
||||
|
||||
Undoable::~Undoable()
|
||||
{
|
||||
if (is_enabled()) {
|
||||
// close the undo information
|
||||
undo_close(sprite->undo);
|
||||
|
||||
// if it isn't committed, we have to rollback all changes
|
||||
if (!committed) {
|
||||
// undo the group of operations
|
||||
undo_do_undo(sprite->undo);
|
||||
|
||||
// clear the redo (sorry to the user, here we lost the old redo
|
||||
// information)
|
||||
undo_clear_redo(sprite->undo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be called to commit all the changes, so the undo will be
|
||||
* finally added in the sprite.
|
||||
*
|
||||
* If you don't use this routine, all the changes will be discarded
|
||||
* (if the sprite's undo was enabled when the Undoable was created).
|
||||
*/
|
||||
void Undoable::commit()
|
||||
{
|
||||
committed = true;
|
||||
}
|
||||
|
||||
void Undoable::set_number_of_frames(int frames)
|
||||
{
|
||||
assert(frames >= 1);
|
||||
|
||||
// increment frames counter in the sprite
|
||||
if (is_enabled())
|
||||
undo_set_frames(sprite->undo, sprite);
|
||||
|
||||
sprite_set_frames(sprite, frames);
|
||||
}
|
||||
|
||||
void Undoable::set_current_frame(int frame)
|
||||
{
|
||||
assert(frame >= 0);
|
||||
|
||||
if (is_enabled())
|
||||
undo_int(sprite->undo, sprite, &sprite->frame);
|
||||
|
||||
sprite_set_frame(sprite, frame);
|
||||
}
|
||||
|
||||
void Undoable::set_current_layer(Layer* layer)
|
||||
{
|
||||
assert(layer);
|
||||
|
||||
if (is_enabled())
|
||||
undo_set_layer(sprite->undo, sprite);
|
||||
|
||||
sprite_set_layer(sprite, layer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new image in the stock.
|
||||
*
|
||||
* @return
|
||||
* The image index in the stock.
|
||||
*/
|
||||
int Undoable::add_image_in_stock(Image* image)
|
||||
{
|
||||
assert(image);
|
||||
|
||||
// add the image in the stock
|
||||
int image_index = stock_add_image(sprite->stock, image);
|
||||
|
||||
if (is_enabled())
|
||||
undo_add_image(sprite->undo, sprite->stock, image_index);
|
||||
|
||||
return image_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and destroys the specified image in the stock.
|
||||
*/
|
||||
void Undoable::remove_image_from_stock(int image_index)
|
||||
{
|
||||
assert(image_index >= 0);
|
||||
|
||||
Image* image = stock_get_image(sprite->stock, image_index);
|
||||
assert(image);
|
||||
|
||||
if (is_enabled())
|
||||
undo_remove_image(sprite->undo, sprite->stock, image_index);
|
||||
|
||||
stock_remove_image(sprite->stock, image);
|
||||
image_free(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new transparent layer.
|
||||
*/
|
||||
Layer* Undoable::new_layer()
|
||||
{
|
||||
// new layer
|
||||
Layer* layer = layer_new(sprite);
|
||||
|
||||
// configure layer name and blend mode
|
||||
layer_set_blend_mode(layer, BLEND_MODE_NORMAL);
|
||||
|
||||
// add the layer in the sprite set
|
||||
if (is_enabled())
|
||||
undo_add_layer(sprite->undo, sprite->set, layer);
|
||||
layer_add_layer(sprite->set, layer);
|
||||
|
||||
// select the new layer
|
||||
set_current_layer(layer);
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
void Undoable::move_layer_after(Layer* layer, Layer* after_this)
|
||||
{
|
||||
if (is_enabled())
|
||||
undo_move_layer(sprite->undo, layer);
|
||||
|
||||
layer_move_layer(layer->parent_layer, layer, after_this);
|
||||
}
|
||||
|
||||
void Undoable::new_frame()
|
||||
{
|
||||
// add a new cel to every layer
|
||||
new_frame_for_layer(sprite->set,
|
||||
sprite->frame+1);
|
||||
|
||||
// increment frames counter in the sprite
|
||||
set_number_of_frames(sprite->frames+1);
|
||||
|
||||
// go to next frame (the new one)
|
||||
set_current_frame(sprite->frame+1);
|
||||
}
|
||||
|
||||
void Undoable::new_frame_for_layer(Layer* layer, int frame)
|
||||
{
|
||||
assert(layer);
|
||||
assert(frame >= 0);
|
||||
|
||||
switch (layer->type) {
|
||||
|
||||
case GFXOBJ_LAYER_IMAGE:
|
||||
// displace all cels in '>=frame' to the next frame
|
||||
for (int c=sprite->frames-1; c>=frame; --c) {
|
||||
Cel* cel = layer_get_cel(layer, c);
|
||||
if (cel)
|
||||
set_cel_frame_position(cel, cel->frame+1);
|
||||
}
|
||||
|
||||
copy_previous_frame(layer, frame);
|
||||
break;
|
||||
|
||||
case GFXOBJ_LAYER_SET: {
|
||||
JLink link;
|
||||
JI_LIST_FOR_EACH(layer->layers, link)
|
||||
new_frame_for_layer(reinterpret_cast<Layer*>(link->data), frame);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Undoable::remove_frame(int frame)
|
||||
{
|
||||
assert(frame >= 0);
|
||||
|
||||
// remove cels from this frame (and displace one position backward
|
||||
// all next frames)
|
||||
remove_frame_of_layer(sprite->set, frame);
|
||||
|
||||
/* decrement frames counter in the sprite */
|
||||
if (is_enabled())
|
||||
undo_set_frames(sprite->undo, sprite);
|
||||
|
||||
sprite_set_frames(sprite, sprite->frames-1);
|
||||
|
||||
/* move backward if we are outside the range of frames */
|
||||
if (sprite->frame >= sprite->frames) {
|
||||
if (is_enabled())
|
||||
undo_int(sprite->undo, sprite, &sprite->frame);
|
||||
|
||||
sprite_set_frame(sprite, sprite->frames-1);
|
||||
}
|
||||
}
|
||||
|
||||
void Undoable::remove_frame_of_layer(Layer* layer, int frame)
|
||||
{
|
||||
assert(layer);
|
||||
assert(frame >= 0);
|
||||
|
||||
switch (layer->type) {
|
||||
|
||||
case GFXOBJ_LAYER_IMAGE:
|
||||
if (Cel* cel = layer_get_cel(layer, frame))
|
||||
remove_cel(layer, cel);
|
||||
|
||||
for (++frame; frame<sprite->frames; ++frame)
|
||||
if (Cel* cel = layer_get_cel(layer, frame))
|
||||
set_cel_frame_position(cel, cel->frame-1);
|
||||
break;
|
||||
|
||||
case GFXOBJ_LAYER_SET: {
|
||||
JLink link;
|
||||
JI_LIST_FOR_EACH(layer->layers, link)
|
||||
remove_frame_of_layer(reinterpret_cast<Layer*>(link->data), frame);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the previous cel of @a frame to @frame.
|
||||
*/
|
||||
void Undoable::copy_previous_frame(Layer* layer, int frame)
|
||||
{
|
||||
assert(layer);
|
||||
assert(frame > 0);
|
||||
|
||||
// create a copy of the previous cel
|
||||
Cel* src_cel = layer_get_cel(layer, frame-1);
|
||||
Image* src_image = src_cel ? stock_get_image(sprite->stock,
|
||||
src_cel->image):
|
||||
NULL;
|
||||
|
||||
// nothing to copy, it will be a transparent cel
|
||||
if (!src_image)
|
||||
return;
|
||||
|
||||
// copy the image
|
||||
Image* dst_image = image_new_copy(src_image);
|
||||
int image_index = add_image_in_stock(dst_image);
|
||||
|
||||
// create the new cel
|
||||
Cel* dst_cel = cel_new(frame, image_index);
|
||||
if (src_cel) { // copy the data from the previous cel
|
||||
cel_set_position(dst_cel, src_cel->x, src_cel->y);
|
||||
cel_set_opacity(dst_cel, src_cel->opacity);
|
||||
}
|
||||
|
||||
// add the cel in the layer
|
||||
add_cel(layer, dst_cel);
|
||||
}
|
||||
|
||||
void Undoable::add_cel(Layer* layer, Cel* cel)
|
||||
{
|
||||
assert(layer);
|
||||
assert(cel);
|
||||
assert(layer_is_image(layer));
|
||||
|
||||
if (is_enabled())
|
||||
undo_add_cel(sprite->undo, layer, cel);
|
||||
|
||||
layer_add_cel(layer, cel);
|
||||
}
|
||||
|
||||
void Undoable::remove_cel(Layer* layer, Cel* cel)
|
||||
{
|
||||
assert(layer);
|
||||
assert(cel);
|
||||
assert(layer_is_image(layer));
|
||||
|
||||
// find if the image that use the cel to remove, is used by
|
||||
// another cels
|
||||
bool used = false;
|
||||
for (int frame=0; frame<sprite->frames; ++frame) {
|
||||
Cel* it = layer_get_cel(layer, frame);
|
||||
if (it && it != cel && it->image == cel->image) {
|
||||
used = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if the image is only used by this cel,
|
||||
// we can remove the image from the stock
|
||||
if (!used)
|
||||
remove_image_from_stock(cel->image);
|
||||
|
||||
if (is_enabled())
|
||||
undo_remove_cel(sprite->undo, layer, cel);
|
||||
|
||||
// remove the cel from the layer
|
||||
layer_remove_cel(layer, cel);
|
||||
|
||||
// and here we destroy the cel
|
||||
cel_free(cel);
|
||||
}
|
||||
|
||||
void Undoable::set_cel_frame_position(Cel* cel, int frame)
|
||||
{
|
||||
assert(cel);
|
||||
assert(frame >= 0);
|
||||
|
||||
if (is_enabled())
|
||||
undo_int(sprite->undo, cel, &cel->frame);
|
||||
|
||||
cel->frame = frame;
|
||||
}
|
||||
|
||||
void Undoable::set_frame_length(int frame, int msecs)
|
||||
{
|
||||
if (is_enabled())
|
||||
undo_set_frlen(sprite->undo, sprite, frame);
|
||||
|
||||
sprite_set_frlen(sprite, frame, msecs);
|
||||
}
|
||||
|
||||
void Undoable::move_frame_before(int frame, int before_frame)
|
||||
{
|
||||
if (frame != before_frame &&
|
||||
frame >= 0 &&
|
||||
frame < sprite->frames &&
|
||||
before_frame >= 0 &&
|
||||
before_frame < sprite->frames) {
|
||||
// change the frame-lengths...
|
||||
|
||||
int frlen_aux = sprite->frlens[frame];
|
||||
|
||||
// moving the frame to the future
|
||||
if (frame < before_frame) {
|
||||
frlen_aux = sprite->frlens[frame];
|
||||
|
||||
for (int c=frame; c<before_frame-1; c++)
|
||||
set_frame_length(c, sprite->frlens[c+1]);
|
||||
|
||||
set_frame_length(before_frame-1, frlen_aux);
|
||||
}
|
||||
// moving the frame to the past
|
||||
else if (before_frame < frame) {
|
||||
frlen_aux = sprite->frlens[frame];
|
||||
|
||||
for (int c=frame; c>before_frame; c--)
|
||||
set_frame_length(c, sprite->frlens[c-1]);
|
||||
|
||||
set_frame_length(before_frame, frlen_aux);
|
||||
}
|
||||
|
||||
// change the cels of position...
|
||||
move_frame_before_layer(sprite->set, frame, before_frame);
|
||||
}
|
||||
}
|
||||
|
||||
void Undoable::move_frame_before_layer(Layer* layer, int frame, int before_frame)
|
||||
{
|
||||
assert(layer);
|
||||
|
||||
switch (layer->type) {
|
||||
|
||||
case GFXOBJ_LAYER_IMAGE: {
|
||||
JLink link;
|
||||
JI_LIST_FOR_EACH(layer->cels, link) {
|
||||
Cel* cel = reinterpret_cast<Cel*>(link->data);
|
||||
int new_frame = cel->frame;
|
||||
|
||||
// moving the frame to the future
|
||||
if (frame < before_frame) {
|
||||
if (cel->frame == frame) {
|
||||
new_frame = before_frame-1;
|
||||
}
|
||||
else if (cel->frame > frame &&
|
||||
cel->frame < before_frame) {
|
||||
new_frame--;
|
||||
}
|
||||
}
|
||||
// moving the frame to the past
|
||||
else if (before_frame < frame) {
|
||||
if (cel->frame == frame) {
|
||||
new_frame = before_frame;
|
||||
}
|
||||
else if (cel->frame >= before_frame &&
|
||||
cel->frame < frame) {
|
||||
new_frame++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cel->frame != new_frame)
|
||||
set_cel_frame_position(cel, new_frame);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GFXOBJ_LAYER_SET: {
|
||||
JLink link;
|
||||
JI_LIST_FOR_EACH(layer->layers, link)
|
||||
move_frame_before_layer(reinterpret_cast<Layer*>(link->data), frame, before_frame);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
76
src/raster/undoable.h
Normal file
76
src/raster/undoable.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2008 David A. 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 RASTER_UNDOABLE_H
|
||||
#define RASTER_UNDOABLE_H
|
||||
|
||||
class Layer;
|
||||
class Sprite;
|
||||
|
||||
/**
|
||||
* Class with high-level set of routines to modify a sprite.
|
||||
*
|
||||
* In this class, all modifications in the sprite have an undo
|
||||
* counterpart (if the sprite's undo is enabled).
|
||||
*/
|
||||
class Undoable
|
||||
{
|
||||
Sprite* sprite;
|
||||
bool committed;
|
||||
bool enabled_flag;
|
||||
|
||||
public:
|
||||
Undoable(Sprite* sprite, const char* label);
|
||||
virtual ~Undoable();
|
||||
|
||||
inline Sprite* get_sprite() const { return sprite; }
|
||||
inline bool is_enabled() const { return enabled_flag; }
|
||||
|
||||
void commit();
|
||||
|
||||
// for sprite
|
||||
void set_number_of_frames(int frames);
|
||||
void set_current_frame(int frame);
|
||||
void set_current_layer(Layer* layer);
|
||||
|
||||
// for images in stock
|
||||
int add_image_in_stock(Image* image);
|
||||
void remove_image_from_stock(int image_index);
|
||||
|
||||
// for layers
|
||||
Layer* new_layer();
|
||||
void move_layer_after(Layer *layer, Layer *after_this);
|
||||
|
||||
// for frames
|
||||
void new_frame();
|
||||
void new_frame_for_layer(Layer* layer, int frame);
|
||||
void remove_frame(int frame);
|
||||
void remove_frame_of_layer(Layer* layer, int frame);
|
||||
void copy_previous_frame(Layer* layer, int frame);
|
||||
void set_frame_length(int frame, int msecs);
|
||||
void move_frame_before(int frame, int before_frame);
|
||||
void move_frame_before_layer(Layer* layer, int frame, int before_frame);
|
||||
|
||||
// for cels
|
||||
void add_cel(Layer* layer, Cel* cel);
|
||||
void remove_cel(Layer* layer, Cel* cel);
|
||||
void set_cel_frame_position(Cel* cel, int frame);
|
||||
|
||||
};
|
||||
|
||||
#endif /* RASTER_UNDOABLE_H */
|
@ -55,7 +55,7 @@ void test_init()
|
||||
|
||||
int test_exit()
|
||||
{
|
||||
trace("OK\n");
|
||||
allegro_exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -74,8 +74,6 @@ JWidget test_init_gui()
|
||||
|
||||
int test_exit_gui(JWidget manager)
|
||||
{
|
||||
trace("OK\n");
|
||||
|
||||
jmanager_free(manager);
|
||||
allegro_exit();
|
||||
return 0;
|
||||
|
@ -220,45 +220,6 @@ static void displace_layers(Undo *undo, Layer *layer, int x, int y)
|
||||
|
||||
static int get_max_layer_num(Layer *layer);
|
||||
|
||||
/**
|
||||
* Creates a new transparent layer.
|
||||
*/
|
||||
Layer *NewLayer(Sprite *sprite)
|
||||
{
|
||||
Layer *layer;
|
||||
|
||||
if (sprite == NULL) {
|
||||
console_printf("NewLayer: No current sprite\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* new layer */
|
||||
layer = layer_new(sprite);
|
||||
if (!layer) {
|
||||
console_printf("NewLayer: Not enough memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* configure layer name and blend mode */
|
||||
layer_set_blend_mode(layer, BLEND_MODE_NORMAL);
|
||||
|
||||
/* undo stuff */
|
||||
if (undo_is_enabled(sprite->undo)) {
|
||||
undo_open(sprite->undo);
|
||||
undo_add_layer(sprite->undo, sprite->set, layer);
|
||||
undo_set_layer(sprite->undo, sprite);
|
||||
undo_close(sprite->undo);
|
||||
}
|
||||
|
||||
/* add the layer in the sprite set */
|
||||
layer_add_layer(sprite->set, layer);
|
||||
|
||||
/* select the new layer */
|
||||
sprite_set_layer(sprite, layer);
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new layer set with the "name" in the current sprite
|
||||
*/
|
||||
@ -684,14 +645,6 @@ void LayerFromBackground(Sprite *sprite)
|
||||
layer_set_name(sprite->layer, "Layer 0");
|
||||
}
|
||||
|
||||
void MoveLayerAfter(Layer *layer, Layer *after_this)
|
||||
{
|
||||
if (undo_is_enabled(layer->sprite->undo))
|
||||
undo_move_layer(layer->sprite->undo, layer);
|
||||
|
||||
layer_move_layer(layer->parent_layer, layer, after_this);
|
||||
}
|
||||
|
||||
/* internal routine */
|
||||
static int get_max_layer_num(Layer *layer)
|
||||
{
|
||||
@ -711,289 +664,6 @@ static int get_max_layer_num(Layer *layer)
|
||||
return max;
|
||||
}
|
||||
|
||||
/* ======================================= */
|
||||
/* Frame */
|
||||
/* ======================================= */
|
||||
|
||||
static bool new_frame_for_layer(Sprite *sprite, Layer *layer, int frame);
|
||||
static bool copy_cel_in_next_frame(Sprite *sprite, Layer *layer, int frame);
|
||||
static void remove_frame_for_layer(Sprite *sprite, Layer *layer, int frame);
|
||||
static void move_frame_before_layer(Undo *undo, Layer *layer, int frame, int before_frame);
|
||||
|
||||
void NewFrame(Sprite *sprite)
|
||||
{
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_open(sprite->undo);
|
||||
|
||||
/* add a new cel to every layer */
|
||||
new_frame_for_layer(sprite,
|
||||
sprite->set,
|
||||
sprite->frame+1);
|
||||
|
||||
/* increment frames counter in the sprite */
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_set_frames(sprite->undo, sprite);
|
||||
sprite_set_frames(sprite, sprite->frames+1);
|
||||
|
||||
/* go to next frame (the new one) */
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_int(sprite->undo, sprite, &sprite->frame);
|
||||
sprite_set_frame(sprite, sprite->frame+1);
|
||||
|
||||
/* close undo & refresh the screen */
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_close(sprite->undo);
|
||||
}
|
||||
|
||||
void RemoveFrame(Sprite *sprite, int frame)
|
||||
{
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_open(sprite->undo);
|
||||
|
||||
/* remove cels from this frame (and displace one position backward
|
||||
all next frames) */
|
||||
remove_frame_for_layer(sprite, sprite->set, frame);
|
||||
|
||||
/* decrement frames counter in the sprite */
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_set_frames(sprite->undo, sprite);
|
||||
|
||||
sprite_set_frames(sprite, sprite->frames-1);
|
||||
|
||||
/* move backward if we are outside the range of frames */
|
||||
if (sprite->frame >= sprite->frames) {
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_int(sprite->undo, sprite, &sprite->frame);
|
||||
|
||||
sprite_set_frame(sprite, sprite->frames-1);
|
||||
}
|
||||
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_close(sprite->undo);
|
||||
}
|
||||
|
||||
void SetFrameLength(Sprite *sprite, int frame, int msecs)
|
||||
{
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_set_frlen(sprite->undo, sprite, frame);
|
||||
|
||||
sprite_set_frlen(sprite, frame, msecs);
|
||||
}
|
||||
|
||||
void MoveFrameBefore(int frame, int before_frame)
|
||||
{
|
||||
Sprite *sprite = current_sprite;
|
||||
int c, frlen_aux;
|
||||
|
||||
if (sprite &&
|
||||
frame != before_frame &&
|
||||
frame >= 0 &&
|
||||
frame < sprite->frames &&
|
||||
before_frame >= 0 &&
|
||||
before_frame < sprite->frames) {
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_open(sprite->undo);
|
||||
|
||||
/* Change the frame-lengths... */
|
||||
|
||||
frlen_aux = sprite->frlens[frame];
|
||||
|
||||
/* moving the frame to the future */
|
||||
if (frame < before_frame) {
|
||||
frlen_aux = sprite->frlens[frame];
|
||||
|
||||
for (c=frame; c<before_frame-1; c++)
|
||||
SetFrameLength(sprite, c, sprite->frlens[c+1]);
|
||||
|
||||
SetFrameLength(sprite, before_frame-1, frlen_aux);
|
||||
}
|
||||
/* moving the frame to the past */
|
||||
else if (before_frame < frame) {
|
||||
frlen_aux = sprite->frlens[frame];
|
||||
|
||||
for (c=frame; c>before_frame; c--)
|
||||
SetFrameLength(sprite, c, sprite->frlens[c-1]);
|
||||
|
||||
SetFrameLength(sprite, before_frame, frlen_aux);
|
||||
}
|
||||
|
||||
/* Change the cels of position... */
|
||||
move_frame_before_layer(sprite->undo, sprite->set, frame, before_frame);
|
||||
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_close(sprite->undo);
|
||||
}
|
||||
}
|
||||
|
||||
static bool new_frame_for_layer(Sprite *sprite, Layer *layer, int frame)
|
||||
{
|
||||
switch (layer->type) {
|
||||
|
||||
case GFXOBJ_LAYER_IMAGE: {
|
||||
Cel *cel;
|
||||
int c;
|
||||
|
||||
for (c=sprite->frames-1; c>=frame; --c) {
|
||||
cel = layer_get_cel(layer, c);
|
||||
if (cel) {
|
||||
undo_int(sprite->undo, cel, &cel->frame);
|
||||
cel->frame++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!copy_cel_in_next_frame(sprite, layer, frame))
|
||||
return FALSE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GFXOBJ_LAYER_SET: {
|
||||
JLink link;
|
||||
JI_LIST_FOR_EACH(layer->layers, link) {
|
||||
if (!new_frame_for_layer(sprite, reinterpret_cast<Layer*>(link->data), frame))
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* makes a copy of the cel in 'frame-1' to a new cel in 'frame' */
|
||||
static bool copy_cel_in_next_frame(Sprite *sprite, Layer *layer, int frame)
|
||||
{
|
||||
int image_index;
|
||||
Image *src_image;
|
||||
Image *dst_image;
|
||||
Cel *src_cel;
|
||||
Cel *dst_cel;
|
||||
|
||||
assert(frame > 0);
|
||||
|
||||
/* create a copy of the previous cel */
|
||||
src_cel = layer_get_cel(layer, frame-1);
|
||||
src_image = src_cel ? stock_get_image(sprite->stock,
|
||||
src_cel->image):
|
||||
NULL;
|
||||
|
||||
if (src_image == NULL) {
|
||||
/* do nothing, it will be a transparent cel */
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
dst_image = image_new_copy(src_image);
|
||||
|
||||
if (!dst_image) {
|
||||
console_printf(_("Not enough memory.\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* add the image in the stock */
|
||||
image_index = stock_add_image(sprite->stock, dst_image);
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_add_image(sprite->undo, sprite->stock, image_index);
|
||||
|
||||
/* create the new cel */
|
||||
dst_cel = cel_new(frame, image_index);
|
||||
|
||||
if (src_cel != NULL) {
|
||||
cel_set_position(dst_cel, src_cel->x, src_cel->y);
|
||||
cel_set_opacity(dst_cel, src_cel->opacity);
|
||||
}
|
||||
|
||||
/* add the cel in the layer */
|
||||
if (undo_is_enabled(sprite->undo))
|
||||
undo_add_cel(sprite->undo, layer, dst_cel);
|
||||
layer_add_cel(layer, dst_cel);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void remove_frame_for_layer(Sprite *sprite, Layer *layer, int frame)
|
||||
{
|
||||
switch (layer->type) {
|
||||
|
||||
case GFXOBJ_LAYER_IMAGE: {
|
||||
Cel *cel = layer_get_cel(layer, frame);
|
||||
if (cel)
|
||||
RemoveCel(layer, cel);
|
||||
|
||||
for (++frame; frame<sprite->frames; ++frame) {
|
||||
cel = layer_get_cel(layer, frame);
|
||||
if (cel) {
|
||||
undo_int(sprite->undo, cel, &cel->frame);
|
||||
cel->frame--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GFXOBJ_LAYER_SET: {
|
||||
JLink link;
|
||||
JI_LIST_FOR_EACH(layer->layers, link)
|
||||
remove_frame_for_layer(sprite, reinterpret_cast<Layer*>(link->data), frame);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void move_frame_before_layer(Undo *undo, Layer *layer, int frame, int before_frame)
|
||||
{
|
||||
switch (layer->type) {
|
||||
|
||||
case GFXOBJ_LAYER_IMAGE: {
|
||||
Cel *cel;
|
||||
JLink link;
|
||||
int new_frame;
|
||||
|
||||
JI_LIST_FOR_EACH(layer->cels, link) {
|
||||
cel = reinterpret_cast<Cel*>(link->data);
|
||||
new_frame = cel->frame;
|
||||
|
||||
/* moving the frame to the future */
|
||||
if (frame < before_frame) {
|
||||
if (cel->frame == frame) {
|
||||
new_frame = before_frame-1;
|
||||
}
|
||||
else if (cel->frame > frame &&
|
||||
cel->frame < before_frame) {
|
||||
new_frame--;
|
||||
}
|
||||
}
|
||||
/* moving the frame to the past */
|
||||
else if (before_frame < frame) {
|
||||
if (cel->frame == frame) {
|
||||
new_frame = before_frame;
|
||||
}
|
||||
else if (cel->frame >= before_frame &&
|
||||
cel->frame < frame) {
|
||||
new_frame++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cel->frame != new_frame) {
|
||||
if (undo_is_enabled(undo))
|
||||
undo_int(undo, (GfxObj *)cel, &cel->frame);
|
||||
|
||||
cel->frame = new_frame;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GFXOBJ_LAYER_SET: {
|
||||
JLink link;
|
||||
JI_LIST_FOR_EACH(layer->layers, link)
|
||||
move_frame_before_layer(undo, reinterpret_cast<Layer*>(link->data), frame, before_frame);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ======================================= */
|
||||
/* Cel */
|
||||
/* ======================================= */
|
||||
|
@ -39,7 +39,6 @@ void CropSprite(Sprite* sprite);
|
||||
/* Layer */
|
||||
/*===================================================================*/
|
||||
|
||||
Layer* NewLayer(Sprite* sprite);
|
||||
Layer* NewLayerSet(Sprite* sprite);
|
||||
void RemoveLayer(Sprite* sprite);
|
||||
|
||||
@ -52,17 +51,6 @@ void CropLayer(Layer* layer, int x, int y, int w, int h);
|
||||
void BackgroundFromLayer(Sprite* sprite);
|
||||
void LayerFromBackground(Sprite* sprite);
|
||||
|
||||
void MoveLayerAfter(Layer* layer, Layer* after_this);
|
||||
|
||||
/* ======================================= */
|
||||
/* Frame */
|
||||
/* ======================================= */
|
||||
|
||||
void NewFrame(Sprite* sprite);
|
||||
void RemoveFrame(Sprite* sprite, int frame);
|
||||
void SetFrameLength(Sprite* sprite, int frame, int msecs);
|
||||
void MoveFrameBefore(int frame, int before_frame);
|
||||
|
||||
/* ======================================= */
|
||||
/* Cel */
|
||||
/* ======================================= */
|
||||
|
Loading…
x
Reference in New Issue
Block a user