gimp/plug-ins/common/animationplay.c

1447 lines
42 KiB
C
Raw Normal View History

1997-11-24 22:05:25 +00:00
/*
* Animation Playback plug-in version 0.98.8
1997-11-24 22:05:25 +00:00
*
* (c) Adam D. Moss : 1997-2000 : adam@gimp.org : adam@foxbox.org
1997-11-24 22:05:25 +00:00
*
* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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.
1997-11-24 22:05:25 +00:00
*/
/*
* BUGS:
* Gets understandably upset if the source image is deleted
* while the animation is playing. Decent solution welcome.
*
* In shaped mode, the shaped-window's mask and its pixmap contents
* can get way out of sync (specifically, the mask changes but
* the contents are frozen). Starvation of GTK's redrawing thread?
* How do I fix this?
*
1997-11-24 22:05:25 +00:00
* Any more? Let me know!
*/
/*
* TODO:
* pdb interface - should we bother?
*
1997-11-24 22:05:25 +00:00
* speedups (caching? most bottlenecks seem to be in pixelrgns)
* -> do pixelrgns properly!
*
* write other half of the user interface (default timing, disposal &c)
1997-11-24 22:05:25 +00:00
*/
#include "config.h"
1997-11-24 22:05:25 +00:00
#include <string.h>
app/gimpui.[ch] removed & renamed some functions from gimpui.[ch] (see 2000-01-13 Michael Natterer <mitch@gimp.org> * app/gimpui.[ch] * app/preferences_dialog.c: removed & renamed some functions from gimpui.[ch] (see below). * libgimp/Makefile.am * libgimp/gimpwidgets.[ch]; new files. Functions moved from app/gimpui.[ch]. Added a constructor for the label + hscale + entry combination used in many plugins (now hscale + spinbutton). * libgimp/gimpui.h: include gimpwidgets.h * plug-ins/megawidget/megawidget.[ch]: removed all functions except the preview stuff (I'm not yet sure how to implement this in libgimp because the libgimp preview should be general enough to replace all the other plugin previews, too). * plug-ins/borderaverage/Makefile.am * plug-ins/borderaverage/borderaverage.c * plug-ins/common/plugin-defs.pl * plug-ins/common/Makefile.am * plug-ins/common/aa.c * plug-ins/common/align_layers.c * plug-ins/common/animationplay.c * plug-ins/common/apply_lens.c * plug-ins/common/blinds.c * plug-ins/common/bumpmap.c * plug-ins/common/checkerboard.c * plug-ins/common/colorify.c * plug-ins/common/convmatrix.c * plug-ins/common/cubism.c * plug-ins/common/curve_bend.c * plug-ins/common/deinterlace.c * plug-ins/common/despeckle.c * plug-ins/common/destripe.c * plug-ins/common/displace.c * plug-ins/common/edge.c * plug-ins/common/emboss.c * plug-ins/common/hot.c * plug-ins/common/nlfilt.c * plug-ins/common/pixelize.c * plug-ins/common/waves.c * plug-ins/sgi/sgi.c * plug-ins/sinus/sinus.c: ui updates like removing megawidget, using the dialog constructor, I18N fixes, indentation, ...
2000-01-13 15:39:26 +00:00
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#include "libgimp/stdplugins-intl.h"
1997-11-24 22:05:25 +00:00
#define DITHERTYPE GDK_RGB_DITHER_NORMAL
1997-11-24 22:05:25 +00:00
typedef enum
{
DISPOSE_UNDEFINED = 0x00,
DISPOSE_COMBINE = 0x01,
DISPOSE_REPLACE = 0x02
} DisposeType;
/* Declare local functions. */
static void query (void);
static void run (const gchar *name,
gint nparams,
const GimpParam *param,
gint *nreturn_vals,
GimpParam **return_vals);
1997-11-24 22:05:25 +00:00
static void do_playback (void);
1997-11-24 22:05:25 +00:00
removed our own action_area API and use GtkDialog's one. Create all 2003-11-06 Michael Natterer <mitch@gimp.org> * libgimpwidgets/gimpdialog.[ch]: removed our own action_area API and use GtkDialog's one. Create all dialogs without separator. Changed almost everything else too. Fixes bug #125143. * libgimpwidgets/gimpquerybox.c * libgimpwidgets/gimpunitmenu.c: changed accordingly. * libgimp/gimpexport.[ch]: ditto. Renamed enum GimpExportReturnType to GimpExportReturn. * libgimp/gimpcompat.h: added a #define for the old name. * themes/Default/gtkrc: increased action_area border to 6 pixels. * app/display/gimpdisplayshell-filter-dialog.c * app/display/gimpdisplayshell-scale.c * app/display/gimpprogress.c * app/gui/brush-select.c * app/gui/channels-commands.c * app/gui/color-notebook.c * app/gui/convert-dialog.c * app/gui/file-new-dialog.c * app/gui/font-select.c * app/gui/gradient-editor-commands.c * app/gui/gradient-select.c * app/gui/grid-dialog.c * app/gui/image-commands.c * app/gui/info-window.c * app/gui/layers-commands.c * app/gui/module-browser.c * app/gui/offset-dialog.c * app/gui/palette-import-dialog.c * app/gui/palette-select.c * app/gui/pattern-select.c * app/gui/preferences-dialog.c * app/gui/qmask-commands.c * app/gui/resize-dialog.c * app/gui/resolution-calibrate-dialog.c * app/gui/stroke-dialog.c * app/gui/templates-commands.c * app/gui/user-install-dialog.c * app/gui/vectors-commands.c * app/tools/gimpcolorpickertool.c * app/tools/gimpcroptool.c * app/tools/gimpimagemaptool.c * app/tools/gimpmeasuretool.c * app/tools/gimptransformtool.c * app/widgets/gimptexteditor.c * app/widgets/gimptooldialog.[ch] * app/widgets/gimpviewabledialog.[ch] * app/widgets/gimpwidgets-utils.c: changed accordingly and increased the dialogs' outer borders to 6 pixels all over the place. * plug-ins/*/*.c: changed accordingly. The plug-ins may be arbitrarily broken, I tested none of them.
2003-11-06 15:27:05 +00:00
static void window_response (GtkWidget *widget,
gint response_id,
gpointer data);
static void playstop_callback (GtkWidget *widget,
gpointer data);
static void rewind_callback (GtkWidget *widget,
gpointer data);
static void step_callback (GtkWidget *widget,
gpointer data);
static gboolean repaint_sda (GtkWidget *darea,
GdkEventExpose *event,
gpointer data);
static gboolean repaint_da (GtkWidget *darea,
GdkEventExpose *event,
gpointer data);
static void render_frame (gint32 whichframe);
static void show_frame (void);
static void total_alpha_preview (guchar* ptr);
static void init_preview_misc (void);
1997-11-24 22:05:25 +00:00
/* tag util functions*/
static int parse_ms_tag (const char *str);
static DisposeType parse_disposal_tag (const char *str);
static DisposeType get_frame_disposal (guint whichframe);
static guint32 get_frame_duration (guint whichframe);
static gboolean is_disposal_tag (const char *str,
DisposeType *disposal,
int *taglength);
static gboolean is_ms_tag (const char *str,
int *duration,
int *taglength);
GimpPlugInInfo PLUG_IN_INFO =
1997-11-24 22:05:25 +00:00
{
NULL, /* init_proc */
NULL, /* quit_proc */
1997-11-24 22:05:25 +00:00
query, /* query_proc */
run, /* run_proc */
1997-11-24 22:05:25 +00:00
};
/* Global widgets'n'stuff */
static GtkWidget *dlg = NULL;
static guchar *preview_data = NULL;
static GtkWidget *drawing_area = NULL;
static GtkWidget *shape_drawing_area = NULL;
static guchar *shape_drawing_area_data = NULL;
static guchar *drawing_area_data = NULL;
static GtkProgressBar *progress;
static guint width, height;
static guchar *preview_alpha1_data;
static guchar *preview_alpha2_data;
static gint32 image_id;
static gint32 total_frames;
static guint frame_number;
static gint32 *layers;
static GimpDrawable *drawable;
static gboolean playing = FALSE;
static guint timer = 0;
static GimpImageBaseType imagetype;
static guchar *palette;
static gint ncolours;
static GtkWidget *psbutton;
1997-11-24 22:05:25 +00:00
/* for shaping */
Changed plug-in menu registration again to allow passing just the menu 2004-05-07 Michael Natterer <mitch@gimp.org> Changed plug-in menu registration again to allow passing just the menu item's label (not the full path) in gimp_install_procedure() and only the path (excluding the item's label) in gimp_plugin_menu_register(). Matches the internal action system better and makes translating the menu paths much easier. (Of yourse it's still possible to use the old syntax for backward compatibility). * app/plug-in/plug-in-proc.[ch]: added "gchar *menu_label". * app/plug-in/plug-in-params.[ch]: added new functions plug_in_param_defs_check() and plug_in_proc_args_check() which check if a procedure's parameters match its menu location (e.g. <Image> needs RUN-MODE, IMAGE, DRAWABLE). * app/plug-in/plug-in-message.c (plug_in_handle_proc_install): if registering an old-style (full) menu_path, use plug_in_param_defs_check(), set proc_def->menu_label otherwise. * tools/pdbgen/pdb/plug_in.pdb (plugin_menu_register): use plug_in_proc_args_check() on the passed menu_path and make sugre old and new style menu registration are not mixed. * app/pdb/plug_in_cmds.c: regenerated. * app/plug-in/plug-in-rc.c: save/restore "menu_label". * app/actions/file-dialog-actions.c * app/actions/plug-in-actions.c * app/menus/plug-in-menus.c: changed action/menu creation accordingly. Some hacks needed to allow both old and new style menu_label/menu_paths. * app/plug-in/plug-in.c * app/widgets/gimpfiledialog.c * app/xcf/xcf.c: changed accordingly. * plug-ins/common/align_layers.c * plug-ins/common/animationplay.c * plug-ins/common/animoptimize.c * plug-ins/common/apply_lens.c * plug-ins/common/autocrop.c * plug-ins/common/autostretch_hsv.c * plug-ins/common/blinds.c * plug-ins/common/blur.c * plug-ins/common/borderaverage.c * plug-ins/common/bumpmap.c * plug-ins/common/c_astretch.c * plug-ins/common/ccanalyze.c * plug-ins/common/channel_mixer.c * plug-ins/common/checkerboard.c * plug-ins/common/color_enhance.c * plug-ins/common/colorify.c * plug-ins/common/colortoalpha.c * plug-ins/common/compose.c * plug-ins/common/convmatrix.c * plug-ins/common/cubism.c * plug-ins/common/curve_bend.c * plug-ins/common/decompose.c * plug-ins/common/deinterlace.c * plug-ins/common/depthmerge.c * plug-ins/common/destripe.c * plug-ins/common/diffraction.c * plug-ins/common/displace.c * plug-ins/common/edge.c * plug-ins/common/emboss.c * plug-ins/common/engrave.c * plug-ins/common/exchange.c * plug-ins/common/film.c * plug-ins/common/flarefx.c * plug-ins/common/fractaltrace.c * plug-ins/common/screenshot.c: ported the first few plug-ins to the new registration scheme.
2004-05-07 00:30:24 +00:00
typedef struct
{
gint x, y;
} CursorOffset;
static gchar *shape_preview_mask;
static GtkWidget *shape_window;
static gint shaping = 0;
static GdkWindow *root_win = NULL;
MAIN ()
1997-11-24 22:05:25 +00:00
static void
query (void)
1997-11-24 22:05:25 +00:00
{
static GimpParamDef args[] =
1997-11-24 22:05:25 +00:00
{
{ GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
{ GIMP_PDB_IMAGE, "image", "Input image" },
{ GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)" }
1997-11-24 22:05:25 +00:00
};
gimp_install_procedure ("plug_in_animationplay",
"This plugin allows you to preview a GIMP layer-based animation.",
"",
"Adam D. Moss <adam@gimp.org>",
"Adam D. Moss <adam@gimp.org>",
"1997, 1998...",
Changed plug-in menu registration again to allow passing just the menu 2004-05-07 Michael Natterer <mitch@gimp.org> Changed plug-in menu registration again to allow passing just the menu item's label (not the full path) in gimp_install_procedure() and only the path (excluding the item's label) in gimp_plugin_menu_register(). Matches the internal action system better and makes translating the menu paths much easier. (Of yourse it's still possible to use the old syntax for backward compatibility). * app/plug-in/plug-in-proc.[ch]: added "gchar *menu_label". * app/plug-in/plug-in-params.[ch]: added new functions plug_in_param_defs_check() and plug_in_proc_args_check() which check if a procedure's parameters match its menu location (e.g. <Image> needs RUN-MODE, IMAGE, DRAWABLE). * app/plug-in/plug-in-message.c (plug_in_handle_proc_install): if registering an old-style (full) menu_path, use plug_in_param_defs_check(), set proc_def->menu_label otherwise. * tools/pdbgen/pdb/plug_in.pdb (plugin_menu_register): use plug_in_proc_args_check() on the passed menu_path and make sugre old and new style menu registration are not mixed. * app/pdb/plug_in_cmds.c: regenerated. * app/plug-in/plug-in-rc.c: save/restore "menu_label". * app/actions/file-dialog-actions.c * app/actions/plug-in-actions.c * app/menus/plug-in-menus.c: changed action/menu creation accordingly. Some hacks needed to allow both old and new style menu_label/menu_paths. * app/plug-in/plug-in.c * app/widgets/gimpfiledialog.c * app/xcf/xcf.c: changed accordingly. * plug-ins/common/align_layers.c * plug-ins/common/animationplay.c * plug-ins/common/animoptimize.c * plug-ins/common/apply_lens.c * plug-ins/common/autocrop.c * plug-ins/common/autostretch_hsv.c * plug-ins/common/blinds.c * plug-ins/common/blur.c * plug-ins/common/borderaverage.c * plug-ins/common/bumpmap.c * plug-ins/common/c_astretch.c * plug-ins/common/ccanalyze.c * plug-ins/common/channel_mixer.c * plug-ins/common/checkerboard.c * plug-ins/common/color_enhance.c * plug-ins/common/colorify.c * plug-ins/common/colortoalpha.c * plug-ins/common/compose.c * plug-ins/common/convmatrix.c * plug-ins/common/cubism.c * plug-ins/common/curve_bend.c * plug-ins/common/decompose.c * plug-ins/common/deinterlace.c * plug-ins/common/depthmerge.c * plug-ins/common/destripe.c * plug-ins/common/diffraction.c * plug-ins/common/displace.c * plug-ins/common/edge.c * plug-ins/common/emboss.c * plug-ins/common/engrave.c * plug-ins/common/exchange.c * plug-ins/common/film.c * plug-ins/common/flarefx.c * plug-ins/common/fractaltrace.c * plug-ins/common/screenshot.c: ported the first few plug-ins to the new registration scheme.
2004-05-07 00:30:24 +00:00
N_("_Playback..."),
"RGB*, INDEXED*, GRAY*",
GIMP_PLUGIN,
G_N_ELEMENTS (args), 0,
args, NULL);
Changed plug-in menu registration again to allow passing just the menu 2004-05-07 Michael Natterer <mitch@gimp.org> Changed plug-in menu registration again to allow passing just the menu item's label (not the full path) in gimp_install_procedure() and only the path (excluding the item's label) in gimp_plugin_menu_register(). Matches the internal action system better and makes translating the menu paths much easier. (Of yourse it's still possible to use the old syntax for backward compatibility). * app/plug-in/plug-in-proc.[ch]: added "gchar *menu_label". * app/plug-in/plug-in-params.[ch]: added new functions plug_in_param_defs_check() and plug_in_proc_args_check() which check if a procedure's parameters match its menu location (e.g. <Image> needs RUN-MODE, IMAGE, DRAWABLE). * app/plug-in/plug-in-message.c (plug_in_handle_proc_install): if registering an old-style (full) menu_path, use plug_in_param_defs_check(), set proc_def->menu_label otherwise. * tools/pdbgen/pdb/plug_in.pdb (plugin_menu_register): use plug_in_proc_args_check() on the passed menu_path and make sugre old and new style menu registration are not mixed. * app/pdb/plug_in_cmds.c: regenerated. * app/plug-in/plug-in-rc.c: save/restore "menu_label". * app/actions/file-dialog-actions.c * app/actions/plug-in-actions.c * app/menus/plug-in-menus.c: changed action/menu creation accordingly. Some hacks needed to allow both old and new style menu_label/menu_paths. * app/plug-in/plug-in.c * app/widgets/gimpfiledialog.c * app/xcf/xcf.c: changed accordingly. * plug-ins/common/align_layers.c * plug-ins/common/animationplay.c * plug-ins/common/animoptimize.c * plug-ins/common/apply_lens.c * plug-ins/common/autocrop.c * plug-ins/common/autostretch_hsv.c * plug-ins/common/blinds.c * plug-ins/common/blur.c * plug-ins/common/borderaverage.c * plug-ins/common/bumpmap.c * plug-ins/common/c_astretch.c * plug-ins/common/ccanalyze.c * plug-ins/common/channel_mixer.c * plug-ins/common/checkerboard.c * plug-ins/common/color_enhance.c * plug-ins/common/colorify.c * plug-ins/common/colortoalpha.c * plug-ins/common/compose.c * plug-ins/common/convmatrix.c * plug-ins/common/cubism.c * plug-ins/common/curve_bend.c * plug-ins/common/decompose.c * plug-ins/common/deinterlace.c * plug-ins/common/depthmerge.c * plug-ins/common/destripe.c * plug-ins/common/diffraction.c * plug-ins/common/displace.c * plug-ins/common/edge.c * plug-ins/common/emboss.c * plug-ins/common/engrave.c * plug-ins/common/exchange.c * plug-ins/common/film.c * plug-ins/common/flarefx.c * plug-ins/common/fractaltrace.c * plug-ins/common/screenshot.c: ported the first few plug-ins to the new registration scheme.
2004-05-07 00:30:24 +00:00
gimp_plugin_menu_register ("plug_in_animationplay",
"<Image>/Filters/Animation");
1997-11-24 22:05:25 +00:00
}
static void
run (const gchar *name,
gint n_params,
const GimpParam *param,
gint *nreturn_vals,
GimpParam **return_vals)
1997-11-24 22:05:25 +00:00
{
static GimpParam values[1];
GimpRunMode run_mode;
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
1997-11-24 22:05:25 +00:00
*nreturn_vals = 1;
*return_vals = values;
run_mode = param[0].data.d_int32;
INIT_I18N ();
if (run_mode == GIMP_RUN_NONINTERACTIVE && n_params != 3)
{
status = GIMP_PDB_CALLING_ERROR;
}
1997-11-24 22:05:25 +00:00
if (status == GIMP_PDB_SUCCESS)
{
image_id = param[1].data.d_image;
do_playback();
if (run_mode != GIMP_RUN_NONINTERACTIVE)
gimp_displays_flush();
}
1997-11-24 22:05:25 +00:00
values[0].type = GIMP_PDB_STATUS;
1997-11-24 22:05:25 +00:00
values[0].data.d_status = status;
}
static void
reshape_from_bitmap (gchar* bitmap)
{
GdkBitmap *shape_mask;
static gchar *prev_bitmap = NULL;
if ((!prev_bitmap) ||
(memcmp(prev_bitmap, bitmap, (width*height)/8 +height)))
{
shape_mask = gdk_bitmap_create_from_data (shape_window->window,
bitmap,
width, height);
gtk_widget_shape_combine_mask (shape_window, shape_mask, 0, 0);
g_object_unref (shape_mask);
if (!prev_bitmap)
{
prev_bitmap = g_malloc ((width * height) / 8 + height);
}
memcpy (prev_bitmap, bitmap, (width * height) / 8 + height);
}
}
static gboolean
shape_pressed (GtkWidget *widget,
GdkEventButton *event)
{
CursorOffset *p;
/* ignore double and triple click */
if (event->type != GDK_BUTTON_PRESS)
return FALSE;
p = g_object_get_data (G_OBJECT(widget), "cursor-offset");
if (!p)
return FALSE;
p->x = (int) event->x;
p->y = (int) event->y;
gtk_grab_add (widget);
gdk_pointer_grab (widget->window, TRUE,
GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON_MOTION_MASK |
GDK_POINTER_MOTION_HINT_MASK,
NULL, NULL, 0);
gdk_window_raise (widget->window);
return FALSE;
}
static gboolean
maybeblocked_expose (GtkWidget *widget,
GdkEventExpose *event)
{
if (playing)
return TRUE;
return repaint_sda (widget, event, NULL);
}
static gboolean
shape_released (GtkWidget *widget)
{
gtk_grab_remove (widget);
gdk_display_pointer_ungrab (gtk_widget_get_display (widget), 0);
gdk_flush ();
return FALSE;
}
static gboolean
shape_motion (GtkWidget *widget,
GdkEventMotion *event)
{
gint xp, yp;
CursorOffset *p;
GdkModifierType mask;
gdk_window_get_pointer (root_win, &xp, &yp, &mask);
/* if a button is still held by the time we process this event... */
if (mask & (GDK_BUTTON1_MASK|
GDK_BUTTON2_MASK|
GDK_BUTTON3_MASK|
GDK_BUTTON4_MASK|
GDK_BUTTON5_MASK))
{
p = g_object_get_data (G_OBJECT (widget), "cursor-offset");
if (!p)
return FALSE;
gtk_window_move (GTK_WINDOW (widget), xp - p->x, yp - p->y);
}
else /* the user has released all buttons */
{
shape_released(widget);
}
return FALSE;
}
static gboolean
repaint_da (GtkWidget *darea,
GdkEventExpose *event,
gpointer data)
{
gdk_draw_rgb_image (drawing_area->window,
drawing_area->style->white_gc,
0, 0, width, height,
(total_frames==1) ? GDK_RGB_DITHER_MAX : DITHERTYPE,
drawing_area_data, width * 3);
return TRUE;
}
static gboolean
repaint_sda (GtkWidget *darea,
GdkEventExpose *event,
gpointer data)
{
gdk_draw_rgb_image (shape_drawing_area->window,
shape_drawing_area->style->white_gc,
0, 0, width, height,
(total_frames==1) ? GDK_RGB_DITHER_MAX : DITHERTYPE,
shape_drawing_area_data, width * 3);
return TRUE;
}
static gboolean
preview_pressed (GtkWidget *widget,
GdkEventButton *event)
{
gint xp, yp;
GdkModifierType mask;
if (shaping)
return FALSE;
/* Create a total-alpha buffer merely for the not-shaped
drawing area to now display. */
drawing_area_data = g_malloc (width * height * 3);
total_alpha_preview (drawing_area_data);
gdk_window_get_pointer (root_win, &xp, &yp, &mask);
gtk_window_move (GTK_WINDOW (shape_window), xp - event->x, yp - event->y);
gtk_widget_show (shape_window);
gdk_window_set_back_pixmap (shape_window->window, NULL, 0);
gdk_window_set_back_pixmap (shape_drawing_area->window, NULL, 1);
show_frame ();
shaping = 1;
memset (shape_preview_mask, 0, (width * height) / 8 + height);
render_frame (frame_number);
show_frame ();
repaint_da (NULL, NULL, NULL);
/* mildly amusing hack */
return shape_pressed (shape_window, event);
}
1997-11-24 22:05:25 +00:00
static void
build_dialog (GimpImageBaseType basetype,
gchar *imagename)
1997-11-24 22:05:25 +00:00
{
gchar *windowname;
CursorOffset *icon_pos;
GtkWidget *button;
GtkWidget *frame;
GtkWidget *frame2;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *hbox2;
GtkWidget *eventbox;
GdkCursor *cursor;
1997-11-24 22:05:25 +00:00
gimp_ui_init ("animationplay", TRUE);
1997-11-24 22:05:25 +00:00
windowname = g_strconcat (_("Animation Playback:"), " ", imagename, NULL);
dlg = gimp_dialog_new (windowname, "animationplay",
removed our own action_area API and use GtkDialog's one. Create all 2003-11-06 Michael Natterer <mitch@gimp.org> * libgimpwidgets/gimpdialog.[ch]: removed our own action_area API and use GtkDialog's one. Create all dialogs without separator. Changed almost everything else too. Fixes bug #125143. * libgimpwidgets/gimpquerybox.c * libgimpwidgets/gimpunitmenu.c: changed accordingly. * libgimp/gimpexport.[ch]: ditto. Renamed enum GimpExportReturnType to GimpExportReturn. * libgimp/gimpcompat.h: added a #define for the old name. * themes/Default/gtkrc: increased action_area border to 6 pixels. * app/display/gimpdisplayshell-filter-dialog.c * app/display/gimpdisplayshell-scale.c * app/display/gimpprogress.c * app/gui/brush-select.c * app/gui/channels-commands.c * app/gui/color-notebook.c * app/gui/convert-dialog.c * app/gui/file-new-dialog.c * app/gui/font-select.c * app/gui/gradient-editor-commands.c * app/gui/gradient-select.c * app/gui/grid-dialog.c * app/gui/image-commands.c * app/gui/info-window.c * app/gui/layers-commands.c * app/gui/module-browser.c * app/gui/offset-dialog.c * app/gui/palette-import-dialog.c * app/gui/palette-select.c * app/gui/pattern-select.c * app/gui/preferences-dialog.c * app/gui/qmask-commands.c * app/gui/resize-dialog.c * app/gui/resolution-calibrate-dialog.c * app/gui/stroke-dialog.c * app/gui/templates-commands.c * app/gui/user-install-dialog.c * app/gui/vectors-commands.c * app/tools/gimpcolorpickertool.c * app/tools/gimpcroptool.c * app/tools/gimpimagemaptool.c * app/tools/gimpmeasuretool.c * app/tools/gimptransformtool.c * app/widgets/gimptexteditor.c * app/widgets/gimptooldialog.[ch] * app/widgets/gimpviewabledialog.[ch] * app/widgets/gimpwidgets-utils.c: changed accordingly and increased the dialogs' outer borders to 6 pixels all over the place. * plug-ins/*/*.c: changed accordingly. The plug-ins may be arbitrarily broken, I tested none of them.
2003-11-06 15:27:05 +00:00
NULL, 0,
gimp_standard_help_func, "plug-in-animationplay",
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
NULL);
g_free (windowname);
removed our own action_area API and use GtkDialog's one. Create all 2003-11-06 Michael Natterer <mitch@gimp.org> * libgimpwidgets/gimpdialog.[ch]: removed our own action_area API and use GtkDialog's one. Create all dialogs without separator. Changed almost everything else too. Fixes bug #125143. * libgimpwidgets/gimpquerybox.c * libgimpwidgets/gimpunitmenu.c: changed accordingly. * libgimp/gimpexport.[ch]: ditto. Renamed enum GimpExportReturnType to GimpExportReturn. * libgimp/gimpcompat.h: added a #define for the old name. * themes/Default/gtkrc: increased action_area border to 6 pixels. * app/display/gimpdisplayshell-filter-dialog.c * app/display/gimpdisplayshell-scale.c * app/display/gimpprogress.c * app/gui/brush-select.c * app/gui/channels-commands.c * app/gui/color-notebook.c * app/gui/convert-dialog.c * app/gui/file-new-dialog.c * app/gui/font-select.c * app/gui/gradient-editor-commands.c * app/gui/gradient-select.c * app/gui/grid-dialog.c * app/gui/image-commands.c * app/gui/info-window.c * app/gui/layers-commands.c * app/gui/module-browser.c * app/gui/offset-dialog.c * app/gui/palette-import-dialog.c * app/gui/palette-select.c * app/gui/pattern-select.c * app/gui/preferences-dialog.c * app/gui/qmask-commands.c * app/gui/resize-dialog.c * app/gui/resolution-calibrate-dialog.c * app/gui/stroke-dialog.c * app/gui/templates-commands.c * app/gui/user-install-dialog.c * app/gui/vectors-commands.c * app/tools/gimpcolorpickertool.c * app/tools/gimpcroptool.c * app/tools/gimpimagemaptool.c * app/tools/gimpmeasuretool.c * app/tools/gimptransformtool.c * app/widgets/gimptexteditor.c * app/widgets/gimptooldialog.[ch] * app/widgets/gimpviewabledialog.[ch] * app/widgets/gimpwidgets-utils.c: changed accordingly and increased the dialogs' outer borders to 6 pixels all over the place. * plug-ins/*/*.c: changed accordingly. The plug-ins may be arbitrarily broken, I tested none of them.
2003-11-06 15:27:05 +00:00
g_signal_connect (dlg, "response",
G_CALLBACK (window_response),
NULL);
/* The 'playback' half of the dialog */
if (total_frames > 1)
windowname = g_strconcat (_("Playback:"), " ",imagename, NULL);
else
windowname = g_strdup (imagename);
frame = gimp_frame_new (windowname);
g_free (windowname);
gtk_container_set_border_width (GTK_CONTAINER (frame), 12);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox),
frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
hbox = gtk_hbox_new (FALSE, 6);
gtk_container_add (GTK_CONTAINER (frame), hbox);
gtk_widget_show (hbox);
vbox = gtk_vbox_new (FALSE, 6);
gtk_container_add (GTK_CONTAINER (hbox), vbox);
gtk_widget_show (vbox);
hbox2 = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox2, TRUE, TRUE, 0);
if (total_frames > 1)
gtk_widget_show (hbox2);
psbutton = gtk_toggle_button_new_with_label ( _("Play/Stop"));
g_signal_connect (psbutton, "toggled",
G_CALLBACK (playstop_callback), NULL);
gtk_box_pack_start (GTK_BOX (hbox2), psbutton, TRUE, TRUE, 0);
gtk_widget_show (psbutton);
button = gtk_button_new_with_label ( _("Rewind"));
g_signal_connect (button, "clicked",
G_CALLBACK (rewind_callback), NULL);
gtk_box_pack_start (GTK_BOX (hbox2), button, TRUE, TRUE, 0);
gtk_widget_show (button);
button = gtk_button_new_with_label ( _("Step"));
g_signal_connect (button, "clicked",
G_CALLBACK (step_callback), NULL);
gtk_box_pack_start (GTK_BOX (hbox2), button, TRUE, TRUE, 0);
gtk_widget_show (button);
hbox2 = gtk_hbox_new (TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0);
gtk_widget_show (hbox2);
frame2 = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (hbox2), frame2, FALSE, FALSE, 0);
gtk_widget_show (frame2);
eventbox = gtk_event_box_new();
gtk_widget_add_events (eventbox, GDK_BUTTON_PRESS_MASK);
gtk_container_add (GTK_CONTAINER (frame2), GTK_WIDGET (eventbox));
gtk_widget_show (eventbox);
drawing_area = gtk_drawing_area_new ();
gtk_widget_set_size_request (drawing_area, width, height);
gtk_container_add (GTK_CONTAINER (eventbox), GTK_WIDGET (drawing_area));
gtk_widget_show (drawing_area);
progress = GTK_PROGRESS_BAR (gtk_progress_bar_new ());
gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (progress), TRUE, TRUE, 0);
if (total_frames > 1)
gtk_widget_show (GTK_WIDGET (progress));
gtk_widget_show (dlg);
/* let's get into shape. */
shape_window = gtk_window_new (GTK_WINDOW_POPUP);
shape_drawing_area = gtk_drawing_area_new ();
gtk_widget_set_size_request (shape_drawing_area, width, height);
gtk_container_add (GTK_CONTAINER (shape_window), shape_drawing_area);
gtk_widget_show (shape_drawing_area);
gtk_widget_add_events (shape_drawing_area, GDK_BUTTON_PRESS_MASK);
gtk_widget_realize (shape_window);
gdk_window_set_back_pixmap (shape_window->window, NULL, 0);
cursor = gdk_cursor_new_for_display (gtk_widget_get_display (shape_window),
GDK_CENTER_PTR);
gdk_window_set_cursor(shape_window->window, cursor);
gdk_cursor_unref (cursor);
g_signal_connect (shape_window, "button_press_event",
G_CALLBACK (shape_pressed),NULL);
g_signal_connect (shape_window, "button_release_event",
G_CALLBACK (shape_released),NULL);
g_signal_connect (shape_window, "motion_notify_event",
G_CALLBACK (shape_motion),NULL);
icon_pos = g_new (CursorOffset, 1);
g_object_set_data (G_OBJECT (shape_window), "cursor-offset", icon_pos);
/* gtk_widget_show (shape_window);*/
g_signal_connect (eventbox, "button_press_event",
G_CALLBACK (preview_pressed), NULL);
g_signal_connect (drawing_area, "expose_event",
G_CALLBACK (repaint_da), drawing_area);
g_signal_connect (shape_drawing_area, "expose_event",
G_CALLBACK (maybeblocked_expose), shape_drawing_area);
root_win = gdk_get_default_root_window ();
1997-11-24 22:05:25 +00:00
}
static void
do_playback (void)
1997-11-24 22:05:25 +00:00
{
width = gimp_image_width (image_id);
height = gimp_image_height (image_id);
1997-11-24 22:05:25 +00:00
layers = gimp_image_get_layers (image_id, &total_frames);
imagetype = gimp_image_base_type (image_id);
1997-11-24 22:05:25 +00:00
if (imagetype == GIMP_INDEXED)
{
palette = gimp_image_get_colormap (image_id, &ncolours);
}
else if (imagetype == GIMP_GRAY)
1997-11-24 22:05:25 +00:00
{
gint i;
1997-11-24 22:05:25 +00:00
palette = g_malloc(768);
for (i = 0; i < 256; i++)
palette[i*3] = palette[i*3+1] = palette[i*3+2] = i;
1997-11-24 22:05:25 +00:00
ncolours = 256;
}
frame_number = 0;
1997-11-24 22:05:25 +00:00
/* cache hint "cache nothing", since we iterate over every
tile in every layer. */
gimp_tile_cache_size (0);
init_preview_misc ();
build_dialog (gimp_image_base_type (image_id),
gimp_image_get_name (image_id));
1997-11-24 22:05:25 +00:00
/* Make sure that whole preview is dirtied with pure-alpha */
total_alpha_preview (preview_data);
render_frame (0);
show_frame ();
1997-11-24 22:05:25 +00:00
gtk_main ();
gdk_flush ();
}
/* Rendering Functions */
static void
render_frame (gint32 whichframe)
1997-11-24 22:05:25 +00:00
{
GimpPixelRgn pixel_rgn;
1997-11-24 22:05:25 +00:00
static guchar *rawframe = NULL;
static gint rawwidth = 0, rawheight = 0, rawbpp = 0;
gint rawx = 0, rawy = 0;
guchar *srcptr;
guchar *destptr;
gint i, j, k; /* imaginative loop variables */
DisposeType dispose;
1997-11-24 22:05:25 +00:00
if (whichframe >= total_frames)
{
printf( "playback: Asked for frame number %d in a %d-frame animation!\n",
(int) (whichframe+1), (int) total_frames);
gimp_quit ();
1997-11-24 22:05:25 +00:00
}
drawable = gimp_drawable_get (layers[total_frames - (whichframe + 1)]);
/* Lame attempt to catch the case that a user has closed the image. */
if (! (drawable->width > 0 && drawable->height > 0))
{
gtk_main_quit ();
return;
}
1997-11-24 22:05:25 +00:00
dispose = get_frame_disposal (frame_number);
1997-11-24 22:05:25 +00:00
/* Image has been closed/etc since we got the layer list? */
/* FIXME - How do we tell if a gimp_drawable_get() fails? */
if (gimp_drawable_width (drawable->drawable_id) == 0)
removed our own action_area API and use GtkDialog's one. Create all 2003-11-06 Michael Natterer <mitch@gimp.org> * libgimpwidgets/gimpdialog.[ch]: removed our own action_area API and use GtkDialog's one. Create all dialogs without separator. Changed almost everything else too. Fixes bug #125143. * libgimpwidgets/gimpquerybox.c * libgimpwidgets/gimpunitmenu.c: changed accordingly. * libgimp/gimpexport.[ch]: ditto. Renamed enum GimpExportReturnType to GimpExportReturn. * libgimp/gimpcompat.h: added a #define for the old name. * themes/Default/gtkrc: increased action_area border to 6 pixels. * app/display/gimpdisplayshell-filter-dialog.c * app/display/gimpdisplayshell-scale.c * app/display/gimpprogress.c * app/gui/brush-select.c * app/gui/channels-commands.c * app/gui/color-notebook.c * app/gui/convert-dialog.c * app/gui/file-new-dialog.c * app/gui/font-select.c * app/gui/gradient-editor-commands.c * app/gui/gradient-select.c * app/gui/grid-dialog.c * app/gui/image-commands.c * app/gui/info-window.c * app/gui/layers-commands.c * app/gui/module-browser.c * app/gui/offset-dialog.c * app/gui/palette-import-dialog.c * app/gui/palette-select.c * app/gui/pattern-select.c * app/gui/preferences-dialog.c * app/gui/qmask-commands.c * app/gui/resize-dialog.c * app/gui/resolution-calibrate-dialog.c * app/gui/stroke-dialog.c * app/gui/templates-commands.c * app/gui/user-install-dialog.c * app/gui/vectors-commands.c * app/tools/gimpcolorpickertool.c * app/tools/gimpcroptool.c * app/tools/gimpimagemaptool.c * app/tools/gimpmeasuretool.c * app/tools/gimptransformtool.c * app/widgets/gimptexteditor.c * app/widgets/gimptooldialog.[ch] * app/widgets/gimpviewabledialog.[ch] * app/widgets/gimpwidgets-utils.c: changed accordingly and increased the dialogs' outer borders to 6 pixels all over the place. * plug-ins/*/*.c: changed accordingly. The plug-ins may be arbitrarily broken, I tested none of them.
2003-11-06 15:27:05 +00:00
gtk_dialog_response (GTK_DIALOG (dlg), GTK_RESPONSE_CLOSE);
1997-11-24 22:05:25 +00:00
if (((dispose==DISPOSE_REPLACE) || (whichframe==0)) &&
gimp_drawable_has_alpha (drawable->drawable_id))
1997-11-24 22:05:25 +00:00
{
total_alpha_preview (preview_data);
1997-11-24 22:05:25 +00:00
}
/* only get a new 'raw' drawable-data buffer if this and
the previous raw buffer were different sizes*/
if ((rawwidth * rawheight * rawbpp)
1997-11-24 22:05:25 +00:00
!=
((gimp_drawable_width (drawable->drawable_id) *
gimp_drawable_height (drawable->drawable_id) *
gimp_drawable_bpp (drawable->drawable_id))))
1997-11-24 22:05:25 +00:00
{
if (rawframe != NULL)
g_free (rawframe);
rawframe = g_malloc ((gimp_drawable_width (drawable->drawable_id)) *
(gimp_drawable_height (drawable->drawable_id)) *
(gimp_drawable_bpp (drawable->drawable_id)));
1997-11-24 22:05:25 +00:00
}
rawwidth = gimp_drawable_width (drawable->drawable_id);
rawheight = gimp_drawable_height (drawable->drawable_id);
rawbpp = gimp_drawable_bpp (drawable->drawable_id);
1997-11-24 22:05:25 +00:00
/* Initialise and fetch the whole raw new frame */
gimp_pixel_rgn_init (&pixel_rgn, drawable,
0, 0, drawable->width, drawable->height,
FALSE, FALSE);
gimp_pixel_rgn_get_rect (&pixel_rgn, rawframe,
0, 0, drawable->width, drawable->height);
1997-11-24 22:05:25 +00:00
gimp_drawable_offsets (drawable->drawable_id, &rawx, &rawy);
1997-11-24 22:05:25 +00:00
/* render... */
switch (imagetype)
{
case GIMP_RGB:
if ((rawwidth == width) &&
(rawheight == height) &&
(rawx == 0) &&
(rawy == 0))
{
/* --- These cases are for the best cases, in --- */
/* --- which this frame is the same size and position --- */
/* --- as the preview buffer itself --- */
if (gimp_drawable_has_alpha (drawable->drawable_id))
{ /* alpha */
destptr = preview_data;
srcptr = rawframe;
i = rawwidth * rawheight;
while (i--)
{
if (! (srcptr[3] & 128))
{
srcptr += 4;
destptr += 3;
continue;
}
*(destptr++) = *(srcptr++);
*(destptr++) = *(srcptr++);
*(destptr++) = *(srcptr++);
srcptr++;
}
/* calculate the shape mask */
if (shaping)
{
srcptr = rawframe + 3;
for (j = 0; j < rawheight; j++)
{
k = j * ((7 + rawwidth) / 8);
for (i = 0; i < rawwidth; i++)
{
if ((*srcptr) & 128)
shape_preview_mask[k + i/8] |= (1 << (i&7));
srcptr += 4;
}
}
}
}
else /* no alpha */
{
if ((rawwidth == width) && (rawheight == height))
{
memcpy (preview_data, rawframe, width * height * 3);
}
if (shaping)
{
/* opacify the shape mask */
memset (shape_preview_mask, 255,
(rawwidth * rawheight) / 8 + rawheight);
}
}
/* Display the preview buffer... finally. */
if (shaping)
{
reshape_from_bitmap (shape_preview_mask);
gdk_draw_rgb_image (shape_drawing_area->window,
shape_drawing_area->style->white_gc,
0, 0, width, height,
(total_frames == 1) ?
GDK_RGB_DITHER_MAX : DITHERTYPE,
preview_data, width * 3);
}
else
{
reshape_from_bitmap (shape_preview_mask);
gdk_draw_rgb_image (drawing_area->window,
drawing_area->style->white_gc,
0, 0, width, height,
(total_frames == 1) ?
GDK_RGB_DITHER_MAX : DITHERTYPE,
preview_data, width * 3);
}
}
1997-11-24 22:05:25 +00:00
else
{
/* --- These are suboptimal catch-all cases for when --- */
/* --- this frame is bigger/smaller than the preview --- */
/* --- buffer, and/or offset within it. --- */
if (gimp_drawable_has_alpha (drawable->drawable_id))
{ /* alpha */
srcptr = rawframe;
for (j = rawy; j < rawheight + rawy; j++)
{
for (i = rawx; i < rawwidth + rawx; i++)
{
if ((i >= 0 && i < width) &&
(j >= 0 && j < height))
{
if (srcptr[3] & 128)
{
preview_data[(j * width + i)*3 ] = *(srcptr);
preview_data[(j * width + i)*3 + 1] = *(srcptr+1);
preview_data[(j * width + i)*3 + 2] = *(srcptr+2);
}
}
srcptr += 4;
}
}
if (shaping)
{
srcptr = rawframe + 3;
for (j=rawy; j<rawheight+rawy; j++)
{
k = j * ((width+7)/8);
for (i=rawx; i<rawwidth+rawx; i++)
{
if ((i>=0 && i<width) &&
(j>=0 && j<height))
{
if ((*srcptr)&128)
shape_preview_mask[k + i/8] |= (1 << (i&7));
}
srcptr += 4;
}
}
}
}
else
{
/* noalpha */
srcptr = rawframe;
for (j = rawy; j < rawheight + rawy; j++)
{
for (i = rawx; i < rawwidth + rawx; i++)
{
if ((i >= 0 && i < width) &&
(j >= 0 && j < height))
{
preview_data[(j * width + i) * 3 ] = *(srcptr);
preview_data[(j * width + i) * 3 + 1] = *(srcptr + 1);
preview_data[(j * width + i) * 3 + 2] = *(srcptr + 2);
}
srcptr += 3;
}
}
}
/* Display the preview buffer... finally. */
if (shaping)
{
if ((dispose != DISPOSE_REPLACE) && (whichframe != 0))
{
int top, bottom;
top = (rawy < 0) ? 0 : rawy;
bottom = ((rawy + rawheight) < height ?
(rawy + rawheight) : height - 1);
reshape_from_bitmap (shape_preview_mask);
gdk_draw_rgb_image (shape_drawing_area->window,
shape_drawing_area->style->white_gc,
0, top, width, bottom-top,
(total_frames == 1) ?
GDK_RGB_DITHER_MAX : DITHERTYPE,
preview_data + 3 * top * width,
width * 3);
}
else
{
reshape_from_bitmap (shape_preview_mask);
gdk_draw_rgb_image (shape_drawing_area->window,
shape_drawing_area->style->white_gc,
0, 0, width, height,
(total_frames == 1) ?
GDK_RGB_DITHER_MAX : DITHERTYPE,
preview_data, width * 3);
}
}
else
{
if ((dispose != DISPOSE_REPLACE) && (whichframe != 0))
{
int top, bottom;
top = (rawy < 0) ? 0 : rawy;
bottom = ((rawy + rawheight) < height ?
(rawy + rawheight) : height - 1);
gdk_draw_rgb_image (drawing_area->window,
drawing_area->style->white_gc,
0, top, width, bottom-top,
(total_frames == 1) ?
GDK_RGB_DITHER_MAX : DITHERTYPE,
preview_data + 3 * top * width,
width * 3);
}
else
{
gdk_draw_rgb_image (drawing_area->window,
drawing_area->style->white_gc,
0, 0, width, height,
(total_frames == 1) ?
GDK_RGB_DITHER_MAX : DITHERTYPE,
preview_data, width * 3);
}
}
}
1997-11-24 22:05:25 +00:00
break;
case GIMP_GRAY:
case GIMP_INDEXED:
1997-11-24 22:05:25 +00:00
if ((rawwidth==width) &&
(rawheight==height) &&
(rawx==0) &&
(rawy==0))
{
/* --- These cases are for the best cases, in --- */
/* --- which this frame is the same size and position --- */
/* --- as the preview buffer itself --- */
if (gimp_drawable_has_alpha (drawable->drawable_id))
{ /* alpha */
destptr = preview_data;
srcptr = rawframe;
i = rawwidth*rawheight;
while (i--)
{
if (! srcptr[1])
{
srcptr += 2;
destptr += 3;
continue;
}
*(destptr++) = palette[0 + 3 * (*(srcptr))];
*(destptr++) = palette[1 + 3 * (*(srcptr))];
*(destptr++) = palette[2 + 3 * (*(srcptr))];
srcptr+=2;
}
/* calculate the shape mask */
if (shaping)
{
srcptr = rawframe + 1;
for (j = 0; j < rawheight; j++)
{
k = j * ((7 + rawwidth) / 8);
for (i = 0; i < rawwidth; i++)
{
if (*srcptr)
shape_preview_mask[k + i/8] |= (1 << (i&7));
srcptr += 2;
}
}
}
}
else /* no alpha */
{
destptr = preview_data;
srcptr = rawframe;
i = rawwidth * rawheight;
while (--i)
{
*(destptr++) = palette[0 + 3 * (*(srcptr))];
*(destptr++) = palette[1 + 3 * (*(srcptr))];
*(destptr++) = palette[2 + 3 * (*(srcptr))];
srcptr++;
}
if (shaping)
{
/* opacify the shape mask */
memset (shape_preview_mask, 255,
(rawwidth * rawheight) / 8 + rawheight);
}
}
/* Display the preview buffer... finally. */
if (shaping)
{
reshape_from_bitmap (shape_preview_mask);
gdk_draw_rgb_image (shape_drawing_area->window,
shape_drawing_area->style->white_gc,
0, 0, width, height,
(total_frames == 1)
? GDK_RGB_DITHER_MAX : DITHERTYPE,
preview_data, width * 3);
}
else
{
gdk_draw_rgb_image (drawing_area->window,
drawing_area->style->white_gc,
0, 0, width, height,
(total_frames == 1) ?
GDK_RGB_DITHER_MAX : DITHERTYPE,
preview_data, width * 3);
}
}
1997-11-24 22:05:25 +00:00
else
{
/* --- These are suboptimal catch-all cases for when --- */
/* --- this frame is bigger/smaller than the preview --- */
/* --- buffer, and/or offset within it. --- */
if (gimp_drawable_has_alpha (drawable->drawable_id))
{ /* alpha */
srcptr = rawframe;
for (j = rawy; j < rawheight + rawy; j++)
{
for (i = rawx; i < rawwidth + rawx; i++)
{
if ((i >= 0 && i < width) &&
(j >= 0 && j < height))
{
if (*(srcptr+1))
{
preview_data[(j * width + i) * 3 + 0] =
palette[0 + 3 * (*(srcptr))];
preview_data[(j * width + i) * 3 + 1] =
palette[1 + 3 * (*(srcptr))];
preview_data[(j * width + i) * 3 + 2] =
palette[2 + 3 * (*(srcptr))];
}
}
srcptr += 2;
}
}
if (shaping)
{
srcptr = rawframe + 1;
for (j=rawy; j<rawheight+rawy; j++)
{
k = j * ((width + 7) / 8);
for (i = rawx; i < rawwidth + rawx; i++)
{
if ((i >= 0 && i < width) &&
(j >= 0 && j < height))
{
if (*srcptr)
shape_preview_mask[k + i/8] |= (1 << (i&7));
}
srcptr += 2;
}
}
}
}
else
{
/* noalpha */
srcptr = rawframe;
for (j = rawy; j < rawheight + rawy; j++)
{
for (i = rawx; i < rawwidth + rawx; i++)
{
if ((i >= 0 && i < width) &&
(j >= 0 && j < height))
{
preview_data[(j * width + i) * 3 + 0] =
palette[0 + 3 * (*(srcptr))];
preview_data[(j * width + i) * 3 + 1] =
palette[1 + 3 * (*(srcptr))];
preview_data[(j * width + i) * 3 + 2] =
palette[2 + 3 * (*(srcptr))];
}
srcptr ++;
}
}
}
/* Display the preview buffer... finally. */
if (shaping)
{
if ((dispose != DISPOSE_REPLACE) && (whichframe != 0))
{
int top, bottom;
top = (rawy < 0) ? 0 : rawy;
bottom = ((rawy + rawheight) < height ?
(rawy + rawheight) : height - 1);
reshape_from_bitmap (shape_preview_mask);
gdk_draw_rgb_image (shape_drawing_area->window,
shape_drawing_area->style->white_gc,
0, top, width, bottom-top,
(total_frames == 1) ?
GDK_RGB_DITHER_MAX : DITHERTYPE,
preview_data + 3 * top * width,
width * 3);
}
else
{
reshape_from_bitmap (shape_preview_mask);
gdk_draw_rgb_image (shape_drawing_area->window,
shape_drawing_area->style->white_gc,
0, 0, width, height,
(total_frames==1)?GDK_RGB_DITHER_MAX
:DITHERTYPE,
preview_data, width * 3);
}
}
else
{
if ((dispose != DISPOSE_REPLACE) && (whichframe != 0))
{
int top, bottom;
top = (rawy < 0) ? 0 : rawy;
bottom = ((rawy + rawheight) < height ?
(rawy + rawheight) : height - 1);
gdk_draw_rgb_image (drawing_area->window,
drawing_area->style->white_gc,
0, top, width, bottom-top,
(total_frames == 1) ?
GDK_RGB_DITHER_MAX : DITHERTYPE,
preview_data + 3 * top * width,
width * 3);
}
else
{
gdk_draw_rgb_image (drawing_area->window,
drawing_area->style->white_gc,
0, 0, width, height,
(total_frames == 1) ?
GDK_RGB_DITHER_MAX : DITHERTYPE,
preview_data, width * 3);
}
}
}
1997-11-24 22:05:25 +00:00
break;
1997-11-24 22:05:25 +00:00
}
/* clean up */
gimp_drawable_detach (drawable);
1997-11-24 22:05:25 +00:00
}
static void
show_frame (void)
1997-11-24 22:05:25 +00:00
{
gchar *text;
1997-11-24 22:05:25 +00:00
/* update the dialog's progress bar */
gtk_progress_bar_set_fraction (progress,
((float) frame_number /
(float) (total_frames - 0.999)));
text = g_strdup_printf (_("Frame %d of %d"), frame_number + 1, total_frames);
gtk_progress_bar_set_text (progress, text);
g_free (text);
1997-11-24 22:05:25 +00:00
}
static void
init_preview_misc (void)
1997-11-24 22:05:25 +00:00
{
int i;
preview_data = g_malloc (width * height * 3);
shape_preview_mask = g_malloc ((width * height) / 8 + 1 + height);
preview_alpha1_data = g_malloc (width * 3);
preview_alpha2_data = g_malloc (width * 3);
1997-11-24 22:05:25 +00:00
for (i=0;i<width;i++)
{
if (i&8)
{
preview_alpha1_data[i*3 + 0] =
preview_alpha1_data[i*3 + 1] =
preview_alpha1_data[i*3 + 2] = 102;
preview_alpha2_data[i*3 + 0] =
preview_alpha2_data[i*3 + 1] =
preview_alpha2_data[i*3 + 2] = 154;
}
1997-11-24 22:05:25 +00:00
else
{
preview_alpha1_data[i*3 + 0] =
preview_alpha1_data[i*3 + 1] =
preview_alpha1_data[i*3 + 2] = 154;
preview_alpha2_data[i*3 + 0] =
preview_alpha2_data[i*3 + 1] =
preview_alpha2_data[i*3 + 2] = 102;
}
1997-11-24 22:05:25 +00:00
}
drawing_area_data = preview_data;
shape_drawing_area_data = preview_data;
1997-11-24 22:05:25 +00:00
}
static void
total_alpha_preview (guchar* ptr)
1997-11-24 22:05:25 +00:00
{
if (shaping)
1997-11-24 22:05:25 +00:00
{
memset(shape_preview_mask, 0, (width * height) / 8 + height);
}
else
{
gint i;
for (i = 0;i < height; i++)
{
if (i & 8)
memcpy (&ptr[i * 3 * width], preview_alpha1_data, 3 * width);
else
memcpy (&ptr[i * 3 * width], preview_alpha2_data, 3 * width);
}
1997-11-24 22:05:25 +00:00
}
}
/* Util. */
static void
remove_timer (void)
1997-11-24 22:05:25 +00:00
{
if (timer)
{
g_source_remove (timer);
1997-11-24 22:05:25 +00:00
timer = 0;
}
}
static void
do_step (void)
1997-11-24 22:05:25 +00:00
{
frame_number = (frame_number+1)%total_frames;
render_frame (frame_number);
1997-11-24 22:05:25 +00:00
}
/* Callbacks */
removed our own action_area API and use GtkDialog's one. Create all 2003-11-06 Michael Natterer <mitch@gimp.org> * libgimpwidgets/gimpdialog.[ch]: removed our own action_area API and use GtkDialog's one. Create all dialogs without separator. Changed almost everything else too. Fixes bug #125143. * libgimpwidgets/gimpquerybox.c * libgimpwidgets/gimpunitmenu.c: changed accordingly. * libgimp/gimpexport.[ch]: ditto. Renamed enum GimpExportReturnType to GimpExportReturn. * libgimp/gimpcompat.h: added a #define for the old name. * themes/Default/gtkrc: increased action_area border to 6 pixels. * app/display/gimpdisplayshell-filter-dialog.c * app/display/gimpdisplayshell-scale.c * app/display/gimpprogress.c * app/gui/brush-select.c * app/gui/channels-commands.c * app/gui/color-notebook.c * app/gui/convert-dialog.c * app/gui/file-new-dialog.c * app/gui/font-select.c * app/gui/gradient-editor-commands.c * app/gui/gradient-select.c * app/gui/grid-dialog.c * app/gui/image-commands.c * app/gui/info-window.c * app/gui/layers-commands.c * app/gui/module-browser.c * app/gui/offset-dialog.c * app/gui/palette-import-dialog.c * app/gui/palette-select.c * app/gui/pattern-select.c * app/gui/preferences-dialog.c * app/gui/qmask-commands.c * app/gui/resize-dialog.c * app/gui/resolution-calibrate-dialog.c * app/gui/stroke-dialog.c * app/gui/templates-commands.c * app/gui/user-install-dialog.c * app/gui/vectors-commands.c * app/tools/gimpcolorpickertool.c * app/tools/gimpcroptool.c * app/tools/gimpimagemaptool.c * app/tools/gimpmeasuretool.c * app/tools/gimptransformtool.c * app/widgets/gimptexteditor.c * app/widgets/gimptooldialog.[ch] * app/widgets/gimpviewabledialog.[ch] * app/widgets/gimpwidgets-utils.c: changed accordingly and increased the dialogs' outer borders to 6 pixels all over the place. * plug-ins/*/*.c: changed accordingly. The plug-ins may be arbitrarily broken, I tested none of them.
2003-11-06 15:27:05 +00:00
static void
window_response (GtkWidget *widget,
gint response_id,
gpointer data)
1997-11-24 22:05:25 +00:00
{
removed our own action_area API and use GtkDialog's one. Create all 2003-11-06 Michael Natterer <mitch@gimp.org> * libgimpwidgets/gimpdialog.[ch]: removed our own action_area API and use GtkDialog's one. Create all dialogs without separator. Changed almost everything else too. Fixes bug #125143. * libgimpwidgets/gimpquerybox.c * libgimpwidgets/gimpunitmenu.c: changed accordingly. * libgimp/gimpexport.[ch]: ditto. Renamed enum GimpExportReturnType to GimpExportReturn. * libgimp/gimpcompat.h: added a #define for the old name. * themes/Default/gtkrc: increased action_area border to 6 pixels. * app/display/gimpdisplayshell-filter-dialog.c * app/display/gimpdisplayshell-scale.c * app/display/gimpprogress.c * app/gui/brush-select.c * app/gui/channels-commands.c * app/gui/color-notebook.c * app/gui/convert-dialog.c * app/gui/file-new-dialog.c * app/gui/font-select.c * app/gui/gradient-editor-commands.c * app/gui/gradient-select.c * app/gui/grid-dialog.c * app/gui/image-commands.c * app/gui/info-window.c * app/gui/layers-commands.c * app/gui/module-browser.c * app/gui/offset-dialog.c * app/gui/palette-import-dialog.c * app/gui/palette-select.c * app/gui/pattern-select.c * app/gui/preferences-dialog.c * app/gui/qmask-commands.c * app/gui/resize-dialog.c * app/gui/resolution-calibrate-dialog.c * app/gui/stroke-dialog.c * app/gui/templates-commands.c * app/gui/user-install-dialog.c * app/gui/vectors-commands.c * app/tools/gimpcolorpickertool.c * app/tools/gimpcroptool.c * app/tools/gimpimagemaptool.c * app/tools/gimpmeasuretool.c * app/tools/gimptransformtool.c * app/widgets/gimptexteditor.c * app/widgets/gimptooldialog.[ch] * app/widgets/gimpviewabledialog.[ch] * app/widgets/gimpwidgets-utils.c: changed accordingly and increased the dialogs' outer borders to 6 pixels all over the place. * plug-ins/*/*.c: changed accordingly. The plug-ins may be arbitrarily broken, I tested none of them.
2003-11-06 15:27:05 +00:00
gtk_widget_destroy (widget);
if (playing)
removed our own action_area API and use GtkDialog's one. Create all 2003-11-06 Michael Natterer <mitch@gimp.org> * libgimpwidgets/gimpdialog.[ch]: removed our own action_area API and use GtkDialog's one. Create all dialogs without separator. Changed almost everything else too. Fixes bug #125143. * libgimpwidgets/gimpquerybox.c * libgimpwidgets/gimpunitmenu.c: changed accordingly. * libgimp/gimpexport.[ch]: ditto. Renamed enum GimpExportReturnType to GimpExportReturn. * libgimp/gimpcompat.h: added a #define for the old name. * themes/Default/gtkrc: increased action_area border to 6 pixels. * app/display/gimpdisplayshell-filter-dialog.c * app/display/gimpdisplayshell-scale.c * app/display/gimpprogress.c * app/gui/brush-select.c * app/gui/channels-commands.c * app/gui/color-notebook.c * app/gui/convert-dialog.c * app/gui/file-new-dialog.c * app/gui/font-select.c * app/gui/gradient-editor-commands.c * app/gui/gradient-select.c * app/gui/grid-dialog.c * app/gui/image-commands.c * app/gui/info-window.c * app/gui/layers-commands.c * app/gui/module-browser.c * app/gui/offset-dialog.c * app/gui/palette-import-dialog.c * app/gui/palette-select.c * app/gui/pattern-select.c * app/gui/preferences-dialog.c * app/gui/qmask-commands.c * app/gui/resize-dialog.c * app/gui/resolution-calibrate-dialog.c * app/gui/stroke-dialog.c * app/gui/templates-commands.c * app/gui/user-install-dialog.c * app/gui/vectors-commands.c * app/tools/gimpcolorpickertool.c * app/tools/gimpcroptool.c * app/tools/gimpimagemaptool.c * app/tools/gimpmeasuretool.c * app/tools/gimptransformtool.c * app/widgets/gimptexteditor.c * app/widgets/gimptooldialog.[ch] * app/widgets/gimpviewabledialog.[ch] * app/widgets/gimpwidgets-utils.c: changed accordingly and increased the dialogs' outer borders to 6 pixels all over the place. * plug-ins/*/*.c: changed accordingly. The plug-ins may be arbitrarily broken, I tested none of them.
2003-11-06 15:27:05 +00:00
playstop_callback (NULL, NULL);
if (shape_window)
removed our own action_area API and use GtkDialog's one. Create all 2003-11-06 Michael Natterer <mitch@gimp.org> * libgimpwidgets/gimpdialog.[ch]: removed our own action_area API and use GtkDialog's one. Create all dialogs without separator. Changed almost everything else too. Fixes bug #125143. * libgimpwidgets/gimpquerybox.c * libgimpwidgets/gimpunitmenu.c: changed accordingly. * libgimp/gimpexport.[ch]: ditto. Renamed enum GimpExportReturnType to GimpExportReturn. * libgimp/gimpcompat.h: added a #define for the old name. * themes/Default/gtkrc: increased action_area border to 6 pixels. * app/display/gimpdisplayshell-filter-dialog.c * app/display/gimpdisplayshell-scale.c * app/display/gimpprogress.c * app/gui/brush-select.c * app/gui/channels-commands.c * app/gui/color-notebook.c * app/gui/convert-dialog.c * app/gui/file-new-dialog.c * app/gui/font-select.c * app/gui/gradient-editor-commands.c * app/gui/gradient-select.c * app/gui/grid-dialog.c * app/gui/image-commands.c * app/gui/info-window.c * app/gui/layers-commands.c * app/gui/module-browser.c * app/gui/offset-dialog.c * app/gui/palette-import-dialog.c * app/gui/palette-select.c * app/gui/pattern-select.c * app/gui/preferences-dialog.c * app/gui/qmask-commands.c * app/gui/resize-dialog.c * app/gui/resolution-calibrate-dialog.c * app/gui/stroke-dialog.c * app/gui/templates-commands.c * app/gui/user-install-dialog.c * app/gui/vectors-commands.c * app/tools/gimpcolorpickertool.c * app/tools/gimpcroptool.c * app/tools/gimpimagemaptool.c * app/tools/gimpmeasuretool.c * app/tools/gimptransformtool.c * app/widgets/gimptexteditor.c * app/widgets/gimptooldialog.[ch] * app/widgets/gimpviewabledialog.[ch] * app/widgets/gimpwidgets-utils.c: changed accordingly and increased the dialogs' outer borders to 6 pixels all over the place. * plug-ins/*/*.c: changed accordingly. The plug-ins may be arbitrarily broken, I tested none of them.
2003-11-06 15:27:05 +00:00
gtk_widget_destroy (GTK_WIDGET (shape_window));
gdk_flush ();
gtk_main_quit ();
1997-11-24 22:05:25 +00:00
}
static gint
advance_frame_callback (gpointer data)
1997-11-24 22:05:25 +00:00
{
remove_timer();
timer = g_timeout_add (get_frame_duration ((frame_number + 1) % total_frames),
advance_frame_callback, NULL);
do_step ();
show_frame ();
return FALSE;
1997-11-24 22:05:25 +00:00
}
static void
playstop_callback (GtkWidget *widget,
gpointer data)
1997-11-24 22:05:25 +00:00
{
if (!playing)
{ /* START PLAYING */
playing = TRUE;
timer = g_timeout_add (get_frame_duration (frame_number),
advance_frame_callback, NULL);
1997-11-24 22:05:25 +00:00
}
else
{ /* STOP PLAYING */
playing = FALSE;
remove_timer ();
1997-11-24 22:05:25 +00:00
}
}
static void
rewind_callback (GtkWidget *widget,
gpointer data)
1997-11-24 22:05:25 +00:00
{
if (playing)
{
playstop_callback (NULL, NULL); /* GTK weirdness workaround */
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psbutton), FALSE);
playing = FALSE;
remove_timer ();
}
1997-11-24 22:05:25 +00:00
frame_number = 0;
render_frame (frame_number);
show_frame ();
1997-11-24 22:05:25 +00:00
}
static void
step_callback (GtkWidget *widget,
gpointer data)
1997-11-24 22:05:25 +00:00
{
if (playing)
{
playstop_callback(NULL, NULL); /* GTK weirdness workaround */
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psbutton), FALSE);
playing = FALSE;
remove_timer();
}
1997-11-24 22:05:25 +00:00
do_step();
show_frame();
}
/* tag util. */
static DisposeType
get_frame_disposal (guint whichframe)
{
gchar *layer_name;
DisposeType disposal;
layer_name = gimp_drawable_get_name (layers[total_frames-(whichframe+1)]);
disposal = parse_disposal_tag (layer_name);
g_free (layer_name);
return disposal;
}
static guint32
get_frame_duration (guint whichframe)
{
gchar *layer_name;
gint duration = 0;
layer_name = gimp_drawable_get_name(layers[total_frames-(whichframe+1)]);
if (layer_name)
{
duration = parse_ms_tag(layer_name);
g_free(layer_name);
}
if (duration < 0) duration = 100; /* FIXME for default-if-not-said */
else
if (duration == 0) duration = 100; /* FIXME - 0-wait is nasty */
return (guint32) duration;
}
static gboolean
is_ms_tag (const char *str,
int *duration,
int *taglength)
{
gint sum = 0;
gint offset;
gint length;
length = strlen(str);
if (str[0] != '(')
return FALSE;
offset = 1;
/* eat any spaces between open-parenthesis and number */
while ((offset<length) && (str[offset] == ' '))
offset++;
if ((offset>=length) || (!g_ascii_isdigit (str[offset])))
return FALSE;
do
{
sum *= 10;
sum += str[offset] - '0';
offset++;
}
while ((offset<length) && (g_ascii_isdigit (str[offset])));
if (length - offset <= 2)
return FALSE;
/* eat any spaces between number and 'ms' */
while ((offset < length) && (str[offset] == ' '))
offset++;
if (length - offset <= 2 ||
g_ascii_toupper (str[offset]) != 'M' ||
g_ascii_toupper (str[offset + 1]) != 'S')
return FALSE;
offset += 2;
/* eat any spaces between 'ms' and close-parenthesis */
while ((offset < length) && (str[offset] == ' '))
offset++;
if ((length - offset < 1) || (str[offset] != ')'))
return FALSE;
offset++;
*duration = sum;
*taglength = offset;
return TRUE;
}
static int
parse_ms_tag (const char *str)
{
int i;
int rtn;
int dummy;
int length;
length = strlen (str);
for (i = 0; i < length; i++)
{
if (is_ms_tag (&str[i], &rtn, &dummy))
return rtn;
}
return -1;
}
static gboolean
is_disposal_tag (const char *str,
DisposeType *disposal,
int *taglength)
{
if (strlen (str) != 9)
return FALSE;
if (strncmp (str, "(combine)", 9) == 0)
{
*taglength = 9;
*disposal = DISPOSE_COMBINE;
return TRUE;
}
else if (strncmp (str, "(replace)", 9) == 0)
{
*taglength = 9;
*disposal = DISPOSE_REPLACE;
return TRUE;
}
return FALSE;
}
static DisposeType
parse_disposal_tag (const char *str)
{
DisposeType rtn;
int i, dummy;
gint length;
length = strlen(str);
for (i = 0; i < length; i++)
{
if (is_disposal_tag (&str[i], &rtn, &dummy))
{
return rtn;
}
}
return DISPOSE_UNDEFINED; /* FIXME */
}