gimp/plug-ins/gap/gap_mov_dialog.c

3261 lines
107 KiB
C

/* gap_mov_dialog.c
* by hof (Wolfgang Hofer)
*
* GAP ... Gimp Animation Plugins
*
* Dialog Window for Move Path (gap_mov)
*
*/
/* code was mainly inspired by SuperNova plug-in
* Copyright (C) 1997 Eiichi Takamori <taka@ma1.seikyou.ne.jp>,
* Spencer Kimball, Federico Mena Quintero
*/
/* 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.
*/
/* revision history:
* gimp 1.1.29b; 2000/11/30 hof: new feature: FRAME based Stepmodes, changes for NONINTERACTIVE mode
* gimp 1.1.23a; 2000/06/04 hof: new button: rotation follow path
* gimp 1.1.20a; 2000/04/25 hof: support for keyframes, anim_preview (suggested by jakub steiner)
* gimp 1.1.17b; 2000/02/23 hof: bugfix: dont flatten the preview, just merge visible layers
* bugfix: for current frame never use diskfile for the preview
* (to avoid inconsitencies, and to speed up a little)
* added "Show Path", pick and drag Controlpoints
* gimp 1.1.17a; 2000/02/20 hof: use gimp_help_set_help_data for tooltips
* added spinbuttons, and more layout cosmetics.
* gimp 1.1.15a; 2000/01/26 hof: removed gimp 1.0.x support
* gimp 1.1.13b; 1999/12/04 hof: some cosmetic gtk fixes
* changed border_width spacing and Buttons in action area
* to same style as used in dialogs of the gimp 1.1.13 main dialogs
* gimp 1.1.8a; 1999/08/31 hof: accept anim framenames without underscore '_'
* gimp 1.1.5a; 1999/05/08 hof: call fileselect in gtk+1.2 style
* version 0.99.00; 1999.03.03 hof: bugfix: update of the preview (did'nt work with gimp1.1.2)
* version 0.98.00; 1998.11.28 hof: Port to GIMP 1.1: replaced buildmenu.h, apply layermask (before rotate)
* mov_imglayer_constrain must check for drawable_id -1
* version 0.97.00; 1998.10.19 hof: Set window title to "Move Path"
* version 0.96.02; 1998.07.30 hof: added clip to frame option and tooltips
* version 0.96.00; 1998.07.09 hof: bugfix (filesel did not reopen after cancel)
* version 0.95.00; 1998.05.12 hof: added rotatation capabilities
* version 0.94.00; 1998.04.25 hof: use only one point as default
* bugfix: initial value for src_paintmode
* fixes the problem reported in p_my_layer_copy (can't get new layer)
* version 0.90.00; 1997.12.14 hof: 1.st (pre) release
*/
/* SYTEM (UNIX) includes */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
/* GIMP includes */
#include "gtk/gtk.h"
#include "config.h"
#include "libgimp/stdplugins-intl.h"
#include "libgimp/gimp.h"
#include "libgimp/gimpui.h"
/* GAP includes */
#include "gap_layer_copy.h"
#include "gap_lib.h"
#include "gap_mov_exec.h"
#include "gap_mov_dialog.h"
#include "gap_pdb_calls.h"
#include "gap_arr_dialog.h"
/* Some useful macros */
extern int gap_debug; /* ==0 ... dont print debug infos */
#define ENTRY_WIDTH 60
#define SCALE_WIDTH 125
#define PREVIEW_SIZE 256
#define RADIUS 3
#define PREVIEW 0x1
#define CURSOR 0x2
#define PATH_LINE 0x4
#define ALL 0xf
/* event masks for the preview widget */
#define PREVIEW_MASK GDK_EXPOSURE_MASK | \
GDK_BUTTON_PRESS_MASK |\
GDK_BUTTON_RELEASE_MASK |\
GDK_BUTTON_MOTION_MASK
#define LABEL_LENGTH 256
typedef struct {
gint run;
} t_mov_interface;
typedef struct {
GtkObject *adjustment;
GtkWidget *entry;
gint constraint;
} t_mov_EntryScaleData;
typedef struct
{
GimpDrawable *drawable;
gint dwidth, dheight;
gint bpp;
GtkWidget *preview;
GimpPixelRgn src_rgn;
gint PixelRgnIsInitialized;
gint show_path;
gint startup;
gint pwidth, pheight;
gint cursor;
gint curx, cury; /* x,y of cursor in preview */
gint oldx, oldy;
GtkWidget *filesel;
GtkAdjustment *x_adj;
GtkAdjustment *y_adj;
GtkAdjustment *wres_adj;
GtkAdjustment *hres_adj;
GtkAdjustment *opacity_adj;
GtkAdjustment *rotation_adj;
GtkAdjustment *keyframe_adj;
gchar PointIndex_Label[LABEL_LENGTH];
GtkWidget *PointIndex_LabelPtr;
gint p_x, p_y;
gint opacity;
gint w_resize;
gint h_resize;
gint rotation;
gint keyframe_abs;
gint max_frame;
gint preview_frame_nr; /* default: current frame */
gint old_preview_frame_nr;
t_anim_info *ainfo_ptr;
gint in_call;
char *pointfile_name;
} t_mov_path_preview;
typedef struct {
t_mov_path_preview *path_ptr;
GtkWidget *dlg;
} t_ok_data;
/* p_buildmenu Structures */
typedef struct _MenuItem MenuItem;
typedef void (*MenuItemCallback) (GtkWidget *widget,
gpointer user_data);
struct _MenuItem
{
char *label;
char unused_accelerator_key;
gint unused_accelerator_mods;
MenuItemCallback callback;
gpointer user_data;
MenuItem *unused_subitems;
GtkWidget *widget;
};
typedef enum
{
OPS_BUTTON_MODIFIER_NONE,
OPS_BUTTON_MODIFIER_SHIFT,
OPS_BUTTON_MODIFIER_CTRL,
OPS_BUTTON_MODIFIER_ALT,
OPS_BUTTON_MODIFIER_SHIFT_CTRL,
OPS_BUTTON_MODIFIER_LAST
} OpsButtonModifier;
/* Declare a local function.
*/
GtkWidget * p_buildmenu (MenuItem *);
long p_move_dialog (t_mov_data *mov_ptr);
static void p_update_point_labels (t_mov_path_preview *path_ptr);
static void p_points_from_tab (t_mov_path_preview *path_ptr);
static void p_points_to_tab (t_mov_path_preview *path_ptr);
static void p_point_refresh (t_mov_path_preview *path_ptr);
static void p_pick_nearest_point (gint px, gint py);
static void p_reset_points ();
static void p_clear_point ();
static void p_load_points (char *filename);
static void p_save_points (char *filename);
static GimpDrawable * p_get_flattened_drawable (gint32 image_id);
static GimpDrawable * p_get_prevw_drawable (t_mov_path_preview *path_ptr);
static gint mov_dialog ( GimpDrawable *drawable, t_mov_path_preview *path_ptr,
gint min, gint max);
static GtkWidget * mov_path_prevw_create ( GimpDrawable *drawable,
t_mov_path_preview *path_ptr);
static GtkWidget * mov_src_sel_create ();
static void mov_path_prevw_destroy ( GtkWidget *widget, gpointer data );
static void mov_path_prevw_preview_init ( t_mov_path_preview *path_ptr );
static void mov_path_prevw_draw ( t_mov_path_preview *path_ptr, gint update );
static void mov_path_x_adjustment_update ( GtkWidget *widget, gpointer data );
static void mov_path_y_adjustment_update ( GtkWidget *widget, gpointer data );
static void mov_path_prevw_cursor_update ( t_mov_path_preview *path_ptr );
static gint mov_path_prevw_preview_expose ( GtkWidget *widget, GdkEvent *event );
static gint mov_path_prevw_preview_events ( GtkWidget *widget, GdkEvent *event );
static gint p_chk_keyframes(t_mov_path_preview *path_ptr);
static void button_pressed_callback (GtkWidget *widget, GdkEventButton *bevent, gpointer client_data);
static void mov_padd_callback (GtkWidget *widget,gpointer data);
static void mov_pins_callback (GtkWidget *widget,gpointer data);
static void mov_pdel_callback (GtkWidget *widget,gpointer data);
static void mov_pnext_callback (GtkWidget *widget,gpointer data);
static void mov_pprev_callback (GtkWidget *widget,gpointer data);
static void mov_pfirst_callback (GtkWidget *widget,gpointer data);
static void mov_plast_callback (GtkWidget *widget,gpointer data);
static void mov_pdel_all_callback (GtkWidget *widget,gpointer data);
static void mov_pclr_callback (GtkWidget *widget,gpointer data);
static void mov_pclr_all_callback (GtkWidget *widget,gpointer data);
static void mov_prot_follow_callback (GtkWidget *widget,gpointer data);
static void mov_pload_callback (GtkWidget *widget,gpointer data);
static void mov_psave_callback (GtkWidget *widget,gpointer data);
static void p_points_load_from_file (GtkWidget *widget,gpointer data);
static void p_points_save_to_file (GtkWidget *widget,gpointer data);
static void mov_close_callback (GtkWidget *widget,gpointer data);
static void mov_ok_callback (GtkWidget *widget,gpointer data);
static void mov_upvw_callback (GtkWidget *widget,gpointer data);
static void mov_apv_callback (GtkWidget *widget,gpointer data);
static void p_filesel_close_cb (GtkWidget *widget, t_mov_path_preview *path_ptr);
static gint mov_imglayer_constrain (gint32 image_id, gint32 drawable_id, gpointer data);
static void mov_imglayer_menu_callback (gint32 id, gpointer data);
static void mov_paintmode_menu_callback (GtkWidget *, gpointer);
static void mov_handmode_menu_callback (GtkWidget *, gpointer);
static void mov_stepmode_menu_callback (GtkWidget *, gpointer);
static void mov_gint_toggle_callback (GtkWidget *, gpointer);
static void mov_show_path_callback (GtkWidget *, gpointer);
/* the option menu items -- the paint modes */
static MenuItem option_paint_items[] =
{
{ N_("Normal"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_NORMAL_MODE, NULL, NULL },
{ N_("Dissolve"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_DISSOLVE_MODE, NULL, NULL },
{ N_("Multiply"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_MULTIPLY_MODE, NULL, NULL },
{ N_("Screen"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_SCREEN_MODE, NULL, NULL },
{ N_("Overlay"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_OVERLAY_MODE, NULL, NULL },
{ N_("Difference"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_DIFFERENCE_MODE, NULL, NULL },
{ N_("Addition"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_ADDITION_MODE, NULL, NULL },
{ N_("Subtract"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_SUBTRACT_MODE, NULL, NULL },
{ N_("Darken Only"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_DARKEN_ONLY_MODE, NULL, NULL },
{ N_("Lighten Only"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_LIGHTEN_ONLY_MODE, NULL, NULL },
{ N_("Hue"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_HUE_MODE, NULL, NULL },
{ N_("Saturation"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_SATURATION_MODE, NULL, NULL },
{ N_("Color"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_COLOR_MODE, NULL, NULL },
{ N_("Value"), 0, 0, mov_paintmode_menu_callback, (gpointer) GIMP_VALUE_MODE, NULL, NULL },
{ NULL, 0, 0, NULL, NULL, NULL, NULL }
};
/* the option menu items -- the handle modes */
static MenuItem option_handle_items[] =
{
{ N_("Left Top"), 0, 0, mov_handmode_menu_callback, (gpointer) GAP_HANDLE_LEFT_TOP, NULL, NULL },
{ N_("Left Bottom"), 0, 0, mov_handmode_menu_callback, (gpointer) GAP_HANDLE_LEFT_BOT, NULL, NULL },
{ N_("Right Top"), 0, 0, mov_handmode_menu_callback, (gpointer) GAP_HANDLE_RIGHT_TOP, NULL, NULL },
{ N_("Right Bottom"), 0, 0, mov_handmode_menu_callback, (gpointer) GAP_HANDLE_RIGHT_BOT, NULL, NULL },
{ N_("Center"), 0, 0, mov_handmode_menu_callback, (gpointer) GAP_HANDLE_CENTER, NULL, NULL },
{ NULL, 0, 0, NULL, NULL, NULL, NULL }
};
/* the option menu items -- the loop step modes */
static MenuItem option_step_items[] =
{
{ N_("Loop"), 0, 0, mov_stepmode_menu_callback, (gpointer) GAP_STEP_LOOP, NULL, NULL },
{ N_("Loop Reverse"), 0, 0, mov_stepmode_menu_callback, (gpointer) GAP_STEP_LOOP_REV, NULL, NULL },
{ N_("Once"), 0, 0, mov_stepmode_menu_callback, (gpointer) GAP_STEP_ONCE, NULL, NULL },
{ N_("OnceReverse"), 0, 0, mov_stepmode_menu_callback, (gpointer) GAP_STEP_ONCE_REV, NULL, NULL },
{ N_("PingPong"), 0, 0, mov_stepmode_menu_callback, (gpointer) GAP_STEP_PING_PONG, NULL, NULL },
{ N_("None"), 0, 0, mov_stepmode_menu_callback, (gpointer) GAP_STEP_NONE, NULL, NULL },
{ N_("Frame Loop"), 0, 0, mov_stepmode_menu_callback, (gpointer) GAP_STEP_FRAME_LOOP, NULL, NULL },
{ N_("Frame Loop Reverse"), 0, 0, mov_stepmode_menu_callback, (gpointer) GAP_STEP_FRAME_LOOP_REV, NULL, NULL },
{ N_("Frame Once"), 0, 0, mov_stepmode_menu_callback, (gpointer) GAP_STEP_FRAME_ONCE, NULL, NULL },
{ N_("Frame OnceReverse"), 0, 0, mov_stepmode_menu_callback, (gpointer) GAP_STEP_FRAME_ONCE_REV, NULL, NULL },
{ N_("Frame PingPong"), 0, 0, mov_stepmode_menu_callback, (gpointer) GAP_STEP_FRAME_PING_PONG, NULL, NULL },
{ N_("Frame None"), 0, 0, mov_stepmode_menu_callback, (gpointer) GAP_STEP_FRAME_NONE, NULL, NULL },
{ NULL, 0, 0, NULL, NULL, NULL, NULL }
};
static t_mov_values *pvals;
static t_mov_interface mov_int =
{
FALSE /* run */
};
OpsButtonModifier global_key_modifier = OPS_BUTTON_MODIFIER_NONE;
/* ============================================================================
**********************
* *
* Dialog interface *
* *
**********************
* ============================================================================
*/
long p_move_dialog (t_mov_data *mov_ptr)
{
GimpDrawable *l_drawable_ptr;
gint l_first, l_last;
char *l_str;
t_mov_path_preview *path_ptr;
if(gap_debug) printf("GAP-DEBUG: START p_move_dialog\n");
path_ptr = g_new( t_mov_path_preview, 1 );
if(path_ptr == NULL)
{
printf("error can't alloc path_preview structure\n");
return -1;
}
path_ptr->show_path = TRUE;
path_ptr->startup = TRUE;
path_ptr->keyframe_adj = NULL;
path_ptr->PixelRgnIsInitialized = FALSE;
pvals = mov_ptr->val_ptr;
l_str = p_strdup_del_underscore(mov_ptr->dst_ainfo_ptr->basename);
path_ptr->pointfile_name = g_strdup_printf("%s.path_points", l_str);
g_free(l_str);
l_first = mov_ptr->dst_ainfo_ptr->first_frame_nr;
l_last = mov_ptr->dst_ainfo_ptr->last_frame_nr;
/* init parameter values */
pvals->dst_image_id = mov_ptr->dst_ainfo_ptr->image_id;
pvals->tmp_image_id = -1;
pvals->src_image_id = -1;
pvals->src_layer_id = -1;
pvals->src_paintmode = GIMP_NORMAL_MODE;
pvals->src_handle = GAP_HANDLE_LEFT_TOP;
pvals->src_stepmode = GAP_STEP_LOOP;
pvals->src_force_visible = 0;
pvals->clip_to_img = 0;
pvals->apv_mode = GAP_APV_QUICK;
pvals->apv_src_frame = -1;
pvals->apv_mlayer_image = -1;
pvals->apv_gap_paste_buff = NULL;
pvals->apv_scalex = 40.0;
pvals->apv_scaley = 40.0;
pvals->cache_src_image_id = -1;
pvals->cache_tmp_image_id = -1;
pvals->cache_tmp_layer_id = -1;
pvals->cache_frame_number = -1;
pvals->cache_ainfo_ptr = NULL;
p_reset_points();
/* pvals->point[1].p_x = 100; */ /* default: move from 0/0 to 100/0 */
pvals->dst_range_start = mov_ptr->dst_ainfo_ptr->curr_frame_nr;
pvals->dst_range_end = l_last;
pvals->dst_layerstack = 0; /* 0 ... insert layer on top of stack */
path_ptr->filesel = NULL; /* fileselector is not open */
path_ptr->ainfo_ptr = mov_ptr->dst_ainfo_ptr;
path_ptr->preview_frame_nr = mov_ptr->dst_ainfo_ptr->curr_frame_nr;
path_ptr->old_preview_frame_nr = path_ptr->preview_frame_nr;
path_ptr->PointIndex_LabelPtr = NULL;
p_points_from_tab(path_ptr);
p_update_point_labels(path_ptr);
/* duplicate the curerent image (for flatten & preview) */
pvals->tmp_image_id = gimp_image_duplicate(pvals->dst_image_id);
/* flatten image, and get the (only) resulting drawable */
l_drawable_ptr = p_get_prevw_drawable(path_ptr);
/* do DIALOG window */
mov_dialog(l_drawable_ptr, path_ptr, l_first, l_last);
p_points_to_tab(path_ptr);
/* destroy the tmp image */
gimp_image_delete(pvals->tmp_image_id);
/* g_free (path_ptr); */ /* DONT free path_ptr it leads to sigsegv ERROR */
if(gap_debug) printf("GAP-DEBUG: END p_move_dialog\n");
if(mov_int.run == TRUE) return 0;
else return -1;
}
/* ============================================================================
*******************
* *
* Main Dialog *
* *
*******************
* ============================================================================
*/
static gint
mov_dialog ( GimpDrawable *drawable, t_mov_path_preview *path_ptr,
gint first_nr, gint last_nr )
{
GtkWidget *vbox;
GtkWidget *vcbox;
GtkWidget *hbox_table;
GtkWidget *hbbox;
GtkWidget *dlg;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *button;
GtkWidget *path_prevw_frame;
GtkWidget *src_sel_frame;
GtkWidget *check_button;
GtkObject *adj;
t_ok_data ok_data;
gchar **argv;
gint argc;
if(gap_debug) printf("GAP-DEBUG: START mov_dialog\n");
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("gap_move");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
/* dialog */
dlg = gtk_dialog_new ();
ok_data.dlg = dlg;
ok_data.path_ptr = path_ptr;
gtk_window_set_title (GTK_WINDOW (dlg), _("Move Path"));
gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) mov_close_callback,
NULL);
/* Initialize Tooltips */
gimp_help_init ();
/* Action area */
gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dlg)->action_area), 2);
gtk_box_set_homogeneous (GTK_BOX (GTK_DIALOG (dlg)->action_area), FALSE);
hbbox = gtk_hbutton_box_new ();
gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbbox), 4);
gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dlg)->action_area), hbbox, FALSE, FALSE, 0);
gtk_widget_show (hbbox);
button = gtk_button_new_from_stock ( GTK_STOCK_OK);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_ok_callback,
&ok_data);
gtk_box_pack_start (GTK_BOX (hbbox), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
button = gtk_button_new_with_label ( _("Update Preview"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_upvw_callback,
path_ptr);
gtk_box_pack_start (GTK_BOX (hbbox), button, TRUE, TRUE, 0);
gimp_help_set_help_data(button,
_("Show PreviewFrame with Selected SrcLayer at current Controlpoint")
, NULL);
gtk_widget_show (button);
button = gtk_button_new_with_label ( _("Anim Preview"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_apv_callback,
path_ptr);
gtk_box_pack_start (GTK_BOX (hbbox), button, TRUE, TRUE, 0);
gimp_help_set_help_data(button,
_("Generate Animated Preview as multilayer image")
, NULL);
gtk_widget_show (button);
button = gtk_button_new_from_stock ( GTK_STOCK_CANCEL);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gtk_widget_destroy,
GTK_OBJECT (dlg));
gtk_box_pack_start (GTK_BOX (hbbox), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
frame = gtk_frame_new ( _("Copy moving source-layer(s) into frames"));
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
gtk_container_set_border_width (GTK_CONTAINER (frame), 4);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0);
/* the vbox */
vbox = gtk_vbox_new (FALSE, 3);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
/* the source select frame */
src_sel_frame = mov_src_sel_create ();
gtk_box_pack_start (GTK_BOX (vbox), src_sel_frame, TRUE, TRUE, 0);
/* the path preview frame (with all the controlpoint widgets) */
path_ptr->max_frame = MAX(first_nr, last_nr);
path_prevw_frame = mov_path_prevw_create ( drawable, path_ptr);
gtk_box_pack_start (GTK_BOX (vbox), path_prevw_frame, TRUE, TRUE, 0);
/* the hbox_table (1 row) */
hbox_table = gtk_table_new (5, 3, FALSE);
gtk_widget_show (hbox_table);
gtk_box_pack_start (GTK_BOX (vbox), hbox_table, TRUE, TRUE, 0);
/* table with 5 rows */
table = gtk_table_new (5, 3, FALSE);
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
gtk_table_attach(GTK_TABLE(hbox_table), table, 0, 1, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL, 4, 0);
/* the start frame scale_entry */
adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 0, /* table col, row */
_("Start Frame:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gfloat)pvals->dst_range_start, /* value */
(gfloat)first_nr, (gfloat)last_nr, /* lower, upper */
1, 10, /* step, page */
0, /* digits */
TRUE, /* constrain */
(gfloat)first_nr, (gfloat)last_nr, /* lower, upper (unconstrained) */
_("First handled frame"), NULL); /* tooltip privatetip */
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
&pvals->dst_range_start);
/* the end frame scale_entry */
adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 1, /* table col, row */
_("End Frame:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gfloat)pvals->dst_range_end, /* value */
(gfloat)first_nr, (gfloat)last_nr, /* lower, upper */
1, 10, /* step, page */
0, /* digits */
TRUE, /* constrain */
(gfloat)first_nr, (gfloat)last_nr, /* lower, upper (unconstrained) */
_("Last handled frame"), NULL); /* tooltip privatetip */
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
&pvals->dst_range_end);
/* the Preview Frame scale_entry */
adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 2, /* table col, row */
_("Preview Frame:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gfloat)path_ptr->preview_frame_nr, /* value */
(gfloat)first_nr, (gfloat)last_nr, /* lower, upper */
1, 10, /* step, page */
0, /* digits */
TRUE, /* constrain */
(gfloat)first_nr, (gfloat)last_nr, /* lower, upper (unconstrained) */
_("Frame to show when UpdPreview button is pressed"),
NULL); /* tooltip privatetip */
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
&path_ptr->preview_frame_nr);
/* the Layerstack scale_entry */
adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 3, /* table col, row */
_("Layerstack:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gfloat)pvals->dst_layerstack, /* value */
0.0, 99.0, /* lower, upper */
1, 10, /* step, page */
0, /* digits */
FALSE, /* constrain */
0.0, 999999.0, /* lower, upper (unconstrained) */
_("How to insert SrcLayer into the Dst. Frame's Layerstack\n0 means on top i.e. in front"),
NULL); /* tooltip privatetip */
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
&pvals->dst_layerstack);
/* the vbox for checkbuttons */
vcbox = gtk_vbox_new (FALSE, 3);
gtk_widget_show (vcbox);
/* toggle force visibility */
check_button = gtk_check_button_new_with_label ( _("Force visibility"));
gtk_signal_connect (GTK_OBJECT (check_button), "toggled",
(GtkSignalFunc) mov_gint_toggle_callback,
&pvals->src_force_visible);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
pvals->src_force_visible);
gimp_help_set_help_data(check_button,
_("Force visibility for all copied Src-Layers")
, NULL);
gtk_widget_show (check_button);
gtk_box_pack_start (GTK_BOX (vcbox), check_button, TRUE, TRUE, 0);
/* toggle clip_to_image */
check_button = gtk_check_button_new_with_label ( _("Clip To Frame"));
gtk_signal_connect (GTK_OBJECT (check_button), "toggled",
(GtkSignalFunc) mov_gint_toggle_callback,
&pvals->clip_to_img);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
pvals->clip_to_img);
gimp_help_set_help_data(check_button,
_("Clip all copied Src-Layers at Frame Boundaries")
, NULL);
gtk_widget_show (check_button);
gtk_box_pack_start (GTK_BOX (vcbox), check_button, TRUE, TRUE, 0);
gtk_table_attach(GTK_TABLE(hbox_table), vcbox, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 4, 0);
gtk_widget_show (frame);
gtk_widget_show (table);
gtk_widget_show (dlg);
path_ptr->startup = FALSE;
gtk_main ();
gdk_flush ();
if(gap_debug) printf("GAP-DEBUG: END mov_dialog\n");
return mov_int.run;
}
/* ============================================================================
* implementation of CALLBACK procedures
* ============================================================================
*/
static void
mov_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
mov_ok_callback (GtkWidget *widget,
gpointer data)
{
t_ok_data *ok_data_ptr;
ok_data_ptr = data;
if(pvals != NULL)
{
if(pvals->src_layer_id < 0)
{
p_msg_win(GIMP_RUN_INTERACTIVE,
_("No Source Image was selected\n"
"(Please open a 2nd Image of the same type before opening Move Path)"));
return;
}
}
if(!p_chk_keyframes(ok_data_ptr->path_ptr))
{
return;
}
mov_int.run = TRUE;
if(pvals->point_idx_max == 0)
{
/* if we have only one point duplicate that point
* (move algorithm needs at least 2 points)
*/
mov_padd_callback(NULL, ok_data_ptr->path_ptr);
}
gtk_widget_destroy (ok_data_ptr->dlg);
}
static void
mov_upvw_callback (GtkWidget *widget,
gpointer data)
{
t_mov_path_preview *path_ptr;
char *l_filename;
long l_frame_nr;
gint32 l_new_tmp_image_id;
gint32 l_old_tmp_image_id;
path_ptr = data;
if(gap_debug) printf("mov_upvw_callback nr: %d old_nr: %d\n",
(int)path_ptr->preview_frame_nr , (int)path_ptr->old_preview_frame_nr);
/* if( path_ptr->preview_frame_nr != path_ptr->old_preview_frame_nr)
* {
*/
l_frame_nr = (long)path_ptr->preview_frame_nr;
l_filename = p_alloc_fname(path_ptr->ainfo_ptr->basename,
l_frame_nr,
path_ptr->ainfo_ptr->extension);
if(l_filename != NULL)
{
/* replace the temporary image */
if(path_ptr->preview_frame_nr == path_ptr->ainfo_ptr->curr_frame_nr)
{
l_new_tmp_image_id = gimp_image_duplicate(path_ptr->ainfo_ptr->image_id);
}
else
{
l_new_tmp_image_id = p_load_image(l_filename);
}
g_free(l_filename);
if (l_new_tmp_image_id >= 0)
{
/* use the new loaded temporary image */
l_old_tmp_image_id = pvals->tmp_image_id;
pvals->tmp_image_id = l_new_tmp_image_id;
/* flatten image, and get the (only) resulting drawable */
path_ptr->drawable = p_get_prevw_drawable(path_ptr);
/* re initialize preview image */
mov_path_prevw_preview_init(path_ptr);
p_point_refresh(path_ptr);
path_ptr->old_preview_frame_nr = path_ptr->preview_frame_nr;
gtk_widget_draw(path_ptr->preview, NULL);
mov_path_prevw_draw ( path_ptr, CURSOR | PATH_LINE );
gdk_flush();
/* destroy the old tmp image */
gimp_image_delete(l_old_tmp_image_id);
}
}
/* } */
}
static void
mov_apv_callback (GtkWidget *widget,
gpointer data)
{
#define ARGC_APV 4
t_mov_path_preview *path_ptr;
t_video_info *vin_ptr;
static gint apv_locked = FALSE;
gint32 l_new_image_id;
GimpParam *return_vals;
int nreturn_vals;
static t_arr_arg argv[ARGC_APV];
static char *radio_apv_mode[3] = { N_("Object on empty frames")
, N_("Object on one frame")
, N_("Exact Object on frames")
};
static int gettextize_loop = 0;
path_ptr = data;
if(!p_chk_keyframes(path_ptr))
{
return;
}
if(apv_locked)
{
return;
}
apv_locked = TRUE;
if(gap_debug) printf("mov_apv_callback preview_frame_nr: %d\n",
(int)path_ptr->preview_frame_nr);
for (;gettextize_loop < 3; gettextize_loop++)
radio_apv_mode[gettextize_loop] = gettext(radio_apv_mode[gettextize_loop]);
p_init_arr_arg(&argv[0], WGT_RADIO);
argv[0].label_txt = _("Anim Preview Mode");
argv[0].help_txt = NULL;
argv[0].radio_argc = 3;
argv[0].radio_argv = radio_apv_mode;
argv[0].radio_ret = 0;
p_init_arr_arg(&argv[1], WGT_FLT_PAIR);
argv[1].constraint = TRUE;
argv[1].label_txt = _("Scale Preview");
argv[1].help_txt = _("Scale down size of the generated animated preview (in %)");
argv[1].flt_min = 5.0;
argv[1].flt_max = 100.0;
argv[1].flt_step = 1.0;
argv[1].flt_ret = pvals->apv_scalex;
p_init_arr_arg(&argv[2], WGT_FLT_PAIR);
argv[2].constraint = TRUE;
argv[2].label_txt = _("Framerate");
argv[2].help_txt = _("Framerate to use in the animated preview in frames/sec");
argv[2].flt_min = 1.0;
argv[2].flt_max = 100.0;
argv[2].flt_step = 1.0;
argv[2].flt_ret = 24;
vin_ptr = p_get_video_info(path_ptr->ainfo_ptr->basename);
if(vin_ptr)
{
if(vin_ptr->framerate > 0) argv[2].flt_ret = vin_ptr->framerate;
g_free(vin_ptr);
}
p_init_arr_arg(&argv[3], WGT_TOGGLE);
argv[3].label_txt = _("Copy to Video Buffer");
argv[3].help_txt = _("Save all single frames of animated preview to video buffer\n"
"(configured in gimprc by video-paste-dir and video-paste-basename)");
argv[3].int_ret = 0;
p_arr_gtk_init(FALSE);
if(TRUE == p_array_dialog( _("Move Path Animated Preview"),
_("Options"),
ARGC_APV, argv))
{
switch(argv[0].radio_ret)
{
case 2:
pvals->apv_mode = GAP_APV_EXACT;
break;
case 1:
pvals->apv_mode = GAP_APV_ONE_FRAME;
break;
default:
pvals->apv_mode = GAP_APV_QUICK;
break;
}
pvals->apv_scalex = argv[1].flt_ret;
pvals->apv_scaley = argv[1].flt_ret;
pvals->apv_framerate = argv[2].flt_ret;
if(argv[3].int_ret)
{
pvals->apv_gap_paste_buff = p_get_video_paste_name();
p_vid_edit_clear();
}
else
{
pvals->apv_gap_paste_buff = NULL;
}
if(gap_debug) printf("Generating Animated Preview\n");
/* TODO: here we should start a thread for calculate and playback of the anim preview,
* so the move_path main window is not blocked until playback exits
*/
p_points_to_tab(path_ptr);
if(!p_chk_keyframes(path_ptr))
{
return;
}
l_new_image_id = p_mov_anim_preview(pvals, path_ptr->ainfo_ptr, path_ptr->preview_frame_nr);
if(l_new_image_id < 0)
{
p_msg_win(GIMP_RUN_INTERACTIVE,
_("Generate Animated Preview failed\n"));
}
else
{
return_vals = gimp_run_procedure ("plug_in_animationplay",
&nreturn_vals,
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
GIMP_PDB_IMAGE, l_new_image_id,
GIMP_PDB_DRAWABLE, -1, /* dummy */
GIMP_PDB_END);
}
pvals->apv_mlayer_image = -1;
}
apv_locked = FALSE;
}
static void
p_copy_point(gint to_idx, gint from_idx)
{
pvals->point[to_idx].p_x = pvals->point[from_idx].p_x;
pvals->point[to_idx].p_y = pvals->point[from_idx].p_y;
pvals->point[to_idx].opacity = pvals->point[from_idx].opacity;
pvals->point[to_idx].w_resize = pvals->point[from_idx].w_resize;
pvals->point[to_idx].h_resize = pvals->point[from_idx].h_resize;
pvals->point[to_idx].rotation = pvals->point[from_idx].rotation;
/* do not copy keyframe */
pvals->point[to_idx].keyframe_abs = 0;
pvals->point[to_idx].keyframe = 0;
}
static void
button_pressed_callback (GtkWidget *widget,
GdkEventButton *bevent,
gpointer client_data)
{
OpsButtonModifier *key_modifier;
g_return_if_fail (client_data != NULL);
key_modifier = (OpsButtonModifier *)client_data;
if (bevent->state & GDK_SHIFT_MASK)
{
if (bevent->state & GDK_CONTROL_MASK)
*key_modifier = OPS_BUTTON_MODIFIER_SHIFT_CTRL;
else
*key_modifier = OPS_BUTTON_MODIFIER_SHIFT;
}
else if (bevent->state & GDK_CONTROL_MASK)
*key_modifier = OPS_BUTTON_MODIFIER_CTRL;
else if (bevent->state & GDK_MOD1_MASK)
*key_modifier = OPS_BUTTON_MODIFIER_ALT;
else
*key_modifier = OPS_BUTTON_MODIFIER_NONE;
if(gap_debug)
{
printf("button_pressed_callback %d\n", (int)*key_modifier);
}
}
static void
mov_padd_callback (GtkWidget *widget,
gpointer data)
{
t_mov_path_preview *path_ptr = data;
gint l_idx;
if(gap_debug) printf("mov_padd_callback\n");
l_idx = pvals->point_idx_max;
if (l_idx < GAP_MOV_MAX_POINT -2)
{
/* advance to next point */
p_points_to_tab(path_ptr);
pvals->point_idx_max++;
pvals->point_idx = pvals->point_idx_max;
/* copy values from previous point to current (new) point */
p_copy_point(pvals->point_idx_max, l_idx);
p_point_refresh(path_ptr);
}
}
static void
mov_pins_callback (GtkWidget *widget,
gpointer data)
{
t_mov_path_preview *path_ptr = data;
gint l_idx;
if(gap_debug) printf("mov_pins_callback\n");
l_idx = pvals->point_idx_max;
if (l_idx < GAP_MOV_MAX_POINT -2)
{
/* advance to next point */
p_points_to_tab(path_ptr);
pvals->point_idx_max++;
for(l_idx = pvals->point_idx_max; l_idx > pvals->point_idx; l_idx--)
{
/* copy values from prev point */
p_copy_point(l_idx, l_idx-1);
}
pvals->point_idx++;
p_point_refresh(path_ptr);
}
}
static void
mov_pdel_callback (GtkWidget *widget,
gpointer data)
{
t_mov_path_preview *path_ptr = data;
gint l_idx;
if(gap_debug) printf("mov_pdel_callback\n");
l_idx = pvals->point_idx_max;
if(pvals->point_idx_max == 0)
{
/* This is the las t point to delete */
p_reset_points();
}
else
{
for(l_idx = pvals->point_idx; l_idx < pvals->point_idx_max; l_idx++)
{
/* copy values from next point */
p_copy_point(l_idx, l_idx+1);
}
pvals->point_idx_max--;
pvals->point_idx = MIN(pvals->point_idx, pvals->point_idx_max);
}
p_point_refresh(path_ptr);
}
static void
mov_pnext_callback (GtkWidget *widget,
gpointer data)
{
t_mov_path_preview *path_ptr = data;
if(gap_debug) printf("mov_pnext_callback\n");
if (pvals->point_idx < pvals->point_idx_max)
{
/* advance to next point */
p_points_to_tab(path_ptr);
pvals->point_idx++;
p_point_refresh(path_ptr);
}
}
static void
mov_pprev_callback (GtkWidget *widget,
gpointer data)
{
t_mov_path_preview *path_ptr = data;
if(gap_debug) printf("mov_pprev_callback\n");
if (pvals->point_idx > 0)
{
/* advance to next point */
p_points_to_tab(path_ptr);
pvals->point_idx--;
p_point_refresh(path_ptr);
}
}
static void
mov_pfirst_callback (GtkWidget *widget,
gpointer data)
{
t_mov_path_preview *path_ptr = data;
if(gap_debug) printf("mov_pfirst_callback\n");
/* advance to first point */
p_points_to_tab(path_ptr);
pvals->point_idx = 0;
p_point_refresh(path_ptr);
}
static void
mov_plast_callback (GtkWidget *widget,
gpointer data)
{
t_mov_path_preview *path_ptr = data;
if(gap_debug) printf("mov_plast_callback\n");
/* advance to first point */
p_points_to_tab(path_ptr);
pvals->point_idx = pvals->point_idx_max;
p_point_refresh(path_ptr);
}
static void
mov_pclr_callback (GtkWidget *widget,
gpointer data)
{
t_mov_path_preview *path_ptr = data;
if(gap_debug) printf("mov_pclr_callback\n");
p_clear_point();
p_point_refresh(path_ptr);
}
static void
mov_pdel_all_callback (GtkWidget *widget,
gpointer data)
{
t_mov_path_preview *path_ptr = data;
if(gap_debug) printf("mov_pdel_all_callback\n");
p_reset_points();
p_point_refresh(path_ptr);
}
static void
mov_pclr_all_callback (GtkWidget *widget,
gpointer data)
{
gint l_idx;
t_mov_path_preview *path_ptr = data;
if(gap_debug) printf("mov_pclr_all_callback\n");
for(l_idx = 0; l_idx <= pvals->point_idx_max; l_idx++)
{
pvals->point[l_idx].rotation = 0; /* no rotation (0 degree) */
}
p_point_refresh(path_ptr);
}
static void
mov_prot_follow_callback (GtkWidget *widget,
gpointer data)
{
gint32 l_startangle;
t_mov_path_preview *path_ptr = data;
if(gap_debug) printf("mov_prot_follow_callback\n");
if( pvals->point_idx_max > 1)
{
l_startangle = 0.0;
if(global_key_modifier == OPS_BUTTON_MODIFIER_SHIFT)
{
p_points_to_tab(path_ptr);
l_startangle = pvals->point[0].rotation;
}
p_calculate_rotate_follow(pvals, l_startangle);
}
global_key_modifier = OPS_BUTTON_MODIFIER_NONE;
p_point_refresh(path_ptr);
}
static void
p_filesel_close_cb(GtkWidget *widget,
t_mov_path_preview *path_ptr)
{
if(path_ptr->filesel == NULL) return;
gtk_widget_destroy(GTK_WIDGET(path_ptr->filesel));
path_ptr->filesel = NULL; /* now filesel is closed */
}
static void
mov_pload_callback (GtkWidget *widget,
gpointer data)
{
GtkWidget *filesel;
t_mov_path_preview *path_ptr = data;
if(path_ptr->filesel != NULL) return; /* filesel is already open */
filesel = gtk_file_selection_new ( _("Load Path Points from file"));
path_ptr->filesel = filesel;
gtk_window_set_position (GTK_WINDOW (filesel), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button),
"clicked", (GtkSignalFunc) p_points_load_from_file,
path_ptr);
gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button),
"clicked", (GtkSignalFunc) p_filesel_close_cb,
path_ptr);
/* "destroy" has to be the last signal,
* (otherwise the other callbacks are never called)
*/
gtk_signal_connect (GTK_OBJECT (filesel), "destroy",
(GtkSignalFunc) p_filesel_close_cb,
path_ptr);
gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel),
path_ptr->pointfile_name);
gtk_widget_show (filesel);
}
static void
mov_psave_callback (GtkWidget *widget,
gpointer data)
{
GtkWidget *filesel;
t_mov_path_preview *path_ptr = data;
if(path_ptr->filesel != NULL) return; /* filesel is already open */
filesel = gtk_file_selection_new ( _("Save Path Points to file"));
path_ptr->filesel = filesel;
gtk_window_set_position (GTK_WINDOW (filesel), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button),
"clicked", (GtkSignalFunc) p_points_save_to_file,
path_ptr);
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button),
"clicked", (GtkSignalFunc) p_filesel_close_cb,
path_ptr);
/* "destroy" has to be the last signal,
* (otherwise the other callbacks are never called)
*/
gtk_signal_connect (GTK_OBJECT (filesel), "destroy",
(GtkSignalFunc) p_filesel_close_cb,
path_ptr);
gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel),
path_ptr->pointfile_name);
gtk_widget_show (filesel);
}
static void
p_points_load_from_file (GtkWidget *widget,
gpointer data)
{
t_mov_path_preview *path_ptr = data;
const gchar *filename;
if(gap_debug) printf("p_points_load_from_file\n");
if(path_ptr->filesel == NULL) return;
filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (path_ptr->filesel));
g_free(path_ptr->pointfile_name);
path_ptr->pointfile_name = g_strdup(filename);
if(gap_debug) printf("p_points_load_from_file %s\n", path_ptr->pointfile_name);
gtk_widget_destroy(GTK_WIDGET(path_ptr->filesel));
path_ptr->filesel = NULL;
p_load_points(path_ptr->pointfile_name);
p_point_refresh(path_ptr);
}
static void
p_points_save_to_file (GtkWidget *widget,
gpointer data)
{
t_mov_path_preview *path_ptr = data;
const gchar *filename;
if(gap_debug) printf("p_points_save_to_file\n");
if(path_ptr->filesel == NULL) return;
filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (path_ptr->filesel));
g_free(path_ptr->pointfile_name);
path_ptr->pointfile_name = g_strdup(filename);
if(gap_debug) printf("p_points_save_to_file %s\n", path_ptr->pointfile_name);
gtk_widget_destroy(GTK_WIDGET(path_ptr->filesel));
path_ptr->filesel = NULL;
p_points_to_tab(path_ptr);
p_save_points(path_ptr->pointfile_name);
p_point_refresh(path_ptr);
}
static void
p_point_refresh(t_mov_path_preview *path_ptr)
{
p_points_from_tab(path_ptr);
p_update_point_labels(path_ptr);
if(gap_debug) printf("p_point_refresh:newval in_call=%d\n", path_ptr->in_call );
if( !path_ptr->in_call )
{
mov_path_prevw_cursor_update( path_ptr );
mov_path_prevw_draw ( path_ptr, CURSOR | PATH_LINE );
}
path_ptr->in_call = TRUE;
gtk_adjustment_set_value (path_ptr->x_adj,
(gfloat)path_ptr->p_x);
gtk_adjustment_set_value (path_ptr->y_adj,
(gfloat)path_ptr->p_y);
gtk_adjustment_set_value (path_ptr->wres_adj,
(gfloat)path_ptr->w_resize);
gtk_adjustment_set_value (path_ptr->hres_adj,
(gfloat)path_ptr->h_resize);
gtk_adjustment_set_value (path_ptr->opacity_adj,
(gfloat)path_ptr->opacity);
gtk_adjustment_set_value (path_ptr->rotation_adj,
(gfloat)path_ptr->rotation);
gtk_adjustment_set_value (path_ptr->keyframe_adj,
(gfloat)path_ptr->keyframe_abs);
path_ptr->in_call = FALSE;
} /* end p_point_refresh */
static void
p_pick_nearest_point(gint px, gint py)
{
gint l_idx;
gint l_idx_min;
gdouble l_sq_dist;
gdouble l_dx, l_dy;
gdouble l_sq_dist_min;
l_idx_min = 0;
l_sq_dist_min = G_MAXDOUBLE;
if(gap_debug) printf("\np_pick_nearest_point: near to %4d %4d\n", (int)px, (int)py);
for(l_idx = pvals->point_idx_max; l_idx >= 0; l_idx--)
{
/* calculate x and y distance */
l_dx = pvals->point[l_idx].p_x - px;
l_dy = pvals->point[l_idx].p_y - py;
/* calculate square of the distance */
l_sq_dist = (l_dx * l_dx) + (l_dy * l_dy);
if(l_sq_dist < l_sq_dist_min)
{
l_sq_dist_min = l_sq_dist;
l_idx_min = l_idx;
}
if(gap_debug)
{
printf(" [%2d] %4d %4d %f\n",
(int)l_idx,
(int)pvals->point[l_idx].p_x,
(int)pvals->point[l_idx].p_y,
(float)l_sq_dist
);
}
}
if(gap_debug) printf("p_pick_nearest_point: selected %d\n", (int)l_idx_min);
pvals->point_idx = l_idx_min;
pvals->point[pvals->point_idx].p_x = px;
pvals->point[pvals->point_idx].p_y = py;
} /* end p_pick_nearest_point */
static void
mov_imglayer_menu_callback(gint32 id, gpointer data)
{
pvals->src_layer_id = id;
pvals->src_image_id = gimp_layer_get_image_id(id);
if(gap_debug) printf("mov_imglayer_menu_callback: image_id=%ld layer_id=%ld\n",
(long)pvals->src_image_id, (long)pvals->src_layer_id);
/* TODO:
* if any remove old src layer from preview
* add this layer to preview (at current point coords)
* update_preview
*/
} /* end mov_imglayer_menu_callback */
static gint
mov_imglayer_constrain(gint32 image_id, gint32 drawable_id, gpointer data)
{
gint32 l_src_image_id;
if(gap_debug) printf("GAP-DEBUG: mov_imglayer_constrain PROCEDURE\n");
if(drawable_id < 0)
{
/* gimp 1.1 makes a first call of the constraint procedure
* with drawable_id = -1, and skips the whole image if FALSE is returned
*/
return(TRUE);
}
l_src_image_id = gimp_layer_get_image_id(drawable_id);
/* dont accept layers from within the destination image id
* or layers within the tmp preview image
* conversions between different base_types are not supported in this version
*/
return((l_src_image_id != pvals->dst_image_id) &&
(l_src_image_id != pvals->tmp_image_id) &&
(gimp_image_base_type(l_src_image_id) == gimp_image_base_type(pvals->tmp_image_id)) );
} /* end mov_imglayer_constrain */
static void
mov_paintmode_menu_callback (GtkWidget *w, gpointer client_data)
{
pvals->src_paintmode = (gint)client_data;
}
static void
mov_handmode_menu_callback (GtkWidget *w, gpointer client_data)
{
pvals->src_handle = (gint)client_data;
}
static void
mov_stepmode_menu_callback (GtkWidget *w, gpointer client_data)
{
pvals->src_stepmode = (gint)client_data;
}
static void
mov_gint_toggle_callback(GtkWidget *w, gpointer client_data)
{
gint *data;
data = (gint*)client_data;
if (GTK_TOGGLE_BUTTON (w)->active)
{
*data = 1;
}
else
{
*data = 0;
}
}
static void
mov_show_path_callback(GtkWidget *widget, gpointer client_data)
{
t_mov_path_preview *path_ptr;
path_ptr = (t_mov_path_preview *)client_data;
mov_gint_toggle_callback(widget, &path_ptr->show_path);
if(path_ptr == NULL) return;
if(path_ptr->startup) return;
if(path_ptr->preview == NULL) return;
if(path_ptr->drawable == NULL) return;
p_point_refresh(path_ptr);
mov_path_prevw_draw ( path_ptr, CURSOR | PATH_LINE );
gtk_widget_draw(path_ptr->preview, NULL);
gdk_flush();
}
/* ============================================================================
* procedures to handle POINTS - TABLE
* ============================================================================
*/
static void
p_points_from_tab(t_mov_path_preview *path_ptr)
{
GtkWidget *scale;
GtkWidget *spinbutton;
path_ptr->p_x = pvals->point[pvals->point_idx].p_x;
path_ptr->p_y = pvals->point[pvals->point_idx].p_y;
path_ptr->opacity = pvals->point[pvals->point_idx].opacity;
path_ptr->w_resize = pvals->point[pvals->point_idx].w_resize;
path_ptr->h_resize = pvals->point[pvals->point_idx].h_resize;
path_ptr->rotation = pvals->point[pvals->point_idx].rotation;
path_ptr->keyframe_abs = pvals->point[pvals->point_idx].keyframe_abs;
if(( path_ptr->keyframe_adj != NULL) && (path_ptr->startup != TRUE))
{
/* findout the gtk_widgets (scale and spinbutton) connected
* to path_ptr->keyframe_adj
* and set_sensitive to TRUE or FALSE
*/
scale = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (path_ptr->keyframe_adj), "scale"));
spinbutton = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (path_ptr->keyframe_adj), "spinbutton"));
if((scale == NULL) || (spinbutton == NULL))
{
return;
}
if(gap_debug)
{
printf("p_points_from_tab: scale %x spinbutton %x\n",
(int)scale, (int)spinbutton);
}
if((pvals->point_idx == 0) || (pvals->point_idx == pvals->point_idx_max))
{
gtk_widget_set_sensitive(scale, FALSE);
gtk_widget_set_sensitive(spinbutton, FALSE);
}
else
{
gtk_widget_set_sensitive(scale, TRUE);
gtk_widget_set_sensitive(spinbutton, TRUE);
}
}
}
static void
p_points_to_tab(t_mov_path_preview *path_ptr)
{
if(gap_debug) printf("p_points_to_tab: idx=%d, rotation=%d\n", (int)pvals->point_idx ,(int) path_ptr->rotation);
pvals->point[pvals->point_idx].p_x = path_ptr->p_x;
pvals->point[pvals->point_idx].p_y = path_ptr->p_y;
pvals->point[pvals->point_idx].opacity = path_ptr->opacity;
pvals->point[pvals->point_idx].w_resize = path_ptr->w_resize;
pvals->point[pvals->point_idx].h_resize = path_ptr->h_resize;
pvals->point[pvals->point_idx].rotation = path_ptr->rotation;
pvals->point[pvals->point_idx].keyframe_abs = path_ptr->keyframe_abs;
if((path_ptr->keyframe_abs > 0)
&& (pvals->point_idx != 0)
&& (pvals->point_idx != pvals->point_idx_max))
{
pvals->point[pvals->point_idx].keyframe = p_conv_keyframe_to_rel(path_ptr->keyframe_abs, pvals);
}
else
{
pvals->point[pvals->point_idx].keyframe = 0;
}
}
void
p_update_point_labels(t_mov_path_preview *path_ptr)
{
g_snprintf (&path_ptr->PointIndex_Label[0], LABEL_LENGTH,
_("Current Point: [ %3d ] of [ %3d ]"),
pvals->point_idx + 1, pvals->point_idx_max +1);
if (NULL != path_ptr->PointIndex_LabelPtr)
{
gtk_label_set_text (GTK_LABEL (path_ptr->PointIndex_LabelPtr),
&path_ptr->PointIndex_Label[0]);
}
}
/* ============================================================================
* p_reset_points
* Init point table with identical 2 Points
* ============================================================================
*/
void p_clear_point()
{
gint l_idx;
l_idx = pvals->point_idx;
if((l_idx >= 0) && (l_idx <= pvals->point_idx_max))
{
pvals->point[l_idx].opacity = 100; /* 100 percent (no transparecy) */
pvals->point[l_idx].w_resize = 100; /* 100% no resizize (1:1) */
pvals->point[l_idx].h_resize = 100; /* 100% no resizize (1:1) */
pvals->point[l_idx].rotation = 0; /* no rotation (0 degree) */
pvals->point[l_idx].keyframe = 0; /* 0: controlpoint is not fixed to keyframe */
pvals->point[l_idx].keyframe_abs = 0; /* 0: controlpoint is not fixed to keyframe */
}
} /* end p_clear_point */
void p_reset_points()
{
pvals->point_idx = 0; /* 0 == current point */
pvals->point_idx_max = 0; /* 0 == there is only one valid point */
p_clear_point();
pvals->point[0].p_x = 0;
pvals->point[0].p_y = 0;
} /* end p_reset_points */
/* ============================================================================
* p_load_points
* load point table (from named file into global pvals)
* (reset points if load failed)
* ============================================================================
*/
void p_load_points(char *filename)
{
if (p_gap_load_pointfile(filename, pvals) < -1)
{
p_reset_points();
}
}
/* ============================================================================
* p_save_points
* save point table (from global pvals into named file)
* ============================================================================
*/
static void
p_save_points(char *filename)
{
p_gap_save_pointfile(filename, pvals);
} /* end p_save_points */
/* ============================================================================
* Create new source selection table Frame, and return it.
* A frame that contains:
* - 2x2 menus (src_image/layer, handle, stepmode, paintmode)
* ============================================================================
*/
static GtkWidget *
mov_src_sel_create()
{
GtkWidget *frame;
GtkWidget *table;
GtkWidget *option_menu;
GtkWidget *menu;
GtkWidget *label;
gint gettextize_loop;
frame = gtk_frame_new ( _("Source Select") );
/*
gtk_signal_connect( GTK_OBJECT( frame ), "destroy",
(GtkSignalFunc) mov_src_sel_destroy,
path_ptr );
*/
gtk_frame_set_shadow_type (GTK_FRAME (frame) ,GTK_SHADOW_ETCHED_IN);
gtk_container_set_border_width (GTK_CONTAINER (frame), 2);
table = gtk_table_new (2, 4, FALSE);
gtk_container_set_border_width (GTK_CONTAINER (table), 2);
gtk_container_add (GTK_CONTAINER (frame), table);
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
/* Source Layer menu */
label = gtk_label_new( _("Source Image/Layer:"));
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 4, 0);
gtk_widget_show(label);
option_menu = gtk_option_menu_new();
gtk_table_attach(GTK_TABLE(table), option_menu, 1, 2, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gimp_help_set_help_data(option_menu,
_("Source Object to insert into Frame Range")
, NULL);
gtk_widget_show(option_menu);
menu = gimp_layer_menu_new(mov_imglayer_constrain,
mov_imglayer_menu_callback,
NULL,
pvals->src_layer_id);
gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
gtk_widget_show(option_menu);
/* Paintmode menu */
label = gtk_label_new( _("Mode:"));
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 4, 0);
gtk_widget_show(label);
option_menu = gtk_option_menu_new();
gtk_table_attach(GTK_TABLE(table), option_menu, 3, 4, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gimp_help_set_help_data(option_menu,
_("Paintmode")
, NULL);
gtk_widget_show(option_menu);
for (gettextize_loop = 0; option_paint_items[gettextize_loop].label != NULL;
gettextize_loop++)
option_paint_items[gettextize_loop].label =
gettext(option_paint_items[gettextize_loop].label);
menu = p_buildmenu (option_paint_items);
gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
gtk_widget_show(option_menu);
/* Loop Stepmode menu */
label = gtk_label_new( _("Stepmode:"));
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 4, 0);
gtk_widget_show(label);
option_menu = gtk_option_menu_new();
gtk_table_attach(GTK_TABLE(table), option_menu, 1, 2, 1, 2,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show(option_menu);
for (gettextize_loop = 0; option_step_items[gettextize_loop].label != NULL;
gettextize_loop++)
option_step_items[gettextize_loop].label =
gettext(option_step_items[gettextize_loop].label);
menu = p_buildmenu (option_step_items);
gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
gimp_help_set_help_data(option_menu,
_("How to fetch the next SrcLayer at the next handled frame")
, NULL);
gtk_widget_show(option_menu);
/* Source Image Handle menu */
label = gtk_label_new( _("Handle:"));
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 2, 3, 1, 2, GTK_FILL, GTK_FILL, 4, 0);
gtk_widget_show(label);
option_menu = gtk_option_menu_new();
gtk_table_attach(GTK_TABLE(table), option_menu, 3, 4, 1, 2,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show(option_menu);
for (gettextize_loop = 0; option_handle_items[gettextize_loop].label != NULL;
gettextize_loop++)
option_handle_items[gettextize_loop].label =
gettext(option_handle_items[gettextize_loop].label);
menu = p_buildmenu (option_handle_items);
gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
gimp_help_set_help_data(option_menu,
_("How to place the SrcLayer at Controlpoint Coordinates")
, NULL);
gtk_widget_show(option_menu);
gtk_widget_show( table );
gtk_widget_show( frame );
return frame;
} /* end mov_src_sel_create */
/* ============================================================================
* Create new path_preview Frame, and return it (GtkFrame).
* A frame that contains one preview and the entries of the current point
* One "Point" has:
* - 2 entrys X/Y, used for positioning
* - Resize 2x Scale + integer entry (for resizing Width + Height)
* - Opacity Scale + integr entry (0 to 100 %)
* - Rotation Scale + ineger entry (-360 to 360 degrees)
* - Keyframe Scale + ineger entry (0 to max_frame)
* ============================================================================
*/
static GtkWidget *
mov_path_prevw_create ( GimpDrawable *drawable, t_mov_path_preview *path_ptr)
{
GtkWidget *frame;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *table;
GtkWidget *label;
GtkWidget *pframe;
GtkWidget *preview;
GtkWidget *button_table;
GtkWidget *pv_table;
GtkWidget *button;
GtkWidget *check_button;
GtkObject *adj;
gint row;
path_ptr->drawable = drawable;
path_ptr->dwidth = gimp_drawable_width(drawable->drawable_id );
path_ptr->dheight = gimp_drawable_height(drawable->drawable_id );
path_ptr->bpp = gimp_drawable_bpp(drawable->drawable_id);
if ( gimp_drawable_has_alpha(drawable->drawable_id) )
path_ptr->bpp--;
path_ptr->cursor = FALSE;
path_ptr->curx = 0;
path_ptr->cury = 0;
path_ptr->oldx = 0;
path_ptr->oldy = 0;
path_ptr->in_call = TRUE; /* to avoid side effects while initialization */
/* the frame */
frame = gtk_frame_new ( _("Move Path Preview") );
gtk_signal_connect( GTK_OBJECT( frame ), "destroy",
(GtkSignalFunc) mov_path_prevw_destroy,
path_ptr );
gtk_frame_set_shadow_type( GTK_FRAME( frame ) ,GTK_SHADOW_ETCHED_IN );
gtk_container_set_border_width( GTK_CONTAINER( frame ), 2 );
/* the vbox */
vbox = gtk_vbox_new (FALSE, 3);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
/* the table (4 rows) */
table = gtk_table_new ( 4, 6, FALSE );
gtk_container_set_border_width (GTK_CONTAINER (table), 2 );
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
/* X */
adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 0, /* table col, row */
_("X:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gfloat)path_ptr->p_x, /* value */
(gfloat)0, (gfloat)path_ptr->dwidth, /* lower, upper */
1, 10, /* step, page */
0, /* digits */
FALSE, /* constrain */
(gfloat)(-GIMP_MAX_IMAGE_SIZE),
(gfloat)GIMP_MAX_IMAGE_SIZE, /* lower, upper (unconstrained) */
_("X Coordinate"),
NULL); /* tooltip privatetip */
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (mov_path_x_adjustment_update),
path_ptr);
path_ptr->x_adj = GTK_ADJUSTMENT(adj);
/* Y */
adj = gimp_scale_entry_new( GTK_TABLE (table), 3, 0, /* table col, row */
_("Y:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gfloat)path_ptr->p_y, /* value */
(gfloat)0, (gfloat)path_ptr->dheight, /* lower, upper */
1, 10, /* step, page */
0, /* digits */
FALSE, /* constrain */
(gfloat)(-GIMP_MAX_IMAGE_SIZE),
(gfloat)GIMP_MAX_IMAGE_SIZE, /* lower, upper (unconstrained) */
_("Y Coordinate"),
NULL); /* tooltip privatetip */
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (mov_path_y_adjustment_update),
path_ptr);
path_ptr->y_adj = GTK_ADJUSTMENT(adj);
/* Widht Scale */
adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 1, /* table col, row */
_("Width:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gfloat)path_ptr->w_resize, /* value */
(gfloat)1, (gfloat)200, /* lower, upper */
1, 10, /* step, page */
0, /* digits */
FALSE, /* constrain */
(gfloat)1, (gfloat)1000, /* lower, upper (unconstrained) */
_("Scale Source Layer's Width in percent"),
NULL); /* tooltip privatetip */
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
&path_ptr->w_resize);
path_ptr->wres_adj = GTK_ADJUSTMENT(adj);
/* Height Scale */
adj = gimp_scale_entry_new( GTK_TABLE (table), 3, 1, /* table col, row */
_("Height:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gfloat)path_ptr->h_resize, /* value */
(gfloat)1, (gfloat)200, /* lower, upper */
1, 10, /* step, page */
0, /* digits */
FALSE, /* constrain */
(gfloat)1, (gfloat)1000, /* lower, upper (unconstrained) */
_("Scale SrcLayer's Height in percent"),
NULL); /* tooltip privatetip */
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
&path_ptr->h_resize);
path_ptr->hres_adj = GTK_ADJUSTMENT(adj);
/* Opacity */
adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 2, /* table col, row */
_("Opacity:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gfloat)path_ptr->opacity, /* value */
(gfloat)0, (gfloat)100, /* lower, upper */
1, 10, /* step, page */
0, /* digits */
TRUE, /* constrain */
(gfloat)0, (gfloat)100, /* lower, upper (unconstrained) */
_("SrcLayer's Opacity in percent"),
NULL); /* tooltip privatetip */
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
&path_ptr->opacity);
path_ptr->opacity_adj = GTK_ADJUSTMENT(adj);
/* Rotation */
adj = gimp_scale_entry_new( GTK_TABLE (table), 3, 2, /* table col, row */
_("Rotate:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gfloat)path_ptr->rotation, /* value */
(gfloat)-360, (gfloat)360, /* lower, upper */
1, 10, /* step, page */
0, /* digits */
FALSE, /* constrain */
(gfloat)-3600, (gfloat)3600, /* lower, upper (unconstrained) */
_("Rotate SrcLayer (in degree)"),
NULL); /* tooltip privatetip */
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
&path_ptr->rotation);
path_ptr->rotation_adj = GTK_ADJUSTMENT(adj);
/* Keyframe */
adj = gimp_scale_entry_new( GTK_TABLE (table), 3, 3, /* table col, row */
_("Keyframe:"), /* label text */
SCALE_WIDTH, ENTRY_WIDTH, /* scalesize spinsize */
(gfloat)path_ptr->keyframe_abs, /* value */
(gfloat)0, (gfloat)path_ptr->max_frame, /* lower, upper */
1, 10, /* step, page */
0, /* digits */
TRUE, /* constrain */
(gfloat)0, (gfloat)path_ptr->max_frame, /* lower, upper (unconstrained) */
_("Fix Controlpoint to Keyframe number\n(0 == No Keyframe)"),
NULL); /* tooltip privatetip */
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
&path_ptr->keyframe_abs);
path_ptr->keyframe_adj = GTK_ADJUSTMENT(adj);
gtk_widget_show( table );
/* the hbox (for preview table and button_table) */
hbox = gtk_hbox_new (FALSE, 3);
gtk_widget_show (hbox);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
/* the preview table (1 rows) */
pv_table = gtk_table_new ( 1, 1, FALSE );
gtk_container_set_border_width (GTK_CONTAINER (pv_table), 2 );
gtk_table_set_row_spacings (GTK_TABLE (pv_table), 2);
gtk_table_set_col_spacings (GTK_TABLE (pv_table), 4);
gtk_box_pack_start (GTK_BOX (hbox), pv_table, TRUE, TRUE, 0);
/* frame (shadow_in) that contains preview */
pframe = gtk_frame_new ( NULL );
gtk_frame_set_shadow_type( GTK_FRAME( pframe ), GTK_SHADOW_IN );
gtk_table_attach( GTK_TABLE(pv_table), pframe, 0, 1, 0, 1,
0, 0, 0, 0 );
/* PREVIEW */
path_ptr->preview = preview = gtk_preview_new( path_ptr->bpp==3 ? GTK_PREVIEW_COLOR : GTK_PREVIEW_GRAYSCALE );
gtk_object_set_user_data( GTK_OBJECT(preview), path_ptr );
gtk_widget_set_events( GTK_WIDGET(preview), PREVIEW_MASK );
gtk_signal_connect_after( GTK_OBJECT(preview), "expose_event",
(GtkSignalFunc) mov_path_prevw_preview_expose,
path_ptr );
gtk_signal_connect( GTK_OBJECT(preview), "event",
(GtkSignalFunc) mov_path_prevw_preview_events,
path_ptr );
gtk_container_add( GTK_CONTAINER( pframe ), path_ptr->preview );
/*
* Resize the greater one of dwidth and dheight to PREVIEW_SIZE
*/
if ( path_ptr->dwidth > path_ptr->dheight ) {
path_ptr->pheight = path_ptr->dheight * PREVIEW_SIZE / path_ptr->dwidth;
path_ptr->pwidth = PREVIEW_SIZE;
} else {
path_ptr->pwidth = path_ptr->dwidth * PREVIEW_SIZE / path_ptr->dheight;
path_ptr->pheight = PREVIEW_SIZE;
}
gtk_preview_size( GTK_PREVIEW( preview ), path_ptr->pwidth, path_ptr->pheight );
/* Draw the contents of preview, that is saved in the preview widget */
mov_path_prevw_preview_init( path_ptr );
gtk_widget_show(preview);
/* button_table 8 rows */
button_table = gtk_table_new (8, 2, TRUE);
gtk_table_set_row_spacings (GTK_TABLE (button_table), 0);
gtk_table_set_col_spacings (GTK_TABLE (button_table), 0);
row = 0;
/* the PointIndex label */
label = gtk_label_new ( &path_ptr->PointIndex_Label[0] ); /* "Current Point: 1" */
gtk_misc_set_alignment( GTK_MISC(label), 0.0, 0.5 );
gtk_table_attach( GTK_TABLE(button_table), label, 0, 2, row, row+1,
GTK_FILL, 0, 4, 0 );
gtk_widget_show(label);
path_ptr->PointIndex_LabelPtr = label; /* store label ptr for later update */
row++;
button = gtk_button_new_with_label ( _("Add Point"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_padd_callback,
path_ptr);
gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1,
GTK_FILL, 0, 0, 0 );
gimp_help_set_help_data(button,
_("Add Controlpoint at end\n(the last Point is duplicated)")
, NULL);
gtk_widget_show (button);
/* toggle clip_to_image */
check_button = gtk_check_button_new_with_label ( _("Show Path"));
gtk_signal_connect (GTK_OBJECT (check_button), "toggled",
(GtkSignalFunc) mov_show_path_callback,
path_ptr);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
path_ptr->show_path);
gimp_help_set_help_data(check_button,
_("Show Path Lines and enable "
"pick/drag with left button "
"or move with right button")
, NULL);
gtk_widget_show (check_button);
gtk_table_attach(GTK_TABLE(button_table), check_button, 1, 2, row, row+1,
0, 0, 0, 0);
row++;
button = gtk_button_new_with_label ( _("Insert Point"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_pins_callback,
path_ptr);
gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1,
GTK_FILL, 0, 0, 0 );
gimp_help_set_help_data(button,
_("Insert Controlpoint\n(the current Point is duplicated)")
, NULL);
gtk_widget_show (button);
button = gtk_button_new_with_label ( _("Delete Point"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_pdel_callback,
path_ptr);
gtk_table_attach( GTK_TABLE(button_table), button, 1, 2, row, row+1,
GTK_FILL, 0, 0, 0 );
gimp_help_set_help_data(button,
_("Delete current Controlpoint")
, NULL);
gtk_widget_show (button);
row++;
button = gtk_button_new_with_label ( _("Prev Point"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_pprev_callback,
path_ptr);
gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1,
GTK_FILL, 0, 0, 0 );
gimp_help_set_help_data(button,
_("Show Previous Controlpoint")
, NULL);
gtk_widget_show (button);
button = gtk_button_new_with_label ( _("Next Point"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_pnext_callback,
path_ptr);
gtk_table_attach( GTK_TABLE(button_table), button, 1, 2, row, row+1,
GTK_FILL, 0, 0, 0 );
gimp_help_set_help_data(button,
_("Show Next Controlpoint")
, NULL);
gtk_widget_show (button);
row++;
button = gtk_button_new_with_label ( _("First Point"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_pfirst_callback,
path_ptr);
gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1,
GTK_FILL, 0, 0, 0 );
gimp_help_set_help_data(button,
_("Show First Controlpoint")
, NULL);
gtk_widget_show (button);
button = gtk_button_new_with_label ( _("Last Point"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_plast_callback,
path_ptr);
gtk_table_attach( GTK_TABLE(button_table), button, 1, 2, row, row+1,
GTK_FILL, 0, 0, 0 );
gimp_help_set_help_data(button,
_("Show Last Controlpoint")
, NULL);
gtk_widget_show (button);
row++;
button = gtk_button_new_with_label ( _("Clear Point"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_pclr_callback,
path_ptr);
gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1,
GTK_FILL, 0, 0, 0 );
gimp_help_set_help_data(button,
_("Reset the current Controlpoint to default Values")
, NULL);
gtk_widget_show (button);
button = gtk_button_new_with_label ( _("Clear All Points"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_pclr_all_callback,
path_ptr);
gtk_table_attach( GTK_TABLE(button_table), button, 1, 2, row, row+1,
GTK_FILL, 0, 0, 0 );
gimp_help_set_help_data(button,
_("Reset all Controlpoints to default Values "
"but dont change the path (X/Y Values)")
, NULL);
gtk_widget_show (button);
row++;
button = gtk_button_new_with_label ( _("Rotate Follow"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "button_press_event",
(GtkSignalFunc) button_pressed_callback,
&global_key_modifier);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_prot_follow_callback,
path_ptr);
gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1,
GTK_FILL, 0, 0, 0 );
gimp_help_set_help_data(button,
_("Set Rotation for all Controlpoints "
"to follow the shape of the path.\n"
"(Shift: use Rotation of contolpoint 1 as offset)")
, NULL);
gtk_widget_show (button);
button = gtk_button_new_with_label ( _("Delete All Points"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_pdel_all_callback,
path_ptr);
gtk_table_attach( GTK_TABLE(button_table), button, 1, 2, row, row+1,
GTK_FILL, 0, 0, 0 );
gimp_help_set_help_data(button,
_("Delete all Controlpoints")
, NULL);
gtk_widget_show (button);
row++;
button = gtk_button_new_with_label ( _("Load Points"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_pload_callback,
path_ptr);
gtk_table_attach( GTK_TABLE(button_table), button, 0, 1, row, row+1,
GTK_FILL, 0, 0, 0 );
gimp_help_set_help_data(button,
_("Load Controlpoints from file")
, NULL);
gtk_widget_show (button);
button = gtk_button_new_with_label ( _("Save Points"));
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) mov_psave_callback,
path_ptr);
gtk_table_attach( GTK_TABLE(button_table), button, 1, 2, row, row+1,
GTK_FILL, 0, 0, 0 );
gimp_help_set_help_data(button,
_("Save Controlpoints to file")
, NULL);
gtk_widget_show (button);
row++;
gtk_box_pack_start (GTK_BOX (hbox), button_table, TRUE, TRUE, 0);
gtk_widget_show (button_table);
gtk_widget_show( pframe );
gtk_widget_show( pv_table );
gtk_widget_show( frame );
mov_path_prevw_cursor_update( path_ptr );
path_ptr->cursor = FALSE; /* Make sure that the cursor has not been drawn */
path_ptr->in_call = FALSE; /* End of initialization */
if(gap_debug) printf("pvals path_ptr=%d,%d\n", path_ptr->p_x, path_ptr->p_y );
if(gap_debug) printf("path_ptr cur=%d,%d\n", path_ptr->curx, path_ptr->cury );
return frame;
}
static void
mov_path_prevw_destroy ( GtkWidget *widget,
gpointer data )
{
t_mov_path_preview *path_ptr = data;
g_free( path_ptr );
}
static void render_preview ( GtkWidget *preview, GimpPixelRgn *srcrgn );
/* ============================================================================
* mov_path_prevw_preview_init
* Initialize preview
* Draw the contents into the internal buffer of the preview widget
* ============================================================================
*/
static void
mov_path_prevw_preview_init ( t_mov_path_preview *path_ptr )
{
gimp_pixel_rgn_init ( &path_ptr->src_rgn, path_ptr->drawable, 0, 0,
path_ptr->dwidth, path_ptr->dheight, FALSE, FALSE );
path_ptr->PixelRgnIsInitialized = TRUE;
render_preview( path_ptr->preview, &path_ptr->src_rgn );
}
/* ============================================================================
* render_preview
* Preview Rendering Util routine
* ============================================================================
*/
#define CHECKWIDTH 8
#define LIGHTCHECK 192
#define DARKCHECK 128
#ifndef OPAQUE
#define OPAQUE 255
#endif
static void
render_preview ( GtkWidget *preview, GimpPixelRgn *srcrgn )
{
guchar *src_row, *dest_row, *src, *dest;
gint row, col;
gint dwidth, dheight, pwidth, pheight;
gint *src_col;
gint bpp, alpha, has_alpha, b;
guchar check;
dwidth = srcrgn->w;
dheight = srcrgn->h;
if( GTK_PREVIEW(preview)->buffer )
{
pwidth = GTK_PREVIEW(preview)->buffer_width;
pheight = GTK_PREVIEW(preview)->buffer_height;
}
else
{
pwidth = preview->requisition.width;
pheight = preview->requisition.height;
}
bpp = srcrgn->bpp;
alpha = bpp;
has_alpha = gimp_drawable_has_alpha( srcrgn->drawable->drawable_id );
if( has_alpha ) alpha--;
/* printf("render_preview: %d %d %d", bpp, alpha, has_alpha);
printf(" (%d %d %d %d)\n", dwidth, dheight, pwidth, pheight); */
src_row = g_new ( guchar, dwidth * bpp );
dest_row = g_new ( guchar, pwidth * bpp );
src_col = g_new ( gint, pwidth );
for ( col = 0; col < pwidth; col++ )
src_col[ col ] = ( col * dwidth / pwidth ) * bpp;
for ( row = 0; row < pheight; row++ )
{
gimp_pixel_rgn_get_row ( srcrgn, src_row,
0, row * dheight / pheight, dwidth );
dest = dest_row;
for ( col = 0; col < pwidth; col++ )
{
src = &src_row[ src_col[col] ];
if( !has_alpha || src[alpha] == OPAQUE )
{
/* no alpha channel or opaque -- simple way */
for ( b = 0; b < alpha; b++ )
dest[b] = src[b];
}
else
{
/* more or less transparent */
if( ( col % (CHECKWIDTH*2) < CHECKWIDTH ) ^
( row % (CHECKWIDTH*2) < CHECKWIDTH ) )
check = LIGHTCHECK;
else
check = DARKCHECK;
if ( src[alpha] == 0 )
{
/* full transparent -- check */
for ( b = 0; b < alpha; b++ )
dest[b] = check;
}
else
{
/* middlemost transparent -- mix check and src */
for ( b = 0; b < alpha; b++ )
dest[b] = ( src[b]*src[alpha] + check*(OPAQUE-src[alpha]) ) / OPAQUE;
}
}
dest += alpha;
}
gtk_preview_draw_row( GTK_PREVIEW( preview ), dest_row,
0, row, pwidth );
}
g_free ( src_col );
g_free ( src_row );
g_free ( dest_row );
} /* end render_preview */
/* ============================================================================
* mov_path_prevw_draw
* Preview Rendering Util routine End
* if update & PATH_LINE, draw the path lines
* if update & CURSOR, draw cross cursor
* ============================================================================
*/
static void
mov_path_prevw_draw ( t_mov_path_preview *path_ptr, gint update )
{
gint l_idx;
GdkColor fg;
GimpRGB foreground;
guchar l_red, l_green, l_blue;
if( update & PREVIEW )
{
path_ptr->cursor = FALSE;
if(gap_debug) printf("draw-preview\n");
}
/* alternate cross cursor OR path graph */
if((path_ptr->show_path)
&& ( pvals != NULL )
&& (update & PATH_LINE))
{
if(gap_debug) printf("draw-preview re-render for PATH draw\n");
if((path_ptr->PixelRgnIsInitialized)
&& (path_ptr->preview))
{
/* redraw the preview
* (to clear path lines and cross cursor)
*/
gtk_widget_draw(path_ptr->preview, NULL);
}
gimp_palette_get_foreground (&foreground);
gimp_rgb_get_uchar (&foreground, &l_red, &l_green, &l_blue);
fg.pixel = gdk_rgb_xpixel_from_rgb ((l_red << 16) | (l_green << 8) | l_blue);
gdk_gc_set_foreground (path_ptr->preview->style->black_gc, &fg);
p_points_to_tab(path_ptr);
for(l_idx = 0; l_idx < pvals->point_idx_max; l_idx++)
{
/* draw the path line(s) */
gdk_draw_line (path_ptr->preview->window,
path_ptr->preview->style->black_gc,
(pvals->point[l_idx].p_x * path_ptr->pwidth) / path_ptr->dwidth,
(pvals->point[l_idx].p_y * path_ptr->pheight) / path_ptr->dheight,
(pvals->point[l_idx +1].p_x * path_ptr->pwidth) / path_ptr->dwidth,
(pvals->point[l_idx +1].p_y * path_ptr->pheight) / path_ptr->dheight
);
/* draw the path point(s) */
gdk_draw_arc (path_ptr->preview->window, path_ptr->preview->style->black_gc, TRUE,
(pvals->point[l_idx +1].p_x * path_ptr->pwidth / path_ptr->dwidth) -RADIUS,
(pvals->point[l_idx +1].p_y * path_ptr->pheight / path_ptr->dheight) -RADIUS,
RADIUS * 2, RADIUS * 2, 0, 23040);
}
/* draw the start point */
gdk_draw_arc (path_ptr->preview->window, path_ptr->preview->style->black_gc, TRUE,
(pvals->point[0].p_x * path_ptr->pwidth / path_ptr->dwidth) -RADIUS,
(pvals->point[0].p_y * path_ptr->pheight / path_ptr->dheight) -RADIUS,
RADIUS * 2, RADIUS * 2, 0, 23040);
/* restore black gc */
fg.pixel = gdk_rgb_xpixel_from_rgb (0);
gdk_gc_set_foreground (path_ptr->preview->style->black_gc, &fg);
}
if( update & CURSOR )
{
if(gap_debug) printf("draw-cursor %d old=%d,%d cur=%d,%d\n",
path_ptr->cursor, path_ptr->oldx, path_ptr->oldy, path_ptr->curx, path_ptr->cury);
gdk_gc_set_function ( path_ptr->preview->style->black_gc, GDK_INVERT);
if( path_ptr->cursor )
{
gdk_draw_line ( path_ptr->preview->window,
path_ptr->preview->style->black_gc,
path_ptr->oldx, 1, path_ptr->oldx, path_ptr->pheight-1 );
gdk_draw_line ( path_ptr->preview->window,
path_ptr->preview->style->black_gc,
1, path_ptr->oldy, path_ptr->pwidth-1, path_ptr->oldy );
}
gdk_draw_line ( path_ptr->preview->window,
path_ptr->preview->style->black_gc,
path_ptr->curx, 1, path_ptr->curx, path_ptr->pheight-1 );
gdk_draw_line ( path_ptr->preview->window,
path_ptr->preview->style->black_gc,
1, path_ptr->cury, path_ptr->pwidth-1, path_ptr->cury );
/* current position of cursor is updated */
path_ptr->oldx = path_ptr->curx;
path_ptr->oldy = path_ptr->cury;
path_ptr->cursor = TRUE;
gdk_gc_set_function ( path_ptr->preview->style->black_gc, GDK_COPY);
}
}
/*
* mov_path_xy_adjustment_update
*/
static void
mov_path_x_adjustment_update( GtkWidget *widget,
gpointer data )
{
t_mov_path_preview *path_ptr;
gint old_val;
path_ptr = (t_mov_path_preview *)data;
if(path_ptr == NULL) return;
old_val = path_ptr->p_x;
gimp_int_adjustment_update(GTK_ADJUSTMENT(widget), &path_ptr->p_x);
if( old_val != path_ptr->p_x )
{
if( !path_ptr->in_call )
{
mov_path_prevw_cursor_update( path_ptr );
mov_path_prevw_draw ( path_ptr, CURSOR | PATH_LINE );
}
}
}
static void
mov_path_y_adjustment_update( GtkWidget *widget,
gpointer data )
{
t_mov_path_preview *path_ptr;
gint old_val;
path_ptr = (t_mov_path_preview *)data;
if(path_ptr == NULL) return;
old_val = path_ptr->p_y;
gimp_int_adjustment_update(GTK_ADJUSTMENT(widget), &path_ptr->p_y);
if( old_val != path_ptr->p_y )
{
if( !path_ptr->in_call )
{
mov_path_prevw_cursor_update( path_ptr );
mov_path_prevw_draw ( path_ptr, CURSOR | PATH_LINE );
}
}
}
/*
* Update the cross cursor's coordinates accoding to pvals->[xy]path_prevw
* but not redraw it
*/
static void
mov_path_prevw_cursor_update ( t_mov_path_preview *path_ptr )
{
path_ptr->curx = path_ptr->p_x * path_ptr->pwidth / path_ptr->dwidth;
path_ptr->cury = path_ptr->p_y * path_ptr->pheight / path_ptr->dheight;
if( path_ptr->curx < 0 ) path_ptr->curx = 0;
else if( path_ptr->curx >= path_ptr->pwidth ) path_ptr->curx = path_ptr->pwidth-1;
if( path_ptr->cury < 0 ) path_ptr->cury = 0;
else if( path_ptr->cury >= path_ptr->pheight) path_ptr->cury = path_ptr->pheight-1;
}
/*
* Handle the expose event on the preview
*/
static gint
mov_path_prevw_preview_expose( GtkWidget *widget,
GdkEvent *event )
{
t_mov_path_preview *path_ptr;
path_ptr = gtk_object_get_user_data( GTK_OBJECT(widget) );
if((!path_ptr->PixelRgnIsInitialized)
|| (path_ptr->in_call))
{
return FALSE;
}
path_ptr->in_call = TRUE;
mov_path_prevw_draw( path_ptr, ALL );
path_ptr->in_call = FALSE;
return FALSE;
}
/*
* Handle other events on the preview
*/
static gint
mov_path_prevw_preview_events ( GtkWidget *widget,
GdkEvent *event )
{
t_mov_path_preview *path_ptr;
GdkEventButton *bevent;
GdkEventMotion *mevent;
gint upd_flag;
gint mouse_button;
path_ptr = gtk_object_get_user_data ( GTK_OBJECT(widget) );
/* HINT:
* smooth update of both CURSOR and PATH_LINE
* on every mousemove works fine on machines with 300MHz.
* for slower machines it is better to paint just the cross cursor,
* and refresh the path lines only at
* button press and release events
*/
/* upd_flag = CURSOR | PATH_LINE; */
upd_flag = CURSOR;
mouse_button = 0;
switch (event->type)
{
case GDK_EXPOSE:
break;
case GDK_BUTTON_RELEASE:
bevent = (GdkEventButton *) event;
mouse_button = 0 - bevent->button;
goto mbuttons;
case GDK_BUTTON_PRESS:
bevent = (GdkEventButton *) event;
mouse_button = bevent->button;
mbuttons:
path_ptr->curx = bevent->x;
path_ptr->cury = bevent->y;
upd_flag = CURSOR | PATH_LINE;
goto mouse;
case GDK_MOTION_NOTIFY:
mevent = (GdkEventMotion *) event;
if ( !mevent->state ) break;
path_ptr->curx = mevent->x;
path_ptr->cury = mevent->y;
mouse:
if((mouse_button == 1)
&& (path_ptr->show_path))
{
/* Picking of pathpoints is done only if
* the left mousebutton goes down (mouse_button == 1)
* and only if Path is visible
*/
p_points_to_tab(path_ptr);
path_ptr->p_x = path_ptr->curx * path_ptr->dwidth / path_ptr->pwidth;
path_ptr->p_y = path_ptr->cury * path_ptr->dheight / path_ptr->pheight;
p_pick_nearest_point(path_ptr->p_x, path_ptr->p_y);
p_point_refresh(path_ptr);
}
else
{
path_ptr->p_x = path_ptr->curx * path_ptr->dwidth / path_ptr->pwidth;
path_ptr->p_y = path_ptr->cury * path_ptr->dheight / path_ptr->pheight;
p_points_to_tab(path_ptr);
mov_path_prevw_cursor_update( path_ptr );
}
mov_path_prevw_draw( path_ptr, upd_flag);
path_ptr->in_call = TRUE;
gtk_adjustment_set_value (path_ptr->x_adj,
(gfloat)path_ptr->p_x);
gtk_adjustment_set_value (path_ptr->y_adj,
(gfloat)path_ptr->p_y);
path_ptr->in_call = FALSE;
break;
default:
break;
}
return FALSE;
}
/* ============================================================================
* p_chk_keyframes
* check if controlpoints and keyframe settings are OK
* return TRUE if OK,
* Pop Up error Dialog window and return FALSE if NOT.
* ============================================================================
*/
gint
p_chk_keyframes(t_mov_path_preview *path_ptr)
{
#define ARGC_ERRWINDOW 2
static t_arr_arg argv[ARGC_APV];
gint l_idx;
gchar *l_err_lbltext;
static t_but_arg b_argv[2];
static gint keychk_locked = FALSE;
p_points_to_tab(path_ptr);
l_err_lbltext = p_gap_chk_keyframes(pvals);
if(*l_err_lbltext != '\0')
{
if(!keychk_locked)
{
keychk_locked = TRUE;
p_init_arr_arg(&argv[0], WGT_LABEL);
argv[0].label_txt = _("Can't operate with current Controlpoint\nor Keyframe settings");
p_init_arr_arg(&argv[1], WGT_LABEL);
argv[1].label_txt = l_err_lbltext;
p_arr_gtk_init(FALSE);
b_argv[0].but_txt = _("Reset Keyframes");
b_argv[0].but_val = TRUE;
b_argv[1].but_txt = GTK_STOCK_CANCEL;
b_argv[1].but_val = FALSE;
if(TRUE == p_array_std_dialog( _("Move Path Controlpointcheck"),
_("Errors:"),
ARGC_ERRWINDOW, argv,
2, b_argv, TRUE))
{
/* Reset all keyframes */
for(l_idx = 0; l_idx <= pvals->point_idx_max; l_idx++ )
{
pvals->point[l_idx].keyframe = 0;
pvals->point[l_idx].keyframe_abs = 0;
p_point_refresh(path_ptr);
}
}
keychk_locked = FALSE;
}
g_free(l_err_lbltext);
return(FALSE);
}
g_free(l_err_lbltext);
return(TRUE);
} /* end p_chk_keyframes */
/* ============================================================================
* p_get_flattened_layer
* flatten the given image and return pointer to the
* (only) remaining drawable.
* ============================================================================
*/
gint32
p_get_flattened_layer(gint32 image_id, GimpMergeType mergemode)
{
GimpImageBaseType l_type;
guint l_width, l_height;
gint32 l_layer_id;
/* get info about the image */
l_width = gimp_image_width(image_id);
l_height = gimp_image_height(image_id);
l_type = gimp_image_base_type(image_id);
l_type = (l_type * 2); /* convert from GimpImageBaseType to GimpImageType */
/* add 2 full transparent dummy layers at top
* (because gimp_image_merge_visible_layers complains
* if there are less than 2 visible layers)
*/
l_layer_id = gimp_layer_new(image_id, "dummy",
l_width, l_height, l_type,
0.0, /* Opacity full transparent */
0); /* NORMAL */
gimp_image_add_layer(image_id, l_layer_id, 0);
l_layer_id = gimp_layer_new(image_id, "dummy",
10, 10, l_type,
0.0, /* Opacity full transparent */
0); /* NORMAL */
gimp_image_add_layer(image_id, l_layer_id, 0);
return gimp_image_merge_visible_layers (image_id, mergemode);
} /* end p_get_flattened_layer */
/* ============================================================================
* p_get_flattened_drawable
* flatten the given image and return pointer to the
* (only) remaining drawable.
* ============================================================================
*/
GimpDrawable *
p_get_flattened_drawable(gint32 image_id)
{
GimpDrawable *l_drawable_ptr ;
l_drawable_ptr = gimp_drawable_get (p_get_flattened_layer(image_id, GIMP_CLIP_TO_IMAGE));
return l_drawable_ptr;
} /* end p_get_flattened_drawable */
/* ============================================================================
* add the selected source layer to the temp. preview image
* (modified accordung to current settings)
* then flatten the temporary preview image,
* and return pointer to the (only) remaining drawable.
* ============================================================================
*/
GimpDrawable *
p_get_prevw_drawable (t_mov_path_preview *path_ptr)
{
t_mov_current l_curr;
gint l_nlayers;
/* check if we have a source layer (to add to the preview) */
if((pvals->src_layer_id >= 0) && (pvals->src_image_id >= 0))
{
p_points_to_tab(path_ptr);
/* calculate current settings */
l_curr.dst_frame_nr = 0;
l_curr.currX = (gdouble)path_ptr->p_x;
l_curr.currY = (gdouble)path_ptr->p_y;
l_curr.currOpacity = (gdouble)path_ptr->opacity;
l_curr.currWidth = (gdouble)path_ptr->w_resize;
l_curr.currHeight = (gdouble)path_ptr->h_resize;
l_curr.currRotation = (gdouble)path_ptr->rotation;
l_curr.src_layer_idx = 0;
l_curr.src_layers = gimp_image_get_layers (pvals->src_image_id, &l_nlayers);
if((l_curr.src_layers != NULL) && (l_nlayers > 0))
{
l_curr.src_last_layer = l_nlayers -1;
/* findout index of src_layer_id */
for(l_curr.src_layer_idx = 0;
l_curr.src_layer_idx < l_nlayers;
l_curr.src_layer_idx++)
{
if(l_curr.src_layers[l_curr.src_layer_idx] == pvals->src_layer_id)
break;
}
}
if(pvals->src_stepmode >= GAP_STEP_FRAME)
{
p_fetch_src_frame (pvals, -1); /* negative value fetches the selected frame number */
}
/* set offsets (in cur_ptr)
* according to handle_mode and src_img dimension (pvals)
*/
p_set_handle_offsets(pvals, &l_curr);
/* render: add source layer to (temporary) preview image */
p_mov_render(pvals->tmp_image_id, pvals, &l_curr);
if(l_curr.src_layers != NULL) g_free(l_curr.src_layers);
l_curr.src_layers = NULL;
}
/* flatten image, and get the (only) resulting drawable */
return(p_get_flattened_drawable(pvals->tmp_image_id));
} /* end p_get_prevw_drawable */
/* ============================================================================
* p_set_handle_offsets
* set handle offsets according to handle mode and src image dimensions
* ============================================================================
*/
void p_set_handle_offsets(t_mov_values *val_ptr, t_mov_current *cur_ptr)
{
guint l_src_width, l_src_height; /* dimensions of the source image */
/* get dimensions of source image */
if((val_ptr->src_stepmode < GAP_STEP_FRAME)
|| (val_ptr->cache_tmp_image_id < 0))
{
l_src_width = gimp_image_width(val_ptr->src_image_id);
l_src_height = gimp_image_height(val_ptr->src_image_id);
}
else
{
/* for Frame Based Modes use the cached tmp image */
l_src_width = gimp_image_width(val_ptr->cache_tmp_image_id);
l_src_height = gimp_image_height(val_ptr->cache_tmp_image_id);
}
cur_ptr->l_handleX = 0.0;
cur_ptr->l_handleY = 0.0;
switch(val_ptr->src_handle)
{
case GAP_HANDLE_LEFT_BOT:
cur_ptr->l_handleY += l_src_height;
break;
case GAP_HANDLE_RIGHT_TOP:
cur_ptr->l_handleX += l_src_width;
break;
case GAP_HANDLE_RIGHT_BOT:
cur_ptr->l_handleX += l_src_width;
cur_ptr->l_handleY += l_src_height;
break;
case GAP_HANDLE_CENTER:
cur_ptr->l_handleX += (l_src_width / 2);
cur_ptr->l_handleY += (l_src_height / 2);
break;
case GAP_HANDLE_LEFT_TOP:
default:
break;
}
} /* end p_set_handle_offsets */
#define BOUNDS(a,x,y) ((a < x) ? x : ((a > y) ? y : a))
/* ============================================================================
* p_mov_render
* insert current source layer into image
* at current settings (position, size opacity ...)
* ============================================================================
*/
/* why dont use: l_cp_layer_id = gimp_layer_copy(src_id);
* ==> Sorry this procedure works only for layers within the same image !!
* Workaround:
* use my 'private' version of layercopy
*/
gint
p_mov_render(gint32 image_id, t_mov_values *val_ptr, t_mov_current *cur_ptr)
{
gint32 l_cp_layer_id;
gint32 l_cp_layer_mask_id;
gint l_offset_x, l_offset_y; /* new offsets within dest. image */
gint l_src_offset_x, l_src_offset_y; /* layeroffsets as they were in src_image */
guint l_new_width;
guint l_new_height;
guint l_orig_width;
guint l_orig_height;
gint l_resized_flag;
gint32 l_interpolation;
gint lx1, ly1, lx2, ly2;
guint l_image_width;
guint l_image_height;
if(gap_debug) printf("p_mov_render: frame/layer: %ld/%ld X=%f, Y=%f\n"
" Width=%f Height=%f\n"
" Opacity=%f Rotate=%f clip_to_img = %d force_visibility = %d\n"
" src_stepmode = %d\n",
cur_ptr->dst_frame_nr, cur_ptr->src_layer_idx,
cur_ptr->currX, cur_ptr->currY,
cur_ptr->currWidth,
cur_ptr->currHeight,
cur_ptr->currOpacity,
cur_ptr->currRotation,
val_ptr->clip_to_img,
val_ptr->src_force_visible,
val_ptr->src_stepmode);
if(val_ptr->src_stepmode < GAP_STEP_FRAME)
{
if(gap_debug)
{
printf("p_mov_render: Before p_my_layer_copy image_id:%d src_layer_id:%d\n"
,(int)image_id, (int)cur_ptr->src_layers[cur_ptr->src_layer_idx]);
}
/* make a copy of the current source layer
* (using current opacity & paintmode values)
*/
l_cp_layer_id = p_my_layer_copy(image_id,
cur_ptr->src_layers[cur_ptr->src_layer_idx],
cur_ptr->currOpacity,
val_ptr->src_paintmode,
&l_src_offset_x,
&l_src_offset_y);
}
else
{
if(gap_debug)
{
printf("p_mov_render: Before p_my_layer_copy image_id:%d cache_tmp_layer_id:%d\n"
,(int)image_id, (int)val_ptr->cache_tmp_layer_id);
}
/* for FRAME based stepmodes use the flattened layer in the cahed frame image */
l_cp_layer_id = p_my_layer_copy(image_id,
val_ptr->cache_tmp_layer_id,
cur_ptr->currOpacity,
val_ptr->src_paintmode,
&l_src_offset_x,
&l_src_offset_y);
}
/* add the copied layer to current destination image */
if(gap_debug) printf("p_mov_render: after layer copy layer_id=%d\n", (int)l_cp_layer_id);
if(l_cp_layer_id < 0)
{
return -1;
}
gimp_image_add_layer(image_id, l_cp_layer_id,
val_ptr->dst_layerstack);
if(gap_debug) printf("p_mov_render: after add layer\n");
if(val_ptr->src_force_visible)
{
gimp_layer_set_visible(l_cp_layer_id, TRUE);
}
/* check for layermask */
l_cp_layer_mask_id = gimp_layer_get_mask_id(l_cp_layer_id);
if(l_cp_layer_mask_id >= 0)
{
/* apply the layermask
* some transitions (especially rotate) can't operate proper on
* layers with masks !
* (tests with gimp-rotate resulted in trashed images,
* even if the mask was rotated too)
*/
gimp_image_remove_layer_mask(image_id, l_cp_layer_id, 0 /* 0==APPLY */ );
}
l_resized_flag = 0;
l_orig_width = gimp_drawable_width(l_cp_layer_id);
l_orig_height = gimp_drawable_height(l_cp_layer_id);
l_new_width = l_orig_width;
l_new_height = l_orig_height;
if((cur_ptr->currWidth > 100.01) || (cur_ptr->currWidth < 99.99)
|| (cur_ptr->currHeight > 100.01) || (cur_ptr->currHeight < 99.99))
{
/* have to scale layer */
l_resized_flag = 1;
l_new_width = (l_orig_width * cur_ptr->currWidth) / 100;
l_new_height = (l_orig_height * cur_ptr->currHeight) / 100;
gimp_layer_scale(l_cp_layer_id, l_new_width, l_new_height, 0);
}
if((cur_ptr->currRotation > 0.5) || (cur_ptr->currRotation < -0.5))
{
l_resized_flag = 1;
l_interpolation = 1; /* rotate always with smoothing option turned on */
/* have to rotate the layer (rotation also changes size as needed) */
p_gimp_rotate(l_cp_layer_id, l_interpolation, cur_ptr->currRotation);
l_new_width = gimp_drawable_width(l_cp_layer_id);
l_new_height = gimp_drawable_height(l_cp_layer_id);
}
if(l_resized_flag == 1)
{
/* adjust offsets according to handle and change of size */
switch(val_ptr->src_handle)
{
case GAP_HANDLE_LEFT_BOT:
l_src_offset_y += ((gint)l_orig_height - (gint)l_new_height);
break;
case GAP_HANDLE_RIGHT_TOP:
l_src_offset_x += ((gint)l_orig_width - (gint)l_new_width);
break;
case GAP_HANDLE_RIGHT_BOT:
l_src_offset_x += ((gint)l_orig_width - (gint)l_new_width);
l_src_offset_y += ((gint)l_orig_height - (gint)l_new_height);
break;
case GAP_HANDLE_CENTER:
l_src_offset_x += (((gint)l_orig_width - (gint)l_new_width) / 2);
l_src_offset_y += (((gint)l_orig_height - (gint)l_new_height) / 2);
break;
case GAP_HANDLE_LEFT_TOP:
default:
break;
}
}
/* calculate offsets in destination image */
l_offset_x = (cur_ptr->currX - cur_ptr->l_handleX) + l_src_offset_x;
l_offset_y = (cur_ptr->currY - cur_ptr->l_handleY) + l_src_offset_y;
/* modify coordinate offsets of the copied layer within dest. image */
gimp_layer_set_offsets(l_cp_layer_id, l_offset_x, l_offset_y);
/* clip the handled layer to image size if desired */
if(val_ptr->clip_to_img != 0)
{
l_image_width = gimp_image_width(image_id);
l_image_height = gimp_image_height(image_id);
lx1 = BOUNDS (l_offset_x, 0, l_image_width);
ly1 = BOUNDS (l_offset_y, 0, l_image_height);
lx2 = BOUNDS ((l_new_width + l_offset_x), 0, l_image_width);
ly2 = BOUNDS ((l_new_height + l_offset_y), 0, l_image_height);
l_new_width = lx2 - lx1;
l_new_height = ly2 - ly1;
if (l_new_width && l_new_height)
{
gimp_layer_resize(l_cp_layer_id, l_new_width, l_new_height,
-(lx1 - l_offset_x),
-(ly1 - l_offset_y));
}
else
{
/* no part of the layer is inside of the current frame (this image)
* instead of removing we make the layer small and move him outside
* the image.
* (that helps to keep the layerstack position of the inserted layer(s)
* constant in all handled anim_frames)
*/
gimp_layer_resize(l_cp_layer_id, 2, 2, -3, -3);
}
}
if(gap_debug) printf("GAP p_mov_render: exit OK\n");
return 0;
} /* end p_mov_render */
/* ============================================================================
* p_buildmenu
* build menu widget for all Items passed in the MenuItems Parameter
* MenuItems is an array of Pointers to Structure MenuItem.
* The End is marked by a Structure Member where the label is a NULL pointer
* (simplifyed version of GIMP 1.0.2 bulid_menu procedur)
* ============================================================================
*/
GtkWidget *
p_buildmenu (MenuItem *items)
{
GtkWidget *menu;
GtkWidget *menu_item;
menu = gtk_menu_new ();
while (items->label)
{
menu_item = gtk_menu_item_new_with_label (items->label);
gtk_container_add (GTK_CONTAINER (menu), menu_item);
if (items->callback)
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
(GtkSignalFunc) items->callback,
items->user_data);
gtk_widget_show (menu_item);
items->widget = menu_item;
items++;
}
return menu;
} /* end p_buildmenu */
/* ============================================================================
* p_fetch_src_frame
* fetch the requested AnimFrame SourceImage into cache_tmp_image_id
* and
* - reduce all visible layer to one layer (cache_tmp_layer_id)
* - (scale to animated preview size if called for AnimPreview )
* - reuse cached image (for subsequent calls for the same framenumber
* of the same source image -- for GAP_STEP_FRAME_NONE
* - never load current frame number from diskfile (use duplicate of the src_image)
* returns 0 (OK) or -1 (on Errors)
* ============================================================================
*/
gint
p_fetch_src_frame(t_mov_values *pvals, gint32 wanted_frame_nr)
{
t_anim_info *l_ainfo_ptr;
t_anim_info *l_old_ainfo_ptr;
if(gap_debug)
{
printf("p_fetch_src_frame: START src_image_id: %d wanted_frame_nr:%d"
" cache_src_image_id:%d cache_frame_number:%d\n"
, (int)pvals->src_image_id
, (int)wanted_frame_nr
, (int)pvals->cache_src_image_id
, (int)pvals->cache_frame_number
);
}
if(pvals->src_image_id < 0)
{
return -1;
}
if((pvals->src_image_id != pvals->cache_src_image_id)
|| (wanted_frame_nr != pvals->cache_frame_number))
{
if(pvals->cache_tmp_image_id >= 0)
{
if(gap_debug)
{
printf("p_fetch_src_frame: DELETE cache_tmp_image_id:%d\n",
(int)pvals->cache_tmp_image_id);
}
/* destroy the cached frame image */
gimp_image_delete(pvals->cache_tmp_image_id);
pvals->cache_tmp_image_id = -1;
}
l_ainfo_ptr = p_alloc_ainfo(pvals->src_image_id, GIMP_RUN_NONINTERACTIVE);
if(pvals->cache_ainfo_ptr == NULL)
{
pvals->cache_ainfo_ptr = l_ainfo_ptr;
}
else
{
if ((pvals->src_image_id == pvals->cache_src_image_id)
&& (strcmp(pvals->cache_ainfo_ptr->basename, l_ainfo_ptr->basename) == 0))
{
pvals->cache_ainfo_ptr->curr_frame_nr = l_ainfo_ptr->curr_frame_nr;
p_free_ainfo(&l_ainfo_ptr);
}
else
{
/* update cached ainfo if source image has changed
* (either by id or by its basename)
*/
l_old_ainfo_ptr = pvals->cache_ainfo_ptr;
pvals->cache_ainfo_ptr = l_ainfo_ptr;
p_free_ainfo(&l_old_ainfo_ptr);
}
}
if ((wanted_frame_nr == pvals->cache_ainfo_ptr->curr_frame_nr)
|| (wanted_frame_nr < 0))
{
/* always take the current source frame from the already opened image
* not only for speedup reasons. (the diskfile may contain non actual imagedata)
*/
pvals->cache_tmp_image_id = gimp_image_duplicate(pvals->src_image_id);
wanted_frame_nr = pvals->cache_ainfo_ptr->curr_frame_nr;
}
else
{
/* build the source framename */
if(pvals->cache_ainfo_ptr->new_filename != NULL)
{
g_free(pvals->cache_ainfo_ptr->new_filename);
}
pvals->cache_ainfo_ptr->new_filename = p_alloc_fname(pvals->cache_ainfo_ptr->basename,
wanted_frame_nr,
pvals->cache_ainfo_ptr->extension);
if(pvals->cache_ainfo_ptr->new_filename == NULL)
{
printf("gap: error got no source frame filename\n");
return -1;
}
/* load the wanted source frame */
pvals->cache_tmp_image_id = p_load_image(pvals->cache_ainfo_ptr->new_filename);
if(pvals->cache_tmp_image_id < 0)
{
printf("gap: load error on src image %s\n", pvals->cache_ainfo_ptr->new_filename);
return -1;
}
}
pvals->cache_tmp_layer_id = p_get_flattened_layer(pvals->cache_tmp_image_id, GIMP_EXPAND_AS_NECESSARY);
/* check if we are generating an anim preview
* where we must Scale (down) the src image to preview size
*/
if ((pvals->apv_mlayer_image >= 0)
&& ((pvals->apv_scalex != 100.0) || (pvals->apv_scaley != 100.0)))
{
GimpParam *l_params;
gint l_retvals;
gint32 l_size_x, l_size_y;
if(gap_debug)
{
printf("p_fetch_src_frame: Scale for Animpreview apv_scalex %f apv_scaley %f\n"
, (float)pvals->apv_scalex, (float)pvals->apv_scaley );
}
l_size_x = (gimp_image_width(pvals->cache_tmp_image_id) * pvals->apv_scalex) / 100;
l_size_y = (gimp_image_height(pvals->cache_tmp_image_id) * pvals->apv_scaley) / 100;
l_params = gimp_run_procedure ("gimp_image_scale",
&l_retvals,
GIMP_PDB_IMAGE, pvals->cache_tmp_image_id,
GIMP_PDB_INT32, l_size_x,
GIMP_PDB_INT32, l_size_y,
GIMP_PDB_END);
}
pvals->cache_src_image_id = pvals->src_image_id;
pvals->cache_frame_number = wanted_frame_nr;
}
return 0; /* OK */
} /* end p_fetch_src_frame */