~andrewsomething/imagination/debian

« back to all changes in this revision

Viewing changes to .pc/15_PLUGINS_INSTALLED.patch/src/support.c

  • Committer: Andrew Starr-Bochicchio
  • Date: 2010-08-10 01:34:10 UTC
  • Revision ID: a.starr.b@gmail.com-20100810013410-m10rrg1coc4bth2f
Tags: 2.1-2
* Acknowledge non-maintainer upload.
 - Thanks to 村仔 and Andrew Lee.
* debian/control:
 - Add a depend on sox and a recommends on libsox-fmt-all
   to provide proper audio support. (LP: #601559)
 - Bump Standards-Version to 3.9.1, no changes needed.
* Convert to Debian source format 3.0 (quilt).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (c) 2009 Giuseppe Torelli <colossus73@gmail.com>
 
3
 *
 
4
 *  This program is free software; you can redistribute it and/or modify
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation; either version 2 of the License,or
 
7
 *  (at your option) any later version.
 
8
 *
 
9
 *  This program is distributed in the hope that it will be useful,
 
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 *  GNU Library General Public License for more details.
 
13
 *
 
14
 *  You should have received a copy of the GNU General Public License
 
15
 *  along with this program; if not,write to the Free Software
 
16
 *  Foundation,Inc.,59 Temple Place - Suite 330,Boston,MA 02111-1307,USA.
 
17
 *
 
18
 */
 
19
 
 
20
#include "support.h"
 
21
#include <glib/gstdio.h>
 
22
 
 
23
#define PLUGINS_INSTALLED 0
 
24
 
 
25
static gboolean img_plugin_is_loaded(img_window_struct *, GModule *);
 
26
 
 
27
GtkWidget *img_load_icon(gchar *filename, GtkIconSize size)
 
28
{
 
29
    GtkWidget *file_image;
 
30
        gchar *path;
 
31
        GdkPixbuf *file_pixbuf = NULL;
 
32
 
 
33
        path = g_strconcat(DATADIR, "/imagination/pixmaps/",filename,NULL);
 
34
        file_pixbuf = gdk_pixbuf_new_from_file(path,NULL);
 
35
        g_free (path);
 
36
 
 
37
        if (file_pixbuf == NULL)
 
38
                file_image = gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE, size);
 
39
    else
 
40
        {
 
41
                file_image = gtk_image_new_from_pixbuf(file_pixbuf);
 
42
            g_object_unref (file_pixbuf);
 
43
        }
 
44
    return file_image;
 
45
}
 
46
 
 
47
gchar *img_convert_seconds_to_time(gint total_secs)
 
48
{
 
49
        gint h, m, s;
 
50
 
 
51
        h =  total_secs / 3600;
 
52
        m = (total_secs % 3600) / 60;
 
53
        s =  total_secs - (h * 3600) - (m * 60);
 
54
        return g_strdup_printf("%02d:%02d:%02d", h, m, s);
 
55
}
 
56
 
 
57
GtkWidget *_gtk_combo_box_new_text(gboolean pointer)
 
58
{
 
59
        GtkWidget *combo_box;
 
60
        GtkCellRenderer *cell;
 
61
        GtkListStore *list;
 
62
        GtkTreeStore *tree;
 
63
        GtkTreeModel *model;
 
64
 
 
65
        if (pointer)
 
66
        {
 
67
                tree = gtk_tree_store_new (4, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT);
 
68
                model = GTK_TREE_MODEL( tree );
 
69
 
 
70
                combo_box = gtk_combo_box_new_with_model (model);
 
71
                g_object_unref (G_OBJECT( model ));
 
72
                cell = gtk_cell_renderer_pixbuf_new ();
 
73
                gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
 
74
                gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell, "pixbuf", 0, NULL);
 
75
        }
 
76
        else
 
77
        {
 
78
                list = gtk_list_store_new (1, G_TYPE_STRING);
 
79
                model = GTK_TREE_MODEL( list );
 
80
                
 
81
                combo_box = gtk_combo_box_new_with_model (model);
 
82
                g_object_unref (G_OBJECT( model ));
 
83
        }
 
84
 
 
85
        cell = gtk_cell_renderer_text_new ();
 
86
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
 
87
        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell, "text", pointer ? 1 : 0, NULL);
 
88
        g_object_set(cell, "ypad", (guint)0, NULL);
 
89
        return combo_box;
 
90
}
 
91
 
 
92
void img_set_statusbar_message(img_window_struct *img_struct, gint selected)
 
93
{
 
94
        gchar *message = NULL;
 
95
        gchar *total_slides = NULL;
 
96
 
 
97
        if (img_struct->slides_nr == 0)
 
98
        {
 
99
                message = g_strdup_printf(_("Welcome to Imagination - %d transitions loaded."),img_struct->nr_transitions_loaded);
 
100
                gtk_statusbar_push(GTK_STATUSBAR(img_struct->statusbar),img_struct->context_id,message);
 
101
                g_free(message);
 
102
                gtk_label_set_text(GTK_LABEL(img_struct->total_slide_number_label),NULL);
 
103
        }
 
104
        else if (selected)
 
105
        {
 
106
                message = g_strdup_printf(_("%d slides selected"),selected);
 
107
                gtk_statusbar_push(GTK_STATUSBAR(img_struct->statusbar),img_struct->context_id,message);
 
108
                g_free(message);
 
109
        }
 
110
        else
 
111
        {
 
112
                total_slides = g_strdup_printf("%d",img_struct->slides_nr);
 
113
                gtk_label_set_text(GTK_LABEL(img_struct->total_slide_number_label),total_slides);
 
114
                message = g_strdup_printf(ngettext("%d slide imported %s" ,"%d slides imported %s",img_struct->slides_nr),img_struct->slides_nr,_(" - Use the CTRL key to select/unselect or SHIFT for multiple select"));
 
115
                gtk_statusbar_push(GTK_STATUSBAR(img_struct->statusbar),img_struct->context_id,message);
 
116
                g_free(total_slides);
 
117
                g_free(message);
 
118
        }
 
119
}
 
120
 
 
121
void img_load_available_transitions(img_window_struct *img)
 
122
{
 
123
        GDir          *dir;
 
124
        const gchar   *transition_name;
 
125
        gchar         *fname = NULL, *name, *filename;
 
126
        gchar        **trans, **bak;
 
127
        GModule       *module;
 
128
        GdkPixbuf     *pixbuf;
 
129
        GtkTreeIter    piter, citer;
 
130
        GtkTreeStore  *model;
 
131
        gpointer       address;
 
132
        gchar         *search_paths[3], **path;
 
133
        void (*plugin_set_name)(gchar **, gchar ***);
 
134
 
 
135
        model = GTK_TREE_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(img->transition_type)));
 
136
        
 
137
        /* Fill the combo box with no transition */
 
138
        gtk_tree_store_append(model, &piter, NULL);
 
139
        gtk_tree_store_set(model, &piter, 0, NULL, 1, _("None"), 2, NULL, 3, -1, -1);
 
140
        gtk_combo_box_set_active(GTK_COMBO_BOX(img->transition_type), 0);
 
141
 
 
142
        /* Create NULL terminated array of paths that we'll be looking at */
 
143
#if PLUGINS_INSTALLED
 
144
        search_paths[0] = g_strconcat(PACKAGE_LIB_DIR,"/imagination",NULL);
 
145
#else
 
146
        search_paths[0] = g_strdup("./transitions");
 
147
#endif
 
148
        search_paths[1] = g_strconcat( g_get_home_dir(), "/.imagination/plugins", NULL );
 
149
        search_paths[2] = NULL;
 
150
 
 
151
        /* Search all paths listed in array */
 
152
        for( path = search_paths; *path; path++ )
 
153
        {
 
154
                dir = g_dir_open( *path, 0, NULL );
 
155
                if( dir == NULL )
 
156
                {
 
157
                        g_free( *path );
 
158
                        continue;
 
159
                }
 
160
                
 
161
                while( TRUE )
 
162
                {
 
163
                        transition_name = g_dir_read_name( dir );
 
164
                        if ( transition_name == NULL )
 
165
                                break;
 
166
                        
 
167
                        fname = g_build_filename( *path, transition_name, NULL );
 
168
                        module = g_module_open( fname, G_MODULE_BIND_LOCAL );
 
169
                        if( module && img_plugin_is_loaded(img, module) == FALSE )
 
170
                        {
 
171
                                /* Obtain the name from the plugin function */
 
172
                                g_module_symbol( module, "img_get_plugin_info",
 
173
                                                                 (void *)&plugin_set_name);
 
174
                                plugin_set_name( &name, &trans );
 
175
                                
 
176
                                /* Add group name to the store */
 
177
                                gtk_tree_store_append( model, &piter, NULL );
 
178
                                gtk_tree_store_set( model, &piter, 0, NULL, 1, name, 3, 0, -1 );
 
179
                                img->plugin_list = g_slist_append(img->plugin_list, module);
 
180
                                
 
181
                                /* Add transitions */
 
182
                                for( bak = trans; *trans; trans += 3 )
 
183
                                {
 
184
#if PLUGINS_INSTALLED
 
185
                                        filename =
 
186
                                                g_strdup_printf( "%s/imagination/pixmaps/imagination-%d.png",
 
187
                                                                                 DATADIR, GPOINTER_TO_INT( trans[2] ) );
 
188
#else /* PLUGINS_INSTALLED */
 
189
                                        filename =
 
190
                                                g_strdup_printf( "./pixmaps/imagination-%d.png",
 
191
                                                                                 GPOINTER_TO_INT( trans[2] ) );
 
192
#endif /* ! PLUGINS_INSTALLED */
 
193
 
 
194
                                        pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
 
195
 
 
196
                                        /* Local plugins will fail to load images from system
 
197
                                         * folder, so we'll try to load the from home folder. */
 
198
                                        if( ! pixbuf )
 
199
                                        {
 
200
                                                g_free( filename );
 
201
                                                filename =
 
202
                                                        g_strdup_printf( "%s/.imagination/pixmaps/imagination-%d.png",
 
203
                                                                                         g_get_home_dir(),
 
204
                                                                                         GPOINTER_TO_INT( trans[2] ) );
 
205
                                                pixbuf = gdk_pixbuf_new_from_file( filename, NULL );
 
206
                                        }
 
207
                                        g_free( filename );
 
208
                                        g_module_symbol( module, trans[1], &address );
 
209
                                        gtk_tree_store_append( model, &citer, &piter );
 
210
                                        gtk_tree_store_set( model, &citer, 0, pixbuf,
 
211
                                                                                                           1, trans[0],
 
212
                                                                                                           2, address,
 
213
                                                                                                           3, GPOINTER_TO_INT( trans[2] ),
 
214
                                                                                                           -1 );
 
215
                                        img->nr_transitions_loaded++;
 
216
                                }
 
217
                                g_free( bak );
 
218
                        }
 
219
                        g_free( fname );
 
220
                }
 
221
                g_free( *path );
 
222
                g_dir_close( dir );
 
223
        }
 
