mirror of https://github.com/GNOME/gimp.git
2671 lines
87 KiB
C
2671 lines
87 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.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 (cant 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"
|
|
|
|
|
|
/* 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
|
|
{
|
|
GDrawable *drawable;
|
|
gint dwidth, dheight;
|
|
gint bpp;
|
|
GtkWidget *preview;
|
|
GPixelRgn 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;
|
|
gchar PointIndex_Label[LABEL_LENGTH];
|
|
GtkWidget *PointIndex_LabelPtr;
|
|
gint p_x, p_y;
|
|
gint opacity;
|
|
gint w_resize;
|
|
gint h_resize;
|
|
gint rotation;
|
|
|
|
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;
|
|
};
|
|
|
|
/* 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 GDrawable * p_get_flattened_drawable (gint32 image_id);
|
|
static GDrawable * p_get_prevw_drawable (t_mov_path_preview *path_ptr);
|
|
|
|
static gint mov_dialog ( GDrawable *drawable, t_mov_path_preview *path_ptr,
|
|
gint min, gint max);
|
|
static GtkWidget * mov_path_prevw_create ( GDrawable *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 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_pres_callback (GtkWidget *widget,gpointer data);
|
|
static void mov_pclr_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 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) NORMAL_MODE, NULL, NULL },
|
|
{ N_("Dissolve"), 0, 0, mov_paintmode_menu_callback, (gpointer) DISSOLVE_MODE, NULL, NULL },
|
|
{ N_("Multiply"), 0, 0, mov_paintmode_menu_callback, (gpointer) MULTIPLY_MODE, NULL, NULL },
|
|
{ N_("Screen"), 0, 0, mov_paintmode_menu_callback, (gpointer) SCREEN_MODE, NULL, NULL },
|
|
{ N_("Overlay"), 0, 0, mov_paintmode_menu_callback, (gpointer) OVERLAY_MODE, NULL, NULL },
|
|
{ N_("Difference"), 0, 0, mov_paintmode_menu_callback, (gpointer) DIFFERENCE_MODE, NULL, NULL },
|
|
{ N_("Addition"), 0, 0, mov_paintmode_menu_callback, (gpointer) ADDITION_MODE, NULL, NULL },
|
|
{ N_("Subtract"), 0, 0, mov_paintmode_menu_callback, (gpointer) SUBTRACT_MODE, NULL, NULL },
|
|
{ N_("Darken Only"), 0, 0, mov_paintmode_menu_callback, (gpointer) DARKEN_ONLY_MODE, NULL, NULL },
|
|
{ N_("Lighten Only"), 0, 0, mov_paintmode_menu_callback, (gpointer) LIGHTEN_ONLY_MODE, NULL, NULL },
|
|
{ N_("Hue"), 0, 0, mov_paintmode_menu_callback, (gpointer) HUE_MODE, NULL, NULL },
|
|
{ N_("Saturation"), 0, 0, mov_paintmode_menu_callback, (gpointer) SATURATION_MODE, NULL, NULL },
|
|
{ N_("Color"), 0, 0, mov_paintmode_menu_callback, (gpointer) COLOR_MODE, NULL, NULL },
|
|
{ N_("Value"), 0, 0, mov_paintmode_menu_callback, (gpointer) 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 },
|
|
{ NULL, 0, 0, NULL, NULL, NULL, NULL }
|
|
};
|
|
|
|
|
|
|
|
static t_mov_values *pvals;
|
|
|
|
static t_mov_interface mov_int =
|
|
{
|
|
FALSE /* run */
|
|
};
|
|
|
|
|
|
/* ============================================================================
|
|
**********************
|
|
* *
|
|
* Dialog interface *
|
|
* *
|
|
**********************
|
|
* ============================================================================
|
|
*/
|
|
|
|
long p_move_dialog (t_mov_data *mov_ptr)
|
|
{
|
|
GDrawable *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 cant alloc path_preview structure\n");
|
|
return -1;
|
|
}
|
|
path_ptr->show_path = TRUE;
|
|
path_ptr->startup = TRUE;
|
|
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 = NORMAL_MODE;
|
|
pvals->src_handle = GAP_HANDLE_LEFT_TOP;
|
|
pvals->src_stepmode = GAP_STEP_LOOP;
|
|
pvals->src_only_visible = 0;
|
|
pvals->clip_to_img = 0;
|
|
|
|
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 = p_gimp_channel_ops_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 ( GDrawable *drawable, t_mov_path_preview *path_ptr,
|
|
gint first_nr, gint last_nr )
|
|
{
|
|
GtkWidget *vbox;
|
|
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;
|
|
guchar *color_cube;
|
|
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 ());
|
|
|
|
|
|
gdk_set_use_xshm (gimp_use_xshm ());
|
|
gtk_preview_set_gamma (gimp_gamma ());
|
|
gtk_preview_set_install_cmap (gimp_install_cmap ());
|
|
color_cube = gimp_color_cube ();
|
|
gtk_preview_set_color_cube (color_cube[0], color_cube[1],
|
|
color_cube[2], color_cube[3]);
|
|
|
|
gtk_widget_set_default_visual (gtk_preview_get_visual ());
|
|
gtk_widget_set_default_colormap (gtk_preview_get_cmap ());
|
|
|
|
/* 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_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_with_label ( _("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 \nSrcLayer at current Controlpoint")
|
|
, NULL);
|
|
gtk_widget_show (button);
|
|
|
|
button = gtk_button_new_with_label ( _("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_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_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\nbutton 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\nDst. 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);
|
|
|
|
/* 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_state (GTK_TOGGLE_BUTTON (check_button), pvals->clip_to_img);
|
|
gimp_help_set_help_data(check_button,
|
|
_("Clip all copied Src-Layers\nat Frame Boundaries")
|
|
, NULL);
|
|
gtk_widget_show (check_button);
|
|
gtk_table_attach(GTK_TABLE(hbox_table), check_button, 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(RUN_INTERACTIVE,
|
|
_("No Source Image was selected\n"
|
|
"(Please open a 2nd Image of the same type before opening Move Path)"));
|
|
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 = p_gimp_channel_ops_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
|
|
p_copy_point(gint from_idx, gint to_idx)
|
|
{
|
|
pvals->point[from_idx].p_x = pvals->point[to_idx].p_x;
|
|
pvals->point[from_idx].p_y = pvals->point[to_idx].p_y;
|
|
pvals->point[from_idx].opacity = pvals->point[to_idx].opacity;
|
|
pvals->point[from_idx].w_resize = pvals->point[to_idx].w_resize;
|
|
pvals->point[from_idx].h_resize = pvals->point[to_idx].h_resize;
|
|
pvals->point[from_idx].rotation = pvals->point[to_idx].rotation;
|
|
}
|
|
|
|
|
|
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 next 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_pres_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
t_mov_path_preview *path_ptr = data;
|
|
|
|
if(gap_debug) printf("mov_pres_callback\n");
|
|
p_reset_points();
|
|
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_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_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;
|
|
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;
|
|
char *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);
|
|
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)
|
|
{
|
|
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;
|
|
}
|
|
|
|
static void
|
|
p_points_to_tab(t_mov_path_preview *path_ptr)
|
|
{
|
|
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;
|
|
}
|
|
|
|
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(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) */
|
|
}
|
|
} /* 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)
|
|
{
|
|
#define POINT_REC_MAX 128
|
|
|
|
FILE *l_fp;
|
|
gint l_idx;
|
|
char l_buff[POINT_REC_MAX +1 ];
|
|
char *l_ptr;
|
|
gint l_cnt;
|
|
gint l_v1, l_v2, l_v3, l_v4, l_v5, l_v6;
|
|
|
|
if(filename == NULL) return;
|
|
|
|
l_fp = fopen(filename, "r");
|
|
if(l_fp != NULL)
|
|
{
|
|
l_idx = -1;
|
|
while (NULL != fgets (l_buff, POINT_REC_MAX, l_fp))
|
|
{
|
|
/* skip leading blanks */
|
|
l_ptr = l_buff;
|
|
while(*l_ptr == ' ') { l_ptr++; }
|
|
|
|
/* check if line empty or comment only (starts with '#') */
|
|
if((*l_ptr != '#') && (*l_ptr != '\n') && (*l_ptr != '\0'))
|
|
{
|
|
l_cnt = sscanf(l_ptr, "%d%d%d%d%d%d", &l_v1, &l_v2, &l_v3, &l_v4, &l_v5, &l_v6);
|
|
if(l_idx == -1)
|
|
{
|
|
if((l_cnt < 2) || (l_v2 > GAP_MOV_MAX_POINT) || (l_v1 > l_v2))
|
|
{
|
|
break;
|
|
}
|
|
pvals->point_idx = l_v1;
|
|
pvals->point_idx_max = l_v2 -1;
|
|
l_idx = 0;
|
|
}
|
|
else
|
|
{
|
|
if(l_cnt != 6)
|
|
{
|
|
p_reset_points();
|
|
break;
|
|
}
|
|
pvals->point[l_idx].p_x = l_v1;
|
|
pvals->point[l_idx].p_y = l_v2;
|
|
pvals->point[l_idx].w_resize = l_v3;
|
|
pvals->point[l_idx].h_resize = l_v4;
|
|
pvals->point[l_idx].opacity = l_v5;
|
|
pvals->point[l_idx].rotation = l_v6;
|
|
l_idx ++;
|
|
}
|
|
|
|
if(l_idx > pvals->point_idx_max) break;
|
|
}
|
|
}
|
|
|
|
fclose(l_fp);
|
|
}
|
|
}
|
|
|
|
/* ============================================================================
|
|
* p_save_points
|
|
* save point table (from global pvals into named file)
|
|
* ============================================================================
|
|
*/
|
|
void p_save_points(char *filename)
|
|
{
|
|
FILE *l_fp;
|
|
gint l_idx;
|
|
|
|
if(filename == NULL) return;
|
|
|
|
l_fp = fopen(filename, "w+");
|
|
if(l_fp != NULL)
|
|
{
|
|
fprintf(l_fp, "# GAP file contains saved Move Path Point Table\n");
|
|
fprintf(l_fp, "%d %d # current_point points\n",
|
|
(int)pvals->point_idx,
|
|
(int)pvals->point_idx_max + 1);
|
|
fprintf(l_fp, "# x y width height opacity rotation\n");
|
|
for(l_idx = 0; l_idx <= pvals->point_idx_max; l_idx++)
|
|
{
|
|
fprintf(l_fp, "%04d %04d %03d %03d %03d %d\n",
|
|
(int)pvals->point[l_idx].p_x,
|
|
(int)pvals->point[l_idx].p_y,
|
|
(int)pvals->point[l_idx].w_resize,
|
|
(int)pvals->point[l_idx].h_resize,
|
|
(int)pvals->point[l_idx].opacity,
|
|
(int)pvals->point[l_idx].rotation);
|
|
}
|
|
|
|
fclose(l_fp);
|
|
}
|
|
} /* 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_border_width( GTK_CONTAINER( frame ), 2 );
|
|
|
|
|
|
table = gtk_table_new ( 2, 4, FALSE );
|
|
gtk_container_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 \nat 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 \nControlpoint 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)
|
|
* ============================================================================
|
|
*/
|
|
|
|
static GtkWidget *
|
|
mov_path_prevw_create ( GDrawable *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->id );
|
|
path_ptr->dheight = gimp_drawable_height(drawable->id );
|
|
path_ptr->bpp = gimp_drawable_bpp(drawable->id);
|
|
if ( gimp_drawable_has_alpha(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_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 (3 rows) */
|
|
table = gtk_table_new ( 3, 6, FALSE );
|
|
gtk_container_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\nin 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\nin 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);
|
|
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_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 7 rows */
|
|
button_table = gtk_table_new (7, 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_state (GTK_TOGGLE_BUTTON (check_button), path_ptr->show_path);
|
|
gimp_help_set_help_data(check_button,
|
|
_("Show Path Lines and enable\n"
|
|
"pick/drag with left button\n"
|
|
"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\nto default Values")
|
|
, NULL);
|
|
gtk_widget_show (button);
|
|
|
|
button = gtk_button_new_with_label ( _("Reset Points"));
|
|
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
|
|
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
(GtkSignalFunc) mov_pres_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 Controlpoints \nto one Defaultpoint")
|
|
, 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, GPixelRgn *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, GPixelRgn *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->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;
|
|
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(&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_get_flattened_drawable
|
|
* flatten the given image and return pointer to the
|
|
* (only) remaining drawable.
|
|
* ============================================================================
|
|
*/
|
|
GDrawable *
|
|
p_get_flattened_drawable(gint32 image_id)
|
|
{
|
|
GDrawable *l_drawable_ptr ;
|
|
GImageType 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 GImageType to GDrawableType */
|
|
|
|
/* 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);
|
|
|
|
l_drawable_ptr = gimp_drawable_get (gimp_image_merge_visible_layers (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.
|
|
* ============================================================================
|
|
*/
|
|
|
|
GDrawable *
|
|
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.deltaX = 0.0;
|
|
l_curr.deltaY = 0.0;
|
|
l_curr.deltaOpacity = 0.0;
|
|
l_curr.deltaWidth = 0.0;
|
|
l_curr.deltaHeight = 0.0;
|
|
l_curr.deltaRotation = 0.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;
|
|
}
|
|
|
|
}
|
|
/* 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);
|
|
}
|
|
|
|
/* 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 */
|
|
l_src_width = gimp_image_width(val_ptr->src_image_id);
|
|
l_src_height = gimp_image_height(val_ptr->src_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\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 );
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
/* 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");
|
|
|
|
/* 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) cant 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_layer_width(l_cp_layer_id);
|
|
l_orig_height = gimp_layer_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_layer_width(l_cp_layer_id);
|
|
l_new_height = gimp_layer_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 */
|