1 /*
2  *  Copyright (c) 2009 Giuseppe Torelli <colossus73@gmail.com>
3  *  Copyright (c) 2009 Tadej Borovšak 	<tadeboro@gmail.com>
4  *  Copyright (c) 2011 Robert Chéramy   <robert@cheramy.net>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License,or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not,write to the Free Software
18  *  Foundation,Inc.,59 Temple Place - Suite 330,Boston,MA 02111-1307,USA.
19  *
20  */
21 
22 #include "callbacks.h"
23 #include "export.h"
24 #include <math.h>
25 #include <sys/stat.h>
26 
27 /* Internal structure, used for creating empty slide */
28 typedef struct _ImgEmptySlide ImgEmptySlide;
29 struct _ImgEmptySlide
30 {
31 	/* Values */
32 	gdouble c_start[3];  /* Start color */
33 	gdouble c_stop[3];   /* Stop color */
34 	gdouble pl_start[2]; /* Linear start point */
35 	gdouble pl_stop[2];  /* Linear stop point */
36 	gdouble pr_start[2]; /* Radial start point */
37 	gdouble pr_stop[2];  /* Radial stop point */
38 	gint    drag;        /* Are we draging point:
39 							  0 - no
40 							  1 - start point
41 							  2 - stop point */
42 	gint    gradient;    /* Gradient type:
43 						      0 - solid color
44 							  1 - linear
45 							  2 - radial */
46 
47 	/* Widgets */
48 	GtkWidget *color2;
49 	GtkWidget *preview;
50 	GtkWidget *radio[3];
51 };
52 
53 static void img_file_chooser_add_preview(img_window_struct *);
54 static void img_update_preview_file_chooser(GtkFileChooser *,img_window_struct *);
55 static gboolean img_transition_timeout(img_window_struct *);
56 static gboolean img_still_timeout(img_window_struct *);
57 static void img_swap_toolbar_images( img_window_struct *, gboolean);
58 static void img_clean_after_preview(img_window_struct *);
59 static void img_about_dialog_activate_link(GtkAboutDialog * , const gchar *, gpointer );
60 static GdkPixbuf *img_rotate_pixbuf( GdkPixbuf *, GtkProgressBar *, ImgAngle );
61 static void img_rotate_selected_slides( img_window_struct *, gboolean );
62 
63 static void
64 img_image_area_change_zoom( gdouble            step,
65 							gboolean           reset,
66 							img_window_struct *img );
67 
68 static void
69 img_overview_change_zoom( gdouble            step,
70 						  gboolean           reset,
71 						  img_window_struct *img );
72 
73 static void
74 img_gradient_toggled( GtkToggleButton *button,
75 					  ImgEmptySlide   *slide );
76 
77 static void
78 img_gradient_color_set( GtkColorButton *button,
79 						ImgEmptySlide  *slide );
80 
81 static gboolean
82 img_gradient_expose( GtkWidget      *widget,
83 					 GdkEventExpose *expose,
84 					 ImgEmptySlide  *slide );
85 
86 static gboolean
87 img_gradient_press( GtkWidget      *widget,
88 					GdkEventButton *button,
89 					ImgEmptySlide  *slide );
90 
91 static gboolean
92 img_gradient_release( GtkWidget      *widget,
93 					  GdkEventButton *button,
94 					  ImgEmptySlide  *slide );
95 
96 static gboolean
97 img_gradient_move( GtkWidget      *widget,
98 				   GdkEventMotion *motion,
99 				   ImgEmptySlide  *slide );
100 
101 
img_set_window_title(img_window_struct * img,gchar * text)102 void img_set_window_title(img_window_struct *img, gchar *text)
103 {
104 	gchar *title = NULL;
105 	static gchar version[] = VERSION "-" REVISION;
106 
107 	if (text == NULL)
108 	{
109 		title = g_strconcat("Imagination ", strcmp(REVISION, "-1") == 0 ? VERSION : version, NULL);
110 		gtk_window_set_title (GTK_WINDOW (img->imagination_window), title);
111 		g_free(title);
112 	}
113 	else
114 	{
115 		title = g_strconcat(text, " - Imagination ", strcmp(REVISION, "-1") == 0 ? VERSION : version, NULL);
116 		gtk_window_set_title (GTK_WINDOW (img->imagination_window), title);
117 		g_free(title);
118 	}
119 }
120 
img_new_slideshow(GtkMenuItem * item,img_window_struct * img_struct)121 void img_new_slideshow(GtkMenuItem *item,img_window_struct *img_struct)
122 {
123     if (img_struct->project_is_modified)
124         if (GTK_RESPONSE_OK != img_ask_user_confirmation(img_struct, _("You didn't save your slideshow yet. Are you sure you want to close it?")))
125             return;
126 	img_close_slideshow(GTK_WIDGET(item), img_struct);
127     img_new_slideshow_settings_dialog(img_struct, FALSE);
128 }
129 
img_project_properties(GtkMenuItem * item,img_window_struct * img_struct)130 void img_project_properties(GtkMenuItem *item, img_window_struct *img_struct)
131 {
132 	img_new_slideshow_settings_dialog(img_struct, TRUE);
133 }
134 
img_add_slides_thumbnails(GtkMenuItem * item,img_window_struct * img)135 void img_add_slides_thumbnails(GtkMenuItem *item, img_window_struct *img)
136 {
137 	GSList	*slides = NULL, *bak;
138 	GdkPixbuf *thumb;
139 	GtkTreeIter iter;
140 	slide_struct *slide_info;
141 	gint slides_cnt = 0, actual_slides = 0;
142 
143 	slides = img_import_slides_file_chooser(img);
144 
145 	if (slides == NULL)
146 		return;
147 
148 	actual_slides = img->slides_nr;
149 	img->slides_nr += g_slist_length(slides);
150 	gtk_widget_show(img->progress_bar);
151 
152 	/* Remove model from thumbnail iconview for efficiency */
153 	g_object_ref( G_OBJECT( img->thumbnail_model ) );
154 	gtk_icon_view_set_model( GTK_ICON_VIEW( img->thumbnail_iconview ), NULL );
155 	gtk_icon_view_set_model( GTK_ICON_VIEW( img->over_icon ), NULL );
156 
157 	bak = slides;
158 	while (slides)
159 	{
160 		if( img_scale_image( slides->data, img->video_ratio, 88, 0,
161 							 img->distort_images, img->background_color,
162 							 &thumb, NULL ) )
163 		{
164 			slide_info = img_create_new_slide();
165 			if (slide_info)
166 			{
167 				img_set_slide_file_info( slide_info, slides->data );
168 				gtk_list_store_append (img->thumbnail_model,&iter);
169 				gtk_list_store_set (img->thumbnail_model, &iter, 0, thumb,
170 																 1, slide_info,
171 																 2, NULL,
172 																 3, FALSE,
173 																 -1);
174 				g_object_unref (thumb);
175 				slides_cnt++;
176 			}
177 			g_free(slides->data);
178 		}
179 		img_increase_progressbar(img, slides_cnt);
180 		slides = slides->next;
181 	}
182 	gtk_widget_hide(img->progress_bar);
183 	g_slist_free(bak);
184 	img_set_total_slideshow_duration(img);
185 	img_set_statusbar_message(img,0);
186 	img->project_is_modified = TRUE;
187 
188 	gtk_icon_view_set_model( GTK_ICON_VIEW( img->thumbnail_iconview ),
189 							 GTK_TREE_MODEL( img->thumbnail_model ) );
190 	gtk_icon_view_set_model( GTK_ICON_VIEW( img->over_icon ),
191 							 GTK_TREE_MODEL( img->thumbnail_model ) );
192 	g_object_unref( G_OBJECT( img->thumbnail_model ) );
193 
194 	/* Select the first slide */
195 	if (actual_slides == 0)
196 		img_goto_first_slide(NULL, img);
197 
198 	/* Select the first loaded slide if a previous set of slides was loaded */
199 	else
200 		img_select_nth_slide(img, actual_slides);
201 }
202 
img_increase_progressbar(img_window_struct * img,gint nr)203 void img_increase_progressbar(img_window_struct *img, gint nr)
204 {
205 	gchar *message;
206 	gdouble percent;
207 
208 	percent = (gdouble)nr / img->slides_nr;
209 	gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (img->progress_bar), percent);
210 	message = g_strdup_printf( _("Please wait, importing image %d out of %d"),
211 							   nr, img->slides_nr );
212 	gtk_statusbar_push(GTK_STATUSBAR(img->statusbar), img->context_id, message);
213 	g_free(message);
214 
215 	while (gtk_events_pending())
216 		gtk_main_iteration();
217 }
218 
img_remove_audio_files(GtkWidget * widget,img_window_struct * img)219 void img_remove_audio_files (GtkWidget *widget, img_window_struct *img)
220 {
221 	GtkTreeSelection *sel;
222 	GtkTreePath *path;
223 	GtkTreeIter iter;
224 	GList *rr_list = NULL;
225 	GList *node;
226 	gchar *time;
227 	gint secs;
228 
229 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(img->music_file_treeview));
230 	gtk_tree_selection_selected_foreach(sel, (GtkTreeSelectionForeachFunc) img_remove_foreach_func, &rr_list);
231 
232 	for (node = rr_list; node != NULL; node = node->next)
233 	{
234 		path = gtk_tree_row_reference_get_path((GtkTreeRowReference *) node->data);
235 		if (path)
236 	    {
237 			if (gtk_tree_model_get_iter(GTK_TREE_MODEL(img->music_file_liststore), &iter, path))
238 			{
239                 gtk_tree_model_get(GTK_TREE_MODEL(img->music_file_liststore), &iter, 3, &secs, -1);
240 				gtk_list_store_remove(img->music_file_liststore, &iter);
241 			}
242 			gtk_tree_path_free(path);
243 		}
244 		img->total_music_secs -= secs;
245 	}
246 	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(img->music_file_liststore), &iter) == FALSE)
247 	{
248         img_play_stop_selected_file(NULL, img);
249 		gtk_widget_set_sensitive (img->remove_audio_button, FALSE);
250 		gtk_widget_set_sensitive (img->play_audio_button, FALSE);
251 		gtk_label_set_text(GTK_LABEL(img->music_time_data), "");
252 	}
253 	else
254 	{
255 		time = img_convert_seconds_to_time(img->total_music_secs);
256 		gtk_label_set_text(GTK_LABEL(img->music_time_data), time);
257 		g_free(time);
258 	}
259 	g_list_foreach(rr_list, (GFunc) gtk_tree_row_reference_free, NULL);
260 	g_list_free(rr_list);
261 }
262 
img_remove_foreach_func(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,GList ** rowref_list)263 void img_remove_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **rowref_list)
264 {
265 	GtkTreeRowReference *rowref;
266 
267 	rowref = gtk_tree_row_reference_new(model, path);
268 	*rowref_list = g_list_append(*rowref_list, rowref);
269 }
270 
img_select_audio_files_to_add(GtkMenuItem * button,img_window_struct * img)271 void img_select_audio_files_to_add ( GtkMenuItem* button, img_window_struct *img)
272 {
273 	GtkFileFilter *audio_filter, *all_files_filter;
274 	GtkWidget *fs;
275 	GSList *files = NULL;
276 	gint response;
277 	gchar *time = NULL;
278 
279 	fs = gtk_file_chooser_dialog_new( _("Import audio files, use CTRL key "
280 										"for multiple select"),
281 									  GTK_WINDOW (img->imagination_window),
282 									  GTK_FILE_CHOOSER_ACTION_OPEN,
283 									  GTK_STOCK_CANCEL,
284 									  GTK_RESPONSE_CANCEL,
285 									  GTK_STOCK_OPEN,
286 									  GTK_RESPONSE_ACCEPT,
287 									  NULL );
288 
289 	/* only audio files filter */
290 	audio_filter = gtk_file_filter_new ();
291 	gtk_file_filter_set_name (audio_filter, _("All audio files") );
292 	gtk_file_filter_add_pattern (audio_filter, "*.wav");
293 	gtk_file_filter_add_pattern (audio_filter, "*.mp3");
294 	gtk_file_filter_add_pattern (audio_filter, "*.ogg");
295 	gtk_file_filter_add_pattern (audio_filter, "*.flac");
296 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (fs), audio_filter);
297 
298 	/* All files filter */
299 	all_files_filter = gtk_file_filter_new ();
300 	gtk_file_filter_set_name(all_files_filter, _("All files"));
301 	gtk_file_filter_add_pattern(all_files_filter, "*");
302 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fs), all_files_filter);
303 
304 	gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (fs), TRUE);
305 
306 	response = gtk_dialog_run (GTK_DIALOG (fs));
307 	if (response == GTK_RESPONSE_ACCEPT)
308 	{
309 		files = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (fs));
310 		g_slist_foreach( files, (GFunc) img_add_audio_files, img);
311 	}
312 	if (files != NULL)
313 	{
314 		g_slist_foreach(files, (GFunc) g_free, NULL);
315 		g_slist_free (files);
316 	}
317 
318 	/* Update incompatibilities display */
319 	img_update_inc_audio_display( img );
320 
321 	time = img_convert_seconds_to_time(img->total_music_secs);
322 	gtk_label_set_text(GTK_LABEL(img->music_time_data), time);
323 	g_free(time);
324 
325 	gtk_widget_destroy (fs);
326 }
327 
img_add_audio_files(gchar * filename,img_window_struct * img)328 void img_add_audio_files (gchar *filename, img_window_struct *img)
329 {
330 	GtkTreeIter iter;
331 	gchar *path, *file, *time;
332 	gint secs;
333 
334 	path = g_path_get_dirname(filename);
335 	file = g_path_get_basename(filename);
336 	time = img_get_audio_length(img, filename, &secs);
337 
338 	if (time != NULL)
339 	{
340 		gtk_list_store_append(img->music_file_liststore, &iter);
341 		gtk_list_store_set (img->music_file_liststore, &iter, 0, path, 1, file, 2, time, 3, secs, -1);
342 
343 		g_free(time);
344 	}
345 	g_free(path);
346 	g_free(file);
347 }
348 
img_import_slides_file_chooser(img_window_struct * img)349 GSList *img_import_slides_file_chooser(img_window_struct *img)
350 {
351 	GtkFileFilter *all_images_filter, *all_files_filter;
352 	GSList *slides = NULL;
353 	int response;
354 
355 	img->import_slide_chooser =
356 		gtk_file_chooser_dialog_new( _("Import images, use SHIFT key for "
357 									   "multiple select"),
358 									 GTK_WINDOW (img->imagination_window),
359 									 GTK_FILE_CHOOSER_ACTION_OPEN,
360 									 GTK_STOCK_CANCEL,
361 									 GTK_RESPONSE_CANCEL,
362 									 GTK_STOCK_OPEN,
363 									 GTK_RESPONSE_ACCEPT,
364 									 NULL);
365 	img_file_chooser_add_preview(img);
366 
367 	/* Image files filter */
368 	all_images_filter = gtk_file_filter_new ();
369 	gtk_file_filter_set_name(all_images_filter,_("All image files"));
370 	gtk_file_filter_add_pixbuf_formats( all_images_filter );
371 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(img->import_slide_chooser),all_images_filter);
372 
373 	/* All files filter */
374 	all_files_filter = gtk_file_filter_new ();
375 	gtk_file_filter_set_name(all_files_filter,_("All files"));
376 	gtk_file_filter_add_pattern(all_files_filter,"*");
377 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(img->import_slide_chooser),all_files_filter);
378 
379 	gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(img->import_slide_chooser),TRUE);
380 	if (img->current_dir)
381 		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(img->import_slide_chooser),img->current_dir);
382 	response = gtk_dialog_run (GTK_DIALOG(img->import_slide_chooser));
383 	if (response == GTK_RESPONSE_ACCEPT)
384 	{
385 		slides = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(img->import_slide_chooser));
386 		if (img->current_dir)
387 			g_free(img->current_dir);
388 		img->current_dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(img->import_slide_chooser));
389 	}
390 	gtk_widget_destroy (img->import_slide_chooser);
391 	return slides;
392 }
393 
img_free_allocated_memory(img_window_struct * img_struct)394 void img_free_allocated_memory(img_window_struct *img_struct)
395 {
396 	GtkTreeModel *model;
397 	GtkTreeIter iter;
398 	slide_struct *entry;
399 
400 	/* Free the memory allocated the single slides one by one */
401 	if (img_struct->slides_nr)
402 	{
403 		model = GTK_TREE_MODEL( img_struct->thumbnail_model );
404 
405 		gtk_tree_model_get_iter_first(model,&iter);
406 		do
407 		{
408 			gtk_tree_model_get(model, &iter,1,&entry,-1);
409 			img_free_slide_struct( entry );
410 			img_struct->slides_nr--;
411 		}
412 		while (gtk_tree_model_iter_next (model,&iter));
413 		g_signal_handlers_block_by_func((gpointer)img_struct->thumbnail_iconview, (gpointer)img_iconview_selection_changed, img_struct);
414 		g_signal_handlers_block_by_func((gpointer)img_struct->over_icon, (gpointer)img_iconview_selection_changed, img_struct);
415 		gtk_list_store_clear(GTK_LIST_STORE(img_struct->thumbnail_model));
416 		g_signal_handlers_unblock_by_func((gpointer)img_struct->thumbnail_iconview, (gpointer)img_iconview_selection_changed, img_struct);
417 		g_signal_handlers_unblock_by_func((gpointer)img_struct->over_icon, (gpointer)img_iconview_selection_changed, img_struct);
418 	}
419 
420 	/* Unlink the possible created rotated pictures and free the GSlist */
421 	/* NOTE: This is now done by img_free_slide_struct function */
422 
423 	/* Delete the audio files in the liststore */
424 	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(img_struct->music_file_liststore), &iter))
425 	{
426 		gtk_list_store_clear(img_struct->music_file_liststore);
427 		img_struct->total_music_secs = 0;
428 		gtk_label_set_text(GTK_LABEL(img_struct->music_time_data), "");
429 	}
430 
431 	/* Free gchar pointers */
432 	if (img_struct->current_dir)
433 	{
434 		g_free(img_struct->current_dir);
435 		img_struct->current_dir = NULL;
436 	}
437 
438 	if (img_struct->project_current_dir)
439     {
440         g_free(img_struct->project_current_dir);
441         img_struct->project_current_dir = NULL;
442     }
443 
444 	if (img_struct->project_filename)
445 	{
446 		g_free(img_struct->project_filename);
447 		img_struct->project_filename = NULL;
448 	}
449 }
450 
img_ask_user_confirmation(img_window_struct * img_struct,gchar * msg)451 gint img_ask_user_confirmation(img_window_struct *img_struct, gchar *msg)
452 {
453 	GtkWidget *dialog;
454 	gint response;
455 
456 	dialog = gtk_message_dialog_new(GTK_WINDOW(img_struct->imagination_window),GTK_DIALOG_MODAL,GTK_MESSAGE_QUESTION,GTK_BUTTONS_OK_CANCEL, "%s.", msg);
457 	gtk_window_set_title(GTK_WINDOW(dialog),"Imagination");
458 	response = gtk_dialog_run (GTK_DIALOG (dialog));
459 	gtk_widget_destroy (GTK_WIDGET (dialog));
460 	return response;
461 }
462 
img_quit_application(GtkWidget * widget,GdkEvent * event,img_window_struct * img_struct)463 gboolean img_quit_application(GtkWidget *widget, GdkEvent *event, img_window_struct *img_struct)
464 {
465 	gint response;
466 
467 	if (img_struct->project_is_modified)
468 	{
469 		response = img_ask_user_confirmation( img_struct, _("You didn't save your slideshow yet. Are you sure you want to close it?"));
470 		if (response != GTK_RESPONSE_OK)
471 			return TRUE;
472 	}
473 	if( img_save_window_settings( img_struct ) )
474 		return( TRUE );
475 	img_free_allocated_memory(img_struct);
476 
477 	/* Unloads the plugins */
478 	g_slist_foreach(img_struct->plugin_list,(GFunc)g_module_close,NULL);
479 	g_slist_free(img_struct->plugin_list);
480 
481 	return FALSE;
482 }
483 
img_file_chooser_add_preview(img_window_struct * img_struct)484 static void img_file_chooser_add_preview(img_window_struct *img_struct)
485 {
486 	GtkWidget *vbox;
487 
488 	vbox = gtk_vbox_new (FALSE, 5);
489 	gtk_container_set_border_width (GTK_CONTAINER(vbox), 10);
490 
491 	img_struct->preview_image = gtk_image_new ();
492 
493 	img_struct->dim_label  = gtk_label_new (NULL);
494 	img_struct->size_label = gtk_label_new (NULL);
495 
496 	gtk_box_pack_start (GTK_BOX (vbox), img_struct->preview_image, FALSE, TRUE, 0);
497 	gtk_box_pack_start (GTK_BOX (vbox), img_struct->dim_label, FALSE, TRUE, 0);
498 	gtk_box_pack_start (GTK_BOX (vbox), img_struct->size_label, FALSE, TRUE, 0);
499 	gtk_widget_show_all (vbox);
500 
501 	gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER(img_struct->import_slide_chooser), vbox);
502 	gtk_file_chooser_set_preview_widget_active (GTK_FILE_CHOOSER(img_struct->import_slide_chooser), FALSE);
503 
504 	g_signal_connect (img_struct->import_slide_chooser, "update-preview",G_CALLBACK (img_update_preview_file_chooser), img_struct);
505 }
506 
img_update_preview_file_chooser(GtkFileChooser * file_chooser,img_window_struct * img_struct)507 static void	img_update_preview_file_chooser(GtkFileChooser *file_chooser,img_window_struct *img_struct)
508 {
509 	gchar *filename,*size;
510 	gboolean has_preview = FALSE;
511 	gint width,height;
512 	GdkPixbuf *pixbuf;
513 	GdkPixbufFormat *pixbuf_format;
514 
515 	filename = gtk_file_chooser_get_filename(file_chooser);
516 	if (filename == NULL)
517 	{
518 		gtk_file_chooser_set_preview_widget_active (file_chooser, has_preview);
519 		return;
520 	}
521 	pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, 93, 70, TRUE, NULL);
522 	has_preview = (pixbuf != NULL);
523 	if (has_preview)
524 	{
525 		pixbuf_format = gdk_pixbuf_get_file_info(filename,&width,&height);
526 		gtk_image_set_from_pixbuf (GTK_IMAGE(img_struct->preview_image), pixbuf);
527 		g_object_unref (pixbuf);
528 
529 		size = g_strdup_printf(ngettext("%d x %d pixels", "%d x %d pixels", height),width,height);
530 		gtk_label_set_text(GTK_LABEL(img_struct->dim_label),size);
531 		g_free(size);
532 	}
533 	g_free(filename);
534 	gtk_file_chooser_set_preview_widget_active (file_chooser, has_preview);
535 }
536 
img_delete_selected_slides(GtkMenuItem * item,img_window_struct * img_struct)537 void img_delete_selected_slides(GtkMenuItem *item,img_window_struct *img_struct)
538 {
539 	GList *selected, *bak;
540 	GtkTreeIter iter;
541 	GtkTreeModel *model;
542 	slide_struct *entry;
543 
544 	model =	GTK_TREE_MODEL( img_struct->thumbnail_model );
545 
546 	selected = gtk_icon_view_get_selected_items(GTK_ICON_VIEW(img_struct->active_icon));
547 	if (selected == NULL)
548 		return;
549 
550 	/* Free the slide struct for each slide and remove it from the iconview */
551 	bak = selected;
552 	g_signal_handlers_block_by_func( (gpointer)img_struct->thumbnail_iconview,
553 									 (gpointer)img_iconview_selection_changed,
554 									 img_struct );
555 	g_signal_handlers_block_by_func( (gpointer)img_struct->over_icon,
556 									 (gpointer)img_iconview_selection_changed,
557 									 img_struct );
558 	while (selected)
559 	{
560 		gtk_tree_model_get_iter(model, &iter,selected->data);
561 		gtk_tree_model_get(model, &iter,1,&entry,-1);
562 		img_free_slide_struct( entry );
563 		gtk_list_store_remove(GTK_LIST_STORE(img_struct->thumbnail_model),&iter);
564 		img_struct->slides_nr--;
565 		selected = selected->next;
566 	}
567 	g_signal_handlers_unblock_by_func( (gpointer)img_struct->thumbnail_iconview,
568 									   (gpointer)img_iconview_selection_changed,
569 									   img_struct );
570 	g_signal_handlers_unblock_by_func( (gpointer)img_struct->over_icon,
571 									   (gpointer)img_iconview_selection_changed,
572 									   img_struct );
573 	g_list_foreach (bak, (GFunc)gtk_tree_path_free, NULL);
574 	g_list_free(bak);
575 
576 	img_set_statusbar_message(img_struct,0);
577 	cairo_surface_destroy( img_struct->current_image );
578 	img_struct->current_image = NULL;
579 	gtk_widget_queue_draw( img_struct->image_area );
580 	img_struct->project_is_modified = TRUE;
581 	img_iconview_selection_changed(GTK_ICON_VIEW(img_struct->active_icon),img_struct);
582 }
583 
584 void
img_rotate_slides_left(GtkWidget * widget,img_window_struct * img)585 img_rotate_slides_left( GtkWidget         *widget,
586 						img_window_struct *img )
587 {
588 	img_rotate_selected_slides( img, TRUE );
589 }
590 
591 void
img_rotate_slides_right(GtkWidget * widget,img_window_struct * img)592 img_rotate_slides_right( GtkWidget         *widget,
593 						 img_window_struct *img )
594 {
595 	img_rotate_selected_slides( img, FALSE );
596 }
597 
598 static void
img_rotate_selected_slides(img_window_struct * img,gboolean clockwise)599 img_rotate_selected_slides( img_window_struct *img,
600 							gboolean           clockwise )
601 {
602 	GtkTreeModel *model;
603 	GtkTreeIter   iter;
604 	GList        *selected,
605 				 *bak;
606 	GdkPixbuf    *thumb;
607 	slide_struct *info_slide;
608 
609 	/* Obtain the selected slideshow filename */
610 	model = GTK_TREE_MODEL( img->thumbnail_model );
611 	selected = gtk_icon_view_get_selected_items(
612 					GTK_ICON_VIEW( img->active_icon ) );
613 
614 	if( selected == NULL)
615 		return;
616 
617 	gtk_widget_show(img->progress_bar);
618 
619 	bak = selected;
620 	while (selected)
621 	{
622 		ImgAngle angle;
623 
624 		gtk_tree_model_get_iter( model, &iter, selected->data );
625 		gtk_tree_model_get( model, &iter, 1, &info_slide, -1 );
626 
627 		angle = ( info_slide->angle + ( clockwise ? 1 : -1 ) ) % 4;
628 		img_rotate_slide( info_slide, angle, GTK_PROGRESS_BAR( img->progress_bar ) );
629 
630 		/* Display the rotated image in thumbnails iconview */
631 		img_scale_image( info_slide->r_filename, img->video_ratio, 88, 0,
632 						 img->distort_images, img->background_color,
633 						 &thumb, NULL );
634 		gtk_list_store_set( img->thumbnail_model, &iter, 0, thumb, -1 );
635 		selected = selected->next;
636 	}
637 	gtk_widget_hide(img->progress_bar);
638 	g_list_foreach (bak, (GFunc)gtk_tree_path_free, NULL);
639 	g_list_free(bak);
640 
641 	/* If no slide is selected currently, simply return */
642 	if( ! img->current_slide )
643 		return;
644 
645 	cairo_surface_destroy( img->current_image );
646 
647 	/* Respect quality settings */
648 	if( img->low_quality )
649 		img_scale_image( img->current_slide->r_filename, img->video_ratio,
650 						 0, img->video_size[1], img->distort_images,
651 						 img->background_color, NULL, &img->current_image );
652 	else
653 		img_scale_image( img->current_slide->r_filename, img->video_ratio,
654 						 0, 0, img->distort_images,
655 						 img->background_color, NULL, &img->current_image );
656 
657 	gtk_widget_queue_draw( img->image_area );
658 }
659 
660 /* Rotate clockwise */
img_rotate_pixbuf(GdkPixbuf * original,GtkProgressBar * progress,ImgAngle angle)661 static GdkPixbuf *img_rotate_pixbuf( GdkPixbuf      *original,
662 									 GtkProgressBar *progress,
663 									 ImgAngle        angle )
664 {
665 	GdkPixbuf     *new;
666 	gint           w, h, r1, r2, channels, bps;
667 	GdkColorspace  colorspace;
668 	gboolean       alpha;
669 	guchar        *pixels1, *pixels2;
670 	gint           i, j;
671 
672 	/* Get data from source */
673 	g_object_get( G_OBJECT( original ), "width", &w,
674 										"height", &h,
675 										"rowstride", &r1,
676 										"n_channels", &channels,
677 										"bits_per_sample", &bps,
678 										"colorspace", &colorspace,
679 										"has_alpha", &alpha,
680 										"pixels", &pixels1,
681 										NULL );
682 
683 	switch( angle )
684 	{
685 		case ANGLE_0:
686 			g_object_ref( G_OBJECT( original ) );
687 			new = original;
688 			break;
689 
690 		case ANGLE_90:
691 			/* Create new rotated image */
692 			new = gdk_pixbuf_new( colorspace, alpha, bps, h, w );
693 			g_object_get( G_OBJECT( new ), "rowstride", &r2,
694 										   "pixels", &pixels2,
695 										   NULL );
696 
697 			/* Copy data, applying transormation along the way */
698 			for( j = 0; j < h; j++ )
699 			{
700 				for( i = 0; i < w; i++ )
701 				{
702 					int source = i * channels + r1 * j;
703 					int dest   = j * channels + r2 * ( w - i - 1 );
704 					int n;
705 
706 					for( n = 0; n < channels; n++ )
707 						pixels2[dest + n] = pixels1[source + n];
708 				}
709 
710 				if( j % 100 )
711 					continue;
712 
713 				/* Update progress bar */
714 				gtk_progress_bar_set_fraction( progress, (gdouble)( j + 1 ) / h );
715 				while( gtk_events_pending() )
716 					gtk_main_iteration();
717 			}
718 			break;
719 
720 		case ANGLE_180:
721 			/* Create new rotated image */
722 			new = gdk_pixbuf_new( colorspace, alpha, bps, w, h );
723 			g_object_get( G_OBJECT( new ), "rowstride", &r2,
724 										   "pixels", &pixels2,
725 										   NULL );
726 
727 			/* Copy data, applying transormation along the way */
728 			for( j = 0; j < h; j++ )
729 			{
730 				for( i = 0; i < w; i++ )
731 				{
732 					int source = i * channels + r1 * j;
733 					int dest   = ( w - i - 1 ) * channels + r2 * ( h - j - 1 );
734 					int n;
735 
736 					for( n = 0; n < channels; n++ )
737 						pixels2[dest + n] = pixels1[source + n];
738 				}
739 
740 				if( j % 100 )
741 					continue;
742 
743 				/* Update progress bar */
744 				gtk_progress_bar_set_fraction( progress, (gdouble)( j + 1 ) / h );
745 				while( gtk_events_pending() )
746 					gtk_main_iteration();
747 			}
748 			break;
749 
750 		case ANGLE_270:
751 			/* Create new rotated image */
752 			new = gdk_pixbuf_new( colorspace, alpha, bps, h, w );
753 			g_object_get( G_OBJECT( new ), "rowstride", &r2,
754 										   "pixels", &pixels2,
755 										   NULL );
756 
757 			/* Copy data, applying transormation along the way */
758 			for( j = 0; j < h; j++ )
759 			{
760 				for( i = 0; i < w; i++ )
761 				{
762 					int source = i * channels + r1 * j;
763 					int dest   = ( h - j - 1 ) * channels + r2 * i;
764 					int n;
765 
766 					for( n = 0; n < channels; n++ )
767 						pixels2[dest + n] = pixels1[source + n];
768 				}
769 
770 				if( j % 100 )
771 					continue;
772 
773 				/* Update progress bar */
774 				gtk_progress_bar_set_fraction( progress, (gdouble)( j + 1 ) / h );
775 				while( gtk_events_pending() )
776 					gtk_main_iteration();
777 			}
778 			break;
779 	}
780 
781 	return( new );
782 }
783 
img_show_about_dialog(GtkMenuItem * item,img_window_struct * img_struct)784 void img_show_about_dialog (GtkMenuItem *item,img_window_struct *img_struct)
785 {
786 	static GtkWidget *about = NULL;
787 	static gchar version[] = VERSION "-" REVISION;
788     const char *authors[] = {"\nDevelopers:\nGiuseppe Torelli <colossus73@gmail.com>\nTadej Borovšak <tadeboro@gmail.com>\nRobert Chéramy <robert@cheramy.net>\n\nImagination logo:\nhttp://linuxgraphicsusers.com\n\nInsert Transitions Family:\nJean-Pierre Redonnet <inphilly@gmail.com>",NULL};
789     //const char *documenters[] = {NULL};
790 
791 	if (about == NULL)
792 	{
793 		about = gtk_about_dialog_new ();
794 		gtk_about_dialog_set_url_hook(img_about_dialog_activate_link, NULL, NULL);
795 		gtk_window_set_position (GTK_WINDOW (about),GTK_WIN_POS_CENTER_ON_PARENT);
796 		gtk_window_set_transient_for (GTK_WINDOW (about),GTK_WINDOW (img_struct->imagination_window));
797 		gtk_window_set_destroy_with_parent (GTK_WINDOW (about),TRUE);
798 		g_object_set (about,
799 			"name", "Imagination",
800 			"version", strcmp(REVISION, "-1") == 0 ? VERSION : version,
801 			"copyright","Copyright \xC2\xA9 2009 Giuseppe Torelli",
802 			"comments","A simple and lightweight DVD slideshow maker",
803 			"authors",authors,
804 			"documenters",NULL,
805 			"translator_credits",_("translator-credits"),
806 			"logo_icon_name","imagination",
807 			"website","http://imagination.sf.net",
808 			"license","Copyright \xC2\xA9 2009 Giuseppe Torelli - Colossus <colossus73@gmail.com>\n\n"
809 		    			"This is free software; you can redistribute it and/or\n"
810     					"modify it under the terms of the GNU Library General Public License as\n"
811     					"published by the Free Software Foundation; either version 2 of the\n"
812     					"License,or (at your option) any later version.\n"
813     					"\n"
814     					"This software is distributed in the hope that it will be useful,\n"
815     					"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
816     					"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
817     					"Library General Public License for more details.\n"
818     					"\n"
819     					"You should have received a copy of the GNU Library General Public\n"
820     					"License along with the Gnome Library; see the file COPYING.LIB.  If not,\n"
821     					"write to the Free Software Foundation,Inc.,59 Temple Place - Suite 330,\n"
822     					"Boston,MA 02111-1307,USA.\n",
823 		      NULL);
824 	}
825 	gtk_dialog_run ( GTK_DIALOG(about));
826 	gtk_widget_hide (about);
827 }
828 
img_about_dialog_activate_link(GtkAboutDialog * dialog,const gchar * link,gpointer data)829 static void img_about_dialog_activate_link(GtkAboutDialog * dialog, const gchar *link, gpointer data)
830 {
831 	/* Replace xdg-open with GTK+ equivalent */
832 	gtk_show_uri( NULL, link, GDK_CURRENT_TIME, NULL );
833 }
834 
img_start_stop_preview(GtkWidget * button,img_window_struct * img)835 void img_start_stop_preview(GtkWidget *button, img_window_struct *img)
836 {
837 	GtkTreeIter iter, prev;
838 	GtkTreePath *path = NULL;
839 	slide_struct *entry;
840 	GtkTreeModel *model;
841 	GList *list = NULL;
842 
843 	/* If no images are present, abort */
844 	if( img->slides_nr == 0 )
845 		return;
846 
847 	if(img->export_is_running)
848 		return;
849 
850 	if (img->preview_is_running)
851 	{
852 		/* Preview is already running */
853 
854 		/* Remove timeout function from main loop */
855 		g_source_remove(img->source_id);
856 
857 		/* Clean resources used by preview and prepare application for
858 		 * next preview. */
859 		img_clean_after_preview(img);
860 	}
861 	else
862 	{
863 		/* Start the preview */
864 		if( img->mode == 1 )
865 		{
866 			img->auto_switch = TRUE;
867 			img_switch_mode( img, 0 );
868 		}
869 
870 		model = GTK_TREE_MODEL( img->thumbnail_model );
871 		list = gtk_icon_view_get_selected_items(
872 					GTK_ICON_VIEW( img->thumbnail_iconview ) );
873 		if( list )
874 			gtk_icon_view_get_cursor( GTK_ICON_VIEW(img->thumbnail_iconview),
875 									  &path, NULL);
876 		if( list )
877 		{
878 			/* Start preview from this slide */
879 			if( path )
880 				gtk_tree_model_get_iter( model, &iter, path );
881 			g_list_foreach( list, (GFunc)gtk_tree_path_free, NULL );
882 			g_list_free( list );
883 		}
884 		else
885 		{
886 			/* Start preview from the beginning */
887 			if( ! gtk_tree_model_get_iter_first( model, &iter ) )
888 				return;
889 		}
890 		img->cur_ss_iter = iter;
891 
892 		/* Replace button and menu images */
893 		img_swap_toolbar_images( img, FALSE );
894 
895 		/* Load the first image in the pixbuf */
896 		gtk_tree_model_get( model, &iter, 1, &entry, -1);
897 
898 		if( ! entry->o_filename )
899 		{
900 			img_scale_gradient( entry->gradient, entry->g_start_point,
901 								entry->g_stop_point, entry->g_start_color,
902 								entry->g_stop_color, img->video_size[0],
903 								img->video_size[1], NULL, &img->image2 );
904 		}
905 		/* Respect quality settings */
906 		else if( img->low_quality )
907 			img_scale_image( entry->r_filename, img->video_ratio,
908 							 0, img->video_size[1], img->distort_images,
909 							 img->background_color, NULL, &img->image2 );
910 		else
911 			img_scale_image( entry->r_filename, img->video_ratio,
912 							 0, 0, img->distort_images,
913 							 img->background_color, NULL, &img->image2 );
914 
915 		/* Load first stop point */
916 		img->point2 = (ImgStopPoint *)( entry->no_points ?
917 										entry->points->data :
918 										NULL );
919 
920 		img->work_slide = entry;
921 		img->cur_point = NULL;
922 
923 		/* If we started our preview from beginning, create empty pixbuf and
924 		 * fill it with background color. Else load image that is before
925 		 * currently selected slide. */
926 		if( path != NULL && gtk_tree_path_prev( path ) )
927 		{
928 			gtk_tree_model_get_iter( model, &prev, path );
929 			gtk_tree_model_get( model, &prev, 1, &entry, -1 );
930 
931 			if( ! entry->o_filename )
932 			{
933 				img_scale_gradient( entry->gradient, entry->g_start_point,
934 									entry->g_stop_point, entry->g_start_color,
935 									entry->g_stop_color, img->video_size[0],
936 									img->video_size[1], NULL, &img->image1 );
937 			}
938 			/* Respect quality settings */
939 			else if( img->low_quality )
940 				img_scale_image( entry->r_filename, img->video_ratio,
941 								 0, img->video_size[1], img->distort_images,
942 								 img->background_color, NULL, &img->image1 );
943 			else
944 				img_scale_image( entry->r_filename, img->video_ratio,
945 								 0, 0, img->distort_images,
946 								 img->background_color, NULL, &img->image1 );
947 
948 			/* Load last stop point */
949 			img->point1 = (ImgStopPoint *)( entry->no_points ?
950 											g_list_last( entry->points )->data :
951 											NULL );
952 		}
953 		else
954 		{
955 			cairo_t *cr;
956 
957 			img->image1 = cairo_image_surface_create( CAIRO_FORMAT_RGB24,
958 													  img->video_size[0],
959 													  img->video_size[1] );
960 			cr = cairo_create( img->image1 );
961 			cairo_set_source_rgb( cr, img->background_color[0],
962 									  img->background_color[1],
963 									  img->background_color[2] );
964 			cairo_paint( cr );
965 			cairo_destroy( cr );
966 		}
967 		if( path )
968 			gtk_tree_path_free( path );
969 
970 		/* Add transition timeout function */
971 		img->preview_is_running = TRUE;
972 		img->total_nr_frames = img->total_secs * img->preview_fps;
973 		img->displayed_frame = 0;
974 		img->next_slide_off = 0;
975 		img_calc_next_slide_time_offset( img, img->preview_fps );
976 
977 		/* Create surfaces to be passed to transition renderer */
978 		img->image_from = cairo_image_surface_create( CAIRO_FORMAT_RGB24,
979 													  img->video_size[0],
980 													  img->video_size[1] );
981 		img->image_to = cairo_image_surface_create( CAIRO_FORMAT_RGB24,
982 													img->video_size[0],
983 													img->video_size[1] );
984 		img->exported_image = cairo_image_surface_create( CAIRO_FORMAT_RGB24,
985 														  img->video_size[0],
986 														  img->video_size[1] );
987 
988 		img->source_id = g_timeout_add( 1000 / img->preview_fps,
989 										(GSourceFunc)img_transition_timeout,
990 										img );
991 	}
992 	return;
993 }
994 
img_goto_first_slide(GtkWidget * button,img_window_struct * img)995 void img_goto_first_slide(GtkWidget *button, img_window_struct *img)
996 {
997 	GtkTreeIter iter;
998 	GtkTreePath *path;
999 	GtkTreeModel *model;
1000 	gchar *slide = NULL;
1001 
1002 	model = GTK_TREE_MODEL( img->thumbnail_model );
1003 	if ( ! gtk_tree_model_get_iter_first(model,&iter))
1004 		return;
1005 
1006 	slide = g_strdup_printf("%d", 1);
1007 	gtk_entry_set_text(GTK_ENTRY(img->slide_number_entry), slide);
1008 	g_free(slide);
1009 	gtk_icon_view_unselect_all(GTK_ICON_VIEW (img->active_icon));
1010 	path = gtk_tree_path_new_from_indices(0,-1);
1011 	gtk_icon_view_set_cursor (GTK_ICON_VIEW (img->active_icon), path, NULL, FALSE);
1012 	gtk_icon_view_select_path (GTK_ICON_VIEW (img->active_icon), path);
1013 	gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (img->active_icon), path, FALSE, 0, 0);
1014 	gtk_tree_path_free (path);
1015 }
1016 
img_goto_prev_slide(GtkWidget * button,img_window_struct * img)1017 void img_goto_prev_slide(GtkWidget *button, img_window_struct *img)
1018 {
1019 	GtkTreeModel *model;
1020 	GtkTreePath *path;
1021 	GList *icons_selected = NULL;
1022 	gchar *slide = NULL;
1023 	gint slide_nr;
1024 
1025 	icons_selected = gtk_icon_view_get_selected_items(GTK_ICON_VIEW(img->active_icon) );
1026 	if( ! icons_selected )
1027 		return;
1028 
1029 	model = GTK_TREE_MODEL( img->thumbnail_model );
1030 	slide_nr = gtk_tree_path_get_indices(icons_selected->data)[0];
1031 
1032 	if (slide_nr == 0)
1033 		return;
1034 
1035 	slide = g_strdup_printf("%d", slide_nr);
1036 	gtk_entry_set_text(GTK_ENTRY(img->slide_number_entry), slide);
1037 	g_free(slide);
1038 	gtk_icon_view_unselect_all(GTK_ICON_VIEW (img->active_icon));
1039 	path = gtk_tree_path_new_from_indices(--slide_nr,-1);
1040 
1041 	gtk_icon_view_set_cursor (GTK_ICON_VIEW (img->active_icon), path, NULL, FALSE);
1042 	gtk_icon_view_select_path (GTK_ICON_VIEW (img->active_icon), path);
1043 	gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (img->active_icon), path, FALSE, 0, 0);
1044 	gtk_tree_path_free (path);
1045 
1046 	g_list_foreach (icons_selected, (GFunc) gtk_tree_path_free, NULL);
1047 	g_list_free (icons_selected);
1048 }
1049 
img_goto_next_slide(GtkWidget * button,img_window_struct * img)1050 void img_goto_next_slide(GtkWidget *button, img_window_struct *img)
1051 {
1052 	GtkTreeModel *model;
1053 	GtkTreePath *path;
1054 	GList *icons_selected = NULL;
1055 	gchar *slide = NULL;
1056 	gint slide_nr;
1057 
1058 	icons_selected = gtk_icon_view_get_selected_items(GTK_ICON_VIEW(img->active_icon) );
1059 	if( ! icons_selected )
1060 		return;
1061 
1062 	/* Now get previous iter :) */
1063 	model = GTK_TREE_MODEL( img->thumbnail_model );
1064 	slide_nr = gtk_tree_path_get_indices(icons_selected->data)[0];
1065 
1066 	if (slide_nr == (img->slides_nr-1) )
1067 		return;
1068 
1069 	gtk_icon_view_unselect_all(GTK_ICON_VIEW (img->active_icon));
1070 	path = gtk_tree_path_new_from_indices(++slide_nr, -1);
1071 
1072 	slide = g_strdup_printf("%d", slide_nr + 1);
1073 	gtk_entry_set_text(GTK_ENTRY(img->slide_number_entry), slide);
1074 	g_free(slide);
1075 	gtk_icon_view_set_cursor (GTK_ICON_VIEW (img->active_icon), path, NULL, FALSE);
1076 	gtk_icon_view_select_path (GTK_ICON_VIEW (img->active_icon), path);
1077 	gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (img->active_icon), path, FALSE, 0, 0);
1078 	gtk_tree_path_free (path);
1079 
1080 	g_list_foreach (icons_selected, (GFunc) gtk_tree_path_free, NULL);
1081 	g_list_free (icons_selected);
1082 }
1083 
1084 
img_goto_last_slide(GtkWidget * button,img_window_struct * img)1085 void img_goto_last_slide(GtkWidget *button, img_window_struct *img)
1086 {
1087 	GtkTreeIter iter;
1088 	GtkTreePath *path;
1089 	GtkTreeModel *model;
1090 	gchar *slide = NULL;
1091 
1092 	model = GTK_TREE_MODEL( img->thumbnail_model );
1093 	if ( ! gtk_tree_model_get_iter_first(model,&iter))
1094 		return;
1095 
1096 	slide = g_strdup_printf("%d", img->slides_nr);
1097 	gtk_entry_set_text(GTK_ENTRY(img->slide_number_entry), slide);
1098 	g_free(slide);
1099 	gtk_icon_view_unselect_all(GTK_ICON_VIEW (img->active_icon));
1100 	path = gtk_tree_path_new_from_indices(img->slides_nr - 1, -1);
1101 	gtk_icon_view_set_cursor (GTK_ICON_VIEW (img->active_icon), path, NULL, FALSE);
1102 	gtk_icon_view_select_path (GTK_ICON_VIEW (img->active_icon), path);
1103 	gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (img->active_icon), path, FALSE, 0, 0);
1104 	gtk_tree_path_free (path);
1105 }
1106 
img_on_drag_data_received(GtkWidget * widget,GdkDragContext * context,int x,int y,GtkSelectionData * data,unsigned int info,unsigned int time,img_window_struct * img)1107 void img_on_drag_data_received (GtkWidget *widget,GdkDragContext *context,int x,int y,GtkSelectionData *data,unsigned int info,unsigned int time, img_window_struct *img)
1108 {
1109 	gchar **pictures = NULL;
1110 	gchar *filename;
1111 	GtkWidget *dialog;
1112 	GdkPixbuf *thumb;
1113 	GtkTreeIter iter;
1114 	gint len = 0, slides_cnt = 0, actual_slides;
1115 	slide_struct *slide_info;
1116 
1117 	pictures = gtk_selection_data_get_uris(data);
1118 	if (pictures == NULL)
1119 	{
1120 		dialog = gtk_message_dialog_new(GTK_WINDOW(img->imagination_window),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("Sorry, I could not perform the operation!"));
1121 		gtk_window_set_title(GTK_WINDOW(dialog),"Imagination");
1122 		gtk_dialog_run (GTK_DIALOG (dialog));
1123 		gtk_widget_destroy (GTK_WIDGET (dialog));
1124 		gtk_drag_finish(context,FALSE,FALSE,time);
1125 		return;
1126 	}
1127 	actual_slides = img->slides_nr;
1128 	gtk_drag_finish (context,TRUE,FALSE,time);
1129 	while(pictures[len])
1130 	{
1131 		filename = g_filename_from_uri (pictures[len],NULL,NULL);
1132 		if( img_scale_image( filename, img->video_ratio, 88, 0,
1133 							 img->distort_images, img->background_color,
1134 							 &thumb, NULL ) )
1135 		{
1136 			slide_info = img_create_new_slide();
1137 			if (slide_info)
1138 			{
1139 				img_set_slide_file_info( slide_info, filename );
1140 				gtk_list_store_append (img->thumbnail_model,&iter);
1141 				gtk_list_store_set (img->thumbnail_model, &iter, 0, thumb, 1, slide_info, -1);
1142 				g_object_unref (thumb);
1143 				slides_cnt++;
1144 			}
1145 		}
1146 		g_free(filename);
1147 		len++;
1148 	}
1149 	if (slides_cnt > 0)
1150 	{
1151 		img->slides_nr += slides_cnt;
1152 		img->project_is_modified = TRUE;
1153 		img_set_total_slideshow_duration(img);
1154 		img_set_statusbar_message(img, 0);
1155 	}
1156 	g_strfreev (pictures);
1157 
1158 	/* Select the first slide */
1159 	if (actual_slides == 0)
1160 		img_goto_first_slide(NULL, img);
1161 
1162 	/* Select the first loaded slide if a previous set of slides was loaded */
1163 	else
1164 		img_select_nth_slide(img, actual_slides);
1165 }
1166 
1167 /*
1168  * img_on_expose_event:
1169  * @widget: preview GtkDrawingArea
1170  * @event: expose event info
1171  * @img: global img_window_struct structure
1172  *
1173  * This function is responsible for all of the drawing on preview area, thus it
1174  * should handle "edit mode" (when user is constructing slide show), "preview
1175  * mode" (when user is previewing his work) and "export mode" (when export is in
1176  * progress).
1177  *
1178  * This might be seen as an overkill for single function, but since all of the
1179  * actual rendering is done by helper functions, this function just merely
1180  * paints the results on screen.
1181  *
1182  * Return value: This function returns TRUE if the area has been painted, FALSE
1183  * otherwise (this way the default expose function is only called when no slide
1184  * is selected).
1185  */
1186 gboolean
img_on_expose_event(GtkWidget * widget,GdkEventExpose * event,img_window_struct * img)1187 img_on_expose_event( GtkWidget         *widget,
1188 					 GdkEventExpose    *event,
1189 					 img_window_struct *img )
1190 {
1191 	cairo_t *cr;
1192 
1193 	/* If we're previewing or exporting, only paint frame that is being
1194 	 * currently produced. */
1195 	if( img->preview_is_running || img->export_is_running > 2 )
1196 	{
1197 		gdouble factor;
1198 
1199 		cr = gdk_cairo_create( widget->window );
1200 
1201 		/* Do the drawing */
1202 		factor = (gdouble)img->image_area->allocation.width /
1203 						  img->video_size[0];
1204 		cairo_scale( cr, factor, factor );
1205 		cairo_set_source_surface( cr, img->exported_image, 0, 0 );
1206 		cairo_paint( cr );
1207 
1208 		cairo_destroy( cr );
1209 	}
1210 	else
1211 	{
1212 		if( ! img->current_image )
1213 			/* Use default handler */
1214 			return( FALSE );
1215 
1216 		cr = gdk_cairo_create( widget->window );
1217 
1218 		/* Do the drawing */
1219 		img_draw_image_on_surface( cr, img->image_area->allocation.width,
1220 								   img->current_image, &img->current_point, img );
1221 
1222 		/* Render subtitle if present */
1223 		if( img->current_slide->subtitle )
1224 			img_render_subtitle( cr,
1225 								 img->video_size[0],
1226 								 img->video_size[1],
1227 								 img->image_area_zoom,
1228 								 img->current_slide->position,
1229 								 img->current_slide->placing,
1230 								 img->current_point.zoom,
1231 								 img->current_point.offx,
1232 								 img->current_point.offy,
1233 								 img->current_slide->subtitle,
1234 								 img->current_slide->font_desc,
1235 								 img->current_slide->font_color,
1236                                  img->current_slide->font_bgcolor,
1237 								 img->current_slide->anim,
1238 								 1.0 );
1239 
1240 		cairo_destroy( cr );
1241 	}
1242 
1243 	return( TRUE );
1244 }
1245 
1246 /*
1247  * img_draw_image_on_surface:
1248  * @cr: cairo context
1249  * @width: width of the surface that @cr draws on
1250  * @surface: cairo surface to be drawn on @cr
1251  * @point: stop point holding zoom and offsets
1252  * @img: global img_window_struct
1253  *
1254  * This function takes care of scaling and moving of @surface to fit properly on
1255  * cairo context passed in.
1256  */
1257 void
img_draw_image_on_surface(cairo_t * cr,gint width,cairo_surface_t * surface,ImgStopPoint * point,img_window_struct * img)1258 img_draw_image_on_surface( cairo_t           *cr,
1259 						   gint               width,
1260 						   cairo_surface_t   *surface,
1261 						   ImgStopPoint      *point,
1262 						   img_window_struct *img )
1263 {
1264 	gdouble  offxr, offyr;  /* Relative offsets */
1265 	gdouble  factor_c;      /* Scaling factor for cairo context */
1266 	gdouble  factor_o;      /* Scalng factor for offset mods */
1267 	gint     cw;            /* Width of the surface */
1268 
1269 	cw = cairo_image_surface_get_width( surface );
1270 	factor_c = (gdouble)width / cw * point->zoom;
1271 	factor_o = (gdouble)img->video_size[0] / cw * point->zoom;
1272 
1273 	offxr = point->offx / factor_o;
1274 	offyr = point->offy / factor_o;
1275 
1276 	/* Make sure that matrix modifications are only visible from this function
1277 	 * and they don't interfere with text drawing. */
1278 	cairo_save( cr );
1279 	cairo_scale( cr, factor_c, factor_c );
1280 	cairo_set_source_surface( cr, surface, offxr, offyr );
1281 	cairo_paint( cr );
1282 	cairo_restore( cr );
1283 }
1284 
img_transition_timeout(img_window_struct * img)1285 static gboolean img_transition_timeout(img_window_struct *img)
1286 {
1287 	/* If we output all transition slides (or if there is no slides to output in
1288 	 * transition part), connect still preview phase. */
1289 	if( img->slide_cur_frame == img->slide_trans_frames )
1290 	{
1291 		img->source_id = g_timeout_add( 1000 / img->preview_fps,
1292 										(GSourceFunc)img_still_timeout, img );
1293 
1294 		return FALSE;
1295 	}
1296 
1297 	/* Render single frame */
1298 	img_render_transition_frame( img );
1299 
1300 	/* Schedule our image redraw */
1301 	gtk_widget_queue_draw( img->image_area );
1302 
1303 	/* Increment counters */
1304 	img->slide_cur_frame++;
1305 	img->displayed_frame++;
1306 
1307 	return TRUE;
1308 }
1309 
img_still_timeout(img_window_struct * img)1310 static gboolean img_still_timeout(img_window_struct *img)
1311 {
1312 	/* If there is next slide, connect transition preview, else finish
1313 	 * preview. */
1314 	if( img->slide_cur_frame == img->slide_nr_frames )
1315 	{
1316 		if( img_prepare_pixbufs( img, TRUE ) )
1317 		{
1318 			img_calc_next_slide_time_offset( img, img->preview_fps );
1319 			img->source_id = g_timeout_add( 1000 / img->preview_fps,
1320 										    (GSourceFunc)img_transition_timeout,
1321 											img );
1322 		}
1323 		else
1324 		{
1325 			/* Clean resources used in preview and prepare application for
1326 			 * next preview. */
1327 			img_clean_after_preview( img );
1328 		}
1329 
1330 		/* Indicate that we must start fresh with new slide */
1331 		img->cur_point = NULL;
1332 
1333 		return FALSE;
1334 	}
1335 
1336 	/* Render frame */
1337 	img_render_still_frame( img, img->preview_fps );
1338 
1339 	/* Increment counters */
1340 	img->still_counter++;
1341 	img->slide_cur_frame++;
1342 	img->displayed_frame++;
1343 
1344 	/* Redraw */
1345 	gtk_widget_queue_draw( img->image_area );
1346 
1347 	return( TRUE );
1348 }
1349 
img_swap_toolbar_images(img_window_struct * img,gboolean flag)1350 static void img_swap_toolbar_images( img_window_struct *img,gboolean flag )
1351 {
1352 	GtkWidget *tmp_image;
1353 
1354 	if( flag )
1355 	{
1356 		tmp_image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PLAY,GTK_ICON_SIZE_MENU);
1357 		gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (img->preview_menu),tmp_image);
1358 
1359 		tmp_image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PLAY,GTK_ICON_SIZE_LARGE_TOOLBAR);
1360 		gtk_widget_show(tmp_image);
1361 		gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(img->preview_button), tmp_image);
1362 		gtk_widget_set_tooltip_text(img->preview_button,_("Starts the preview"));
1363 	}
1364 	else
1365 	{
1366 		tmp_image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_STOP,GTK_ICON_SIZE_MENU);
1367 		gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (img->preview_menu),tmp_image);
1368 
1369 		tmp_image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_STOP,GTK_ICON_SIZE_LARGE_TOOLBAR);
1370 		gtk_widget_show(tmp_image);
1371 		gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(img->preview_button), tmp_image);
1372 		gtk_widget_set_tooltip_text(img->preview_button,_("Stops the preview"));
1373 	}
1374 }
1375 
img_clean_after_preview(img_window_struct * img)1376 static void img_clean_after_preview(img_window_struct *img)
1377 {
1378 	/* Switch to right mode */
1379 	if( img->auto_switch )
1380 	{
1381 		img_switch_mode( img, 1 );
1382 		img->auto_switch = FALSE;
1383 	}
1384 
1385 	/* Swap toolbar and menu icons */
1386 	img_swap_toolbar_images( img, TRUE );
1387 
1388 	/* Indicate that preview is not running */
1389 	img->preview_is_running = FALSE;
1390 
1391 	/* Destroy images that were used */
1392 	cairo_surface_destroy( img->image1 );
1393 	cairo_surface_destroy( img->image2 );
1394 	cairo_surface_destroy( img->image_from );
1395 	cairo_surface_destroy( img->image_to );
1396 	cairo_surface_destroy( img->exported_image );
1397 
1398 	gtk_widget_queue_draw( img->image_area );
1399 
1400 	return;
1401 }
1402 
img_choose_slideshow_filename(GtkWidget * widget,img_window_struct * img)1403 void img_choose_slideshow_filename(GtkWidget *widget, img_window_struct *img)
1404 {
1405 	GtkWidget *fc;
1406 	GtkFileChooserAction action = 0;
1407 	gint response;
1408 	gchar *filename = NULL;
1409     GtkFileFilter *project_filter, *all_files_filter;
1410 
1411 	/* Determine the mode of the chooser. */
1412 	if (widget == img->open_menu || widget == img->open_button || widget == img->import_project_menu)
1413 		action = GTK_FILE_CHOOSER_ACTION_OPEN;
1414 	else if (widget == img->save_as_menu || widget == img->save_menu || widget == img->save_button)
1415 		action = GTK_FILE_CHOOSER_ACTION_SAVE;
1416 
1417     /* close old slideshow if we import */
1418     if (widget == img->open_menu || widget == img->open_button)
1419     {
1420         if (img->project_is_modified)
1421             if (GTK_RESPONSE_OK != img_ask_user_confirmation(img, _("You didn't save your slideshow yet. Are you sure you want to close it?")))
1422                 return;
1423         img_close_slideshow(widget, img);
1424     }
1425 
1426 	/* If user wants to save empty slideshow, simply abort */
1427 	if( img->slides_nr == 0 && action == GTK_FILE_CHOOSER_ACTION_SAVE  )
1428 		return;
1429 
1430 	if (img->project_filename == NULL || widget == img->save_as_menu || action == GTK_FILE_CHOOSER_ACTION_OPEN)
1431 	{
1432 		fc = gtk_file_chooser_dialog_new (action == GTK_FILE_CHOOSER_ACTION_OPEN ? _("Load an Imagination slideshow project") :
1433 					_("Save an Imagination slideshow project"),
1434 					GTK_WINDOW (img->imagination_window),
1435 					action,
1436 					GTK_STOCK_CANCEL,
1437 					GTK_RESPONSE_CANCEL,
1438 					action == GTK_FILE_CHOOSER_ACTION_OPEN ?  GTK_STOCK_OPEN : GTK_STOCK_SAVE,
1439 					GTK_RESPONSE_ACCEPT,NULL);
1440 
1441         /* Filter .img files */
1442         project_filter = gtk_file_filter_new ();
1443         gtk_file_filter_set_name(project_filter, _("Imagination projects"));
1444         gtk_file_filter_add_pattern(project_filter, "*.img");
1445         gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fc), project_filter);
1446 
1447         /* All files filter */
1448         all_files_filter = gtk_file_filter_new ();
1449         gtk_file_filter_set_name(all_files_filter, _("All files"));
1450         gtk_file_filter_add_pattern(all_files_filter, "*");
1451         gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fc), all_files_filter);
1452 
1453         if (widget == img->save_as_menu || (widget == img->save_menu && img->project_filename == NULL))
1454             gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER (fc), "unknown.img");
1455 
1456         if (img->project_current_dir)
1457             gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fc),img->project_current_dir);
1458 
1459 
1460 		gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (fc),TRUE);
1461 		response = gtk_dialog_run (GTK_DIALOG (fc));
1462 		if (response == GTK_RESPONSE_ACCEPT)
1463 		{
1464 			filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc));
1465 			if( ! filename )
1466 			{
1467 				gtk_widget_destroy(fc);
1468 				return;
1469 			}
1470 			if (img->project_current_dir)
1471                 g_free(img->project_current_dir);
1472             img->project_current_dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(fc));
1473 
1474 		}
1475 		else if (response == GTK_RESPONSE_CANCEL || GTK_RESPONSE_DELETE_EVENT)
1476 		{
1477 			gtk_widget_destroy(fc);
1478 			return;
1479 		}
1480 		gtk_widget_destroy(fc);
1481 	}
1482 
1483 	if( ! filename )
1484 		filename = g_strdup( img->project_filename );
1485 
1486 	if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
1487 		img_load_slideshow( img, filename );
1488 	else
1489 		img_save_slideshow( img, filename );
1490 
1491 	g_free( filename );
1492 }
1493 
img_close_slideshow(GtkWidget * widget,img_window_struct * img)1494 void img_close_slideshow(GtkWidget *widget, img_window_struct *img)
1495 {
1496     /* When called from close_menu, ask for confirmation */
1497     if (img->project_is_modified && widget == img->close_menu)
1498     {
1499         if (GTK_RESPONSE_OK != img_ask_user_confirmation(img, _("You didn't save your slideshow yet. Are you sure you want to close it?")))
1500             return;
1501     }
1502 	img->project_is_modified = FALSE;
1503 	img_free_allocated_memory(img);
1504 	img_set_window_title(img,NULL);
1505 	img_set_statusbar_message(img,0);
1506 	if( img->current_image )
1507 		cairo_surface_destroy( img->current_image );
1508 	img->current_image = NULL;
1509 	gtk_widget_queue_draw( img->image_area );
1510 	gtk_label_set_text(GTK_LABEL (img->total_time_data),"");
1511 
1512 	/* Reset slideshow properties */
1513 	img->distort_images = TRUE;
1514 	img->background_color[0] = 0;
1515 	img->background_color[1] = 0;
1516 	img->background_color[2] = 0;
1517 	img->final_transition.speed = NORMAL;
1518 	img->final_transition.render = NULL;
1519 
1520 	/* Disable the video tab */
1521     img_disable_videotab (img);
1522 
1523     gtk_entry_set_text(GTK_ENTRY(img->slide_number_entry), "");
1524 }
1525 
img_move_audio_up(GtkButton * button,img_window_struct * img)1526 void img_move_audio_up( GtkButton *button, img_window_struct *img )
1527 {
1528 	GtkTreeSelection *sel;
1529 	GtkTreeModel     *model;
1530 	GtkTreeIter       iter1, iter2;
1531 
1532 	/* We need path, since there is no gtk_tree_model_iter_prev function!! */
1533 	GtkTreePath      *path;
1534 
1535 	/* First we need to get selected iter. This function won't work if
1536 	 * selection's mode is set to GTK_SELECTION_MULTIPLE!! */
1537 	sel = gtk_tree_view_get_selection( GTK_TREE_VIEW( img->music_file_treeview ) );
1538 	if( ! gtk_tree_selection_get_selected( sel, &model, &iter1 ) )
1539 		return;
1540 
1541 	/* Now get previous iter and swap two items if previous iter exists. */
1542 	path = gtk_tree_model_get_path( model, &iter1 );
1543 	if( gtk_tree_path_prev( path ) )
1544 	{
1545 		gtk_tree_model_get_iter( model, &iter2, path );
1546 		gtk_list_store_swap( GTK_LIST_STORE( model ), &iter1, &iter2 );
1547 	}
1548 	gtk_tree_path_free( path );
1549 }
1550 
img_move_audio_down(GtkButton * button,img_window_struct * img)1551 void img_move_audio_down( GtkButton *button, img_window_struct *img )
1552 {
1553 	GtkTreeSelection *sel;
1554 	GtkTreeModel     *model;
1555 	GtkTreeIter       iter1, iter2;
1556 
1557 	/* First we need to get selected iter. This function won't work if
1558 	 * selection's mode is set to GTK_SELECTION_MULTIPLE!! */
1559 	sel = gtk_tree_view_get_selection( GTK_TREE_VIEW( img->music_file_treeview ) );
1560 	if( ! gtk_tree_selection_get_selected( sel, &model, &iter1 ) )
1561 		return;
1562 
1563 	/* Get next iter and swap rows if iter exists. */
1564 	iter2 = iter1;
1565 	if( gtk_tree_model_iter_next( model, &iter2 ) )
1566 		gtk_list_store_swap( GTK_LIST_STORE( model ), &iter1, &iter2 );
1567 }
1568 
1569 /*
1570  * img_ken_burns_zoom_changed:
1571  * @range: GtkRange that will provide proper value for us
1572  * @img: global img_window_strct structure
1573  *
1574  * This function modifies current zoom value and queues redraw of preview area.
1575  *
1576  * To keep image center in focus, we also do some calculation on offsets.
1577  *
1578  * IMPORTANT: This function is part of the Ken Burns effect and doesn't change
1579  * preview area size!! If you're looking for function that does that,
1580  * img_image_area_change_zoom is the thing to look at.
1581  */
1582 void
img_ken_burns_zoom_changed(GtkRange * range,img_window_struct * img)1583 img_ken_burns_zoom_changed( GtkRange          *range,
1584 							img_window_struct *img )
1585 {
1586 	/* Store old zoom for calcutaions */
1587 	gdouble old_zoom = img->current_point.zoom;
1588 
1589 	img->current_point.zoom = gtk_range_get_value( range );
1590 
1591 	/* If zoom is 1, reset parameters to avoid drift. */
1592 	if( img->current_point.zoom < 1.00005 )
1593 	{
1594 		img->maxoffx = 0;
1595 		img->maxoffy = 0;
1596 		img->current_point.offx = 0;
1597 		img->current_point.offy = 0;
1598 	}
1599 	else
1600 	{
1601 		gdouble fracx, fracy;
1602 		gint    tmpoffx, tmpoffy;
1603 		gdouble aw  = img->video_size[0];
1604 		gdouble ah  = img->video_size[1];
1605 		gdouble aw2 = aw / 2;
1606 		gdouble ah2 = ah / 2;
1607 
1608 		fracx = (gdouble)( aw2 - img->current_point.offx ) / ( aw2 * old_zoom );
1609 		fracy = (gdouble)( ah2 - img->current_point.offy ) / ( ah2 * old_zoom );
1610 		img->maxoffx = aw * ( 1 - img->current_point.zoom );
1611 		img->maxoffy = ah * ( 1 - img->current_point.zoom );
1612 		tmpoffx = aw2 * ( 1 - fracx * img->current_point.zoom );
1613 		tmpoffy = ah2 * ( 1 - fracy * img->current_point.zoom );
1614 
1615 		img->current_point.offx = CLAMP( tmpoffx, img->maxoffx, 0 );
1616 		img->current_point.offy = CLAMP( tmpoffy, img->maxoffy, 0 );
1617 	}
1618 
1619 	gtk_widget_queue_draw( img->image_area );
1620 }
1621 
1622 /*
1623  * img_image_area_button_press:
1624  * @widget: image area
1625  * @event: event description
1626  * @img: global img_window_struct structure
1627  *
1628  * This function stores initial coordinates of button press that we'll be
1629  * needing for drag emulation.
1630  *
1631  * Return value: TRUE, indicating that we handled this event.
1632  */
1633 gboolean
img_image_area_button_press(GtkWidget * widget,GdkEventButton * event,img_window_struct * img)1634 img_image_area_button_press( GtkWidget         *widget,
1635 							 GdkEventButton    *event,
1636 							 img_window_struct *img )
1637 {
1638 	if( event->button != 1 )
1639 		return( FALSE );
1640 
1641 	img->x = event->x;
1642 	img->y = event->y;
1643 	img->bak_offx = img->current_point.offx;
1644 	img->bak_offy = img->current_point.offy;
1645 
1646 	return( TRUE );
1647 }
1648 
1649 /*
1650  * img_image_area_motion:
1651  * @widget: image area
1652  * @event: event description
1653  * @img: global img_window_struct structure
1654  *
1655  * This function calculates offsets from stored button press coordinates and
1656  * queue redraw of the preview area.
1657  *
1658  * Return value: TRUE if moune button 1 has been pressed during drag, else
1659  * FALSE.
1660  */
1661 gboolean
img_image_area_motion(GtkWidget * widget,GdkEventMotion * event,img_window_struct * img)1662 img_image_area_motion( GtkWidget         *widget,
1663 					   GdkEventMotion    *event,
1664 					   img_window_struct *img )
1665 {
1666 	gdouble deltax,
1667 			deltay;
1668 
1669 	deltax = ( event->x - img->x ) / img->image_area_zoom;
1670 	deltay = ( event->y - img->y ) / img->image_area_zoom;
1671 
1672 	img->current_point.offx = CLAMP( deltax + img->bak_offx, img->maxoffx, 0 );
1673 	img->current_point.offy = CLAMP( deltay + img->bak_offy, img->maxoffy, 0 );
1674 
1675 	gtk_widget_queue_draw( img->image_area );
1676 
1677 	return( TRUE );
1678 }
1679 
1680 /* Zoom callback functions */
1681 void
img_zoom_in(GtkWidget * item,img_window_struct * img)1682 img_zoom_in( GtkWidget         *item,
1683 			 img_window_struct *img )
1684 {
1685 	if( img->mode == 0 )
1686 		img_image_area_change_zoom( 0.1, FALSE, img );
1687 	else
1688 		img_overview_change_zoom( 0.1, FALSE, img );
1689 }
1690 
1691 void
img_zoom_out(GtkWidget * item,img_window_struct * img)1692 img_zoom_out( GtkWidget         *item,
1693 			  img_window_struct *img )
1694 {
1695 	if( img->mode == 0 )
1696 		img_image_area_change_zoom( - 0.1, FALSE, img );
1697 	else
1698 		img_overview_change_zoom( - 0.1, FALSE, img );
1699 }
1700 
1701 void
img_zoom_reset(GtkWidget * item,img_window_struct * img)1702 img_zoom_reset( GtkWidget         *item,
1703 				img_window_struct *img )
1704 {
1705 	if( img->mode == 0 )
1706 		img_image_area_change_zoom( 0, TRUE, img );
1707 	else
1708 		img_overview_change_zoom( 0, TRUE, img );
1709 }
1710 
1711 void
img_zoom_fit(GtkWidget * item,img_window_struct * img)1712 img_zoom_fit( GtkWidget         *item,
1713               img_window_struct *img )
1714 {
1715     gdouble step, level1, level2;
1716 
1717     if( img->mode == 0 )
1718     {
1719         /* we want to fit the frame into prev_root. Frame = video + 4 px */
1720         level1 = (float)img->prev_root->allocation.width / (img->video_size[0] + 4);
1721         level2 = (float)img->prev_root->allocation.height / (img->video_size[1] + 4);
1722         if (level1 < level2)
1723             /* step is relative to zoom level 1 */
1724             step = level1 - 1;
1725         else
1726             step = level2 - 1;
1727 
1728         img_image_area_change_zoom( 0, TRUE, img );
1729         img_image_area_change_zoom( step, FALSE, img );
1730     }
1731     else
1732         img_overview_change_zoom( 0, TRUE, img );
1733 }
1734 
1735 /*
1736  * img_image_area_change_zoom:
1737  * @step: amount of zoom to be changed
1738  * @reset: do we want to reset zoom level
1739  * @img: global img_widget_struct structure
1740  *
1741  * This function will increase/decrease/reset zoom level. If @step is less than
1742  * zero, preview area will zoom out, if @step is bigger that zero, image area
1743  * will zoom in.
1744  *
1745  * If @reset is TRUE, @step value is ignored and zoom reset to 1.
1746  *
1747  * Zoom level of image area is in interval [0.1, 5], but this can be easily
1748  * changed by adjusting bounds array values. If the zoom would be set outside of
1749  * this interval, it is clamped in between those two values.
1750  */
1751 static void
img_image_area_change_zoom(gdouble step,gboolean reset,img_window_struct * img)1752 img_image_area_change_zoom( gdouble            step,
1753 							gboolean           reset,
1754 							img_window_struct *img )
1755 {
1756 	static gdouble bounds[] = { 0.1, 5.0 };
1757 
1758 	if( reset )
1759 		img->image_area_zoom = 1;
1760 	else
1761 		img->image_area_zoom = CLAMP( img->image_area_zoom + step,
1762 									  bounds[0], bounds[1] );
1763 
1764 	/* Apply change */
1765 	gtk_widget_set_size_request( img->image_area,
1766 								 img->video_size[0] * img->image_area_zoom,
1767 								 img->video_size[1] * img->image_area_zoom );
1768 }
1769 
1770 static void
img_overview_change_zoom(gdouble step,gboolean reset,img_window_struct * img)1771 img_overview_change_zoom( gdouble            step,
1772 						  gboolean           reset,
1773 						  img_window_struct *img )
1774 {
1775 	static gdouble  bounds[] = { 0.1, 3.0 };
1776 	GtkTreeModel   *model;
1777 
1778 	if( reset )
1779 		img->overview_zoom = 1;
1780 	else
1781 		img->overview_zoom = CLAMP( img->overview_zoom + step,
1782 									bounds[0], bounds[1] );
1783 
1784 	/* Apply change */
1785 	g_object_get( G_OBJECT( img->over_icon ), "model", &model, NULL );
1786 	g_object_set( G_OBJECT( img->over_icon ), "model", NULL, NULL );
1787 	g_object_set( img->over_cell, "zoom", img->overview_zoom, NULL );
1788 	g_object_set( G_OBJECT( img->over_icon ), "model", model, NULL );
1789 	g_object_unref( G_OBJECT( model ) );
1790 }
1791 
1792 void
img_quality_toggled(GtkCheckMenuItem * item,img_window_struct * img)1793 img_quality_toggled( GtkCheckMenuItem  *item,
1794 					 img_window_struct *img )
1795 {
1796 	img->low_quality = gtk_check_menu_item_get_active( item );
1797 }
1798 
1799 void
img_add_stop_point(GtkButton * button,img_window_struct * img)1800 img_add_stop_point( GtkButton         *button,
1801 					img_window_struct *img )
1802 {
1803 	ImgStopPoint *point;
1804 	GList        *tmp;
1805 
1806 	if (img->current_slide == NULL)
1807 		return;
1808 
1809 	/* Create new point */
1810 	point = g_slice_new( ImgStopPoint );
1811 	*point = img->current_point;
1812 	point->time = gtk_spin_button_get_value_as_int(
1813 						GTK_SPIN_BUTTON( img->ken_duration ) );
1814 
1815 	/* Append it to the list */
1816 	tmp = img->current_slide->points;
1817 	tmp = g_list_append( tmp, point );
1818 	img->current_slide->points = tmp;
1819 	img->current_slide->cur_point = img->current_slide->no_points;
1820 	img->current_slide->no_points++;
1821 
1822 	/* Update display */
1823 	img_update_stop_display( img, FALSE );
1824 	img_ken_burns_update_sensitivity( img, TRUE,
1825 									  img->current_slide->no_points );
1826 
1827 	/* Sync timings */
1828 	img_sync_timings( img->current_slide, img );
1829 }
1830 
1831 void
img_update_stop_point(GtkButton * button,img_window_struct * img)1832 img_update_stop_point( GtkButton         *button,
1833 					   img_window_struct *img )
1834 {
1835 	ImgStopPoint *point;
1836 
1837 	if( img->current_slide == NULL )
1838 		return;
1839 
1840 	/* Get selected point */
1841 	point = g_list_nth_data( img->current_slide->points,
1842 							 img->current_slide->cur_point );
1843 
1844 	/* Update data */
1845 	*point = img->current_point;
1846 	point->time = gtk_spin_button_get_value_as_int(
1847 						GTK_SPIN_BUTTON( img->ken_duration ) );
1848 
1849 	/* Update display */
1850 	img_update_stop_display( img, FALSE );
1851 
1852 	/* Sync timings */
1853 	img_sync_timings( img->current_slide, img );
1854 }
1855 
1856 void
img_delete_stop_point(GtkButton * button,img_window_struct * img)1857 img_delete_stop_point( GtkButton         *button,
1858 					   img_window_struct *img )
1859 {
1860 	GList *node;
1861 
1862 	if( img->current_slide == NULL )
1863 		return;
1864 
1865 	/* Get selected node and free it */
1866 	node = g_list_nth( img->current_slide->points,
1867 					   img->current_slide->cur_point );
1868 	g_slice_free( ImgStopPoint, node->data );
1869 	img->current_slide->points =
1870 			g_list_delete_link( img->current_slide->points, node );
1871 
1872 	/* Update counters */
1873 	img->current_slide->no_points--;
1874 	img->current_slide->cur_point = MIN( img->current_slide->cur_point,
1875 										 img->current_slide->no_points - 1 );
1876 
1877 	/* Update display */
1878 	img_update_stop_display( img, TRUE );
1879 	img_ken_burns_update_sensitivity( img, TRUE,
1880 									  img->current_slide->no_points );
1881 
1882 	/* Sync timings */
1883 	img_sync_timings( img->current_slide, img );
1884 }
1885 
1886 void
img_update_stop_display(img_window_struct * img,gboolean update_pos)1887 img_update_stop_display( img_window_struct *img,
1888 						 gboolean           update_pos )
1889 {
1890 	gchar        *string;
1891 	gint          full;
1892 
1893 	/* Disable/enable slide duration */
1894 	gtk_widget_set_sensitive( img->duration,
1895 							  img->current_slide->no_points == 0 );
1896 
1897 	/* Set slide duration */
1898 	full = img_calc_slide_duration_points( img->current_slide->points,
1899 										   img->current_slide->no_points );
1900 	if( ! full )
1901 		full = img->current_slide->duration;
1902 	gtk_spin_button_set_value( GTK_SPIN_BUTTON( img->duration ), full );
1903 
1904 	/* Set point count */
1905 	string = g_strdup_printf( "%d", img->current_slide->no_points );
1906 	gtk_label_set_text( GTK_LABEL( img->total_stop_points_label), string );
1907 	g_free( string );
1908 
1909 	/* If no point is set yet, use default values */
1910 	if( img->current_slide->no_points )
1911 	{
1912 		ImgStopPoint *point;
1913 
1914 		/* Set current point */
1915 		string = g_strdup_printf( "%d", img->current_slide->cur_point + 1 );
1916 		gtk_entry_set_text( GTK_ENTRY( img->ken_entry ), string );
1917 		g_free( string );
1918 
1919 		/* Set duration of this point */
1920 		point = (ImgStopPoint *)g_list_nth_data( img->current_slide->points,
1921 												 img->current_slide->cur_point );
1922 		gtk_spin_button_set_value( GTK_SPIN_BUTTON( img->ken_duration ),
1923 								   point->time );
1924 
1925 		/* Set zoom value */
1926 		gtk_range_set_value( GTK_RANGE( img->ken_zoom ), point->zoom );
1927 
1928 		/* Do we need to refresh current stop point on screen */
1929 		if( update_pos )
1930 			img->current_point = *point;
1931 	}
1932 	else
1933 	{
1934 		ImgStopPoint point = { 1, 0, 0, 1.0 };
1935 
1936 		gtk_entry_set_text( GTK_ENTRY( img->ken_entry ), "" );
1937 		gtk_spin_button_set_value( GTK_SPIN_BUTTON( img->ken_duration ), 1 );
1938 		gtk_range_set_value( GTK_RANGE( img->ken_zoom ), 1.0 );
1939 		if( update_pos )
1940 			img->current_point = point;
1941 	}
1942 
1943 	/* Force update on preview area */
1944 	gtk_widget_queue_draw( img->image_area );
1945 }
1946 
1947 void
img_update_subtitles_widgets(img_window_struct * img)1948 img_update_subtitles_widgets( img_window_struct *img )
1949 {
1950 	gchar       *string;
1951 	GdkColor     color;
1952 	gdouble     *f_colors;
1953 
1954 	/* Block all handlers */
1955 	g_signal_handlers_block_by_func( img->slide_text_buffer,
1956 									 img_queue_subtitle_update, img );
1957 	g_signal_handlers_block_by_func( img->sub_font,
1958 									 img_text_font_set, img );
1959 	g_signal_handlers_block_by_func( img->sub_color,
1960 									 img_font_color_changed, img );
1961     g_signal_handlers_block_by_func( img->sub_bgcolor,
1962                                      img_font_bgcolor_changed, img );
1963 	g_signal_handlers_block_by_func( img->sub_anim,
1964 									 img_text_anim_set, img );
1965 	g_signal_handlers_block_by_func( img->sub_anim_duration,
1966 									 img_combo_box_anim_speed_changed, img );
1967 	g_signal_handlers_block_by_func( img->sub_placing,
1968 									 img_placing_changed, img );
1969 	g_signal_handlers_block_by_func( img->sub_pos, img_text_pos_changed, img );
1970 
1971 	/* Update text field */
1972 	string = ( img->current_slide->subtitle ?
1973 			   img->current_slide->subtitle :
1974 			   "" );
1975 	g_object_set( G_OBJECT( img->slide_text_buffer ), "text", string, NULL );
1976 
1977 	/* Update font button */
1978 	string = pango_font_description_to_string(img->current_slide->font_desc);
1979 	gtk_font_button_set_font_name(GTK_FONT_BUTTON(img->sub_font), string);
1980 	g_free(string);
1981 
1982 	/* Update color button */
1983 	f_colors = img->current_slide->font_color;
1984 	color.red   = (gint)( f_colors[0] * 0xffff );
1985 	color.green = (gint)( f_colors[1] * 0xffff );
1986 	color.blue  = (gint)( f_colors[2] * 0xffff );
1987 	gtk_color_button_set_color( GTK_COLOR_BUTTON( img->sub_color ), &color );
1988 	gtk_color_button_set_alpha( GTK_COLOR_BUTTON( img->sub_color ),
1989 								(gint)(f_colors[3] * 0xffff ) );
1990 
1991     /* Update background color button */
1992     f_colors = img->current_slide->font_bgcolor;
1993     color.red   = (gint)( f_colors[0] * 0xffff );
1994     color.green = (gint)( f_colors[1] * 0xffff );
1995     color.blue  = (gint)( f_colors[2] * 0xffff );
1996     gtk_color_button_set_color( GTK_COLOR_BUTTON( img->sub_bgcolor ), &color );
1997     gtk_color_button_set_alpha( GTK_COLOR_BUTTON( img->sub_bgcolor ),
1998                                 (gint)(f_colors[3] * 0xffff ) );
1999 
2000 	/* Update animation */
2001 	gtk_combo_box_set_active( GTK_COMBO_BOX( img->sub_anim ),
2002 							  img->current_slide->anim_id );
2003 
2004 	/* Update duration */
2005 	gtk_spin_button_set_value( GTK_SPIN_BUTTON( img->sub_anim_duration ),
2006 							  img->current_slide->anim_duration );
2007 
2008 	/* Update placing */
2009 	gtk_combo_box_set_active( GTK_COMBO_BOX( img->sub_placing ),
2010 							  img->current_slide->placing );
2011 
2012 	/* Update position */
2013 	img_table_button_set_active_item( IMG_TABLE_BUTTON( img->sub_pos ),
2014 									  img->current_slide->position );
2015 
2016 	/* Unblock all handlers */
2017 	g_signal_handlers_unblock_by_func( img->slide_text_buffer,
2018 									   img_queue_subtitle_update, img );
2019 	g_signal_handlers_unblock_by_func( img->sub_font,
2020 									   img_text_font_set, img );
2021 	g_signal_handlers_unblock_by_func( img->sub_color,
2022 									   img_font_color_changed, img );
2023     g_signal_handlers_unblock_by_func( img->sub_bgcolor,
2024                                        img_font_bgcolor_changed, img );
2025 	g_signal_handlers_unblock_by_func( img->sub_anim,
2026 									   img_text_anim_set, img );
2027 	g_signal_handlers_unblock_by_func( img->sub_anim_duration,
2028 									   img_combo_box_anim_speed_changed, img );
2029 	g_signal_handlers_unblock_by_func( img->sub_placing,
2030 									   img_placing_changed, img );
2031 	g_signal_handlers_unblock_by_func( img->sub_pos,
2032 									   img_text_pos_changed, img );
2033 }
2034 
2035 void
img_goto_prev_point(GtkButton * button,img_window_struct * img)2036 img_goto_prev_point( GtkButton         *button,
2037 					 img_window_struct *img )
2038 {
2039 	if( img->current_slide && img->current_slide->no_points )
2040 	{
2041 		img->current_slide->cur_point =
2042 				CLAMP( img->current_slide->cur_point - 1,
2043 					   0, img->current_slide->no_points - 1 );
2044 
2045 		img_update_stop_display( img, TRUE );
2046 	}
2047 }
2048 
2049 void
img_goto_next_point(GtkButton * button,img_window_struct * img)2050 img_goto_next_point( GtkButton         *button,
2051 					 img_window_struct *img )
2052 {
2053 	if( img->current_slide && img->current_slide->no_points )
2054 	{
2055 		img->current_slide->cur_point =
2056 				CLAMP( img->current_slide->cur_point + 1,
2057 					   0, img->current_slide->no_points - 1 );
2058 
2059 		img_update_stop_display( img, TRUE );
2060 	}
2061 }
2062 
2063 void
img_goto_point(GtkEntry * entry,img_window_struct * img)2064 img_goto_point ( GtkEntry          *entry,
2065 				 img_window_struct *img )
2066 {
2067 	const gchar *string;
2068 	gint         number;
2069 
2070 	string = gtk_entry_get_text( entry );
2071 	number = (gint)strtol( string, NULL, 10 );
2072 
2073 	if( img->current_slide && img->current_slide->no_points )
2074 	{
2075 		img->current_slide->cur_point =
2076 				CLAMP( number - 1, 0, img->current_slide->no_points - 1 );
2077 
2078 		img_update_stop_display( img, TRUE );
2079 	}
2080 }
2081 
2082 
2083 void
img_calc_current_ken_point(ImgStopPoint * res,ImgStopPoint * from,ImgStopPoint * to,gdouble progress,gint mode)2084 img_calc_current_ken_point( ImgStopPoint *res,
2085 							ImgStopPoint *from,
2086 							ImgStopPoint *to,
2087 							gdouble       progress,
2088 							gint          mode )
2089 {
2090 	gdouble fracx, /* Factor for x offset */
2091 			fracy, /* Factor for y offset */
2092 			fracz; /* Factor for zoom */
2093 
2094 	switch( mode )
2095 	{
2096 		case( 0 ): /* Linear mode */
2097 			fracx = progress;
2098 			fracy = progress;
2099 			fracz = progress;
2100 			break;
2101 
2102 		case( 1 ): /* Acceleration mode */
2103 			break;
2104 
2105 		case( 2 ): /* Deceleration mode */
2106 			break;
2107 	}
2108 
2109 	res->offx = from->offx * ( 1 - fracx ) + to->offx * fracx;
2110 	res->offy = from->offy * ( 1 - fracy ) + to->offy * fracy;
2111 	res->zoom = from->zoom * ( 1 - fracz ) + to->zoom * fracz;
2112 }
2113 
img_clipboard_cut_copy_operation(img_window_struct * img,ImgClipboardMode mode)2114 void img_clipboard_cut_copy_operation(img_window_struct *img, ImgClipboardMode mode)
2115 {
2116 	GtkClipboard *img_clipboard;
2117 	GList *selected = NULL;
2118 	GtkTargetEntry targets[] =
2119 	{
2120 		{ "application/imagination-info-list", 0, 0 }
2121 	};
2122 
2123 	selected =
2124 		gtk_icon_view_get_selected_items(GTK_ICON_VIEW(img->active_icon));
2125 	if (selected == NULL)
2126 		return;
2127 
2128 	img_clipboard = gtk_clipboard_get (IMG_CLIPBOARD);
2129 
2130 	/* Let's delete the GList if the user selechooses Cut/Copy again instead of Paste */
2131 	if (img->selected_paths)
2132 	{
2133 		g_list_foreach (img->selected_paths, (GFunc)gtk_tree_path_free, NULL);
2134 		g_list_free (img->selected_paths);
2135 	}
2136 	img->selected_paths = selected;
2137 	img->clipboard_mode = mode;
2138 
2139 	gtk_clipboard_set_with_data (	img_clipboard,
2140 									targets, G_N_ELEMENTS (targets),
2141 									(GtkClipboardGetFunc) 	img_clipboard_get,
2142 									NULL, img);
2143 }
2144 
img_clipboard_get(GtkClipboard * clipboard,GtkSelectionData * selection_data,guint info,img_window_struct * img)2145 void img_clipboard_get (GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, img_window_struct *img)
2146 {
2147 	if (selection_data->target != IMG_INFO_LIST)
2148 		return;
2149 
2150 	gtk_selection_data_set (selection_data, selection_data->target, 8, (guchar *) img->selected_paths, sizeof(GList) * g_list_length(img->selected_paths) );
2151 }
2152 
img_clipboard_clear(GtkClipboard * clipboard,img_window_struct * img)2153 void img_clipboard_clear (GtkClipboard *clipboard, img_window_struct *img)
2154 {
2155 	img_message (img, FALSE, "I'm here\n");
2156 	//gtk_clipboard_clear(clipboard);
2157 }
2158 
2159 void
img_add_empty_slide(GtkMenuItem * item,img_window_struct * img)2160 img_add_empty_slide( GtkMenuItem       *item,
2161 					 img_window_struct *img )
2162 {
2163 	/* This structure retains values across invocations */
2164 	static ImgEmptySlide slide = { { 0, 0, 0 },         /* Start color */
2165 								   { 1, 1, 1 },         /* Stop color */
2166 								   { 0, 0 },            /* Start point (l) */
2167 								   { -1, 0 },           /* Stop point (l) */
2168 								   { 0, 0 },            /* Start point (r) */
2169 								   { 0, 0 },            /* Stop point (r) */
2170 								   0,                   /* Drag */
2171 								   0,                   /* Gradient type */
2172 								   NULL,                /* Color button */
2173 								   NULL,                /* Preview area */
2174 								   { NULL, NULL, NULL } /* Radio buttons */
2175 								 };
2176 
2177 	GList *where_to_insert = NULL;
2178 
2179 	/* Widgets */
2180 	GtkWidget *dialog,
2181 			  *vbox,
2182 			  *frame,
2183 			  *table,
2184 			  *radio1,
2185 			  *radio2,
2186 			  *radio3,
2187 			  *color1,
2188 			  *color2,
2189 			  *preview,
2190 			  *hbox;
2191 	GdkColor   color;
2192 	gint       i, w, h, pos;
2193 
2194 	dialog = gtk_dialog_new_with_buttons(
2195 					_("Create empty slide"),
2196 					GTK_WINDOW( img->imagination_window ),
2197 					GTK_DIALOG_MODAL,
2198 					GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2199 					GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2200 					NULL );
2201 
2202 	gtk_button_box_set_layout (GTK_BUTTON_BOX (GTK_DIALOG (dialog)->action_area), GTK_BUTTONBOX_SPREAD);
2203 	gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
2204 	vbox = gtk_dialog_get_content_area( GTK_DIALOG( dialog ) );
2205 
2206 	frame = gtk_frame_new( _("Empty slide options:") );
2207 	gtk_box_pack_start( GTK_BOX( vbox ), frame, TRUE, TRUE, 5 );
2208 	gtk_container_set_border_width( GTK_CONTAINER( frame ), 5 );
2209 
2210 	hbox = gtk_hbox_new( FALSE, 6 );
2211 	gtk_container_add( GTK_CONTAINER( frame ), hbox );
2212 
2213 	table = gtk_table_new( 4, 2, TRUE );
2214 	gtk_box_pack_start( GTK_BOX( hbox ), table, FALSE, FALSE, 10 );
2215 
2216 	radio1 = gtk_radio_button_new_with_mnemonic( NULL, _("Use _solid color") );
2217 	gtk_table_attach( GTK_TABLE( table ), radio1, 0, 2, 0, 1,
2218 					  GTK_FILL, GTK_FILL, 0, 0 );
2219 	slide.radio[0] = radio1;
2220 
2221 	radio2 = gtk_radio_button_new_with_mnemonic_from_widget(
2222 				GTK_RADIO_BUTTON( radio1 ), _("Use _linear gradient") );
2223 	gtk_table_attach( GTK_TABLE( table ), radio2, 0, 2, 1, 2,
2224 					  GTK_FILL, GTK_FILL, 0, 0 );
2225 	slide.radio[1] = radio2;
2226 
2227 	radio3 = gtk_radio_button_new_with_mnemonic_from_widget(
2228 				GTK_RADIO_BUTTON( radio1 ), _("Use _radial gradient") );
2229 	gtk_table_attach( GTK_TABLE( table ), radio3, 0, 2, 2, 3,
2230 					  GTK_FILL, GTK_FILL, 0, 0 );
2231 	slide.radio[2] = radio3;
2232 
2233 	gtk_toggle_button_set_active(
2234 			GTK_TOGGLE_BUTTON( slide.radio[slide.gradient] ), TRUE );
2235 	for( i = 0; i < 3; i++ )
2236 		g_signal_connect( G_OBJECT( slide.radio[i] ), "toggled",
2237 						  G_CALLBACK( img_gradient_toggled ), &slide );
2238 
2239 	color.red   = (gint)( slide.c_start[0] * 0xffff );
2240 	color.green = (gint)( slide.c_start[1] * 0xffff );
2241 	color.blue  = (gint)( slide.c_start[2] * 0xffff );
2242 	color1 = gtk_color_button_new_with_color( &color );
2243 	gtk_table_attach( GTK_TABLE( table ), color1, 0, 1, 3, 4,
2244 					  GTK_FILL, GTK_FILL, 0, 0 );
2245 	g_signal_connect( G_OBJECT( color1 ), "color-set",
2246 					  G_CALLBACK( img_gradient_color_set ), &slide );
2247 
2248 	color.red   = (gint)( slide.c_stop[0] * 0xffff );
2249 	color.green = (gint)( slide.c_stop[1] * 0xffff );
2250 	color.blue  = (gint)( slide.c_stop[2] * 0xffff );
2251 	color2 = gtk_color_button_new_with_color( &color );
2252 	gtk_table_attach( GTK_TABLE( table ), color2, 1, 2, 3, 4,
2253 					  GTK_FILL, GTK_FILL, 0, 0 );
2254 	gtk_widget_set_sensitive( color2, (gboolean)slide.gradient );
2255 	g_signal_connect( G_OBJECT( color2 ), "color-set",
2256 					  G_CALLBACK( img_gradient_color_set ), &slide );
2257 
2258 	frame = gtk_frame_new( _("Preview") );
2259 	gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 5 );
2260 
2261 	w = img->video_size[0] / 2;
2262 	h = img->video_size[1] / 2;
2263 	preview = gtk_drawing_area_new();
2264 	gtk_widget_set_size_request( preview, w, h );
2265 	gtk_widget_add_events( preview, GDK_BUTTON1_MOTION_MASK |
2266 									GDK_BUTTON_PRESS_MASK |
2267 									GDK_BUTTON_RELEASE_MASK );
2268 	gtk_container_add( GTK_CONTAINER( frame ), preview );
2269 	g_signal_connect( G_OBJECT( preview ), "expose-event",
2270 					  G_CALLBACK( img_gradient_expose ), &slide );
2271 	g_signal_connect( G_OBJECT( preview ), "button-press-event",
2272 					  G_CALLBACK( img_gradient_press ), &slide );
2273 	g_signal_connect( G_OBJECT( preview ), "button-release-event",
2274 					  G_CALLBACK( img_gradient_release ), &slide );
2275 	g_signal_connect( G_OBJECT( preview ), "motion-notify-event",
2276 					  G_CALLBACK( img_gradient_move ), &slide );
2277 
2278 	/* Show all */
2279 	gtk_widget_show_all( dialog );
2280 
2281 	/* Fill internal structure */
2282 	slide.color2 = color2;
2283 	slide.preview = preview;
2284 	if( slide.pl_stop[0] < 0 )
2285 	{
2286 		slide.pl_stop[0] = (gdouble)w;
2287 		slide.pl_stop[1] = (gdouble)h;
2288 		slide.pr_start[0] = w * 0.5;
2289 		slide.pr_start[1] = h * 0.5;
2290 	}
2291 
2292 	if( gtk_dialog_run( GTK_DIALOG( dialog ) ) == GTK_RESPONSE_ACCEPT )
2293 	{
2294 		GtkTreeIter   iter;
2295 		slide_struct *slide_info;
2296 		GdkPixbuf    *thumb;
2297 
2298 		slide_info = img_create_new_slide();
2299 		if( slide_info )
2300 		{
2301 			gdouble p_start[2],
2302 					p_stop[2];
2303 
2304 			/* Convert gradient points into relative offsets (this enables us to
2305 			 * scale gradient on any surface size) */
2306 			if( slide.gradient < 2 ) /* solid and linear */
2307 			{
2308 				p_start[0] = slide.pl_start[0] / w;
2309 				p_start[1] = slide.pl_start[1] / h;
2310 				p_stop[0] = slide.pl_stop[0] / w;
2311 				p_stop[1] = slide.pl_stop[1] / h;
2312 			}
2313 			else /* Radial gradient */
2314 			{
2315 				p_start[0] = slide.pr_start[0] / w;
2316 				p_start[1] = slide.pr_start[1] / h;
2317 				p_stop[0] = slide.pr_stop[0] / w;
2318 				p_stop[1] = slide.pr_stop[1] / h;
2319 			}
2320 
2321 			/* Update slide info */
2322 			img_set_slide_gradient_info( slide_info, slide.gradient,
2323 										 slide.c_start, slide.c_stop,
2324 										 p_start, p_stop );
2325 
2326 			/* Create thumbnail */
2327 			img_scale_gradient( slide.gradient, p_start, p_stop,
2328 								slide.c_start, slide.c_stop,
2329 								88, 72,
2330 								&thumb, NULL );
2331 
2332 			/* Add slide to store */
2333 			where_to_insert	=	gtk_icon_view_get_selected_items(GTK_ICON_VIEW(img->active_icon));
2334 			if (where_to_insert)
2335 			{
2336 				pos = gtk_tree_path_get_indices(where_to_insert->data)[0]+1;
2337 				gtk_list_store_insert_with_values(img->thumbnail_model, &iter,
2338 												 pos,
2339 												 0, thumb,
2340 						 						 1, slide_info,
2341 						 						 2, NULL,
2342 						 						 3, FALSE,
2343 						 						-1 );
2344 				g_list_foreach (where_to_insert, (GFunc)gtk_tree_path_free, NULL);
2345 				g_list_free (where_to_insert);
2346 			}
2347 			else
2348 			{
2349 				gtk_list_store_append( img->thumbnail_model, &iter );
2350 				gtk_list_store_set(img->thumbnail_model, &iter, 0, thumb, 1, slide_info, 2, NULL, 3, FALSE, -1 );
2351 			}
2352 			g_object_unref( G_OBJECT( thumb ) );
2353 			img->slides_nr++;
2354 			img_set_total_slideshow_duration( img );
2355 
2356 			img_select_nth_slide( img, img->slides_nr );
2357 		}
2358 	}
2359 	gtk_widget_destroy( dialog );
2360 }
2361 
2362 static void
img_gradient_toggled(GtkToggleButton * button,ImgEmptySlide * slide)2363 img_gradient_toggled( GtkToggleButton *button,
2364 					  ImgEmptySlide   *slide )
2365 {
2366 	GtkWidget *widget = GTK_WIDGET( button );
2367 	gint       i;
2368 
2369 	if( ! gtk_toggle_button_get_active( button ) )
2370 		return;
2371 
2372 	for( i = 0; widget != slide->radio[i]; i++ )
2373 		;
2374 
2375 	slide->gradient = i;
2376 
2377 	gtk_widget_set_sensitive( slide->color2, (gboolean)i );
2378 
2379 	gtk_widget_queue_draw( slide->preview );
2380 }
2381 
2382 static void
img_gradient_color_set(GtkColorButton * button,ImgEmptySlide * slide)2383 img_gradient_color_set( GtkColorButton *button,
2384 						ImgEmptySlide  *slide )
2385 {
2386 	GdkColor  color;
2387 	gdouble  *my_color;
2388 
2389 	gtk_color_button_get_color( button, &color );
2390 
2391 	if( (GtkWidget *)button == slide->color2 )
2392 		my_color = slide->c_stop;
2393 	else
2394 		my_color = slide->c_start;
2395 
2396 	my_color[0] = (gdouble)color.red   / 0xffff;
2397 	my_color[1] = (gdouble)color.green / 0xffff;
2398 	my_color[2] = (gdouble)color.blue  / 0xffff;
2399 
2400 	gtk_widget_queue_draw( slide->preview );
2401 }
2402 
2403 static gboolean
img_gradient_expose(GtkWidget * widget,GdkEventExpose * expose,ImgEmptySlide * slide)2404 img_gradient_expose( GtkWidget      *widget,
2405 					 GdkEventExpose *expose,
2406 					 ImgEmptySlide  *slide )
2407 {
2408 	cairo_t         *cr;
2409 	cairo_pattern_t *pattern;
2410 	gint             w, h;
2411 	gdouble          radius, diffx, diffy;
2412 
2413 	gdk_drawable_get_size( expose->window, &w, &h );
2414 	cr = gdk_cairo_create( expose->window );
2415 	switch( slide->gradient )
2416 	{
2417 		case 0:
2418 			cairo_set_source_rgb( cr, slide->c_start[0],
2419 									  slide->c_start[1],
2420 									  slide->c_start[2] );
2421 			cairo_paint( cr );
2422 			break;
2423 
2424 		case 1:
2425 			pattern = cairo_pattern_create_linear( slide->pl_start[0],
2426 												   slide->pl_start[1],
2427 												   slide->pl_stop[0],
2428 												   slide->pl_stop[1] );
2429 			cairo_pattern_add_color_stop_rgb( pattern, 0,
2430 											  slide->c_start[0],
2431 											  slide->c_start[1],
2432 											  slide->c_start[2] );
2433 			cairo_pattern_add_color_stop_rgb( pattern, 1,
2434 											  slide->c_stop[0],
2435 											  slide->c_stop[1],
2436 											  slide->c_stop[2] );
2437 			cairo_set_source( cr, pattern );
2438 			cairo_paint( cr );
2439 			cairo_pattern_destroy( pattern );
2440 
2441 			/* Paint indicators */
2442 			cairo_rectangle( cr, slide->pl_start[0] - 7,
2443 								 slide->pl_start[1] - 7,
2444 								 15, 15 );
2445 			cairo_rectangle( cr, slide->pl_stop[0] - 7,
2446 								 slide->pl_stop[1] - 7,
2447 								 15, 15 );
2448 			cairo_set_source_rgb( cr, 0, 0, 0 );
2449 			cairo_stroke_preserve( cr );
2450 			cairo_set_source_rgb( cr, 1, 1, 1 );
2451 			cairo_fill( cr );
2452 			break;
2453 
2454 		case 2:
2455 			diffx = ABS( slide->pr_start[0] - slide->pr_stop[0] );
2456 			diffy = ABS( slide->pr_start[1] - slide->pr_stop[1] );
2457 			radius = sqrt( pow( diffx, 2 ) + pow( diffy, 2 ) );
2458 			pattern = cairo_pattern_create_radial( slide->pr_start[0],
2459 												   slide->pr_start[1],
2460 												   0,
2461 												   slide->pr_start[0],
2462 												   slide->pr_start[1],
2463 												   radius );
2464 			cairo_pattern_add_color_stop_rgb( pattern, 0,
2465 											  slide->c_start[0],
2466 											  slide->c_start[1],
2467 											  slide->c_start[2] );
2468 			cairo_pattern_add_color_stop_rgb( pattern, 1,
2469 											  slide->c_stop[0],
2470 											  slide->c_stop[1],
2471 											  slide->c_stop[2] );
2472 			cairo_set_source( cr, pattern );
2473 			cairo_paint( cr );
2474 			cairo_pattern_destroy( pattern );
2475 
2476 			/* Paint indicators */
2477 			cairo_rectangle( cr, slide->pr_start[0] - 7,
2478 								 slide->pr_start[1] - 7,
2479 								 15, 15 );
2480 			cairo_rectangle( cr, slide->pr_stop[0] - 7,
2481 								 slide->pr_stop[1] - 7,
2482 								 15, 15 );
2483 			cairo_set_source_rgb( cr, 0, 0, 0 );
2484 			cairo_stroke_preserve( cr );
2485 			cairo_set_source_rgb( cr, 1, 1, 1 );
2486 			cairo_fill( cr );
2487 			break;
2488 	}
2489 	cairo_destroy( cr );
2490 
2491 	return( TRUE );
2492 }
2493 
2494 static gboolean
img_gradient_press(GtkWidget * widget,GdkEventButton * button,ImgEmptySlide * slide)2495 img_gradient_press( GtkWidget      *widget,
2496 					GdkEventButton *button,
2497 					ImgEmptySlide  *slide )
2498 {
2499 	if( button->button != 1 )
2500 		return( FALSE );
2501 
2502 	switch( slide->gradient )
2503 	{
2504 		case 1:
2505 			if( button->x < ( slide->pl_start[0] + 8 ) &&
2506 				button->x > ( slide->pl_start[0] - 8 ) &&
2507 				button->y < ( slide->pl_start[1] + 8 ) &&
2508 				button->y > ( slide->pl_start[1] - 8 ) )
2509 			{
2510 				slide->drag = 1;
2511 			}
2512 			else if( button->x < ( slide->pl_stop[0] + 8 ) &&
2513 					 button->x > ( slide->pl_stop[0] - 8 ) &&
2514 					 button->y < ( slide->pl_stop[1] + 8 ) &&
2515 					 button->y > ( slide->pl_stop[1] - 8 ) )
2516 			{
2517 				slide->drag = 2;
2518 			}
2519 			break;
2520 
2521 		case 2:
2522 			if( button->x < ( slide->pr_start[0] + 8 ) &&
2523 				button->x > ( slide->pr_start[0] - 8 ) &&
2524 				button->y < ( slide->pr_start[1] + 8 ) &&
2525 				button->y > ( slide->pr_start[1] - 8 ) )
2526 			{
2527 				slide->drag = 1;
2528 			}
2529 			else if( button->x < ( slide->pr_stop[0] + 8 ) &&
2530 					 button->x > ( slide->pr_stop[0] - 8 ) &&
2531 					 button->y < ( slide->pr_stop[1] + 8 ) &&
2532 					 button->y > ( slide->pr_stop[1] - 8 ) )
2533 			{
2534 				slide->drag = 2;
2535 			}
2536 			break;
2537 	}
2538 
2539 	return( TRUE );
2540 }
2541 
2542 static gboolean
img_gradient_release(GtkWidget * widget,GdkEventButton * button,ImgEmptySlide * slide)2543 img_gradient_release( GtkWidget      *widget,
2544 					  GdkEventButton *button,
2545 					  ImgEmptySlide  *slide )
2546 {
2547 	slide->drag = 0;
2548 
2549 	return( TRUE );
2550 }
2551 
2552 static gboolean
img_gradient_move(GtkWidget * widget,GdkEventMotion * motion,ImgEmptySlide * slide)2553 img_gradient_move( GtkWidget      *widget,
2554 				   GdkEventMotion *motion,
2555 				   ImgEmptySlide  *slide )
2556 {
2557 	gint w, h;
2558 
2559 	if( ! slide->drag )
2560 		return( FALSE );
2561 
2562 	gdk_drawable_get_size( motion->window, &w, &h );
2563 	switch( slide->gradient )
2564 	{
2565 		case 1:
2566 			if( slide->drag == 1 )
2567 			{
2568 				slide->pl_start[0] = CLAMP( motion->x, 0, w );
2569 				slide->pl_start[1] = CLAMP( motion->y, 0, h );
2570 			}
2571 			else
2572 			{
2573 				slide->pl_stop[0] = CLAMP( motion->x, 0, w );
2574 				slide->pl_stop[1] = CLAMP( motion->y, 0, h );
2575 			}
2576 			break;
2577 
2578 		case 2:
2579 			if( slide->drag == 1 )
2580 			{
2581 				slide->pr_start[0] = CLAMP( motion->x, 0, w );
2582 				slide->pr_start[1] = CLAMP( motion->y, 0, h );
2583 			}
2584 			else
2585 			{
2586 				slide->pr_stop[0] = CLAMP( motion->x, 0, w );
2587 				slide->pr_stop[1] = CLAMP( motion->y, 0, h );
2588 			}
2589 			break;
2590 	}
2591 	gtk_widget_queue_draw( slide->preview );
2592 
2593 	return( TRUE );
2594 }
2595 
2596 gboolean
img_save_window_settings(img_window_struct * img)2597 img_save_window_settings( img_window_struct *img )
2598 {
2599 	GKeyFile *kf;
2600 	gchar    *group = "Interface settings";
2601 	gchar    *rc_file, *rc_path, *contents;
2602 	int       w, h, g, f; /* Width, height, gutter, flags */
2603 	gboolean  max;
2604 
2605 	gtk_window_get_size( GTK_WINDOW( img->imagination_window ), &w, &h );
2606 	g = gtk_paned_get_position( GTK_PANED( img->paned ) );
2607 	f = gdk_window_get_state( gtk_widget_get_window( img->imagination_window ) );
2608 	max = f & GDK_WINDOW_STATE_MAXIMIZED;
2609 
2610 	/* If window is maximized, store sizes that are a bit smaller than full
2611 	 * screen, else making window non-fullscreen will have no effect. */
2612 	if( max )
2613 	{
2614 		w -= 100;
2615 		h -= 100;
2616 	}
2617 
2618 	kf = g_key_file_new();
2619 	g_key_file_set_integer( kf, group, "width",   w );
2620 	g_key_file_set_integer( kf, group, "height",  h );
2621 	g_key_file_set_integer( kf, group, "gutter",  g );
2622 	g_key_file_set_integer( kf, group, "mode",    img->mode );
2623 	g_key_file_set_double(  kf, group, "zoom_p",  img->image_area_zoom );
2624 	g_key_file_set_double(  kf, group, "zoom_o",  img->overview_zoom );
2625 	g_key_file_set_boolean( kf, group, "quality", img->low_quality );
2626 	g_key_file_set_boolean( kf, group, "max",     max );
2627 	g_key_file_set_integer( kf, group, "preview", img->preview_fps );
2628 
2629 	rc_path = g_build_filename( g_get_home_dir(), ".config",
2630 								"imagination", NULL );
2631 	rc_file = g_build_filename( rc_path, "imaginationrc", NULL );
2632 	contents = g_key_file_to_data( kf, NULL, NULL );
2633 	g_key_file_free( kf );
2634 
2635 	g_mkdir_with_parents( rc_path, S_IRWXU );
2636 	g_file_set_contents( rc_file, contents, -1, NULL );
2637 
2638 	g_free( contents );
2639 	g_free( rc_file );
2640 	g_free( rc_path );
2641 
2642 	return( FALSE );
2643 }
2644 
2645 gboolean
img_load_window_settings(img_window_struct * img)2646 img_load_window_settings( img_window_struct *img )
2647 {
2648 	GKeyFile *kf;
2649 	gchar    *group = "Interface settings";
2650 	gchar    *rc_file;
2651 	int       w, h, g, m; /* Width, height, gutter, mode */
2652 	gboolean  max;
2653 
2654 	rc_file = g_build_filename( g_get_home_dir(), ".config",
2655 								"imagination", "imaginationrc", NULL );
2656 	if( ! g_file_test( rc_file, G_FILE_TEST_EXISTS ) )
2657 		return( FALSE );
2658 
2659 	kf = g_key_file_new();
2660 	g_key_file_load_from_file( kf, rc_file, G_KEY_FILE_NONE, NULL );
2661 
2662 	w                    = g_key_file_get_integer( kf, group, "width",   NULL );
2663 	h                    = g_key_file_get_integer( kf, group, "height",  NULL );
2664 	g                    = g_key_file_get_integer( kf, group, "gutter",  NULL );
2665 	m                    = g_key_file_get_integer( kf, group, "mode",    NULL );
2666 	img->image_area_zoom = g_key_file_get_double(  kf, group, "zoom_p",  NULL );
2667 	img->overview_zoom   = g_key_file_get_double(  kf, group, "zoom_o",  NULL );
2668 	img->low_quality     = g_key_file_get_boolean( kf, group, "quality", NULL );
2669 	max                  = g_key_file_get_boolean( kf, group, "max",     NULL );
2670 
2671 	/* New addition to environment settings */
2672 	img->preview_fps     = g_key_file_get_integer( kf, group, "preview", NULL );
2673 	if( ! img->preview_fps )
2674 		img->preview_fps = PREVIEW_FPS_DEFAULT;
2675 
2676 	g_key_file_free( kf );
2677 
2678 	/* Update mode */
2679 	img->mode = - 1;
2680 
2681 	img_switch_mode( img, m );
2682 	if (m == 0)
2683 		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (img->menu_preview_mode), TRUE);
2684 	else
2685 		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (img->menu_overview_mode), TRUE);
2686 	/* Update window size and gutter position */
2687 	gtk_window_set_default_size( GTK_WINDOW( img->imagination_window ), w, h );
2688 	gtk_paned_set_position( GTK_PANED( img->paned ), g );
2689 	if( max )
2690 		gtk_window_maximize( GTK_WINDOW( img->imagination_window ) );
2691 
2692 	/* Update zoom display */
2693 	gtk_widget_set_size_request( img->image_area,
2694 								 img->video_size[0] * img->image_area_zoom,
2695 								 img->video_size[1] * img->image_area_zoom );
2696 	g_object_set( img->over_cell, "zoom", img->overview_zoom, NULL );
2697 
2698 	return( TRUE );
2699 }
2700 
2701 void
img_set_window_default_settings(img_window_struct * img)2702 img_set_window_default_settings( img_window_struct *img )
2703 {
2704 	img->image_area_zoom = 1.0;
2705 	img->overview_zoom = 1.0;
2706 	img->low_quality = TRUE;
2707 	img->preview_fps = PREVIEW_FPS_DEFAULT;
2708 
2709 	/* Update mode */
2710 	img->mode = - 1;
2711 	img_switch_mode( img, 0 );
2712 
2713 	/* Update window size and gutter position */
2714 	gtk_window_set_default_size( GTK_WINDOW( img->imagination_window ),
2715 								 800, 600 );
2716 	gtk_paned_set_position( GTK_PANED( img->paned ), 500 );
2717 }
2718 
2719 void
img_rotate_slide(slide_struct * slide,ImgAngle angle,GtkProgressBar * progress)2720 img_rotate_slide( slide_struct   *slide,
2721 				  ImgAngle        angle,
2722 				  GtkProgressBar *progress )
2723 {
2724 	gchar *filename;
2725 
2726 	/* If this slide is gradient, do nothing */
2727 	if( ! slide->o_filename )
2728 		return;
2729 
2730 	/* If the angle is ANGLE_0, then simply copy original filename into rotated
2731 	 * filename. */
2732 	if( angle )
2733 	{
2734 		GdkPixbuf *image,
2735 				  *rotated;
2736 		gint       handle;
2737 		GError    *error = NULL;
2738 
2739 		image = gdk_pixbuf_new_from_file( slide->o_filename, NULL );
2740 		if( progress )
2741 			rotated = img_rotate_pixbuf( image, progress, angle );
2742 		else
2743 			rotated = gdk_pixbuf_rotate_simple( image, angle * 90 );
2744 		g_object_unref( image );
2745 
2746 		handle = g_file_open_tmp( "img-XXXXXX.jpg", &filename, NULL );
2747 		close( handle );
2748 		if( ! gdk_pixbuf_save( rotated, filename, "jpeg", &error, NULL ) )
2749 		{
2750 			g_message( "%s.", error->message );
2751 			g_error_free( error );
2752 			g_free( filename );
2753 			filename = g_strdup( slide->r_filename );
2754 		}
2755 		g_object_unref( rotated );
2756 	}
2757 	else
2758 		filename = g_strdup( slide->o_filename );
2759 
2760 	/* Delete any temporary image that is present from previous rotation */
2761 	if( slide->angle )
2762 		unlink( slide->r_filename );
2763 	g_free( slide->r_filename );
2764 	slide->r_filename = filename;
2765 	slide->angle = angle;
2766 }
2767 
2768 void
img_notebook_switch_page(GtkNotebook * notebook,GtkNotebookPage * page,guint page_num,img_window_struct * img)2769 img_notebook_switch_page (GtkNotebook       *notebook,
2770                           GtkNotebookPage   *page,
2771                           guint              page_num,
2772                           img_window_struct *img)
2773 {
2774     /* When message page is viewed, set it back to black */
2775     if (page_num == img->message_page)
2776     {
2777         PangoAttrList *   pango_list = pango_attr_list_new();
2778         PangoAttribute *  pango_attr = pango_attr_weight_new (PANGO_WEIGHT_NORMAL);
2779         pango_attr_list_insert(pango_list, pango_attr);
2780         gtk_label_set_attributes(GTK_LABEL(img->message_label), pango_list);
2781         pango_attr_list_unref (pango_list);
2782     }
2783 }