224
}
 
225
 
 
226
static gboolean img_plugin_is_loaded(img_window_struct *img, GModule *module)
 
227
{
 
228
        return (g_slist_find(img->plugin_list,module) != NULL);
 
229
}
 
230
 
 
231
void img_show_file_chooser(SexyIconEntry *entry, SexyIconEntryPosition icon_pos,int button,img_window_struct *img)
 
232
{
 
233
        GtkWidget *file_selector;
 
234
        gchar *dest_dir;
 
235
        gint response;
 
236
 
 
237
        file_selector = gtk_file_chooser_dialog_new (_("Please choose the slideshow project filename"),
 
238
                                                        GTK_WINDOW (img->imagination_window),
 
239
                                                        GTK_FILE_CHOOSER_ACTION_SAVE,
 
240
                                                        GTK_STOCK_CANCEL,
 
241
                                                        GTK_RESPONSE_CANCEL,
 
242
                                                        GTK_STOCK_SAVE,
 
243
                                                        GTK_RESPONSE_ACCEPT,
 
244
                                                        NULL);
 
245
 
 
246
        gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (file_selector),TRUE);
 
247
        response = gtk_dialog_run (GTK_DIALOG(file_selector));
 
248
        if (response == GTK_RESPONSE_ACCEPT)
 
249
        {
 
250
                dest_dir = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (file_selector));
 
251
                gtk_entry_set_text(GTK_ENTRY(entry),dest_dir);
 
252
                g_free(dest_dir);
 
253
        }
 
254
        gtk_widget_destroy(file_selector);
 
255
}
 
256
 
 
257
slide_struct *
 
258
img_create_new_slide( void )
 
259
{
 
260
        slide_struct    *slide = NULL;
 
261
 
 
262
        slide = g_slice_new0( slide_struct );
 
263
        if( slide )
 
264
        {
 
265
                /* Still part */
 
266
                slide->duration = 1;
 
267
 
 
268
                /* Transition */
 
269
                slide->path = g_strdup( "0" );
 
270
                slide->transition_id = -1;
 
271
                slide->speed = NORMAL;
 
272
 
 
273
                /* Ken Burns */
 
274
                slide->cur_point = -1;
 
275
 
 
276
                /* Subtitles */
 
277
                slide->anim_duration = 1;
 
278
                slide->position = IMG_SUB_POS_MIDDLE_CENTER;
 
279
                slide->placing = IMG_REL_PLACING_EXPORTED_VIDEO;
 
280
                slide->font_desc = pango_font_description_from_string( "Sans 12" );
 
281
                slide->font_color[0] = 0; /* R */
 
282
                slide->font_color[1] = 0; /* G */
 
283
                slide->font_color[2] = 0; /* B */
 
284
                slide->font_color[3] = 1; /* A */
 
285
        }
 
286
 
 
287
        return( slide );
 
288
}
 
289
 
 
290
void
 
291
img_set_slide_file_info( slide_struct *slide,
 
292
                                                 const gchar  *filename )
 
293
{
 
294
        GdkPixbufFormat *format;
 
295
        gint             width,
 
296
                                         height;
 
297
 
 
298
        format = gdk_pixbuf_get_file_info( filename, &width, &height );
 
299
 
 
300
        slide->o_filename = g_strdup( filename );
 
301
        slide->r_filename = g_strdup( filename );
 
302
        slide->angle = 0;
 
303
        
 
304
        slide->resolution = g_strdup_printf( "%d x %d", width, height );
 
305
        slide->type = gdk_pixbuf_format_get_name( format );
 
306
}
 
307
 
 
308
void
 
309
img_set_slide_gradient_info( slide_struct *slide,
 
310
                                                         gint          gradient,
 
311
                                                         gdouble      *start_color,
 
312
                                                         gdouble      *stop_color,
 
313
                                                         gdouble      *start_point,
 
314
                                                         gdouble      *stop_point )
 
315
{
 
316
        gint i;
 
317
 
 
318
        slide->gradient = gradient;
 
319
        for( i = 0; i < 3; i++ )
 
320
        {
 
321
                slide->g_start_color[i] = start_color[i];
 
322
                slide->g_stop_color[i]  = stop_color[i];
 
323
        }
 
324
        for( i = 0; i < 2; i++ )
 
325
        {
 
326
                slide->g_start_point[i] = start_point[i];
 
327
                slide->g_stop_point[i]  = stop_point[i];
 
328
        }
 
329
}
 
330
 
 
331
void
 
332
img_set_slide_still_info( slide_struct      *slide,
 
333
                                                  gint               duration,
 
334
                                                  img_window_struct *img )
 
