diff --git a/ChangeLog b/ChangeLog index 7ebff9d59..6f5b47693 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2008-03-29 David A. Capello + + * src/file/jpeg_format.c (getdata_JPEG): Added from configure_jpeg. + + * src/file/filedata.h (JpegData): Added. + + * src/file/file.h (FileFormat): Added the `getdata' method to + configure the output format. + +2008-03-28 David A. Capello + + * src/commands/cmd_save_file.c (save_sprite_in_background): Added + to save sprites with progress bar. + + * src/commands/fx/effectbg.c (effect_apply_to_target_with_progressbar): + Added to show progress bar and background processing when the user + applies an effect. + + * src/effect/effect.h (Effect): Added progress information to + customize the progress and cancellation of the effect operations. + + * src/file/fli_format.c (load_FLI), + src/file/gif_format.c (load_GIF): Now these two routines + configure the only layer as `Background'. + + * src/file/file.h (FileOp): Added seq.has_alpha so a PNG file with + alpha hasn't a `Background' layer. + 2008-03-27 David A. Capello * Added a call to undo_set_label(...) for every undo operation in diff --git a/TODO.txt b/TODO.txt index 2b2fa184d..c641ec4cf 100644 --- a/TODO.txt +++ b/TODO.txt @@ -8,6 +8,7 @@ Next beta + quick_move + quick_copy + quick_swap +- search for "TODO remove me" - add the progress bar for effects and save-file. - fix colors - tooltips for color-bar. diff --git a/data/gui-en.xml b/data/gui-en.xml index 2bf01165e..19d4667b4 100644 --- a/data/gui-en.xml +++ b/data/gui-en.xml @@ -204,7 +204,7 @@ - + diff --git a/makefile.lst b/makefile.lst index 4ee11ddfd..4deab3782 100644 --- a/makefile.lst +++ b/makefile.lst @@ -62,7 +62,6 @@ COMMON_SOURCES = \ src/commands/cmd_reselect_mask.c \ src/commands/cmd_run_script.c \ src/commands/cmd_save_file.c \ - src/commands/cmd_save_file_as.c \ src/commands/cmd_save_mask.c \ src/commands/cmd_screen_shot.c \ src/commands/cmd_select_file.c \ @@ -77,6 +76,7 @@ COMMON_SOURCES = \ src/commands/fx/cmd_despeckle.c \ src/commands/fx/cmd_invert_color.c \ src/commands/fx/cmd_replace_color.c \ + src/commands/fx/effectbg.c \ src/console/console.c \ src/core/app.c \ src/core/cfg.c \ diff --git a/src/commands/cmd_open_file.c b/src/commands/cmd_open_file.c index f051a3deb..1e58f0ed4 100644 --- a/src/commands/cmd_open_file.c +++ b/src/commands/cmd_open_file.c @@ -177,7 +177,7 @@ static void cmd_open_file_execute(const char *argument) } } } - /* else do nothing (the user canceled or something like that) */ + /* else do nothing (the user cancelled or something like that) */ } } diff --git a/src/commands/cmd_save_file.c b/src/commands/cmd_save_file.c index 127d0776e..ced61126b 100644 --- a/src/commands/cmd_save_file.c +++ b/src/commands/cmd_save_file.c @@ -20,40 +20,153 @@ #include -#include "jinete/jbase.h" +#include "jinete/jinete.h" #include "commands/commands.h" #include "core/app.h" #include "console/console.h" +#include "dialogs/filesel.h" #include "file/file.h" +#include "modules/gui.h" #include "modules/recent.h" #include "modules/sprites.h" #include "raster/sprite.h" #include "widgets/statebar.h" +typedef struct SaveFileData +{ + Monitor *monitor; + FileOp *fop; + Progress *progress; + JThread thread; + JWidget alert_window; +} SaveFileData; + +/** + * Thread to do the hard work: save the file to the disk. + * + * [saving thread] + */ +static void savefile_bg(void *fop_data) +{ + FileOp *fop = (FileOp *)fop_data; + fop_operate(fop); + fop_done(fop); +} + +/** + * Called by the gui-monitor (a timer in the gui module that is called + * every 100 milliseconds). + * + * [main thread] + */ +static void monitor_savefile_bg(void *_data) +{ + SaveFileData *data = (SaveFileData *)_data; + FileOp *fop = (FileOp *)data->fop; + + if (data->progress) + progress_update(data->progress, fop_get_progress(fop)); + + if (fop_is_done(fop)) + remove_gui_monitor(data->monitor); +} + +/** + * Called when the monitor is destroyed. + * + * [main thread] + */ +static void monitor_free(void *_data) +{ + SaveFileData *data = (SaveFileData *)_data; + + if (data->alert_window != NULL) { + data->monitor = NULL; + jwindow_close(data->alert_window, NULL); + } +} + +static void save_sprite_in_background(Sprite *sprite) +{ + FileOp *fop = fop_to_save_sprite(sprite); + if (fop) { + JThread thread = jthread_new(savefile_bg, fop); + if (thread) { + SaveFileData *data = jnew(SaveFileData, 1); + + data->fop = fop; + data->progress = progress_new(app_get_statusbar()); + data->thread = thread; + data->alert_window = jalert_new(PACKAGE + "<filename)); + data->monitor = NULL; + + /* add a monitor to check the saving (FileOp) progress */ + data->monitor = add_gui_monitor(monitor_savefile_bg, + monitor_free, data); + + /* TODO error handling */ + + jwindow_open_fg(data->alert_window); + + if (data->monitor != NULL) + remove_gui_monitor(data->monitor); + + /* wait the `savefile_bg' thread */ + jthread_join(data->thread); + + /* show any error */ + if (fop->error) { + console_open(); + console_printf(fop->error); + console_close(); + } + /* no error? */ + else { + recent_file(sprite->filename); + sprite_mark_as_saved(sprite); + statusbar_set_text(app_get_statusbar(), + 2000, "File %s, saved.", + get_filename(sprite->filename)); + } + + progress_free(data->progress); + jwidget_free(data->alert_window); + fop_free(fop); + jfree(data); + } + } +} + +/********************************************************************* + Save File + *********************************************************************/ + +/** + * Returns true if there is a current sprite to save. + * + * [main thread] + */ static bool cmd_save_file_enabled(const char *argument) { return current_sprite != NULL; } +/** + * Saves the current sprite in a file. + * + * [main thread] + */ static void cmd_save_file_execute(const char *argument) { + Sprite *sprite = current_sprite; + /* if the sprite is associated to a file in the file-system, we can save it directly without user interaction */ - if (sprite_is_associated_to_file(current_sprite)) { - if (sprite_save(current_sprite) == 0) { - recent_file(current_sprite->filename); - sprite_mark_as_saved(current_sprite); - - if (app_get_statusbar()) - statusbar_set_text(app_get_statusbar(), - 1000, "File %s, saved.", - get_filename(current_sprite->filename)); - } - else { - /* TODO if the user cancel we shouldn't unrecent the file */ - unrecent_file(current_sprite->filename); - } + if (sprite_is_associated_to_file(sprite)) { + save_sprite_in_background(sprite); } /* if the sprite isn't associated to a file, we must to show the save-as dialog to the user to select for first time the file-name @@ -63,6 +176,64 @@ static void cmd_save_file_execute(const char *argument) } } +/********************************************************************* + Save File As + *********************************************************************/ + +static bool cmd_save_file_as_enabled(const char *argument) +{ + return current_sprite != NULL; +} + +static void cmd_save_file_as_execute(const char *argument) +{ + Sprite *sprite = current_sprite; + char filename[4096]; + char exts[4096]; + char *newfilename; + int ret; + + ustrcpy(filename, sprite->filename); + get_writable_extensions(exts, sizeof(exts)); + + for (;;) { + newfilename = ase_file_selector(_("Save Sprite"), filename, exts); + if (!newfilename) + return; + ustrcpy(filename, newfilename); + jfree(newfilename); + + /* does the file exist? */ + if (exists(filename)) { + /* ask if the user wants overwrite the file? */ + ret = jalert("%s<<%s<<%s||%s||%s||%s", + _("Warning"), + _("File exists, overwrite it?"), + get_filename(filename), + _("&Yes"), _("&No"), _("&Cancel")); + } + else + break; + + /* "yes": we must continue with the operation... */ + if (ret == 1) + break; + /* "cancel" or per example: we back doing nothing */ + else if (ret != 2) + return; + + /* "no": we must back to select other file-name */ + } + + sprite_set_filename(sprite, filename); + app_realloc_sprite_list(); + + save_sprite_in_background(sprite); +} + +/** + * Command to save the current sprite in its associated file. + */ Command cmd_save_file = { CMD_SAVE_FILE, cmd_save_file_enabled, @@ -70,3 +241,14 @@ Command cmd_save_file = { cmd_save_file_execute, NULL }; + +/** + * Command to save the current sprite in another file. + */ +Command cmd_save_file_as = { + CMD_SAVE_FILE_AS, + cmd_save_file_as_enabled, + NULL, + cmd_save_file_as_execute, + NULL +}; diff --git a/src/commands/cmd_save_file_as.c b/src/commands/cmd_save_file_as.c deleted file mode 100644 index 8609e1f3e..000000000 --- a/src/commands/cmd_save_file_as.c +++ /dev/null @@ -1,98 +0,0 @@ -/* 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 - -#include "jinete/jalert.h" - -#include "commands/commands.h" -#include "console/console.h" -#include "core/app.h" -#include "dialogs/filesel.h" -#include "file/file.h" -#include "modules/recent.h" -#include "modules/gui.h" -#include "modules/sprites.h" -#include "raster/sprite.h" - -static bool cmd_save_file_as_enabled(const char *argument) -{ - return current_sprite != NULL; -} - -static void cmd_save_file_as_execute(const char *argument) -{ - char filename[4096]; - char exts[4096]; - char *newfilename; - int ret; - - ustrcpy(filename, current_sprite->filename); - get_writable_extensions(exts, sizeof(exts)); - - for (;;) { - newfilename = ase_file_selector(_("Save Sprite"), filename, exts); - if (!newfilename) - return; - ustrcpy(filename, newfilename); - jfree(newfilename); - - /* does the file exist? */ - if (exists(filename)) { - /* ask if the user wants overwrite the file? */ - ret = jalert("%s<<%s<<%s||%s||%s||%s", - _("Warning"), - _("File exists, overwrite it?"), - get_filename(filename), - _("&Yes"), _("&No"), _("&Cancel")); - } - else - break; - - /* "yes": we must continue with the operation... */ - if (ret == 1) - break; - /* "cancel" or per example: we back doing nothing */ - else if (ret != 2) - return; - - /* "no": we must back to select other file-name */ - } - - sprite_set_filename(current_sprite, filename); - app_realloc_sprite_list(); - - if (sprite_save(current_sprite) == 0) { - recent_file(filename); - sprite_mark_as_saved(current_sprite); - } - else { - /* TODO if the user cancel we shouldn't unrecent the file */ - unrecent_file(filename); - } -} - -Command cmd_save_file_as = { - CMD_SAVE_FILE_AS, - cmd_save_file_as_enabled, - NULL, - cmd_save_file_as_execute, - NULL -}; diff --git a/src/commands/fx/cmd_color_curve.c b/src/commands/fx/cmd_color_curve.c index db406c170..0daeeafe5 100644 --- a/src/commands/fx/cmd_color_curve.c +++ b/src/commands/fx/cmd_color_curve.c @@ -21,6 +21,7 @@ #include "jinete/jinete.h" #include "commands/commands.h" +#include "commands/fx/effectbg.h" #include "console/console.h" #include "core/app.h" #include "core/cfg.h" @@ -124,7 +125,7 @@ static void cmd_color_curve_execute(const char *argument) jwindow_open_fg(window); if (jwindow_get_killer(window) == button_ok) { - effect_apply_to_target(effect); + effect_apply_to_target_with_progressbar(effect); } effect_free(effect); diff --git a/src/commands/fx/cmd_convolution_matrix.c b/src/commands/fx/cmd_convolution_matrix.c index cfa51d25d..49b5062e7 100644 --- a/src/commands/fx/cmd_convolution_matrix.c +++ b/src/commands/fx/cmd_convolution_matrix.c @@ -32,6 +32,7 @@ #include "jinete/jwindow.h" #include "commands/commands.h" +#include "commands/fx/effectbg.h" #include "console/console.h" #include "core/cfg.h" #include "core/color.h" @@ -149,7 +150,7 @@ static void cmd_convolution_matrix_execute(const char *argument) jwindow_open_fg(window); if (jwindow_get_killer(window) == button_ok) { - effect_apply_to_target(effect); + effect_apply_to_target_with_progressbar(effect); } effect_free(effect); diff --git a/src/commands/fx/cmd_despeckle.c b/src/commands/fx/cmd_despeckle.c index c9d857bb9..0b97bb9fd 100644 --- a/src/commands/fx/cmd_despeckle.c +++ b/src/commands/fx/cmd_despeckle.c @@ -28,6 +28,7 @@ #include "jinete/jwindow.h" #include "commands/commands.h" +#include "commands/fx/effectbg.h" #include "console/console.h" #include "core/cfg.h" #include "core/core.h" @@ -130,7 +131,7 @@ static void cmd_despeckle_execute(const char *argument) jwindow_open_fg(window); if (jwindow_get_killer(window) == button_ok) { - effect_apply_to_target(effect); + effect_apply_to_target_with_progressbar(effect); } effect_free(effect); diff --git a/src/commands/fx/cmd_invert_color.c b/src/commands/fx/cmd_invert_color.c index a0a57718a..08f72a936 100644 --- a/src/commands/fx/cmd_invert_color.c +++ b/src/commands/fx/cmd_invert_color.c @@ -27,6 +27,7 @@ #include "jinete/jwindow.h" #include "commands/commands.h" +#include "commands/fx/effectbg.h" #include "console/console.h" #include "core/cfg.h" #include "core/color.h" @@ -109,7 +110,7 @@ static void cmd_invert_color_execute(const char *argument) jwindow_open_fg(window); if (jwindow_get_killer(window) == button_ok) { - effect_apply_to_target(effect); + effect_apply_to_target_with_progressbar(effect); } effect_free(effect); diff --git a/src/commands/fx/cmd_replace_color.c b/src/commands/fx/cmd_replace_color.c index abcebe45c..58abf8c4d 100644 --- a/src/commands/fx/cmd_replace_color.c +++ b/src/commands/fx/cmd_replace_color.c @@ -23,6 +23,7 @@ #include "jinete/jinete.h" #include "commands/commands.h" +#include "commands/fx/effectbg.h" #include "console/console.h" #include "core/app.h" #include "core/cfg.h" @@ -137,7 +138,7 @@ static void cmd_replace_color_execute(const char *argument) jwindow_open_fg(window); if (jwindow_get_killer(window) == button_ok) { - effect_apply_to_target(effect); + effect_apply_to_target_with_progressbar(effect); } effect_free(effect); diff --git a/src/commands/fx/effectbg.c b/src/commands/fx/effectbg.c new file mode 100644 index 000000000..24b8a45bd --- /dev/null +++ b/src/commands/fx/effectbg.c @@ -0,0 +1,193 @@ +/* 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 +#include + +#include "jinete/jinete.h" + +#include "core/app.h" +#include "core/cfg.h" +#include "effect/effect.h" +#include "modules/editors.h" +#include "modules/gui.h" +#include "modules/sprites.h" +#include "raster/sprite.h" +#include "widgets/editor.h" +#include "widgets/statebar.h" + +/********************************************************************** + Apply effect in two threads: bg-thread to modify the sprite, and the + main thread to monitoring the progress. + **********************************************************************/ + +typedef struct ThreadData +{ + Effect *effect; /* effect to be applied */ + JMutex mutex; /* mutex to access to 'pos', 'done' + and 'cancelled' fields in different + threads */ + float pos; /* current progress position */ + bool done; /* was the effect completelly applied? */ + bool cancelled; /* was the effect cancelled by the user? */ + Monitor *monitor; /* monitor to update the progress-bar */ + Progress *progress; /* the progress-bar */ + JThread thread; /* thread to apply the effect in background */ + JWidget alert_window; /* alert for the user to cancel the + effect-progress if he wants */ +} ThreadData; + +/** + * Called by @ref effect_apply to informate the progress of the + * effect. + * + * [effect thread] + */ +static void effect_progress_hook(void *_data, float progress) +{ + ThreadData *data = (ThreadData *)_data; + + jmutex_lock(data->mutex); + data->pos = progress; + jmutex_unlock(data->mutex); +} + +/** + * Called by @ref effect_apply to know if the user cancelled the + * operation. + * + * [effect thread] + */ +static bool effect_is_cancelled_hook(void *_data) +{ + ThreadData *data = (ThreadData *)_data; + bool cancelled; + + jmutex_lock(data->mutex); + cancelled = data->cancelled; + jmutex_unlock(data->mutex); + + return cancelled; +} + +/** + * Applies the effect to the sprite in a background thread. + * + * [effect thread] + */ +static void effect_bg(void *_data) +{ + ThreadData *data = (ThreadData *)_data; + + /* apply the effect */ + effect_apply_to_target(data->effect); + + /* mark the work as 'done' */ + jmutex_lock(data->mutex); + data->done = TRUE; + jmutex_unlock(data->mutex); +} + +/** + * Called by the gui-monitor (a timer in the gui module that is called + * every 100 milliseconds). + * + * [main thread] + */ +static void monitor_effect_bg(void *_data) +{ + ThreadData *data = (ThreadData *)_data; + float pos; + bool done; + + jmutex_lock(data->mutex); + pos = data->pos; + done = data->done; + jmutex_unlock(data->mutex); + + if (data->progress) + progress_update(data->progress, pos); + + if (data->done) + remove_gui_monitor(data->monitor); +} + +/** + * Called to destroy the data of the monitor. + * + * [main thread] + */ +static void monitor_free(void *_data) +{ + ThreadData *data = (ThreadData *)_data; + + if (data->alert_window != NULL) + jwindow_close(data->alert_window, NULL); +} + +/** + * Applies the effect to the specified targets in the effect structure. + * + * [main thread] + */ +void effect_apply_to_target_with_progressbar(Effect *effect) +{ + ThreadData *data; + + data = jnew(ThreadData, 1); + if (data == NULL) { + jalert("Error<progress_data = data; + effect->progress = effect_progress_hook; + effect->is_cancelled = effect_is_cancelled_hook; + + data->mutex = jmutex_new(); + data->effect = effect; + data->pos = 0.0; + data->done = FALSE; + data->cancelled = FALSE; + data->progress = progress_new(app_get_statusbar()); + data->thread = jthread_new(effect_bg, data); + data->alert_window = jalert_new(PACKAGE + "<monitor = add_gui_monitor(monitor_effect_bg, + monitor_free, data); + + /* TODO error handling */ + + jwindow_open_fg(data->alert_window); + + jmutex_lock(data->mutex); + if (!data->done) { + remove_gui_monitor(data->monitor); + data->cancelled = TRUE; + } + jmutex_unlock(data->mutex); + + /* wait the `effect_bg' thread */ + jthread_join(data->thread); + + progress_free(data->progress); + jwidget_free(data->alert_window); + jfree(data); +} diff --git a/src/commands/fx/effectbg.h b/src/commands/fx/effectbg.h new file mode 100644 index 000000000..73ff033ad --- /dev/null +++ b/src/commands/fx/effectbg.h @@ -0,0 +1,26 @@ +/* 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 COMMANDS_FX_EFFECTBG_H +#define COMMANDS_FX_EFFECTBG_H + +struct Effect; + +void effect_apply_to_target_with_progressbar(struct Effect *effect); + +#endif /* COMMANDS_FX_EFFECTBG_H */ diff --git a/src/core/app.c b/src/core/app.c index 5eb9f5133..cc606ef0e 100644 --- a/src/core/app.c +++ b/src/core/app.c @@ -465,7 +465,7 @@ void app_realloc_sprite_list(void) * * @warning This routine can't be used when a menu callback was * called, because, it destroy the menus, you should use - * rebuild_recent_list() instead (src/gui/gui.c). + * schedule_rebuild_recent_list() instead (src/modules/gui.c). */ bool app_realloc_recent_list(void) { diff --git a/src/core/color.c b/src/core/color.c index 767fece75..51a7b1bf0 100644 --- a/src/core/color.c +++ b/src/core/color.c @@ -701,8 +701,9 @@ void color_to_formalstring(int imgtype, color_t color, break; case COLOR_TYPE_INDEX: { - ase_uint32 _c = palette_get_entry(get_current_palette(), data & 0xff); + ase_uint32 _c; data = GET_COLOR_DATA_INDEX(color); + _c = palette_get_entry(get_current_palette(), data & 0xff); uszprintf(buf, size, "%s %d (RGB %d %d %d)", _("Index"), data & 0xff, diff --git a/src/core/file_system.c b/src/core/file_system.c index ff392cfc0..f77426264 100644 --- a/src/core/file_system.c +++ b/src/core/file_system.c @@ -982,7 +982,7 @@ static FileItem *get_fileitem_by_path(const char *path, bool create_if_not) FileItem *fileitem; int attrib; - #ifdef ALLEGRO_UNIX +#ifdef ALLEGRO_UNIX if (*path == 0) return rootitem; #endif diff --git a/src/effect/colcurve.h b/src/effect/colcurve.h index 9b2e4c668..0f6caa0fd 100644 --- a/src/effect/colcurve.h +++ b/src/effect/colcurve.h @@ -50,8 +50,8 @@ void curve_get_values(Curve *curve, int x1, int x2, int *values); void set_color_curve(Curve *curve); -void apply_color_curve4 (struct Effect *effect); -void apply_color_curve2 (struct Effect *effect); -void apply_color_curve1 (struct Effect *effect); +void apply_color_curve4(struct Effect *effect); +void apply_color_curve2(struct Effect *effect); +void apply_color_curve1(struct Effect *effect); #endif /* EFFECT_COLCURVE_H */ diff --git a/src/effect/convmatr.h b/src/effect/convmatr.h index 558425ff2..7639176cf 100644 --- a/src/effect/convmatr.h +++ b/src/effect/convmatr.h @@ -55,8 +55,8 @@ JList get_convmatr_stock(void); void init_convolution_matrix(void); void exit_convolution_matrix(void); -void apply_convolution_matrix4 (struct Effect *effect); -void apply_convolution_matrix2 (struct Effect *effect); -void apply_convolution_matrix1 (struct Effect *effect); +void apply_convolution_matrix4(struct Effect *effect); +void apply_convolution_matrix2(struct Effect *effect); +void apply_convolution_matrix1(struct Effect *effect); #endif /* EFFECT_CONVMATR_H */ diff --git a/src/effect/effect.c b/src/effect/effect.c index b4f5526cd..df97585a5 100644 --- a/src/effect/effect.c +++ b/src/effect/effect.c @@ -117,6 +117,9 @@ Effect *effect_new(Sprite *sprite, const char *name) effect->mask_address = NULL; effect->effect_data = effect_data; effect->apply = apply; + effect->progress_data = NULL; + effect->progress = NULL; + effect->is_cancelled = NULL; effect_load_target(effect); @@ -266,27 +269,37 @@ bool effect_apply_step(Effect *effect) void effect_apply(Effect *effect) { -/* add_progress(effect->h); */ + bool cancelled = FALSE; effect_begin(effect); - while (effect_apply_step(effect)) - ; -/* do_progress(effect->row); */ + while (!cancelled && effect_apply_step(effect)) { + if (effect->progress != NULL) + (effect->progress)(effect->progress_data, + effect->progress_base + + effect->progress_width * (effect->row+1) / effect->h); - /* undo stuff */ - if (undo_is_enabled(effect->sprite->undo)) { - undo_set_label(effect->sprite->undo, - effect->effect_data->label); - undo_image(effect->sprite->undo, effect->src, - effect->x, effect->y, effect->w, effect->h); + if (effect->is_cancelled != NULL) + cancelled = (effect->is_cancelled)(effect->progress_data); } - /* copy "dst" to "src" */ - image_copy(effect->src, effect->dst, 0, 0); + if (!cancelled) { + /* undo stuff */ + if (undo_is_enabled(effect->sprite->undo)) { + undo_set_label(effect->sprite->undo, + effect->effect_data->label); + undo_image(effect->sprite->undo, effect->src, + effect->x, effect->y, effect->w, effect->h); + } -/* del_progress(); */ + /* copy "dst" to "src" */ + image_copy(effect->src, effect->dst, 0, 0); + } } + +/** + * Updates the current editor to show the progress of the preview. + */ void effect_flush(Effect *effect) { if (effect->row >= 0) { @@ -329,6 +342,7 @@ void effect_apply_to_target(Effect *effect) int n, n2, images = 0; Stock *stock; int *x, *y; + bool cancelled = FALSE; stock = sprite_get_images(effect->sprite, target, TRUE, &x, &y); if (!stock) @@ -339,24 +353,29 @@ void effect_apply_to_target(Effect *effect) images++; if (images > 0) { + /* open undo group of operations */ if (images > 1) { - /* open undo */ if (undo_is_enabled(effect->sprite->undo)) undo_open(effect->sprite->undo); } -/* add_progress(images); */ - for (n=n2=0; nnimage; n++) { + effect->progress_base = 0.0f; + effect->progress_width = 1.0f / images; + + for (n=n2=0; nnimage && !cancelled; n++) { if (!stock->image[n]) continue; -/* do_progress(n2++); */ effect_apply_to_image(effect, stock->image[n], x[n], y[n]); - } -/* del_progress(); */ + if (effect->is_cancelled != NULL) + cancelled = (effect->is_cancelled)(effect->progress_data); + + effect->progress_base += effect->progress_width; + } + + /* close undo group of operations */ if (images > 1) { - /* close */ if (undo_is_enabled(effect->sprite->undo)) undo_close(effect->sprite->undo); } diff --git a/src/effect/effect.h b/src/effect/effect.h index 1ce4d6b71..ca936dc8d 100644 --- a/src/effect/effect.h +++ b/src/effect/effect.h @@ -50,6 +50,11 @@ typedef struct Effect int a:1; int index:1; } target; + /* hooks */ + float progress_base, progress_width; + void *progress_data; + void (*progress)(void *data, float progress); + bool (*is_cancelled)(void *data); } Effect; Effect *effect_new(struct Sprite *sprite, const char *name); diff --git a/src/file/ase_format.c b/src/file/ase_format.c index c8a6dcb5c..c2e15ce11 100644 --- a/src/file/ase_format.c +++ b/src/file/ase_format.c @@ -106,6 +106,7 @@ FileFormat format_ase = "ase,aseprite", load_ASE, save_ASE, + NULL, FILE_SUPPORT_RGB | FILE_SUPPORT_RGBA | FILE_SUPPORT_GRAY | diff --git a/src/file/bmp_format.c b/src/file/bmp_format.c index 0ea42c256..33024edce 100644 --- a/src/file/bmp_format.c +++ b/src/file/bmp_format.c @@ -35,6 +35,7 @@ FileFormat format_bmp = "bmp", load_BMP, save_BMP, + NULL, FILE_SUPPORT_RGB | FILE_SUPPORT_GRAY | FILE_SUPPORT_INDEXED | @@ -678,7 +679,7 @@ static bool load_BMP(FileOp *fop) } /* setup the file-data */ - if (fop_sequence_get_filedata(fop) == NULL) { + if (fop->seq.filedata == NULL) { BmpData *bmpdata = bmpdata_new(); bmpdata->format = format; diff --git a/src/file/file.c b/src/file/file.c index 8c63160fd..a66837630 100644 --- a/src/file/file.c +++ b/src/file/file.c @@ -320,7 +320,7 @@ FileOp *fop_to_save_sprite(Sprite *sprite) if (jlist_length(fop->sprite->palettes) > 1) { if (!(fop->format->flags & (FILE_SUPPORT_PALETTES | FILE_SUPPORT_SEQUENCES))) { - usprintf(buf+ustrlen(buf), "<<- %s", _("Palette changes")); + usprintf(buf+ustrlen(buf), "<<- %s", _("Palette changes between frames")); } } @@ -414,6 +414,20 @@ FileOp *fop_to_save_sprite(Sprite *sprite) else fop->filename = jstrdup(fop->sprite->filename); + /* configure output format? */ + if (fop->format->getdata) { + FileData *data = (fop->format->getdata)(fop); + + /* does the user cancelled the operation? */ + if (data == NULL) { + fop_free(fop); + return NULL; + } + + fop->seq.filedata = data; + sprite_set_filedata(fop->sprite, data); + } + return fop; } @@ -470,6 +484,7 @@ void fop_operate(FileOp *fop) frame = 0; old_image = NULL; + fop->seq.has_alpha = FALSE; fop->seq.progress_offset = 0.0f; fop->seq.progress_fraction = 1.0f / (float)frames; @@ -539,6 +554,10 @@ void fop_operate(FileOp *fop) /* final setup */ if (fop->sprite != NULL) { + /* configure the layer as the `Background' */ + if (!fop->seq.has_alpha) + layer_configure_as_background(fop->seq.layer); + /* set the frames range */ sprite_set_frames(fop->sprite, frame); @@ -691,11 +710,6 @@ void fop_sequence_set_filedata(FileOp *fop, FileData *filedata) fop->seq.filedata = filedata; } -FileData *fop_sequence_get_filedata(FileOp *fop) -{ - return fop->seq.filedata; -} - void fop_sequence_set_color(FileOp *fop, int index, int r, int g, int b) { palette_set_entry(fop->seq.palette, index, _rgba(r, g, b, 255)); @@ -731,9 +745,6 @@ Image *fop_sequence_image(FileOp *fop, int imgtype, int w, int h) /* add the layer */ layer_add_layer(sprite->set, layer); - /* configure the layer as the background */ - layer_configure_as_background(layer); - /* done */ fop->sprite = sprite; fop->seq.layer = layer; diff --git a/src/file/file.h b/src/file/file.h index efb24d1c7..2f5ca2c9e 100644 --- a/src/file/file.h +++ b/src/file/file.h @@ -50,10 +50,14 @@ struct FileFormat; struct FileOp; /* file operations */ -typedef enum { FileOpLoad, FileOpSave } FileOpType; +typedef enum { FileOpLoad, + FileOpSave } FileOpType; + typedef bool (*FileLoad)(struct FileOp *fop); typedef bool (*FileSave)(struct FileOp *fop); +typedef struct FileData *(*FileGetData)(struct FileOp *fop); + /* load or/and save a file format */ typedef struct FileFormat { @@ -61,6 +65,7 @@ typedef struct FileFormat const char *exts; /* extensions (e.g. "jpeg,jpg") */ FileLoad load; /* procedure to read a sprite in this format */ FileSave save; /* procedure to write a sprite in this format */ + FileGetData getdata; /* procedure to configure the format to be saved */ int flags; } FileFormat; @@ -92,6 +97,7 @@ typedef struct FileOp float progress_fraction; /* progress fraction for one frame */ /* to load sequences */ int frame; + bool has_alpha; struct Layer *layer; struct Cel *last_cel; struct FileData *filedata; @@ -118,8 +124,6 @@ void fop_stop(FileOp *fop); void fop_free(FileOp *fop); void fop_sequence_set_filedata(FileOp *fop, struct FileData *filedata); -struct FileData *fop_sequence_get_filedata(FileOp *fop); - void fop_sequence_set_color(FileOp *fop, int index, int r, int g, int b); void fop_sequence_get_color(FileOp *fop, int index, int *r, int *g, int *b); struct Image *fop_sequence_image(FileOp *fi, int imgtype, int w, int h); diff --git a/src/file/filedata.c b/src/file/filedata.c index 3f78ebd8e..37c4f2957 100644 --- a/src/file/filedata.c +++ b/src/file/filedata.c @@ -56,3 +56,14 @@ BmpData *bmpdata_new(void) return bmpdata; } + +JpegData *jpegdata_new(void) +{ + JpegData *jpegdata = (JpegData *)filedata_new(FILEDATA_JPEG, + sizeof(JpegData)); + + if (jpegdata == NULL) + return NULL; + + return jpegdata; +} diff --git a/src/file/filedata.h b/src/file/filedata.h index d52301107..ad1368c23 100644 --- a/src/file/filedata.h +++ b/src/file/filedata.h @@ -21,6 +21,7 @@ enum { FILEDATA_BMP, + FILEDATA_JPEG, FILEDATA_MAX }; @@ -60,4 +61,23 @@ typedef struct BmpData BmpData *bmpdata_new(void); +/********************************************************************* + Data for JPEG files + *********************************************************************/ + +#define JPEGDATA_METHOD_SLOW 0 /* slow but accurate integer algorithm */ +#define JPEGDATA_METHOD_FAST 1 /* faster, less accurate integer method */ +#define JPEGDATA_METHOD_FLOAT 2 /* floating-point: accurate, fast on fast HW */ +#define JPEGDATA_METHOD_DEFAULT JPEGDATA_METHOD_SLOW + +typedef struct JpegData +{ + FileData head; + float quality; /* 1.0 maximum quality */ + float smooth; /* 1.0 maximum smooth */ + int method; +} JpegData; + +JpegData *jpegdata_new(void); + #endif /* FILEDATA_H */ diff --git a/src/file/fli_format.c b/src/file/fli_format.c index 9aa83c480..d0fcab5cb 100644 --- a/src/file/fli_format.c +++ b/src/file/fli_format.c @@ -37,6 +37,7 @@ FileFormat format_fli = "flc,fli", load_FLI, save_FLI, + NULL, FILE_SUPPORT_INDEXED | FILE_SUPPORT_FRAMES | FILE_SUPPORT_PALETTES @@ -104,8 +105,8 @@ static bool load_FLI(FileOp *fop) /* create the image */ sprite = sprite_new(IMAGE_INDEXED, w, h); layer = layer_new(sprite); - layer_set_name(layer, _("Background")); layer_add_layer(sprite->set, layer); + layer_configure_as_background(layer); /* set frames and speed */ sprite_set_frames(sprite, fli_header.frames); diff --git a/src/file/gif_format.c b/src/file/gif_format.c index 60980f89c..fb97301bd 100644 --- a/src/file/gif_format.c +++ b/src/file/gif_format.c @@ -47,12 +47,12 @@ FileFormat format_gif = "gif", load_GIF, save_GIF, + NULL, FILE_SUPPORT_INDEXED | FILE_SUPPORT_FRAMES | FILE_SUPPORT_PALETTES }; - static void render_gif_frame(GIF_FRAME *frame, Image *image, int x, int y, int w, int h) { @@ -117,7 +117,7 @@ static bool load_GIF(FileOp *fop) } layer_add_layer(sprite->set, layer); - layer_set_name(layer, _("Base")); + layer_configure_as_background(layer); image_clear(current_image, gif->background_index); image_clear(current_image_old, gif->background_index); diff --git a/src/file/ico_format.c b/src/file/ico_format.c index fcc9d9e98..3a5f9ef95 100644 --- a/src/file/ico_format.c +++ b/src/file/ico_format.c @@ -34,6 +34,7 @@ FileFormat format_ico = "ico", NULL, /* load_ICO, */ save_ICO, + NULL, /* FILE_SUPPORT_RGB | */ /* FILE_SUPPORT_GRAY | */ FILE_SUPPORT_INDEXED diff --git a/src/file/jpeg_format.c b/src/file/jpeg_format.c index bd6f30cec..f202e1160 100644 --- a/src/file/jpeg_format.c +++ b/src/file/jpeg_format.c @@ -28,6 +28,7 @@ #include "core/cfg.h" #include "core/core.h" #include "file/file.h" +#include "file/filedata.h" #include "raster/raster.h" #include "script/script.h" @@ -35,8 +36,7 @@ static bool load_JPEG(FileOp *fop); static bool save_JPEG(FileOp *fop); - -static bool configure_jpeg(void); /* TODO warning: not thread safe */ +static JpegData *getdata_JPEG(FileOp *fop); FileFormat format_jpeg = { @@ -44,6 +44,7 @@ FileFormat format_jpeg = "jpeg,jpg", load_JPEG, save_JPEG, + getdata_JPEG, FILE_SUPPORT_RGB | FILE_SUPPORT_GRAY | FILE_SUPPORT_SEQUENCES @@ -228,19 +229,8 @@ static bool save_JPEG(FileOp *fop) FILE *file; JSAMPARRAY buffer; JDIMENSION buffer_height; + JpegData *jpegdata = (JpegData *)fop->seq.filedata; int c; - int smooth; - int quality; - J_DCT_METHOD method; - - /* Configure JPEG compression only in the first frame. */ - if (fop->sprite->frame == 0 && !configure_jpeg()) - return FALSE; - - /* Options. */ - smooth = get_config_int("JPEG", "Smooth", 0); - quality = get_config_int("JPEG", "Quality", 100); - method = get_config_int("JPEG", "Method", JDCT_DEFAULT); /* Open the file for write in it. */ file = fopen(fop->filename, "wb"); @@ -271,9 +261,9 @@ static bool save_JPEG(FileOp *fop) } jpeg_set_defaults(&cinfo); - jpeg_set_quality(&cinfo, quality, TRUE); - cinfo.dct_method = method; - cinfo.smoothing_factor = smooth; + jpeg_set_quality(&cinfo, (int)MID(0, 100.0f * jpegdata->quality, 100), TRUE); + cinfo.dct_method = jpegdata->method; + cinfo.smoothing_factor = (int)MID(0, 100.0f * jpegdata->smooth, 100); /* Start compressor. */ jpeg_start_compress(&cinfo, TRUE); @@ -358,26 +348,25 @@ static bool save_JPEG(FileOp *fop) /** * Shows the JPEG configuration dialog. */ -static bool configure_jpeg(void) +static JpegData *getdata_JPEG(FileOp *fop) { JWidget window, box1, box2, box3, box4, box5; JWidget label_quality, label_smooth, label_method; JWidget slider_quality, slider_smooth, view_method; JWidget list_method, button_ok, button_cancel; - int quality, smooth, method; - bool ret; + JpegData *jpegdata = jpegdata_new(); + + /* configuration parameters */ + jpegdata->quality = get_config_float("JPEG", "Quality", 0.6f); + jpegdata->smooth = 0.0f; + jpegdata->method = JPEGDATA_METHOD_DEFAULT; /* interactive mode */ if (!is_interactive()) - return TRUE; - - /* configuration parameters */ - quality = get_config_int("JPEG", "Quality", 100); - smooth = get_config_int("JPEG", "Smooth", 0); - method = get_config_int("JPEG", "Method", 0); + return jpegdata; /* widgets */ - window = jwindow_new(_("Configure JPEG Compression")); + window = jwindow_new(_("JPEG Options")); box1 = jbox_new(JI_VERTICAL); box2 = jbox_new(JI_HORIZONTAL); box3 = jbox_new(JI_VERTICAL + JI_HOMOGENEOUS); @@ -386,8 +375,8 @@ static bool configure_jpeg(void) label_quality = jlabel_new(_("Quality:")); label_smooth = jlabel_new(_("Smooth:")); label_method = jlabel_new(_("Method:")); - slider_quality = jslider_new(0, 100, quality); - slider_smooth = jslider_new(0, 100, smooth); + slider_quality = jslider_new(0, 10, jpegdata->quality*10); + slider_smooth = jslider_new(0, 10, jpegdata->smooth*10); view_method = jview_new(); list_method = jlistbox_new(); button_ok = jbutton_new(_("&OK")); @@ -396,13 +385,14 @@ static bool configure_jpeg(void) jwidget_add_child(list_method, jlistitem_new(_("Slow"))); jwidget_add_child(list_method, jlistitem_new(_("Fast"))); jwidget_add_child(list_method, jlistitem_new(_("Float"))); - jlistbox_select_index(list_method, method); + jlistbox_select_index(list_method, jpegdata->method); - jview_attach(view_method, list_method); + jview_attach(view_method, list_method); jview_maxsize(view_method); jwidget_expansive(box4, TRUE); jwidget_expansive(view_method, TRUE); + jwidget_magnetic(button_ok, TRUE); jwidget_add_child(box3, label_quality); jwidget_add_child(box3, label_smooth); @@ -421,19 +411,17 @@ static bool configure_jpeg(void) jwindow_open_fg(window); if (jwindow_get_killer(window) == button_ok) { - ret = TRUE; + jpegdata->quality = jslider_get_value(slider_quality) / 10.0f; + jpegdata->smooth = jslider_get_value(slider_smooth) / 10.0f; + jpegdata->method = jlistbox_get_selected_index(list_method); - quality = jslider_get_value(slider_quality); - smooth = jslider_get_value(slider_smooth); - method = jlistbox_get_selected_index(list_method); - - set_config_int("JPEG", "Quality", quality); - set_config_int("JPEG", "Smooth", smooth); - set_config_int("JPEG", "Method", method); + set_config_float("JPEG", "Quality", jpegdata->quality); + } + else { + filedata_free((FileData *)jpegdata); + jpegdata = NULL; } - else - ret = FALSE; jwidget_free(window); - return ret; + return jpegdata; } diff --git a/src/file/pcx_format.c b/src/file/pcx_format.c index dff228b48..2b134853c 100644 --- a/src/file/pcx_format.c +++ b/src/file/pcx_format.c @@ -34,6 +34,7 @@ FileFormat format_pcx = "pcx", load_PCX, save_PCX, + NULL, FILE_SUPPORT_RGB | FILE_SUPPORT_GRAY | FILE_SUPPORT_INDEXED | diff --git a/src/file/png_format.c b/src/file/png_format.c index dc8def3c5..9e77b72b8 100644 --- a/src/file/png_format.c +++ b/src/file/png_format.c @@ -42,6 +42,7 @@ FileFormat format_png = "png", load_PNG, save_PNG, + NULL, FILE_SUPPORT_RGB | FILE_SUPPORT_RGBA | FILE_SUPPORT_GRAY | @@ -155,17 +156,23 @@ static bool load_PNG(FileOp *fop) /* create the output image */ switch (info_ptr->color_type) { - case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + fop->seq.has_alpha = TRUE; + case PNG_COLOR_TYPE_RGB: imgtype = IMAGE_RGB; break; - case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_GRAY_ALPHA: + fop->seq.has_alpha = TRUE; + case PNG_COLOR_TYPE_GRAY: imgtype = IMAGE_GRAYSCALE; break; + case PNG_COLOR_TYPE_PALETTE: imgtype = IMAGE_INDEXED; break; + default: fop_error(fop, "Color type not supported\n)"); png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); diff --git a/src/file/tga_format.c b/src/file/tga_format.c index 094152c48..58b07025c 100644 --- a/src/file/tga_format.c +++ b/src/file/tga_format.c @@ -37,6 +37,7 @@ FileFormat format_tga = "tga", load_TGA, save_TGA, + NULL, FILE_SUPPORT_RGB | FILE_SUPPORT_RGBA | FILE_SUPPORT_GRAY | diff --git a/src/modules/gui.c b/src/modules/gui.c index 690f87992..183619272 100644 --- a/src/modules/gui.c +++ b/src/modules/gui.c @@ -54,6 +54,8 @@ #define REBUILD_RECENT_LIST 2 #define REFRESH_FULL_SCREEN 4 +#define MONITOR_TIMER_MSECS 100 + /**************************************************************/ #ifdef ALLEGRO_WINDOWS @@ -573,7 +575,7 @@ JWidget load_widget(const char *filename, const char *name) return widget; } -void rebuild_recent_list(void) +void schedule_rebuild_recent_list(void) { next_idle_flags |= REBUILD_RECENT_LIST; } @@ -740,7 +742,7 @@ Monitor *add_gui_monitor(void (*proc)(void *), jlist_append(monitors, monitor); if (monitor_timer < 0) - monitor_timer = jmanager_add_timer(manager, 100); + monitor_timer = jmanager_add_timer(manager, MONITOR_TIMER_MSECS); jmanager_start_timer(monitor_timer); @@ -748,7 +750,7 @@ Monitor *add_gui_monitor(void (*proc)(void *), } /** - * Removes a previously added monitor. + * Removes and frees a previously added monitor. */ void remove_gui_monitor(Monitor *monitor) { diff --git a/src/modules/gui.h b/src/modules/gui.h index 647a07a28..00544a8e4 100644 --- a/src/modules/gui.h +++ b/src/modules/gui.h @@ -50,7 +50,7 @@ void save_window_pos(JWidget window, const char *section); JWidget load_widget(const char *filename, const char *name); -void rebuild_recent_list(void); +void schedule_rebuild_recent_list(void); void hook_signal(JWidget widget, int signal_num, diff --git a/src/modules/recent.c b/src/modules/recent.c index ee9e42370..f6434a167 100644 --- a/src/modules/recent.c +++ b/src/modules/recent.c @@ -88,7 +88,7 @@ void recent_file(const char *filename) if (strcmp(filename, filename_it) == 0) { jlist_remove(recent_files, filename_it); jlist_prepend(recent_files, filename_it); - rebuild_recent_list(); + schedule_rebuild_recent_list(); return; } count++; @@ -103,7 +103,7 @@ void recent_file(const char *filename) } jlist_prepend(recent_files, jstrdup(filename)); - rebuild_recent_list(); + schedule_rebuild_recent_list(); } } @@ -118,7 +118,7 @@ void unrecent_file(const char *filename) if (strcmp(filename, filename_it) == 0) { jfree(filename_it); jlist_delete_link(recent_files, link); - rebuild_recent_list(); + schedule_rebuild_recent_list(); break; } } diff --git a/src/widgets/preview.c b/src/widgets/preview.c index 8fbdb7fe4..0a9877378 100644 --- a/src/widgets/preview.c +++ b/src/widgets/preview.c @@ -102,6 +102,8 @@ static bool preview_msg_proc(JWidget widget, JMessage msg) case JM_CLOSE: set_preview_image(NULL, NULL); + /* stop the preview timer */ + jmanager_stop_timer(preview->timer_id); break; case JM_TIMER: