mirror of
https://github.com/game-stop/veejay.git
synced 2025-12-20 06:40:01 +01:00
1401 lines
37 KiB
C
1401 lines
37 KiB
C
/* Gveejay Reloaded - graphical interface for VeeJay
|
|
* (C) 2002-2005 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.
|
|
*/
|
|
|
|
#include <libvjnet/vj-client.h>
|
|
#include <libvjmsg/vj-common.h>
|
|
#include <veejay/vims.h>
|
|
#include <gtk/gtk.h>
|
|
#include <string.h>
|
|
#include <gdk/gdkx.h>
|
|
#include <glib.h>
|
|
#include <gdk/gdk.h>
|
|
#include "sequence.h"
|
|
#include "tracksources.h"
|
|
|
|
#define SEQ_BUTTON_CLOSE 0
|
|
#define SEQ_BUTTON_RULE 1
|
|
#include <assert.h>
|
|
#include <gveejay-reloaded/multitrack.h>
|
|
#include <gveejay-reloaded/common.h>
|
|
#include <gveejay-reloaded/utils.h>
|
|
#include <gveejay-reloaded/widgets/gtktimeselection.h>
|
|
#define WTIME 50000
|
|
#define G_ERRORCHECK_MUTEXES 1
|
|
#define G_DEBUG_LOCKS 1
|
|
|
|
G_LOCK_DEFINE(mt_lock);
|
|
|
|
#define __MAX_TRACKS 64
|
|
typedef struct
|
|
{
|
|
GtkWidget *event_box;
|
|
GtkWidget *frame;
|
|
GtkWidget *main_vbox;
|
|
GtkWidget *panel;
|
|
GtkWidget *hbox;
|
|
GtkWidget *area;
|
|
GtkWidget *sub_frame;
|
|
GtkWidget *sub_hbox;
|
|
GtkWidget *toggle;
|
|
GtkWidget *buttons[8];
|
|
GtkWidget *icons[8];
|
|
GtkWidget *button_box;
|
|
GtkWidget *timeline_;
|
|
GtkWidget *labels_[4];
|
|
GtkWidget *sliders_[4];
|
|
GtkWidget *button_box2;
|
|
GtkWidget *buttons2[8];
|
|
void *tracks;
|
|
gint dim[2];
|
|
} sequence_view_t;
|
|
|
|
typedef struct
|
|
{
|
|
int num;
|
|
sequence_view_t *view;
|
|
void *sequence;
|
|
char *hostname;
|
|
int port_num;
|
|
void *backlink;
|
|
int preview;
|
|
int active;
|
|
int used;
|
|
gint timeout;
|
|
int status_lock;
|
|
int history[4][18];
|
|
int status_cache[18];
|
|
char *tracks[__MAX_TRACKS];
|
|
} mt_priv_t;
|
|
|
|
typedef struct
|
|
{
|
|
mt_priv_t *pt[__MAX_TRACKS+1];
|
|
int stop_mt;
|
|
GThread *thread;
|
|
} all_priv_t;
|
|
|
|
typedef struct
|
|
{
|
|
GtkWidget *main_window;
|
|
GtkWidget *main_box;
|
|
GtkWidget *status_bar;
|
|
GtkWidget *scroll;
|
|
void *data;
|
|
int selected;
|
|
int sensitive;
|
|
int quit;
|
|
} multitracker_t;
|
|
|
|
static void (*img_cb)(GdkPixbuf *p);
|
|
static void (*gui_cb)(int, char*, int);
|
|
static int mt_new_connection_dialog(multitracker_t *mt, char *hostname,int len, int *port_num);
|
|
static void add_buttons( mt_priv_t *p, sequence_view_t *seqv , GtkWidget *w);
|
|
static void add_buttons2( mt_priv_t *p, sequence_view_t *seqv , GtkWidget *w);
|
|
static int num_tracks_active( multitracker_t * mt );
|
|
void *mt_preview( gpointer user_data );
|
|
|
|
static int preview_width_ = 0;
|
|
static int preview_height_ = 0;
|
|
|
|
static volatile int MAX_TRACKS = 4;
|
|
static volatile int LAST_TRACK = 0;
|
|
|
|
void multitrack_preview_master(void *data, int status)
|
|
{
|
|
multitracker_t *mt = (multitracker_t*) data;
|
|
all_priv_t *pt = (all_priv_t*) mt->data;
|
|
mt_priv_t *last = pt->pt[LAST_TRACK];
|
|
if(status == last->preview)
|
|
return;
|
|
G_LOCK(mt_lock);
|
|
last->preview = status;
|
|
G_UNLOCK(mt_lock);
|
|
}
|
|
|
|
static void status_print(multitracker_t *mt, const char format[], ... )
|
|
{
|
|
char buf[1024];
|
|
va_list args;
|
|
bzero(buf,1024);
|
|
va_start(args,format);
|
|
vsnprintf( buf,sizeof(buf), format, args );
|
|
int nr,nw;
|
|
gchar *text = g_locale_to_utf8( buf, -1, &nr, &nw, NULL );
|
|
text[strlen(text)-1] = '\0';
|
|
gtk_statusbar_push( GTK_STATUSBAR(mt->status_bar), 0, text);
|
|
g_free(text);
|
|
va_end(args);
|
|
}
|
|
|
|
void multitrack_sync_start(void *data)
|
|
{
|
|
multitracker_t *mt = (multitracker_t*)data;
|
|
all_priv_t *pt = (all_priv_t*)mt->data;
|
|
gint i;
|
|
G_LOCK(mt_lock);
|
|
for( i = 0;i < MAX_TRACKS; i ++ )
|
|
{
|
|
mt_priv_t *p = pt->pt[i];
|
|
if(p->active)
|
|
{
|
|
veejay_sequence_send( p->sequence,VIMS_VIDEO_PLAY_STOP, NULL,NULL);
|
|
veejay_sequence_send( p->sequence,VIMS_VIDEO_GOTO_START , NULL ,NULL);
|
|
veejay_sequence_send(p->sequence, VIMS_VIDEO_PLAY_FORWARD, NULL ,NULL);
|
|
}
|
|
}
|
|
G_UNLOCK(mt_lock);
|
|
}
|
|
void multitrack_sync_simple_cmd(void *data, int vims_id, int value)
|
|
{
|
|
multitracker_t *mt = (multitracker_t*)data;
|
|
all_priv_t *pt = (all_priv_t*)mt->data;
|
|
gint i;
|
|
G_LOCK(mt_lock);
|
|
for( i = 0;i < MAX_TRACKS; i ++ )
|
|
{
|
|
mt_priv_t *p = pt->pt[i];
|
|
if(p->active)
|
|
veejay_sequence_send( p->sequence, vims_id, (value > 0 ? "%d": NULL),
|
|
(value > 0 ? value :NULL));
|
|
}
|
|
G_UNLOCK(mt_lock);
|
|
}
|
|
|
|
|
|
|
|
int * sequence_get_track_status(void *priv)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) priv;
|
|
multitracker_t *mt = (multitracker_t*) p->backlink;
|
|
all_priv_t *a = (all_priv_t*) mt->data;
|
|
gint i;
|
|
int *result = (int*) malloc(sizeof(int) * MAX_TRACKS );
|
|
|
|
for( i = 0;i < MAX_TRACKS ; i ++ )
|
|
{
|
|
mt_priv_t *q = a->pt[i];
|
|
result[i] = 0; // reset it
|
|
if(q->active)
|
|
{
|
|
// find in tracklist
|
|
gint j;
|
|
gint num = -1;
|
|
for( j = 0; j < MAX_TRACKS; j ++ )
|
|
{
|
|
if(p->tracks[j])
|
|
{
|
|
char hostname[255];
|
|
int port_num = 0;
|
|
char *str = p->tracks[j];
|
|
int tag_id = 0;
|
|
if(sscanf(str, "%s %d %d", hostname, &port_num, &tag_id ))
|
|
{
|
|
if(strncasecmp( hostname, q->hostname,strlen(hostname)) == 0 && port_num ==
|
|
q->port_num )
|
|
{
|
|
num = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if( num >= 0 )
|
|
result[i] = 1;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void seq_gotostart(GtkWidget *w, gpointer user_data )
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
if(p->active)
|
|
veejay_sequence_send( p->sequence,VIMS_VIDEO_GOTO_START , NULL ,NULL);
|
|
}
|
|
static void seq_reverse(GtkWidget *w, gpointer user_data)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
if(p->active)
|
|
veejay_sequence_send(p->sequence, VIMS_VIDEO_PLAY_BACKWARD, NULL ,NULL);
|
|
}
|
|
static void seq_pause(GtkWidget *w, gpointer user_data)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
if(p->active)
|
|
veejay_sequence_send(p->sequence, VIMS_VIDEO_PLAY_STOP, NULL ,NULL);
|
|
}
|
|
static void seq_play( GtkWidget *w, gpointer user_data)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
if(p->active)
|
|
veejay_sequence_send(p->sequence, VIMS_VIDEO_PLAY_FORWARD, NULL ,NULL);
|
|
}
|
|
static void seq_gotoend(GtkWidget *w, gpointer user_data)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
if(p->active)
|
|
veejay_sequence_send(p->sequence, VIMS_VIDEO_GOTO_END , NULL,NULL );
|
|
}
|
|
static void seq_speeddown(GtkWidget *w, gpointer user_data)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
int n = p->status_cache[SAMPLE_SPEED];
|
|
if( n < 0 ) n += 1;
|
|
if( n > 0 ) n -= 1;
|
|
if(p->active)
|
|
veejay_sequence_send( p->sequence, VIMS_VIDEO_SET_SPEED, "%d", n );
|
|
}
|
|
static void seq_speedup(GtkWidget *w, gpointer user_data)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
int n = p->status_cache[SAMPLE_SPEED];
|
|
if( n < 0 ) n -= 1;
|
|
if( n > 0 ) n += 1;
|
|
if(p->active)
|
|
veejay_sequence_send( p->sequence, VIMS_VIDEO_SET_SPEED, "%d", n );
|
|
}
|
|
static void seq_prevframe(GtkWidget *w, gpointer user_data)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
if(p->active)
|
|
veejay_sequence_send( p->sequence, VIMS_VIDEO_PREV_FRAME, NULL,NULL );
|
|
}
|
|
static void seq_nextframe(GtkWidget *w, gpointer user_data)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
if(p->active)
|
|
veejay_sequence_send( p->sequence, VIMS_VIDEO_SKIP_FRAME, NULL,NULL );
|
|
}
|
|
|
|
static void seq_speed( GtkWidget *w, gpointer user_data)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
|
|
if(p->status_lock)
|
|
return;
|
|
gdouble value = GTK_ADJUSTMENT( GTK_RANGE(w)->adjustment )->value;
|
|
gint speed = (gint) value;
|
|
if(p->active && speed != 0)
|
|
veejay_sequence_send( p->sequence, VIMS_VIDEO_SET_SPEED, "%d", speed );
|
|
}
|
|
|
|
static void seq_opacity( GtkWidget *w, gpointer user_data)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
|
|
if(p->status_lock)
|
|
return;
|
|
gdouble value = GTK_ADJUSTMENT( GTK_RANGE(w)->adjustment )->value;
|
|
gint opacity = (gint)( value * 255.0);
|
|
if(p->active)
|
|
veejay_sequence_send( p->sequence, VIMS_CHAIN_MANUAL_FADE, "%d %d",0, opacity );
|
|
}
|
|
|
|
#define FIRST_ROW_END 5
|
|
static struct
|
|
{
|
|
const char *name;
|
|
int vims_id;
|
|
const char *file;
|
|
void (*f)();
|
|
} button_template_t[] =
|
|
{
|
|
{ "button_gotostart", VIMS_VIDEO_GOTO_START, "button_gotostart.png", seq_gotostart },
|
|
{ "button_reverse", VIMS_VIDEO_PLAY_BACKWARD, "button_reverse.png" , seq_reverse },
|
|
{ "button_pauseplay", VIMS_VIDEO_PLAY_STOP, "button_pause.png", seq_pause},
|
|
{ "button_play", VIMS_VIDEO_PLAY_FORWARD, "button_play.png", seq_play },
|
|
{ "button_gotoend", VIMS_VIDEO_GOTO_END, "button_gotoend.png",seq_gotoend },
|
|
|
|
{ "button_speeddown", VIMS_VIDEO_SET_SPEED, "button_down.png", seq_speeddown },
|
|
{ "button_speedup", VIMS_VIDEO_SET_SPEED, "button_up.png", seq_speedup },
|
|
{ "button_prevframe", VIMS_VIDEO_PREV_FRAME, "button_prev.png", seq_prevframe },
|
|
{ "button_nextframe", VIMS_VIDEO_SKIP_FRAME, "button_skip.png", seq_nextframe },
|
|
{ NULL , 0 , NULL },
|
|
};
|
|
|
|
static void add_buttons( mt_priv_t *p, sequence_view_t *seqv , GtkWidget *w)
|
|
{
|
|
int i;
|
|
for( i = 0; i < FIRST_ROW_END;i ++ )
|
|
{
|
|
char path[1024];
|
|
bzero(path,1024);
|
|
get_gd(path,NULL, button_template_t[i].file );
|
|
seqv->icons[i] = gtk_image_new_from_file( path );
|
|
seqv->buttons[i] = gtk_button_new_with_label(" ");
|
|
gtk_widget_set_size_request( seqv->icons[i],24,20 );
|
|
|
|
gtk_button_set_image( GTK_BUTTON(seqv->buttons[i]), seqv->icons[i] );
|
|
gtk_widget_set_size_request( seqv->buttons[i],24,20 );
|
|
// gtk_container_add( GTK_CONTAINER( w ), seqv->buttons[i] );
|
|
gtk_box_pack_start( GTK_BOX(w), seqv->buttons[i], TRUE,TRUE, 0 );
|
|
g_signal_connect( G_OBJECT( seqv->buttons[i] ), "clicked", G_CALLBACK( button_template_t[i].f),
|
|
(gpointer*)p );
|
|
gtk_widget_show( seqv->buttons[i] );
|
|
|
|
}
|
|
// gtk_widget_set_sensitive( w, FALSE );
|
|
}
|
|
static void add_buttons2( mt_priv_t *p, sequence_view_t *seqv , GtkWidget *w)
|
|
{
|
|
int i;
|
|
for( i = FIRST_ROW_END; button_template_t[i].name != NULL ;i ++ )
|
|
{
|
|
char path[1024];
|
|
bzero(path,1024);
|
|
get_gd(path,NULL, button_template_t[i].file );
|
|
seqv->icons[i] = gtk_image_new_from_file( path );
|
|
seqv->buttons2[i] = gtk_button_new_with_label(" ");
|
|
gtk_widget_set_size_request( seqv->icons[i],24,20 );
|
|
|
|
gtk_button_set_image( GTK_BUTTON(seqv->buttons2[i]), seqv->icons[i] );
|
|
gtk_widget_set_size_request( seqv->buttons2[i],24,20 );
|
|
gtk_box_pack_start( GTK_BOX(w), seqv->buttons2[i], TRUE,TRUE, 0 );
|
|
g_signal_connect( G_OBJECT( seqv->buttons2[i] ), "clicked", G_CALLBACK( button_template_t[i].f),
|
|
(gpointer*)p );
|
|
gtk_widget_show( seqv->buttons2[i] );
|
|
|
|
}
|
|
// gtk_widget_set_sensitive( w, FALSE );
|
|
}
|
|
|
|
static void update_timeline( mt_priv_t *p, gint total, gint current )
|
|
{
|
|
timeline_set_length( GTK_WIDGET(p->view->timeline_),
|
|
(gdouble) total,
|
|
(gdouble) current );
|
|
char *total = format_time( total,25.0f );
|
|
gtk_label_set_text( p->view->labels_[1], total );
|
|
g_free(total);
|
|
}
|
|
static void update_pos( mt_priv_t *p, gint current )
|
|
{
|
|
timeline_set_pos( p->view->timeline_, current );
|
|
char *now = format_time( current ,25.0f);
|
|
gtk_label_set_text( p->view->labels_[0], now );
|
|
g_free(now);
|
|
}
|
|
static void update_speed( mt_priv_t *p, gint speed )
|
|
{
|
|
gtk_adjustment_set_value( GTK_ADJUSTMENT( GTK_RANGE( p->view->sliders_[0] )->adjustment), (gdouble) speed );
|
|
}
|
|
|
|
static gboolean update_track_list( mt_priv_t *p )
|
|
{
|
|
if(p->active)
|
|
{
|
|
int len = 0;
|
|
gchar *buf = veejay_sequence_get_track_list( p->sequence, 5, &len );
|
|
int i = 0;
|
|
int it = 0;
|
|
char *ptr = buf;
|
|
// clear existing buffer
|
|
for( i = 0; i < MAX_TRACKS ; i ++ )
|
|
{
|
|
if( p->tracks[i] )
|
|
free(p->tracks[i]);
|
|
p->tracks[i] = NULL;
|
|
}
|
|
|
|
if( !buf )
|
|
return TRUE;
|
|
|
|
i = 0;
|
|
while( i < len )
|
|
{
|
|
int dlen = 0;
|
|
char tmp_len[4];
|
|
bzero( tmp_len, 4 );
|
|
strncpy( tmp_len, ptr , 3 );
|
|
sscanf( tmp_len , "%d", &dlen );
|
|
if(dlen>0)
|
|
{
|
|
ptr += 3;
|
|
p->tracks[it] = strndup( ptr, dlen );
|
|
it++;
|
|
|
|
ptr += dlen;
|
|
}
|
|
i += ( 3 + dlen );
|
|
}
|
|
free( buf );
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
static void playmode_sensitivity( mt_priv_t *p, gint pm )
|
|
{
|
|
if( pm == MODE_STREAM )
|
|
{
|
|
gtk_widget_set_sensitive( GTK_WIDGET( p->view->button_box2 ), FALSE );
|
|
gtk_widget_set_sensitive( GTK_WIDGET( p->view->button_box ), FALSE );
|
|
gtk_widget_set_sensitive( GTK_WIDGET( p->view->sliders_[0] ), FALSE );
|
|
gtk_widget_set_sensitive( GTK_WIDGET( p->view->timeline_ ), FALSE );
|
|
gtk_widget_set_sensitive( GTK_WIDGET( p->view->sliders_[1] ), TRUE );
|
|
}
|
|
else
|
|
{
|
|
if( pm == MODE_SAMPLE || pm == MODE_PLAIN )
|
|
{
|
|
gtk_widget_set_sensitive( GTK_WIDGET( p->view->button_box2 ), TRUE );
|
|
gtk_widget_set_sensitive( GTK_WIDGET( p->view->button_box ), TRUE );
|
|
gtk_widget_set_sensitive( GTK_WIDGET( p->view->sliders_[0] ), TRUE );
|
|
gtk_widget_set_sensitive( GTK_WIDGET( p->view->timeline_ ), TRUE );
|
|
}
|
|
if( pm == MODE_SAMPLE )
|
|
gtk_widget_set_sensitive( GTK_WIDGET( p->view->sliders_[1] ), TRUE );
|
|
else
|
|
gtk_widget_set_sensitive( GTK_WIDGET( p->view->sliders_[1] ), FALSE );
|
|
}
|
|
}
|
|
|
|
static void update_widgets(int *status, mt_priv_t *p, int pm)
|
|
{
|
|
int *h = p->history[pm];
|
|
gdk_threads_enter();
|
|
|
|
playmode_sensitivity( p, pm );
|
|
|
|
if( pm == MODE_SAMPLE || pm == MODE_PLAIN )
|
|
{
|
|
// if( h[TOTAL_FRAMES] != status[TOTAL_FRAMES] )
|
|
// update_timeline( p, status[TOTAL_FRAMES], status[FRAME_NUM] );
|
|
if( h[FRAME_NUM] != status[FRAME_NUM] )
|
|
update_pos( p, status[FRAME_NUM] );
|
|
if( h[SAMPLE_SPEED] != status[SAMPLE_SPEED] )
|
|
update_speed( p, status[SAMPLE_SPEED] );
|
|
}
|
|
|
|
if( h[TOTAL_SLOTS] != status[TOTAL_SLOTS])
|
|
{
|
|
if(update_track_list( p ))
|
|
update_track_view( MAX_TRACKS, get_track_tree( p->view->tracks ), (void*)p );
|
|
}
|
|
|
|
gdk_threads_leave();
|
|
}
|
|
|
|
static gboolean update_sequence_widgets( gpointer data )
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) data;
|
|
char status[100];
|
|
int array[18];
|
|
veejay_get_status( p->sequence, status );
|
|
int n = status_to_arr( status, array );
|
|
if( n != 17 )
|
|
{
|
|
printf("status error\n");
|
|
}
|
|
p->status_lock = 1;
|
|
|
|
int pm = array[PLAY_MODE];
|
|
int i;
|
|
for( i = 0; i < 18; i ++ )
|
|
p->status_cache[i] = array[i];
|
|
|
|
update_widgets(array, p, pm);
|
|
|
|
int *his = p->history[ pm ];
|
|
for( i = 0; i < 18; i ++ )
|
|
his[i] = array[i];
|
|
p->status_lock = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
static int free_slot(void *data)
|
|
{
|
|
int i = 0;
|
|
all_priv_t *pt = (all_priv_t*)data;
|
|
for( i = 0; i < MAX_TRACKS; i ++ )
|
|
{
|
|
mt_priv_t *p = pt->pt[i];
|
|
if(p->used == 0)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static void store_data( void *data, int index,char *hostname, int port_num )
|
|
{
|
|
all_priv_t *pt = (all_priv_t*) data;
|
|
if(pt->pt[index]->hostname) free(pt->pt[index]->hostname);
|
|
pt->pt[index]->hostname = strdup(hostname);
|
|
pt->pt[index]->port_num = port_num;
|
|
}
|
|
|
|
static void free_data( mt_priv_t *p )
|
|
{
|
|
sequence_view_t *v = p->view;
|
|
void *b = p->backlink;
|
|
int n = p->num;
|
|
|
|
if( p->timeout )
|
|
g_source_remove( p->timeout );
|
|
p->timeout = 0;
|
|
|
|
veejay_abort_sequence( p->sequence );
|
|
|
|
if( p->hostname )
|
|
free( p->hostname );
|
|
|
|
memset( p, 0,sizeof(mt_priv_t));
|
|
p->view = v;
|
|
p->backlink = b;
|
|
p->num = n;
|
|
}
|
|
|
|
static void delete_data( void *data, int index )
|
|
{
|
|
all_priv_t *pt = (all_priv_t*)data;
|
|
char track_title[100];
|
|
mt_priv_t *p = pt->pt[index];
|
|
|
|
if(p->used)
|
|
{
|
|
// gtk_widget_set_sensitive( GTK_WIDGET(p->view->toggle), FALSE );
|
|
gtk_widget_set_sensitive( GTK_WIDGET(p->view->panel),FALSE);
|
|
set_logo( p->view->area );
|
|
free_data( p );
|
|
}
|
|
|
|
}
|
|
static void set_logo(GtkWidget *area)
|
|
{
|
|
char path[1024];
|
|
bzero(path,1024);
|
|
get_gd(path,NULL, "veejay-logo.png");
|
|
GdkPixbuf *buf = gdk_pixbuf_new_from_file( path,NULL );
|
|
GdkPixbuf *buf2 = gdk_pixbuf_scale_simple( buf,preview_width_,preview_height_, GDK_INTERP_BILINEAR );
|
|
gtk_image_set_from_pixbuf( GTK_IMAGE(area), buf2 );
|
|
gdk_pixbuf_unref( buf );
|
|
gdk_pixbuf_unref( buf2 );
|
|
}
|
|
|
|
static sequence_view_t *get_sequence_view(void *data,int index)
|
|
{
|
|
all_priv_t *pt = (all_priv_t*)data;
|
|
return pt->pt[index]->view;
|
|
}
|
|
|
|
|
|
static int mt_new_connection_dialog(multitracker_t *mt, char *hostname,int len, int *port_num)
|
|
{
|
|
GtkWidget *dialog = gtk_dialog_new_with_buttons(
|
|
"New Track",
|
|
GTK_WINDOW( mt->main_window ),
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_STOCK_CANCEL,
|
|
GTK_RESPONSE_REJECT,
|
|
GTK_STOCK_OK,
|
|
GTK_RESPONSE_ACCEPT,
|
|
NULL );
|
|
|
|
|
|
GtkWidget *text_entry = gtk_entry_new();
|
|
gtk_entry_set_text( GTK_ENTRY(text_entry), "localhost" );
|
|
gtk_editable_set_editable( GTK_ENTRY(text_entry), TRUE );
|
|
gtk_dialog_set_default_response( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
|
|
gtk_window_set_resizable( GTK_WINDOW( dialog ), FALSE );
|
|
gint base = 3490;
|
|
gint dport = base + (1000 * num_tracks_active( mt ));
|
|
|
|
GtkObject *adj = gtk_adjustment_new( dport,1024,65535,5,10,0);
|
|
GtkWidget *num_entry = gtk_spin_button_new( adj, 5.0, 0 );
|
|
|
|
GtkWidget *text_label = gtk_label_new( "Hostname" );
|
|
GtkWidget *num_label = gtk_label_new( "Port" );
|
|
g_signal_connect( G_OBJECT(dialog), "response",
|
|
G_CALLBACK( gtk_widget_hide ), G_OBJECT( dialog ) );
|
|
|
|
GtkWidget *vbox = gtk_vbox_new( FALSE, 4 );
|
|
gtk_container_add( GTK_CONTAINER( vbox ), text_label );
|
|
gtk_container_add( GTK_CONTAINER( vbox ), text_entry );
|
|
gtk_container_add( GTK_CONTAINER( vbox ), num_label );
|
|
gtk_container_add( GTK_CONTAINER( vbox ), num_entry );
|
|
gtk_container_add( GTK_CONTAINER( GTK_DIALOG(dialog)->vbox), vbox );
|
|
gtk_widget_show_all( dialog );
|
|
|
|
gint res = gtk_dialog_run( GTK_DIALOG(dialog) );
|
|
|
|
if( res == GTK_RESPONSE_ACCEPT )
|
|
{
|
|
gchar *host = gtk_entry_get_text( GTK_ENTRY( text_entry ) );
|
|
gint port = gtk_spin_button_get_value( GTK_SPIN_BUTTON(num_entry ));
|
|
strncpy( hostname, host, len );
|
|
*port_num = port;
|
|
}
|
|
|
|
gtk_widget_destroy( dialog );
|
|
|
|
return res;
|
|
}
|
|
|
|
void setup_geometry( int w, int h, int n_tracks )
|
|
{
|
|
LAST_TRACK = n_tracks + 1;
|
|
MAX_TRACKS = n_tracks;
|
|
}
|
|
|
|
void *multitrack_new( void (*f)(int,char*,int), void (*g)(GdkPixbuf *),GtkWidget *win, GtkWidget *box ,GtkWidget *msg, gint max_w, gint max_h, GtkWidget *main_preview_area)
|
|
{
|
|
max_w = 352;
|
|
max_h = 288;
|
|
multitracker_t *mt = NULL;
|
|
all_priv_t *pt = NULL;
|
|
|
|
mt = (multitracker_t*) malloc(sizeof(multitracker_t));
|
|
memset( mt, 0, sizeof(multitracker_t));
|
|
|
|
mt->main_window = win;
|
|
mt->main_box = box;
|
|
mt->status_bar = msg;
|
|
gui_cb = f;
|
|
img_cb = g;
|
|
|
|
pt = (all_priv_t*) malloc(sizeof(all_priv_t));
|
|
memset(pt,0,sizeof(pt));
|
|
|
|
mt->scroll = gtk_scrolled_window_new(NULL,NULL);
|
|
preview_width_ = max_w / 2;
|
|
preview_height_ = max_h / 2;
|
|
gdouble mw = preview_width_ * 5;
|
|
|
|
gtk_widget_set_size_request(mt->scroll,(int)mw,max_h*1.2);
|
|
gtk_container_set_border_width(GTK_CONTAINER(mt->scroll),2);
|
|
gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(mt->scroll),GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS );
|
|
GtkWidget *table = gtk_table_new( 1, MAX_TRACKS, FALSE );
|
|
gtk_box_pack_start( GTK_BOX( mt->main_box ), mt->scroll , FALSE,FALSE, 0 );
|
|
gtk_widget_show(mt->scroll);
|
|
|
|
int c = 0;
|
|
for( c = 0; c < MAX_TRACKS; c ++ )
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) malloc(sizeof( mt_priv_t));
|
|
memset( p, 0, sizeof(mt_priv_t));
|
|
p->num = c;
|
|
p->view = new_sequence_view( p,0,0,0, main_preview_area );
|
|
p->backlink = (void*) mt;
|
|
pt->pt[c] = p;
|
|
gtk_table_attach_defaults( table, p->view->event_box, c, c+1, 0, 1 );
|
|
}
|
|
|
|
max_w = 352;
|
|
max_h = 288;
|
|
|
|
gtk_scrolled_window_add_with_viewport(
|
|
GTK_SCROLLED_WINDOW( mt->scroll ), table );
|
|
|
|
gtk_widget_show(table);
|
|
|
|
|
|
mt_priv_t *lt = (mt_priv_t*) malloc(sizeof( mt_priv_t));
|
|
memset( lt, 0, sizeof(mt_priv_t));
|
|
lt->num = LAST_TRACK;
|
|
lt->backlink = (void*) mt;
|
|
lt->view = new_sequence_view( lt, 0, 0,1 , main_preview_area);
|
|
pt->pt[LAST_TRACK] = lt;
|
|
|
|
gtk_container_add( GTK_CONTAINER( mt->main_box ), lt->view->event_box );
|
|
mt->data = (void*) pt;
|
|
|
|
GError *err = NULL;
|
|
pt->thread = g_thread_create( (GThreadFunc) mt_preview, (gpointer*) mt ,FALSE,&err);
|
|
if(!pt->thread)
|
|
{
|
|
status_print( mt, "%s while starting image thread", err->message);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
return (void*) mt;
|
|
}
|
|
|
|
void multitrack_open(void *data)
|
|
{
|
|
multitracker_t *mt = (multitracker_t*) data;
|
|
G_LOCK(mt_lock);
|
|
mt->sensitive = 1;
|
|
G_UNLOCK(mt_lock);
|
|
}
|
|
|
|
void multitrack_close( void *data )
|
|
{
|
|
multitracker_t *mt = (multitracker_t*) data;
|
|
G_LOCK(mt_lock);
|
|
mt->sensitive = 0;
|
|
G_UNLOCK(mt_lock);
|
|
}
|
|
|
|
void multitrack_quit( void *data )
|
|
{
|
|
multitracker_t *mt = (multitracker_t*) data;
|
|
G_LOCK(mt_lock);
|
|
mt->quit = 1;
|
|
G_UNLOCK(mt_lock);
|
|
all_priv_t *a = (all_priv_t*) mt->data;
|
|
int i;
|
|
for( i = 0; i <MAX_TRACKS; i ++ )
|
|
{
|
|
mt_priv_t *p = a->pt[i];
|
|
if(p) free_data(p);
|
|
}
|
|
}
|
|
|
|
int multitrack_add_track( void *data )
|
|
{
|
|
multitracker_t *mt = (multitracker_t*) data;
|
|
if(mt)
|
|
{
|
|
// open input dialog, query hostname and postnum etc
|
|
char *hostname = g_new0(char , 100 );
|
|
int port_num = 0;
|
|
if( mt_new_connection_dialog( mt, hostname, 100, &port_num ) == GTK_RESPONSE_ACCEPT )
|
|
{
|
|
all_priv_t *pt = (all_priv_t*)mt->data;
|
|
int track = free_slot( mt->data );
|
|
if( track == -1 )
|
|
{
|
|
status_print(mt, "No free Tracks available!");
|
|
g_free(hostname);
|
|
return 0;
|
|
}
|
|
|
|
int i;
|
|
int found = 0;
|
|
for( i = 0; i < MAX_TRACKS ; i ++ )
|
|
{
|
|
mt_priv_t *p = pt->pt[i];
|
|
if(p->active)
|
|
{
|
|
if(strncasecmp(hostname,p->hostname,strlen(hostname)) == 0 && port_num == p->port_num )
|
|
{
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
void *seq = NULL;
|
|
if(found)
|
|
{
|
|
status_print( mt, "Track %d: '%s' '%d' already in Track %d\n",
|
|
track, hostname,port_num, i );
|
|
g_free(hostname);
|
|
return 0;
|
|
}
|
|
seq = veejay_sequence_init( port_num, hostname, preview_width_*2, preview_height_*2 );
|
|
if(seq == NULL )
|
|
{
|
|
status_print( mt, "Error while connecting to '%s' : '%d'", hostname, port_num );
|
|
g_free(hostname);
|
|
pt->pt[track]->sequence = NULL;
|
|
pt->pt[track]->active = 0;
|
|
pt->pt[track]->used = 0;
|
|
return 0;
|
|
}
|
|
pt->pt[track]->timeout = gtk_timeout_add( 300, update_sequence_widgets, (gpointer*) pt->pt[track] );
|
|
|
|
veejay_configure_sequence( seq, preview_width_, preview_height_ );
|
|
|
|
G_LOCK(mt_lock);
|
|
pt->pt[track]->sequence = seq;
|
|
pt->pt[track]->active = 1;
|
|
pt->pt[track]->used = 1;
|
|
store_data( mt->data, track, hostname, port_num );
|
|
G_UNLOCK(mt_lock);
|
|
mt_priv_t *p = pt->pt[track];
|
|
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( p->view->toggle ), 1 );
|
|
status_print( mt, "Track %d: Connection established with '%s' port %d\n",
|
|
track, hostname, port_num );
|
|
gtk_widget_set_sensitive( GTK_WIDGET(p->view->panel),TRUE);
|
|
}
|
|
g_free(hostname);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void multitrack_close_track( void *data )
|
|
{
|
|
multitracker_t *mt = (multitracker_t*) data;
|
|
|
|
}
|
|
|
|
int multrack_audoadd( void *data, char *hostname, int port_num )
|
|
{
|
|
multitracker_t *mt = (multitracker_t*) data;
|
|
all_priv_t *a = (all_priv_t*)mt->data;
|
|
G_LOCK(mt_lock);
|
|
int track = free_slot( mt->data );
|
|
void *seq = veejay_sequence_init( port_num, hostname, preview_width_*2, preview_height_*2 );
|
|
|
|
if(seq == NULL )
|
|
{
|
|
status_print( mt, "Error while connecting to '%s' : '%d'", hostname, port_num );
|
|
g_free(hostname);
|
|
a->pt[track]->sequence = NULL;
|
|
a->pt[track]->active = 0;
|
|
a->pt[track]->used = 0;
|
|
G_UNLOCK(mt_lock);
|
|
}
|
|
a->pt[track]->timeout = gtk_timeout_add( 300, update_sequence_widgets, (gpointer*) a->pt[track] );
|
|
veejay_configure_sequence( seq, preview_width_, preview_height_ );
|
|
|
|
a->pt[track]->sequence = seq;
|
|
a->pt[track]->active = 1;
|
|
a->pt[track]->used = 1;
|
|
|
|
store_data( mt->data, track, hostname, port_num );
|
|
|
|
|
|
multitrack_set_current( data, hostname, port_num , preview_width_*2, preview_height_*2);
|
|
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( a->pt[track]->view->toggle ), 1 );
|
|
status_print( mt, "Track %d: Connection established with '%s' port %d\n",
|
|
track, hostname, port_num );
|
|
gtk_widget_set_sensitive( GTK_WIDGET(a->pt[track]->view->panel),TRUE);
|
|
// gtk_widget_set_sensitive( GTK_WIDGET(a->pt[track]->view->toggle),TRUE);
|
|
|
|
G_UNLOCK(mt_lock);
|
|
return track;
|
|
}
|
|
|
|
int multitrack_autoload( void *data, char *hostname, int port_num )
|
|
{
|
|
multitrack_set_current( data, hostname, port_num , preview_width_*2, preview_height_*2);
|
|
|
|
return 1;
|
|
}
|
|
void multitrack_set_current2( void *data, char *hostname, int port_num , int width, int height)
|
|
{
|
|
}
|
|
|
|
static int num_tracks_active( multitracker_t * mt )
|
|
{
|
|
int i;
|
|
int sum = 0;
|
|
all_priv_t *a = (all_priv_t*) mt->data;
|
|
for( i = 0; i < MAX_TRACKS ; i ++ )
|
|
{
|
|
mt_priv_t *p = a->pt[i];
|
|
if(p->active)
|
|
sum ++;
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
static int find_track( multitracker_t *mt, const char *host, int port )
|
|
{
|
|
int i;
|
|
all_priv_t *a = (all_priv_t*) mt->data;
|
|
if(!host || port <= 0 || port > 65535 )
|
|
return -1;
|
|
|
|
for( i = 0; i < MAX_TRACKS ; i ++ )
|
|
{
|
|
mt_priv_t *p = a->pt[i];
|
|
if(p->active)
|
|
{
|
|
if(strncasecmp( p->hostname, host, strlen(host)) == 0 && port ==
|
|
p->port_num )
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int find_sequence( all_priv_t *a )
|
|
{
|
|
mt_priv_t *c = a->pt[LAST_TRACK];
|
|
if(!c->active)
|
|
return -1;
|
|
int i;
|
|
for( i= 0; i < MAX_TRACKS; i ++ )
|
|
{// if( c == a->pt[i]->sequence ) return i;
|
|
if(a->pt[i]->active)
|
|
{
|
|
if(strncasecmp(c->hostname, a->pt[i]->hostname, strlen(a->pt[i]->hostname) ) == 0 &&
|
|
c->port_num == a->pt[i]->port_num )
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int find_vtrack_id( mt_priv_t *p, mt_priv_t *q, int *got_tag_id )
|
|
{
|
|
if(!q->active)
|
|
return -1;
|
|
if(!p->active)
|
|
return -1;
|
|
char hostname[255];
|
|
int port_num = 0;
|
|
int tag_id = 0;
|
|
int i;
|
|
for( i = 0; i < MAX_TRACKS; i++ )
|
|
{
|
|
if(p->tracks[i])
|
|
{
|
|
char *str = p->tracks[ i ];
|
|
if(sscanf(str, "%s %d %d", hostname, &port_num, &tag_id ))
|
|
{
|
|
if(strncasecmp( q->hostname,hostname,strlen(hostname) ) == 0 &&
|
|
port_num == q->port_num )
|
|
{
|
|
*got_tag_id = tag_id;
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void multitrack_release_track(void *data, int id, int release_this )
|
|
{
|
|
char hostname[255];
|
|
int port_num = 0;
|
|
int tag_id = 0;
|
|
|
|
if( release_this < 0 || release_this > MAX_TRACKS )
|
|
return;
|
|
|
|
if( id < 0 || id > MAX_TRACKS )
|
|
return;
|
|
G_LOCK(mt_lock);
|
|
|
|
multitracker_t *mt = (multitracker_t*) data;
|
|
all_priv_t *a = (all_priv_t*) mt->data;
|
|
mt_priv_t *p = a->pt[id];
|
|
mt_priv_t *q = a->pt[release_this];
|
|
|
|
int stream_id = find_vtrack_id( p,q, &tag_id );
|
|
if( stream_id >= 0 )
|
|
veejay_sequence_send( p->sequence , VIMS_STREAM_DELETE, "%d", tag_id);
|
|
G_UNLOCK(mt_lock);
|
|
}
|
|
|
|
void multitrack_bind_track( void *data, int id, int bind_this )
|
|
{
|
|
if( bind_this < 0 || bind_this > MAX_TRACKS )
|
|
return;
|
|
|
|
if( id < 0 || id > MAX_TRACKS )
|
|
return;
|
|
|
|
|
|
G_LOCK(mt_lock);
|
|
|
|
multitracker_t *mt = (multitracker_t*) data;
|
|
all_priv_t *a = (all_priv_t*) mt->data;
|
|
mt_priv_t *p = a->pt[id];
|
|
|
|
mt_priv_t *q = a->pt[bind_this];
|
|
|
|
if(!q->active)
|
|
{
|
|
G_UNLOCK(mt_lock);
|
|
status_print(mt,"Track %d is empty\n", bind_this );
|
|
return;
|
|
}
|
|
if(!p->active)
|
|
{
|
|
//@@@ fatal
|
|
G_UNLOCK(mt_lock);
|
|
return;
|
|
}
|
|
|
|
if( strncasecmp( q->hostname, p->hostname, strlen(q->hostname)) == 0 &&
|
|
q->port_num == p->port_num )
|
|
{
|
|
G_UNLOCK(mt_lock);
|
|
status_print(mt, "Track %d: Cannot bind to myself", bind_this);
|
|
return;
|
|
}
|
|
|
|
// connect q to p
|
|
veejay_sequence_send( p->sequence, VIMS_STREAM_NEW_UNICAST, "%d %s", q->port_num,q->hostname );
|
|
|
|
G_UNLOCK(mt_lock);
|
|
|
|
status_print(mt, "Veejay '%s:%d' retrieving frames from Veejay '%s:%d",
|
|
p->hostname,p->port_num,q->hostname,q->port_num );
|
|
|
|
}
|
|
|
|
|
|
// set_current opens Main preview
|
|
void multitrack_set_current( void *data, char *hostname, int port_num , int width, int height)
|
|
{
|
|
multitracker_t *mt = (multitracker_t*)data;
|
|
|
|
all_priv_t *a = (all_priv_t*) mt->data;
|
|
mt_priv_t *last_track = a->pt[LAST_TRACK];
|
|
if( last_track->active )
|
|
{
|
|
// make sure to reset width/height back to small
|
|
veejay_configure_sequence( last_track->sequence, preview_width_, preview_height_ );
|
|
}
|
|
|
|
int id = find_track( mt, hostname, port_num );
|
|
if(id >= 0 )
|
|
{
|
|
last_track->used = 1;
|
|
last_track->active = 1;
|
|
last_track->sequence = a->pt[id]->sequence;
|
|
if(last_track->hostname)
|
|
free(last_track->hostname);
|
|
last_track->hostname = strdup(hostname);
|
|
last_track->port_num = port_num;
|
|
assert( last_track->sequence != NULL );
|
|
veejay_configure_sequence( last_track->sequence, 352, 288 );
|
|
gtk_widget_set_size_request( GTK_WIDGET( last_track->view->area ), width,height );
|
|
}
|
|
else
|
|
{
|
|
all_priv_t *a = (all_priv_t*) mt->data;
|
|
mt_priv_t *last_track = a->pt[LAST_TRACK];
|
|
last_track->active = 0;
|
|
}
|
|
}
|
|
|
|
void multitrack_restart(void *data)
|
|
{
|
|
}
|
|
|
|
static gboolean seqv_mouse_press_event ( GtkWidget *w, GdkEventButton *event, gpointer user_data)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
multitracker_t *mt = (multitracker_t*) p->backlink;
|
|
if( p == NULL )
|
|
{
|
|
status_print((multitracker_t*)p->backlink,"Track %d is empty\n", p->num);
|
|
return FALSE;
|
|
}
|
|
if( gveejay_busy() )
|
|
{
|
|
status_print( (multitracker_t*)p->backlink,
|
|
"Already connecting to Track %d", mt->selected );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// mt->selected = p->num;
|
|
|
|
if(event->type == GDK_2BUTTON_PRESS)
|
|
{
|
|
mt->selected = p->num;
|
|
gui_cb( 0, strdup(p->hostname), p->port_num );
|
|
G_LOCK(mt_lock);
|
|
multitrack_set_current( (void*) mt, p->hostname, p->port_num ,preview_width_*2,preview_height_*2 );
|
|
/*
|
|
all_priv_t *a = (all_priv_t*) mt->data;
|
|
mt_priv_t *last_track = a->pt[LAST_TRACK];
|
|
last_track->used = 1;
|
|
last_track->active = 1;
|
|
last_track->sequence = p->sequence;
|
|
assert( last_track->sequence != NULL );
|
|
veejay_configure_sequence( last_track->sequence, 352, 288 );*/
|
|
|
|
G_UNLOCK(mt_lock);
|
|
}
|
|
|
|
if( event->type == GDK_BUTTON_PRESS )
|
|
{
|
|
status_print((multitracker_t*)p->backlink,"Selected Track %d\n", p->num);
|
|
mt->selected = p->num;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void sequence_preview_cb(GtkWidget *widget, gpointer user_data)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
veejay_toggle_image_loader( p->sequence,
|
|
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
|
|
}
|
|
|
|
static gint seqv_image_expose( GtkWidget *w, gpointer user_data )
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
return FALSE;
|
|
}
|
|
|
|
static void sequence_set_current_frame(GtkWidget *w, gpointer user_data)
|
|
{
|
|
mt_priv_t *p = (mt_priv_t*) user_data;
|
|
if(!p->status_lock)
|
|
{
|
|
gdouble pos = timeline_get_pos( TIMELINE_SELECTION(w) );
|
|
veejay_sequence_send(p->sequence, VIMS_VIDEO_SET_FRAME, "%d" , (gint) pos);
|
|
}
|
|
}
|
|
|
|
static sequence_view_t *new_sequence_view( mt_priv_t *p,gint w, gint h, gint last, GtkWidget *main_area )
|
|
{
|
|
sequence_view_t *seqv = (sequence_view_t*) malloc(sizeof(sequence_view_t));
|
|
memset( seqv, 0,sizeof( sequence_view_t ));
|
|
|
|
|
|
if(!last || main_area == NULL)
|
|
{
|
|
seqv->event_box = gtk_event_box_new();
|
|
gtk_event_box_set_visible_window( seqv->event_box, TRUE );
|
|
GTK_WIDGET_SET_FLAGS( seqv->event_box, GTK_CAN_FOCUS );
|
|
if( w == 0 && h == 0 )
|
|
g_signal_connect( G_OBJECT( seqv->event_box ),
|
|
"button_press_event",
|
|
G_CALLBACK( seqv_mouse_press_event ),
|
|
(gpointer*) p );
|
|
gtk_widget_show( GTK_WIDGET( seqv->event_box ) );
|
|
|
|
|
|
gchar *track_title = g_new0( gchar, 20 );
|
|
sprintf(track_title, "Track %d", p->num );
|
|
seqv->frame = gtk_frame_new( track_title );
|
|
g_free(track_title);
|
|
gtk_container_set_border_width( GTK_CONTAINER( seqv->frame) , 1 );
|
|
gtk_widget_show( GTK_WIDGET( seqv->frame ) );
|
|
gtk_container_add( GTK_CONTAINER( seqv->event_box), seqv->frame );
|
|
seqv->main_vbox = gtk_vbox_new(FALSE,0);
|
|
gtk_container_add( GTK_CONTAINER( seqv->frame ), seqv->main_vbox );
|
|
gtk_widget_show( GTK_WIDGET( seqv->main_vbox ) );
|
|
|
|
seqv->area = gtk_image_new();
|
|
}
|
|
else
|
|
seqv->area = main_area;
|
|
|
|
set_logo( seqv->area );
|
|
|
|
g_signal_connect( G_OBJECT( seqv->area ),
|
|
"expose_event",
|
|
G_CALLBACK( seqv_image_expose ),
|
|
(gpointer*) p );
|
|
|
|
if(!last || !main_area)
|
|
{
|
|
gtk_box_pack_start( GTK_BOX(seqv->main_vbox),GTK_WIDGET( seqv->area), FALSE,FALSE,0);
|
|
gtk_widget_set_size_request( seqv->area, w == 0 ? preview_width_ : w, h == 0 ? preview_height_: h );
|
|
}
|
|
|
|
if(!last)
|
|
{
|
|
seqv->panel = gtk_frame_new(NULL);
|
|
seqv->toggle = gtk_toggle_button_new_with_label( "preview" );
|
|
g_signal_connect( G_OBJECT( seqv->toggle ), "toggled", G_CALLBACK(sequence_preview_cb),
|
|
(gpointer*)p );
|
|
//gtk_widget_set_sensitive( GTK_WIDGET(seqv->toggle), FALSE );
|
|
//gtk_container_add( GTK_CONTAINER( seqv->main_vbox ), seqv->toggle );
|
|
gtk_box_pack_start( GTK_BOX(seqv->main_vbox), seqv->toggle,FALSE,FALSE, 0 );
|
|
gtk_widget_show( seqv->toggle );
|
|
|
|
GtkWidget *vvbox = gtk_vbox_new(FALSE, 0);
|
|
|
|
seqv->button_box = gtk_hbox_new(FALSE,0);
|
|
gtk_box_pack_start( GTK_BOX(vvbox), seqv->button_box ,FALSE,FALSE, 0 );
|
|
if( w== 0 && h == 0 )
|
|
add_buttons( p,seqv,seqv->button_box );
|
|
gtk_widget_show( seqv->button_box );
|
|
gtk_container_add( GTK_CONTAINER( seqv->main_vbox ), seqv->panel );
|
|
|
|
seqv->button_box2 = gtk_hbox_new(FALSE, 0);
|
|
gtk_box_pack_start( GTK_BOX(vvbox), seqv->button_box2, FALSE,FALSE, 0 );
|
|
if( w== 0 && h == 0)
|
|
add_buttons2( p,seqv,seqv->button_box2 );
|
|
gtk_widget_show( seqv->button_box2 );
|
|
gtk_container_add( GTK_CONTAINER( seqv->panel ), vvbox );
|
|
gtk_widget_show(vvbox);
|
|
|
|
GtkWidget *box = gtk_vbox_new(FALSE,0);
|
|
seqv->timeline_ = timeline_new();
|
|
gtk_widget_set_size_request( seqv->panel, 180 ,14);
|
|
gtk_widget_show( seqv->panel );
|
|
gtk_box_pack_start( GTK_BOX( box ), seqv->timeline_, FALSE,FALSE, 0 );
|
|
//gtk_container_add( GTK_CONTAINER(seqv->panel), box );
|
|
gtk_box_pack_start( GTK_BOX( vvbox ), box , FALSE,FALSE,0);
|
|
gtk_widget_show(seqv->timeline_);
|
|
g_signal_connect( seqv->timeline_, "pos_changed",
|
|
(GCallback) sequence_set_current_frame, (gpointer*) p );
|
|
|
|
/* tree */
|
|
GtkWidget *scroll = gtk_scrolled_window_new(NULL,NULL);
|
|
// gtk_srolled_window_set_placement( GTK_SCROLLED_WINDOW(scroll), GTK_CORNER_TOP_RIGHT );
|
|
gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_ETCHED_IN );
|
|
gtk_widget_set_size_request(scroll,30,70);
|
|
gtk_container_set_border_width(GTK_CONTAINER(scroll),0);
|
|
gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scroll),GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
|
|
GtkWidget *vvvbox = gtk_hbox_new(FALSE,0);
|
|
seqv->tracks = create_track_view(p->num, MAX_TRACKS, (void*) p );
|
|
gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( get_track_tree(seqv->tracks)) , FALSE );
|
|
gtk_widget_set_size_request( get_track_tree(seqv->tracks),20,80 );
|
|
gtk_widget_show(scroll);
|
|
|
|
gtk_scrolled_window_add_with_viewport(
|
|
GTK_SCROLLED_WINDOW( scroll ), get_track_tree(seqv->tracks) );
|
|
gtk_widget_show( get_track_tree(seqv->tracks));
|
|
gtk_box_pack_start( GTK_BOX(vvvbox), scroll, TRUE,TRUE, 0);
|
|
|
|
GtkWidget *hhbox = gtk_hbox_new(FALSE,0);
|
|
seqv->sliders_[0] = gtk_vscale_new_with_range( -12.0,12.0,1.0 );
|
|
seqv->sliders_[1] = gtk_vscale_new_with_range( 0.0, 1.0, 0.01 );
|
|
gtk_scale_set_digits( GTK_SCALE(seqv->sliders_[1]), 2 );
|
|
g_signal_connect( G_OBJECT( seqv->sliders_[0] ), "value_changed", G_CALLBACK( seq_speed ),
|
|
(gpointer*)p );
|
|
g_signal_connect( G_OBJECT( seqv->sliders_[1] ), "value_changed", G_CALLBACK( seq_opacity ),
|
|
(gpointer*)p );
|
|
|
|
gtk_box_pack_start( GTK_BOX( hhbox ), seqv->sliders_[0], TRUE, TRUE, 0 );
|
|
gtk_box_pack_start( GTK_BOX( hhbox ), seqv->sliders_[1], TRUE, TRUE, 0 );
|
|
gtk_widget_show( seqv->sliders_[0] );
|
|
gtk_widget_show( seqv->sliders_[1] );
|
|
// gtk_container_add( GTK_CONTAINER( vvvbox ), hhbox );
|
|
gtk_box_pack_start( GTK_BOX(vvvbox), hhbox, TRUE,TRUE, 0 );
|
|
gtk_widget_show( hhbox );
|
|
|
|
gtk_container_add( GTK_CONTAINER( box ), vvvbox );
|
|
gtk_widget_show( vvvbox );
|
|
gtk_widget_show( box );
|
|
|
|
|
|
GtkWidget *hbox = gtk_hbox_new(FALSE,0);
|
|
gtk_box_set_spacing( hbox, 10 );
|
|
seqv->labels_[0] = gtk_label_new( "00:00:00:00" );
|
|
seqv->labels_[1] = gtk_label_new( "00:00:00:00" );
|
|
gtk_box_pack_start( GTK_BOX( hbox ), seqv->labels_[0], FALSE, FALSE, 0 );
|
|
gtk_box_pack_start( GTK_BOX( hbox ), seqv->labels_[1], FALSE, FALSE, 0 );
|
|
gtk_widget_show( seqv->labels_[0] );
|
|
gtk_widget_show( seqv->labels_[1] );
|
|
gtk_box_pack_start( GTK_BOX(seqv->main_vbox), hbox, FALSE,FALSE, 0 );
|
|
gtk_widget_show( hbox );
|
|
|
|
|
|
gtk_widget_set_sensitive(GTK_WIDGET(seqv->panel), FALSE );
|
|
}
|
|
|
|
gtk_widget_show( GTK_WIDGET( seqv->area ) );
|
|
|
|
seqv->dim[0] = w;
|
|
seqv->dim[1] = h;
|
|
|
|
return seqv;
|
|
}
|
|
|
|
|
|
void *mt_preview( gpointer user_data )
|
|
{
|
|
multitracker_t *mt = (multitracker_t*) user_data;
|
|
all_priv_t *a = (all_priv_t*) mt->data;
|
|
gint i = 0;
|
|
GdkPixbuf *cache[MAX_TRACKS+2];
|
|
|
|
for( ;; )
|
|
{
|
|
|
|
G_LOCK(mt_lock);
|
|
mt_priv_t *lt = a->pt[LAST_TRACK];
|
|
gint error = 0;
|
|
|
|
memset( cache, 0, (MAX_TRACKS+2) * sizeof(GdkPixbuf*));
|
|
|
|
if(mt->quit)
|
|
{
|
|
G_UNLOCK(mt_lock);
|
|
g_thread_exit(NULL);
|
|
}
|
|
|
|
if(lt->active && lt->preview)
|
|
{
|
|
cache[LAST_TRACK] = veejay_get_image( lt->sequence, &error );
|
|
if( error )
|
|
delete_data( mt->data, LAST_TRACK );
|
|
}
|
|
|
|
int ref = find_sequence( a );
|
|
|
|
|
|
if( mt->sensitive )
|
|
for( i = 0; i < MAX_TRACKS ; i ++ )
|
|
{
|
|
mt_priv_t *p = a->pt[i];
|
|
if( p->active && ref != i)
|
|
{
|
|
cache[i] = veejay_get_image(
|
|
p->sequence,
|
|
&error );
|
|
if( error )
|
|
cache[i] = 0;
|
|
}
|
|
}
|
|
G_UNLOCK(mt_lock);
|
|
|
|
if( ref >= 0 && cache[LAST_TRACK] && lt->preview)
|
|
{
|
|
cache[ref] = gdk_pixbuf_scale_simple(
|
|
cache[LAST_TRACK],
|
|
preview_width_,
|
|
preview_height_,
|
|
GDK_INTERP_BILINEAR );
|
|
}
|
|
|
|
|
|
gdk_threads_enter();
|
|
if( mt->sensitive )
|
|
for( i = 0; i < MAX_TRACKS ; i ++ )
|
|
{
|
|
mt_priv_t *p = a->pt[i];
|
|
if(cache[i])
|
|
{
|
|
GtkImage *image = GTK_IMAGE( p->view->area );
|
|
gtk_image_set_from_pixbuf( image, cache[i] );
|
|
}
|
|
}
|
|
|
|
if(mt->quit)
|
|
{
|
|
gdk_threads_leave();
|
|
g_thread_exit(NULL);
|
|
}
|
|
else
|
|
if(lt->active && cache[LAST_TRACK])
|
|
{
|
|
GtkImage *image = GTK_IMAGE( lt->view->area );
|
|
gtk_image_set_from_pixbuf( image, cache[LAST_TRACK] );
|
|
img_cb( cache[LAST_TRACK] );
|
|
gdk_pixbuf_unref( cache[LAST_TRACK] );
|
|
}
|
|
//@@ cleanup
|
|
for( i = 0; i < MAX_TRACKS ; i ++ )
|
|
{
|
|
mt_priv_t *p = a->pt[i];
|
|
if(cache[i])
|
|
{
|
|
gdk_pixbuf_unref(cache[i]);
|
|
}
|
|
cache[i] = NULL;
|
|
}
|
|
gdk_threads_leave();
|
|
}
|
|
}
|
|
|
|
|
|
|