335
{
 
336
        if( slide->duration != duration )
 
337
        {
 
338
                slide->duration = duration;
 
339
 
 
340
                if( ! img->total_dur_id )
 
341
                        img->total_dur_id =
 
342
                                g_idle_add( (GSourceFunc)img_set_total_slideshow_duration, img );
 
343
        }
 
344
}
 
345
 
 
346
void
 
347
img_set_slide_transition_info( slide_struct      *slide,
 
348
                                                           GtkListStore      *store,
 
349
                                                           GtkTreeIter       *iter,
 
350
                                                           GdkPixbuf         *pix,
 
351
                                                           const gchar       *path,
 
352
                                                           gint               transition_id,
 
353
                                                           ImgRender          render,
 
354
                                                           guint              speed,
 
355
                                                           img_window_struct *img )
 
356
{
 
357
        /* Set transition render. */
 
358
        if( path && ( slide->transition_id != transition_id ) )
 
359
        {
 
360
                if( slide->path )
 
361
                        g_free( slide->path );
 
362
 
 
363
                slide->path = g_strdup( path );
 
364
                slide->transition_id = transition_id;
 
365
                slide->render = render;
 
366
 
 
367
                gtk_list_store_set( store, iter, 2, pix, -1 );
 
368
        }
 
369
 
 
370
        if( speed && ( slide->speed != speed ) )
 
371
        {
 
372
                slide->speed = speed;
 
373
 
 
374
                if( ! img->total_dur_id )
 
375
                        img->total_dur_id =
 
376
                                g_idle_add( (GSourceFunc)img_set_total_slideshow_duration, img );
 
377
        }
 
378
}
 
379
 
 
380
void
 
381
img_set_slide_ken_burns_info( slide_struct *slide,
 
382
                                                          gint          cur_point,
 
383
                                                          gsize         length,
 
384
                                                          gdouble      *points )
 
385
{
 
386
        ImgStopPoint *point;
 
387
        gint          i,
 
388
                                  full;
 
389
 
 
390
        if( slide->no_points )
 
391
        {
 
392
                g_list_free( slide->points );
 
393
                slide->no_points = 0;
 
394
        }
 
395
 
 
396
        for( i = 0; i < length; i += 4 )
 
397
        {
 
398
                /* Create new point */
 
399
                point = g_slice_new( ImgStopPoint );
 
400
                point->time = (gint)( points[0 + i] + 0.5 );
 
401
                point->offx = points[1 + i];
 
402
                point->offy = points[2 + i];
 
403
                point->zoom = points[3 + i];
 
404
                
 
405
                /* Append it to the list */
 
406
                slide->points = g_list_append( slide->points, point );
 
407
                slide->no_points++;
 
408
        }
 
409
 
 
410
        slide->cur_point = CLAMP( cur_point, -1, slide->no_points - 1 );
 
411
 
 
412
        full = img_calc_slide_duration_points( slide->points,
 
413
                                                                                   slide->no_points );
 
414
        if( full )
 
415
                slide->duration = full;
 
416
}
 
417
 
 
418
void
 
419
img_set_slide_text_info( slide_struct      *slide,
 
420
                                                 GtkListStore      *store,
 
421
                                                 GtkTreeIter       *iter,
 
422
                                                 const gchar       *subtitle,
 
423
                                                 gint               anim_id,
 
424
                                                 gint               anim_duration,
 
425
                                                 gint               position,
 
426
                                                 gint               placing,
 
427
                                                 const gchar       *font_desc,
 
428
                                                 gdouble           *font_color,
 
429
                                                 img_window_struct *img )
 
430
{
 
431
        /* Set the slide text info parameters */
 
432
        if( store && iter )
 
433
        {
 
434
                gboolean flag;
 
435
 
 
436
                if( slide->subtitle )
 
437
                        g_free( slide->subtitle );
 
438
                slide->subtitle = g_strdup( subtitle );
 
439
 
 
440
                flag = ( subtitle ? TRUE : FALSE );
 
441
                gtk_list_store_set( store, iter, 3, flag, -1 );
 
442
        }
 
443
 
 
444
        if( ( anim_id > -1 ) && ( anim_id != slide->anim_id ) )
 
445
        {
 
446
                GtkTreeModel *model;
 
447
                gchar        *path;
 
448
                GtkTreeIter   iter;
 
449
 
 
450
                path = g_strdup_printf( "%d", anim_id );
 
451
                model = gtk_combo_box_get_model( GTK_COMBO_BOX( img->sub_anim ) );
 
452
                gtk_tree_model_get_iter_from_string( model, &iter, path );
 
453
                g_free( path );
 
454
 
 
455
                slide->anim_id = anim_id;
 
456
                gtk_tree_model_get( model, &iter, 1, &slide->anim, -1 );
 
457
 
 
458
                /* Sync timings */
 
459
                img_sync_timings( slide, img );
 
460
        }
 
461
 
 
462
        if( ( anim_duration > 0 ) && ( anim_duration != slide->anim_duration ) )
 
463
        {
 
464
                slide->anim_duration = anim_duration;
 
465
 
 
466
                /* Synchronize timings */
 
467
                img_sync_timings( slide, img );
 
468
        }
 
469
 
 
470
        if( ( position > -1 ) && ( position != slide->position ) )
 
471
                slide->position = position;
 
472
 
 
473
        if( ( placing > -1 ) && ( placing != slide->placing ) )
 
474
                slide->placing = placing;
 
475
 
 
476
        if( font_desc )
 
477
        {
 
478
                if( slide->font_desc )
 
479
                        pango_font_description_free( slide->font_desc );
 
480
                slide->font_desc = pango_font_description_from_string( font_desc );
 
481
        }
 
482
 
 
483
        if( font_color )
 
484
        {
 
485
                slide->font_color[0] = font_color[0];
 
486
                slide->font_color[1] = font_color[1];
 
487
                slide->font_color[2] = font_color[2];
 
488
                slide->font_color[3] = font_color[3];
 
489
        }
 
490
}                                                               
 
