Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

storyboard.cc

Go to the documentation of this file.
00001 /*
00002 * storyboard.cc Storyboard view object
00003 * Copyright (C) 2003-2007 Dan Dennedy <dan@dennedy.org>
00004 *
00005 * This program is free software; you can redistribute it and/or modify
00006 * it under the terms of the GNU General Public License as published by
00007 * the Free Software Foundation; either version 2 of the License, or
00008 * (at your option) any later version.
00009 *
00010 * This program is distributed in the hope that it will be useful,
00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 * GNU General Public License for more details.
00014 *
00015 * You should have received a copy of the GNU General Public License
00016 * along with this program; if not, write to the Free Software Foundation,
00017 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018 */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023 
00024 #include <iostream>
00025 #include <vector>
00026 #include <string>
00027 
00028 #include <pthread.h>
00029 
00030 #include "storyboard.h"
00031 #include "frame.h"
00032 #include "preferences.h"
00033 #include "error.h"
00034 #include "page_editor.h"
00035 #include "commands.h"
00036 #include "stringutils.h"
00037 
00038 extern "C"
00039 {
00040 #include "support.h"
00041 #include "cell-renderers/mg-popup-entry.h"
00042 #include "cell-renderers/mg-cell-renderer-popup.h"
00043 #include "cell-renderers/mg-cell-renderer-list.h"
00044 
00045     extern KinoCommon *common;
00046     extern struct navigate_control g_nav_ctl;
00047 }
00048 
00049 enum SceneStatus {
00050     SCENE_INIT,
00051     SCENE_IDLE,
00052     SCENE_STARTING,
00053     SCENE_RUNNING,
00054     SCENE_RESTART
00055 };
00056 
00057 enum
00058 {
00059     COLUMN_THUMBNAIL = 0,
00060     COLUMN_NAME,
00061     COLUMN_NAME_MODE,
00062     COLUMN_VALUE,
00063     COLUMN_VALUE_MODE,
00064     N_COLUMNS
00065 };
00066 
00067 enum SceneStatus showScenesRunning = SCENE_INIT;
00068 
00069 static std::vector< GdkPixbuf * > *backup = NULL;
00070 static pthread_mutex_t scene_mutex = PTHREAD_MUTEX_INITIALIZER;
00071 
00072 
00073 static int getSceneFromPath( gchar *path )
00074 {
00075     std::vector< int > scenes = common->getPageEditor() ->GetScene();
00076     int i = atoi( path );
00077     if ( i > ( int ) scenes.size() )
00078         i = scenes.size() - 1;
00079     return ( i <= 0 ) ? 0 : scenes[ i - 1 ];
00080 }
00081 
00082 static void removeImages( std::vector< GdkPixbuf * >** list )
00083 {
00084     if ( *list != NULL )
00085     {
00086         std::vector< GdkPixbuf * >::iterator iter;
00087         for ( iter = ( *list ) ->begin(); iter != ( *list ) ->end(); iter++ )
00088         {
00089             if ( *iter != NULL )
00090                 g_object_unref( *iter );
00091         }
00092         ( *list ) ->erase( ( *list ) ->begin(), ( *list ) ->end() );
00093         delete ( *list );
00094         *list = NULL;
00095     }
00096 }
00097 
00098 static void tree_model_row_inserted_cb( GtkTreeModel* model, GtkTreePath* path, GtkTreeIter* iter, gpointer data )
00099 {
00100     Storyboard * storyboard = ( Storyboard* ) ( data );
00101     //std::cerr << "tree_model_row_inserted_cb skip " << storyboard->getSkip() << std::endl;
00102     if ( ! storyboard->getSkip() )
00103     {
00104         gchar * row = gtk_tree_path_to_string( path );
00105         int row_num = atoi( row );
00106         //std::cerr << "tree_model_row_inserted_cb row " << row << std::endl;
00107         if ( strchr( row, ':' ) != NULL )
00108             row_num++;
00109         storyboard->setSkip();
00110         storyboard->moveScene( row_num );
00111         g_free( row );
00112     }
00113 }
00114 
00115 static gboolean tree_view_row_select( GtkWidget *widget, GdkEventButton *event, gpointer data )
00116 {
00117     GtkTreeView * treeview = GTK_TREE_VIEW( widget );
00118     GtkTreeSelection *selection = gtk_tree_view_get_selection( treeview );
00119 
00120     GtkTreeIter iter;
00121     GtkTreeModel *model;
00122 
00123     if ( gtk_tree_selection_get_selected ( selection, &model, &iter ) )
00124     {
00125         gchar * row = gtk_tree_model_get_string_from_iter( model, &iter );
00126         if ( strchr( row, ':' ) )
00127         {
00128             GtkTreeViewColumn* column;
00129             GtkTreePath *path;
00130             gtk_tree_view_get_cursor( treeview, &path, &column );
00131             if ( path && column )
00132                 gtk_tree_view_set_cursor( treeview, path, column, TRUE);
00133         }
00134         else
00135         {
00136             common->selectScene( atoi( row ) );
00137         }
00138         g_free( row );
00139     }
00140 
00141     return FALSE;
00142 }
00143 
00144 // Double click expands/collapses
00145 static void tree_view_row_activated( GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data )
00146 {
00147     // Reserve this action for future use.
00148 #if 0
00149     if ( gtk_tree_view_row_expanded( treeview, path ) )
00150         gtk_tree_view_collapse_row( treeview, path );
00151     else
00152         gtk_tree_view_expand_row( treeview, path, FALSE );
00153 #endif
00154 }
00155 
00156 
00157 static void
00158 on_name_start_editing( MgCellRendererPopup *cell )
00159 {
00160     g_nav_ctl.escaped = TRUE;
00161 }
00162 
00163 static void
00164 on_name_show_popup( MgCellRendererList *cell,
00165                   const gchar        *path_string,
00166                   gint                x1,
00167                   gint                y1,
00168                   gint                x2,
00169                   gint                y2,
00170                   GtkTreeModel       *model)
00171 {
00172     GtkTreePath  *path = gtk_tree_path_new_from_string( path_string );
00173     GtkTreeIter   iter;
00174     vector< std::string > metaNames;
00175     vector< std::string >::iterator metaNamesIter;
00176     GList *list = NULL;
00177     int currentScene = getSceneFromPath( const_cast< char* >( path_string ) );
00178 
00179     gtk_tree_model_get_iter (model, &iter, path);
00180     StringUtils::split( Preferences::getInstance().metaNames, ",", metaNames );
00181 
00182     for ( metaNamesIter = metaNames.begin(); metaNamesIter != metaNames.end(); ++metaNamesIter )
00183     {
00184         std::string metaname = *metaNamesIter;
00185         if ( metaname.at( 0 ) != '*' )
00186         {
00187             // Only add the name if it does not yet exist
00188             if ( common->getPlayList()->GetSeqAttribute( currentScene, metaname.c_str() ) == "" )
00189                 list = g_list_append( list, strdup( metaname.c_str() ) );
00190         }
00191     }
00192     cell->list = list;
00193     cell->selected_index = 0;
00194     
00195     gtk_tree_path_free( path );
00196 }
00197 
00198 static void
00199 on_name_edited( MgCellRendererList *cell,
00200     gchar               *path_string,
00201     gchar               *new_text,
00202     GtkTreeStore        *model )
00203 {
00204     GtkTreePath  *path = gtk_tree_path_new_from_string( path_string );
00205     GtkTreeIter   iter;
00206     gchar        *parentPathString = path_string;
00207     GtkTreePath  *parentPath = NULL;
00208     GtkTreeIter   parent;
00209     vector< std::string > metaNames;
00210     vector< std::string >::iterator metaNamesIter;
00211     int currentScene = getSceneFromPath( const_cast< char* >( path_string ) );
00212     int i = 0;
00213 
00214     path_string = strrchr( path_string, ':' );
00215     if ( path_string )
00216     {
00217         *path_string = 0;
00218         parentPath = gtk_tree_path_new_from_string( parentPathString );
00219         gtk_tree_model_get_iter( GTK_TREE_MODEL( model ), &parent, parentPath );
00220     }
00221     gtk_tree_model_get_iter( GTK_TREE_MODEL( model ), &iter, path );
00222     
00223     StringUtils::split( Preferences::getInstance().metaNames, ",", metaNames );
00224 
00225 
00226     for ( GList *l = cell->list; l; l = l->next )
00227     {
00228         if ( cell->selected_index == i++ )
00229         {
00230             // Get the existing name
00231             const char *name = mg_popup_entry_get_text( MG_POPUP_ENTRY( cell->parent.editable ) );
00232             
00233             // Update the model
00234             gtk_tree_store_set( model, &iter, COLUMN_NAME, (gchar*) l->data, COLUMN_VALUE, "-", -1 );
00235 
00236             // Refresh the view
00237             gtk_tree_model_row_changed( GTK_TREE_MODEL( model ), path, &iter );
00238 
00239             if ( name[0] != '(' )
00240             {
00241                 // Clear the old xml attribute
00242                 common->getPlayList()->SetSeqAttribute( currentScene, name, "" );
00243             }
00244             else
00245             {
00246                 // Set the new xml attribute name, and value = ""
00247                 common->getPlayList()->SetSeqAttribute( currentScene, (char*) l->data, "-" );
00248 
00249                 // See if there is an unset metadata item
00250                 for ( metaNamesIter = metaNames.begin(); metaNamesIter != metaNames.end(); ++metaNamesIter )
00251                 {
00252                     std::string metaname = *metaNamesIter;
00253                     if ( metaname.at( 0 ) == '*' )
00254                         metaname.erase( 0,1 );
00255                         
00256                     // There is
00257                     if ( common->getPlayList()->GetSeqAttribute( currentScene, metaname.c_str() ) == "" )
00258                     {
00259                         GetStoryboard()->setSkip();
00260                         // Add an extra metadata row to let user add attributes
00261                         gtk_tree_store_append( model, &iter, &parent );
00262                         gtk_tree_store_set( model, &iter,
00263                                     COLUMN_NAME, _("(new)"),
00264                                     COLUMN_NAME_MODE, GTK_CELL_RENDERER_MODE_EDITABLE,
00265                                     COLUMN_VALUE, "",
00266                                     COLUMN_VALUE_MODE, GTK_CELL_RENDERER_MODE_EDITABLE,
00267                                     -1 );
00268                         GetStoryboard()->clearSkip();
00269                         break;
00270                     }
00271                 }
00272             }
00273 
00274             break;
00275         }
00276     }
00277 
00278     g_nav_ctl.escaped = FALSE;
00279 
00280     if ( path )
00281         gtk_tree_path_free( path );
00282     if ( parentPath )
00283         gtk_tree_path_free( parentPath );
00284 }
00285 
00286 static void
00287 on_value_start_editing( MgCellRendererPopup *cell )
00288 {
00289     g_nav_ctl.escaped = TRUE;
00290 }
00291 
00292 static void
00293 on_value_show_popup( MgCellRendererList *cell,
00294                   const gchar        *path_string,
00295                   gint                x1,
00296                   gint                y1,
00297                   gint                x2,
00298                   gint                y2,
00299                   GtkTreeStore       *model)
00300 {
00301     GtkTreePath  *path = gtk_tree_path_new_from_string( path_string );
00302     GtkTreeIter   iter;
00303     GValue        name;
00304     gchar        *name_string;
00305     vector< std::pair< std::string, std::string > > metaValues;
00306     vector< std::pair< std::string, std::string > >::iterator metaValuesIter;
00307     GList *list = NULL;
00308 
00309     // Get the attribute name
00310     gtk_tree_model_get_iter( GTK_TREE_MODEL( model ), &iter, path );
00311     memset( &name, 0, sizeof( name ) );
00312     gtk_tree_model_get_value( GTK_TREE_MODEL( model ), &iter, COLUMN_NAME, &name );
00313     name_string = const_cast< char* >( g_value_get_string( &name ) );
00314 
00315     // Put non-* values into the popup list
00316     metaValues = Preferences::getInstance().metaValues[ name_string ];
00317     for ( metaValuesIter = metaValues.begin(); metaValuesIter != metaValues.end(); ++metaValuesIter )
00318     {
00319         if ( metaValuesIter->first != "*" )
00320             list = g_list_append( list, strdup( metaValuesIter->first.c_str() ) );
00321     }
00322     cell->list = list;
00323     cell->selected_index = 0;
00324 
00325     if ( path )
00326         gtk_tree_path_free( path );
00327     g_value_unset( &name );
00328 }
00329 
00330 static void
00331 on_value_edited( MgCellRendererList *cell,
00332     gchar               *path_string,
00333     gchar               *new_text,
00334     GtkTreeStore        *model )
00335 {
00336     GtkTreePath  *path = gtk_tree_path_new_from_string( path_string );
00337     GtkTreeIter   iter;
00338     GValue        name;
00339     gchar        *name_string;
00340 
00341     // Get the attribute name
00342     gtk_tree_model_get_iter( GTK_TREE_MODEL( model ), &iter, path );
00343     memset( &name, 0, sizeof( name ) );
00344     gtk_tree_model_get_value( GTK_TREE_MODEL( model ), &iter, COLUMN_NAME, &name );
00345     name_string = const_cast< char* >( g_value_get_string( &name ) );
00346 
00347     if ( name_string && name_string[0] != '(' )
00348     {
00349         if ( Preferences::getInstance().metaValues.find( name_string ) != Preferences::getInstance().metaValues.end() )
00350         {
00351             vector< std::pair< std::string, std::string > >& metaValues = Preferences::getInstance().metaValues[ name_string ];
00352             vector< std::pair< std::string, std::string > >::iterator metaValuesIter;
00353             char *value = NULL;
00354             char *label = NULL;
00355         
00356             // See if values range is open-ended (* in metaValues)
00357             for ( metaValuesIter = metaValues.begin(); metaValuesIter != metaValues.end() && metaValuesIter->first != "*"; ++metaValuesIter );
00358 
00359             if ( metaValuesIter != metaValues.end() && MG_CELL_RENDERER_POPUP( cell )->shown == FALSE )
00360             {
00361                 // Get the value from the entry
00362                 label = value = const_cast< char* >( mg_popup_entry_get_text( MG_POPUP_ENTRY( cell->parent.editable ) ) );
00363 
00364                 // See if a hidden value exists for the label value
00365                 for ( metaValuesIter = metaValues.begin(); metaValuesIter != metaValues.end(); ++metaValuesIter )
00366                 {
00367                     if ( metaValuesIter->first == label )
00368                     {
00369                         value = const_cast< char* >( metaValuesIter->second.c_str() );
00370                         break;
00371                     }
00372                 }
00373             }
00374             else if ( MG_CELL_RENDERER_POPUP( cell )->shown == TRUE )
00375             {
00376                 int i = 0;
00377                 
00378                 // Get the value from the popup list
00379                 for ( GList *l = cell->list; l; l = l->next )
00380                 {
00381                     if ( cell->selected_index == i++ )
00382                     {
00383                         label = (char*) l->data;
00384                         break;
00385                     }
00386                 }
00387 
00388                 // See if a hidden value exists for the label value
00389                 for ( metaValuesIter = metaValues.begin(); metaValuesIter != metaValues.end(); ++metaValuesIter )
00390                 {
00391                     if ( metaValuesIter->first == label )
00392                     {
00393                         value = const_cast< char* >( metaValuesIter->second.c_str() );
00394                         break;
00395                     }
00396                 }
00397             }
00398 
00399             if ( value )
00400             {
00401                 // Update the model
00402                 gtk_tree_store_set( model, &iter, COLUMN_VALUE, label, -1 );
00403 
00404                 // Refresh the view
00405                 gtk_tree_model_row_changed( GTK_TREE_MODEL( model ), path, &iter );
00406 
00407                 // Set the old xml attribute
00408                 common->getPlayList()->SetSeqAttribute( getSceneFromPath( const_cast< char* >( path_string ) ), name_string, value );
00409             }
00410         }
00411     }
00412     
00413     g_nav_ctl.escaped = FALSE;
00414 
00415     if ( path )
00416         gtk_tree_path_free( path );
00417     g_value_unset( &name );
00418 }
00419 
00420 static gboolean scroll_handler( gpointer data )
00421 {
00422     GtkTreeView* view = GTK_TREE_VIEW( data );
00423     GtkTreeSelection* selection = gtk_tree_view_get_selection( view );
00424     GtkTreeIter iter;
00425     GtkTreeModel* model;
00426     if ( gtk_tree_selection_get_selected( selection, &model, &iter ) == TRUE )
00427     {
00428         GtkTreePath* path = gtk_tree_model_get_path( model, &iter );
00429         gtk_tree_view_scroll_to_cell( view, path, NULL, TRUE, 0.5, 0.0 );
00430         gtk_tree_path_free( path );
00431     }
00432     return FALSE;
00433 }
00434 
00435 static gboolean expansion_handler( gpointer data )
00436 {
00437     GtkTreeView* view = GTK_TREE_VIEW( data );
00438     gtk_tree_view_expand_all( view );
00439     
00440     GdkWindow* win = gtk_tree_view_get_bin_window( view );
00441     GdkRectangle rect;
00442     gtk_tree_view_get_visible_rect( view, &rect );
00443     gtk_tree_view_tree_to_widget_coords( view, rect.x, rect.y, &rect.x, &rect.y );
00444     gdk_window_invalidate_rect( win, &rect, TRUE );
00445 
00446     g_idle_add( scroll_handler, data );
00447     
00448     return FALSE;
00449 }
00450 
00451 Storyboard::Storyboard( KinoCommon *common ) :
00452         common( common ), skipSelect( false ), skip( false )
00453 {
00454     GtkCellRenderer* renderer;
00455     GtkTreeViewColumn* column;
00456     GtkTreeSelection* select;
00457 
00458     gdk_threads_enter();
00459 
00460     // Create the tree view
00461     view = GTK_TREE_VIEW( lookup_widget( common->getWidget(), "treeview_storyboard" ) );
00462     g_signal_connect( G_OBJECT( view ), "button-release-event", G_CALLBACK( tree_view_row_select ), this );
00463     g_signal_connect( G_OBJECT( view ), "row-activated", G_CALLBACK( tree_view_row_activated ), this );
00464     gtk_tree_view_set_enable_search( view, FALSE );
00465 
00466     // Store the current scene
00467     selection = common->getCurrentScene();
00468 
00469     // Create the model and connect it to the view
00470     model = gtk_tree_store_new( N_COLUMNS, G_TYPE_OBJECT, G_TYPE_STRING,
00471         G_TYPE_INT, G_TYPE_STRING, G_TYPE_INT );
00472     gtk_tree_view_set_model( view, GTK_TREE_MODEL( model ) );
00473     g_signal_connect( G_OBJECT( model ), "row-inserted",
00474                       G_CALLBACK( tree_model_row_inserted_cb ), static_cast<gpointer>( this ) );
00475 
00476     // Add the thumbnail column
00477     renderer = gtk_cell_renderer_pixbuf_new();
00478     column = gtk_tree_view_column_new_with_attributes(
00479                  _( "Storyboard" ), renderer, "pixbuf", COLUMN_THUMBNAIL, NULL );
00480     gtk_tree_view_column_set_fixed_width( column, 100 );
00481     gtk_tree_view_column_set_min_width( column, 100 );
00482     gtk_tree_view_column_set_max_width( column, 100 );
00483     gtk_tree_view_append_column( view, column );
00484     gtk_tree_view_set_expander_column( view, column );
00485 
00486     // Add the meta name column
00487     column = gtk_tree_view_column_new();
00488     gtk_tree_view_column_set_title( column, _("Property") );
00489     gtk_tree_view_column_set_resizable( column, TRUE );
00490     gtk_tree_view_append_column( view, column );
00491     
00492     renderer = mg_cell_renderer_list_new();
00493     g_object_set( G_OBJECT( renderer ), "editable", TRUE, NULL );
00494     gtk_tree_view_column_pack_start( column, renderer, TRUE );
00495     gtk_tree_view_column_set_attributes( column, renderer,
00496                 "text", COLUMN_NAME,
00497                 "mode", COLUMN_NAME_MODE,
00498                 NULL );
00499 
00500     g_signal_connect( G_OBJECT( renderer ),
00501                 "start-editing",
00502                 G_CALLBACK( on_name_start_editing ),
00503                 NULL );
00504     g_signal_connect( G_OBJECT( renderer ),
00505                 "show_popup",
00506                 G_CALLBACK( on_name_show_popup ),
00507                 model );
00508     g_signal_connect( G_OBJECT( renderer ),
00509                 "edited",
00510                 G_CALLBACK( on_name_edited ),
00511                 model );
00512     
00513     // Add the meta value column
00514     column = gtk_tree_view_column_new();
00515     gtk_tree_view_column_set_title( column, _("Value") );
00516     gtk_tree_view_column_set_resizable( column, FALSE );
00517     gtk_tree_view_append_column( view, column );
00518     
00519     renderer = mg_cell_renderer_list_new();
00520     g_object_set( G_OBJECT( renderer ), "editable", TRUE, NULL );
00521 
00522     gtk_tree_view_column_pack_start( column, renderer, TRUE );
00523     gtk_tree_view_column_set_attributes( column, renderer,
00524                 "text", COLUMN_VALUE,
00525                 "mode", COLUMN_VALUE_MODE,
00526                 NULL );
00527 
00528     g_signal_connect( G_OBJECT( renderer ),
00529                 "start-editing",
00530                 G_CALLBACK( on_value_start_editing ),
00531                 NULL );
00532     g_signal_connect( G_OBJECT( renderer ),
00533                 "show_popup",
00534                 G_CALLBACK( on_value_show_popup ),
00535                 model );
00536     g_signal_connect( G_OBJECT( renderer ),
00537                 "edited",
00538                 G_CALLBACK( on_value_edited ),
00539                 model );
00540 
00541     select = gtk_tree_view_get_selection( view );
00542     gtk_tree_selection_set_mode( select, GTK_SELECTION_SINGLE );
00543     
00544     gdk_threads_leave();
00545     g_object_unref( G_OBJECT( model ) ); // view has the reference
00546 }
00547 
00548 Storyboard::~Storyboard()
00549 {}
00550 
00551 void *showScenesThread( void *arg )
00552 {
00553     Frame & frame = *( GetFramePool( ) ->GetFrame( ) );
00554     GdkPixbuf *image = NULL;
00555     GdkPixbuf *thumbnail = NULL;
00556     static std::vector< GdkPixbuf * > *icons = NULL;
00557     std::vector< int > scene;
00558     int frameNum = 0;
00559     Storyboard *storyboard = static_cast<Storyboard *>( arg );
00560     GtkTreeIter iter, child;
00561     unsigned char *pixels = new unsigned char[ FRAME_MAX_WIDTH * FRAME_MAX_HEIGHT * 4 ];
00562 
00563     frame.decoder->quality = DV_QUALITY_DC;
00564     if ( Preferences::getInstance().displayQuality < 4 )
00565         frame.decoder->quality |= DV_QUALITY_COLOR;
00566 
00567 
00568     while ( showScenesRunning != SCENE_IDLE )
00569     {
00570         // Apparently(?) the thumbs generated cannot be removed while they're used in the
00571         // icon list - this doesn't appear to be the case for the timeline page, but is
00572         // definitely causing problems here - could be the modified images causing an issue
00573         // perhaps? Anyway, to avoid a blank list during the execution of this thread, take
00574         // a backup of the previous list and create a new one (see comments below).
00575 
00576         icons = new std::vector< GdkPixbuf *>;
00577 
00578         // Change from SCENE_STARTING to SCENE_RUNNING
00579         showScenesRunning = SCENE_RUNNING;
00580 
00581         // Get the scene list (contains the frame number first frame of each scene)
00582         scene = common->getPageEditor() ->GetScene();
00583 
00584         // Create the icons vector but terminate if the running state changes
00585         for ( unsigned int i = 0; showScenesRunning == SCENE_RUNNING && i < scene.size(); ++i )
00586         {
00587 
00588             frameNum = i == 0 ? 0 : scene[ i - 1 ];
00589 
00590             fail_neg( common->getPlayList() ->GetFrame( frameNum, frame ) );
00591 
00592             frame.ExtractHeader();
00593             frame.ExtractRGB( pixels );
00594 
00595             // Get the image
00596             image = gdk_pixbuf_new_from_data( pixels, GDK_COLORSPACE_RGB, FALSE, 8,
00597                                               frame.GetWidth(), frame.GetHeight(), frame.GetWidth() * 3,
00598                                               NULL, NULL );
00599 
00600             // create the thumbnail
00601             thumbnail = gdk_pixbuf_scale_simple( image, 80, frame.IsWide() ? 45 : 60, GDK_INTERP_NEAREST );
00602             icons->push_back( thumbnail );
00603             g_object_unref( image );
00604         }
00605 
00606         // Render the icons if we're still running, otherwise remove the [partial] list generated
00607         // NB: The freeze followed by a thread_leave causes the icon list to be blanked on the screen and
00608         // removing the current list before clearing the iconlist causes possible core dumps if a redraw
00609         // is required before the new list is in place - hence the backup keeps the last used list until
00610         // we're sure that we can safely remove them
00611 
00612         if ( showScenesRunning == SCENE_RUNNING )
00613         {
00614             pthread_mutex_lock( &scene_mutex );
00615             storyboard->setSkip();
00616             gdk_threads_enter();
00617             gtk_tree_store_clear( storyboard->getModel() );
00618             for ( unsigned int i = 0; showScenesRunning == SCENE_RUNNING && i < scene.size(); ++i )
00619             {
00620                 char start[ 1024 ] = "";
00621                 vector< std::string > metaNames;
00622                 vector< std::string >::iterator metaNamesIter;
00623                 StringUtils::split( Preferences::getInstance().metaNames, ",", metaNames );
00624 
00625                 // Generate scene info
00626                 frameNum = ( i == 0 ) ? 0 : scene[ i - 1 ];
00627                 fail_neg( common->getPlayList() ->GetFrame( frameNum, frame ) );
00628                 frame.ExtractHeader();
00629                 storyboard->getTime().setFramerate( frame.GetFrameRate() );
00630                 char* fileName = common->getPlayList() ->GetFileNameOfFrame( frameNum );
00631                 snprintf( start, 1024, "%s\n%s\n%s",
00632                     g_path_get_basename( fileName ),
00633                     storyboard->getTime().parseFramesToString( frameNum, common->getTimeFormat() ).c_str(),
00634                     storyboard->getTime().parseFramesToString( scene[ i ] - frameNum, common->getTimeFormat() ).c_str()
00635                 );
00636                 free( fileName );
00637                 
00638                 // Put the thumbnail and scene metadata into the model
00639                 gtk_tree_store_append( storyboard->getModel(), &iter, NULL );
00640                 gtk_tree_store_set( storyboard->getModel(), &iter,
00641                                     COLUMN_THUMBNAIL, ( *icons ) [ i ],
00642                                     COLUMN_NAME, _("File:\nBegin:\nDuration:"),
00643                                     COLUMN_NAME_MODE, GTK_CELL_RENDERER_MODE_ACTIVATABLE,
00644                                     COLUMN_VALUE, start,
00645                                     COLUMN_VALUE_MODE, GTK_CELL_RENDERER_MODE_ACTIVATABLE,
00646                                     -1 );
00647 
00648                 for ( metaNamesIter = metaNames.begin(); metaNamesIter != metaNames.end(); ++metaNamesIter )
00649                 {
00650                     std::string metaname = *metaNamesIter;
00651                     if ( metaname.at(0) == '*' )
00652                         metaname.erase(0,1);
00653                         
00654                     // Add standard metadata where exists or required (*name)
00655                     if ( metaNamesIter->at( 0 ) == '*' || common->getPlayList()->GetSeqAttribute( frameNum, metaname.c_str() ) != "" )
00656                     {
00657                         vector< std::pair< std::string, std::string > >& metaValues = Preferences::getInstance().metaValues[ metaname ];
00658                         vector< std::pair< std::string, std::string > >::iterator metaValuesIter;
00659                         std::string labelString = common->getPlayList()->GetSeqAttribute( frameNum, metaname.c_str() );
00660                         char *label = const_cast< char* >( labelString.c_str() );
00661     
00662                         // See if a label exists for the value
00663                         for ( metaValuesIter = metaValues.begin(); metaValuesIter != metaValues.end(); ++metaValuesIter )
00664                         {
00665                             if ( metaValuesIter->second == label )
00666                             {
00667                                 label = const_cast< char* >( metaValuesIter->first.c_str() );
00668                                 break;
00669                             }
00670                         }
00671                         
00672                         gtk_tree_store_append( storyboard->getModel(), &child, &iter );
00673                         gtk_tree_store_set( storyboard->getModel(), &child,
00674                                     COLUMN_NAME, metaname.c_str(),
00675                                     COLUMN_NAME_MODE, GTK_CELL_RENDERER_MODE_EDITABLE,
00676                                     COLUMN_VALUE, label,
00677                                     COLUMN_VALUE_MODE, GTK_CELL_RENDERER_MODE_EDITABLE,
00678                                     -1 );
00679                     }
00680                 }
00681                 // See if we should add extra row for setting a new metadata item
00682                 for ( metaNamesIter = metaNames.begin(); metaNamesIter != metaNames.end(); ++metaNamesIter )
00683                 {
00684                     std::string metaname = *metaNamesIter;
00685                     if ( metaname.at( 0 ) == '*' )
00686                         metaname.erase( 0, 1 );
00687                         
00688                     if ( common->getPlayList()->GetSeqAttribute( frameNum, metaname.c_str() ) == "" )
00689                     {
00690 
00691                         gtk_tree_store_append( storyboard->getModel(), &child, &iter );
00692                         gtk_tree_store_set( storyboard->getModel(), &child,
00693                                     COLUMN_NAME, _("(new)"),
00694                                     COLUMN_NAME_MODE, GTK_CELL_RENDERER_MODE_EDITABLE,
00695                                     COLUMN_VALUE, "",
00696                                     COLUMN_VALUE_MODE, GTK_CELL_RENDERER_MODE_EDITABLE,
00697                                     -1 );
00698                         break;
00699                     }
00700                 }   
00701             }
00702             if ( scene.size() )
00703                 storyboard->select( common->getCurrentScene() );
00704 
00705             gdk_threads_leave();
00706             storyboard->clearSkip();
00707             pthread_mutex_unlock( &scene_mutex );
00708 
00709             if ( scene.size() && Preferences::getInstance().expandStoryboard )
00710                 g_idle_add( expansion_handler, storyboard->getView() );
00711             
00712             // Clean up temporary backup now
00713             removeImages( &backup );
00714             // Now backup
00715             backup = icons;
00716         }
00717         else
00718         {
00719             // Remove any unused thumbs in icons
00720             removeImages( &icons );
00721         }
00722         // If we're still running now, it's OK to idle again.
00723         if ( showScenesRunning == SCENE_RUNNING )
00724             showScenesRunning = SCENE_IDLE;
00725 
00726     }
00727     GetFramePool( ) ->DoneWithFrame( &frame );
00728 
00729     delete[] pixels;
00730     return NULL;
00731 }
00732 
00733 void Storyboard::redraw( )
00734 {
00735     static pthread_t scenes_thread;
00736     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
00737 
00738     pthread_mutex_lock( &mutex );
00739     selection = -1;
00740 
00741     // If running then, set as RESTART otherwise start the thread,
00742     // otherwise we're already waiting on a restart so do nothing
00743     if ( showScenesRunning == SCENE_RUNNING )
00744     {
00745         showScenesRunning = SCENE_RESTART;
00746     }
00747     else if ( showScenesRunning == SCENE_INIT )
00748     {
00749         showScenesRunning = SCENE_STARTING;
00750         pthread_create( &scenes_thread, NULL, showScenesThread, this );
00751     }
00752     else if ( showScenesRunning == SCENE_IDLE )
00753     {
00754         pthread_join( scenes_thread, NULL );
00755         showScenesRunning = SCENE_STARTING;
00756         pthread_create( &scenes_thread, NULL, showScenesThread, this );
00757     }
00758 
00759     pthread_mutex_unlock( &mutex );
00760 }
00761 
00762 void Storyboard::select( int scene )
00763 {
00764     if ( scene > -1 && scene < gtk_tree_model_iter_n_children( GTK_TREE_MODEL( model ), NULL ) )
00765     {
00766         GtkTreeIter iter;
00767         GtkTreeSelection* selection = gtk_tree_view_get_selection( view );
00768         if ( gtk_tree_model_iter_nth_child( GTK_TREE_MODEL( model ), &iter, NULL, scene ) )
00769         {
00770             GtkTreePath * path = gtk_tree_model_get_path( GTK_TREE_MODEL( model ), &iter );
00771             skipSelect = true;
00772             gtk_tree_selection_select_iter( selection, &iter );
00773             gtk_tree_view_scroll_to_cell( view, path, NULL, TRUE, 0.5, 0.0 );
00774             gtk_tree_path_free( path );
00775             skipSelect = false;
00776         }
00777         this->selection = scene;
00778     }
00779 }
00780 
00781 void Storyboard::setSensitive( bool sensitive )
00782 {
00783     gtk_widget_set_sensitive( GTK_WIDGET( view ), sensitive ? TRUE : FALSE );
00784 }
00785 
00786 void Storyboard::moveScene( unsigned int destScene )
00787 {
00788     std::cerr << "moving scene " << selection << " to scene " << destScene << std::endl;
00789     std::vector <int> scenes = common->getPageEditor() ->GetScene();
00790     int start = ( selection == 0 ) ? 0 : scenes[ selection - 1 ];
00791     int end = common->getPlayList() ->FindEndOfScene( start );
00792     int destFrame = 0;
00793 
00794     common->getPageEditor() ->CopyFrames( start, end );
00795     common->getPlayList() ->Delete( start, end );
00796 
00797     if ( destScene >= scenes.size() )
00798     {
00799         destFrame = common->getPlayList() ->GetNumFrames();
00800     }
00801     else if ( ( int ) destScene > selection )
00802     {
00803         common->getPageEditor() ->ResetBar();
00804         scenes = common->getPageEditor() ->GetScene();
00805         destFrame = scenes[ destScene - 2 ];
00806     }
00807     else if ( destScene > 0 )
00808     {
00809         common->getPageEditor() ->ResetBar();
00810         scenes = common->getPageEditor() ->GetScene();
00811         destFrame = scenes[ destScene - 1 ];
00812     }
00813 
00814     common->getPageEditor() ->PasteFrames( destFrame );
00815     common->moveToFrame( destFrame );
00816 
00817     redraw( );
00818 }
00819 
00820 Storyboard *GetStoryboard( )
00821 {
00822     static Storyboard * singleton = new Storyboard( common );
00823     return singleton;
00824 }

Generated on Sun Mar 11 22:11:47 2007 for Kino by  doxygen 1.4.2