mirror of https://github.com/GNOME/gimp.git
3421 lines
96 KiB
C
3421 lines
96 KiB
C
/* gap_navigator_dialog.c
|
|
* by hof (Wolfgang Hofer)
|
|
*
|
|
* GAP ... Gimp Animation Plugins
|
|
*
|
|
* This Module contains the GAP Video Navigator dialog Window
|
|
* that provides a VCR-GUI for the GAP basic navigation functions.
|
|
*
|
|
*/
|
|
/* 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.
|
|
*/
|
|
|
|
/* TODO:
|
|
* - BUG X11 deadlock if GAP Video Navigator runs another plugin
|
|
* from the double-click callback procedure in the frame listbox,
|
|
* and the other plugin opens a new gtk dialog.
|
|
* (the new dialog does not get the focus)
|
|
* Current workaround:
|
|
* save frames of other types than xcf before the
|
|
* listbox is filled.
|
|
* (this forces the GAP p_decide_save_as Dialog
|
|
* when the Navigator is opened or an image != xcf is
|
|
* selected in the image optionmenu, and sets
|
|
* the fileformat specific save parameters)
|
|
*
|
|
* - BUGFIX or workaround needed: list widget can't handle large lists
|
|
* (test failed at 1093 items maybe there is a limit of 1092 ??)
|
|
*
|
|
* - start of a 2.nd navigator should pop up the 1st one and exit.
|
|
* x- scroll the listbox (active image should always be in the visible (exposed) area
|
|
* problem: 1092 limit !
|
|
* x- implement the unfinished callback procedures
|
|
* x- Updatde Button (to create all missing and out of date thumbnails)
|
|
* x- tooltips
|
|
* x- multiple selections
|
|
* x- timezoom and framerate should be stored in a video info file
|
|
* x- calculate & update for frame timing labels
|
|
* x- Render Preview defaultIcon for images without thumbnail
|
|
* and for preview_size 0 (off)
|
|
*
|
|
* Events that sould be handled:
|
|
* - changes of the active_image (in ram) :: update of one frame_widget
|
|
* x- change of preview_size :: update full frame_widgets list
|
|
* x- changes of the active_image (on disk) :: update of image_menu + full frame_widgets list
|
|
* (maybe i'll set a polling timer event to watch the diskfile)
|
|
* x- close of the active_image (in ram) :: update of image_menu + full frame_widgets list
|
|
*
|
|
* - drag & drop
|
|
* (Problem: gimage struct is not available for plugins,
|
|
* need a Drag&Drop type that operates on image_id)
|
|
* - preferences should have additional video_preview_size
|
|
* (tiny,small,normal,large,huge)
|
|
*
|
|
*/
|
|
|
|
|
|
/* revision history:
|
|
* version 1.1.20a; 2000.04.25 hof: copy/cut/paste menu
|
|
* version 1.1.14a; 2000.01.08 hof: 1st release
|
|
*/
|
|
|
|
static char *gap_navigator_version = "1.1.19a; 2000/04/24";
|
|
|
|
|
|
/* SYTEM (UNIX) includes */
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <signal.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
/* GIMP includes */
|
|
#include <gtk/gtk.h>
|
|
#include "config.h"
|
|
#include <libgimp/stdplugins-intl.h>
|
|
#include <libgimp/gimp.h>
|
|
#include <libgimp/gimpui.h>
|
|
|
|
#include <pixmaps/update.xpm>
|
|
#include <pixmaps/play.xpm>
|
|
#include <pixmaps/duplicate.xpm>
|
|
#include <pixmaps/delete.xpm>
|
|
|
|
#include <pixmaps/prev.xpm>
|
|
#include <pixmaps/next.xpm>
|
|
#include <pixmaps/first.xpm>
|
|
#include <pixmaps/last.xpm>
|
|
|
|
/*
|
|
* OpsButton is not available for plugins in libgimp 1.1.14
|
|
* workaround: include gimp-1.1.14/app/ops_buttons.h /.c
|
|
*/
|
|
|
|
/* --------------------------------------- start copy of gimp-1.1.14/app/ops_buttons.h */
|
|
#ifndef __OPS_BUTTONS_H__
|
|
#define __OPS_BUTTONS_H__
|
|
|
|
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;
|
|
|
|
typedef enum
|
|
{
|
|
OPS_BUTTON_NORMAL,
|
|
OPS_BUTTON_RADIO
|
|
} OpsButtonType;
|
|
|
|
typedef struct _OpsButton OpsButton;
|
|
|
|
struct _OpsButton
|
|
{
|
|
gchar **xpm_data; /* xpm data for the button */
|
|
GtkSignalFunc callback; /* callback function */
|
|
GtkSignalFunc *ext_callbacks; /* callback functions when
|
|
* modifiers are pressed */
|
|
gchar *tooltip;
|
|
gchar *private_tip;
|
|
GtkWidget *widget; /* the button widget */
|
|
gint modifier;
|
|
};
|
|
|
|
/* Function declarations */
|
|
|
|
GtkWidget * ops_button_box_new (GtkWidget *parent,
|
|
OpsButton *ops_button,
|
|
OpsButtonType ops_type);
|
|
|
|
#endif /* __OPS_BUTTONS_H__ */
|
|
/* --------------------------------------- end copy of gimp-1.1.14/app/ops_buttons.h */
|
|
|
|
|
|
/* GAP includes */
|
|
#include "gap_lib.h"
|
|
#include "gap_pdb_calls.h"
|
|
|
|
/* Note:
|
|
* the PDB call of gimp_file_load_thumbnail has a bug in gimp-1.1.14.
|
|
* As workaround i use a copy of gimp-1.1.14/app/fileops.c:readXVThumb
|
|
* to read .xvpics correct directly from file (this is also the faster way)
|
|
*/
|
|
guchar* readXVThumb (const gchar *fnam,
|
|
gint *w,
|
|
gint *h,
|
|
gchar **imginfo /* caller frees if != NULL */);
|
|
|
|
/* some definitions used in all dialogs */
|
|
#define PREVIEW_EVENT_MASK (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | \
|
|
GDK_ENTER_NOTIFY_MASK)
|
|
#define BUTTON_EVENT_MASK (GDK_EXPOSURE_MASK | GDK_ENTER_NOTIFY_MASK | \
|
|
GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | \
|
|
GDK_BUTTON_RELEASE_MASK)
|
|
|
|
#define MAX_HEIGHT_GTK_SCROLLED_WIN 32767
|
|
#define PLUGIN_NAME "plug_in_gap_navigator"
|
|
#define LIST_WIDTH 200
|
|
#define LIST_HEIGHT 150
|
|
#define PREVIEW_BPP 3
|
|
#define THUMBNAIL_BPP 3
|
|
#define MIX_CHANNEL(b, a, m) (((a * m) + (b * (255 - m))) / 255)
|
|
#define PREVIEW_BG_GRAY1 80
|
|
#define PREVIEW_BG_GRAY2 180
|
|
|
|
#define NUPD_IMAGE_MENU 1
|
|
#define NUPD_THUMBFILE_TIMESTAMP 2
|
|
#define NUPD_FRAME_NR_CHANGED 4
|
|
#define NUPD_PREV_LIST 8
|
|
#define NUPD_PREV_LIST_ICONS 16
|
|
#define NUPD_ALL 0xffffffff;
|
|
|
|
typedef struct _OpenFrameImages OpenFrameImages;
|
|
typedef struct _NaviDialog NaviDialog;
|
|
typedef struct _FrameWidget FrameWidget;
|
|
typedef struct _SelectedRange SelectedRange;
|
|
|
|
struct _OpenFrameImages{
|
|
gint32 image_id;
|
|
gint32 frame_nr;
|
|
OpenFrameImages *next;
|
|
};
|
|
|
|
|
|
struct _NaviDialog
|
|
{
|
|
gint tooltip_on;
|
|
GtkWidget *shell;
|
|
GtkWidget *vbox;
|
|
GtkWidget *mode_option_menu;
|
|
GtkWidget *frame_list;
|
|
GtkWidget *scrolled_win;
|
|
GtkWidget *preserve_trans;
|
|
GtkWidget *framerate_box;
|
|
GtkWidget *timezoom_box;
|
|
GtkWidget *image_option_menu;
|
|
GtkWidget *image_menu;
|
|
GtkWidget *ops_menu;
|
|
GtkWidget *copy_menu_item;
|
|
GtkWidget *cut_menu_item;
|
|
GtkWidget *pastea_menu_item;
|
|
GtkWidget *pasteb_menu_item;
|
|
GtkWidget *paster_menu_item;
|
|
GtkWidget *clrpaste_menu_item;
|
|
GtkAccelGroup *accel_group;
|
|
GtkAdjustment *framerate_data;
|
|
GtkAdjustment *timezoom_data;
|
|
GtkWidget *frame_preview;
|
|
GtkWidget *framerange_number_label;
|
|
gint waiting_cursor;
|
|
GdkCursor *cursor_wait;
|
|
GdkCursor *cursor_acitve;
|
|
gint32 paste_at_frame; /* -1: use current frame */
|
|
|
|
gdouble ratio;
|
|
gdouble preview_size;
|
|
gint image_width, image_height;
|
|
gint gimage_width, gimage_height;
|
|
|
|
/* state information */
|
|
gint32 active_imageid;
|
|
gint32 any_imageid;
|
|
t_anim_info *ainfo_ptr;
|
|
t_video_info *vin_ptr;
|
|
GSList *frame_widgets;
|
|
int timer;
|
|
int cycle_time;
|
|
OpenFrameImages *OpenFrameImagesList;
|
|
int OpenFrameImagesCount;
|
|
gint32 item_height;
|
|
};
|
|
|
|
|
|
struct _FrameWidget
|
|
{
|
|
GtkWidget *clip_widget;
|
|
GtkWidget *number_label;
|
|
GtkWidget *time_label;
|
|
GtkWidget *frame_preview;
|
|
GtkWidget *list_item;
|
|
GtkWidget *label;
|
|
|
|
gint32 image_id;
|
|
gint32 frame_nr;
|
|
GdkPixmap *frame_pixmap;
|
|
gint width, height;
|
|
|
|
/* state information */
|
|
gboolean visited;
|
|
time_t thumb_timestamp;
|
|
char *thumb_filename;
|
|
/* GimpDropType drop_type; */
|
|
};
|
|
|
|
|
|
struct _SelectedRange {
|
|
gint32 from;
|
|
gint32 to;
|
|
SelectedRange *next;
|
|
SelectedRange *prev;
|
|
};
|
|
|
|
/* -----------------------
|
|
* procedure declarations
|
|
* -----------------------
|
|
*/
|
|
int gap_navigator(gint32 image_id);
|
|
static void navi_preview_extents (void);
|
|
static void frames_dialog_flush (void);
|
|
static void frames_dialog_update (gint32 image_id);
|
|
static void frame_widget_preview_redraw (FrameWidget *);
|
|
static void navi_vid_copy_and_cut(gint cut_flag);
|
|
|
|
static gint navi_images_menu_constrain (gint32 image_id, gint32 drawable_id, gpointer data);
|
|
static void navi_images_menu_callback (gint32 id, gpointer data);
|
|
static void navi_update_after_goto(void);
|
|
static SelectedRange *navi_get_selected_ranges(void);
|
|
static void navi_ops_menu_set_sensitive(void);
|
|
|
|
static void navi_dialog_thumb_update_callback(GtkWidget *w, gpointer data);
|
|
static void navi_dialog_thumb_updateall_callback(GtkWidget *w, gpointer data);
|
|
static void navi_dialog_vcr_play_callback(GtkWidget *w, gpointer data);
|
|
static void navi_dialog_vcr_play_optim_callback(GtkWidget *w, gpointer data);
|
|
static void navi_dialog_frames_duplicate_frame_callback(GtkWidget *w, gpointer data);
|
|
static void navi_dialog_frames_delete_frame_callback(GtkWidget *w, gpointer data);
|
|
|
|
static void navi_dialog_vcr_goto_first_callback(GtkWidget *w, gpointer data);
|
|
static void navi_dialog_vcr_goto_prev_callback(GtkWidget *w, gpointer data);
|
|
static void navi_dialog_vcr_goto_prevblock_callback(GtkWidget *w, gpointer data);
|
|
static void navi_dialog_vcr_goto_next_callback(GtkWidget *w, gpointer data);
|
|
static void navi_dialog_vcr_goto_nextblock_callback(GtkWidget *w, gpointer data);
|
|
static void navi_dialog_vcr_goto_last_callback(GtkWidget *w, gpointer data);
|
|
|
|
static void navi_framerate_scale_update(GtkAdjustment *w, gpointer data);
|
|
static void navi_timezoom_scale_update(GtkAdjustment *w, gpointer data);
|
|
|
|
|
|
static gint frame_list_events (GtkWidget *, GdkEvent *, gpointer);
|
|
|
|
static void frame_widget_select_update (GtkWidget *, gpointer);
|
|
static gint frame_widget_button_events (GtkWidget *, GdkEvent *);
|
|
static gint frame_widget_preview_events (GtkWidget *, GdkEvent *);
|
|
|
|
static gint navi_dialog_poll(GtkWidget *w, gpointer data);
|
|
static void navi_dialog_update(gint32 update_flag);
|
|
static void navi_scroll_to_current_frame_nr(void);
|
|
|
|
static FrameWidget * frame_widget_create (gint32 image_id, gint32 frame_nr);
|
|
static void frame_widget_delete (FrameWidget *fw);
|
|
static gint32 navi_get_preview_size(void);
|
|
static void frames_timing_update (void);
|
|
static void frame_widget_time_label_update(FrameWidget *fw);
|
|
static void navi_dialog_tooltips(void);
|
|
static void navi_set_waiting_cursor(void);
|
|
static void navi_set_active_cursor(void);
|
|
|
|
/* -----------------------
|
|
* Local data
|
|
* -----------------------
|
|
*/
|
|
|
|
static NaviDialog *naviD = NULL;
|
|
static gint suspend_gimage_notify = 0;
|
|
static gint32 global_old_active_imageid = -1;
|
|
|
|
/* the ops buttons */
|
|
static GtkSignalFunc navi_dialog_update_ext_callbacks[] =
|
|
{
|
|
navi_dialog_thumb_updateall_callback, NULL, NULL, NULL
|
|
};
|
|
static GtkSignalFunc navi_dialog_vcr_play_ext_callbacks[] =
|
|
{
|
|
navi_dialog_vcr_play_optim_callback, NULL, NULL, NULL
|
|
};
|
|
static GtkSignalFunc navi_dialog_vcr_goto_prev_ext_callbacks[] =
|
|
{
|
|
navi_dialog_vcr_goto_prevblock_callback, NULL, NULL, NULL
|
|
};
|
|
static GtkSignalFunc navi_dialog_vcr_goto_next_ext_callbacks[] =
|
|
{
|
|
navi_dialog_vcr_goto_nextblock_callback, NULL, NULL, NULL
|
|
};
|
|
|
|
static OpsButton frames_ops_buttons[] =
|
|
{
|
|
{ play_xpm, navi_dialog_vcr_play_callback, navi_dialog_vcr_play_ext_callbacks,
|
|
N_("Playback \n"
|
|
"<Shift> optimized"),
|
|
"#playback",
|
|
NULL, 0 },
|
|
{ update_xpm, navi_dialog_thumb_update_callback, navi_dialog_update_ext_callbacks,
|
|
N_("Smart Update .xvpics\n"
|
|
"<Shift> forced upd"),
|
|
"#update",
|
|
NULL, 0 },
|
|
{ duplicate_xpm, navi_dialog_frames_duplicate_frame_callback, NULL,
|
|
N_("Duplicate selected Frames"),
|
|
"#duplicate",
|
|
NULL, 0 },
|
|
{ delete_xpm, navi_dialog_frames_delete_frame_callback, NULL,
|
|
N_("Delete selected Frames"),
|
|
"#delete",
|
|
NULL, 0 },
|
|
{ NULL, NULL, NULL, NULL, NULL, NULL, 0 }
|
|
};
|
|
|
|
static OpsButton vcr_ops_buttons[] =
|
|
{
|
|
{ first_xpm, navi_dialog_vcr_goto_first_callback, NULL,
|
|
N_("Goto 1st Frame"),
|
|
"#goto_first",
|
|
NULL, 0 },
|
|
{ prev_xpm, navi_dialog_vcr_goto_prev_callback, navi_dialog_vcr_goto_prev_ext_callbacks,
|
|
N_("Goto prev Frame\n"
|
|
"<Shift> use timezoom stepsize"),
|
|
"#goto_previous",
|
|
NULL, 0 },
|
|
{ next_xpm, navi_dialog_vcr_goto_next_callback, navi_dialog_vcr_goto_next_ext_callbacks,
|
|
N_("Goto next Frame\n"
|
|
"<Shift> use timezoom stepsize"),
|
|
"#goto_next",
|
|
NULL, 0 },
|
|
{ last_xpm, navi_dialog_vcr_goto_last_callback, NULL,
|
|
N_("Goto last Frame"),
|
|
"#goto_last",
|
|
NULL, 0 },
|
|
|
|
{ NULL, NULL, NULL, NULL, NULL, NULL, 0 }
|
|
};
|
|
|
|
/* ------------------------
|
|
* gap DEBUG switch
|
|
* ------------------------
|
|
*/
|
|
|
|
/* int gap_debug = 1; */ /* print debug infos */
|
|
/* int gap_debug = 0; */ /* 0: dont print debug infos */
|
|
|
|
int gap_debug = 0;
|
|
|
|
|
|
static void query(void);
|
|
static void run(char *name, int nparam, GimpParam *param,
|
|
int *nretvals, GimpParam **retvals);
|
|
|
|
GimpPlugInInfo PLUG_IN_INFO =
|
|
{
|
|
NULL, /* init_proc */
|
|
NULL, /* quit_proc */
|
|
query, /* query_proc */
|
|
run, /* run_proc */
|
|
};
|
|
|
|
/* ------------------------
|
|
* MAIN, query & run
|
|
* ------------------------
|
|
*/
|
|
|
|
MAIN ()
|
|
|
|
static void
|
|
query ()
|
|
{
|
|
static GimpParamDef args_navigator[] =
|
|
{
|
|
{GIMP_PDB_INT32, "run_mode", "Interactive"},
|
|
{GIMP_PDB_IMAGE, "image", "(unused)"},
|
|
{GIMP_PDB_DRAWABLE, "drawable", "(unused)"},
|
|
};
|
|
static int nargs_navigator = sizeof(args_navigator) / sizeof(args_navigator[0]);
|
|
|
|
static GimpParamDef *return_vals = NULL;
|
|
static int nreturn_vals = 0;
|
|
|
|
|
|
gimp_install_procedure(PLUGIN_NAME,
|
|
"GAP video navigator dialog",
|
|
"",
|
|
"Wolfgang Hofer (hof@hotbot.com)",
|
|
"Wolfgang Hofer",
|
|
gap_navigator_version,
|
|
N_("<Image>/Video/VCR Navigator..."),
|
|
"RGB*, INDEXED*, GRAY*",
|
|
GIMP_PLUGIN,
|
|
nargs_navigator, nreturn_vals,
|
|
args_navigator, return_vals);
|
|
} /* end query */
|
|
|
|
|
|
|
|
static void
|
|
run (char *name,
|
|
int n_params,
|
|
GimpParam *param,
|
|
int *nreturn_vals,
|
|
GimpParam **return_vals)
|
|
{
|
|
gint32 l_active_image;
|
|
char *l_env;
|
|
|
|
static GimpParam values[2];
|
|
GimpRunModeType run_mode;
|
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
|
gint32 nr;
|
|
pid_t l_navid_pid;
|
|
|
|
gint32 l_rc;
|
|
|
|
*nreturn_vals = 1;
|
|
*return_vals = values;
|
|
nr = 0;
|
|
l_rc = 0;
|
|
|
|
|
|
l_env = g_getenv("GAP_DEBUG");
|
|
if(l_env != NULL)
|
|
{
|
|
if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1;
|
|
}
|
|
|
|
run_mode = param[0].data.d_int32;
|
|
l_active_image = -1;
|
|
|
|
if(gap_debug) printf("\n\ngap_navigator: debug name = %s\n", name);
|
|
|
|
l_active_image = param[1].data.d_image;
|
|
|
|
if (run_mode == GIMP_RUN_NONINTERACTIVE) {
|
|
INIT_I18N();
|
|
} else {
|
|
INIT_I18N_UI();
|
|
}
|
|
|
|
/* check for other Video navigator Dialog Process */
|
|
if (sizeof(pid_t) == gimp_get_data_size(PLUGIN_NAME))
|
|
{
|
|
gimp_get_data(PLUGIN_NAME, &l_navid_pid);
|
|
if(l_navid_pid != 0)
|
|
{
|
|
/* kill with signal 0 checks only if the process is alive (no signal is sent)
|
|
* returns 0 if alive, 1 if no process with given pid found.
|
|
*/
|
|
if (0 == kill(l_navid_pid, 0))
|
|
{
|
|
p_msg_win(GIMP_RUN_INTERACTIVE, _("Cant open two or more Video Navigator Windows."));
|
|
l_rc = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(l_rc == 0)
|
|
{
|
|
/* set pid data when navigator is running */
|
|
l_navid_pid = getpid();
|
|
gimp_set_data(PLUGIN_NAME, &l_navid_pid, sizeof(pid_t));
|
|
if (strcmp (name, PLUGIN_NAME) == 0)
|
|
{
|
|
if (run_mode != GIMP_RUN_INTERACTIVE)
|
|
{
|
|
status = GIMP_PDB_CALLING_ERROR;
|
|
}
|
|
|
|
if (status == GIMP_PDB_SUCCESS)
|
|
{
|
|
l_rc = gap_navigator(l_active_image);
|
|
}
|
|
}
|
|
/* set pid data to 0 when navigator stops */
|
|
l_navid_pid = 0;
|
|
gimp_set_data(PLUGIN_NAME, &l_navid_pid, sizeof(pid_t));
|
|
}
|
|
|
|
/* ---------- return handling --------- */
|
|
|
|
if(l_rc < 0)
|
|
{
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
|
}
|
|
|
|
values[0].type = GIMP_PDB_STATUS;
|
|
values[0].data.d_status = status;
|
|
}
|
|
|
|
|
|
/* ---------------------------------
|
|
* the navigator callback procedures
|
|
* ---------------------------------
|
|
*/
|
|
|
|
static void
|
|
edit_copy_callback (GtkWidget *w, gpointer client_data)
|
|
{
|
|
if(gap_debug) printf("edit_copy_callback\n");
|
|
navi_vid_copy_and_cut(FALSE /* cut_flag */);
|
|
}
|
|
static void
|
|
edit_cut_callback (GtkWidget *w, gpointer client_data)
|
|
{
|
|
if(gap_debug) printf("edit_cut_callback\n");
|
|
navi_vid_copy_and_cut(TRUE /* cut_flag */);
|
|
}
|
|
|
|
|
|
static void
|
|
p_edit_paste_call(gint32 paste_mode)
|
|
{
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
|
|
if(naviD->paste_at_frame >= 0)
|
|
{
|
|
/* goto the first selected frame */
|
|
return_vals = gimp_run_procedure ("plug_in_gap_goto",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_INT32, naviD->paste_at_frame,
|
|
GIMP_PDB_END);
|
|
if (return_vals[0].data.d_status != GIMP_PDB_SUCCESS)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
return_vals = gimp_run_procedure ("plug_in_gap_video_edit_paste",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_INT32, paste_mode,
|
|
GIMP_PDB_END);
|
|
navi_update_after_goto();
|
|
|
|
}
|
|
static void
|
|
edit_pasteb_callback (GtkWidget *w, gpointer client_data)
|
|
{
|
|
p_edit_paste_call(VID_PASTE_INSERT_BEFORE);
|
|
}
|
|
static void
|
|
edit_pastea_callback (GtkWidget *w, gpointer client_data)
|
|
{
|
|
p_edit_paste_call(VID_PASTE_INSERT_AFTER);
|
|
}
|
|
static void
|
|
edit_paster_callback (GtkWidget *w, gpointer client_data)
|
|
{
|
|
p_edit_paste_call(VID_PASTE_REPLACE);
|
|
}
|
|
|
|
static void
|
|
edit_clrpaste_callback (GtkWidget *w, gpointer client_data)
|
|
{
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
|
|
if(gap_debug) printf("edit_clrpaste_callback\n");
|
|
return_vals = gimp_run_procedure ("plug_in_gap_video_edit_clear",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_END);
|
|
}
|
|
|
|
|
|
void
|
|
navi_vid_copy_and_cut(gint cut_flag)
|
|
{
|
|
SelectedRange *range_list;
|
|
SelectedRange *range_list2;
|
|
SelectedRange *range_item;
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
|
|
if(gap_debug) printf("navi_dialog_vid_copy_callback\n");
|
|
|
|
range_list = navi_get_selected_ranges();
|
|
if(range_list)
|
|
{
|
|
navi_set_waiting_cursor();
|
|
p_vid_edit_clear();
|
|
|
|
/* generate prev linkpointers in the range list */
|
|
range_item = NULL;
|
|
range_list2 = range_list;
|
|
while(1 == 1)
|
|
{
|
|
range_list2->prev = range_item;
|
|
range_item = range_list2;
|
|
if(range_list2->next == NULL)
|
|
{
|
|
break;
|
|
}
|
|
range_list2 = range_list2->next;
|
|
}
|
|
|
|
while(range_list2)
|
|
{
|
|
/* Note: process the ranges from low frame_nummers
|
|
* upto high frame_numbers.
|
|
* (the range_list was created in a way that
|
|
* the highest range is added as 1st list element
|
|
* so we start at end of the list and to the 1. element using prev linkpinters
|
|
*/
|
|
if(gap_debug) printf("Copy Range from:%d to:%d\n"
|
|
,(int)range_list2->from ,(int)range_list2->to );
|
|
|
|
return_vals = gimp_run_procedure ("plug_in_gap_video_edit_copy",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_INT32, range_list2->from,
|
|
GIMP_PDB_INT32, range_list2->to,
|
|
GIMP_PDB_END);
|
|
range_item = range_list2;
|
|
range_list2 = range_list2->prev;
|
|
}
|
|
|
|
while(range_list)
|
|
{
|
|
if(cut_flag)
|
|
{
|
|
if(gap_debug) printf("Delete Range from:%d to:%d\n"
|
|
,(int)range_list->from ,(int)range_list->to );
|
|
|
|
return_vals = gimp_run_procedure ("plug_in_gap_goto",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_INT32, range_list->from,
|
|
GIMP_PDB_END);
|
|
if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
|
|
{
|
|
return_vals = gimp_run_procedure ("plug_in_gap_del",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_INT32, 1 + (range_list->to - range_list->from), /* number of frames to delete */
|
|
GIMP_PDB_END);
|
|
}
|
|
}
|
|
|
|
range_item = range_list;
|
|
range_list = range_list->next;
|
|
g_free(range_item);
|
|
}
|
|
|
|
navi_update_after_goto();
|
|
}
|
|
} /* end navi_dialog_frames_duplicate_frame_callback */
|
|
|
|
|
|
|
|
static gint32
|
|
navi_get_preview_size(void)
|
|
{
|
|
char *value_string;
|
|
gint32 preview_size;
|
|
|
|
preview_size = 32; /* default preview size if nothing is configured */
|
|
value_string = p_gimp_gimprc_query("video-preview-size");
|
|
if(value_string == NULL)
|
|
{
|
|
value_string = p_gimp_gimprc_query("preview-size");
|
|
}
|
|
|
|
if(value_string)
|
|
{
|
|
if(gap_debug) printf("navi_get_preview_size value_str:%s:\n", value_string);
|
|
|
|
if (strcmp (value_string, "none") == 0)
|
|
preview_size = 0;
|
|
else if (strcmp (value_string, "tiny") == 0)
|
|
preview_size = 24;
|
|
else if (strcmp (value_string, "small") == 0)
|
|
preview_size = 32;
|
|
else if (strcmp (value_string, "medium") == 0)
|
|
preview_size = 48;
|
|
else if (strcmp (value_string, "large") == 0)
|
|
preview_size = 64;
|
|
else if (strcmp (value_string, "huge") == 0)
|
|
preview_size = 128;
|
|
else
|
|
preview_size = atol(value_string);
|
|
|
|
g_free(value_string);
|
|
}
|
|
else
|
|
{
|
|
if(gap_debug) printf("navi_get_preview_size value_str is NULL\n");
|
|
}
|
|
|
|
return (preview_size);
|
|
}
|
|
|
|
static gint
|
|
navi_check_exist_first_and_last(t_anim_info *ainfo_ptr)
|
|
{
|
|
char *l_fname;
|
|
|
|
l_fname = p_alloc_fname(ainfo_ptr->basename,
|
|
ainfo_ptr->last_frame_nr,
|
|
ainfo_ptr->extension);
|
|
if (!p_file_exists(l_fname))
|
|
{
|
|
g_free(l_fname);
|
|
return(FALSE);
|
|
}
|
|
g_free(l_fname);
|
|
|
|
l_fname = p_alloc_fname(ainfo_ptr->basename,
|
|
ainfo_ptr->first_frame_nr,
|
|
ainfo_ptr->extension);
|
|
if (!p_file_exists(l_fname))
|
|
{
|
|
g_free(l_fname);
|
|
return(FALSE);
|
|
}
|
|
g_free(l_fname);
|
|
|
|
l_fname = p_alloc_fname(ainfo_ptr->basename,
|
|
ainfo_ptr->last_frame_nr+1,
|
|
ainfo_ptr->extension);
|
|
if (p_file_exists(l_fname))
|
|
{
|
|
g_free(l_fname);
|
|
return(FALSE);
|
|
}
|
|
g_free(l_fname);
|
|
|
|
l_fname = p_alloc_fname(ainfo_ptr->basename,
|
|
ainfo_ptr->first_frame_nr-1,
|
|
ainfo_ptr->extension);
|
|
if (p_file_exists(l_fname))
|
|
{
|
|
g_free(l_fname);
|
|
return(FALSE);
|
|
}
|
|
g_free(l_fname);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
t_anim_info *
|
|
navi_get_ainfo(gint32 image_id, t_anim_info *old_ainfo_ptr)
|
|
{
|
|
t_anim_info *ainfo_ptr;
|
|
ainfo_ptr = p_alloc_ainfo(image_id, GIMP_RUN_NONINTERACTIVE);
|
|
if(ainfo_ptr)
|
|
{
|
|
if(old_ainfo_ptr)
|
|
{
|
|
if((old_ainfo_ptr->image_id == image_id)
|
|
&& (strcmp(old_ainfo_ptr->basename, ainfo_ptr->basename) == 0))
|
|
{
|
|
if(navi_check_exist_first_and_last(old_ainfo_ptr))
|
|
{
|
|
/* - image_id and name have not changed,
|
|
* - first and last frame still exist
|
|
* and are still first and last frame
|
|
* In that case we can reuse first and last frame_nr
|
|
* without scanning the directory for frames
|
|
*/
|
|
ainfo_ptr->first_frame_nr = old_ainfo_ptr->first_frame_nr;
|
|
ainfo_ptr->last_frame_nr = old_ainfo_ptr->last_frame_nr;
|
|
ainfo_ptr->frame_cnt = old_ainfo_ptr->frame_cnt;
|
|
return(ainfo_ptr);
|
|
}
|
|
}
|
|
}
|
|
p_dir_ainfo(ainfo_ptr);
|
|
}
|
|
return(ainfo_ptr);
|
|
}
|
|
|
|
void navi_reload_ainfo_force(gint32 image_id)
|
|
{
|
|
t_anim_info *old_ainfo_ptr;
|
|
char frame_nr_to_char[20];
|
|
|
|
if(gap_debug) printf("navi_reload_ainfo_force image_id:%d\n", (int)image_id);
|
|
old_ainfo_ptr = naviD->ainfo_ptr;
|
|
naviD->active_imageid = image_id;
|
|
naviD->ainfo_ptr = navi_get_ainfo(image_id, old_ainfo_ptr);
|
|
|
|
if((strcmp(naviD->ainfo_ptr->extension, ".xcf") != 0)
|
|
&& (strcmp(naviD->ainfo_ptr->extension, ".xcfgz") != 0)
|
|
&& (global_old_active_imageid != image_id))
|
|
{
|
|
/* for other frameformats than xcf
|
|
* save the frame a 1st time (to set filetype specific save paramters)
|
|
* this also is a workaround for a BUG that causes an X11 deadlock
|
|
* when the save dialog pops up from the double-click callback in the frames listbox
|
|
*/
|
|
suspend_gimage_notify++;
|
|
p_save_named_frame(image_id, naviD->ainfo_ptr->old_filename);
|
|
suspend_gimage_notify--;
|
|
}
|
|
global_old_active_imageid = image_id;
|
|
|
|
if(naviD->framerange_number_label)
|
|
{
|
|
sprintf(frame_nr_to_char, "%04d - %04d"
|
|
, (int)naviD->ainfo_ptr->first_frame_nr
|
|
, (int)naviD->ainfo_ptr->last_frame_nr );
|
|
gtk_label_set_text (GTK_LABEL (naviD->framerange_number_label),
|
|
frame_nr_to_char);
|
|
}
|
|
|
|
if(old_ainfo_ptr) p_free_ainfo(&old_ainfo_ptr);
|
|
}
|
|
|
|
void navi_reload_ainfo(gint32 image_id)
|
|
{
|
|
if(image_id < 0) navi_reload_ainfo_force(naviD->any_imageid);
|
|
else navi_reload_ainfo_force(image_id);
|
|
|
|
if(naviD->ainfo_ptr)
|
|
{
|
|
if(naviD->vin_ptr) g_free(naviD->vin_ptr);
|
|
naviD->vin_ptr = p_get_video_info(naviD->ainfo_ptr->basename);
|
|
gtk_adjustment_set_value(naviD->framerate_data, (gfloat)naviD->vin_ptr->framerate);
|
|
gtk_adjustment_set_value(naviD->timezoom_data, (gfloat)naviD->vin_ptr->timezoom);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static gint
|
|
navi_images_menu_constrain(gint32 image_id, gint32 drawable_id, gpointer data)
|
|
{
|
|
if(gap_debug) printf("navi_images_menu_constrain PROCEDURE imageID:%d\n", (int)image_id);
|
|
|
|
if(p_get_frame_nr(image_id) < 0)
|
|
{
|
|
return(FALSE); /* reject images without frame number */
|
|
}
|
|
if(naviD)
|
|
{
|
|
if(naviD->active_imageid < 0)
|
|
{
|
|
/* if there is no valid active_imageid
|
|
* we nominate the first one that comes along
|
|
*/
|
|
naviD->any_imageid = image_id;
|
|
}
|
|
}
|
|
return(TRUE);
|
|
} /* end navi_images_menu_constrain */
|
|
|
|
|
|
static void
|
|
navi_images_menu_callback (gint32 image_id, gpointer data)
|
|
{
|
|
if(gap_debug) printf("navi_images_menu_callback PROCEDURE imageID:%d\n", (int)image_id);
|
|
|
|
if(naviD)
|
|
{
|
|
if(naviD->active_imageid != image_id)
|
|
{
|
|
navi_reload_ainfo(image_id);
|
|
navi_dialog_update(NUPD_FRAME_NR_CHANGED | NUPD_PREV_LIST);
|
|
navi_scroll_to_current_frame_nr();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
navid_update_exposed_previews(void)
|
|
{
|
|
if(naviD == NULL) return;
|
|
|
|
/* I've tried to send an "expose_event" to frame_preview widgets
|
|
* using gtk_signal_emit_by_name , but it did not work.
|
|
* So i decided to use the trick widget_hide and widget_show
|
|
* to force gtk to (re)expose the widgets in the listbox
|
|
* That way all visible items in the listbox are refreshed (redraw)
|
|
*/
|
|
gtk_widget_hide(naviD->scrolled_win);
|
|
gtk_widget_show(naviD->scrolled_win);
|
|
}
|
|
|
|
|
|
static void
|
|
navi_set_waiting_cursor(void)
|
|
{
|
|
if(naviD == NULL) return;
|
|
if(naviD->waiting_cursor) return;
|
|
|
|
naviD->waiting_cursor = TRUE;
|
|
gdk_window_set_cursor(GTK_WIDGET(naviD->shell)->window, naviD->cursor_wait);
|
|
}
|
|
static void
|
|
navi_set_active_cursor(void)
|
|
{
|
|
if(naviD == NULL) return;
|
|
if(!naviD->waiting_cursor) return;
|
|
|
|
naviD->waiting_cursor = FALSE;
|
|
gdk_window_set_cursor(GTK_WIDGET(naviD->shell)->window, naviD->cursor_acitve);
|
|
}
|
|
|
|
static void
|
|
navi_scroll_to_current_frame_nr(void)
|
|
{
|
|
GtkAdjustment *adj;
|
|
gfloat adj_val;
|
|
gint index;
|
|
gint page_size;
|
|
|
|
if(naviD == NULL) return;
|
|
if(naviD->ainfo_ptr == NULL) return;
|
|
if(naviD->vin_ptr == NULL) return;
|
|
if(naviD->scrolled_win == NULL) return;
|
|
|
|
|
|
if(gap_debug) printf("navi_scroll_to_current_frame_nr: BEGIN timezoom:%d, item_height:%d\n", (int)naviD->vin_ptr->timezoom, (int)naviD->item_height);
|
|
|
|
adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (naviD->scrolled_win));
|
|
adj_val = adj->value;
|
|
page_size = MAX(adj->page_size, naviD->item_height);
|
|
index = 0;
|
|
if(naviD->vin_ptr->timezoom)
|
|
{
|
|
index = (naviD->ainfo_ptr->curr_frame_nr - naviD->ainfo_ptr->first_frame_nr) / naviD->vin_ptr->timezoom;
|
|
}
|
|
|
|
if (index * naviD->item_height < adj->value)
|
|
{
|
|
adj_val = index * naviD->item_height;
|
|
}
|
|
else if ((index + 1) * naviD->item_height > adj->value + page_size)
|
|
{
|
|
adj_val = (index + 1) * naviD->item_height - page_size;
|
|
}
|
|
|
|
if(adj_val > MAX_HEIGHT_GTK_SCROLLED_WIN - page_size)
|
|
{
|
|
adj_val = MAX_HEIGHT_GTK_SCROLLED_WIN - page_size;
|
|
}
|
|
if(adj_val != adj->value)
|
|
{
|
|
if(gap_debug) printf("navi_scroll_to_current_frame_nr: OLD: %d should be set to adj_val: %d index:%d\n", (int)adj->value, (int)adj_val, (int)index);
|
|
if(gap_debug) printf("navi_scroll_to_current_frame_nr: adj->lower :%d adj->upper :%d\n", (int)adj->lower, (int)adj->upper);
|
|
/* gtk_adjustment_set_value(adj, adj_val); */
|
|
adj->value = adj_val;
|
|
gtk_adjustment_value_changed (adj);
|
|
if(gap_debug) printf("navi_scroll_to_current_frame_nr: NEW : %d should be equal to adj_val: %d adj->page_size:%d\n", (int)adj->value, (int)adj_val, (int)adj->page_size);
|
|
}
|
|
}
|
|
|
|
static void
|
|
navi_dialog_tooltips(void)
|
|
{
|
|
char *value_string;
|
|
gint tooltip_on;
|
|
|
|
if(naviD == NULL) return;
|
|
|
|
tooltip_on = TRUE;
|
|
value_string = p_gimp_gimprc_query("show-tool-tips");
|
|
|
|
if(value_string != NULL)
|
|
{
|
|
if (strcmp(value_string, "no") == 0)
|
|
{
|
|
tooltip_on = FALSE;
|
|
}
|
|
}
|
|
|
|
if(naviD->tooltip_on != tooltip_on)
|
|
{
|
|
naviD->tooltip_on = tooltip_on;
|
|
|
|
if(tooltip_on)
|
|
{
|
|
gimp_help_enable_tooltips ();
|
|
}
|
|
else
|
|
{
|
|
gimp_help_disable_tooltips ();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static gint
|
|
navi_find_OpenFrameList(OpenFrameImages *search_item)
|
|
{
|
|
OpenFrameImages *item_list;
|
|
|
|
item_list = naviD->OpenFrameImagesList;
|
|
while(item_list)
|
|
{
|
|
if((item_list->image_id == search_item->image_id)
|
|
&& (item_list->frame_nr == search_item->frame_nr))
|
|
{
|
|
return(TRUE); /* item found in the list */
|
|
}
|
|
item_list = (OpenFrameImages *)item_list->next;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
static void
|
|
navi_free_OpenFrameList(OpenFrameImages *list)
|
|
{
|
|
OpenFrameImages *item_list;
|
|
OpenFrameImages *item_next;
|
|
|
|
item_list = list;
|
|
while(item_list)
|
|
{
|
|
item_next = (OpenFrameImages *)item_list->next;
|
|
g_free(item_list);
|
|
item_list = item_next;
|
|
}
|
|
}
|
|
|
|
static gint
|
|
navi_check_image_menu_changes()
|
|
{
|
|
int nimages;
|
|
gint32 *images;
|
|
gint32 frame_nr;
|
|
int i;
|
|
gint l_rc;
|
|
int item_count;
|
|
OpenFrameImages *item_list;
|
|
OpenFrameImages *new_item;
|
|
|
|
l_rc = TRUE;
|
|
if(naviD->OpenFrameImagesList == NULL)
|
|
{
|
|
l_rc = FALSE;
|
|
}
|
|
item_list = NULL;
|
|
item_count = 0;
|
|
images = gimp_image_list (&nimages);
|
|
for (i = 0; i < nimages; i++)
|
|
{
|
|
frame_nr = p_get_frame_nr(images[i]); /* check for anim frame */
|
|
if(frame_nr >= 0)
|
|
{
|
|
item_count++;
|
|
new_item = g_malloc(sizeof(OpenFrameImages));
|
|
new_item->image_id = images[i];
|
|
new_item->frame_nr = frame_nr;
|
|
new_item->next = item_list;
|
|
item_list = new_item;
|
|
if(!navi_find_OpenFrameList(new_item))
|
|
{
|
|
l_rc = FALSE;
|
|
}
|
|
}
|
|
}
|
|
g_free(images);
|
|
|
|
if(item_count != naviD->OpenFrameImagesCount)
|
|
{
|
|
l_rc = FALSE;
|
|
}
|
|
|
|
if(l_rc == TRUE)
|
|
{
|
|
navi_free_OpenFrameList(item_list);
|
|
}
|
|
else
|
|
{
|
|
navi_free_OpenFrameList(naviD->OpenFrameImagesList);
|
|
naviD->OpenFrameImagesCount = item_count;
|
|
naviD->OpenFrameImagesList = item_list;
|
|
}
|
|
return(l_rc);
|
|
}
|
|
|
|
static gint
|
|
navi_refresh_image_menu()
|
|
{
|
|
if(naviD)
|
|
{
|
|
if(!navi_check_image_menu_changes())
|
|
{
|
|
if(gap_debug) printf("navi_refresh_image_menu ** BEGIN REFRESH\n");
|
|
if(naviD->OpenFrameImagesCount != 0)
|
|
{
|
|
gtk_widget_set_sensitive(naviD->vbox, TRUE);
|
|
}
|
|
|
|
naviD->image_menu = gimp_image_menu_new(navi_images_menu_constrain,
|
|
navi_images_menu_callback,
|
|
naviD,
|
|
naviD->active_imageid
|
|
);
|
|
gtk_option_menu_set_menu(GTK_OPTION_MENU(naviD->image_option_menu), naviD->image_menu);
|
|
gtk_widget_show (naviD->image_menu);
|
|
if(naviD->OpenFrameImagesCount == 0)
|
|
{
|
|
gtk_widget_set_sensitive(naviD->vbox, FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
void
|
|
navi_update_after_goto(void)
|
|
{
|
|
if(naviD)
|
|
{
|
|
navi_dialog_update(NUPD_IMAGE_MENU | NUPD_FRAME_NR_CHANGED);
|
|
navi_scroll_to_current_frame_nr();
|
|
}
|
|
gimp_displays_flush();
|
|
navi_set_active_cursor();
|
|
}
|
|
|
|
|
|
static SelectedRange *
|
|
navi_get_selected_ranges(void)
|
|
{
|
|
FrameWidget *fw;
|
|
GSList *list;
|
|
GtkStateType state;
|
|
|
|
SelectedRange *new_range;
|
|
SelectedRange *range_list;
|
|
|
|
range_list = NULL;
|
|
new_range = NULL;
|
|
list = naviD->frame_widgets;
|
|
while (list)
|
|
{
|
|
fw = (FrameWidget *) list->data;
|
|
list = g_slist_next (list);
|
|
state = fw->list_item->state;
|
|
if(state == GTK_STATE_SELECTED)
|
|
{
|
|
if(new_range == NULL)
|
|
{
|
|
new_range = g_malloc(sizeof(SelectedRange));
|
|
new_range->next = range_list;
|
|
new_range->from = fw->frame_nr;
|
|
new_range->to = fw->frame_nr;
|
|
range_list = new_range;
|
|
}
|
|
else
|
|
{
|
|
new_range->to = fw->frame_nr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
new_range = NULL;
|
|
}
|
|
}
|
|
|
|
return(range_list);
|
|
}
|
|
|
|
void
|
|
navi_ops_menu_set_sensitive(void)
|
|
{
|
|
FrameWidget *fw;
|
|
GSList *list;
|
|
GtkStateType state;
|
|
|
|
if(naviD == NULL)
|
|
{
|
|
return;
|
|
}
|
|
if(p_vid_edit_framecount() > 0)
|
|
{
|
|
gtk_widget_set_sensitive(naviD->pastea_menu_item, TRUE);
|
|
gtk_widget_set_sensitive(naviD->pasteb_menu_item, TRUE);
|
|
gtk_widget_set_sensitive(naviD->paster_menu_item, TRUE);
|
|
gtk_widget_set_sensitive(naviD->clrpaste_menu_item, TRUE);
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_set_sensitive(naviD->pastea_menu_item, FALSE);
|
|
gtk_widget_set_sensitive(naviD->pasteb_menu_item, FALSE);
|
|
gtk_widget_set_sensitive(naviD->paster_menu_item, FALSE);
|
|
gtk_widget_set_sensitive(naviD->clrpaste_menu_item, FALSE);
|
|
}
|
|
|
|
list = naviD->frame_widgets;
|
|
while (list)
|
|
{
|
|
fw = (FrameWidget *) list->data;
|
|
list = g_slist_next (list);
|
|
state = fw->list_item->state;
|
|
if(state == GTK_STATE_SELECTED)
|
|
{
|
|
naviD->paste_at_frame = fw->frame_nr;
|
|
gtk_widget_set_sensitive(naviD->copy_menu_item, TRUE);
|
|
gtk_widget_set_sensitive(naviD->cut_menu_item, TRUE);
|
|
return;
|
|
}
|
|
}
|
|
gtk_widget_set_sensitive(naviD->copy_menu_item, FALSE);
|
|
gtk_widget_set_sensitive(naviD->cut_menu_item, FALSE);
|
|
|
|
naviD->paste_at_frame = -1; /* nothing selected, use current frame_nr */
|
|
|
|
} /* end navi_ops_menu_set_sensitive */
|
|
|
|
|
|
|
|
static void
|
|
navi_thumb_update(gint update_all)
|
|
{
|
|
gint32 l_frame_nr;
|
|
gint32 l_image_id;
|
|
gint l_upd_flag;
|
|
gint l_any_upd_flag;
|
|
char *l_image_filename;
|
|
char *l_thumb_filename;
|
|
struct stat l_stat_thumb;
|
|
struct stat l_stat_image;
|
|
|
|
if(naviD == NULL) return;
|
|
if(naviD->ainfo_ptr == NULL) return;
|
|
|
|
l_any_upd_flag = FALSE;
|
|
for(l_frame_nr = naviD->ainfo_ptr->first_frame_nr;
|
|
l_frame_nr <= naviD->ainfo_ptr->last_frame_nr;
|
|
l_frame_nr++)
|
|
{
|
|
l_upd_flag = TRUE;
|
|
l_image_filename = p_alloc_fname(naviD->ainfo_ptr->basename, l_frame_nr, naviD->ainfo_ptr->extension);
|
|
l_thumb_filename = p_alloc_fname_thumbnail(l_image_filename);
|
|
|
|
|
|
if(!update_all)
|
|
{
|
|
if (0 == stat(l_thumb_filename, &l_stat_thumb))
|
|
{
|
|
/* thumbnail filename exists */
|
|
if(S_ISREG(l_stat_thumb.st_mode))
|
|
{
|
|
/* and is a regular file */
|
|
if (0 == stat(l_image_filename, &l_stat_image))
|
|
{
|
|
if(l_stat_image.st_mtime < l_stat_thumb.st_mtime)
|
|
{
|
|
/* time of last modification of image is older (less)
|
|
* than last modification of the thumbnail
|
|
* So we can skip the thumbnail Update for this frame
|
|
*/
|
|
l_upd_flag = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if(l_upd_flag)
|
|
{
|
|
l_any_upd_flag = TRUE;
|
|
if(gap_debug) printf("navi_thumb_update frame_nr:%d\n", (int)l_frame_nr);
|
|
l_image_id = p_load_image(l_image_filename);
|
|
p_gimp_file_save_thumbnail(l_image_id, l_image_filename);
|
|
gimp_image_delete(l_image_id);
|
|
}
|
|
|
|
if(l_image_filename) g_free(l_image_filename);
|
|
if(l_thumb_filename) g_free(l_thumb_filename);
|
|
}
|
|
|
|
if(l_any_upd_flag )
|
|
{
|
|
navid_update_exposed_previews();
|
|
}
|
|
}
|
|
|
|
static void navi_dialog_thumb_update_callback(GtkWidget *w, gpointer data)
|
|
{
|
|
if(gap_debug) printf("navi_dialog_thumb_update_callback\n");
|
|
navi_thumb_update(FALSE);
|
|
}
|
|
|
|
static void navi_dialog_thumb_updateall_callback(GtkWidget *w, gpointer data)
|
|
{
|
|
if(gap_debug) printf("navi_dialog_thumb_updateall_callback\n");
|
|
navi_thumb_update(TRUE);
|
|
}
|
|
|
|
|
|
static void navi_playback(gint32 optimize)
|
|
{
|
|
SelectedRange *range_list;
|
|
SelectedRange *range_item;
|
|
gint32 l_from;
|
|
gint32 l_to;
|
|
|
|
gint32 l_new_image_id;
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
char l_frame_name[50];
|
|
int l_frame_delay;
|
|
|
|
|
|
if(gap_debug) printf("navi_dialog_vcr_play_callback\n");
|
|
|
|
strcpy(l_frame_name, "frame_[####]");
|
|
if(naviD->vin_ptr)
|
|
{
|
|
if(naviD->vin_ptr->framerate > 0)
|
|
{
|
|
l_frame_delay = 1000 / naviD->vin_ptr->framerate;
|
|
sprintf(l_frame_name, "frame_[####] (%dms)", (int)l_frame_delay);
|
|
}
|
|
}
|
|
|
|
l_from = naviD->ainfo_ptr->first_frame_nr;
|
|
l_to = naviD->ainfo_ptr->last_frame_nr;
|
|
|
|
range_list = navi_get_selected_ranges();
|
|
if(range_list)
|
|
{
|
|
l_to = naviD->ainfo_ptr->first_frame_nr;
|
|
l_from = naviD->ainfo_ptr->last_frame_nr;
|
|
|
|
while(range_list)
|
|
{
|
|
l_from = MIN(l_from, range_list->from);
|
|
l_to = MAX(l_to, range_list->to);
|
|
range_item = range_list;
|
|
range_list = range_list->next;
|
|
g_free(range_item);
|
|
}
|
|
}
|
|
|
|
return_vals = gimp_run_procedure ("plug_in_gap_range_to_multilayer",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_INT32, l_from,
|
|
GIMP_PDB_INT32, l_to,
|
|
GIMP_PDB_INT32, 3, /* flatten image */
|
|
GIMP_PDB_INT32, 1, /* BG_VISIBLE */
|
|
GIMP_PDB_INT32, (gint32)naviD->vin_ptr->framerate,
|
|
GIMP_PDB_STRING, l_frame_name,
|
|
GIMP_PDB_INT32, 6, /* use all visible layers */
|
|
GIMP_PDB_INT32, 0, /* ignore case */
|
|
GIMP_PDB_INT32, 0, /* normal selection (no invert) */
|
|
GIMP_PDB_STRING, "0", /* select string (ignored) */
|
|
GIMP_PDB_END);
|
|
|
|
if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
|
|
{
|
|
l_new_image_id = return_vals[1].data.d_image;
|
|
|
|
if(optimize)
|
|
{
|
|
return_vals = gimp_run_procedure ("plug_in_animationoptimize",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, l_new_image_id,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_END);
|
|
if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
|
|
{
|
|
#ifdef COMMENT_BLOCK
|
|
/* sorry, plug_in_animationoptimize does create
|
|
* a new anim-optimized image, but does not return the id
|
|
* of the created image so we can't play the optimized
|
|
* image automatically.
|
|
*/
|
|
|
|
/* destroy the tmp image */
|
|
gimp_image_delete(l_new_image_id);
|
|
|
|
l_new_image_id = return_vals[1].data.d_image;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* TODO: here we should start a thread for the playback,
|
|
* so the navigator is not blocked until playback exits
|
|
*/
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
static void navi_dialog_vcr_play_callback(GtkWidget *w, gpointer data)
|
|
{
|
|
if(gap_debug) printf("navi_dialog_vcr_play_callback\n");
|
|
navi_playback(FALSE /* dont not optimize */);
|
|
}
|
|
|
|
static void navi_dialog_vcr_play_optim_callback(GtkWidget *w, gpointer data)
|
|
{
|
|
if(gap_debug) printf("navi_dialog_vcr_play_optim_callback\n");
|
|
navi_playback(TRUE /* optimize */);
|
|
}
|
|
|
|
void navi_dialog_frames_duplicate_frame_callback(GtkWidget *w, gpointer data)
|
|
{
|
|
SelectedRange *range_list;
|
|
SelectedRange *range_item;
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
|
|
|
|
if(gap_debug) printf("navi_dialog_frames_duplicate_frame_callback\n");
|
|
|
|
range_list = navi_get_selected_ranges();
|
|
if(range_list)
|
|
{
|
|
navi_set_waiting_cursor();
|
|
while(range_list)
|
|
{
|
|
/* Note: process the ranges from high frame_nummers
|
|
* downto low frame_numbers.
|
|
* (the range_list was created in a way that
|
|
* the highest range is added as 1st list element)
|
|
*/
|
|
if(gap_debug) printf("Duplicate Range from:%d to:%d\n"
|
|
,(int)range_list->from ,(int)range_list->to );
|
|
|
|
return_vals = gimp_run_procedure ("plug_in_gap_goto",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_INT32, range_list->from,
|
|
GIMP_PDB_END);
|
|
if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
|
|
{
|
|
return_vals = gimp_run_procedure ("plug_in_gap_dup",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_INT32, 1, /* copy block 1 times */
|
|
GIMP_PDB_INT32, range_list->from,
|
|
GIMP_PDB_INT32, range_list->to,
|
|
GIMP_PDB_END);
|
|
}
|
|
range_item = range_list;
|
|
range_list = range_list->next;
|
|
g_free(range_item);
|
|
}
|
|
navi_update_after_goto();
|
|
}
|
|
} /* end navi_dialog_frames_duplicate_frame_callback */
|
|
|
|
void navi_dialog_frames_delete_frame_callback(GtkWidget *w, gpointer data)
|
|
{
|
|
SelectedRange *range_list;
|
|
SelectedRange *range_item;
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
|
|
|
|
if(gap_debug) printf("navi_dialog_frames_delete_frame_callback\n");
|
|
|
|
range_list = navi_get_selected_ranges();
|
|
if(range_list)
|
|
{
|
|
navi_set_waiting_cursor();
|
|
while(range_list)
|
|
{
|
|
/* Note: process the ranges from high frame_nummers
|
|
* downto low frame_numbers.
|
|
* (the range_list was created in a way that
|
|
* the highest range is added as 1st list element)
|
|
*/
|
|
if(gap_debug) printf("Delete Range from:%d to:%d\n"
|
|
,(int)range_list->from ,(int)range_list->to );
|
|
|
|
return_vals = gimp_run_procedure ("plug_in_gap_goto",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_INT32, range_list->from,
|
|
GIMP_PDB_END);
|
|
if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
|
|
{
|
|
return_vals = gimp_run_procedure ("plug_in_gap_del",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_INT32, 1 + (range_list->to - range_list->from), /* number of frames to delete */
|
|
GIMP_PDB_END);
|
|
}
|
|
range_item = range_list;
|
|
range_list = range_list->next;
|
|
g_free(range_item);
|
|
}
|
|
navi_update_after_goto();
|
|
}
|
|
} /* end navi_dialog_frames_delete_frame_callback */
|
|
|
|
void navi_dialog_goto_callback(gint32 dst_framenr)
|
|
{
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
|
|
if(gap_debug) printf("navi_dialog_goto_callback\n");
|
|
navi_set_waiting_cursor();
|
|
return_vals = gimp_run_procedure ("plug_in_gap_goto",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_INT32, dst_framenr,
|
|
GIMP_PDB_END);
|
|
navi_update_after_goto();
|
|
}
|
|
|
|
void navi_dialog_vcr_goto_first_callback(GtkWidget *w, gpointer data)
|
|
{
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
|
|
if(gap_debug) printf("navi_dialog_vcr_goto_first_callback\n");
|
|
navi_set_waiting_cursor();
|
|
return_vals = gimp_run_procedure ("plug_in_gap_first",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_END);
|
|
navi_update_after_goto();
|
|
}
|
|
|
|
void navi_dialog_vcr_goto_prev_callback(GtkWidget *w, gpointer data)
|
|
{
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
|
|
if(gap_debug) printf("navi_dialog_vcr_goto_prev_callback\n");
|
|
navi_set_waiting_cursor();
|
|
return_vals = gimp_run_procedure ("plug_in_gap_prev",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_END);
|
|
navi_update_after_goto();
|
|
}
|
|
|
|
void navi_dialog_vcr_goto_prevblock_callback(GtkWidget *w, gpointer data)
|
|
{
|
|
gint32 dst_framenr;
|
|
|
|
if(gap_debug) printf("navi_dialog_vcr_goto_prevblock_callback\n");
|
|
if(naviD->ainfo_ptr == NULL) navi_reload_ainfo(naviD->active_imageid);
|
|
if(naviD->ainfo_ptr == NULL) return;
|
|
if(naviD->vin_ptr == NULL) return;
|
|
dst_framenr = MAX(naviD->ainfo_ptr->curr_frame_nr - naviD->vin_ptr->timezoom,
|
|
naviD->ainfo_ptr->first_frame_nr);
|
|
|
|
navi_dialog_goto_callback(dst_framenr);
|
|
}
|
|
|
|
void navi_dialog_vcr_goto_next_callback(GtkWidget *w, gpointer data)
|
|
{
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
|
|
if(gap_debug) printf("navi_dialog_vcr_goto_next_callback\n");
|
|
navi_set_waiting_cursor();
|
|
return_vals = gimp_run_procedure ("plug_in_gap_next",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_END);
|
|
navi_update_after_goto();
|
|
}
|
|
void navi_dialog_vcr_goto_nextblock_callback(GtkWidget *w, gpointer data)
|
|
{
|
|
gint32 dst_framenr;
|
|
|
|
if(gap_debug) printf("navi_dialog_vcr_goto_nextblock_callback\n");
|
|
if(naviD->ainfo_ptr == NULL) navi_reload_ainfo(naviD->active_imageid);
|
|
if(naviD->ainfo_ptr == NULL) return;
|
|
if(naviD->vin_ptr == NULL) return;
|
|
dst_framenr = MIN(naviD->ainfo_ptr->curr_frame_nr + naviD->vin_ptr->timezoom,
|
|
naviD->ainfo_ptr->last_frame_nr);
|
|
|
|
navi_dialog_goto_callback(dst_framenr);
|
|
}
|
|
|
|
void navi_dialog_vcr_goto_last_callback(GtkWidget *w, gpointer data)
|
|
{
|
|
GimpParam *return_vals;
|
|
int nreturn_vals;
|
|
|
|
if(gap_debug) printf("navi_dialog_vcr_goto_last_callback\n");
|
|
navi_set_waiting_cursor();
|
|
return_vals = gimp_run_procedure ("plug_in_gap_last",
|
|
&nreturn_vals,
|
|
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
|
|
GIMP_PDB_IMAGE, naviD->active_imageid,
|
|
GIMP_PDB_DRAWABLE, -1, /* dummy */
|
|
GIMP_PDB_END);
|
|
navi_update_after_goto();
|
|
}
|
|
|
|
static void
|
|
frames_timing_update (void)
|
|
{
|
|
FrameWidget *fw;
|
|
GSList *list;
|
|
|
|
list = naviD->frame_widgets;
|
|
while (list)
|
|
{
|
|
fw = (FrameWidget *) list->data;
|
|
list = g_slist_next (list);
|
|
frame_widget_time_label_update(fw);
|
|
}
|
|
}
|
|
|
|
void
|
|
navi_framerate_scale_update(GtkAdjustment *adjustment,
|
|
gpointer data)
|
|
{
|
|
gdouble framerate;
|
|
|
|
if(naviD == NULL) return;
|
|
if(naviD->vin_ptr == NULL) return;
|
|
|
|
framerate = (gdouble) (adjustment->value);
|
|
if(framerate != naviD->vin_ptr->framerate)
|
|
{
|
|
naviD->vin_ptr->framerate = framerate;
|
|
if(naviD->ainfo_ptr)
|
|
{
|
|
/* write new framerate to video info file */
|
|
p_set_video_info(naviD->vin_ptr, naviD->ainfo_ptr->basename);
|
|
}
|
|
frames_timing_update();
|
|
}
|
|
if(gap_debug) printf("navi_framerate_scale_update :%d\n", (int)naviD->vin_ptr->framerate);
|
|
}
|
|
|
|
void
|
|
navi_timezoom_scale_update(GtkAdjustment *adjustment,
|
|
gpointer data)
|
|
{
|
|
gint timezoom;
|
|
GtkAdjustment *adj;
|
|
gfloat adj_val;
|
|
|
|
if(naviD == NULL) return;
|
|
if(naviD->vin_ptr == NULL) return;
|
|
|
|
timezoom = (int) (adjustment->value);
|
|
if(timezoom != naviD->vin_ptr->timezoom)
|
|
{
|
|
adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (naviD->scrolled_win));
|
|
|
|
if(timezoom != 0)
|
|
{
|
|
adj_val = (adj->value * (gfloat)naviD->vin_ptr->timezoom) / (gfloat)timezoom;
|
|
if(adj_val > MAX_HEIGHT_GTK_SCROLLED_WIN)
|
|
{
|
|
adj_val = MAX_HEIGHT_GTK_SCROLLED_WIN - adj->page_size;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
adj_val = adj->value;
|
|
}
|
|
naviD->vin_ptr->timezoom = timezoom;
|
|
if(naviD->ainfo_ptr)
|
|
{
|
|
/* write new timezoom to video info file */
|
|
p_set_video_info(naviD->vin_ptr, naviD->ainfo_ptr->basename);
|
|
}
|
|
frames_dialog_flush();
|
|
gtk_adjustment_set_value(adjustment, (gfloat)timezoom);
|
|
adj->value = adj_val;
|
|
gtk_adjustment_value_changed (adj);
|
|
}
|
|
if(gap_debug) printf("navi_timezoom_scale_update :%d\n", (int)naviD->vin_ptr->timezoom);
|
|
}
|
|
|
|
/********************************/
|
|
/* frame list events callback */
|
|
/********************************/
|
|
|
|
static gint
|
|
frame_list_events (GtkWidget *widget,
|
|
GdkEvent *event,
|
|
gpointer data)
|
|
{
|
|
GdkEventButton *bevent;
|
|
GtkWidget *event_widget;
|
|
FrameWidget *frame_widget;
|
|
|
|
event_widget = gtk_get_event_widget (event);
|
|
|
|
if (GTK_IS_LIST_ITEM (event_widget))
|
|
{
|
|
frame_widget =
|
|
(FrameWidget *) gtk_object_get_user_data (GTK_OBJECT (event_widget));
|
|
|
|
switch (event->type)
|
|
{
|
|
case GDK_BUTTON_PRESS:
|
|
bevent = (GdkEventButton *) event;
|
|
|
|
if (bevent->button == 3)
|
|
{
|
|
if(gap_debug) printf("frame_list_events: GDK_BUTTON_PRESS bevent->button == 3\n");
|
|
navi_ops_menu_set_sensitive();
|
|
gtk_menu_popup (GTK_MENU (naviD->ops_menu),
|
|
NULL, NULL, NULL, NULL,
|
|
3, bevent->time);
|
|
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case GDK_2BUTTON_PRESS:
|
|
bevent = (GdkEventButton *) event;
|
|
if(gap_debug) printf("frame_list_events: GDK_2BUTTON_PRESS event\n");
|
|
|
|
navi_dialog_goto_callback(frame_widget->frame_nr);
|
|
return TRUE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void
|
|
frames_dialog_flush (void)
|
|
{
|
|
if(gap_debug) printf("frames_dialog_flush\n");
|
|
if(naviD)
|
|
{
|
|
frames_dialog_update(naviD->active_imageid);
|
|
}
|
|
}
|
|
|
|
void
|
|
frames_dialog_update (gint32 image_id)
|
|
{
|
|
FrameWidget *fw;
|
|
GSList *list;
|
|
GList *item_list;
|
|
gint32 l_frame_nr;
|
|
gint32 l_count;
|
|
gint32 l_warning_flag;
|
|
gint32 scrolled_window_height;
|
|
gint32 scrolled_window_height_ok;
|
|
GtkAdjustment *adj;
|
|
gint l_waiting_cursor;
|
|
|
|
if(gap_debug) printf("frames_dialog_update image_id:%d\n", (int)image_id);
|
|
|
|
if (! naviD) /* || (naviD->active_imageid == image_id) */
|
|
{
|
|
return;
|
|
}
|
|
l_waiting_cursor = naviD->waiting_cursor;
|
|
if(!naviD->waiting_cursor) navi_set_waiting_cursor();
|
|
|
|
navi_reload_ainfo(image_id);
|
|
|
|
/* Make sure the gimage is not notified of this change */
|
|
suspend_gimage_notify++;
|
|
scrolled_window_height_ok = 0;
|
|
|
|
/* Free all elements in the frames listbox */
|
|
gtk_list_clear_items (GTK_LIST (naviD->frame_list), 0, -1);
|
|
|
|
list = naviD->frame_widgets;
|
|
while (list)
|
|
{
|
|
fw = (FrameWidget *) list->data;
|
|
list = g_slist_next (list);
|
|
frame_widget_delete (fw);
|
|
}
|
|
|
|
if (naviD->frame_widgets)
|
|
g_warning ("frames_dialog_update(): naviD->frame_widgets not empty!");
|
|
naviD->frame_widgets = NULL;
|
|
|
|
/* Find the preview extents */
|
|
navi_preview_extents ();
|
|
|
|
|
|
/* naviD->active_layer = NULL;
|
|
*/
|
|
|
|
l_count = 0;
|
|
l_warning_flag = 0;
|
|
scrolled_window_height = naviD->item_height;
|
|
item_list = NULL;
|
|
for (l_frame_nr = naviD->ainfo_ptr->first_frame_nr;
|
|
l_frame_nr <= naviD->ainfo_ptr->last_frame_nr;
|
|
l_frame_nr++)
|
|
{
|
|
/* create a frame list item */
|
|
if((l_frame_nr == naviD->ainfo_ptr->first_frame_nr)
|
|
|| (l_frame_nr == naviD->ainfo_ptr->last_frame_nr)
|
|
|| (((l_frame_nr - naviD->ainfo_ptr->first_frame_nr) % naviD->vin_ptr->timezoom) == 0) )
|
|
{
|
|
|
|
if(scrolled_window_height < MAX_HEIGHT_GTK_SCROLLED_WIN)
|
|
{
|
|
fw = frame_widget_create (image_id, l_frame_nr);
|
|
if(fw)
|
|
{
|
|
naviD->frame_widgets = g_slist_append (naviD->frame_widgets, fw);
|
|
item_list = g_list_append (item_list, fw->list_item);
|
|
scrolled_window_height_ok = scrolled_window_height;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(l_warning_flag == 0)
|
|
{
|
|
printf("WARNING: GTK listbox can't handle more than %d items of %d pixels height\n"
|
|
,(int)l_count, (int)naviD->item_height);
|
|
printf(" can't display frames upto %d\n", (int)naviD->ainfo_ptr->last_frame_nr);
|
|
l_warning_flag = 1;
|
|
}
|
|
}
|
|
l_count++;
|
|
scrolled_window_height += naviD->item_height;
|
|
}
|
|
}
|
|
|
|
if(gap_debug) printf("LIST_CREATED: first:%d, last:%d\n, count:%d\n",
|
|
(int)naviD->ainfo_ptr->first_frame_nr,
|
|
(int)naviD->ainfo_ptr->last_frame_nr,
|
|
(int)l_count );
|
|
|
|
|
|
/* get the index of the active frame */
|
|
if (item_list)
|
|
{
|
|
gtk_list_insert_items (GTK_LIST (naviD->frame_list), item_list, 0);
|
|
adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (naviD->scrolled_win));
|
|
adj->lower = 0;
|
|
adj->upper = scrolled_window_height_ok;
|
|
}
|
|
suspend_gimage_notify--;
|
|
if(!l_waiting_cursor) navi_set_active_cursor();
|
|
}
|
|
|
|
static void
|
|
frame_widget_select_update (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
FrameWidget *frame_widget;
|
|
|
|
if (! (frame_widget = (FrameWidget *) data))
|
|
return;
|
|
|
|
/* Is the list item being selected? */
|
|
if (widget->state != GTK_STATE_SELECTED)
|
|
return;
|
|
|
|
/* Only notify the gimage of an active layer change if necessary */
|
|
if (suspend_gimage_notify == 0)
|
|
{
|
|
if(gap_debug) printf("frame_widget_select_update NOT IMPLEMENTED (maybe not needed)\n");
|
|
}
|
|
}
|
|
|
|
static gint
|
|
frame_widget_button_events (GtkWidget *widget,
|
|
GdkEvent *event)
|
|
{
|
|
if(gap_debug) printf("frame_widget_button_events NOT IMPLEMENTED\n");
|
|
return -1;
|
|
}
|
|
|
|
/***********************/
|
|
/* Preview functions */
|
|
/***********************/
|
|
static gint
|
|
render_current_preview (GtkWidget *preview_widget, FrameWidget *fw)
|
|
{
|
|
guchar *l_rowbuf;
|
|
guchar *l_ptr;
|
|
gint32 l_x, l_y;
|
|
gint32 l_ofx, l_ofy;
|
|
gint32 l_ofs_thpixel;
|
|
guchar *l_thumbdata_ptr;
|
|
gint32 l_thumbdata_count;
|
|
gint32 l_th_width;
|
|
gint32 l_th_height;
|
|
gint32 l_th_bpp;
|
|
gint32 l_thumb_rowstride;
|
|
gint32 l_pv_width;
|
|
gint32 l_pv_height;
|
|
gdouble l_xscale;
|
|
gdouble l_yscale;
|
|
gdouble l_ofd;
|
|
guchar l_alpha;
|
|
gint l_1;
|
|
gint l_offset;
|
|
gint l_rc;
|
|
|
|
|
|
if(gap_debug) printf("render_current_preview START\n");
|
|
|
|
l_rc = FALSE;
|
|
if(naviD == NULL) return (l_rc);
|
|
if(naviD->ainfo_ptr == NULL) return(l_rc);
|
|
|
|
l_thumbdata_ptr = NULL;
|
|
l_pv_width = naviD->image_width;
|
|
l_pv_height = naviD->image_height;
|
|
|
|
if(gap_debug) printf("render_current_preview BEFORE p_gimp_image_thumbnail w:%d h:%d,\n"
|
|
,(int)l_pv_width, (int)l_pv_height);
|
|
p_gimp_image_thumbnail(naviD->active_imageid, l_pv_width, l_pv_height,
|
|
&l_th_width, &l_th_height, &l_th_bpp,
|
|
&l_thumbdata_count, &l_thumbdata_ptr);
|
|
if(gap_debug) printf("render_current_preview AFTER p_gimp_image_thumbnail th_w:%d th_h:%d, th_bpp:%d, count:%d\n"
|
|
,(int)l_th_width, (int)l_th_height, (int)l_th_bpp, (int)l_thumbdata_count);
|
|
|
|
if(l_th_bpp < 3) l_1 = 0;
|
|
else l_1 = 1;
|
|
|
|
l_rowbuf = g_malloc(PREVIEW_BPP * l_pv_width);
|
|
if(l_rowbuf == NULL) return(l_rc);
|
|
|
|
if(l_thumbdata_ptr != NULL)
|
|
{
|
|
l_xscale = (gdouble)l_th_width / (gdouble)l_pv_width;
|
|
l_yscale = (gdouble)l_th_height / (gdouble)l_pv_height;
|
|
l_thumb_rowstride = l_th_bpp * l_th_width;
|
|
|
|
/* render preview */
|
|
for(l_y = 0; l_y < l_pv_height; l_y++)
|
|
{
|
|
l_ptr = l_rowbuf;
|
|
l_ofd = (l_yscale * (gdouble)l_y) + 0.5;
|
|
l_ofy = (gint32)(l_ofd) * l_thumb_rowstride;
|
|
|
|
if(l_y & 0x4) l_offset = 4;
|
|
else l_offset = 0;
|
|
|
|
if((l_th_bpp > 3) || (l_th_bpp == 2))
|
|
{
|
|
/* thumbdata has alpha channel */
|
|
for(l_x = 0; l_x < l_pv_width; l_x++)
|
|
{
|
|
l_ofd = (l_xscale * (gdouble)l_x) + 0.5;
|
|
l_ofx = (gint32)(l_ofd) * l_th_bpp;
|
|
l_ofs_thpixel = l_ofy + l_ofx;
|
|
|
|
l_alpha = l_thumbdata_ptr[l_ofs_thpixel + (l_th_bpp -1)];
|
|
|
|
if((l_x + l_offset) & 0x4)
|
|
{
|
|
*l_ptr = MIX_CHANNEL (PREVIEW_BG_GRAY2, l_thumbdata_ptr[l_ofs_thpixel], l_alpha);
|
|
l_ptr[1] = MIX_CHANNEL (PREVIEW_BG_GRAY2, l_thumbdata_ptr[l_ofs_thpixel + l_1], l_alpha);
|
|
l_ptr[2] = MIX_CHANNEL (PREVIEW_BG_GRAY2, l_thumbdata_ptr[l_ofs_thpixel + l_1 + l_1], l_alpha);
|
|
}
|
|
else
|
|
{
|
|
*l_ptr = MIX_CHANNEL (PREVIEW_BG_GRAY1, l_thumbdata_ptr[l_ofs_thpixel], l_alpha);
|
|
l_ptr[1] = MIX_CHANNEL (PREVIEW_BG_GRAY1, l_thumbdata_ptr[l_ofs_thpixel + l_1], l_alpha);
|
|
l_ptr[2] = MIX_CHANNEL (PREVIEW_BG_GRAY1, l_thumbdata_ptr[l_ofs_thpixel + l_1 + l_1], l_alpha);
|
|
}
|
|
|
|
l_ptr += PREVIEW_BPP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(l_x = 0; l_x < l_pv_width; l_x++)
|
|
{
|
|
l_ofd = (l_xscale * (gdouble)l_x) + 0.5;
|
|
l_ofx = (gint32)(l_ofd) * l_th_bpp;
|
|
l_ofs_thpixel = l_ofy + l_ofx;
|
|
|
|
*l_ptr = l_thumbdata_ptr[l_ofs_thpixel];
|
|
l_ptr[1] = l_thumbdata_ptr[l_ofs_thpixel + l_1];
|
|
l_ptr[2] = l_thumbdata_ptr[l_ofs_thpixel + l_1 + l_1];
|
|
|
|
l_ptr += PREVIEW_BPP;
|
|
}
|
|
}
|
|
gtk_preview_draw_row(GTK_PREVIEW(preview_widget), l_rowbuf, 0, l_y, l_pv_width);
|
|
}
|
|
l_rc = TRUE;
|
|
}
|
|
|
|
if(l_rowbuf) g_free(l_rowbuf);
|
|
if(l_thumbdata_ptr) g_free(l_thumbdata_ptr);
|
|
|
|
if(gap_debug) printf("render_current_preview END\n");
|
|
|
|
return (l_rc);
|
|
|
|
} /* end render_current_preview */
|
|
|
|
static gint
|
|
render_preview (GtkWidget *preview_widget, FrameWidget *fw)
|
|
{
|
|
guchar *l_rowbuf;
|
|
guchar *l_ptr;
|
|
gint32 l_x, l_y;
|
|
gint32 l_ofx, l_ofy;
|
|
gint32 l_ofs_thpixel;
|
|
gint32 l_th_width;
|
|
gint32 l_th_height;
|
|
gint32 l_thumb_rowstride;
|
|
gint32 l_pv_width;
|
|
gint32 l_pv_height;
|
|
gdouble l_xscale;
|
|
gdouble l_yscale;
|
|
gdouble l_ofd;
|
|
char *l_filename;
|
|
gint l_rc;
|
|
guchar *l_raw_thumb;
|
|
gchar *l_tname;
|
|
gchar *imginfo = NULL;
|
|
struct stat l_stat_thumb;
|
|
|
|
|
|
if(gap_debug) printf("render_preview (quick)\n");
|
|
|
|
l_rc = FALSE;
|
|
l_raw_thumb = NULL;
|
|
if(naviD == NULL) return (l_rc);
|
|
if(naviD->ainfo_ptr == NULL) return(l_rc);
|
|
if(naviD->ainfo_ptr->curr_frame_nr == fw->frame_nr)
|
|
{
|
|
/* if this is the currently open image
|
|
* we first write the thumbnail to disc
|
|
* so we get an up to date version in the following readXVThumb call
|
|
*/
|
|
l_rc = render_current_preview(preview_widget, fw);
|
|
return(l_rc);
|
|
}
|
|
|
|
l_filename = p_alloc_fname(naviD->ainfo_ptr->basename, fw->frame_nr, naviD->ainfo_ptr->extension);
|
|
l_tname = p_alloc_fname_thumbnail(l_filename);
|
|
|
|
|
|
if (0 == stat(l_tname, &l_stat_thumb))
|
|
{
|
|
fw->thumb_timestamp = l_stat_thumb.st_mtime;
|
|
l_raw_thumb = readXVThumb (l_tname, &l_th_width, &l_th_height, &imginfo);
|
|
if(fw->thumb_filename) g_free(fw->thumb_filename);
|
|
fw->thumb_filename = l_tname;
|
|
}
|
|
else
|
|
{
|
|
g_free(l_tname);
|
|
}
|
|
|
|
l_pv_width = naviD->image_width;
|
|
l_pv_height = naviD->image_height;
|
|
|
|
l_rowbuf = g_malloc(PREVIEW_BPP * l_pv_width);
|
|
if(l_rowbuf == NULL) return(l_rc);
|
|
|
|
if(l_raw_thumb != NULL)
|
|
{
|
|
l_xscale = (gdouble)l_th_width / (gdouble)l_pv_width;
|
|
l_yscale = (gdouble)l_th_height / (gdouble)l_pv_height;
|
|
l_thumb_rowstride = l_th_width; /* raw thumb data BPP is 1 */
|
|
|
|
/* render preview */
|
|
for(l_y = 0; l_y < l_pv_height; l_y++)
|
|
{
|
|
l_ptr = l_rowbuf;
|
|
l_ofd = (l_yscale * (gdouble)l_y) + 0.5;
|
|
l_ofy = (gint32)(l_ofd) * l_thumb_rowstride; /* check if > thumbnail height !!! */
|
|
|
|
for(l_x = 0; l_x < l_pv_width; l_x++)
|
|
{
|
|
l_ofd = (l_xscale * (gdouble)l_x) + 0.5;
|
|
l_ofx = (gint32)(l_ofd); /* raw thumb data BPP is 1 */
|
|
l_ofs_thpixel = l_ofy + l_ofx;
|
|
|
|
*l_ptr = ((l_raw_thumb[l_ofs_thpixel]>>5)*255)/7;
|
|
l_ptr[1] = (((l_raw_thumb[l_ofs_thpixel]>>2)&7)*255)/7;
|
|
l_ptr[2] = (((l_raw_thumb[l_ofs_thpixel])&3)*255)/3;
|
|
|
|
l_ptr += PREVIEW_BPP;
|
|
}
|
|
gtk_preview_draw_row(GTK_PREVIEW(preview_widget), l_rowbuf, 0, l_y, l_pv_width);
|
|
}
|
|
l_rc = TRUE;
|
|
}
|
|
|
|
if(l_rowbuf) g_free(l_rowbuf);
|
|
if(l_raw_thumb) g_free(l_raw_thumb);
|
|
if(l_filename) g_free(l_filename);
|
|
|
|
return (l_rc);
|
|
} /* end render_preview */
|
|
|
|
|
|
void
|
|
render_no_preview (GtkWidget *widget,
|
|
GdkPixmap *pixmap)
|
|
{
|
|
int w, h;
|
|
int x1, y1, x2, y2;
|
|
GdkPoint poly[6];
|
|
int foldh, foldw;
|
|
int i;
|
|
|
|
gdk_window_get_size (pixmap, &w, &h);
|
|
|
|
x1 = 2;
|
|
y1 = h / 8 + 2;
|
|
x2 = w - w / 8 - 2;
|
|
y2 = h - 2;
|
|
gdk_draw_rectangle (pixmap, widget->style->bg_gc[GTK_STATE_NORMAL], 1,
|
|
0, 0, w, h);
|
|
/*
|
|
gdk_draw_rectangle (pixmap, widget->style->black_gc, 0,
|
|
x1, y1, (x2 - x1), (y2 - y1));
|
|
*/
|
|
|
|
foldw = w / 4;
|
|
foldh = h / 4;
|
|
x1 = w / 8 + 2;
|
|
y1 = 2;
|
|
x2 = w - 2;
|
|
y2 = h - h / 8 - 2;
|
|
|
|
poly[0].x = x1 + foldw; poly[0].y = y1;
|
|
poly[1].x = x1 + foldw; poly[1].y = y1 + foldh;
|
|
poly[2].x = x1; poly[2].y = y1 + foldh;
|
|
poly[3].x = x1; poly[3].y = y2;
|
|
poly[4].x = x2; poly[4].y = y2;
|
|
poly[5].x = x2; poly[5].y = y1;
|
|
gdk_draw_polygon (pixmap, widget->style->white_gc, 1, poly, 6);
|
|
|
|
gdk_draw_line (pixmap, widget->style->black_gc,
|
|
x1, y1 + foldh, x1, y2);
|
|
gdk_draw_line (pixmap, widget->style->black_gc,
|
|
x1, y2, x2, y2);
|
|
gdk_draw_line (pixmap, widget->style->black_gc,
|
|
x2, y2, x2, y1);
|
|
gdk_draw_line (pixmap, widget->style->black_gc,
|
|
x1 + foldw, y1, x2, y1);
|
|
|
|
for (i = 0; i < foldw; i++)
|
|
{
|
|
gdk_draw_line (pixmap, widget->style->black_gc,
|
|
x1 + i, y1 + foldh, x1 + i, (foldw == 1) ? y1 :
|
|
(y1 + (foldh - (foldh * i) / (foldw - 1))));
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
frame_widget_preview_redraw (FrameWidget *frame_widget)
|
|
{
|
|
GdkPixmap **pixmap;
|
|
GtkWidget *widget;
|
|
|
|
widget = frame_widget->frame_preview;
|
|
pixmap = &frame_widget->frame_pixmap;
|
|
|
|
if(gap_debug) printf("frame_widget_preview_redraw image_id: %d, frame_nr:%d\n"
|
|
,(int)frame_widget->image_id
|
|
,(int)frame_widget->frame_nr);
|
|
|
|
/* determine width and height */
|
|
if((frame_widget->width != naviD->image_width)
|
|
|| (frame_widget->height != naviD->image_height))
|
|
{
|
|
frame_widget->width = naviD->image_width;
|
|
frame_widget->height = naviD->image_height;
|
|
if (frame_widget->width < 1) frame_widget->width = 1;
|
|
if (frame_widget->height < 1) frame_widget->height = 1;
|
|
gtk_drawing_area_size (GTK_DRAWING_AREA (frame_widget->frame_preview),
|
|
naviD->image_width + 4, naviD->image_height + 4);
|
|
if(*pixmap)
|
|
{
|
|
gdk_pixmap_unref(*pixmap);
|
|
*pixmap = NULL;
|
|
}
|
|
}
|
|
/* allocate the layer widget pixmap */
|
|
if (! *pixmap)
|
|
{
|
|
*pixmap = gdk_pixmap_new (widget->window,
|
|
naviD->image_width,
|
|
naviD->image_height,
|
|
-1);
|
|
}
|
|
|
|
|
|
if(naviD->preview_size < 1)
|
|
{
|
|
/* preview_size is none, render a default icon */
|
|
render_no_preview (widget, *pixmap);
|
|
}
|
|
else
|
|
{
|
|
if(TRUE == render_preview (naviD->frame_preview, frame_widget))
|
|
{
|
|
gtk_preview_put (GTK_PREVIEW (naviD->frame_preview),
|
|
*pixmap, widget->style->black_gc,
|
|
0, 0, 0, 0, naviD->image_width, naviD->image_height);
|
|
}
|
|
else
|
|
{
|
|
/* frame has no thumbnail (.xvpics), render a default icon */
|
|
render_no_preview (widget, *pixmap);
|
|
}
|
|
}
|
|
|
|
/* make sure the image has been transfered completely to the pixmap before
|
|
* we use it again...
|
|
*/
|
|
gdk_flush ();
|
|
|
|
} /* end frame_widget_preview_redraw */
|
|
|
|
|
|
static gint
|
|
frame_widget_preview_events (GtkWidget *widget,
|
|
GdkEvent *event)
|
|
{
|
|
GdkEventExpose *eevent;
|
|
GdkPixmap **pixmap;
|
|
GdkEventButton *bevent;
|
|
FrameWidget *frame_widget;
|
|
int valid;
|
|
int sx, sy, dx, dy, w, h;
|
|
|
|
pixmap = NULL;
|
|
valid = FALSE;
|
|
|
|
frame_widget = (FrameWidget *) gtk_object_get_user_data (GTK_OBJECT (widget));
|
|
if (frame_widget->frame_nr < 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pixmap = &frame_widget->frame_pixmap;
|
|
/* valid = GIMP_DRAWABLE(frame_widget->layer)->preview_valid; */ /* ?? */
|
|
|
|
switch (event->type)
|
|
{
|
|
case GDK_2BUTTON_PRESS:
|
|
navi_dialog_goto_callback(frame_widget->frame_nr);
|
|
return TRUE;
|
|
case GDK_BUTTON_PRESS:
|
|
/* Control-button press disables the application of the mask */
|
|
bevent = (GdkEventButton *) event;
|
|
|
|
if(gap_debug) printf("frame_widget_preview_events GDK_BUTTON_PRESS button:%d\n"
|
|
, (int)bevent->button);
|
|
|
|
if (bevent->button == 3)
|
|
{
|
|
navi_ops_menu_set_sensitive();
|
|
gtk_menu_popup (GTK_MENU (naviD->ops_menu),
|
|
NULL, NULL, NULL, NULL,
|
|
3, bevent->time);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (event->button.state & GDK_CONTROL_MASK)
|
|
{
|
|
}
|
|
/* Alt-button press makes the mask visible instead of the layer */
|
|
else if (event->button.state & GDK_MOD1_MASK)
|
|
{
|
|
}
|
|
break;
|
|
|
|
case GDK_EXPOSE:
|
|
if(gap_debug) printf("frame_widget_preview_events GDK_EXPOSE\n");
|
|
|
|
navi_preview_extents();
|
|
frame_widget_time_label_update(frame_widget);
|
|
|
|
if (!valid || !*pixmap)
|
|
{
|
|
frame_widget_preview_redraw (frame_widget);
|
|
|
|
gdk_draw_pixmap (widget->window,
|
|
widget->style->black_gc,
|
|
*pixmap,
|
|
0, 0, 2, 2,
|
|
naviD->image_width,
|
|
naviD->image_height);
|
|
}
|
|
else
|
|
{
|
|
eevent = (GdkEventExpose *) event;
|
|
|
|
w = eevent->area.width;
|
|
h = eevent->area.height;
|
|
|
|
if (eevent->area.x < 2)
|
|
{
|
|
sx = eevent->area.x;
|
|
dx = 2;
|
|
w -= (2 - eevent->area.x);
|
|
}
|
|
else
|
|
{
|
|
sx = eevent->area.x - 2;
|
|
dx = eevent->area.x;
|
|
}
|
|
|
|
if (eevent->area.y < 2)
|
|
{
|
|
sy = eevent->area.y;
|
|
dy = 2;
|
|
h -= (2 - eevent->area.y);
|
|
}
|
|
else
|
|
{
|
|
sy = eevent->area.y - 2;
|
|
dy = eevent->area.y;
|
|
}
|
|
|
|
if ((sx + w) >= naviD->image_width)
|
|
{
|
|
w = naviD->image_width - sx;
|
|
}
|
|
|
|
if ((sy + h) >= naviD->image_height)
|
|
{
|
|
h = naviD->image_height - sy;
|
|
}
|
|
|
|
if ((w > 0) && (h > 0))
|
|
{
|
|
gdk_draw_pixmap (widget->window,
|
|
widget->style->black_gc,
|
|
*pixmap,
|
|
sx, sy, dx, dy, w, h);
|
|
}
|
|
}
|
|
|
|
/* The boundary indicating whether layer or mask is active */
|
|
/* frames do not have boundary */
|
|
/* frame_widget_boundary_redraw (frame_widget); */
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
} /* end frame_widget_preview_events */
|
|
|
|
|
|
static gint
|
|
navi_dialog_poll(GtkWidget *w, gpointer data)
|
|
{
|
|
gint32 frame_nr;
|
|
gint32 update_flag;
|
|
gint32 video_preview_size;
|
|
|
|
if(gap_debug) printf("navi_dialog_poll TIMER POLL\n");
|
|
|
|
if(naviD)
|
|
{
|
|
if(suspend_gimage_notify == 0)
|
|
{
|
|
update_flag = NUPD_IMAGE_MENU;
|
|
video_preview_size = navi_get_preview_size();
|
|
if(naviD->preview_size != video_preview_size)
|
|
{
|
|
naviD->preview_size = video_preview_size;
|
|
update_flag = NUPD_ALL;
|
|
}
|
|
|
|
/* check and enable/disable tooltips */
|
|
navi_dialog_tooltips ();
|
|
|
|
frame_nr = p_get_frame_nr(naviD->active_imageid);
|
|
if(frame_nr < 0 )
|
|
{
|
|
/* no valid frame number, maybe frame was closed
|
|
*/
|
|
naviD->active_imageid = -1;
|
|
update_flag = NUPD_ALL;
|
|
}
|
|
else
|
|
{
|
|
if(naviD->ainfo_ptr)
|
|
{
|
|
update_flag = NUPD_IMAGE_MENU | NUPD_FRAME_NR_CHANGED;
|
|
}
|
|
else
|
|
{
|
|
update_flag = NUPD_ALL;
|
|
}
|
|
}
|
|
navi_dialog_update(update_flag);
|
|
}
|
|
|
|
/* restart timer */
|
|
naviD->timer = gtk_timeout_add(naviD->cycle_time,
|
|
(GtkFunction)navi_dialog_poll, NULL);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
navid_thumb_timestamp_check(void)
|
|
{
|
|
struct stat l_stat_thumb;
|
|
FrameWidget *fw;
|
|
GSList *list;
|
|
GtkAdjustment *adj;
|
|
gint item_count;
|
|
|
|
if(naviD == NULL) return;
|
|
if(naviD->ainfo_ptr == NULL) return;
|
|
|
|
adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (naviD->scrolled_win));
|
|
|
|
if(gap_debug) printf("navid_thumb_timestamp_check: adj->value:%d adj->page_size:%d\n", (int)adj->value, (int)adj->page_size);
|
|
|
|
list = naviD->frame_widgets;
|
|
item_count = -1;
|
|
while (list)
|
|
{
|
|
item_count++;
|
|
fw = (FrameWidget *) list->data;
|
|
list = g_slist_next (list);
|
|
|
|
if((item_count * naviD->item_height) < (adj->value - naviD->image_height))
|
|
{
|
|
continue; /* WIDGET IS NOT EXPOSED */
|
|
}
|
|
if((item_count * naviD->item_height) > (adj->value + adj->page_size))
|
|
{
|
|
return; /* WIDGET (and all further widgets) ARE NOT EXPOSED */
|
|
}
|
|
|
|
if(gap_debug) printf("navid_thumb_timestamp_check: Widget IS EXPOSED frame_nr:%04d\n", (int)fw->frame_nr);
|
|
|
|
if(fw->frame_nr == naviD->ainfo_ptr->curr_frame_nr)
|
|
{
|
|
/* always redraw the currently opened frame
|
|
* (the render procedure uses gimp's internal chached thumbnaildata
|
|
* so the timestamp of the .xvpics thumbnailfile does not matter here)
|
|
*/
|
|
gtk_widget_draw(fw->frame_preview, NULL);
|
|
continue;
|
|
}
|
|
|
|
/* for the other exposed items we check the tumbnail timestamp */
|
|
if(fw->thumb_filename)
|
|
{
|
|
if (0 == stat(fw->thumb_filename, &l_stat_thumb))
|
|
{
|
|
if(fw->thumb_timestamp < l_stat_thumb.st_mtime)
|
|
{
|
|
gtk_widget_draw(fw->frame_preview, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
navi_dialog_update(gint32 update_flag)
|
|
{
|
|
gint32 l_first, l_last;
|
|
gint l_image_menu_was_changed;
|
|
|
|
l_image_menu_was_changed = FALSE;
|
|
if(update_flag & NUPD_IMAGE_MENU)
|
|
{
|
|
l_image_menu_was_changed = navi_refresh_image_menu();
|
|
}
|
|
if(update_flag & NUPD_FRAME_NR_CHANGED)
|
|
{
|
|
l_first = -1;
|
|
l_last = -1;
|
|
|
|
if(naviD->ainfo_ptr)
|
|
{
|
|
l_first = naviD->ainfo_ptr->first_frame_nr;
|
|
l_last = naviD->ainfo_ptr->last_frame_nr;
|
|
}
|
|
navi_reload_ainfo(naviD->active_imageid);
|
|
navi_preview_extents();
|
|
|
|
/* we must force a rebuild of the list of frame_widgets
|
|
* if any frames were deleteted or are created
|
|
* (outside of the naviagator)
|
|
*/
|
|
if(naviD->ainfo_ptr)
|
|
{
|
|
if((l_first != naviD->ainfo_ptr->first_frame_nr)
|
|
|| (l_last != naviD->ainfo_ptr->last_frame_nr))
|
|
{
|
|
update_flag |= NUPD_PREV_LIST;
|
|
}
|
|
}
|
|
}
|
|
if(update_flag & NUPD_PREV_LIST)
|
|
{
|
|
frames_dialog_flush();
|
|
}
|
|
else
|
|
{
|
|
navid_thumb_timestamp_check();
|
|
}
|
|
}
|
|
|
|
|
|
/* ------------------------
|
|
* dialog helper procedures
|
|
* ------------------------
|
|
*/
|
|
static void
|
|
navi_preview_extents (void)
|
|
{
|
|
gint32 width, height;
|
|
if (!naviD)
|
|
return;
|
|
|
|
naviD->gimage_width = gimp_image_width(naviD->active_imageid);
|
|
naviD->gimage_height = gimp_image_height(naviD->active_imageid);
|
|
|
|
/* Get the image width and height variables, based on the gimage */
|
|
if (naviD->gimage_width > naviD->gimage_height)
|
|
{
|
|
naviD->ratio = (double) naviD->preview_size / (double) naviD->gimage_width;
|
|
}
|
|
else
|
|
{
|
|
naviD->ratio = (double) naviD->preview_size / (double) naviD->gimage_height;
|
|
}
|
|
|
|
if (naviD->preview_size > 0)
|
|
{
|
|
width = (int) (naviD->ratio * naviD->gimage_width);
|
|
height = (int) (naviD->ratio * naviD->gimage_height);
|
|
if (width < 1) width = 1;
|
|
if (height < 1) height = 1;
|
|
}
|
|
else
|
|
{
|
|
width = 16;
|
|
height = 10;
|
|
}
|
|
|
|
if((naviD->image_width != width)
|
|
|| (naviD->image_height != height))
|
|
{
|
|
naviD->image_width = width;
|
|
naviD->image_height = height;
|
|
gtk_preview_size (GTK_PREVIEW (naviD->frame_preview),
|
|
naviD->image_width, naviD->image_height);
|
|
}
|
|
|
|
naviD->item_height = 6 + naviD->image_height;
|
|
|
|
if(gap_debug) printf("navi_preview_extents w: %d h:%d\n", (int)naviD->image_width, (int)naviD->image_height);
|
|
}
|
|
|
|
static void
|
|
navi_calc_frametiming(gint32 frame_nr, char *buf)
|
|
{
|
|
gint32 first;
|
|
gdouble msec_per_frame;
|
|
gint32 tmsec;
|
|
gint32 tms;
|
|
gint32 tsec;
|
|
gint32 tmin;
|
|
|
|
first = frame_nr;
|
|
if(naviD->ainfo_ptr)
|
|
{
|
|
first = naviD->ainfo_ptr->first_frame_nr;
|
|
}
|
|
|
|
if(naviD->vin_ptr == NULL)
|
|
{
|
|
sprintf(buf, "min:sec:msec");
|
|
return;
|
|
}
|
|
|
|
if(naviD->vin_ptr->framerate < 1)
|
|
{
|
|
sprintf(buf, "min:sec:msec");
|
|
return;
|
|
}
|
|
|
|
msec_per_frame = 1000.0 / naviD->vin_ptr->framerate;
|
|
tmsec = (frame_nr - first) * msec_per_frame;
|
|
|
|
tms = tmsec % 1000;
|
|
tsec = (tmsec / 1000) % 60;
|
|
tmin = tmsec / 60000;
|
|
|
|
sprintf(buf, "%02d:%02d:%03d", (int)tmin, (int)tsec, (int)tms);
|
|
}
|
|
|
|
static void
|
|
frame_widget_time_label_update(FrameWidget *fw)
|
|
{
|
|
char frame_nr_to_time[20];
|
|
|
|
navi_calc_frametiming(fw->frame_nr, frame_nr_to_time);
|
|
|
|
gtk_label_set_text (GTK_LABEL (fw->time_label), frame_nr_to_time);
|
|
}
|
|
|
|
static FrameWidget *
|
|
frame_widget_create (gint32 image_id, gint32 frame_nr)
|
|
{
|
|
FrameWidget *frame_widget;
|
|
GtkWidget *list_item;
|
|
GtkWidget *hbox;
|
|
GtkWidget *vbox;
|
|
GtkWidget *alignment;
|
|
|
|
char frame_nr_to_char[20];
|
|
char frame_nr_to_time[20];
|
|
|
|
|
|
if(gap_debug) printf("frame_widget_create CREATE image_id:%d, nr:%d\n", (int)image_id, (int)frame_nr);
|
|
|
|
list_item = gtk_list_item_new ();
|
|
|
|
/* create the frame widget and add it to the list */
|
|
frame_widget = g_new (FrameWidget, 1);
|
|
frame_widget->image_id = image_id;
|
|
frame_widget->frame_nr = frame_nr;
|
|
frame_widget->frame_preview = NULL;
|
|
frame_widget->frame_pixmap = NULL;
|
|
frame_widget->list_item = list_item;
|
|
frame_widget->width = -1;
|
|
frame_widget->height = -1;
|
|
frame_widget->thumb_timestamp = 0;
|
|
frame_widget->thumb_filename = NULL;
|
|
frame_widget->visited = TRUE;
|
|
/* frame_widget->drop_type = GIMP_DROP_NONE; */
|
|
|
|
sprintf(frame_nr_to_char, "%04d", (int)frame_nr);
|
|
navi_calc_frametiming(frame_nr, frame_nr_to_time);
|
|
|
|
|
|
/* Need to let the list item know about the frame_widget */
|
|
gtk_object_set_user_data (GTK_OBJECT (list_item), frame_widget);
|
|
|
|
/* set up the list item observer */
|
|
gtk_signal_connect (GTK_OBJECT (list_item), "select",
|
|
(GtkSignalFunc) frame_widget_select_update,
|
|
frame_widget);
|
|
gtk_signal_connect (GTK_OBJECT (list_item), "deselect",
|
|
(GtkSignalFunc) frame_widget_select_update,
|
|
frame_widget);
|
|
|
|
vbox = gtk_vbox_new (FALSE, 1);
|
|
gtk_container_add (GTK_CONTAINER (list_item), vbox);
|
|
|
|
hbox = gtk_hbox_new (FALSE, 1);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 1);
|
|
|
|
/* the frame number label */
|
|
frame_widget->number_label = gtk_label_new (frame_nr_to_char);
|
|
gtk_box_pack_start (GTK_BOX (hbox), frame_widget->number_label, FALSE, FALSE, 2);
|
|
gtk_widget_show (frame_widget->number_label);
|
|
|
|
/* The frame preview */
|
|
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
|
|
gtk_box_pack_start (GTK_BOX (hbox), alignment, FALSE, FALSE, 2);
|
|
gtk_widget_show (alignment);
|
|
|
|
frame_widget->frame_preview = gtk_drawing_area_new ();
|
|
gtk_drawing_area_size (GTK_DRAWING_AREA (frame_widget->frame_preview),
|
|
naviD->image_width + 4, naviD->image_height + 4);
|
|
gtk_widget_set_events (frame_widget->frame_preview, PREVIEW_EVENT_MASK);
|
|
gtk_signal_connect (GTK_OBJECT (frame_widget->frame_preview), "event",
|
|
(GtkSignalFunc) frame_widget_preview_events,
|
|
frame_widget);
|
|
gtk_object_set_user_data (GTK_OBJECT (frame_widget->frame_preview), frame_widget);
|
|
gtk_container_add (GTK_CONTAINER (alignment), frame_widget->frame_preview);
|
|
gtk_widget_show (frame_widget->frame_preview);
|
|
|
|
/* the frame timing label */
|
|
frame_widget->time_label = gtk_label_new (frame_nr_to_time);
|
|
gtk_box_pack_start (GTK_BOX (hbox), frame_widget->time_label, FALSE, FALSE, 2);
|
|
gtk_widget_show (frame_widget->time_label);
|
|
|
|
frame_widget->clip_widget = gtk_drawing_area_new ();
|
|
gtk_drawing_area_size (GTK_DRAWING_AREA (frame_widget->clip_widget), 1, 2);
|
|
gtk_widget_set_events (frame_widget->clip_widget, BUTTON_EVENT_MASK);
|
|
gtk_signal_connect (GTK_OBJECT (frame_widget->clip_widget), "event",
|
|
(GtkSignalFunc) frame_widget_button_events,
|
|
frame_widget);
|
|
gtk_object_set_user_data (GTK_OBJECT (frame_widget->clip_widget), frame_widget);
|
|
gtk_box_pack_start (GTK_BOX (vbox), frame_widget->clip_widget,
|
|
FALSE, FALSE, 0);
|
|
/* gtk_widget_show (frame_widget->clip_widget); */
|
|
|
|
|
|
gtk_object_set_data (GTK_OBJECT (list_item), "gap_framenumber", (gpointer)frame_nr );
|
|
|
|
gtk_widget_show (hbox);
|
|
gtk_widget_show (vbox);
|
|
gtk_widget_show (list_item);
|
|
|
|
gtk_widget_ref (frame_widget->list_item);
|
|
|
|
if(gap_debug) printf("frame_widget_create END image_id:%d, nr:%d\n", (int)image_id, (int)frame_nr);
|
|
|
|
return frame_widget;
|
|
}
|
|
|
|
static void
|
|
frame_widget_delete (FrameWidget *fw)
|
|
{
|
|
if(gap_debug) printf("frame_widget_delete image_id:%d frame_nr:%d\n"
|
|
,(int)fw->image_id
|
|
,(int)fw->frame_nr
|
|
);
|
|
if(fw->frame_pixmap)
|
|
{
|
|
gdk_pixmap_unref(fw->frame_pixmap);
|
|
}
|
|
|
|
if(fw->thumb_filename) g_free(fw->thumb_filename);
|
|
|
|
/* Remove the layer widget from the list */
|
|
naviD->frame_widgets = g_slist_remove (naviD->frame_widgets, fw);
|
|
|
|
/* Release the widget */
|
|
gtk_widget_unref(fw->list_item);
|
|
g_free(fw);
|
|
}
|
|
|
|
|
|
|
|
GtkWidget *
|
|
navi_dialog_create (GtkWidget* shell, gint32 image_id)
|
|
{
|
|
GtkWidget *vbox;
|
|
GtkWidget *util_box;
|
|
GtkWidget *button_box;
|
|
GtkWidget *label;
|
|
GtkWidget *slider;
|
|
GtkWidget *menu_item;
|
|
char *l_basename;
|
|
char frame_nr_to_char[20];
|
|
|
|
if(gap_debug) printf("navi_dialog_create\n");
|
|
|
|
if (naviD)
|
|
{
|
|
return naviD->vbox;
|
|
}
|
|
l_basename = NULL;
|
|
sprintf(frame_nr_to_char, "0000 - 0000");
|
|
naviD = g_new (NaviDialog, 1);
|
|
naviD->waiting_cursor = FALSE;
|
|
naviD->cursor_wait = gdk_cursor_new (GDK_WATCH);
|
|
naviD->cursor_acitve = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
|
|
naviD->shell = shell;
|
|
naviD->frame_preview = NULL;
|
|
naviD->OpenFrameImagesList = NULL;
|
|
naviD->OpenFrameImagesCount = 0;
|
|
naviD->any_imageid = -1;
|
|
naviD->frame_widgets = NULL;
|
|
naviD->cycle_time = 1000; /* polling cylcle of 1 sec */
|
|
naviD->timer = 0;
|
|
naviD->active_imageid = image_id;
|
|
/* naviD->ainfo_ptr = navi_get_ainfo(naviD->active_imageid, NULL); */
|
|
naviD->ainfo_ptr = NULL;
|
|
naviD->framerange_number_label = NULL;
|
|
navi_reload_ainfo_force(image_id);
|
|
if(naviD->ainfo_ptr != NULL)
|
|
{
|
|
sprintf(frame_nr_to_char, "%04d - %04d"
|
|
, (int)naviD->ainfo_ptr->first_frame_nr
|
|
, (int)naviD->ainfo_ptr->last_frame_nr);
|
|
l_basename = naviD->ainfo_ptr->basename;
|
|
}
|
|
naviD->vin_ptr = p_get_video_info(l_basename);
|
|
naviD->image_width = 0;
|
|
naviD->image_height = 0;
|
|
naviD->preview_size = navi_get_preview_size();
|
|
|
|
if (naviD->preview_size > 0)
|
|
{
|
|
naviD->frame_preview = gtk_preview_new (GTK_PREVIEW_COLOR);
|
|
navi_preview_extents ();
|
|
}
|
|
|
|
/* creates tooltips */
|
|
gimp_help_init ();
|
|
|
|
/* The main vbox */
|
|
naviD->vbox = gtk_event_box_new ();
|
|
|
|
vbox = gtk_vbox_new (FALSE, 1);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
|
|
gtk_container_add (GTK_CONTAINER (naviD->vbox), vbox);
|
|
|
|
/* The image menu */
|
|
util_box = gtk_hbox_new (FALSE, 1);
|
|
gtk_box_pack_start (GTK_BOX (vbox), util_box, FALSE, FALSE, 0);
|
|
|
|
/* The popup menu (copy/cut/paste) */
|
|
naviD->ops_menu = gtk_menu_new ();
|
|
|
|
/* menu_item copy */
|
|
menu_item = gtk_menu_item_new_with_label (_("Copy"));
|
|
gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
|
|
(GtkSignalFunc) edit_copy_callback,
|
|
naviD);
|
|
gtk_widget_show (menu_item);
|
|
naviD->copy_menu_item = menu_item;
|
|
|
|
/* menu_item cut */
|
|
menu_item = gtk_menu_item_new_with_label (_("Cut"));
|
|
gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
|
|
(GtkSignalFunc) edit_cut_callback,
|
|
naviD);
|
|
gtk_widget_show (menu_item);
|
|
naviD->cut_menu_item = menu_item;
|
|
|
|
/* menu_item paste before */
|
|
menu_item = gtk_menu_item_new_with_label (_("Paste before"));
|
|
gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
|
|
(GtkSignalFunc) edit_pasteb_callback,
|
|
naviD);
|
|
gtk_widget_show (menu_item);
|
|
naviD->pasteb_menu_item = menu_item;
|
|
|
|
/* menu_item copy */
|
|
menu_item = gtk_menu_item_new_with_label (_("Paste after"));
|
|
gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
|
|
(GtkSignalFunc) edit_pastea_callback,
|
|
naviD);
|
|
gtk_widget_show (menu_item);
|
|
naviD->pastea_menu_item = menu_item;
|
|
|
|
/* menu_item copy */
|
|
menu_item = gtk_menu_item_new_with_label (_("Paste replace"));
|
|
gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
|
|
(GtkSignalFunc) edit_paster_callback,
|
|
naviD);
|
|
gtk_widget_show (menu_item);
|
|
naviD->paster_menu_item = menu_item;
|
|
|
|
/* menu_item copy */
|
|
menu_item = gtk_menu_item_new_with_label (_("Clear Video Buffer"));
|
|
gtk_container_add (GTK_CONTAINER (naviD->ops_menu), menu_item);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
|
|
(GtkSignalFunc) edit_clrpaste_callback,
|
|
naviD);
|
|
gtk_widget_show (menu_item);
|
|
naviD->clrpaste_menu_item = menu_item;
|
|
|
|
gtk_widget_show (naviD->ops_menu);
|
|
|
|
|
|
/* The image menu */
|
|
naviD->image_option_menu = gtk_option_menu_new();
|
|
naviD->image_menu = NULL;
|
|
navi_refresh_image_menu();
|
|
gtk_box_pack_start (GTK_BOX (util_box), naviD->image_option_menu, FALSE, FALSE, 0);
|
|
gtk_widget_show (naviD->image_option_menu);
|
|
gtk_widget_show (naviD->image_menu);
|
|
gtk_widget_show (util_box);
|
|
|
|
/* the Framerange label */
|
|
util_box = gtk_hbox_new (FALSE, 1);
|
|
gtk_box_pack_start (GTK_BOX (vbox), util_box, FALSE, FALSE, 0);
|
|
|
|
label = gtk_label_new (_("Videoframes:"));
|
|
gtk_box_pack_start (GTK_BOX (util_box), label, FALSE, FALSE, 2);
|
|
gtk_widget_show (label);
|
|
|
|
/* the max frame number label */
|
|
naviD->framerange_number_label = gtk_label_new (frame_nr_to_char);
|
|
gtk_box_pack_start (GTK_BOX (util_box), naviD->framerange_number_label, FALSE, FALSE, 2);
|
|
gtk_widget_show (naviD->framerange_number_label);
|
|
gtk_widget_show (util_box);
|
|
|
|
|
|
/* framerate scale */
|
|
naviD->framerate_box = util_box = gtk_hbox_new (FALSE, 1);
|
|
gtk_box_pack_start (GTK_BOX (vbox), util_box, FALSE, FALSE, 0);
|
|
|
|
label = gtk_label_new (_("Framerate:"));
|
|
gtk_box_pack_start (GTK_BOX (util_box), label, FALSE, FALSE, 2);
|
|
gtk_widget_show (label);
|
|
|
|
naviD->framerate_data =
|
|
GTK_ADJUSTMENT (gtk_adjustment_new (naviD->vin_ptr->framerate, 1.0, 100.0, 1.0, 1.0, 0.0));
|
|
slider = gtk_hscale_new (naviD->framerate_data);
|
|
gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED); /* GTK_UPDATE_CONTINUOUS */
|
|
gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_RIGHT);
|
|
gtk_box_pack_start (GTK_BOX (util_box), slider, TRUE, TRUE, 0);
|
|
gtk_signal_connect (GTK_OBJECT (naviD->framerate_data), "value_changed",
|
|
(GtkSignalFunc) navi_framerate_scale_update,
|
|
naviD);
|
|
gtk_widget_show (slider);
|
|
|
|
gimp_help_set_help_data (slider, NULL, "#framerate_scale");
|
|
|
|
gtk_widget_show (util_box);
|
|
|
|
/* timezoom scale */
|
|
naviD->timezoom_box = util_box = gtk_hbox_new (FALSE, 1);
|
|
gtk_box_pack_start (GTK_BOX (vbox), util_box, FALSE, FALSE, 0);
|
|
|
|
label = gtk_label_new (_("Timezoom:"));
|
|
gtk_box_pack_start (GTK_BOX (util_box), label, FALSE, FALSE, 2);
|
|
gtk_widget_show (label);
|
|
|
|
naviD->timezoom_data =
|
|
GTK_ADJUSTMENT (gtk_adjustment_new ((gdouble)naviD->vin_ptr->timezoom, 1.0, 100.0, 1.0, 1.0, 0.0));
|
|
slider = gtk_hscale_new (naviD->timezoom_data);
|
|
gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
|
|
gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_RIGHT);
|
|
gtk_box_pack_start (GTK_BOX (util_box), slider, TRUE, TRUE, 0);
|
|
gtk_signal_connect (GTK_OBJECT (naviD->timezoom_data), "value_changed",
|
|
(GtkSignalFunc) navi_timezoom_scale_update,
|
|
naviD);
|
|
gtk_widget_show (slider);
|
|
|
|
gimp_help_set_help_data (slider, NULL, "#timezoom_scale");
|
|
|
|
gtk_widget_show (util_box);
|
|
|
|
/* The frames listbox */
|
|
naviD->scrolled_win = gtk_scrolled_window_new (NULL, NULL);
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (naviD->scrolled_win),
|
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
|
|
gtk_widget_set_usize (naviD->scrolled_win, LIST_WIDTH, LIST_HEIGHT);
|
|
gtk_box_pack_start (GTK_BOX (vbox), naviD->scrolled_win, TRUE, TRUE, 2);
|
|
|
|
naviD->frame_list = gtk_list_new ();
|
|
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (naviD->scrolled_win),
|
|
naviD->frame_list);
|
|
gtk_list_set_selection_mode (GTK_LIST (naviD->frame_list),
|
|
GTK_SELECTION_EXTENDED); /* GTK_SELECTION_BROWSE */
|
|
gtk_signal_connect (GTK_OBJECT (naviD->frame_list), "event",
|
|
(GtkSignalFunc) frame_list_events,
|
|
naviD);
|
|
gtk_container_set_focus_vadjustment (GTK_CONTAINER (naviD->frame_list),
|
|
gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (naviD->scrolled_win)));
|
|
GTK_WIDGET_UNSET_FLAGS (GTK_SCROLLED_WINDOW (naviD->scrolled_win)->vscrollbar,
|
|
GTK_CAN_FOCUS);
|
|
|
|
gtk_widget_show (naviD->frame_list);
|
|
gtk_widget_show (naviD->scrolled_win);
|
|
|
|
/* The ops buttons */
|
|
button_box = ops_button_box_new (naviD->shell,
|
|
frames_ops_buttons, OPS_BUTTON_NORMAL);
|
|
gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 2);
|
|
gtk_widget_show (button_box);
|
|
|
|
|
|
/* The VCR ops buttons */
|
|
button_box = ops_button_box_new (naviD->shell,
|
|
vcr_ops_buttons, OPS_BUTTON_NORMAL);
|
|
gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 2);
|
|
gtk_widget_show (button_box);
|
|
|
|
gtk_widget_show (vbox);
|
|
gtk_widget_show (naviD->vbox);
|
|
|
|
if(gap_debug) printf("navi_dialog_create END\n");
|
|
|
|
return naviD->vbox;
|
|
}
|
|
|
|
|
|
/* ---------------------------------
|
|
* the navigator MAIN dialog
|
|
* ---------------------------------
|
|
*/
|
|
int gap_navigator(gint32 image_id)
|
|
{
|
|
GtkWidget *shell;
|
|
GtkWidget *button;
|
|
GtkWidget *subshell;
|
|
gint argc = 1;
|
|
guchar *color_cube;
|
|
gchar **argv = g_new (gchar *, 1);
|
|
argv[0] = g_strdup ("gap_navigator");
|
|
|
|
if(gap_debug) fprintf(stderr, "\nSTARTing gap_navigator_dialog\n");
|
|
|
|
/* Init GTK */
|
|
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());
|
|
|
|
/* The main shell */
|
|
shell = gimp_dialog_new (_("Video Navigator"), "gap_navigator",
|
|
gimp_standard_help_func, "filters/gap_navigator_dialog.html",
|
|
GTK_WIN_POS_NONE,
|
|
FALSE, TRUE, FALSE,
|
|
NULL);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (shell), "delete_event",
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
|
NULL);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (shell), "destroy",
|
|
GTK_SIGNAL_FUNC (gtk_main_quit),
|
|
NULL);
|
|
|
|
/* The subshell (toplevel vbox) */
|
|
subshell = gtk_vbox_new (FALSE, 1);
|
|
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (shell)->vbox), subshell);
|
|
|
|
if(gap_debug) printf("BEFORE navi_dialog_create\n");
|
|
|
|
/* The naviD dialog structure */
|
|
navi_dialog_create (shell, image_id);
|
|
if(gap_debug) printf("AFTER navi_dialog_create\n");
|
|
|
|
gtk_box_pack_start (GTK_BOX (subshell), naviD->vbox, TRUE, TRUE, 0);
|
|
|
|
/* The action area */
|
|
gtk_container_set_border_width
|
|
(GTK_CONTAINER (GTK_DIALOG (shell)->action_area), 1);
|
|
|
|
/* The close button */
|
|
button = gtk_button_new_with_label (_("Close"));
|
|
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
|
GTK_OBJECT (shell));
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (shell)->action_area),
|
|
button, TRUE, TRUE, 0);
|
|
gtk_widget_show (button);
|
|
|
|
gtk_widget_show (subshell);
|
|
gtk_widget_show (shell);
|
|
|
|
frames_dialog_flush();
|
|
navi_scroll_to_current_frame_nr();
|
|
|
|
naviD->timer = gtk_timeout_add(naviD->cycle_time,
|
|
(GtkFunction)navi_dialog_poll, NULL);
|
|
|
|
|
|
if(gap_debug) printf("BEFORE gtk_main\n");
|
|
gtk_main ();
|
|
gdk_flush ();
|
|
|
|
if(gap_debug) printf("END gap_navigator_dialog\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
* Some Code Parts copied from gimp/app directory
|
|
* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
*/
|
|
|
|
|
|
/* --------------------------------------- start copy of gimp-1.1.14/app/fileops.c readXVThumb */
|
|
/* The readXVThumb function source may be re-used under
|
|
the XFree86-style license. <adam@gimp.org> */
|
|
guchar*
|
|
readXVThumb (const gchar *fnam,
|
|
gint *w,
|
|
gint *h,
|
|
gchar **imginfo /* caller frees if != NULL */)
|
|
{
|
|
FILE *fp;
|
|
const gchar *P7_332 = "P7 332";
|
|
gchar P7_buf[7];
|
|
gchar linebuf[200];
|
|
guchar *buf;
|
|
gint twofivefive;
|
|
void *ptr;
|
|
|
|
*w = *h = 0;
|
|
*imginfo = NULL;
|
|
|
|
fp = fopen (fnam, "rb");
|
|
if (!fp)
|
|
return (NULL);
|
|
|
|
fread (P7_buf, 6, 1, fp);
|
|
|
|
if (strncmp(P7_buf, P7_332, 6)!=0)
|
|
{
|
|
g_warning("Thumbnail doesn't have the 'P7 332' header.");
|
|
fclose(fp);
|
|
return(NULL);
|
|
}
|
|
|
|
/*newline*/
|
|
fread (P7_buf, 1, 1, fp);
|
|
|
|
do
|
|
{
|
|
ptr = fgets(linebuf, 199, fp);
|
|
if ((strncmp(linebuf, "#IMGINFO:", 9) == 0) &&
|
|
(linebuf[9] != '\0') &&
|
|
(linebuf[9] != '\n'))
|
|
{
|
|
if (linebuf[strlen(linebuf)-1] == '\n')
|
|
linebuf[strlen(linebuf)-1] = '\0';
|
|
|
|
if (linebuf[9] != '\0')
|
|
{
|
|
if (*imginfo)
|
|
g_free(*imginfo);
|
|
*imginfo = g_strdup (&linebuf[9]);
|
|
}
|
|
}
|
|
}
|
|
while (ptr && linebuf[0]=='#'); /* keep throwing away comment lines */
|
|
|
|
if (!ptr)
|
|
{
|
|
/* g_warning("Thumbnail ended - not an image?"); */
|
|
fclose(fp);
|
|
return(NULL);
|
|
}
|
|
|
|
sscanf(linebuf, "%d %d %d\n", w, h, &twofivefive);
|
|
|
|
if (twofivefive!=255)
|
|
{
|
|
g_warning("Thumbnail is of funky depth.");
|
|
fclose(fp);
|
|
return(NULL);
|
|
}
|
|
|
|
if ((*w)<1 || (*h)<1 || (*w)>80 || (*h)>60)
|
|
{
|
|
g_warning ("Thumbnail size bad. Corrupted?");
|
|
fclose(fp);
|
|
return (NULL);
|
|
}
|
|
|
|
buf = g_malloc((*w)*(*h));
|
|
|
|
fread(buf, (*w)*(*h), 1, fp);
|
|
|
|
fclose(fp);
|
|
|
|
return(buf);
|
|
}
|
|
/* --------------------------------------- end copy of gimp-1.1.14/app/fileops.c readXVThumb */
|
|
|
|
|
|
/* --------------------------------------- start copy of gimp-1.1.14/app/ops_buttons.c */
|
|
static void ops_button_pressed_callback (GtkWidget*, GdkEventButton*, gpointer);
|
|
static void ops_button_extended_callback (GtkWidget*, gpointer);
|
|
|
|
|
|
GtkWidget *
|
|
ops_button_box_new (GtkWidget *parent,
|
|
OpsButton *ops_button,
|
|
OpsButtonType ops_type)
|
|
{
|
|
GtkWidget *button;
|
|
GtkWidget *button_box;
|
|
GtkWidget *pixmap_widget;
|
|
GdkPixmap *pixmap;
|
|
GdkBitmap *mask;
|
|
GtkStyle *style;
|
|
GSList *group = NULL;
|
|
|
|
gtk_widget_realize (parent);
|
|
style = gtk_widget_get_style (parent);
|
|
|
|
button_box = gtk_hbox_new (TRUE, 1);
|
|
|
|
while (ops_button->xpm_data)
|
|
{
|
|
pixmap = gdk_pixmap_create_from_xpm_d (parent->window,
|
|
&mask,
|
|
&style->bg[GTK_STATE_NORMAL],
|
|
ops_button->xpm_data);
|
|
pixmap_widget = gtk_pixmap_new (pixmap, mask);
|
|
|
|
switch (ops_type)
|
|
{
|
|
case OPS_BUTTON_NORMAL :
|
|
button = gtk_button_new ();
|
|
break;
|
|
case OPS_BUTTON_RADIO :
|
|
button = gtk_radio_button_new (group);
|
|
group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
|
|
gtk_container_set_border_width (GTK_CONTAINER (button), 0);
|
|
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);
|
|
break;
|
|
default :
|
|
button = NULL; /*stop compiler complaints */
|
|
g_error ("ops_button_box_new: unknown type %d\n", ops_type);
|
|
break;
|
|
}
|
|
|
|
gtk_container_add (GTK_CONTAINER (button), pixmap_widget);
|
|
|
|
if (ops_button->ext_callbacks == NULL)
|
|
{
|
|
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
|
|
(GtkSignalFunc) ops_button->callback,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
gtk_signal_connect (GTK_OBJECT (button), "button_press_event",
|
|
(GtkSignalFunc) ops_button_pressed_callback,
|
|
ops_button);
|
|
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
(GtkSignalFunc) ops_button_extended_callback,
|
|
ops_button);
|
|
}
|
|
|
|
gimp_help_set_help_data (button,
|
|
gettext (ops_button->tooltip),
|
|
ops_button->private_tip);
|
|
|
|
gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_show (pixmap_widget);
|
|
gtk_widget_show (button);
|
|
|
|
ops_button->widget = button;
|
|
ops_button->modifier = OPS_BUTTON_MODIFIER_NONE;
|
|
|
|
ops_button++;
|
|
}
|
|
|
|
return (button_box);
|
|
}
|
|
|
|
static void
|
|
ops_button_pressed_callback (GtkWidget *widget,
|
|
GdkEventButton *bevent,
|
|
gpointer client_data)
|
|
{
|
|
OpsButton *ops_button;
|
|
|
|
g_return_if_fail (client_data != NULL);
|
|
ops_button = (OpsButton*)client_data;
|
|
|
|
if (bevent->state & GDK_SHIFT_MASK)
|
|
{
|
|
if (bevent->state & GDK_CONTROL_MASK)
|
|
ops_button->modifier = OPS_BUTTON_MODIFIER_SHIFT_CTRL;
|
|
else
|
|
ops_button->modifier = OPS_BUTTON_MODIFIER_SHIFT;
|
|
}
|
|
else if (bevent->state & GDK_CONTROL_MASK)
|
|
ops_button->modifier = OPS_BUTTON_MODIFIER_CTRL;
|
|
else if (bevent->state & GDK_MOD1_MASK)
|
|
ops_button->modifier = OPS_BUTTON_MODIFIER_ALT;
|
|
else
|
|
ops_button->modifier = OPS_BUTTON_MODIFIER_NONE;
|
|
}
|
|
|
|
static void
|
|
ops_button_extended_callback (GtkWidget *widget,
|
|
gpointer client_data)
|
|
{
|
|
OpsButton *ops_button;
|
|
|
|
g_return_if_fail (client_data != NULL);
|
|
ops_button = (OpsButton*)client_data;
|
|
|
|
if (ops_button->modifier > OPS_BUTTON_MODIFIER_NONE &&
|
|
ops_button->modifier < OPS_BUTTON_MODIFIER_LAST)
|
|
{
|
|
if (ops_button->ext_callbacks[ops_button->modifier - 1] != NULL)
|
|
(ops_button->ext_callbacks[ops_button->modifier - 1]) (widget, NULL);
|
|
else
|
|
(ops_button->callback) (widget, NULL);
|
|
}
|
|
else
|
|
(ops_button->callback) (widget, NULL);
|
|
|
|
ops_button->modifier = OPS_BUTTON_MODIFIER_NONE;
|
|
}
|
|
/* --------------------------------------- end copy of gimp-1.1.14/app/ops_buttons.c */
|