491
 
 
492
void
 
493
img_free_slide_struct( slide_struct *entry )
 
494
{
 
495
        GList *tmp;
 
496
 
 
497
        if( entry->angle != ANGLE_0 )
 
498
                g_unlink( entry->r_filename );
 
499
        g_free(entry->o_filename);
 
500
        g_free(entry->r_filename);
 
501
        g_free(entry->resolution);
 
502
        g_free(entry->type);
 
503
        
 
504
        /* Free stop point list */
 
505
        for( tmp = entry->points; tmp; tmp = g_list_next( tmp ) )
 
506
                g_slice_free( ImgStopPoint, tmp->data );
 
507
        g_list_free( entry->points );
 
508
 
 
509
        g_slice_free( slide_struct, entry );
 
510
}
 
511
 
 
512
gboolean
 
513
img_set_total_slideshow_duration( img_window_struct *img )
 
514
{
 
515
        gchar        *time;
 
516
        GtkTreeIter   iter;
 
517
        slide_struct *entry;
 
518
        GtkTreeModel *model;
 
519
 
 
520
        img->total_secs = 0;
 
521
 
 
522
        model = GTK_TREE_MODEL( img->thumbnail_model );
 
523
        if( gtk_tree_model_get_iter_first( model, &iter ) )
 
524
        {
 
525
                do
 
526
                {
 
527
                        gtk_tree_model_get( model, &iter, 1, &entry, -1 );
 
528
                        img->total_secs += entry->duration;
 
529
                        
 
530
                        if(entry->render)
 
531
                                img->total_secs += entry->speed;
 
532
                }
 
533
                while( gtk_tree_model_iter_next( model, &iter ) );
 
534
 
 
535
                /* Add time of last pseudo slide */
 
536
                if( img->final_transition.render )
 
537
                        img->total_secs += img->final_transition.speed;
 
538
        }
 
539
                
 
540
        time = img_convert_seconds_to_time(img->total_secs);
 
541
        gtk_label_set_text(GTK_LABEL (img->total_time_data),time);
 
542
        g_free(time);
 
543
 
 
544
        /* This is here only to be able to add this to idle source. */
 
545
        img->total_dur_id = 0;
 
546
        return( FALSE );
 
547
}
 
548
 
 
549
gint
 
550
img_calc_slide_duration_points( GList *list,
 
551
                                                                gint   length )
 
552
{
 
553
        GList        *tmp;
 
554
        gint          i, duration = 0;
 
555
        ImgStopPoint *point;
 
556
 
 
557
        /* If we have no points, return 0 */
 
558
        if( length == 0 )
 
559
                return( 0 );
 
560
 
 
561
        /* Calculate length */
 
562
        for( tmp = list, i = 0; i < length; tmp = g_list_next( tmp ), i++ )
 
563
        {
 
564
                point = (ImgStopPoint *)tmp->data;
 
565
                duration += point->time;
 
566
        }
 
567
 
 
568
        return( duration );
 
569
}
 
570
 
 
571
/*
 
572
 * img_scale_image:
 
573
 *
 
574
 * This function should be called for all image loading needs. It'll properly
 
575
 * scale and trim loaded images, add borders if needed and return surface or
 
576
 * pixbuf of requested size.
 
577
 *
 
578
 * If one of the size requests is 0, the other one will be calculated from
 
579
 * first one with aspect ratio calculation. If both dimensions are 0, image
 
580
 * will be loaded from disk at original size (this is mainly used for export,
 
581
 * when we want to have images at their best quality).
 
582
 *
 
583
 * Return value: TRUE if image loading succeded, FALSE otherwise.
 
584
 */
 
585
gboolean
 
586
img_scale_image( const gchar      *filename,
 
587
                                 gdouble           ratio,
 
588
                                 gint              width,
 
589
                                 gint              height,
 
590
                                 gboolean          distort,
 
591
                                 gdouble          *color,
 
592
                                 GdkPixbuf       **pixbuf,
 
593
                                 cairo_surface_t **surface )
 
