Files
veejay/veejay-current/gveejay-reloaded/widgets/gtktimeselection.c
Niels Elburg dceb686de2 synchronized veejay current
git-svn-id: svn://code.dyne.org/veejay/trunk@740 eb8d1916-c9e9-0310-b8de-cf0c9472ead5
2007-01-29 16:14:38 +00:00

854 lines
23 KiB
C

/* veejay - Linux VeeJay
* (C) 2002-2004 Niels Elburg <nelburg@looze.net>
*
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
Implements a new slider type widget with selection markers
*/
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <gtkcairo.h>
#include <gtk/gtk.h>
#include "gtktimeselection.h"
enum
{
POS_CHANGED,
IN_CHANGED,
OUT_CHANGED,
BIND_CHANGED,
CLEAR_CHANGED,
SELECTION_CHANGED_SIGNAL,
LAST_SIGNAL
};
enum
{
MIN = 1,
MAX = 2,
POS = 3,
LENGTH = 4,
IN_POINT = 5,
OUT_POINT = 6,
SEL = 7,
BIND = 8,
CLEARED = 9,
};
typedef enum {
MOUSE_OUTSIDE,
MOUSE_STEPPER,
MOUSE_SELECTION,
MOUSE_WIDGET /* inside widget but not in any of the above */
} mouse_location;
/* Slider with 2 bars
*/
typedef enum TimelineAction
{
action_none = 0,
action_in_point,
action_out_point,
action_pos,
action_atomic,
} TimelineAction;
#define POINT_IN_RECT(xcoord, ycoord, rect) \
((xcoord) >= (rect).x && \
(xcoord) < ((rect).x + (rect).width) && \
(ycoord) >= (rect).y && \
(ycoord) < ((rect).y + (rect).height))
struct _TimelineSelection
{
GtkCairo cr;
GtkWidget *widget;
gdouble min;
gdouble max;
gdouble value;
gdouble frame_num;
gdouble num_video_frames;
gdouble in;
gdouble out;
gboolean bind;
gint grab_button;
TimelineAction action;
mouse_location grab_location;
mouse_location current_location;
GdkRectangle stepper;
GdkRectangle selection;
gboolean has_stepper;
gboolean clear;
gdouble stepper_size; /* size of triangle */
gdouble stepper_draw_size;
gdouble stepper_length; /* length from top to bottom */
gint step_size; /* step frames 1,2,4,8,16, ... */
gdouble frame_width;
gdouble frame_height;
gdouble font_line;
gboolean has_selection; /* use in/out points for selection */
gdouble move_x;
};
static void get_property( GObject *object,
guint id, GValue *value , GParamSpec *pspec );
static void set_property (GObject *object,
guint id, GValue * value, GParamSpec *pspec);
static gboolean event_press (GtkWidget *widget, GdkEventButton *bev, gpointer user_data);
static gboolean event_release (GtkWidget *widget, GdkEventButton *bev, gpointer user_data);
static gboolean event_motion (GtkWidget *widget, GdkEventMotion *mev, gpointer user_data);
static void timeline_class_init( TimelineSelectionClass *class );
static void timeline_init(TimelineSelection *te );
static void paint(GtkWidget *widget, cairo_t *cr, gpointer user_data);
static GObjectClass *parent_class = NULL;
static GtkActionGroup *action_group = NULL;
static gint timeline_signals[LAST_SIGNAL] = { 0 };
struct _TimelineSelectionClass
{
GtkCairoClass parent_class;
void (*pos_changed) (TimelineSelection *te);
void (*in_point_changed) (TimelineSelection *te);
void (*out_point_changed) (TimelineSelection *te);
void (*bind_toggled) (TimelineSelection *te);
void (*cleared) (TimelineSelection *te);
};
static void set_property (GObject *object,
guint id, GValue *value, GParamSpec *pspec)
{
TimelineSelection *te = TIMELINE_SELECTION(object);
switch(id)
{
case MIN:
if(te->min != g_value_get_double(value))
{
te->min = g_value_get_double(value);
}
break;
case MAX:
if(te->max != g_value_get_double(value))
{
te->min = g_value_get_double(value);
}
break;
case POS:
if(te->frame_num != g_value_get_double(value))
{
te->frame_num = g_value_get_double(value);
}
break;
case LENGTH:
if(te->num_video_frames != g_value_get_double(value))
{
te->num_video_frames = g_value_get_double(value);
}
break;
case IN_POINT:
if(te->in != g_value_get_double(value))
{
te->in = g_value_get_double(value);
}
break;
case OUT_POINT:
if(te->out != g_value_get_double(value))
{
te->out = g_value_get_double(value);
}
break;
case SEL:
if(te->has_selection != g_value_get_boolean(value))
{
te->has_selection = g_value_get_boolean(value);
}
break;
case BIND:
if(te->bind != g_value_get_boolean(value))
{
te->bind = g_value_get_boolean(value);
}
break;
case CLEARED:
if(te->clear != g_value_get_boolean(value))
{
te->clear = g_value_get_boolean(value);
}
break;
default:
g_assert(FALSE);
break;
}
gtk_widget_queue_draw( GTK_WIDGET( te ));
}
static void get_property( GObject *object,
guint id, GValue *value , GParamSpec *pspec )
{
TimelineSelection *te = TIMELINE_SELECTION(object);
switch( id )
{
case MIN: g_value_set_double( value, te->min );break;
case MAX: g_value_set_double( value, te->max );break;
case POS: g_value_set_double( value, te->frame_num ); break;
case LENGTH: g_value_set_double( value, te->num_video_frames ); break;
case IN_POINT: g_value_set_double( value, te->in ); break;
case OUT_POINT: g_value_set_double( value, te->out ); break;
case SEL: g_value_set_boolean(value, te->has_selection) ; break;
case BIND: g_value_set_boolean(value, te->bind ); break;
case CLEARED: g_value_set_boolean(value,te->clear );break;
}
}
static void finalize (GObject *object)
{
parent_class->finalize( object );
}
static void timeline_class_init( TimelineSelectionClass *class )
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS( class );
parent_class = g_type_class_peek( GTK_TYPE_CAIRO );
gobject_class->finalize = finalize;
gobject_class->get_property = get_property;
gobject_class->set_property = set_property;
g_object_class_install_property( gobject_class,
MIN,
g_param_spec_double( "min",
"left", "left", 0.0, 1.0, 0.0, G_PARAM_READWRITE ));
g_object_class_install_property( gobject_class,
MAX,
g_param_spec_double( "max",
"right", "right", 0.0, 1.0, 1.0, G_PARAM_READWRITE ));
g_object_class_install_property( gobject_class,
POS,
g_param_spec_double( "pos",
"current position", "current position", 0.0,9999999.0, 0.0,
G_PARAM_READWRITE ));
g_object_class_install_property( gobject_class,
LENGTH,
g_param_spec_double( "length",
"Length (in frames)", "Length (in frames) ",0.0,9999999.0, 1.0,
G_PARAM_READWRITE ));
g_object_class_install_property( gobject_class,
IN_POINT,
g_param_spec_double( "in",
"In point", "(in frames) ",0.0,1.0, 0.0,
G_PARAM_READWRITE ));
g_object_class_install_property( gobject_class,
OUT_POINT,
g_param_spec_double( "out",
"Out point", "(in frames) ",0.0,1.0, 1.0,
G_PARAM_READWRITE ));
g_object_class_install_property( gobject_class,
SEL,
g_param_spec_boolean( "selection",
"Marker", "(in frames) ",FALSE,
G_PARAM_READWRITE ));
g_object_class_install_property( gobject_class,
BIND,
g_param_spec_boolean( "bind", "Bind marker", "Bind In/Out points", FALSE, G_PARAM_READWRITE));
g_object_class_install_property( gobject_class,
CLEARED,
g_param_spec_boolean( "clear", "Clear marker", "Clear in/out points", FALSE, G_PARAM_READWRITE ));
timeline_signals[ SELECTION_CHANGED_SIGNAL ] =
g_signal_new( "selection_changed",
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_FIRST,0,NULL,NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 , NULL );
timeline_signals[ POS_CHANGED ] =
g_signal_new( "pos_changed",
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET( TimelineSelectionClass, pos_changed ),
NULL,NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0, NULL);
timeline_signals[ IN_CHANGED ] =
g_signal_new( "in_point_changed",
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET( TimelineSelectionClass, in_point_changed ),
NULL,NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0, NULL);
timeline_signals[ OUT_CHANGED ] =
g_signal_new( "out_point_changed",
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET( TimelineSelectionClass, out_point_changed ),
NULL,NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0, NULL);
timeline_signals[ CLEAR_CHANGED ] =
g_signal_new( "cleared", G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET( TimelineSelectionClass, cleared ),
NULL,NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0, NULL );
timeline_signals[ BIND_CHANGED ] =
g_signal_new( "bind_toggled",
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET( TimelineSelectionClass, bind_toggled ),
NULL,NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0, NULL );
}
static int default_theme_ = 1;
void timeline_theme_colors( int inverse )
{
default_theme_ = inverse;
}
static void timeline_init( TimelineSelection *te )
{
te->min = 0.0;
te->max = 0.0;
te->action = action_none;
te->in = 0.0;
te->out = 1.0;
te->num_video_frames = 1.0;
te->frame_num = 0.0;
te->grab_location = MOUSE_OUTSIDE;
te->current_location = MOUSE_OUTSIDE;
te->grab_button = 0;
te->has_stepper = TRUE;
te->has_selection = FALSE;
te->stepper_size = 16; // 8 x 8 pixels
te->stepper_draw_size = 12;
te->stepper_length = 0;
te->frame_height = 10;
te->font_line = 12;
te->move_x = 0;
}
GType timeline_get_type(void)
{
static GType gtype = 0;
if(!gtype)
{
static const GTypeInfo ginfo = {
sizeof( TimelineSelectionClass),
NULL,
NULL,
(GClassInitFunc) timeline_class_init,
NULL,
NULL,
sizeof(TimelineSelection),
0,
(GInstanceInitFunc) timeline_init,
NULL
};
gtype = g_type_register_static( GTK_TYPE_CAIRO, "Timeline", &ginfo, 0 );
}
return gtype;
}
gdouble timeline_get_in_point( TimelineSelection *te )
{
gdouble result = 0.0;
g_object_get( G_OBJECT(te), "in", &result, NULL );
return result;
}
gdouble timeline_get_out_point( TimelineSelection *te )
{
gdouble result = 0.0;
g_object_get( G_OBJECT(te), "out", &result, NULL );
return result;
}
gboolean timeline_get_selection( TimelineSelection *te )
{
gboolean result = FALSE;
g_object_get( G_OBJECT(te), "selection", &result, NULL );
return result;
}
gboolean timeline_get_bind( TimelineSelection *te )
{
gboolean result = FALSE;
g_object_get( G_OBJECT(te), "bind", &result, NULL );
return result;
}
void timeline_set_bind(GtkWidget *widget, gboolean active)
{
TimelineSelection *te = TIMELINE_SELECTION(widget);
g_object_set( G_OBJECT(te), "bind", active, NULL );
g_signal_emit( te->widget, timeline_signals[BIND_CHANGED], 0);
}
void timeline_set_out_point( GtkWidget *widget, gdouble pos )
{
TimelineSelection *te = TIMELINE_SELECTION(widget);
g_object_set( G_OBJECT(te), "out", pos, NULL );
g_signal_emit(te->widget, timeline_signals[OUT_CHANGED], 0);
gtk_widget_queue_draw( GTK_WIDGET(te->widget) );
}
void timeline_clear_points( GtkWidget *widget )
{
gboolean cleared = TRUE;
gdouble pos = 0.0;
gdouble pos2 = 1.0;
TimelineSelection *te = TIMELINE_SELECTION(widget);
g_object_set( G_OBJECT(te), "clear", cleared, NULL );
g_object_set( G_OBJECT(te), "in", pos, NULL );
g_object_set( G_OBJECT(te), "out", pos2, NULL );
g_signal_emit(te->widget, timeline_signals[CLEAR_CHANGED], 0 );
gtk_widget_queue_draw(GTK_WIDGET(te->widget) );
}
void timeline_set_in_point( GtkWidget *widget, gdouble pos )
{
TimelineSelection *te = TIMELINE_SELECTION(widget);
g_object_set( G_OBJECT(te), "in", pos, NULL );
g_signal_emit(te->widget, timeline_signals[IN_CHANGED], 0);
gtk_widget_queue_draw( GTK_WIDGET(te->widget) );
}
void timeline_set_selection( GtkWidget *widget, gboolean active)
{
TimelineSelection *te = TIMELINE_SELECTION(widget);
g_object_set( G_OBJECT(te), "selection", active, NULL );
gtk_widget_queue_draw( GTK_WIDGET(te->widget) );
}
void timeline_set_length( GtkWidget *widget, gdouble length, gdouble pos)
{
TimelineSelection *te = TIMELINE_SELECTION( widget );
g_object_set( G_OBJECT(te), "length", length, NULL );
timeline_set_pos( GTK_WIDGET(te->widget), pos );
}
void timeline_set_pos( GtkWidget *widget,gdouble pos)
{
TimelineSelection *te = TIMELINE_SELECTION( widget );
g_object_set( G_OBJECT(te), "pos", pos, NULL );
g_signal_emit( te->widget, timeline_signals[POS_CHANGED], 0);
gtk_widget_queue_draw( GTK_WIDGET(te->widget) );
}
gdouble timeline_get_pos( TimelineSelection *te )
{
gdouble result = 0.0;
g_object_get( G_OBJECT(te), "pos", &result, NULL );
return result;
}
gdouble timeline_get_length( TimelineSelection *te )
{
gdouble result = 0.0;
g_object_get( G_OBJECT(te), "length", &result, NULL );
return result;
}
static void move_selection( GtkWidget *widget, gdouble x, gdouble width )
{
TimelineSelection *te = TIMELINE_SELECTION( widget );
gdouble dx3 = (0.5 * (te->out - te->in)) * width;
gdouble dx1 = x - dx3;
gdouble dx2 = x + dx3;
te->in = (1.0/width) * dx1;
te->out = (1.0/width ) * dx2;
if(te->in < 0.0 ) te->in = 0.0; else if (te->in > 1.0) te->in = 1.0;
if(te->out < 0.0 ) te->out = 0.0; else if (te->out > 1.0) te->out = 1.0;
timeline_set_out_point(widget, te->out );
timeline_set_in_point(widget, te->in );
te->move_x = x;
}
static gboolean event_press(GtkWidget *widget, GdkEventButton *ev, gpointer user_data)
{
TimelineSelection *te = TIMELINE_SELECTION( widget );
gdouble width = widget->allocation.width;
te->grab_button = ev->button;
te->current_location = MOUSE_WIDGET;
if( ev->type == GDK_2BUTTON_PRESS && te->grab_button == 1 )
{
timeline_clear_points( widget );
return FALSE;
}
if(te->grab_button == 1 && POINT_IN_RECT( ev->x, ev->y, te->stepper ) )
{
if(te->has_stepper)
{
te->current_location = MOUSE_STEPPER;
te->action = action_pos;
}
return FALSE;
}
if(te->grab_button == 1 && te->has_selection)
{
if( POINT_IN_RECT( ev->x, ev->y, te->selection ) && te->bind )
{
te->current_location = MOUSE_SELECTION;
}
if(!te->bind)
{
gdouble val = (1.0 / width) * ev->x;
timeline_set_in_point( widget, val );
}
}
else if(te->grab_button == 3 && te->has_selection )
{
if( POINT_IN_RECT( ev->x, ev->y, te->selection ) && te->bind )
{
te->current_location = MOUSE_SELECTION;
}
if(!te->bind)
{
gdouble val = (1.0/width) * ev->x;
timeline_set_out_point( widget, val );
}
}
else if(te->grab_button == 2 && te->has_selection)
{
gint dx = ev->x;
gint dy = ev->y;
if( POINT_IN_RECT( dx, dy, te->selection ) )
{
timeline_set_bind( widget, (te->bind ? FALSE: TRUE ));
te->move_x = (gdouble) ev->x;
}
}
gtk_widget_queue_draw( widget );
return FALSE;
}
static gboolean event_release (GtkWidget *widget, GdkEventButton *ev, gpointer user_data)
{
TimelineSelection *te = TIMELINE_SELECTION (widget);
te->action = action_none;
te->current_location = MOUSE_WIDGET;
// te->grab_button = 0;
// te->move_x = 0;
return FALSE;
}
static gboolean
event_motion (GtkWidget *widget, GdkEventMotion *ev, gpointer user_data)
{
TimelineSelection *te = TIMELINE_SELECTION (widget);
gdouble width = (gdouble) widget->allocation.width;
gint x,y;
GdkModifierType state;
gdk_window_get_pointer( ev->window, &x,&y,&state );
if( te->has_stepper && te->current_location == MOUSE_STEPPER && ev->state & GDK_BUTTON1_MASK)
{
gdouble rel_pos = ((gdouble)ev->x / width) * te->num_video_frames;
gdouble new_pos = (gdouble) ((gint) rel_pos );
timeline_set_pos( widget, new_pos );
return FALSE;
}
if( te->has_selection && te->current_location != MOUSE_STEPPER)
{
if(!te->bind)
{
gdouble gx = (1.0 / width) * x;
if(te->grab_button == 1 && ev->state & GDK_BUTTON1_MASK)
timeline_set_in_point(widget, gx );
else if(te->grab_button == 3 && ev->state & GDK_BUTTON3_MASK)
timeline_set_out_point( widget, gx );
}
}
if(te->has_selection && te->bind && te->grab_button == 2 )
move_selection( widget, x, width );
gtk_widget_queue_draw( widget );
return FALSE;
}
/* draw a rounded rectangle */
void
cairo_rectangle_round (cairo_t * cr,
double x0,
double y0, double width, double height, double radius)
{
double x1, y1;
x1 = x0 + width;
y1 = y0 + height;
if (width <= 0.001 || height <= 0.001)
return;
if (width / 2 < radius)
{
if (height / 2 < radius)
{
cairo_move_to (cr, x0, (y0 + y1) / 2);
cairo_curve_to (cr, x0, y0, x0, y0, (x0 + x1) / 2, y0);
cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
}
else
{
cairo_move_to (cr, x0, y0 + radius);
cairo_curve_to (cr, x0, y0, x0, y0, (x0 + x1) / 2, y0);
cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
cairo_line_to (cr, x1, y1 - radius);
cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
}
}
else
{
if (height / 2 < radius)
{
cairo_move_to (cr, x0, (y0 + y1) / 2);
cairo_curve_to (cr, x0, y0, x0, y0, x0 + radius, y0);
cairo_line_to (cr, x1 - radius, y0);
cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
cairo_line_to (cr, x0 + radius, y1);
cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
}
else
{
cairo_move_to (cr, x0, y0 + radius);
cairo_curve_to (cr, x0, y0, x0, y0, x0 + radius, y0);
cairo_line_to (cr, x1 - radius, y0);
cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
cairo_line_to (cr, x1, y1 - radius);
cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
cairo_line_to (cr, x0 + radius, y1);
cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
}
}
cairo_close_path (cr);
}
static void paint (GtkWidget *widget, cairo_t * cr, gpointer user_data)
{
GtkStyle *style = widget->style;
TimelineSelection *te = TIMELINE_SELECTION( widget );
double width = widget->allocation.width;
double height = widget->allocation.height;
gdouble marker_width = width/ te->num_video_frames;
gdouble frame_width = marker_width * 0.9;
// gdouble marker_height = height / te->num_video_frames;
gdouble marker_height = te->frame_height;
gint i;
te->frame_width = marker_width;
cairo_save(cr);
cairo_identity_matrix(cr);
/* Draw frames*/
/* Drawing many boxes cause CPU hog .. */
/*
cairo_set_source_rgba( cr, 0.0, 0.0, 0.0, 0.2 );
for(i =0; i < te->num_video_frames; i ++ )
{
double x1 = marker_width * i;
double x2 = x1 + frame_width;
cairo_rectangle_round(cr, x1, height - te->stepper_size, frame_width, marker_height, 4);
}
cairo_stroke(cr); */
// cairo_fill(cr);
/* Draw stepper */
if( te->has_stepper )
{
cairo_set_source_rgba( cr, 1.0,0.0,0.0,1.0);
double x1 = marker_width * te->frame_num;
double x2 = x1 + frame_width;
te->stepper.x = x1 - 8;
te->stepper.y = 0;
te->stepper.width = te->stepper_size + 8;
te->stepper.height = te->stepper_size + 2;
// cairo_set_line_width( cr, 0.16 );
cairo_move_to( cr, x1 - te->stepper_draw_size, 0.0 * height );
cairo_rel_line_to( cr, te->stepper_draw_size, te->stepper_draw_size );
cairo_rel_line_to( cr, te->stepper_draw_size, -te->stepper_draw_size );
cairo_rel_line_to( cr, -2.0 * te->stepper_draw_size, 0 );
cairo_set_line_join( cr, CAIRO_LINE_JOIN_MITER);
cairo_move_to(cr, x1, te->stepper_draw_size );
cairo_rel_line_to( cr, 0.0, te->stepper_length );
cairo_stroke(cr);
//cairo_fill_preserve(cr);
if( te->grab_button == 1 && te->current_location == MOUSE_STEPPER )
{
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD );
cairo_move_to(cr, x1 + (te->stepper_size * 0.5),te->font_line );
gchar text[40];
sprintf(text, "%d", (gint)te->frame_num );
cairo_text_path( cr, text );
cairo_set_font_size( cr, 0.2 );
double v = ( default_theme_ ? 1.0 : 0.0 );
cairo_set_source_rgba( cr, v,v,v,0.7 );
cairo_fill(cr);
}
//cairo_fill_preserve(cr);
}
/* Draw selection */
if( te->has_selection )
{
gdouble in = te->in * width;
gdouble out = te->out * width;
gdouble v = (default_theme_ ? 1.0: 0.0);
/* If user is editing in_point */
if( te->grab_button == 1 && te->current_location != MOUSE_STEPPER )
{
gdouble f = te->in * te->num_video_frames;
cairo_set_source_rgba( cr, 0.0, v,v,0.3 );
cairo_move_to( cr, in, 0.0 );
cairo_rel_line_to( cr, 0.0 , te->stepper_length );
cairo_stroke(cr);
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD );
cairo_move_to(cr, in , te->font_line );
gchar text[40];
sprintf(text, "%d",(gint) f );
cairo_text_path( cr, text );
cairo_set_font_size( cr, 0.2 );
cairo_set_source_rgba( cr, v,v,v,0.7 );
cairo_fill(cr);
}
if( te->grab_button == 3 && te->current_location != MOUSE_STEPPER )
{
gdouble f = te->out * te->num_video_frames;
cairo_set_source_rgba( cr, 0.0, v,v,0.3 );
cairo_move_to( cr, out , 0.0 );
cairo_rel_line_to( cr, 0.0 , te->stepper_length );
cairo_stroke(cr);
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD );
cairo_move_to(cr, out ,te->font_line );
gchar text[40];
sprintf(text, "%d", (gint) f );
cairo_text_path( cr, text );
cairo_set_font_size( cr, 0.2 );
cairo_set_source_rgba( cr, v,v,v,0.7 );
cairo_fill(cr);
}
cairo_set_source_rgba( cr, v, v, v, 0.3 );
cairo_rectangle_round(cr, in,
0.095 * height,
(out - in),
marker_height,
10);
te->selection.x = in;
te->selection.y = 0;
te->selection.width = out;
te->selection.height = te->font_line;
cairo_fill_preserve(cr);
}
cairo_restore(cr);
}
GtkWidget *timeline_new(void)
{
GtkWidget *widget = GTK_WIDGET( g_object_new( timeline_get_type(), NULL ));
TimelineSelection *te = TIMELINE_SELECTION( widget );
gtk_widget_set_size_request(widget, 200,16 );
gtk_widget_set_events( widget,
GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_POINTER_MOTION_MASK |
GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON3_MOTION_MASK | GDK_2BUTTON_PRESS );
g_signal_connect( G_OBJECT(widget), "paint", G_CALLBACK(paint), NULL );
g_signal_connect( G_OBJECT(widget), "motion_notify_event",
G_CALLBACK(event_motion), NULL );
g_signal_connect( G_OBJECT(widget), "button_press_event",
G_CALLBACK(event_press), NULL );
g_signal_connect( G_OBJECT(widget), "button_release_event",
G_CALLBACK(event_release), NULL );
te->widget = widget;
return widget;
}