2
* Copyright © 2010 Yuvaraj Pandian T <yuvipanda@yuvi.in>
3
* Copyright © 2010 daniel g. siegel <dgsiegel@gnome.org>
4
* Copyright © 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
6
* Licensed under the GNU General Public License Version 2
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program. If not, see <http://www.gnu.org/licenses/>.
32
const int FULLSCREEN_TIMEOUT_INTERVAL = 5 * 1000;
33
const int EFFECTS_PER_PAGE = 9;
35
public class Cheese.MainWindow : Gtk.Window
37
private MediaMode current_mode;
39
private Gtk.Builder gtk_builder;
40
private Clutter.Script clutter_builder;
42
private GLib.Settings settings;
44
private Gtk.Widget thumbnails;
45
private GtkClutter.Embed viewport_widget;
46
private Gtk.VBox main_vbox;
47
private Eog.ThumbNav thumb_nav;
48
private Cheese.ThumbView thumb_view;
49
private Gtk.Alignment thumbnails_right;
50
private Gtk.Alignment thumbnails_bottom;
51
private Gtk.MenuBar menubar;
52
private Gtk.HBox leave_fullscreen_button_container;
53
private Gtk.ToggleButton photo_toggle_button;
54
private Gtk.ToggleButton video_toggle_button;
55
private Gtk.ToggleButton burst_toggle_button;
56
private Gtk.Button take_action_button;
57
private Gtk.Label take_action_button_label;
58
private Gtk.Image take_action_button_image;
59
private Gtk.ToggleButton effects_toggle_button;
60
private Gtk.Button leave_fullscreen_button;
61
private Gtk.HBox buttons_area;
62
private Gtk.Menu thumbnail_popup;
64
private Clutter.Stage viewport;
65
private Clutter.Box viewport_layout;
66
private Clutter.Texture video_preview;
67
private Clutter.BinLayout viewport_layout_manager;
68
private Clutter.Text countdown_layer;
69
private Clutter.Rectangle background_layer;
70
private Clutter.Text error_layer;
72
private Clutter.Box current_effects_grid;
73
private int current_effects_page = 0;
74
private ArrayList<Clutter.Box> effects_grids;
76
private Gtk.Action take_photo_action;
77
private Gtk.Action take_video_action;
78
private Gtk.Action take_burst_action;
79
private Gtk.Action photo_mode_action;
80
private Gtk.Action video_mode_action;
81
private Gtk.Action burst_mode_action;
82
private Gtk.ToggleAction effects_toggle_action;
83
private Gtk.ToggleAction wide_mode_action;
84
private Gtk.ToggleAction fullscreen_action;
85
private Gtk.Action countdown_action;
86
private Gtk.Action effects_page_prev_action;
87
private Gtk.Action effects_page_next_action;
89
private bool is_fullscreen;
90
private bool is_wide_mode;
91
private bool is_recording; /* Video Recording Flag */
92
private bool is_bursting;
93
private bool is_effects_selector_active;
94
private bool is_camera_actions_sensitive;
95
private bool action_cancelled;
96
private bool is_command_line_startup;
98
private Gtk.Button[] buttons;
100
private Cheese.Camera camera;
101
private Cheese.FileUtil fileutil;
102
private Cheese.Flash flash;
104
private Cheese.EffectsManager effects_manager;
105
private Cheese.PreferencesDialog preferences_dialog;
107
private Cheese.Effect selected_effect;
109
[CCode (instance_pos = -1)]
110
public void on_quit (Gtk.Action action)
115
[CCode (instance_pos = -1)]
116
public void on_preferences_dialog (Gtk.Action action)
118
if (preferences_dialog == null)
119
preferences_dialog = new Cheese.PreferencesDialog (camera, settings);
120
preferences_dialog.set_current_mode (current_mode);
121
preferences_dialog.show ();
124
public bool on_thumbnail_mouse_button_press (Gtk.Widget iconview,
125
Gdk.EventButton event)
128
path = thumb_view.get_path_at_pos ((int) event.x, (int) event.y);
133
if (!thumb_view.path_is_selected (path))
135
thumb_view.unselect_all ();
136
thumb_view.select_path (path);
137
thumb_view.set_cursor (path, null, false);
140
if (event.type == Gdk.EventType.BUTTON_PRESS)
142
if (event.button == 3)
144
thumbnail_popup.popup (null, thumb_view, null, event.button, event.time);
148
if (event.type == Gdk.EventType.2BUTTON_PRESS)
156
[CCode (instance_pos = -1)]
157
public void on_file_open (Gtk.Action ? action)
159
string filename, uri;
162
filename = thumb_view.get_selected_image ();
164
if (filename == null)
165
return; /* Nothing selected. */
169
uri = GLib.Filename.to_uri (filename);
170
screen = this.get_screen ();
171
Gtk.show_uri (screen, uri, Gtk.get_current_event_time ());
175
MessageDialog error_dialog = new MessageDialog (this,
176
Gtk.DialogFlags.MODAL |
177
Gtk.DialogFlags.DESTROY_WITH_PARENT,
178
Gtk.MessageType.ERROR,
184
error_dialog.destroy ();
188
[CCode (instance_pos = -1)]
189
public void on_file_delete (Gtk.Action action)
193
MessageDialog confirmation_dialog;
195
GLib.List<GLib.File> files = thumb_view.get_selected_images_list ();
197
for (int i = 0; i < files.length (); i++)
199
file = files<GLib.File>.nth (i).data;
203
confirmation_dialog = new MessageDialog.with_markup (this,
204
Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
205
Gtk.MessageType.WARNING,
206
Gtk.ButtonsType.NONE,
207
"Are you sure you want to permanently delete the file \"%s\"?",
208
file.get_basename ());
209
confirmation_dialog.add_button (Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL);
210
confirmation_dialog.add_button (Gtk.Stock.DELETE, Gtk.ResponseType.ACCEPT);
211
confirmation_dialog.format_secondary_text ("%s", "If you delete an item, it will be permanently lost");
212
response = confirmation_dialog.run ();
213
confirmation_dialog.destroy ();
214
if (response == Gtk.ResponseType.ACCEPT)
222
MessageDialog error_dialog = new MessageDialog (this,
223
Gtk.DialogFlags.MODAL |
224
Gtk.DialogFlags.DESTROY_WITH_PARENT,
225
Gtk.MessageType.ERROR,
227
"Could not delete %s",
231
error_dialog.destroy ();
237
[CCode (instance_pos = -1)]
238
public void on_file_move_to_trash (Gtk.Action action)
242
GLib.List<GLib.File> files = thumb_view.get_selected_images_list ();
244
for (int i = 0; i < files.length (); i++)
246
file = files<GLib.File>.nth (i).data;
256
MessageDialog error_dialog = new MessageDialog (this,
257
Gtk.DialogFlags.MODAL |
258
Gtk.DialogFlags.DESTROY_WITH_PARENT,
259
Gtk.MessageType.ERROR,
261
"Could not move %s to trash",
265
error_dialog.destroy ();
270
[CCode (instance_pos = -1)]
271
public void on_file_move_to_trash_all (Gtk.Action action)
276
File directory = File.new_for_path (fileutil.get_photo_path ());
277
FileEnumerator enumerator = directory.enumerate_children (FILE_ATTRIBUTE_STANDARD_NAME, 0, null);
279
while ((file_info = enumerator.next_file (null)) != null)
281
file_to_trash = File.new_for_path (fileutil.get_photo_path () + GLib.Path.DIR_SEPARATOR_S + file_info.get_name ());
282
file_to_trash.trash (null);
285
directory = File.new_for_path (fileutil.get_video_path ());
286
enumerator = directory.enumerate_children (FILE_ATTRIBUTE_STANDARD_NAME, 0, null);
288
while ((file_info = enumerator.next_file (null)) != null)
290
file_to_trash = File.new_for_path (fileutil.get_photo_path () + GLib.Path.DIR_SEPARATOR_S + file_info.get_name ());
291
file_to_trash.trash (null);
295
warning ("Error: %s\n", e.message);
300
[CCode (instance_pos = -1)]
301
public void on_file_save_as (Gtk.Action action)
303
string filename, basename;
304
FileChooserDialog save_as_dialog;
307
filename = thumb_view.get_selected_image ();
308
if (filename == null)
309
return; /* Nothing selected. */
311
save_as_dialog = new FileChooserDialog ("Save File",
313
Gtk.FileChooserAction.SAVE,
314
Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL,
315
Gtk.Stock.SAVE, Gtk.ResponseType.ACCEPT,
318
save_as_dialog.do_overwrite_confirmation = true;
319
basename = GLib.Filename.display_basename (filename);
320
save_as_dialog.set_current_name (basename);
321
save_as_dialog.set_current_folder (GLib.Environment.get_home_dir ());
323
response = save_as_dialog.run ();
325
save_as_dialog.hide ();
326
if (response == Gtk.ResponseType.ACCEPT)
328
string target_filename;
329
target_filename = save_as_dialog.get_filename ();
331
File src = File.new_for_path (filename);
332
File dest = File.new_for_path (target_filename);
336
src.copy (dest, FileCopyFlags.OVERWRITE, null, null);
340
MessageDialog error_dialog = new MessageDialog (this,
341
Gtk.DialogFlags.MODAL |
342
Gtk.DialogFlags.DESTROY_WITH_PARENT,
343
Gtk.MessageType.ERROR,
349
error_dialog.destroy ();
352
save_as_dialog.destroy ();
355
[CCode (instance_pos = -1)]
356
public void on_help_contents (Gtk.Action action)
359
screen = this.get_screen ();
361
Gtk.show_uri (screen, "ghelp:cheese", Gtk.get_current_event_time ());
364
warning ("Error: %s\n", err.message);
368
[CCode (instance_pos = -1)]
369
public void on_help_about (Gtk.Action action)
371
Gtk.AboutDialog about_dialog;
372
about_dialog = (Gtk.AboutDialog)gtk_builder.get_object ("aboutdialog");
373
about_dialog.set_transient_for (this);
374
about_dialog.set_modal (true);
375
about_dialog.version = Config.VERSION;
377
about_dialog.hide ();
380
[CCode (instance_pos = -1)]
381
public void on_layout_wide_mode (ToggleAction action)
383
if (!is_command_line_startup)
385
/* Don't save to settings when using -w mode from command-line, so
386
* command-line options change the mode for one run only. */
387
settings.set_boolean ("wide-mode", action.active);
389
set_wide_mode (action.active);
392
[CCode (instance_pos = -1)]
393
public void on_layout_fullscreen (ToggleAction action)
395
if (!is_command_line_startup)
397
/* Don't save to settings when using -f mode from command-line, so
398
* command-line options change the mode for one run only. */
399
settings.set_boolean ("fullscreen", action.active);
401
set_fullscreen_mode (action.active);
404
[CCode (instance_pos = -1)]
405
public void on_mode_change (RadioAction action)
407
set_mode ((MediaMode) action.value);
410
private void enable_mode_change ()
412
photo_mode_action.sensitive = true;
413
video_mode_action.sensitive = true;
414
burst_mode_action.sensitive = true;
415
effects_toggle_action.sensitive = true;
418
private void disable_mode_change ()
420
photo_mode_action.sensitive = false;
421
video_mode_action.sensitive = false;
422
burst_mode_action.sensitive = false;
423
effects_toggle_action.sensitive = false;
426
private void set_resolution(MediaMode mode)
431
unowned GLib.List<VideoFormat> formats = camera.get_video_formats ();
436
unowned Cheese.VideoFormat format;
442
case MediaMode.PHOTO:
443
case MediaMode.BURST:
444
width = settings.get_int ("photo-x-resolution");
445
height = settings.get_int ("photo-y-resolution");
447
case MediaMode.VIDEO:
448
width = settings.get_int ("video-x-resolution");
449
height = settings.get_int ("video-y-resolution");
453
for (int i = 0; i < formats.length (); i++)
455
format = formats<VideoFormat>.nth (i).data;
456
if (width == format.width && height == format.height)
458
camera.set_video_format (format);
464
private void set_mode (MediaMode mode)
466
this.current_mode = mode;
468
set_resolution (current_mode);
470
if (preferences_dialog != null)
471
preferences_dialog.set_current_mode (current_mode);
473
switch (this.current_mode)
475
case MediaMode.PHOTO:
476
take_photo_action.sensitive = true;
477
take_video_action.sensitive = false;
478
take_burst_action.sensitive = false;
479
take_action_button.related_action = take_photo_action;
482
case MediaMode.VIDEO:
483
take_photo_action.sensitive = false;
484
take_video_action.sensitive = true;
485
take_burst_action.sensitive = false;
486
take_action_button.related_action = take_video_action;
489
case MediaMode.BURST:
490
take_photo_action.sensitive = false;
491
take_video_action.sensitive = false;
492
take_burst_action.sensitive = true;
493
take_action_button.related_action = take_burst_action;
496
take_action_button_label.label = "<b>" + take_action_button.related_action.label + "</b>";
497
take_action_button.tooltip_text = take_action_button.related_action.tooltip;
500
private TimeoutSource fullscreen_timeout;
501
private void clear_fullscreen_timeout ()
503
if (fullscreen_timeout != null)
505
fullscreen_timeout.destroy ();
506
fullscreen_timeout = null;
510
private void set_fullscreen_timeout ()
512
fullscreen_timeout = new TimeoutSource (FULLSCREEN_TIMEOUT_INTERVAL);
513
fullscreen_timeout.attach (null);
514
fullscreen_timeout.set_callback (() => {buttons_area.hide ();
515
clear_fullscreen_timeout ();
519
private bool fullscreen_motion_notify_callback (Gtk.Widget viewport, EventMotion e)
521
/* Start a new timeout at the end of every mouse pointer movement.
522
* So all timeouts will be cancelled, except one at the last pointer movement.
523
* We call show even if the button isn't hidden. */
524
clear_fullscreen_timeout ();
525
buttons_area.show ();
526
set_fullscreen_timeout ();
530
private void set_fullscreen_mode (bool fullscreen_mode)
532
/* After the first time the window has been shown using this.show_all (),
533
* the value of leave_fullscreen_button_container.no_show_all should be set to false
534
* So that the next time leave_fullscreen_button_container.show_all () is called, the button is actually shown
535
* FIXME: If this code can be made cleaner/clearer, please do */
537
is_fullscreen = fullscreen_mode;
542
thumbnails_right.hide ();
546
thumbnails_bottom.hide ();
549
leave_fullscreen_button_container.no_show_all = false;
550
leave_fullscreen_button_container.show_all ();
552
/* Make all buttons look 'flat' */
553
foreach (Gtk.Button b in buttons)
555
if (b.get_name () != "take_action_button")
556
b.relief = Gtk.ReliefStyle.NONE;
559
viewport_widget.motion_notify_event.connect (fullscreen_motion_notify_callback);
560
set_fullscreen_timeout ();
566
thumbnails_right.show_all ();
570
thumbnails_bottom.show_all ();
573
leave_fullscreen_button_container.hide ();
575
/* Make all buttons look, uhm, Normal */
576
foreach (Gtk.Button b in buttons)
578
if (b.get_name () != "take_action_button")
579
b.relief = Gtk.ReliefStyle.NORMAL;
582
/* Stop timer so buttons_area does not get hidden after returning from
584
clear_fullscreen_timeout ();
585
/* Show the buttons area anyway - it might've been hidden in fullscreen mode */
586
buttons_area.show ();
587
viewport_widget.motion_notify_event.disconnect (fullscreen_motion_notify_callback);
588
this.unfullscreen ();
592
private void set_wide_mode (bool wide_mode)
594
is_wide_mode = wide_mode;
596
/* keep the viewport to its current size while rearranging the ui,
597
* so that thumbview moves from right to bottom and viceversa
598
* while the rest of the window stays unchanged */
599
Gtk.Allocation alloc;
600
viewport_widget.get_allocation (out alloc);
601
viewport_widget.set_size_request (alloc.width, alloc.height);
605
thumb_view.set_columns (1);
606
thumb_nav.set_vertical (true);
607
if (thumbnails_bottom.get_child () != null)
609
thumbnails_bottom.remove (thumb_nav);
611
thumbnails_right.add (thumb_nav);
612
thumbnails_right.show_all ();
613
thumbnails_right.resize_children ();
614
thumbnails_bottom.hide ();
618
thumb_view.set_columns (5000);
619
thumb_nav.set_vertical (false);
620
if (thumbnails_right.get_child () != null)
622
thumbnails_right.remove (thumb_nav);
624
thumbnails_bottom.add (thumb_nav);
625
thumbnails_bottom.show_all ();
626
thumbnails_bottom.resize_children ();
627
thumbnails_right.hide ();
630
/* handy trick to keep the window to the desired size while not
631
* requesting a fixed one. This way the window is resized to its
632
* natural size (particularly with the constraints imposed by the
633
* viewport, see above) but can still be shrinked down */
636
this.get_preferred_size(out req, out req);
637
this.resize (req.width, req.height);
638
viewport_widget.set_size_request (-1, -1);
641
/* To make sure that the layout manager manages the entire stage. */
642
public void on_stage_resize (Clutter.Actor actor,
643
Clutter.ActorBox box,
644
Clutter.AllocationFlags flags)
646
this.viewport_layout.set_size (viewport.width, viewport.height);
647
this.background_layer.set_size (viewport.width, viewport.height);
650
[CCode (instance_pos = -1)]
651
public void on_countdown_toggle (ToggleAction action)
653
settings.set_boolean ("countdown", action.active);
656
private void finish_countdown_callback ()
658
if (action_cancelled == false)
660
string file_name = fileutil.get_new_media_filename (this.current_mode);
662
if (settings.get_boolean ("flash"))
666
CanberraGtk.play_for_widget (this.main_vbox, 0,
667
Canberra.PROP_EVENT_ID, "camera-shutter",
668
Canberra.PROP_MEDIA_ROLE, "event",
669
Canberra.PROP_EVENT_DESCRIPTION, _("Shutter sound"),
671
this.camera.take_photo (file_name);
674
if (current_mode == MediaMode.PHOTO)
676
take_photo_action.sensitive = true;
677
enable_mode_change ();
681
Countdown current_countdown;
682
public void take_photo ()
684
if (settings.get_boolean ("countdown"))
686
if (current_mode == MediaMode.PHOTO)
688
take_photo_action.sensitive = false;
689
disable_mode_change ();
692
current_countdown = new Countdown (this.countdown_layer);
693
current_countdown.start (finish_countdown_callback);
697
finish_countdown_callback ();
701
private int burst_count;
702
private uint burst_callback_id;
704
private bool burst_take_photo ()
706
if (is_bursting && burst_count < settings.get_int ("burst-repeat"))
714
toggle_photo_bursting (false);
719
private bool on_key_release (Gdk.EventKey event)
723
key = Gdk.keyval_name (event.keyval);
724
if (strcmp (key, "Escape") == 0)
726
if ((current_countdown != null && current_countdown.running) || is_bursting || is_recording)
728
action_cancelled = true;
729
if (current_mode == MediaMode.PHOTO)
731
current_countdown.stop ();
732
finish_countdown_callback ();
735
if (current_mode == MediaMode.BURST)
737
toggle_photo_bursting (false);
740
if (current_mode == MediaMode.VIDEO)
742
toggle_video_recording (false);
744
action_cancelled = false;
747
if (is_effects_selector_active)
749
effects_toggle_action.set_active (false);
755
public void toggle_video_recording (bool is_start)
759
camera.start_video_recording (fileutil.get_new_media_filename (this.current_mode));
760
take_action_button_label.label = "<b>" + _("Stop _Recording") + "</b>";
761
take_action_button.tooltip_text = "Stop recording";
762
take_action_button_image.set_from_stock (Gtk.Stock.MEDIA_STOP, Gtk.IconSize.BUTTON);
763
this.is_recording = true;
764
this.disable_mode_change ();
768
camera.stop_video_recording ();
769
take_action_button_label.label = "<b>" + take_action_button.related_action.label + "</b>";
770
take_action_button.tooltip_text = take_action_button.related_action.tooltip;
771
take_action_button_image.set_from_stock (Gtk.Stock.MEDIA_RECORD, Gtk.IconSize.BUTTON);
772
this.is_recording = false;
773
this.enable_mode_change ();
777
public void toggle_photo_bursting (bool is_start)
782
this.disable_mode_change ();
783
effects_toggle_action.sensitive = false;
784
take_action_button_label.label = "<b>" + _("Stop _Taking Pictures") + "</b>";
785
take_action_button.tooltip_text = "Stop taking pictures";
788
/* 3500 ms is the approximate time for countdown animation to finish, so
789
if burst-delay time is less than 3500 ms, just use 3500 ms. */
790
if (((settings.get_int ("burst-delay") - 3500) < 1000) && settings.get_boolean ("countdown"))
792
burst_callback_id = GLib.Timeout.add (3500, burst_take_photo);
796
burst_callback_id = GLib.Timeout.add (settings.get_int ("burst-delay"), burst_take_photo);
801
if (current_countdown != null && current_countdown.running)
802
current_countdown.stop ();
805
this.enable_mode_change ();
806
take_action_button_label.label = "<b>" + take_action_button.related_action.label + "</b>";
807
take_action_button.tooltip_text = take_action_button.related_action.tooltip;
809
fileutil.reset_burst ();
810
GLib.Source.remove (burst_callback_id);
814
[CCode (instance_pos = -1)]
815
public void on_take_action (Gtk.Action action)
817
if (current_mode == MediaMode.PHOTO)
822
if (current_mode == MediaMode.VIDEO)
824
toggle_video_recording (!is_recording);
827
if (current_mode == MediaMode.BURST)
829
toggle_photo_bursting (!is_bursting);
833
[CCode (instance_pos = -1)]
834
public void on_effects_toggle (Gtk.ToggleAction action)
836
toggle_effects_selector (action.active);
837
take_photo_action.sensitive = !action.active;
838
take_video_action.sensitive = !action.active;
839
take_burst_action.sensitive = !action.active;
840
photo_mode_action.sensitive = !action.active;
841
video_mode_action.sensitive = !action.active;
842
burst_mode_action.sensitive = !action.active;
845
public bool on_selected_effect_change (Clutter.Actor source,
846
Clutter.ButtonEvent event)
848
selected_effect = source.get_data ("effect");
849
camera.set_effect (selected_effect);
850
settings.set_string ("selected-effect", selected_effect.name);
851
effects_toggle_action.set_active (false);
855
[CCode (instance_pos = -1)]
856
public void on_prev_effects_page (Gtk.Action action)
858
if (current_effects_page != 0)
860
activate_effects_page (current_effects_page - 1);
864
[CCode (instance_pos = -1)]
865
public void on_next_effects_page (Gtk.Action action)
867
if (current_effects_page != (effects_manager.effects.size / EFFECTS_PER_PAGE))
869
activate_effects_page (current_effects_page + 1);
873
private void activate_effects_page (int number)
875
if (!is_effects_selector_active)
877
current_effects_page = number;
878
if (viewport_layout.get_children ().index (current_effects_grid) != -1)
880
viewport_layout.remove ((Clutter.Actor) current_effects_grid);
882
current_effects_grid = effects_grids[number];
883
current_effects_grid.set ("opacity", 0);
884
viewport_layout.add ((Clutter.Actor) current_effects_grid);
885
current_effects_grid.animate (Clutter.AnimationMode.LINEAR, 1000, "opacity", 255);
887
for (int i = 0; i < effects_manager.effects.size; i++)
889
int page_of_effect = i / EFFECTS_PER_PAGE;
890
Cheese.Effect effect = effects_manager.effects[i];
891
if (page_of_effect == number)
893
if (!effect.is_preview_connected ())
895
Clutter.Texture texture = effect.get_data<Clutter.Texture> ("texture");
896
camera.connect_effect_texture (effect, texture);
898
effect.enable_preview ();
902
if (effect.is_preview_connected ())
903
effect.disable_preview ();
906
setup_effects_page_switch_sensitivity ();
909
private void setup_effects_page_switch_sensitivity ()
911
effects_page_prev_action.sensitive = (is_effects_selector_active && current_effects_page != 0);
912
effects_page_next_action.sensitive =
913
(is_effects_selector_active && current_effects_page != effects_manager.effects.size / EFFECTS_PER_PAGE);
916
private void toggle_effects_selector (bool active)
918
is_effects_selector_active = active;
921
video_preview.hide ();
923
if (effects_grids.size == 0)
925
error_layer.text = _("No effects found");
930
current_effects_grid.show ();
931
activate_effects_page (current_effects_page);
936
if (effects_grids.size == 0)
942
current_effects_grid.hide ();
944
video_preview.show ();
947
camera.toggle_effects_pipeline (active);
948
setup_effects_page_switch_sensitivity ();
951
private void setup_effects_selector ()
953
if (current_effects_grid == null)
955
effects_manager = new EffectsManager ();
956
effects_manager.load_effects ();
958
/* Must initialize effects_grids before returning, as it is dereferenced later, bug 654671. */
959
effects_grids = new ArrayList<Clutter.Box> ();
961
if (effects_manager.effects.size == 0)
963
warning ("gnome-video-effects is not installed.");
967
for (int i = 0; i <= effects_manager.effects.size / EFFECTS_PER_PAGE; i++)
969
Clutter.TableLayout table_layout = new TableLayout ();
970
Clutter.Box grid = new Clutter.Box (table_layout);
971
effects_grids.add (grid);
972
table_layout.set_column_spacing (10);
973
table_layout.set_row_spacing (10);
976
for (int i = 0; i < effects_manager.effects.size; i++)
978
Effect effect = effects_manager.effects[i];
979
Clutter.Texture texture = new Clutter.Texture ();
980
Clutter.BinLayout layout = new Clutter.BinLayout (Clutter.BinAlignment.CENTER,
981
Clutter.BinAlignment.CENTER);
982
Clutter.Box box = new Clutter.Box (layout);
983
Clutter.Text text = new Clutter.Text ();
984
Clutter.Rectangle rect = new Clutter.Rectangle ();
987
rect.color = Clutter.Color.from_string ("black");
989
texture.keep_aspect_ratio = true;
990
box.pack ((Clutter.Actor) texture, null, null);
992
box.set_data ("effect", effect);
993
effect.set_data ("texture", texture);
995
box.button_release_event.connect (on_selected_effect_change);
997
text.text = effect.name;
998
text.color = Clutter.Color.from_string ("white");
1000
rect.height = text.height + 5;
1001
box.pack ((Clutter.Actor) rect,
1002
"x-align", Clutter.BinAlignment.FILL,
1003
"y-align", Clutter.BinAlignment.END, null);
1005
box.pack ((Clutter.Actor) text,
1006
"x-align", Clutter.BinAlignment.CENTER,
1007
"y-align", Clutter.BinAlignment.END, null);
1009
Clutter.TableLayout table_layout = (Clutter.TableLayout) effects_grids[i / EFFECTS_PER_PAGE].layout_manager;
1010
table_layout.pack ((Clutter.Actor) box,
1011
(i % EFFECTS_PER_PAGE) % 3,
1012
(i % EFFECTS_PER_PAGE) / 3);
1013
table_layout.set_expand (box, false, false);
1016
setup_effects_page_switch_sensitivity ();
1017
current_effects_grid = effects_grids[0];
1021
private Gee.HashMap<string, bool> action_sensitivities;
1022
public void toggle_camera_actions_sensitivities (bool active)
1024
is_camera_actions_sensitive = active;
1027
foreach (string key in action_sensitivities.keys)
1029
Gtk.Action action = (Gtk.Action)gtk_builder.get_object (key);
1030
action.sensitive = action_sensitivities.get (key);
1035
action_sensitivities = new HashMap<string, bool> (GLib.str_hash);
1036
GLib.SList<weak GLib.Object> objects = gtk_builder.get_objects ();
1037
foreach (GLib.Object obj in objects)
1039
if (obj is Gtk.Action)
1041
Gtk.Action action = (Gtk.Action)obj;
1042
action_sensitivities.set (action.name, action.sensitive);
1046
/* Keep only these actions sensitive. */
1047
string [] active_actions = { "cheese_action",
1057
"move_all_to_trash"};
1059
/* Gross hack because Vala's `in` operator doesn't really work */
1061
foreach (GLib.Object obj in objects)
1064
if (obj is Gtk.Action)
1066
Gtk.Action action = (Gtk.Action)obj;
1067
foreach (string s in active_actions)
1069
if (action.name == s)
1075
((Gtk.Action)obj).sensitive = false;
1081
private void camera_state_changed (Gst.State new_state)
1083
if (new_state == Gst.State.PLAYING)
1085
if (!is_camera_actions_sensitive)
1086
toggle_camera_actions_sensitivities (true);
1088
Effect effect = effects_manager.get_effect (settings.get_string ("selected-effect"));
1090
camera.set_effect (effect);
1094
public void set_startup_wide_mode ()
1098
/* Cheese was already in wide mode, avoid setting it again. */
1102
is_command_line_startup = true;
1103
wide_mode_action.set_active (true);
1104
is_command_line_startup = false;
1107
public void set_startup_fullscreen_mode ()
1109
is_command_line_startup = true;
1110
fullscreen_action.set_active (true);
1111
is_command_line_startup = false;
1114
public void setup_ui ()
1116
gtk_builder = new Gtk.Builder ();
1117
clutter_builder = new Clutter.Script ();
1118
fileutil = new FileUtil ();
1119
flash = new Flash (this);
1120
settings = new GLib.Settings ("org.gnome.Cheese");
1123
gtk_builder.add_from_file (GLib.Path.build_filename (Config.PACKAGE_DATADIR, "cheese-actions.ui"));
1124
gtk_builder.add_from_file (GLib.Path.build_filename (Config.PACKAGE_DATADIR, "cheese-about.ui"));
1125
gtk_builder.add_from_file (GLib.Path.build_filename (Config.PACKAGE_DATADIR, "cheese-main-window.ui"));
1126
gtk_builder.connect_signals (this);
1128
clutter_builder.load_from_file (GLib.Path.build_filename (Config.PACKAGE_DATADIR, "cheese-viewport.json"));
1131
error ("Error: %s", err.message);
1134
main_vbox = (Gtk.VBox)gtk_builder.get_object ("mainbox_normal");
1135
thumbnails = (Gtk.Widget)gtk_builder.get_object ("thumbnails");
1136
viewport_widget = (GtkClutter.Embed)gtk_builder.get_object ("viewport");
1137
viewport = (Clutter.Stage)viewport_widget.get_stage ();
1138
thumbnails_right = (Gtk.Alignment)gtk_builder.get_object ("thumbnails_right");
1139
thumbnails_bottom = (Gtk.Alignment)gtk_builder.get_object ("thumbnails_bottom");
1140
menubar = (Gtk.MenuBar)gtk_builder.get_object ("main_menubar");
1141
leave_fullscreen_button_container = (Gtk.HBox)gtk_builder.get_object ("leave_fullscreen_button_bin");
1142
photo_toggle_button = (Gtk.ToggleButton)gtk_builder.get_object ("photo_toggle_button");
1143
video_toggle_button = (Gtk.ToggleButton)gtk_builder.get_object ("video_toggle_button");
1144
burst_toggle_button = (Gtk.ToggleButton)gtk_builder.get_object ("burst_toggle_button");
1145
take_action_button = (Gtk.Button)gtk_builder.get_object ("take_action_button");
1146
take_action_button_label = (Gtk.Label)gtk_builder.get_object ("take_action_button_internal_label");
1147
take_action_button_image = (Gtk.Image)gtk_builder.get_object ("take_action_button_internal_image");
1148
effects_toggle_button = (Gtk.ToggleButton)gtk_builder.get_object ("effects_toggle_button");
1149
leave_fullscreen_button = (Gtk.Button)gtk_builder.get_object ("leave_fullscreen_button");
1150
buttons_area = (Gtk.HBox)gtk_builder.get_object ("buttons_area");
1151
thumbnail_popup = (Gtk.Menu)gtk_builder.get_object ("thumbnail_popup");
1153
take_photo_action = (Gtk.Action)gtk_builder.get_object ("take_photo");
1154
take_video_action = (Gtk.Action)gtk_builder.get_object ("take_video");
1155
take_burst_action = (Gtk.Action)gtk_builder.get_object ("take_burst");
1156
photo_mode_action = (Gtk.Action)gtk_builder.get_object ("photo_mode");
1157
video_mode_action = (Gtk.Action)gtk_builder.get_object ("video_mode");
1158
burst_mode_action = (Gtk.Action)gtk_builder.get_object ("burst_mode");
1159
effects_toggle_action = (Gtk.ToggleAction)gtk_builder.get_object ("effects_toggle");
1160
countdown_action = (Gtk.Action)gtk_builder.get_object ("countdown");
1161
wide_mode_action = (Gtk.ToggleAction)gtk_builder.get_object ("wide_mode");
1162
fullscreen_action = (Gtk.ToggleAction)gtk_builder.get_object ("fullscreen");
1163
effects_page_next_action = (Gtk.Action)gtk_builder.get_object ("effects_page_next");
1164
effects_page_prev_action = (Gtk.Action)gtk_builder.get_object ("effects_page_prev");
1166
/* Array contains all 'buttons', for easier manipulation
1167
* IMPORTANT: IF ANOTHER BUTTON IS ADDED UNDER THE VIEWPORT, ADD IT TO THIS ARRAY */
1168
buttons = {photo_toggle_button,
1169
video_toggle_button,
1170
burst_toggle_button,
1172
effects_toggle_button,
1173
leave_fullscreen_button};
1175
video_preview = (Clutter.Texture)clutter_builder.get_object ("video_preview");
1176
viewport_layout = (Clutter.Box)clutter_builder.get_object ("viewport_layout");
1177
viewport_layout_manager = (Clutter.BinLayout)clutter_builder.get_object ("viewport_layout_manager");
1178
countdown_layer = (Clutter.Text)clutter_builder.get_object ("countdown_layer");
1179
background_layer = (Clutter.Rectangle)clutter_builder.get_object ("background");
1180
error_layer = (Clutter.Text)clutter_builder.get_object ("error_layer");
1182
video_preview.keep_aspect_ratio = true;
1183
video_preview.request_mode = Clutter.RequestMode.HEIGHT_FOR_WIDTH;
1184
viewport.add_actor (background_layer);
1185
viewport_layout.set_layout_manager (viewport_layout_manager);
1187
viewport.add_actor (viewport_layout);
1189
viewport.allocation_changed.connect (on_stage_resize);
1191
thumb_view = new Cheese.ThumbView ();
1192
thumb_nav = new Eog.ThumbNav (thumb_view, false);
1194
Gtk.CssProvider css;
1197
css = new Gtk.CssProvider();
1198
css.load_from_path (GLib.Path.build_filename (Config.PACKAGE_DATADIR, "cheese.css"));
1202
stdout.printf ("Error: %s\n", e.message);
1205
Gtk.StyleContext context;
1206
context = thumb_view.get_style_context ();
1207
screen = Gdk.Screen.get_default();
1208
context.add_provider_for_screen (screen, css, 600);
1210
thumb_view.button_press_event.connect (on_thumbnail_mouse_button_press);
1212
this.add (main_vbox);
1213
main_vbox.show_all ();
1215
/* needed for the sizing tricks in set_wide_mode (allocation is 0
1216
* if the widget is not realized */
1217
viewport_widget.realize ();
1219
/* call set_active instead of our set_wide_mode so that the toggle
1220
* action state is updated */
1221
wide_mode_action.set_active (settings.get_boolean ("wide-mode"));
1223
/* apparently set_active doesn't emit toggled nothing has
1224
* changed, do it manually */
1225
if (!settings.get_boolean ("wide-mode"))
1226
wide_mode_action.toggled ();
1228
set_mode (MediaMode.PHOTO);
1229
setup_effects_selector ();
1231
toggle_camera_actions_sensitivities (false);
1233
this.key_release_event.connect (on_key_release);
1235
if (settings.get_boolean ("fullscreen"))
1236
fullscreen_action.active = true;
1239
public void setup_camera (string ? uri)
1244
if (uri != null && uri.length > 0)
1247
device = settings.get_string ("camera");
1249
camera = new Camera (video_preview,
1251
settings.get_int ("photo-x-resolution"),
1252
settings.get_int ("photo-y-resolution"));
1254
camera.setup (device);
1258
video_preview.hide ();
1259
warning ("Error: %s\n", err.message);
1260
error_layer.text = err.message;
1261
error_layer.show ();
1263
toggle_camera_actions_sensitivities (false);
1267
value = settings.get_double ("brightness");
1269
camera.set_balance_property ("brightness", value);
1271
value = settings.get_double ("contrast");
1273
camera.set_balance_property ("contrast", value);
1275
value = settings.get_double ("hue");
1277
camera.set_balance_property ("hue", value);
1279
value = settings.get_double ("saturation");
1281
camera.set_balance_property ("saturation", value);
1283
camera.state_flags_changed.connect (camera_state_changed);
1286
public void start_thumbview_monitors ()
1288
thumb_view.start_monitoring_video_path (fileutil.get_video_path ());
1289
thumb_view.start_monitoring_photo_path (fileutil.get_photo_path ());