594
{
 
595
        GdkPixbuf *loader;             /* Pixbuf used for loading */
 
596
        gint       i_width, i_height;  /* Image dimensions */
 
597
        gint       offset_x, offset_y; /* Offset values for borders */
 
598
        gdouble    i_ratio;            /* Export and image aspect ratios */
 
599
        gdouble    skew;               /* Transformation between ratio and
 
600
                                                                                         i_ratio */
 
601
        gboolean   transform = FALSE;  /* Flag that controls scalling */
 
602
 
 
603
        /* MAximal distortion values */
 
604
        gdouble max_stretch = 0.1280;
 
605
        gdouble max_crop    = 0.8500;
 
606
 
 
607
        /* Borderline skew values */
 
608
        gdouble max_skew = ( 1 + max_stretch ) / max_crop;
 
609
        gdouble min_skew = ( 1 - max_stretch ) * max_crop;
 
610
 
 
611
        /* Obtain information about image being loaded */
 
612
        if( ! gdk_pixbuf_get_file_info( filename, &i_width, &i_height ) )
 
613
                return( FALSE );
 
614
 
 
615
        /* How distorted images would be if we scaled them */
 
616
        i_ratio = (gdouble)i_width / i_height;
 
617
        skew = ratio / i_ratio;
 
618
 
 
619
        /* Calculationg surface dimensions.
 
620
         *
 
621
         * In order to be as flexible as possible, this function can load images at
 
622
         * various sizes, but at aspect ration that matches the aspect ratio of main
 
623
         * preview area. How size is determined? If width argument is not -1, this
 
624
         * is taken as a reference dimension from which height is calculated (if
 
625
         * height argument also present, it's ignored). If width argument is -1,
 
626
         * height is taken as a reference dimension. If both width and height are
 
627
         * -1, surface dimensions are calculated to to fit original image.
 
628
         */
 
629
        if( width > 0 )
 
630
        {
 
631
                /* Calculate height according to width */
 
632
                height = width / ratio;
 
633
        }
 
634
        else if( height > 0 )
 
635
        {
 
636
                /* Calculate width from height */
 
637
                width = height * ratio;
 
638
        }
 
639
        else
 
640
        {
 
641
                /* Load image at maximum quality
 
642
                 *
 
643
                 * If the user doesn't want to have distorted images, we create slightly
 
644
                 * bigger surface that will hold borders too.
 
645
                 *
 
646
                 * If images should be distorted, we first check if we're able to fit
 
647
                 * image without distorting it too much. If images would be largely
 
648
                 * distorted, we simply load them undistorted.
 
649
                 *
 
650
                 * If we came all the way to  here, then we're able to distort image.
 
651
                 */
 
652
                if( ( ! distort )       || /* Don't distort */
 
653
                        ( skew > max_skew ) || /* Image is too wide */
 
654
                        ( skew < min_skew )  ) /* Image is too tall */
 
655
                {
 
656
                        /* User doesn't want images to be distorted or distortion would be
 
657
                         * too intrusive. */
 
658
                        if( ratio < i_ratio )
 
659
                        {
 
660
                                /* Borders will be added on left and right */
 
661
                                width = i_width;
 
662
                                height = width / ratio;
 
663
                        }
 
664
                        else
 
665
                        {
 
666
                                /* Borders will be added on top and bottom */
 
667
                                height = i_height;
 
668
                                width = height * ratio;
 
669
                        }
 
670
                }
 
671
                else
 
672
                {
 
673
                        /* User wants images to be distorted and we're able to do it
 
674
                         * without ruining images. */
 
675
                        if( ratio < i_ratio )
 
676
                        {
 
677
                                /* Image will be distorted horizontally */
 
678
                                height = i_height;
 
679
                                width = height * ratio;
 
680
                        }
 
681
                        else
 
682
                        {
 
683
                                /* Image will be distorted vertically */
 
684
                                width = i_width;
 
685
                                height = width / ratio;
 
686
                        }
 
687
                }
 
688
        }
 
689
 
 
690
        /* Will image be disotrted?
 
691
         *
 
692
         * Conditions:
 
693
         *  - user allows us to do it
 
694
         *  - skew is in sensible range
 
695
         *  - image is not smaller than exported wideo size
 
696
         */
 
697
        transform = distort && skew < max_skew && skew > min_skew &&
 
698
                                ( i_width >= width || i_height >= height );
 
699
 
 
700
        /* Load image into pixbuf at proper size */
 
701
        if( transform )
 
702
        {
 
703
                gint lw, lh;
 
704
 
 
705
                /* Images will be loaded at slightly modified dimensions */
 
706
                if( ratio < i_ratio )
 
707
                {
 
708
                        /* Horizontal scaling */
 
709
                        lw = (gdouble)width / ( skew + 1 ) * 2;
 
710
                        lh = height;
 
711
                }
 
712
                else
 
713
                {
 
714
                        /* Vertical scaling */
 
715
                        lw = width;
 
716
                        lh = (gdouble)height * ( skew + 1 ) / 2;
 
717
                }
 
718
                loader = gdk_pixbuf_new_from_file_at_scale( filename, lw, lh,
 
719
                                                                                                        FALSE, NULL );
 
720
        }
 
721
        else
 
722
        {
 
723
                /* Simply load image into pixbuf at size */
 
724
                loader = gdk_pixbuf_new_from_file_at_size( filename, width,
 
725
                                                                                                   height, NULL );
 
726
        }
 
727
        if( ! loader )
 
728
                return( FALSE );
 
729
 
 
730
        i_width  = gdk_pixbuf_get_width( loader );
 
731
        i_height = gdk_pixbuf_get_height( loader );
 
732
 
 
733
        /* Calculate offsets */
 
734
        offset_x = ( width - i_width ) / 2;   /* CAN BE NEGATIVE!!! */
 
735
        offset_y = ( height - i_height ) / 2; /* CAN BE NEGATIVE!!! */
 
736
 
 
737
        /* Prepare output
 
738
         *
 
739
         * We can give two different output formats: cairo_surface_t and GdkPixbuf.
 
740
         */
 
741
        if( pixbuf )
 
742
        {
 
743
                /* Create new pixbuf with loaded image */
 
744
                GdkPixbuf *tmp_pix;   /* Pixbuf used for loading */
 
745
                guint32    tmp_color; /* Background color */
 
746
 
 
747
                tmp_color = ( (gint)( color[0] * 0xff ) << 24 ) |
 
748
                                        ( (gint)( color[1] * 0xff ) << 16 ) |
 
749
                                        ( (gint)( color[2] * 0xff ) <<  8 );
 
750
                tmp_pix = gdk_pixbuf_new( GDK_COLORSPACE_RGB, FALSE, 8, width, height );
 
751
                gdk_pixbuf_fill( tmp_pix, tmp_color );
 
752
                gdk_pixbuf_composite( loader, tmp_pix,
 
753
                                                          MAX( 0, offset_x ), MAX( 0, offset_y ),
 
754
                                                          MIN( i_width, width ), MIN( i_height, height ),
 
755
                                                          offset_x, offset_y, 1, 1,
 
756
                                                          GDK_INTERP_BILINEAR, 255 );
 
757
 
 
758
                *pixbuf = tmp_pix;
 
759
        }
 
760
        if( surface )
 
761
        {
 
762
                /* Paint surface with loaded image
 
763
                 * 
 
764
                 * If image cannot be scalled, transform is FALSE. In this case, just
 
765
                 * borders are added. If transform is not 0, than scale image before
 
766
                 * painting it. */
 
767
                cairo_t         *cr;       /* Cairo, used to transform image */
 
768
                cairo_surface_t *tmp_surf; /* Surface to draw on */
 
769
 
 
770
                /* Create image surface with proper dimensions */
 
771
                tmp_surf = cairo_image_surface_create( CAIRO_FORMAT_RGB24,
 
772
                                                                                           width, height );
 
773
 
 
774
                cr = cairo_create( tmp_surf );
 
775
                
 
776
                if( ! transform )
 
777
                {
 
778
                        /* Fill with background color */
 
779
                        cairo_set_source_rgb( cr, color[0], color[1], color[2] );
 
780
                        cairo_paint( cr );
 
781
                }
 
782
                
 
783
                /* Paint image */
 
784
                gdk_cairo_set_source_pixbuf( cr, loader, offset_x, offset_y );
 
785
                cairo_paint( cr );
 
786
                
 
787
                cairo_destroy( cr );
 
788
 
 
789
                /* Return surface */
 
790
                *surface = tmp_surf;
 
791
        }
 
792
 
 
793
        /* Free temporary pixbuf */
 
794
        g_object_unref( G_OBJECT( loader ) );
 
795
 
 
796
        return( TRUE );
 
797
}
 
