[gimp/wip/animation: 37/197] plug-ins: better support of big images: quality checkbox, loading notice, cleaner exit, frames locki
- From: Jehan Pagès <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/animation: 37/197] plug-ins: better support of big images: quality checkbox, loading notice, cleaner exit, frames locki
- Date: Sat, 7 Oct 2017 03:01:30 +0000 (UTC)
commit ee28201289f373813db850ea7b47bcab194029bd
Author: Jehan <jehan girinstud io>
Date: Fri Dec 21 21:46:19 2012 +0900
plug-ins: better support of big images: quality checkbox, loading notice, cleaner exit, frames locking.
The "preview quality" checkbox allows to preview the animation as at
most half the original image's dimension. Big animations (more than the
screen's dimension) with many frames will be checked by default.
This allows to significantly reduce loading time for huge images.
While loading, the playing progress bar will be used as a loading
progress bar, and care has been taken so that the UI is not frozen when
this happens. This allows a much better user experience.
Also the created frame image must be cleaned on exit, because even
though the process will finish, GEGL won't know about it (bug 690512).
Finally I lock the UI and prevent several actions on frames in the same
time, like rendering, or reinitialization.
plug-ins/common/animation-play.c | 352 ++++++++++++++++++++++++++++++++------
1 files changed, 297 insertions(+), 55 deletions(-)
---
diff --git a/plug-ins/common/animation-play.c b/plug-ins/common/animation-play.c
index 6376573..05f550a 100644
--- a/plug-ins/common/animation-play.c
+++ b/plug-ins/common/animation-play.c
@@ -22,14 +22,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/*
- * TODO:
- * pdb interface - should we bother?
- *
- * speedups (caching? most bottlenecks seem to be in pixelrgns)
- * -> do pixelrgns properly!
- */
-
#include "config.h"
#include <string.h>
@@ -46,7 +38,6 @@
#define PLUG_IN_ROLE "gimp-animation-play"
#define DITHERTYPE GDK_RGB_DITHER_NORMAL
-
typedef enum
{
DISPOSE_COMBINE = 0x00,
@@ -104,6 +95,8 @@ static void zoomcombo_activated (GtkEntry *combo,
gpointer data);
static void zoomcombo_changed (GtkWidget *combo,
gpointer data);
+static void quality_checkbox_toggled (GtkToggleButton *button,
+ gpointer data);
static gboolean repaint_sda (GtkWidget *darea,
GdkEventExpose *event,
gpointer data);
@@ -111,9 +104,11 @@ static gboolean repaint_da (GtkWidget *darea,
GdkEventExpose *event,
gpointer data);
+static void init_quality_checkbox (void);
static void init_frames (void);
-static void render_frame (gint32 whichframe);
-static void show_frame (void);
+static void render_frame (guint whichframe);
+static void show_playing_progress (void);
+static void show_loading_progress (gint layer_nb);
static void total_alpha_preview (void);
static void update_alpha_preview (void);
static void update_combobox (void);
@@ -122,6 +117,9 @@ static gint get_fps (gint index);
static gdouble get_scale (gint index);
static void update_scale (gdouble scale);
+/* Utils */
+static void remove_timer (void);
+static void clean_exit (void);
/* tag util functions*/
static gint parse_ms_tag (const gchar *str);
@@ -146,17 +144,20 @@ const GimpPlugInInfo PLUG_IN_INFO =
/* Global widgets'n'stuff */
static GtkWidget *window = NULL;
+static gulong destroy_handler;
static GdkWindow *root_win = NULL;
static GtkUIManager *ui_manager = NULL;
static GtkWidget *progress;
static GtkWidget *speedcombo = NULL;
static GtkWidget *fpscombo = NULL;
static GtkWidget *zoomcombo = NULL;
+static GtkWidget *quality_checkbox = NULL;
static GtkWidget *frame_disposal_combo = NULL;
static gint32 image_id;
static guint width = -1,
- height = -1;
+ height = -1,
+ preview_width, preview_height;
static gint32 *layers = NULL;
static gint32 total_layers = 0;
@@ -174,15 +175,19 @@ static guint shape_drawing_area_width = -1,
shape_drawing_area_height = -1;
static gchar *shape_preview_mask = NULL;
-
+static gint32 frames_image_id;
static gint32 total_frames = 0;
static gint32 *frames = NULL;
static guchar *rawframe = NULL;
static guint32 *frame_durations = NULL;
static guint frame_number;
static guint frame_number_min, frame_number_max;
+/* Since the application is single-thread, a boolean is enough.
+ * It may become a mutex in the future with multi-thread support. */
+static gboolean frames_lock = FALSE;
static gboolean playing = FALSE;
+static gboolean initialized_once = FALSE;
static guint timer = 0;
static gboolean detached = FALSE;
static gdouble scale, shape_scale;
@@ -202,6 +207,33 @@ static AnimationSettings settings =
static gint32 frames_image_id = 0;
+static void
+clean_exit (void)
+{
+ if (playing)
+ remove_timer ();
+
+ if (frames_image_id)
+ gimp_image_delete (frames_image_id);
+ frames_image_id = 0;
+
+ if (shape_window)
+ gtk_widget_destroy (GTK_WIDGET (shape_window));
+
+ g_signal_handler_disconnect (window, destroy_handler);
+ if (window)
+ gtk_widget_destroy (GTK_WIDGET (window));
+
+ if (frames)
+ g_free (frames);
+ if (frame_durations)
+ g_free (frame_durations);
+
+ gegl_exit ();
+ gtk_main_quit ();
+ gimp_quit ();
+}
+
MAIN ()
static void
@@ -241,9 +273,13 @@ run (const gchar *name,
static GimpParam values[1];
GimpRunMode run_mode;
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
+ GeglConfig *config;
INIT_I18N ();
gegl_init (NULL, NULL);
+ config = gegl_config ();
+ /* For preview, we want fast (0.0) over high quality (1.0). */
+ g_object_set (config, "quality", 0.0, NULL);
*nreturn_vals = 1;
*return_vals = values;
@@ -266,6 +302,10 @@ run (const gchar *name,
all_reg = g_regex_new("\\[\\*\\]", G_REGEX_OPTIMIZE, 0, NULL);
initialize ();
+
+ /* At least one full initialization finished. */
+ initialized_once = TRUE;
+
gtk_main ();
gimp_set_data (PLUG_IN_PROC, &settings, sizeof (settings));
@@ -349,7 +389,8 @@ da_size_callback (GtkWidget *widget,
drawing_area_width = allocation->width;
drawing_area_height = allocation->height;
- scale = MIN ((gdouble) drawing_area_width / (gdouble) width, (gdouble) drawing_area_height / (gdouble)
height);
+ scale = MIN ((gdouble) drawing_area_width / (gdouble) preview_width,
+ (gdouble) drawing_area_height / (gdouble) preview_height);
g_free (drawing_area_data);
drawing_area_data = g_malloc (drawing_area_width * drawing_area_height * 3);
@@ -400,7 +441,8 @@ sda_size_callback (GtkWidget *widget,
shape_drawing_area_width = allocation->width;
shape_drawing_area_height = allocation->height;
- shape_scale = MIN ((gdouble) shape_drawing_area_width / (gdouble) width, (gdouble)
shape_drawing_area_height / (gdouble) height);
+ shape_scale = MIN ((gdouble) shape_drawing_area_width / (gdouble) preview_width,
+ (gdouble) shape_drawing_area_height / (gdouble) preview_height);
g_free (shape_drawing_area_data);
g_free (shape_preview_mask);
@@ -507,8 +549,8 @@ repaint_da (GtkWidget *darea,
gdk_draw_rgb_image (gtk_widget_get_window (darea),
style->white_gc,
- (gint) ((drawing_area_width - scale * width) / 2),
- (gint) ((drawing_area_height - scale * height) / 2),
+ (gint) ((drawing_area_width - scale * preview_width) / 2),
+ (gint) ((drawing_area_height - scale * preview_height) / 2),
drawing_area_width, drawing_area_height,
(total_frames == 1) ? GDK_RGB_DITHER_MAX : DITHERTYPE,
drawing_area_data, drawing_area_width * 3);
@@ -525,8 +567,8 @@ repaint_sda (GtkWidget *darea,
gdk_draw_rgb_image (gtk_widget_get_window (darea),
style->white_gc,
- (gint) ((shape_drawing_area_width - shape_scale * width) / 2),
- (gint) ((shape_drawing_area_height - shape_scale * height) / 2),
+ (gint) ((shape_drawing_area_width - shape_scale * preview_width) / 2),
+ (gint) ((shape_drawing_area_height - shape_scale * preview_height) / 2),
shape_drawing_area_width, shape_drawing_area_height,
(total_frames == 1) ? GDK_RGB_DITHER_MAX : DITHERTYPE,
shape_drawing_area_data, shape_drawing_area_width * 3);
@@ -538,7 +580,7 @@ static void
close_callback (GtkAction *action,
gpointer data)
{
- gtk_widget_destroy (GTK_WIDGET (data));
+ clean_exit ();
}
static void
@@ -756,10 +798,11 @@ refresh_dialog (gchar *imagename)
* diminish the drawing area by as much, then compute the corresponding scale. */
if (window_width + 50 > screen_width || window_height + 50 > screen_height)
{
- guint expected_drawing_area_width = MAX (1, width - window_width + screen_width);
- guint expected_drawing_area_height = MAX (1, height - window_height + screen_height);
- gdouble expected_scale = MIN ((gdouble) expected_drawing_area_width / (gdouble) width,
- (gdouble) expected_drawing_area_height / (gdouble) height);
+ gint expected_drawing_area_width = MAX (1, preview_width - window_width + screen_width);
+ gint expected_drawing_area_height = MAX (1, preview_height - window_height + screen_height);
+
+ gdouble expected_scale = MIN ((gdouble) expected_drawing_area_width / (gdouble) preview_width,
+ (gdouble) expected_drawing_area_height / (gdouble) preview_height);
update_scale (expected_scale);
/* There is unfortunately no good way to know the size of the decorations, taskbars, etc.
@@ -794,9 +837,9 @@ build_dialog (gchar *imagename)
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_role (GTK_WINDOW (window), "animation-playback");
- g_signal_connect (window, "destroy",
- G_CALLBACK (window_destroy),
- NULL);
+ destroy_handler = g_signal_connect (window, "destroy",
+ G_CALLBACK (window_destroy),
+ NULL);
g_signal_connect (window, "popup-menu",
G_CALLBACK (popup_menu),
NULL);
@@ -868,6 +911,21 @@ build_dialog (gchar *imagename)
gtk_box_pack_end (GTK_BOX (hbox), progress, TRUE, TRUE, 0);
gtk_widget_show (progress);
+ /* Degraded quality animation preview. */
+ quality_checkbox = gtk_check_button_new_with_label (_("Preview Quality"));
+ gtk_box_pack_end (GTK_BOX (hbox), quality_checkbox, FALSE, FALSE, 0);
+ gtk_widget_show (quality_checkbox);
+
+ init_quality_checkbox ();
+ quality_checkbox_toggled (GTK_TOGGLE_BUTTON (quality_checkbox), NULL);
+
+ g_signal_connect (GTK_TOGGLE_BUTTON (quality_checkbox),
+ "toggled",
+ G_CALLBACK (quality_checkbox_toggled),
+ NULL);
+
+ gimp_help_set_help_data (quality_checkbox, _("Degraded image quality for low memory footprint"), NULL);
+
/* Zoom */
zoomcombo = gtk_combo_box_text_new_with_entry ();
gtk_box_pack_end (GTK_BOX (hbox), zoomcombo, FALSE, FALSE, 0);
@@ -963,7 +1021,7 @@ build_dialog (gchar *imagename)
gtk_widget_show (frame_disposal_combo);
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
- gtk_window_set_default_size (GTK_WINDOW (window), width + 20, height + 90);
+ gtk_window_set_default_size (GTK_WINDOW (window), preview_width + 20, preview_height + 90);
gtk_widget_show (window);
/* shape_drawing_area for detached feature. */
@@ -1009,33 +1067,85 @@ build_dialog (gchar *imagename)
/* We request a minimum size *after* having connecting the
* size-allocate signal for correct initialization. */
- gtk_widget_set_size_request (drawing_area, width, height);
- gtk_widget_set_size_request (shape_drawing_area, width, height);
+ gtk_widget_set_size_request (drawing_area, preview_width, preview_height);
+ gtk_widget_set_size_request (shape_drawing_area, preview_width, preview_height);
root_win = gdk_get_default_root_window ();
}
static void
+init_quality_checkbox (void)
+{
+ GdkScreen *screen;
+ guint screen_width, screen_height;
+ static const gint lower_quality_frame_limit = 10;
+
+ screen = gtk_widget_get_screen (window);
+ screen_height = gdk_screen_get_height (screen);
+ screen_width = gdk_screen_get_width (screen);
+
+ /* We will set a lower quality as default if image is more than half the screen size
+ * and there are more than a given limit of frames. */
+ if (total_frames > lower_quality_frame_limit &&
+ (width > screen_width || height > screen_height))
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (quality_checkbox), TRUE);
+ else
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (quality_checkbox), FALSE);
+}
+
+static void
init_frames (void)
{
/* Frames are associated to an unused image. */
- static gint32 frames_image_id;
gint32 new_frame, previous_frame, new_layer;
gboolean animated;
GtkAction *action;
gint duration = 0;
DisposeType disposal = settings.default_frame_disposal;
gchar *layer_name;
+ gint layer_offx, layer_offy;
+ gboolean preview_quality;
- set_total_frames ();
if (total_frames <= 0)
{
gimp_message (_("This animation has no frame."));
- gtk_main_quit ();
- gimp_quit ();
+ clean_exit ();
return;
}
+ if (frames_lock)
+ return;
+ frames_lock = TRUE;
+
+ /* Block the frame-related UI during frame initialization. */
+ action = gtk_ui_manager_get_action (ui_manager,
+ "/ui/anim-play-toolbar/play");
+ gtk_action_set_sensitive (action, FALSE);
+
+ action = gtk_ui_manager_get_action (ui_manager,
+ "/ui/anim-play-toolbar/step-back");
+ gtk_action_set_sensitive (action, FALSE);
+
+ action = gtk_ui_manager_get_action (ui_manager,
+ "/ui/anim-play-toolbar/step");
+ gtk_action_set_sensitive (action, FALSE);
+
+ action = gtk_ui_manager_get_action (ui_manager,
+ "/ui/anim-play-toolbar/rewind");
+ gtk_action_set_sensitive (action, FALSE);
+
+ action = gtk_ui_manager_get_action (ui_manager,
+ "/ui/anim-play-toolbar/refresh");
+ gtk_action_set_sensitive (action, FALSE);
+
+ action = gtk_ui_manager_get_action (ui_manager,
+ "/ui/anim-play-toolbar/detach");
+ gtk_action_set_sensitive (action, FALSE);
+
+ gtk_widget_set_sensitive (GTK_WIDGET (zoomcombo), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (frame_disposal_combo), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (quality_checkbox), FALSE);
+
/* Cleanup before re-generation. */
if (frames)
{
@@ -1048,18 +1158,22 @@ init_frames (void)
frame_durations = g_try_malloc0_n (total_frames, sizeof (guint32));
if (! frames || ! frame_durations)
{
+ frames_lock = FALSE;
gimp_message (_("Memory could not be allocated to the frame container."));
- gtk_main_quit ();
- gimp_quit ();
+ clean_exit ();
return;
}
+
/* We only use RGB images for display because indexed images would somehow
render terrible colors. Layers from other types will be automatically
converted. */
frames_image_id = gimp_image_new (width, height, GIMP_RGB);
+
/* Save processing time and memory by not saving history and merged frames. */
gimp_image_undo_disable (frames_image_id);
+ preview_quality = preview_width != width || preview_height != height;
+
if (disposal == DISPOSE_TAGS)
{
gint i, j, k;
@@ -1068,6 +1182,7 @@ init_frames (void)
for (i = 0; i < total_layers; i++)
{
+ show_loading_progress (i);
layer_name = gimp_item_get_name (layers[total_layers - (i + 1)]);
nospace_name = g_regex_replace_literal (nospace_reg, layer_name, -1, 0, "", 0, NULL);
if (g_regex_match (all_reg, nospace_name, 0, NULL))
@@ -1076,12 +1191,23 @@ init_frames (void)
{
new_layer = gimp_layer_new_from_drawable (layers[total_layers - (i + 1)], frames_image_id);
gimp_image_insert_layer (frames_image_id, new_layer, 0, 0);
+ gimp_item_set_visible (new_layer, TRUE);
+ if (preview_quality)
+ {
+ gimp_layer_scale (new_layer,
+ (gimp_drawable_width (layers[total_layers - (i + 1)]) * (gint)
preview_width) / (gint) width,
+ (gimp_drawable_height (layers[total_layers - (i + 1)]) * (gint)
preview_height) / (gint) height,
+ FALSE);
+ gimp_drawable_offsets (layers[total_layers - (i + 1)], &layer_offx, &layer_offy);
+ gimp_layer_set_offsets (new_layer, (layer_offx * (gint) preview_width) / (gint) width,
+ (layer_offy * (gint) preview_height) / (gint) height);
+ }
+ gimp_layer_resize_to_image_size (new_layer);
if (! frames[j])
frames[j] = new_layer;
else
{
gimp_item_set_visible (frames[j], TRUE);
- gimp_item_set_visible (new_layer, TRUE);
frames[j] = gimp_image_merge_visible_layers (frames_image_id, GIMP_CLIP_TO_IMAGE);
}
gimp_item_set_visible (frames[j], FALSE);
@@ -1108,12 +1234,23 @@ init_frames (void)
{
new_layer = gimp_layer_new_from_drawable (layers[total_layers - (i + 1)],
frames_image_id);
gimp_image_insert_layer (frames_image_id, new_layer, 0, 0);
+ gimp_item_set_visible (new_layer, TRUE);
+ if (preview_quality)
+ {
+ gimp_layer_scale (new_layer,
+ (gimp_drawable_width (layers[total_layers - (i + 1)]) *
(gint) preview_width) / (gint) width,
+ (gimp_drawable_height (layers[total_layers - (i + 1)]) *
(gint) preview_height) / (gint) height,
+ FALSE);
+ gimp_drawable_offsets (layers[total_layers - (i + 1)], &layer_offx,
&layer_offy);
+ gimp_layer_set_offsets (new_layer, (layer_offx * (gint) preview_width) /
(gint) width,
+ (layer_offy * (gint) preview_height) / (gint)
height);
+ }
+ gimp_layer_resize_to_image_size (new_layer);
if (! frames[k - frame_number_min])
frames[k - frame_number_min] = new_layer;
else
{
gimp_item_set_visible (frames[k - frame_number_min], TRUE);
- gimp_item_set_visible (new_layer, TRUE);
frames[k - frame_number_min] = gimp_image_merge_visible_layers
(frames_image_id, GIMP_CLIP_TO_IMAGE);
}
gimp_item_set_visible (frames[k - frame_number_min], FALSE);
@@ -1125,12 +1262,23 @@ init_frames (void)
new_layer = gimp_layer_new_from_drawable (layers[total_layers - (i + 1)],
frames_image_id);
gimp_image_insert_layer (frames_image_id, new_layer, 0, 0);
+ gimp_item_set_visible (new_layer, TRUE);
+ if (preview_quality)
+ {
+ gimp_layer_scale (new_layer,
+ (gimp_drawable_width (layers[total_layers - (i + 1)]) *
(gint) preview_width) / (gint) width,
+ (gimp_drawable_height (layers[total_layers - (i + 1)]) *
(gint) preview_height) / (gint) height,
+ FALSE);
+ gimp_drawable_offsets (layers[total_layers - (i + 1)], &layer_offx,
&layer_offy);
+ gimp_layer_set_offsets (new_layer, (layer_offx * (gint) preview_width) /
(gint) width,
+ (layer_offy * (gint) preview_height) / (gint) height);
+ }
+ gimp_layer_resize_to_image_size (new_layer);
if (! frames[num - frame_number_min])
frames[num - frame_number_min] = new_layer;
else
{
gimp_item_set_visible (frames[num - frame_number_min], TRUE);
- gimp_item_set_visible (new_layer, TRUE);
frames[num - frame_number_min] = gimp_image_merge_visible_layers
(frames_image_id, GIMP_CLIP_TO_IMAGE);
}
gimp_item_set_visible (frames[num - frame_number_min], FALSE);
@@ -1162,6 +1310,7 @@ init_frames (void)
for (i = 0; i < total_frames; i++)
{
+ show_loading_progress (i);
layer_name = gimp_item_get_name (layers[total_layers - (i + 1)]);
if (layer_name)
{
@@ -1173,12 +1322,22 @@ init_frames (void)
if (i > 0 && disposal != DISPOSE_REPLACE)
{
previous_frame = gimp_layer_copy (frames[i - 1]);
+
gimp_image_insert_layer (frames_image_id, previous_frame, 0, 0);
gimp_item_set_visible (previous_frame, TRUE);
}
+
new_layer = gimp_layer_new_from_drawable (layers[total_layers - (i + 1)], frames_image_id);
+
gimp_image_insert_layer (frames_image_id, new_layer, 0, 0);
gimp_item_set_visible (new_layer, TRUE);
+ gimp_layer_scale (new_layer, (gimp_drawable_width (layers[total_layers - (i + 1)]) * (gint)
preview_width) / (gint) width,
+ (gimp_drawable_height (layers[total_layers - (i + 1)]) * (gint) preview_height)
/ (gint) height, FALSE);
+ gimp_drawable_offsets (layers[total_layers - (i + 1)], &layer_offx, &layer_offy);
+ gimp_layer_set_offsets (new_layer, (layer_offx * (gint) preview_width) / (gint) width,
+ (layer_offy * (gint) preview_height) / (gint) height);
+ gimp_layer_resize_to_image_size (new_layer);
+
new_frame = gimp_image_merge_visible_layers (frames_image_id, GIMP_CLIP_TO_IMAGE);
frames[i] = new_frame;
gimp_item_set_visible (new_frame, FALSE);
@@ -1207,9 +1366,23 @@ init_frames (void)
"/ui/anim-play-toolbar/rewind");
gtk_action_set_sensitive (action, animated);
+ action = gtk_ui_manager_get_action (ui_manager,
+ "/ui/anim-play-toolbar/refresh");
+ gtk_action_set_sensitive (action, TRUE);
+
+ action = gtk_ui_manager_get_action (ui_manager,
+ "/ui/anim-play-toolbar/detach");
+ gtk_action_set_sensitive (action, TRUE);
+
+ gtk_widget_set_sensitive (GTK_WIDGET (zoomcombo), TRUE);
+ gtk_widget_set_sensitive (GTK_WIDGET (frame_disposal_combo), TRUE);
+ gtk_widget_set_sensitive (GTK_WIDGET (quality_checkbox), TRUE);
+
/* Keep the same frame number, unless it is now invalid. */
if (frame_number > frame_number_max || frame_number < frame_number_min)
frame_number = frame_number_min;
+
+ frames_lock = FALSE;
}
static void
@@ -1222,7 +1395,7 @@ initialize (void)
if (! gimp_image_is_valid (image_id))
{
gimp_message (_("Invalid image. Did you close it?"));
- gtk_main_quit ();
+ clean_exit ();
return;
}
@@ -1230,10 +1403,17 @@ initialize (void)
height = gimp_image_height (image_id);
layers = gimp_image_get_layers (image_id, &total_layers);
+ set_total_frames ();
+
if (!window)
build_dialog (gimp_image_get_name (image_id));
refresh_dialog (gimp_image_get_name (image_id));
+ /* I want to make sure the progress bar is realized before init_frames()
+ * which may take quite a bit of time. */
+ if (!gtk_widget_get_realized (progress))
+ gtk_widget_realize (progress);
+
init_frames ();
render_frame (frame_number);
}
@@ -1241,7 +1421,7 @@ initialize (void)
/* Rendering Functions */
static void
-render_frame (gint32 whichframe)
+render_frame (guint whichframe)
{
GeglBuffer *buffer;
gint i, j, k;
@@ -1252,6 +1432,12 @@ render_frame (gint32 whichframe)
gdouble drawing_scale;
guchar *preview_data;
+ /* Do not try to update the drawing areas while init_frame() is still running. */
+ if (frames_lock)
+ return;
+
+ frames_lock = TRUE;
+
g_assert (whichframe >= frame_number_min && whichframe <= frame_number_max);
if (detached)
@@ -1325,8 +1511,8 @@ render_frame (gint32 whichframe)
/* Display the preview buffer. */
gdk_draw_rgb_image (gtk_widget_get_window (da),
(gtk_widget_get_style (da))->white_gc,
- (gint) ((drawing_width - drawing_scale * width) / 2),
- (gint) ((drawing_height - drawing_scale * height) / 2),
+ (gint) ((drawing_width - drawing_scale * preview_width) / 2),
+ (gint) ((drawing_height - drawing_scale * preview_height) / 2),
drawing_width, drawing_height,
(total_frames == 1 ?
GDK_RGB_DITHER_MAX : DITHERTYPE),
@@ -1336,11 +1522,31 @@ render_frame (gint32 whichframe)
g_object_unref (buffer);
/* Update UI. */
- show_frame ();
+ show_playing_progress ();
+
+ frames_lock = FALSE;
}
static void
-show_frame (void)
+show_loading_progress (gint layer_nb)
+{
+ gchar *text;
+ gfloat load_rate = (gfloat) layer_nb / ((gfloat) total_layers - 0.999);
+
+ /* update the dialog's progress bar */
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress), load_rate);
+
+ text = g_strdup_printf (_("Loading animation %d %%"), (gint) (load_rate * 100));
+ gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progress), text);
+ g_free (text);
+
+ /* Forcing the UI to update even with intensive computation. */
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+static void
+show_playing_progress (void)
{
gchar *text;
@@ -1440,13 +1646,7 @@ do_step (void)
static void
window_destroy (GtkWidget *widget)
{
- if (playing)
- remove_timer ();
-
- if (shape_window)
- gtk_widget_destroy (GTK_WIDGET (shape_window));
-
- gtk_main_quit ();
+ clean_exit ();
}
@@ -1674,6 +1874,8 @@ static void
framecombo_changed (GtkWidget *combo, gpointer data)
{
settings.default_frame_disposal = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
+
+ set_total_frames ();
init_frames ();
render_frame (frame_number);
}
@@ -1706,10 +1908,10 @@ update_scale (gdouble scale)
/* FIXME: scales under 0.5 are broken. See bug 690265. */
if (scale <= 0.5)
- scale = 0.501;
+ scale = 0.51;
- expected_drawing_area_width = width * scale;
- expected_drawing_area_height = height * scale;
+ expected_drawing_area_width = preview_width * scale;
+ expected_drawing_area_height = preview_height * scale;
gtk_widget_set_size_request (drawing_area, expected_drawing_area_width, expected_drawing_area_height);
gtk_widget_set_size_request (shape_drawing_area, expected_drawing_area_width,
expected_drawing_area_height);
@@ -1725,6 +1927,46 @@ update_scale (gdouble scale)
}
/*
+ * Callback emitted when the user toggle the quality checkbox.
+ */
+static void
+quality_checkbox_toggled (GtkToggleButton *button,
+ gpointer data)
+{
+ gint previous_preview_width = preview_width;
+
+ if (gtk_toggle_button_get_active (button))
+ {
+ GdkScreen *screen;
+ guint screen_width, screen_height;
+
+ screen = gtk_widget_get_screen (window);
+ screen_height = gdk_screen_get_height (screen);
+ screen_width = gdk_screen_get_width (screen);
+
+ /* Get some maximum value for both dimension. */
+ preview_width = MIN (screen_width / 2, width);
+ preview_height = MIN (screen_height / 2, height);
+ /* Get the correct ratio. */
+ preview_width = MIN (preview_width, preview_height * width / height);
+ preview_height = preview_width * height / width;
+ }
+ else
+ {
+ preview_width = width;
+ preview_height = height;
+ }
+
+ if (initialized_once && previous_preview_width != preview_width)
+ {
+ gint index = gtk_combo_box_get_active (GTK_COMBO_BOX (zoomcombo));
+
+ init_frames ();
+ update_scale (get_scale (index));
+ }
+}
+
+/*
* Callback emitted when the user hits the Enter key of the zoom combo.
*/
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]