00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif
00024
00025 #include <iostream>
00026 #include <pthread.h>
00027
00028 #include "page_timeline.h"
00029 #include "page_editor.h"
00030 #include "commands.h"
00031
00032 enum
00033 {
00034 COLUMN_ICON = 0,
00035 COLUMN_TIME,
00036 COLUMN_FRAME,
00037 N_COLUMNS
00038 };
00039
00040
00041
00042
00043
00044 extern "C"
00045 {
00046
00047 extern KinoCommon *common;
00048 extern navigate_control g_nav_ctl;
00049
00050 int getOneSecond( void )
00051 {
00052 Frame & frame = *( GetFramePool() ->GetFrame( ) );
00053 common->getPlayList() ->GetFrame( common->g_currentFrame, frame );
00054 int value = ( frame.IsPAL() ? 25 : 30 );
00055 GetFramePool( ) ->DoneWithFrame( &frame );
00056 return value;
00057 }
00058
00059 static unsigned char pixels[ FRAME_MAX_WIDTH * FRAME_MAX_HEIGHT * 4 ];
00060
00061 void
00062 on_iconview_timeline_selection_changed( GtkIconView *iconview,
00063 gpointer user_data )
00064 {
00065 PageTimeline* page = static_cast< PageTimeline* >( user_data );
00066 GtkTreeIter iter;
00067 GValue val = {0, };
00068
00069 GList* items = gtk_icon_view_get_selected_items( page->getView() );
00070 if ( items )
00071 {
00072 gtk_tree_model_get_iter( GTK_TREE_MODEL( page->getModel() ), &iter,
00073 static_cast< GtkTreePath* >( items->data ) );
00074 gtk_tree_model_get_value( GTK_TREE_MODEL( page->getModel() ), &iter, COLUMN_FRAME, &val );
00075 common->moveToFrame( g_value_get_int( &val ) );
00076 g_value_unset( &val );
00077 g_list_foreach( items, reinterpret_cast< GFunc >( gtk_tree_path_free ), NULL );
00078 g_list_free( items );
00079
00080 common->changePageRequest( PAGE_EDITOR );
00081 }
00082 }
00083
00084 void
00085 on_iconview_timeline_item_activated( GtkIconView *iconview,
00086 GtkTreePath *path,
00087 gpointer user_data)
00088 {
00089 PageTimeline *page = static_cast< PageTimeline* >( user_data );
00090 GtkTreeIter iter;
00091 GValue val = {0, };
00092
00093 gtk_tree_model_get_iter( GTK_TREE_MODEL( page->getModel() ), &iter, path );
00094 gtk_tree_model_get_value( GTK_TREE_MODEL( page->getModel() ), &iter, COLUMN_FRAME, &val );
00095 common->moveToFrame( g_value_get_int( &val ) );
00096
00097 g_value_unset( &val );
00098 common->changePageRequest( PAGE_EDITOR );
00099 }
00100
00101
00102 void
00103 on_timeline_ok_button_pressed ( GtkButton * button,
00104 gpointer user_data )
00105 {
00106 common->getPageTimeline( ) ->showIcons( );
00107 }
00108
00109 static gboolean on_iconlist_refresh_required( GtkWidget * some_widget, void * some_event, gpointer user_data )
00110 {
00111 ( ( PageTimeline * ) user_data ) ->refresh( );
00112 return false;
00113 }
00114
00115 void
00116 on_start_spin_value_changed (GtkSpinButton *spinbutton,
00117 gpointer user_data)
00118 {
00119 gtk_entry_set_text( GTK_ENTRY( lookup_widget( GTK_WIDGET( spinbutton ), "entry_timeline_start" ) ),
00120 common->getTime().parseFramesToString( ( int )gtk_spin_button_get_value( spinbutton ),
00121 common->getTimeFormat() ).c_str() );
00122 }
00123
00124 void
00125 on_entry_timeline_start_activate (GtkEntry *entry,
00126 gpointer user_data)
00127 {
00128 common->getTime().parseValueToString( gtk_entry_get_text( entry ), common->getTimeFormat() );
00129 GtkSpinButton *spinbutton = GTK_SPIN_BUTTON( lookup_widget( GTK_WIDGET( entry ), "start_spin" ) );
00130 gtk_spin_button_set_value( spinbutton, common->getTime().getFrames() );
00131 on_start_spin_value_changed( spinbutton, NULL );
00132 }
00133
00134 gboolean
00135 on_entry_timeline_start_focus_out_event
00136 (GtkWidget *widget,
00137 GdkEventFocus *event,
00138 gpointer user_data)
00139 {
00140 on_entry_timeline_start_activate( GTK_ENTRY( widget ), NULL );
00141 g_nav_ctl.escaped = FALSE;
00142 return FALSE;
00143 }
00144
00145 void
00146 on_end_spin_value_changed (GtkSpinButton *spinbutton,
00147 gpointer user_data)
00148 {
00149 gtk_entry_set_text( GTK_ENTRY( lookup_widget( GTK_WIDGET( spinbutton ), "entry_timeline_end" ) ),
00150 common->getTime().parseFramesToString( ( int )gtk_spin_button_get_value( spinbutton ),
00151 common->getTimeFormat() ).c_str() );
00152 }
00153
00154 void
00155 on_entry_timeline_end_activate (GtkEntry *entry,
00156 gpointer user_data)
00157 {
00158 common->getTime().parseValueToString( gtk_entry_get_text( entry ), common->getTimeFormat() );
00159 GtkSpinButton *spinbutton = GTK_SPIN_BUTTON( lookup_widget( GTK_WIDGET( entry ), "end_spin" ) );
00160 gtk_spin_button_set_value( spinbutton, common->getTime().getFrames() );
00161 on_end_spin_value_changed( spinbutton, NULL );
00162 }
00163
00164 gboolean
00165 on_entry_timeline_end_focus_out_event (GtkWidget *widget,
00166 GdkEventFocus *event,
00167 gpointer user_data)
00168 {
00169 on_entry_timeline_end_activate( GTK_ENTRY( widget ), NULL );
00170 g_nav_ctl.escaped = FALSE;
00171 return FALSE;
00172 }
00173 }
00174
00175 PageTimeline::PageTimeline( KinoCommon *common ) :
00176 refresh_required( false ), action( 0 ),
00177 last_begin( 0 ), last_end( 0 ), scene( -1 ),
00178 showIconsRunning( TIMELINE_INIT )
00179 {
00180 this->common = common;
00181
00182 view = GTK_ICON_VIEW( lookup_widget( common->getWidget(), "iconview_timeline" ) );
00183 g_signal_connect( G_OBJECT( view ), "expose_event", G_CALLBACK( on_iconlist_refresh_required ), this );
00184 g_signal_connect( G_OBJECT( view ), "item-activated", G_CALLBACK( on_iconview_timeline_item_activated ), this );
00185 g_signal_connect( G_OBJECT( view ), "selection-changed", G_CALLBACK( on_iconview_timeline_selection_changed ), this );
00186 model = gtk_list_store_new( N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT );
00187 gtk_icon_view_set_model( view, GTK_TREE_MODEL( model ) );
00188 gtk_icon_view_set_pixbuf_column( view, COLUMN_ICON );
00189 gtk_icon_view_set_text_column( view, COLUMN_TIME );
00190 pthread_mutex_init( &key, NULL );
00191 pthread_mutex_init( &mutex, NULL );
00192 }
00193
00194 void PageTimeline::start()
00195 {
00196 std::cerr << ">> Starting timeline" << std::endl;
00197
00198 if ( common->getPlayList() ->GetNumFrames() > 0 )
00199 {
00200 int begin = common->getPlayList() ->FindStartOfScene( common->g_currentFrame );
00201 int end = common->getPlayList() ->FindEndOfScene( common->g_currentFrame );
00202
00203 if ( last_begin != begin || last_end != end )
00204 {
00205 GtkEntry *startSpin = GTK_ENTRY( lookup_widget( common->getWidget(), "start_spin" ) );
00206 GtkEntry *endSpin = GTK_ENTRY( lookup_widget( common->getWidget(), "end_spin" ) );
00207 GtkAdjustment *adjust = gtk_spin_button_get_adjustment( GTK_SPIN_BUTTON( startSpin ) );
00208
00209 adjust->lower = 0;
00210 adjust->upper = common->getPlayList() ->GetNumFrames();
00211 gtk_spin_button_set_value( GTK_SPIN_BUTTON( startSpin ), begin );
00212 g_signal_emit_by_name( adjust, "changed" );
00213
00214 adjust = gtk_spin_button_get_adjustment( GTK_SPIN_BUTTON( endSpin ) );
00215 adjust->lower = 0;
00216 adjust->upper = common->getPlayList() ->GetNumFrames();
00217 gtk_spin_button_set_value( GTK_SPIN_BUTTON( endSpin ), end );
00218 g_signal_emit_by_name( adjust, "changed" );
00219
00220 last_begin = begin;
00221 last_end = end;
00222
00223 scene = 0;
00224 vector <int> scenes = common->getPageEditor() ->GetScene();
00225 while ( begin > scenes[ scene++ ] )
00226 ;
00227 scene--;
00228
00229 refresh_required = true;
00230 }
00231 }
00232 gtk_notebook_set_page( GTK_NOTEBOOK( lookup_widget( common->getWidget(), "notebook_keyhelp" ) ), 3 );
00233 gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( lookup_widget( common->getWidget(), "menuitem_timeline" ) ), TRUE );
00234 }
00235
00236 void PageTimeline::selectScene( int i )
00237 {
00238 std::cerr << "Time line scene " << i << std::endl;
00239 GtkWidget *start_spin = lookup_widget( common->getWidget(), "start_spin" );
00240 GtkWidget *end_spin = lookup_widget( common->getWidget(), "end_spin" );
00241 GtkAdjustment *adjust = gtk_spin_button_get_adjustment( GTK_SPIN_BUTTON( start_spin ) );
00242 vector <int> scenes = common->getPageEditor() ->GetScene();
00243
00244 if ( i < 0 )
00245 i = 0;
00246 if ( i >= ( int ) scenes.size() )
00247 i = scenes.size() - 1;
00248 int value = i == 0 ? 0 : scenes[ i - 1 ];
00249 adjust->lower = 0;
00250 adjust->upper = scenes[ scenes.size() - 1 ];
00251 gtk_spin_button_set_value( GTK_SPIN_BUTTON( start_spin ), value );
00252
00253 adjust = gtk_spin_button_get_adjustment( GTK_SPIN_BUTTON( end_spin ) );
00254
00255 adjust->lower = 0;
00256 adjust->upper = scenes[ scenes.size() - 1 ];
00257 gtk_spin_button_set_value( GTK_SPIN_BUTTON( end_spin ), scenes[ i ] - 1 );
00258
00259 last_begin = value;
00260 last_end = scenes[ i ] - 1;
00261 scene = i;
00262
00263 common->g_currentFrame = value;
00264
00265 Frame &frame = *( GetFramePool( ) ->GetFrame( ) );
00266 FileHandler *media;
00267 common->getPlayList() ->GetMediaObject( value, &media );
00268 common->getPlayList() ->GetFrame( value, frame );
00269 common->showFrameMoreInfo( frame, media );
00270 GetFramePool( ) ->DoneWithFrame( &frame );
00271 common->setCurrentScene( value );
00272
00273 showIcons( );
00274 }
00275
00276 gulong PageTimeline::activate()
00277 {
00278 return SCENE_LIST;
00279 }
00280
00281 void PageTimeline::showIcons( )
00282 {
00283 pthread_mutex_lock( &mutex );
00284
00285
00286
00287 if ( showIconsRunning == TIMELINE_RUNNING )
00288 {
00289 showIconsRunning = TIMELINE_RESTART;
00290 }
00291 else if ( showIconsRunning == TIMELINE_INIT )
00292 {
00293 showIconsRunning = TIMELINE_STARTING;
00294 pthread_create( &thread, NULL, ThreadProxy, this );
00295 }
00296 else if ( showIconsRunning == TIMELINE_IDLE )
00297 {
00298 pthread_join( thread, NULL );
00299 showIconsRunning = TIMELINE_STARTING;
00300 pthread_create( &thread, NULL, ThreadProxy, this );
00301 }
00302
00303 pthread_mutex_unlock( &mutex );
00304 }
00305
00306 void* PageTimeline::ThreadProxy( void* arg )
00307 {
00308 PageTimeline* self = static_cast< PageTimeline* >( arg );
00309 return self->Thread();
00310 }
00311
00312 void* PageTimeline::Thread()
00313 {
00314 Frame &frame = *GetFramePool( ) ->GetFrame( );
00315
00316
00317 frame.decoder->quality = DV_QUALITY_DC;
00318 if ( Preferences::getInstance().displayQuality < 4 )
00319 frame.decoder->quality |= DV_QUALITY_COLOR;
00320
00321 while ( showIconsRunning != TIMELINE_IDLE )
00322 {
00323 GtkTreeIter iter;
00324
00325 showIconsRunning = TIMELINE_RUNNING;
00326 refresh_required = false;
00327 gdk_threads_enter();
00328
00329
00330 int my_action = ++ action;
00331
00332
00333 pthread_mutex_lock( &key );
00334
00335
00336 GtkWidget *start_spin = lookup_widget( common->getWidget(), "start_spin" );
00337 GtkWidget *end_spin = lookup_widget( common->getWidget(), "end_spin" );
00338
00339
00340 int start = atoi( gtk_entry_get_text( GTK_ENTRY( start_spin ) ) );
00341 int end = atoi( gtk_entry_get_text( GTK_ENTRY( end_spin ) ) );
00342
00343
00344 int items_per_row = ( GTK_WIDGET( view )->allocation.width - 12 ) / 96;
00345 int number_of_rows = GTK_WIDGET( view )->allocation.height / 98;
00346 int total_possible = items_per_row * number_of_rows;
00347 int total_required = end - start + 1;
00348
00349
00350 double increment = 1;
00351 if ( total_required == 1 )
00352 increment = 2;
00353 else if ( total_possible < total_required )
00354 increment = 1 / ( ( double ) total_possible - 1 );
00355 else
00356 increment = 1 / ( ( double ) total_required );
00357
00358
00359 gtk_list_store_clear( model );
00360
00361
00362 int count = 0;
00363
00364
00365 for ( double position = 0;
00366 showIconsRunning == TIMELINE_RUNNING &&
00367 action == my_action && count ++ < total_possible;
00368 position += increment )
00369 {
00370
00371 int index = start + ( int ) ( position * total_required );
00372
00373 if ( position >= 1 )
00374 index = start + total_required - 1;
00375
00376
00377 string text = "";
00378
00379
00380 common->getPlayList() ->GetFrame( ( int ) index, frame );
00381
00382
00383 frame.ExtractRGB( pixels );
00384
00385
00386 GdkPixbuf *image = gdk_pixbuf_new_from_data( pixels, GDK_COLORSPACE_RGB, FALSE, 8,
00387 frame.GetWidth(), frame.GetHeight(), frame.GetWidth() * 3, NULL, NULL );
00388
00389
00390 GdkPixbuf *scaled = gdk_pixbuf_scale_simple( image, 90, frame.IsWide() ? 51 : 68, GDK_INTERP_NEAREST );
00391
00392
00393 char label[ 256 ] = "";
00394 sprintf( label, "%d", ( int ) index + 1 );
00395 common->getTime().setFramerate( frame.GetFrameRate() );
00396 text = common->getTime().parseFramesToString( index, common->getTimeFormat() );
00397
00398
00399 gtk_list_store_append( model, &iter );
00400 gtk_list_store_set( model, &iter, COLUMN_ICON, scaled,
00401 COLUMN_TIME, text.c_str(), COLUMN_FRAME, index, -1 );
00402
00403
00404 g_object_unref( image );
00405 g_object_unref( scaled );
00406
00407
00408 while ( action == my_action && gtk_events_pending() )
00409 {
00410 pthread_mutex_unlock( &key );
00411 gtk_main_iteration();
00412 pthread_mutex_lock( &key );
00413 }
00414
00415 if ( position >= 1 )
00416 break;
00417 }
00418
00419
00420 pthread_mutex_unlock( &key );
00421 gdk_threads_leave();
00422
00423
00424 if ( showIconsRunning == TIMELINE_RUNNING )
00425 showIconsRunning = TIMELINE_IDLE;
00426 }
00427 GetFramePool( ) ->DoneWithFrame( &frame );
00428
00429 return NULL;
00430 }
00431
00432 void PageTimeline::refresh( )
00433 {
00434 if ( refresh_required )
00435 {
00436 refresh_required = false;
00437 showIcons( );
00438 }
00439 }
00440
00441 gboolean PageTimeline::processKeyboard( GdkEventKey *event )
00442 {
00443 gboolean ret = FALSE;
00444
00445
00446 switch ( event->keyval )
00447 {
00448 case GDK_k:
00449 case GDK_Up:
00450 selectScene( scene - 1 );
00451 break;
00452 case GDK_j:
00453 case GDK_Down:
00454 selectScene( scene + 1 );
00455 break;
00456 case GDK_Return:
00457 selectScene( scene );
00458 break;
00459 case GDK_Escape:
00460 common->changePageRequest( PAGE_EDITOR );
00461 break;
00462 default:
00463 break;
00464 }
00465
00466 return ret;
00467 }
00468
00469 gboolean PageTimeline::processCommand( char *cmd )
00470 {
00471 if ( strcmp( cmd, "F2" ) == 0 )
00472 {
00473 common->keyboardFeedback( cmd, _( "Edit" ) );
00474 common->changePageRequest( PAGE_TIMELINE );
00475 }
00476
00477 else if ( strcmp( cmd, "A" ) == 0 )
00478 {
00479 common->keyboardFeedback( cmd, _( "Capture, append to movie" ) );
00480 common->moveToFrame( common->getPlayList() ->GetNumFrames() );
00481 FileTracker::GetInstance().SetMode( CAPTURE_MOVIE_APPEND );
00482 common->changePageRequest( PAGE_CAPTURE );
00483 }
00484
00485 else if ( strcmp( cmd, "a" ) == 0 )
00486 {
00487 common->keyboardFeedback( cmd, _( "Capture, insert after frame" ) );
00488 common->moveToFrame( common->getPlayList() ->FindEndOfScene( common->g_currentFrame ) );
00489 FileTracker::GetInstance().SetMode( CAPTURE_FRAME_APPEND );
00490 common->changePageRequest( PAGE_CAPTURE );
00491 }
00492
00493 else if ( strcmp( cmd, "t" ) == 0 )
00494 {
00495 common->keyboardFeedback( cmd, _( "Trim" ) );
00496 common->changePageRequest( PAGE_TRIM );
00497 }
00498
00499 else if ( strcmp( cmd, "v" ) == 0 )
00500 {
00501 common->keyboardFeedback( cmd, _( "Timeline" ) );
00502 common->changePageRequest( PAGE_TIMELINE );
00503 }
00504
00505 else if ( strcmp( cmd, "C" ) == 0 )
00506 {
00507 common->keyboardFeedback( cmd, _( "FX" ) );
00508 common->changePageRequest( PAGE_MAGICK );
00509 }
00510
00511 else if ( strcmp( cmd, ":W" ) == 0 )
00512 {
00513 common->keyboardFeedback( cmd, _( "Export" ) );
00514 common->changePageRequest( PAGE_TIMELINE );
00515 }
00516
00517
00518
00519 else if ( strcmp( cmd, ":w" ) == 0 )
00520 {
00521 common->keyboardFeedback( cmd, _( "Write playlist" ) );
00522 common->savePlayList( );
00523 }
00524
00525
00526
00527 else if ( strcmp( cmd, ":q" ) == 0 )
00528 {
00529 common->keyboardFeedback( cmd, _( "quit" ) );
00530 kinoDeactivate();
00531 }
00532
00533 return FALSE;
00534 }
00535
00536 void PageTimeline::timeFormatChanged()
00537 {
00538 on_start_spin_value_changed( GTK_SPIN_BUTTON( lookup_widget( common->getWidget(), "start_spin" ) ), NULL );
00539 on_end_spin_value_changed( GTK_SPIN_BUTTON( lookup_widget( common->getWidget(), "end_spin" ) ), NULL );
00540 showIcons();
00541 }