798
 
 
799
void
 
800
img_set_project_mod_state( img_window_struct *img,
 
801
                                                   gboolean           modified )
 
802
{
 
803
        if( ( img->project_is_modified ? modified : ! modified ) )
 
804
                return;
 
805
 
 
806
        img->project_is_modified = modified;
 
807
 
 
808
        /* FIXME: Do any updates here (add "*" to window title, ...). */
 
809
}
 
810
 
 
811
void
 
812
img_sync_timings( slide_struct      *slide,
 
813
                                  img_window_struct *img )
 
814
{
 
815
        /* If times are already synchronized, return */
 
816
        if( slide->duration >= slide->anim_duration )
 
817
                return;
 
818
 
 
819
        /* Do the right thing;) */
 
820
        if( slide->no_points )
 
821
        {
 
822
                gint          diff;
 
823
                ImgStopPoint *point;
 
824
 
 
825
                /* Calculate difference that we need to accomodate */
 
826
                diff = slide->anim_duration - slide->duration;
 
827
 
 
828
                /* Elongate last point */
 
829
                point = (ImgStopPoint *)g_list_last( slide->points )->data;
 
830
                point->time += diff;
 
831
                
 
832
                /* Update Ken Burns display */
 
833
                gtk_spin_button_set_value( GTK_SPIN_BUTTON( img->ken_duration ),
 
834
                                                                   point->time );
 
835
        }
 
836
 
 
837
        /* Update display */
 
838
        gtk_spin_button_set_value( GTK_SPIN_BUTTON( img->duration ),
 
839
                                                           slide->anim_duration );
 
840
}
 
841
 
 
842
void img_select_nth_slide(img_window_struct *img, gint slide_to_select)
 
843
{
 
844
        GtkTreePath *path;
 
845
 
 
846
        gtk_icon_view_unselect_all(GTK_ICON_VIEW (img->active_icon));
 
847
        path = gtk_tree_path_new_from_indices(slide_to_select, -1);
 
848
        gtk_icon_view_set_cursor (GTK_ICON_VIEW (img->active_icon), path, NULL, FALSE);
 
849
        gtk_icon_view_select_path (GTK_ICON_VIEW (img->active_icon), path);
 
850
        gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (img->active_icon), path, FALSE, 0, 0);
 
851
        gtk_tree_path_free (path);
 
852
}
 
853
 
 
854
GdkPixbuf *
 
855
img_convert_surface_to_pixbuf( cairo_surface_t *surface )
 
856
{
 
857
        GdkPixbuf *pixbuf;
 
858
        gint       w, h, ss, sp, row, col;
 
859
        guchar    *data_s, *data_p;
 
860
 
 
861
        /* Information about surface */
 
862
        w = cairo_image_surface_get_width( surface );
 
863
        h = cairo_image_surface_get_height( surface );
 
864
        ss = cairo_image_surface_get_stride( surface );
 
865
        data_s = cairo_image_surface_get_data( surface );
 
866
 
 
867
        /* Create new pixbuf according to upper specs */
 
868
        pixbuf = gdk_pixbuf_new( GDK_COLORSPACE_RGB, FALSE, 8, w, h );
 
869
 
 
870
        /* Get info about new pixbuf */
 
871
        sp = gdk_pixbuf_get_rowstride( pixbuf );
 
872
        data_p = gdk_pixbuf_get_pixels( pixbuf );
 
873
 
 
874
        /* Copy pixels */
 
875
        for( row = 0; row < h; row++ )
 
876
        {
 
877
                for( col = 0; col < w; col++ )
 
878
                {
 
879
                        gint index_s, index_p;
 
880
 
 
881
                        index_s = row * ss + col * 4;
 
882
                        index_p = row * sp + col * 3;
 
883
 
 
884
                        data_p[index_p + 0] = data_s[index_s + 2];
 
885
                        data_p[index_p + 1] = data_s[index_s + 1];
 
886
                        data_p[index_p + 2] = data_s[index_s + 0];
 
887
                }
 
888
        }
 
889
 
 
890
        return( pixbuf );
 
891
}
 
892
 
 
893
gboolean
 
894
img_scale_gradient( gint              gradient,
 
895
                                        gdouble          *p_start,
 
896
                                        gdouble          *p_stop,
 
897
                                        gdouble          *c_start,
 
898
                                        gdouble          *c_stop,
 
899
                                        gint              width,
 
900
                                        gint              height,
 
901
                                        GdkPixbuf       **pixbuf,
 
902
                                        cairo_surface_t **surface )
 
903
{
 
904
        cairo_surface_t *sf;
 
905
        cairo_t         *cr;
 
906
        cairo_pattern_t *pat;
 
907
        gdouble          diffx, diffy, radius;
 
908
 
 
909
        sf = cairo_image_surface_create( CAIRO_FORMAT_RGB24, width, height );
 
910
        cr = cairo_create( sf );
 
911
 
 
912
        switch( gradient )
 
913
        {
 
914
                case 0: /* Solid color */
 
915
                        cairo_set_source_rgb( cr, c_start[0], c_start[1], c_start[2] );
 
916
                        cairo_paint( cr );
 
917
                        break;
 
918
 
 
919
                case 1: /* Linear gradient */
 
920
                        pat = cairo_pattern_create_linear( p_start[0] * width,
 
921
                                                                                           p_start[1] * height,
 
922
                                                                                           p_stop[0] * width,
 
923
                                                                                           p_stop[1] * height );
 
924
                        cairo_pattern_add_color_stop_rgb( pat, 0, c_start[0],
 
925
                                                                                          c_start[1], c_start[2] );
 
926
                        cairo_pattern_add_color_stop_rgb( pat, 1, c_stop[0],
 
927
                                                                                          c_stop[1], c_stop[2] );
 
928
                        cairo_set_source( cr, pat );
 
929
                        cairo_paint( cr );
 
930
                        cairo_pattern_destroy( pat );
 
931
                        break;
 
932
 
 
933
                case 2: /* Radial gradient */
 
934
                        diffx = ABS( p_start[0] - p_stop[0] ) * width;
 
935
                        diffy = ABS( p_start[1] - p_stop[1] ) * height;
 
936
                        radius = sqrt( pow( diffx, 2 ) + pow( diffy, 2 ) );
 
937
 
 
938
                        pat = cairo_pattern_create_radial( p_start[0] * width,
 
939
                                                                                           p_start[1] * height, 0,
 
940
                                                                                           p_start[0] * width,
 
941
                                                                                           p_start[1] * height, radius );
 
942
                        cairo_pattern_add_color_stop_rgb( pat, 0, c_start[0],
 
943
                                                                                          c_start[1], c_start[2] );
 
944
                        cairo_pattern_add_color_stop_rgb( pat, 1, c_stop[0],
 
945
                                                                                          c_stop[1], c_stop[2] );
 
946
                        cairo_set_source( cr, pat );
 
947
                        cairo_paint( cr );
 
948
                        cairo_pattern_destroy( pat );
 
949
                        break;
 
950
        }
 
951
        cairo_destroy( cr );
 
952
 
 
953
        if( surface )
 
954
                *surface = sf;
 
955
        else
 
956
        {
 
957
                *pixbuf = img_convert_surface_to_pixbuf( sf );
 
958
                cairo_surface_destroy( sf );
 
959
        }
 
960
 
 
961
        return( TRUE );
 
962
}
 
963