Merge lp:~l-admin-3/snap-elementary/snap-clutter-gst into lp:snap-elementary

Proposed by Marcus Wichelmann
Status: Merged
Merged at revision: 352
Proposed branch: lp:~l-admin-3/snap-elementary/snap-clutter-gst
Merge into: lp:snap-elementary
Diff against target: 2130 lines (+683/-1247)
21 files modified
CMakeLists.txt (+20/-17)
README (+3/-4)
data/CMakeLists.txt (+3/-0)
schemas/CMakeLists.txt (+3/-2)
schemas/org.pantheon.snap.gschema.xml (+6/-17)
src/Application.vala (+79/-86)
src/Backend/Settings.vala (+46/-0)
src/CMakeLists.txt (+12/-13)
src/Dialogs/Preferences.vala (+0/-31)
src/MainWindow.vala (+184/-335)
src/Services/Settings.vala (+0/-36)
src/Services/ThumbnailProvider.vala (+0/-159)
src/Utils.vala (+45/-142)
src/Widgets/Camera.vala (+0/-176)
src/Widgets/CameraView.vala (+88/-0)
src/Widgets/Countdown.vala (+0/-117)
src/Widgets/Gallery.vala (+0/-69)
src/Widgets/HeaderBar.vala (+126/-0)
src/Widgets/LoadingView.vala (+57/-0)
src/Widgets/NoCamera.vala (+0/-32)
src/config.vala.cmake (+11/-11)
To merge this branch: bzr merge lp:~l-admin-3/snap-elementary/snap-clutter-gst
Reviewer Review Type Date Requested Status
Cody Garver (community) Approve
Review via email: mp+283164@code.launchpad.net

Commit message

Rebase application on clutterGst and refactor frontend

Description of the change

This branch rebases the application on the ClutterGst library which provides some useful features and keeps our own code cleaner. Because of these huge backend changes the frontend has been refactored.

Overview:
* Instant start thanks to connecting to the video device in an own thread
* No more flickering when (un)focusing the window
* Video mode is working again (!) and stores records as mp4-files
* Higher frame rate
* Gallery button removed (The camera library should be handled by pantheon-photos now)
* Fullscreen mode added
* Use Granite's AlertView
* Tidy up CMake files
* Code better readable now and only half as long (!)

A camera selection for multiple video devices can be added later, if ClutterGst supports it correctly.

To post a comment you must log in.
Revision history for this message
Marcus Wichelmann (l-admin-3) wrote :

TODO: Change encoding format to webm

Revision history for this message
Cody Garver (codygarver) wrote :

Merged with corrected output video container .ogv. Gonna report a bug about webm support.

review: Approve
Revision history for this message
Marcus Wichelmann (l-admin-3) wrote :

Okay, thank you! 😄
Sorry, had no time to look into this for now…

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-12-11 19:37:59 +0000
3+++ CMakeLists.txt 2016-01-19 15:51:17 +0000
4@@ -1,14 +1,16 @@
5-# Check http://elementaryos.org/docs/developer-guide/cmake for documentation
6+# Project name
7+project (snap-photobooth)
8
9+# CMake version
10 cmake_minimum_required (VERSION 2.8)
11 cmake_policy (VERSION 2.8)
12-project (snap-photobooth)
13-enable_testing ()
14+
15+# Project configuration
16 set (DATADIR "${CMAKE_INSTALL_PREFIX}/share/snap-photobooth")
17 set (PKGDATADIR "${DATADIR}/snap-photobooth")
18 set (GETTEXT_PACKAGE "snap-photobooth")
19-set (RELEASE_NAME "The elementary Text Editor.")
20-set (VERSION "0.2.0.1")
21+set (RELEASE_NAME "The elementary Camera Viewer.")
22+set (VERSION "0.3")
23 set (VERSION_INFO "Release")
24 set (PREFIX ${CMAKE_INSTALL_PREFIX})
25 set (DOLLAR "$")
26@@ -20,6 +22,7 @@
27 set (CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION}")
28 set (CPACK_SOURCE_IGNORE_FILES "/build/;/.bzr/;/.bzrignore;~$;${CPACK_SOURCE_IGNORE_FILES}")
29
30+# CPack
31 include (CPack)
32 add_custom_target (dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
33
34@@ -27,26 +30,29 @@
35 configure_file (${CMAKE_SOURCE_DIR}/src/config.vala.cmake ${CMAKE_SOURCE_DIR}/src/config.vala)
36
37 # Some definitions
38-add_definitions(-DGETTEXT_PACKAGE=\"${GETTEXT_PACKAGE}\")
39+add_definitions (-DGETTEXT_PACKAGE=\"${GETTEXT_PACKAGE}\")
40
41 # Vala
42 find_package (Vala REQUIRED)
43 include (ValaVersion)
44 ensure_vala_version ("0.20" MINIMUM)
45 include (ValaPrecompile)
46+add_definitions (-DVALA_VERSION="${VALA_SHORTVER}")
47
48-add_definitions(-DVALA_VERSION="${VALA_SHORTVER}")
49-add_definitions(-w) # Disable gcc warnings
50+# Disable gcc warnings
51+add_definitions (-w)
52
53 # Dependencies
54 find_package (PkgConfig)
55-set (SNAP_DEPS gee-0.8 gobject-2.0 glib-2.0 gio-2.0 gtk+-3.0>=3.10 gdk-x11-3.0 granite gstreamer-1.0 gstreamer-video-1.0 gstreamer-pbutils-1.0 x11 gudev-1.0 zeitgeist-2.0)
56+set (SNAP_DEPS gio-2.0 gee-0.8 gtk+-3.0 granite clutter-gst-3.0 clutter-gtk-1.0)
57 pkg_check_modules (DEPS REQUIRED ${SNAP_DEPS})
58
59-set(NORMAL_CFLAGS ${DEPS_CFLAGS})
60-set(NORMAL_LINK_DIRS ${DEPS_LIBRARY_DIRS})
61-set(NORMAL_LIBRARIES ${DEPS_LIBRARIES})
62+# Linking paramaters
63+set (NORMAL_CFLAGS ${DEPS_CFLAGS})
64+set (NORMAL_LINK_DIRS ${DEPS_LIBRARY_DIRS})
65+set (NORMAL_LIBRARIES ${DEPS_LIBRARIES})
66
67+# Linking
68 add_definitions (${DEPS_CFLAGS})
69 link_libraries (${DEPS_LIBRARIES})
70 link_directories (${DEPS_LIBRARY_DIRS})
71@@ -54,8 +60,5 @@
72 # Subdirectories
73 add_subdirectory (src)
74 add_subdirectory (schemas)
75-add_subdirectory (po)
76-
77-# Data
78-install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/snap-photobooth.appdata.xml DESTINATION share/appdata)
79-install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/snap-photobooth.desktop DESTINATION share/applications)
80+add_subdirectory (data)
81+add_subdirectory (po)
82\ No newline at end of file
83
84=== modified file 'README'
85--- README 2014-04-08 18:58:54 +0000
86+++ README 2016-01-19 15:51:17 +0000
87@@ -1,11 +1,10 @@
88 Dependencies
89 ------------
90- - valac-0.20
91+ - valac-0.30
92 - libgtk-3.0-dev
93- - libgstreamer1.0-dev
94- - libzeitgeist-2.0-dev
95 - libgranite-dev
96- - libgee-dev
97+ - libclutter-gst-3.0-dev
98+ - libclutter-gtk-1.0-dev
99
100 Testing and installation
101 ------------------------
102
103=== added file 'data/CMakeLists.txt'
104--- data/CMakeLists.txt 1970-01-01 00:00:00 +0000
105+++ data/CMakeLists.txt 2016-01-19 15:51:17 +0000
106@@ -0,0 +1,3 @@
107+# Install appinfo files
108+install (FILES snap-photobooth.appdata.xml DESTINATION share/appdata)
109+install (FILES snap-photobooth.desktop DESTINATION share/applications)
110\ No newline at end of file
111
112=== removed directory 'data/pixmaps'
113=== removed file 'data/pixmaps/thumbnail-frame.png'
114Binary files data/pixmaps/thumbnail-frame.png 2012-08-13 07:09:44 +0000 and data/pixmaps/thumbnail-frame.png 1970-01-01 00:00:00 +0000 differ
115=== modified file 'schemas/CMakeLists.txt'
116--- schemas/CMakeLists.txt 2013-07-27 22:46:41 +0000
117+++ schemas/CMakeLists.txt 2016-01-19 15:51:17 +0000
118@@ -1,2 +1,3 @@
119-include(GSettings)
120-add_schema("org.pantheon.snap.gschema.xml")
121\ No newline at end of file
122+# Install settings schema
123+include (GSettings)
124+add_schema ("org.pantheon.snap.gschema.xml")
125\ No newline at end of file
126
127=== modified file 'schemas/org.pantheon.snap.gschema.xml'
128--- schemas/org.pantheon.snap.gschema.xml 2014-03-11 04:31:49 +0000
129+++ schemas/org.pantheon.snap.gschema.xml 2016-01-19 15:51:17 +0000
130@@ -1,22 +1,11 @@
131 <schemalist>
132+ <enum id="org.pantheon.snap.settings.mode">
133+ <value nick="photo" value="0" />
134+ <value nick="video" value="1" />
135+ </enum>
136 <schema path="/org/pantheon/snap/settings/" id="org.pantheon.snap.settings" gettext-domain="snap">
137- <key name="bg-color" type="s">
138- <default>'black'</default>
139- <summary>The background color of the camera preview.</summary>
140- <description>The background color of the camera preview.</description>
141- </key>
142- <key name="countdown-time" type="i">
143- <default>3</default>
144- <summary>The time for the countdown.</summary>
145- <description>The time for the countdown.</description>
146- </key>
147- <key name="countdown" type="b">
148- <default>true</default>
149- <summary>Use or not the countdown.</summary>
150- <description>Use or not the countdown.</description>
151- </key>
152- <key name="mode" type="i">
153- <default>0</default>
154+ <key name="mode" enum="org.pantheon.snap.settings.mode">
155+ <default>"photo"</default>
156 <summary>The mode of the camera, photo or video</summary>
157 <description>Photo mode is represented by 0, video mode by 1</description>
158 </key>
159
160=== renamed file 'src/Snap.vala' => 'src/Application.vala'
161--- src/Snap.vala 2015-12-21 13:52:21 +0000
162+++ src/Application.vala 2016-01-19 15:51:17 +0000
163@@ -1,86 +1,79 @@
164-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
165-/***
166- BEGIN LICENSE
167-
168- Copyright (C) 2011-2013 Mario Guerriero <mario@elementaryos.org>
169- This program is free software: you can redistribute it and/or modify it
170- under the terms of the GNU Lesser General Public License version 3, as
171- published by the Free Software Foundation.
172-
173- This program is distributed in the hope that it will be useful, but
174- WITHOUT ANY WARRANTY; without even the implied warranties of
175- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
176- PURPOSE. See the GNU General Public License for more details.
177-
178- You should have received a copy of the GNU General Public License along
179- with this program. If not, see <http://www.gnu.org/licenses>
180-
181- END LICENSE
182-***/
183-
184-namespace Snap {
185- public Snap.Services.Settings settings;
186-
187- public class SnapApp : Granite.Application {
188- /**
189- * Translatable launcher (.desktop) strings to be added to template (.pot) file.
190- * These strings should reflect any changes in these launcher keys in .desktop file
191- */
192- public const string CAMERA = N_("Camera");
193- public const string COMMENT = N_("Take photos and videos with the camera");
194- public const string GENERIC_NAME = N_("Photo Booth");
195- public const string PROGRAM_NAME = "Snap";
196- public const string QUICKLIST_ABOUT_STOCK = N_("About Snap");
197- public const string QUICKLIST_ABOUT_GENERIC = N_("About Camera");
198-
199- public SnapWindow window = null;
200-
201- construct {
202- build_data_dir = Constants.DATADIR;
203- build_pkg_data_dir = Constants.PKGDATADIR;
204- build_release_name = Constants.RELEASE_NAME;
205- build_version = Constants.VERSION;
206- build_version_info = Constants.VERSION_INFO;
207-
208- program_name = PROGRAM_NAME;
209- exec_name = "snap-photobooth";
210- app_years = "2011-2015";
211- app_icon = "accessories-camera";
212- app_launcher = "snap-photobooth.desktop";
213- application_id = "net.launchpad.snap-elementary";
214- main_url = "https://launchpad.net/snap-elementary";
215- bug_url = "https://bugs.launchpad.net/snap-elementary";
216- help_url = "https://answers.launchpad.net/snap-elementary";
217- translate_url = "https://translations.launchpad.net/snap-elementary";
218- about_authors = {"Mario Guerriero <mario@elementaryos.org>", null };
219- about_artists = { "Daniel Fore <daniel.p.fore@gmail.com >", "Harvey Cabaguio <harveycabaguio@gmail.com>", null };
220- about_translators = _("translator-credits");
221- about_license_type = Gtk.License.GPL_3_0;
222- }
223-
224- public SnapApp () {
225- Granite.Services.Logger.initialize ("Snap");
226- Granite.Services.Logger.DisplayLevel = Granite.Services.LogLevel.DEBUG;
227-
228- settings = new Snap.Services.Settings ();
229- }
230-
231- protected override void activate () {
232- if (get_windows () == null) {
233- window = new SnapWindow (this);
234- window.show ();
235- }
236- else {
237- window.present ();
238- }
239- }
240-
241- public static int main (string[] args) {
242- Gst.init (ref args);
243-
244- var app = new SnapApp ();
245-
246- return app.run (args);
247- }
248- }
249-}
250+/*
251+ * Copyright (c) 2011-2016 Snap Developers (http://launchpad.net/snap-elementary)
252+ *
253+ * This program is free software; you can redistribute it and/or
254+ * modify it under the terms of the GNU General Public
255+ * License as published by the Free Software Foundation; either
256+ * version 2 of the License, or (at your option) any later version.
257+ *
258+ * This program is distributed in the hope that it will be useful,
259+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
260+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
261+ * General Public License for more details.
262+ *
263+ * You should have received a copy of the GNU General Public
264+ * License along with this program; if not, write to the
265+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
266+ * Boston, MA 02111-1307, USA.
267+ *
268+ * Authored by: Marcus Wichelmann <marcus.wichelmann@hotmail.de>
269+ */
270+
271+public class Snap.Application : Granite.Application {
272+ /**
273+ * Translatable launcher (.desktop) strings to be added to template (.pot) file.
274+ * These strings should reflect any changes in these launcher keys in .desktop file
275+ */
276+ public static const string CAMERA = N_("Camera");
277+ public static const string COMMENT = N_("Take photos and videos with the camera");
278+ public static const string GENERIC_NAME = N_("Photo Booth");
279+ public static const string PROGRAM_NAME = "Snap";
280+ public static const string QUICKLIST_ABOUT_STOCK = N_("About Snap");
281+ public static const string QUICKLIST_ABOUT_GENERIC = N_("About Camera");
282+
283+ public static int main (string[] args) {
284+ ClutterGst.init (ref args);
285+
286+ var application = new Application ();
287+
288+ return application.run (args);
289+ }
290+
291+ public MainWindow? main_window = null;
292+
293+ construct {
294+ build_data_dir = Config.DATADIR;
295+ build_pkg_data_dir = Config.PKGDATADIR;
296+ build_release_name = Config.RELEASE_NAME;
297+ build_version = Config.VERSION;
298+ build_version_info = Config.VERSION_INFO;
299+
300+ program_name = PROGRAM_NAME;
301+ exec_name = "snap-photobooth";
302+ app_years = "2011-2015";
303+ app_icon = "accessories-camera";
304+ app_launcher = "snap-photobooth.desktop";
305+ application_id = "net.launchpad.snap-elementary";
306+ main_url = "https://launchpad.net/snap-elementary";
307+ bug_url = "https://bugs.launchpad.net/snap-elementary";
308+ help_url = "https://answers.launchpad.net/snap-elementary";
309+ translate_url = "https://translations.launchpad.net/snap-elementary";
310+ about_authors = { "Marcus Wichelmann <marcus.wichelmann@hotmail.de>", "Mario Guerriero <mario@elementaryos.org>", null };
311+ about_artists = { "Daniel Fore <daniel.p.fore@gmail.com >", "Harvey Cabaguio <harveycabaguio@gmail.com>", null };
312+ about_translators = _("translator-credits");
313+ about_license_type = Gtk.License.GPL_3_0;
314+ }
315+
316+ public Application () {
317+ /* TODO */
318+ }
319+
320+ protected override void activate () {
321+ if (this.get_windows () == null) {
322+ main_window = new MainWindow (this);
323+ main_window.show_all ();
324+ } else {
325+ main_window.present ();
326+ }
327+ }
328+}
329\ No newline at end of file
330
331=== added directory 'src/Backend'
332=== added file 'src/Backend/Settings.vala'
333--- src/Backend/Settings.vala 1970-01-01 00:00:00 +0000
334+++ src/Backend/Settings.vala 2016-01-19 15:51:17 +0000
335@@ -0,0 +1,46 @@
336+/*
337+ * Copyright (c) 2011-2016 Snap Developers (http://launchpad.net/snap-elementary)
338+ *
339+ * This program is free software; you can redistribute it and/or
340+ * modify it under the terms of the GNU General Public
341+ * License as published by the Free Software Foundation; either
342+ * version 2 of the License, or (at your option) any later version.
343+ *
344+ * This program is distributed in the hope that it will be useful,
345+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
346+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
347+ * General Public License for more details.
348+ *
349+ * You should have received a copy of the GNU General Public
350+ * License along with this program; if not, write to the
351+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
352+ * Boston, MA 02111-1307, USA.
353+ *
354+ * Authored by: Marcus Wichelmann <marcus.wichelmann@hotmail.de>
355+ */
356+
357+public class Snap.Backend.Settings : Granite.Services.Settings {
358+ protected string mode { get; set; }
359+
360+ public signal void action_type_changed (Utils.ActionType action_type);
361+
362+ public Settings () {
363+ base ("org.pantheon.snap.settings");
364+
365+ connect_signals ();
366+ }
367+
368+ public Utils.ActionType get_action_type () {
369+ return (mode == "photo" ? Utils.ActionType.PHOTO : Utils.ActionType.VIDEO);
370+ }
371+
372+ public void set_action_type (Utils.ActionType action_type) {
373+ mode = (action_type == Utils.ActionType.PHOTO ? "photo" : "video");
374+ }
375+
376+ private void connect_signals () {
377+ this.notify["mode"].connect (() => {
378+ action_type_changed (get_action_type ());
379+ });
380+ }
381+}
382\ No newline at end of file
383
384=== modified file 'src/CMakeLists.txt'
385--- src/CMakeLists.txt 2015-10-01 12:24:52 +0000
386+++ src/CMakeLists.txt 2016-01-19 15:51:17 +0000
387@@ -1,25 +1,24 @@
388-vala_precompile(VALA_C
389- Resources.vala
390- Snap.vala
391- SnapWindow.vala
392- ######
393- Services/Settings.vala
394- Services/ThumbnailProvider.vala
395- ######
396- Widgets/Camera.vala
397- Widgets/Gallery.vala
398- Widgets/NoCamera.vala
399- ######
400+# Configure precompilation
401+vala_precompile (VALA_C
402 config.vala
403+ Utils.vala
404+ Application.vala
405+ MainWindow.vala
406+ Widgets/HeaderBar.vala
407+ Widgets/LoadingView.vala
408+ Widgets/CameraView.vala
409+ Backend/Settings.vala
410 PACKAGES
411 ${SNAP_DEPS}
412 posix
413 OPTIONS
414- --vapidir=${CMAKE_SOURCE_DIR}/vapi
415 --thread
416+ --target-glib=2.32
417 --enable-experimental
418 )
419
420+# Register new executable
421 add_executable (snap-photobooth ${VALA_C})
422
423+# Installation
424 install (TARGETS snap-photobooth RUNTIME DESTINATION bin)
425
426=== removed directory 'src/Dialogs'
427=== removed file 'src/Dialogs/Preferences.vala'
428--- src/Dialogs/Preferences.vala 2015-02-26 12:35:06 +0000
429+++ src/Dialogs/Preferences.vala 1970-01-01 00:00:00 +0000
430@@ -1,31 +0,0 @@
431-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
432-/***
433- BEGIN LICENSE
434-
435- Copyright (C) 2011-2012 Mario Guerriero <mefrio.g@gmail.com>
436- This program is free software: you can redistribute it and/or modify it
437- under the terms of the GNU Lesser General Public License version 3, as
438- published by the Free Software Foundation.
439-
440- This program is distributed in the hope that it will be useful, but
441- WITHOUT ANY WARRANTY; without even the implied warranties of
442- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
443- PURPOSE. See the GNU General Public License for more details.
444-
445- You should have received a copy of the GNU General Public License along
446- with this program. If not, see <http://www.gnu.org/licenses>
447-
448- END LICENSE
449-***/
450-
451-namespace Snap.Dialogs {
452- public class Preferences : Gtk.Dialog {
453- public Preferences (string? title, SnapWindow? window) {
454- this.title = title;
455- this.type_hint = Gdk.WindowTypeHint.DIALOG;
456- this.set_transient_for (window);
457- set_default_size (300, 200);
458- modal = true;
459- }
460- }
461-}
462
463=== renamed file 'src/SnapWindow.vala' => 'src/MainWindow.vala'
464--- src/SnapWindow.vala 2015-03-31 22:50:02 +0000
465+++ src/MainWindow.vala 2016-01-19 15:51:17 +0000
466@@ -1,335 +1,184 @@
467-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
468-/***
469- BEGIN LICENSE
470-
471- Copyright (C) 2011-2013 Mario Guerriero <mario@elementaryos.org>
472- This program is free software: you can redistribute it and/or modify it
473- under the terms of the GNU Lesser General Public License version 3, as
474- published by the Free Software Foundation.
475-
476- This program is distributed in the hope that it will be useful, but
477- WITHOUT ANY WARRANTY; without even the implied warranties of
478- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
479- PURPOSE. See the GNU General Public License for more details.
480-
481- You should have received a copy of the GNU General Public License along
482- with this program. If not, see <http://www.gnu.org/licenses>
483-
484- END LICENSE
485-***/
486-
487-namespace Snap {
488-
489- public class SnapWindow : Gtk.Window {
490- private const string VIDEO_ICON_SYMBOLIC = "view-list-video-symbolic";
491- private const string PHOTO_ICON_SYMBOLIC = "view-list-images-symbolic";
492- private const string STOP_ICON_SYMBOLIC = "media-playback-stop-symbolic";
493-
494- private Snap.SnapApp snap_app;
495-
496- private Snap.Widgets.Camera camera;
497- private Snap.Widgets.Gallery gallery;
498- private Snap.Widgets.NoCamera no_camera;
499- private Gtk.HeaderBar toolbar;
500- private Gtk.Stack stack;
501- private Granite.Widgets.ModeButton mode_button;
502- private Gtk.Button take_button;
503- private Gtk.ButtonBox gallery_button_box;
504- private Gtk.ToggleButton gallery_button;
505- private Gtk.Statusbar statusbar;
506- private File photo_path;
507- private File video_path;
508-
509- private bool camera_detected;
510- private string camera_uri;
511-
512- public SnapWindow (Snap.SnapApp snap_app) {
513- this.snap_app = snap_app;
514- this.set_application (this.snap_app);
515-
516- this.title = "Snap";
517- this.icon_name = "snap-photobooth";
518- this.set_size_request (640, 480);
519-
520- // Get paths
521- photo_path = File.new_for_path (Resources.get_media_dir (Widgets.Camera.ActionType.PHOTO));
522- video_path = File.new_for_path (Resources.get_media_dir (Widgets.Camera.ActionType.VIDEO));
523-
524- // Create missing directories
525- create_directories ();
526-
527- // camera
528- camera_uri = this.detect_camera ();
529- camera_detected = camera_uri != "";
530-
531- // Setup the camera
532- this.camera = new Snap.Widgets.Camera (camera_uri);
533-
534- // Calculate thumbnail sizes
535- var thumb_width = (camera.video_width - 19) / 4 - 18; // 19 = scrollbar_width + 2 * margin; 4 = row-count; 18 = 2 * item_padding + column_spacing
536- var thumb_height = (int)(((float)thumb_width / camera.video_width) * camera.video_height);
537-
538- // Init thumbnail providers
539- Resources.photo_thumb_provider = new Services.ThumbnailProvider (photo_path, thumb_width, thumb_height);
540- Resources.video_thumb_provider = new Services.ThumbnailProvider (video_path, thumb_width, thumb_height);
541-
542- // Setup UI
543- setup_window ();
544-
545- // Set the window position
546- this.window_position = Gtk.WindowPosition.CENTER;
547- }
548-
549- void setup_window () {
550- // Toolbar
551- toolbar = new Gtk.HeaderBar ();
552- toolbar.show_close_button = true;
553- this.set_titlebar (toolbar);
554-
555- // Gallery button
556- gallery_button_box = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
557- gallery_button_box.set_spacing (4);
558- gallery_button_box.set_layout (Gtk.ButtonBoxStyle.START);
559-
560- gallery_button = new Gtk.ToggleButton.with_label (_("Gallery"));
561- gallery_button.sensitive = gallery_files_exists ();
562- gallery_button.toggled.connect (() => {
563- if (this.stack.get_visible_child () != this.gallery) {
564- this.show_gallery ();
565- this.load_thumbnails ();
566- }
567- else {
568- this.show_camera ();
569- }
570- });
571- gallery_button_box.pack_start (gallery_button, true, true, 0);
572-
573- toolbar.pack_start (gallery_button_box);
574-
575- // Mode switcher
576- mode_button = new Granite.Widgets.ModeButton ();
577- mode_button.valign = Gtk.Align.CENTER;
578- mode_button.halign = Gtk.Align.CENTER;
579-
580- mode_button.append (load_toolbar_icon (PHOTO_ICON_SYMBOLIC));
581- mode_button.append (load_toolbar_icon (VIDEO_ICON_SYMBOLIC));
582-
583- // Hide video mode until fixed https://bugs.launchpad.net/snap-elementary/+bug/1374072
584- //toolbar.pack_end (mode_button);
585-
586- var take_button_style = new Gtk.CssProvider ();
587- try {
588- take_button_style.load_from_data (Resources.TAKE_BUTTON_STYLESHEET, -1);
589- } catch (Error e) {
590- warning (e.message);
591- }
592-
593- // Take button
594- take_button = new Gtk.Button ();
595- take_button.get_style_context ().add_provider (take_button_style, Gtk.STYLE_PROVIDER_PRIORITY_USER);
596- take_button.get_style_context ().add_class ("take-button");
597- take_button.get_style_context ().add_class ("destructive-action");
598- take_button.get_style_context ().add_class ("raised");
599- take_button.clicked.connect (() => {
600- if (this.stack.get_visible_child () != this.camera) {
601- gallery_button.set_active (false);
602- return;
603- }
604- if (!this.camera.get_capturing ()) {
605- this.camera.take_start ();
606- if (this.camera.get_action_type() == Widgets.Camera.ActionType.VIDEO) {
607- set_take_button_icon (Snap.Widgets.Camera.ActionType.CAPTURING);
608- }
609-
610- } else {
611- this.camera.take_stop ();
612- if (this.camera.get_action_type() == Widgets.Camera.ActionType.VIDEO) {
613- set_take_button_icon (Snap.Widgets.Camera.ActionType.VIDEO);
614- }
615- }
616- });
617- take_button.set_sensitive (camera_detected);
618-
619- var take_button_box = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
620- take_button_box.set_spacing (4);
621- take_button_box.set_layout (Gtk.ButtonBoxStyle.START);
622- take_button_box.pack_start (take_button, false, false, 0);
623-
624- // Make the take button wider
625- take_button.set_size_request (54, -1);
626-
627- toolbar.set_custom_title (take_button_box);
628-
629- // Setup NoCamera widget
630- this.no_camera = new Snap.Widgets.NoCamera ();
631-
632- // Setup gallery widget
633- this.gallery = new Snap.Widgets.Gallery ();
634-
635- // Setup preview area
636- this.camera.capture_start.connect (() => {
637- // Disable uneeded buttons
638- gallery_button.sensitive = false;
639- this.mode_button.sensitive = false;
640- this.set_take_button_icon (Snap.Widgets.Camera.ActionType.CAPTURING);
641- });
642- this.camera.capture_stop.connect (() => {
643- // Enable extra buttons
644- gallery_button.sensitive = gallery_files_exists ();
645- this.mode_button.sensitive = true;
646- this.set_take_button_icon (this.camera.get_action_type ());
647- });
648-
649- // Setup window main content area
650- this.stack = new Gtk.Stack ();
651- this.stack.transition_type = Gtk.StackTransitionType.SLIDE_UP_DOWN;
652- this.stack.add_named (this.gallery, "Gallery");
653- this.stack.add_named (this.camera, "Camera");
654- this.stack.add_named (this.no_camera, "NoCamera");
655- if (camera_detected)
656- this.stack.set_visible_child (this.camera); // Show camera on launch
657- else
658- this.stack.set_visible_child (this.no_camera); // Show no_camera on launch
659-
660- // Statusbar
661- statusbar = new Gtk.Statusbar ();
662-
663- // Some signals
664- mode_button.mode_changed.connect (on_mode_changed);
665- this.key_press_event.connect (this.on_key_press_event);
666-
667- mode_button.set_active (Snap.settings.mode);
668-
669- this.add (this.stack);
670- this.show_all ();
671- }
672-
673- private string detect_camera () {
674- try {
675- var video_devices = File.new_for_path ("/dev/.");
676- FileEnumerator enumerator = video_devices.enumerate_children (FileAttribute.STANDARD_NAME, 0);
677- FileInfo info;
678- while ((info = enumerator.next_file (null)) != null) {
679- if (info.get_name ().has_prefix ("video")){
680- debug ("camera found: %s", info.get_name ());
681- return "v4l2:///dev/%s".printf (info.get_name ());
682- }
683- }
684- } catch (Error err) {
685- debug ("camera detection failed: %s", err.message);
686- }
687-
688- debug ("no camera");
689- return "";
690- }
691-
692- protected override bool delete_event (Gdk.EventAny event) {
693- Resources.photo_thumb_provider.clear_cache ();
694- Resources.video_thumb_provider.clear_cache ();
695- return false;
696- }
697-
698- private void on_mode_changed () {
699- var type = (mode_button.selected == 0) ?
700- Snap.Widgets.Camera.ActionType.PHOTO : Snap.Widgets.Camera.ActionType.VIDEO;
701-
702- Snap.settings.mode = type;
703-
704- this.camera.set_action_type (type);
705- this.set_take_button_icon (type);
706- }
707-
708- private void set_take_button_icon (Snap.Widgets.Camera.ActionType? type) {
709- string icon_name;
710-
711- if (type == Snap.Widgets.Camera.ActionType.PHOTO)
712- icon_name = PHOTO_ICON_SYMBOLIC;
713- else if (type == Snap.Widgets.Camera.ActionType.VIDEO)
714- icon_name = VIDEO_ICON_SYMBOLIC;
715- else if (type == Snap.Widgets.Camera.ActionType.CAPTURING)
716- icon_name = STOP_ICON_SYMBOLIC;
717- else
718- assert_not_reached();
719-
720- take_button.set_image (load_toolbar_icon (icon_name));
721- }
722-
723- private Gtk.Image load_toolbar_icon (string icon_name) {
724- var icon = new ThemedIcon.with_default_fallbacks (icon_name);
725- return new Gtk.Image.from_gicon (icon, Gtk.IconSize.SMALL_TOOLBAR);
726- }
727-
728- private bool on_key_press_event (Gdk.EventKey ev) {
729- // 32 is the ASCII value for spacebar
730- if (ev.keyval == 32)
731- this.take_button.clicked ();
732-
733- return false;
734- }
735-
736- private void lock_camera_actions () {
737- this.mode_button.set_sensitive (false);
738- }
739-
740- private void unlock_camera_actions () {
741- this.mode_button.set_sensitive (true);
742- }
743-
744- private void load_thumbnails () {
745- this.gallery.clear_view ();
746- Resources.photo_thumb_provider.parse_thumbs.begin ();
747- Resources.video_thumb_provider.parse_thumbs.begin ();
748- }
749-
750- private void show_gallery () {
751- if (camera_detected) {
752- this.camera.stop ();
753- }
754- this.lock_camera_actions ();
755- this.stack.set_visible_child (this.gallery);
756- }
757-
758- private void show_camera () {
759- if (camera_detected) {
760- this.stack.set_visible_child (this.camera); // Show camera on launch
761- this.camera.play ();
762- this.unlock_camera_actions ();
763- }
764- else {
765- this.stack.set_visible_child (this.no_camera); // Show no_camera on launch
766- }
767- }
768-
769- private void create_directories () {
770- try {
771- if (!photo_path.query_exists ())
772- photo_path.make_directory ();
773-
774- if (!video_path.query_exists ())
775- video_path.make_directory ();
776- } catch (Error e) {
777- warning ("Error: Creating media-directories failed: %s", e.message);
778- }
779- }
780-
781- private bool gallery_files_exists () {
782- FileInfo file_info;
783-
784- try {
785- FileEnumerator enumerator_photo = photo_path.enumerate_children (FileAttribute.STANDARD_NAME, 0);
786- FileEnumerator enumerator_video = video_path.enumerate_children (FileAttribute.STANDARD_NAME, 0);
787-
788- if ((file_info = enumerator_photo.next_file ()) != null ||
789- (file_info = enumerator_video.next_file ()) != null) {
790- // Gallery is not empty
791- return true;
792- }
793- } catch (Error perr) {
794- warning ("Error: check_gallery_files photo failed: %s", perr.message);
795- }
796-
797- // Gallery is empty, button may be disabled
798- return false;
799- }
800- }
801-}
802+/*
803+ * Copyright (c) 2011-2016 Snap Developers (http://launchpad.net/snap-elementary)
804+ *
805+ * This program is free software; you can redistribute it and/or
806+ * modify it under the terms of the GNU General Public
807+ * License as published by the Free Software Foundation; either
808+ * version 2 of the License, or (at your option) any later version.
809+ *
810+ * This program is distributed in the hope that it will be useful,
811+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
812+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
813+ * General Public License for more details.
814+ *
815+ * You should have received a copy of the GNU General Public
816+ * License along with this program; if not, write to the
817+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
818+ * Boston, MA 02111-1307, USA.
819+ *
820+ * Authored by: Marcus Wichelmann <marcus.wichelmann@hotmail.de>
821+ */
822+
823+public class Snap.MainWindow : Gtk.Window {
824+ private const string VIDEO_ICON_SYMBOLIC = "view-list-video-symbolic";
825+ private const string PHOTO_ICON_SYMBOLIC = "view-list-images-symbolic";
826+ private const string STOP_ICON_SYMBOLIC = "media-playback-stop-symbolic";
827+
828+ private Backend.Settings settings;
829+
830+ private Widgets.HeaderBar header_bar;
831+
832+ private Gtk.Stack stack;
833+
834+ private Widgets.LoadingView loading_view;
835+
836+ private Granite.Widgets.AlertView no_device_view;
837+
838+ private GtkClutter.Embed clutter_embed;
839+ private Clutter.Stage clutter_stage;
840+
841+ private Widgets.CameraView? camera_view = null;
842+
843+ private ClutterGst.Aspectratio camera_content;
844+ private Clutter.Actor camera_actor;
845+
846+ private bool is_fullscreened = false;
847+
848+ public MainWindow (Application application) {
849+ this.set_application (application);
850+ this.title = "Snap";
851+ this.icon_name = "snap-photobooth";
852+ this.set_size_request (640, 480);
853+ this.window_position = Gtk.WindowPosition.CENTER;
854+
855+ settings = new Backend.Settings ();
856+
857+ build_ui ();
858+ connect_signals ();
859+
860+ new Thread<int> (null, () => {
861+ debug ("Initializing camera manager...");
862+
863+ initialize_camera_manager ();
864+
865+ return 0;
866+ });
867+ }
868+
869+ private void build_ui () {
870+ this.add_events (Gdk.EventMask.KEY_PRESS_MASK);
871+ this.set_default_size (1000, 700);
872+
873+ header_bar = new Widgets.HeaderBar (settings);
874+
875+ stack = new Gtk.Stack ();
876+ stack.transition_type = Gtk.StackTransitionType.CROSSFADE;
877+ stack.transition_duration = 500;
878+
879+ loading_view = new Widgets.LoadingView ();
880+
881+ no_device_view = new Granite.Widgets.AlertView (_("No camera device found"),
882+ _("Connect a webcam or any other supported video device to your computer to display it's picture here."),
883+ "camera-web");
884+
885+ clutter_embed = new GtkClutter.Embed ();
886+
887+ clutter_stage = (Clutter.Stage)clutter_embed.get_stage ();
888+ clutter_stage.background_color = Clutter.Color.get_static (Clutter.StaticColor.BLACK);
889+ clutter_stage.set_fullscreen (true);
890+
891+ camera_content = new ClutterGst.Aspectratio ();
892+
893+ camera_actor = new GtkClutter.Actor ();
894+ camera_actor.content = camera_content;
895+ camera_actor.add_constraint (new Clutter.BindConstraint (clutter_stage, Clutter.BindCoordinate.SIZE, 0));
896+
897+ clutter_stage.add_child (camera_actor);
898+
899+ stack.add_named (loading_view, "loading");
900+ stack.add_named (no_device_view, "no-device");
901+ stack.add_named (clutter_embed, "camera");
902+
903+ this.set_titlebar (header_bar);
904+ this.add (stack);
905+ }
906+
907+ private void initialize_camera_manager () {
908+ ClutterGst.CameraManager camera_manager = ClutterGst.CameraManager.get_default ();
909+
910+ Idle.add (() => {
911+ GenericArray<ClutterGst.CameraDevice> camera_devices = camera_manager.get_camera_devices ();
912+
913+ if (camera_devices.length > 0 && camera_devices[0].get_name () != null) {
914+ initialize_camera_view ();
915+ } else {
916+ stack.set_visible_child_name ("no-device");
917+
918+ debug ("No camera device found.");
919+ }
920+
921+ return false;
922+ });
923+ }
924+
925+ private void initialize_camera_view () {
926+ camera_view = new Widgets.CameraView ();
927+ camera_view.initialized.connect (() => {
928+ header_bar.set_camera_controls_sensitive (true);
929+ stack.set_visible_child_name ("camera");
930+ });
931+
932+ camera_content.set_player (camera_view);
933+
934+ loading_view.set_status (_("Connecting to \"%s\"…".printf (camera_view.get_camera_device ().get_name ())));
935+ }
936+
937+ private void connect_signals () {
938+ this.key_press_event.connect ((event) => {
939+ switch (event.keyval) {
940+ case Gdk.Key.F11 :
941+
942+ if (is_fullscreened) {
943+ this.unfullscreen ();
944+ } else {
945+ this.fullscreen ();
946+ }
947+
948+ is_fullscreened = !is_fullscreened;
949+
950+ break;
951+
952+ default:
953+
954+ return Gdk.EVENT_PROPAGATE;
955+ }
956+
957+ return Gdk.EVENT_STOP;
958+ });
959+
960+ header_bar.take_photo_clicked.connect (() => {
961+ if (camera_view == null) {
962+ return;
963+ }
964+
965+ camera_view.take_photo ();
966+ });
967+ header_bar.start_recording_clicked.connect (() => {
968+ if (camera_view == null) {
969+ return;
970+ }
971+
972+ if (camera_view.start_recording ()) {
973+ header_bar.set_is_recording (true);
974+ }
975+ });
976+ header_bar.stop_recording_clicked.connect (() => {
977+ if (camera_view == null) {
978+ return;
979+ }
980+
981+ camera_view.stop_recording ();
982+ header_bar.set_is_recording (false);
983+ });
984+ }
985+}
986\ No newline at end of file
987
988=== removed directory 'src/Services'
989=== removed file 'src/Services/Settings.vala'
990--- src/Services/Settings.vala 2015-04-01 10:54:18 +0000
991+++ src/Services/Settings.vala 1970-01-01 00:00:00 +0000
992@@ -1,36 +0,0 @@
993-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
994-/***
995- BEGIN LICENSE
996-
997- Copyright (C) 2011-2012 Mario Guerriero <mario@elementaryos.org>
998- This program is free software: you can redistribute it and/or modify it
999- under the terms of the GNU Lesser General Public License version 3, as published
1000- by the Free Software Foundation.
1001-
1002- This program is distributed in the hope that it will be useful, but
1003- WITHOUT ANY WARRANTY; without even the implied warranties of
1004- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1005- PURPOSE. See the GNU General Public License for more details.
1006-
1007- You should have received a copy of the GNU General Public License along
1008- with this program. If not, see <http://www.gnu.org/licenses/>
1009-
1010- END LICENSE
1011-***/
1012-
1013-
1014-namespace Snap.Services {
1015- public class Settings : Granite.Services.Settings {
1016- public string bg_color { get; set; }
1017- public bool countdown { get; set; }
1018- public int countdown_time { get; set; }
1019- public int mode { get; set; }
1020-
1021- public Settings () {
1022- base ("org.pantheon.snap.settings");
1023-
1024- // Reset video mode to 0 until fixed https://bugs.launchpad.net/snap-elementary/+bug/1374072
1025- this.mode = 0;
1026- }
1027- }
1028-}
1029
1030=== removed file 'src/Services/ThumbnailProvider.vala'
1031--- src/Services/ThumbnailProvider.vala 2015-02-26 13:57:05 +0000
1032+++ src/Services/ThumbnailProvider.vala 1970-01-01 00:00:00 +0000
1033@@ -1,159 +0,0 @@
1034-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
1035-/***
1036- BEGIN LICENSE
1037-
1038- Copyright (C) 2011-2012 Mario Guerriero <mario@elementaryos.org>
1039- This program is free software: you can redistribute it and/or modify it
1040- under the terms of the GNU Lesser General Public License version 3, as published
1041- by the Free Software Foundation.
1042-
1043- This program is distributed in the hope that it will be useful, but
1044- WITHOUT ANY WARRANTY; without even the implied warranties of
1045- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1046- PURPOSE. See the GNU General Public License for more details.
1047-
1048- You should have received a copy of the GNU General Public License along
1049- with this program. If not, see <http://www.gnu.org/licenses/>
1050-
1051- END LICENSE
1052-***/
1053-
1054-namespace Snap.Services {
1055- public class Thumbnail : GLib.Object {
1056- public File file { get; protected set; }
1057- public Gdk.Pixbuf pixbuf { get; protected set; }
1058- public bool is_temp { get; public set; }
1059- public File temp_file { get; public set; }
1060-
1061- public Thumbnail (File file, Gdk.Pixbuf pixbuf) {
1062- this.file = file;
1063- this.pixbuf = pixbuf;
1064- }
1065- }
1066-
1067- public class ThumbnailProvider : GLib.Object {
1068- private File path;
1069- private Gee.Set<Thumbnail> cache;
1070- private int temp_thumb;
1071-
1072- public uint thumb_width = 0;
1073- public uint thumb_height = 0;
1074-
1075- public signal void thumbnail_loaded (Thumbnail thumbnail);
1076-
1077- /**
1078- * Creates a new object of time ThumbnailProvider. This type of objects are used
1079- * to obtain thumbnails for files in a specific path
1080- * @param path the path where the provider will look for thumbnails
1081- */
1082- public ThumbnailProvider (File path, uint thumb_width, uint thumb_height) {
1083- this.path = path;
1084- this.cache = new Gee.TreeSet<Thumbnail> ();
1085- this.temp_thumb = 0;
1086- this.thumb_width = thumb_width;
1087- this.thumb_height = thumb_height;
1088- }
1089-
1090- /**
1091- * Asynchronously load thumbnails and add them in a Gee.TreeSet object. The thumbnail_loaded
1092- * is emitted whenever a new Thumbnail is fully loaded
1093- */
1094- public async void parse_thumbs () {
1095- try {
1096- var e = yield this.path.enumerate_children_async (FileAttribute.STANDARD_NAME,
1097- 0, Priority.DEFAULT);
1098- while (true) {
1099- var files = yield e.next_files_async (10, Priority.DEFAULT);
1100- if (files == null) {
1101- break;
1102- }
1103-
1104- foreach (var info in files) {
1105- File thumb_path = this.path.resolve_relative_path (info.get_name ());
1106- var thumb = this.get_thumbnail (thumb_path);
1107- if (thumb != null) {
1108- this.cache.add (thumb);
1109- thumbnail_loaded (thumb);
1110- }
1111- }
1112- }
1113- } catch (Error err) {
1114- warning ("Error: parse_thumbs failed: %s", err.message);
1115- }
1116- }
1117-
1118- private Thumbnail? get_thumbnail (File file) {
1119- Thumbnail? thumb = null;
1120- try {
1121- var info = file.query_info ("*", 0, null);
1122- var attr = info.get_attribute_byte_string ("thumbnail::path");
1123- Gdk.Pixbuf pix = null;
1124- if (attr == null) pix = new Gdk.Pixbuf.from_file (file.get_path ());
1125- else pix = new Gdk.Pixbuf.from_file (attr);
1126- pix = pix.scale_simple ((int)thumb_width, (int)thumb_height, 0);
1127- thumb = new Thumbnail (file, pix);
1128- } catch (Error err) {
1129- warning ("Error: get_thumbnail failed: %s", err.message);
1130- }
1131-
1132- if (thumb == null) {
1133- // Try to obtain the thumbnail with ffmpegthumbnailer
1134- try {
1135- string tmp_path = GLib.Environment.get_tmp_dir ();
1136- string out_path = tmp_path + "/temp" + this.temp_thumb.to_string () + ".png";
1137- string[] spawn_args = {"ffmpegthumbnailer",
1138- "-i", file.get_path (), // Input file
1139- "-o", out_path, // Output file
1140- "-c", "png",
1141- "-f", "-t", "10",
1142- "-s", thumb_width.to_string () };
1143- string[] spawn_env = Environ.get ();
1144- Pid child_pid;
1145-
1146- Process.spawn_async ("/",
1147- spawn_args,
1148- spawn_env,
1149- SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
1150- null,
1151- out child_pid);
1152-
1153- ChildWatch.add (child_pid, (pid, status) => {
1154- // Triggered when the child indicated by child_pid exits
1155- Process.close_pid (pid);
1156- });
1157-
1158- Gdk.Pixbuf pix = new Gdk.Pixbuf.from_file (out_path);
1159- pix = pix.scale_simple ((int)thumb_width, (int)thumb_height, 0);
1160- thumb = new Thumbnail (file, pix);
1161- thumb.is_temp = true;
1162- thumb.temp_file = File.new_for_path (out_path);
1163- // Increment temp thumbs counter
1164- this.temp_thumb++;
1165- } catch (SpawnError serr) {
1166- warning ("Error: get_thumbnail failed: %s", serr.message);
1167- } catch (Error err) {
1168- warning ("Error: get_thumbnail failed: %s", err.message);
1169- }
1170- }
1171- return thumb;
1172- }
1173-
1174- /**
1175- * Execute this method on quitting to clean temp cache
1176- */
1177- public void clear_cache () {
1178- Gee.Iterator<Thumbnail> iterator = this.cache.iterator ();
1179- while (iterator.has_next ()) {
1180- iterator.next ();
1181- Thumbnail? thumb = iterator.get ();
1182- if (thumb != null && thumb.is_temp) {
1183- try {
1184- thumb.temp_file.delete (null);
1185- } catch (Error err) {
1186- warning ("Error: clear_cache failed: %s", err.message);
1187- }
1188- }
1189- }
1190- }
1191- }
1192-}
1193
1194=== renamed file 'src/Resources.vala' => 'src/Utils.vala'
1195--- src/Resources.vala 2015-02-26 12:35:06 +0000
1196+++ src/Utils.vala 2016-01-19 15:51:17 +0000
1197@@ -1,156 +1,59 @@
1198-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
1199-/*-
1200- * Copyright (c) 2011-2012 Snap Developers
1201+/*
1202+ * Copyright (c) 2011-2016 Snap Developers (http://launchpad.net/snap-elementary)
1203 *
1204- * This library is free software; you can redistribute it and/or
1205- * modify it under the terms of the GNU Library General Public
1206+ * This program is free software; you can redistribute it and/or
1207+ * modify it under the terms of the GNU General Public
1208 * License as published by the Free Software Foundation; either
1209 * version 2 of the License, or (at your option) any later version.
1210 *
1211- * This library is distributed in the hope that it will be useful,
1212+ * This program is distributed in the hope that it will be useful,
1213 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1214 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1215- * Library General Public License for more details.
1216+ * General Public License for more details.
1217 *
1218- * You should have received a copy of the GNU Library General Public
1219- * License along with this library; if not, write to the
1220+ * You should have received a copy of the GNU General Public
1221+ * License along with this program; if not, write to the
1222 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1223 * Boston, MA 02111-1307, USA.
1224+ *
1225+ * Authored by: Marcus Wichelmann <marcus.wichelmann@hotmail.de>
1226 */
1227
1228-using Snap.Widgets;
1229-using Snap.Services;
1230-
1231-namespace Resources {
1232- public const string TAKE_BUTTON_STYLESHEET = """
1233- .take-button {
1234- border-radius: 400px;
1235- }
1236- """;
1237-
1238- public const string PREVIEW_STYLESHEET = """
1239- .snap-preview-bg {
1240- background-color: #000;
1241- }
1242- """;
1243-
1244- public const string ICON_VIEW_STYLESHEET = """
1245- GtkIconView.view {
1246- background-color: @bg_color;
1247- }
1248-
1249- GtkIconView.view.cell:selected,
1250- GtkIconView.view.cell:selected:focused {
1251- background-color: @selected_bg_color;
1252- border-radius: 4px;
1253- }
1254- """;
1255-
1256- /**
1257- * @return path to save photos or videos
1258- */
1259- public string get_media_dir (Camera.ActionType type) {
1260- UserDirectory user_dir;
1261-
1262- if (type == Camera.ActionType.PHOTO)
1263- user_dir = UserDirectory.PICTURES;
1264- else
1265- user_dir = UserDirectory.VIDEOS;
1266-
1267- string dir = GLib.Environment.get_user_special_dir (user_dir);
1268- return GLib.Path.build_path ("/", dir, "Webcam");
1269+namespace Snap.Utils {
1270+ public enum ActionType {
1271+ PHOTO,
1272+ VIDEO
1273 }
1274
1275- /**
1276- * Creates a file name with format 'YYYY-MM-DD HH:MM:SS.ext'
1277- *
1278- * @param extension file extension [allow-none]
1279- *
1280- * @return new photo/video filename.
1281- */
1282- public string get_new_media_filename (Camera.ActionType type, string? ext = null) {
1283- // Get date and time
1284- var datetime = new GLib.DateTime.now_local ();
1285- string time = datetime.format ("%F%H:%M:%S");
1286-
1287- int n = 0;
1288- string filename = "";
1289+ public string get_new_media_filename (ActionType action_type) {
1290+ string time = new GLib.DateTime.now_local ().format ("%F%H:%M:%S");
1291+
1292+ int file_id = 0;
1293+ string next_filename = "";
1294+
1295 do {
1296- filename = time + (n > 0 ? "-" + n.to_string () : "");
1297- n++;
1298- } while (GLib.FileUtils.test (build_media_filename (filename, type, ext), FileTest.EXISTS));
1299-
1300- return build_media_filename (filename, type, ext);
1301- }
1302-
1303- /**
1304- * @return a valid photo/video filename.
1305- */
1306- public string build_media_filename (string filename, Camera.ActionType type, string? ext = null) {
1307- string new_filename = filename;
1308- if (ext == null) {
1309- if (type == Camera.ActionType.PHOTO)
1310- new_filename += ".jpg";
1311- else if (type == Camera.ActionType.VIDEO)
1312- new_filename += ".mp4";
1313- } else {
1314- new_filename += "." + ext;
1315- }
1316-
1317- string media_dir = get_media_dir (type);
1318- if (!FileUtils.test (media_dir, FileTest.EXISTS))
1319- DirUtils.create (media_dir, 0777);
1320-
1321- return GLib.Path.build_filename (Path.DIR_SEPARATOR_S, media_dir, new_filename);
1322- }
1323-
1324- /**
1325- * @return a valid photo/video uri.
1326- */
1327- public string build_uri_from_filename (string filename) {
1328- var file = File.new_for_path (filename);
1329-
1330- return file.get_uri ();
1331- }
1332-
1333- /** Thumbnail providers **/
1334- public ThumbnailProvider photo_thumb_provider;
1335- public ThumbnailProvider video_thumb_provider;
1336-
1337- /**
1338- * @param surface_size size of the new pixbuf. Set a value of 0 to use the pixbuf's natural size.
1339- **/
1340- public Gdk.Pixbuf get_pixbuf_shadow (Gdk.Pixbuf pixbuf, int surface_size,
1341- int shadow_size = 5, double alpha = 0.8) {
1342- int S_WIDTH = (surface_size > 0)? surface_size : pixbuf.width;
1343- int S_HEIGHT = (surface_size > 0)? surface_size : pixbuf.height;
1344-
1345- var buffer_surface = new Granite.Drawing.BufferSurface(S_WIDTH, S_HEIGHT);
1346-
1347- S_WIDTH -= 2 * shadow_size;
1348- S_HEIGHT -= 2 * shadow_size;
1349-
1350- buffer_surface.context.rectangle (shadow_size, shadow_size, S_WIDTH, S_HEIGHT);
1351- buffer_surface.context.set_source_rgba (0, 0, 0, alpha);
1352- buffer_surface.context.fill();
1353- buffer_surface.fast_blur(2, 3);
1354- Gdk.cairo_set_source_pixbuf(buffer_surface.context, pixbuf.scale_simple (S_WIDTH, S_HEIGHT, Gdk.InterpType.BILINEAR), shadow_size, shadow_size);
1355- buffer_surface.context.paint();
1356-
1357- return buffer_surface.load_to_pixbuf();
1358- }
1359-
1360- /**
1361- * Launch a file with its default handler
1362- */
1363- public void launch_file (File file) {
1364- try {
1365- var handler = file.query_default_handler (null);
1366- var list = new GLib.List<File> ();
1367- list.append (file);
1368- handler.launch (list, null);
1369- } catch (Error err) {
1370- warning (err.message);
1371- }
1372- }
1373-}
1374+ next_filename = time + (file_id > 0 ? "-" + file_id.to_string () : "");
1375+ file_id++;
1376+ } while (GLib.FileUtils.test (build_media_filename (next_filename, action_type), FileTest.EXISTS));
1377+
1378+ return build_media_filename (next_filename, action_type);
1379+ }
1380+
1381+ public string build_media_filename (string filename, ActionType action_type) {
1382+ string full_filename = "%s.%s".printf (filename, action_type == ActionType.PHOTO ? "jpg" : "mp4");
1383+ string media_directory = get_media_directory (action_type);
1384+
1385+ if (!FileUtils.test (media_directory, FileTest.EXISTS)) {
1386+ DirUtils.create (media_directory, 0777);
1387+ }
1388+
1389+ return GLib.Path.build_filename (Path.DIR_SEPARATOR_S, media_directory, full_filename);
1390+ }
1391+
1392+ public string get_media_directory (ActionType action_type) {
1393+ UserDirectory user_dir = (action_type == ActionType.PHOTO ? UserDirectory.PICTURES : UserDirectory.VIDEOS);
1394+ string media_directory = GLib.Environment.get_user_special_dir (user_dir);
1395+
1396+ return GLib.Path.build_path (Path.DIR_SEPARATOR_S, media_directory, "Webcam");
1397+ }
1398+}
1399\ No newline at end of file
1400
1401=== removed file 'src/Widgets/Camera.vala'
1402--- src/Widgets/Camera.vala 2015-03-02 14:02:30 +0000
1403+++ src/Widgets/Camera.vala 1970-01-01 00:00:00 +0000
1404@@ -1,176 +0,0 @@
1405-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
1406-/***
1407- BEGIN LICENSE
1408-
1409- Copyright (C) 2013 Mario Guerriero <mario@elementaryos.org>
1410- This program is free software: you can redistribute it and/or modify it
1411- under the terms of the GNU Lesser General Public License version 3, as
1412- published by the Free Software Foundation.
1413-
1414- This program is distributed in the hope that it will be useful, but
1415- WITHOUT ANY WARRANTY; without even the implied warranties of
1416- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1417- PURPOSE. See the GNU General Public License for more details.
1418-
1419- You should have received a copy of the GNU General Public License along
1420- with this program. If not, see <http://www.gnu.org/licenses>
1421-
1422- END LICENSE
1423-***/
1424-
1425-namespace Snap.Widgets {
1426- public class Camera : Gtk.DrawingArea {
1427- public enum ActionType {
1428- PHOTO = 0,
1429- VIDEO,
1430- CAPTURING;
1431- }
1432-
1433- private const double PERCENTAGE_SCREEN = 0.6;
1434-
1435- public uint video_width = 640;
1436- public uint video_height = 480;
1437-
1438- private ActionType type;
1439-
1440- private bool capturing = false;
1441-
1442- private Gst.Element? camerabin = null;
1443- private Gst.Element? videoflip = null;
1444-
1445- public signal void capture_start ();
1446- public signal void capture_stop ();
1447-
1448- public class Camera (string camera_uri) {
1449- this.videoflip = Gst.ElementFactory.make ("videoflip", "videoflip");
1450- this.videoflip.set_property ("method", 4);
1451-
1452- this.camerabin = Gst.ElementFactory.make ("camerabin","camera");
1453- this.camerabin.set_property ("viewfinder-filter", videoflip);
1454-
1455- this.camerabin.bus.add_watch (0,(bus,message) => {
1456- if (Gst.Video.is_video_overlay_prepare_window_handle_message (message))
1457- (message.src as Gst.Video.Overlay).set_window_handle ((uint*) Gdk.X11Window.get_xid (this.get_window()));
1458- return true;
1459- });
1460-
1461- var preview_caps = Gst.Caps.from_string ("video/x-raw, format=\"rgb\"");
1462- this.camerabin.set_property ("preview-caps", preview_caps);
1463-
1464- // Workaround to fix a CSD releated bug.
1465- // See https://bugzilla.gnome.org/show_bug.cgi?id=721148
1466- // for more information
1467- Gdk.Visual visual = Gdk.Visual.get_system ();
1468- if (visual != null)
1469- this.set_visual (visual);
1470- // workaround END
1471-
1472- try {
1473- var info = new Gst.PbUtils.Discoverer (10 * Gst.SECOND).discover_uri (camera_uri);
1474- var video = info.get_video_streams ();
1475-
1476- if (video != null && video.data != null) {
1477- var video_info = (Gst.PbUtils.DiscovererVideoInfo)video.data;
1478-
1479- video_width = video_info.get_width ();
1480- video_height = video_info.get_height ();
1481- }
1482-
1483- var current_screen = this.get_screen ();
1484- var screen_width = current_screen.get_width ();
1485- var screen_height = current_screen.get_height ();
1486-
1487- if (video_width >= screen_width * PERCENTAGE_SCREEN || video_height >= screen_height * PERCENTAGE_SCREEN) {
1488- if ((float)screen_width / video_width < (float)screen_height / video_height) {
1489- var new_video_width = (int)(screen_width * PERCENTAGE_SCREEN);
1490- video_height = (int)(((float)new_video_width / video_width) * video_height);
1491- video_width = new_video_width;
1492- } else {
1493- var new_video_height = (int)(screen_height * PERCENTAGE_SCREEN);
1494- video_width = (int)(((float)new_video_height / video_height) * video_width);
1495- video_height = new_video_height;
1496- }
1497- }
1498- } catch (Error e) {
1499- debug ("Getting the video-size failed: %s", e.message);
1500- }
1501-
1502- this.set_size_request ((int)video_width, (int)video_height);
1503- this.show_all ();
1504- this.play ();
1505- }
1506-
1507- /**
1508- * Change the camera recording type (switch between Video or Photo mode)
1509- */
1510- public void set_action_type (ActionType type) {
1511- debug ("mode changed");
1512- this.type = type;
1513- }
1514-
1515- /**
1516- * Starts Camera visualization
1517- */
1518- public void play () {
1519- this.camerabin.set_state (Gst.State.PLAYING);
1520- }
1521-
1522- /**
1523- * Stops Camera visualization
1524- */
1525- public void stop () {
1526- this.camerabin.set_state (Gst.State.NULL);
1527- }
1528-
1529- /**
1530- * Send to the Camera an acquire signal depending on its recording mode
1531- */
1532- public void take_start () {
1533- debug ("Recording...");
1534-
1535- this.capture_start ();
1536-
1537- string location = Resources.get_new_media_filename (this.type);
1538- // "(int) this.type + 1" is here because GST developers used mode 1 for photos
1539- // and mode 2 for videos (can't understand why not 0 and 1)
1540- this.camerabin.set_property ("mode", (int) this.type + 1);
1541-
1542- this.capturing = (this.type == ActionType.VIDEO);
1543-
1544- debug ("%s", location);
1545-
1546- camerabin.set_property ("location", location);
1547- GLib.Signal.emit_by_name (camerabin, "start-capture");
1548-
1549- if (this.type == ActionType.PHOTO)
1550- this.capture_stop ();
1551- }
1552-
1553- /**
1554- * Tells the camera to stop recording (to be used only in video mode)
1555- */
1556- public void take_stop () {
1557- debug ("Stopping video record...");
1558-
1559- this.capturing = false;
1560-
1561- GLib.Signal.emit_by_name (camerabin, "stop-capture");
1562-
1563- this.capture_stop ();
1564- }
1565-
1566- /**
1567- * @return the action Camera is supposed to do
1568- */
1569- public ActionType get_action_type () {
1570- return type;
1571- }
1572-
1573- /**
1574- * @return true if camera is recording a video, false otherwise
1575- */
1576- public bool get_capturing () {
1577- return capturing;
1578- }
1579- }
1580-}
1581
1582=== added file 'src/Widgets/CameraView.vala'
1583--- src/Widgets/CameraView.vala 1970-01-01 00:00:00 +0000
1584+++ src/Widgets/CameraView.vala 2016-01-19 15:51:17 +0000
1585@@ -0,0 +1,88 @@
1586+/*
1587+ * Copyright (c) 2011-2016 Snap Developers (http://launchpad.net/snap-elementary)
1588+ *
1589+ * This program is free software; you can redistribute it and/or
1590+ * modify it under the terms of the GNU General Public
1591+ * License as published by the Free Software Foundation; either
1592+ * version 2 of the License, or (at your option) any later version.
1593+ *
1594+ * This program is distributed in the hope that it will be useful,
1595+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1596+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1597+ * General Public License for more details.
1598+ *
1599+ * You should have received a copy of the GNU General Public
1600+ * License along with this program; if not, write to the
1601+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1602+ * Boston, MA 02111-1307, USA.
1603+ *
1604+ * Authored by: Marcus Wichelmann <marcus.wichelmann@hotmail.de>
1605+ */
1606+
1607+public class Snap.Widgets.CameraView : ClutterGst.Camera {
1608+ public signal void initialized ();
1609+
1610+ public CameraView () {
1611+ new Thread<int> (null, () => {
1612+ debug ("Initializing camera view...");
1613+
1614+ initialize_view ();
1615+
1616+ return 0;
1617+ });
1618+ }
1619+
1620+ public new bool take_photo () {
1621+ if (!this.is_ready_for_capture () || this.is_recording_video ()) {
1622+ warning ("Device isn't ready for taking photos.");
1623+
1624+ return false;
1625+ }
1626+
1627+ base.take_photo (Utils.get_new_media_filename (Utils.ActionType.PHOTO));
1628+
1629+ return true;
1630+ }
1631+
1632+ public bool start_recording () {
1633+ if (!this.is_ready_for_capture () || this.is_recording_video ()) {
1634+ warning ("Device isn't ready for recording videos.");
1635+
1636+ return false;
1637+ }
1638+
1639+ this.start_video_recording (Utils.get_new_media_filename (Utils.ActionType.VIDEO));
1640+
1641+ return true;
1642+ }
1643+
1644+ public void stop_recording () {
1645+ if (!this.is_recording_video ()) {
1646+ warning ("Cannot stop recording because no record is running.");
1647+
1648+ return;
1649+ }
1650+
1651+ this.stop_video_recording ();
1652+ }
1653+
1654+ private void initialize_view () {
1655+ Gst.Element flip_filter = Gst.ElementFactory.make ("videoflip", "videoflip");
1656+ flip_filter.set_property ("method", 4);
1657+
1658+ this.set_filter (flip_filter);
1659+ this.set_playing (true);
1660+
1661+ if (this.is_ready_for_capture ()) {
1662+ debug ("Camera view initalized.");
1663+
1664+ Idle.add (() => {
1665+ initialized ();
1666+
1667+ return false;
1668+ });
1669+ } else {
1670+ warning ("Initializing camera view failed.");
1671+ }
1672+ }
1673+}
1674\ No newline at end of file
1675
1676=== removed file 'src/Widgets/Countdown.vala'
1677--- src/Widgets/Countdown.vala 2015-02-26 12:35:06 +0000
1678+++ src/Widgets/Countdown.vala 1970-01-01 00:00:00 +0000
1679@@ -1,117 +0,0 @@
1680-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
1681-/***
1682- BEGIN LICENSE
1683-
1684- Copyright (C) 2011-2012 Mario Guerriero <mefrio.g@gmail.com>
1685- This program is free software: you can redistribute it and/or modify it
1686- under the terms of the GNU Lesser General Public License version 3, as
1687- published by the Free Software Foundation.
1688-
1689- This program is distributed in the hope that it will be useful, but
1690- WITHOUT ANY WARRANTY; without even the implied warranties of
1691- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1692- PURPOSE. See the GNU General Public License for more details.
1693-
1694- You should have received a copy of the GNU General Public License along
1695- with this program. If not, see <http://www.gnu.org/licenses>
1696-
1697- END LICENSE
1698-***/
1699-
1700-namespace Snap.Widgets {
1701-
1702- public class Countdown : Granite.Widgets.CompositedWindow {
1703- public signal void time_elapsed ();
1704-
1705- public Label count_label {get; private set;}
1706- public Label title_label {get; private set;}
1707-
1708- public MediaType media_type {get; private set;}
1709-
1710- private bool window_destroyed = false;
1711-
1712- public Countdown (MediaType media_type) {
1713- this.media_type = media_type;
1714-
1715- this.set_default_size (300, 200);
1716- this.window_position = WindowPosition.CENTER;
1717- this.set_keep_above (true);
1718- this.stick ();
1719- this.type_hint = Gdk.WindowTypeHint.SPLASHSCREEN;
1720- this.skip_pager_hint = true;
1721- this.skip_taskbar_hint = true;
1722-
1723- var box = new Box (Orientation.VERTICAL, 0);
1724- box.margin = 40;
1725- box.margin_left = box.margin_right = 60;
1726-
1727- this.title_label = new Label ("");
1728- this.title_label.use_markup = true;
1729-
1730- this.count_label = new Label ("");
1731- this.count_label.use_markup = true;
1732-
1733- box.pack_start (title_label);
1734- box.pack_start (count_label);
1735-
1736- this.add (box);
1737-
1738- string media_text = "";
1739-
1740- if (media_type == MediaType.PHOTO)
1741- media_text = _("Taking photo in");
1742- else if (media_type == MediaType.VIDEO)
1743- media_text = _("Recording starts in");
1744-
1745- media_text = media_text.replace ("&", "&amp;");
1746-
1747- title_label.label = "<span size='20000' color='#fbfbfb'>" + media_text + "</span>";
1748- }
1749-
1750- public override bool draw (Cairo.Context ctx) {
1751- int w = this.get_allocated_width ();
1752- int h = this.get_allocated_height ();
1753- Granite.Drawing.Utilities.cairo_rounded_rectangle (ctx, 4, 4, w - 8, h - 8, 4);
1754- ctx.set_source_rgba (0.1, 0.1, 0.1, 0.8);
1755- ctx.fill ();
1756- return base.draw (ctx);
1757- }
1758-
1759- public void start (int secs) {
1760- set_count (secs);
1761-
1762- if (secs > 0)
1763- this.show_all ();
1764-
1765- Timeout.add (1000, () => {
1766- secs --;
1767-
1768- if (window_destroyed)
1769- return false;
1770-
1771- if (secs == 0) {
1772- this.hide ();
1773- }
1774- else if (secs == -1) {
1775- if (!window_destroyed)
1776- this.time_elapsed (); // notify that we're finished here
1777- this.destroy ();
1778- return false; // stop
1779- }
1780-
1781- set_count (secs);
1782- return true; // keep going
1783- });
1784- }
1785-
1786- public override void destroy () {
1787- window_destroyed = true;
1788- base.destroy ();
1789- }
1790-
1791- private void set_count (int secs) {
1792- count_label.label = "<span size='40000' color='#fbfbfb'>" + secs.to_string () + "</span>";
1793- }
1794- }
1795-}
1796-
1797
1798=== removed file 'src/Widgets/Gallery.vala'
1799--- src/Widgets/Gallery.vala 2015-02-26 12:35:06 +0000
1800+++ src/Widgets/Gallery.vala 1970-01-01 00:00:00 +0000
1801@@ -1,69 +0,0 @@
1802-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
1803-/***
1804- BEGIN LICENSE
1805-
1806- Copyright (C) 2013 Mario Guerriero <mario@elementaryos.org>
1807- This program is free software: you can redistribute it and/or modify it
1808- under the terms of the GNU Lesser General Public License version 3, as
1809- published by the Free Software Foundation.
1810-
1811- This program is distributed in the hope that it will be useful, but
1812- WITHOUT ANY WARRANTY; without even the implied warranties of
1813- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1814- PURPOSE. See the GNU General Public License for more details.
1815-
1816- You should have received a copy of the GNU General Public License along
1817- with this program. If not, see <http://www.gnu.org/licenses>
1818-
1819- END LICENSE
1820-***/
1821-
1822-namespace Snap.Widgets {
1823-
1824- public class Gallery : Gtk.ScrolledWindow {
1825- private Gtk.ListStore model;
1826- private Gtk.IconView view;
1827-
1828- public Gallery () {
1829- this.model = new Gtk.ListStore (2, typeof (Gdk.Pixbuf), typeof (Services.Thumbnail));
1830-
1831- this.view = new Gtk.IconView.with_model (model);
1832- this.view.set_pixbuf_column (0);
1833- this.view.set_selection_mode (Gtk.SelectionMode.SINGLE);
1834- this.view.selection_changed.connect (() => {
1835- GLib.List<Gtk.TreePath> paths = this.view.get_selected_items ();
1836- Gtk.TreeIter iter;
1837- Services.Thumbnail thumb = null;
1838-
1839- foreach (Gtk.TreePath path in paths) {
1840- this.model.get_iter (out iter, path);
1841-
1842- GLib.Value val;
1843- this.model.get_value (iter, 1, out val);
1844-
1845- thumb = (Services.Thumbnail) val;
1846-
1847- Resources.launch_file (thumb.file);
1848- }
1849- });
1850-
1851- Resources.photo_thumb_provider.thumbnail_loaded.connect (add_thumbnail);
1852- Resources.video_thumb_provider.thumbnail_loaded.connect (add_thumbnail);
1853-
1854- this.add (view);
1855- }
1856-
1857- private void add_thumbnail (Services.Thumbnail thumb) {
1858- Gtk.TreeIter iter;
1859- this.model.append (out iter);
1860- this.model.set (iter, 0, thumb.pixbuf, 1, thumb);
1861- }
1862-
1863- /**
1864- + Simply clear the IconView as the name suggests
1865- */
1866- public void clear_view () {
1867- this.model.clear ();
1868- }
1869- }
1870-}
1871
1872=== added file 'src/Widgets/HeaderBar.vala'
1873--- src/Widgets/HeaderBar.vala 1970-01-01 00:00:00 +0000
1874+++ src/Widgets/HeaderBar.vala 2016-01-19 15:51:17 +0000
1875@@ -0,0 +1,126 @@
1876+/*
1877+ * Copyright (c) 2011-2016 Snap Developers (http://launchpad.net/snap-elementary)
1878+ *
1879+ * This program is free software; you can redistribute it and/or
1880+ * modify it under the terms of the GNU General Public
1881+ * License as published by the Free Software Foundation; either
1882+ * version 2 of the License, or (at your option) any later version.
1883+ *
1884+ * This program is distributed in the hope that it will be useful,
1885+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1886+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1887+ * General Public License for more details.
1888+ *
1889+ * You should have received a copy of the GNU General Public
1890+ * License along with this program; if not, write to the
1891+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1892+ * Boston, MA 02111-1307, USA.
1893+ *
1894+ * Authored by: Marcus Wichelmann <marcus.wichelmann@hotmail.de>
1895+ */
1896+
1897+public class Snap.Widgets.HeaderBar : Gtk.HeaderBar {
1898+ private static const string PHOTO_ICON_SYMBOLIC = "view-list-images-symbolic";
1899+ private static const string VIDEO_ICON_SYMBOLIC = "view-list-video-symbolic";
1900+ private static const string STOP_ICON_SYMBOLIC = "media-playback-stop-symbolic";
1901+
1902+ public const string TAKE_BUTTON_STYLESHEET = """
1903+ .take-button {
1904+ border-radius: 400px;
1905+ }
1906+ """;
1907+
1908+ public Backend.Settings settings { private get; construct; }
1909+
1910+ private Gtk.Button take_button;
1911+ private Granite.Widgets.ModeButton mode_button;
1912+
1913+ private bool is_recording = false;
1914+
1915+ public signal void take_photo_clicked ();
1916+ public signal void start_recording_clicked ();
1917+ public signal void stop_recording_clicked ();
1918+
1919+ public HeaderBar (Backend.Settings settings) {
1920+ Object (settings: settings);
1921+
1922+ build_ui ();
1923+ update_take_button_icon ();
1924+ connect_signals ();
1925+ }
1926+
1927+ public void set_is_recording (bool is_recording) {
1928+ this.is_recording = is_recording;
1929+
1930+ update_take_button_icon ();
1931+ }
1932+
1933+ public void set_camera_controls_sensitive (bool sensitive) {
1934+ take_button.set_sensitive (sensitive);
1935+ mode_button.set_sensitive (sensitive);
1936+ }
1937+
1938+ private void build_ui () {
1939+ this.show_close_button = true;
1940+
1941+ take_button = new Gtk.Button.from_icon_name (PHOTO_ICON_SYMBOLIC, Gtk.IconSize.BUTTON);
1942+ take_button.set_size_request (54, -1);
1943+ take_button.sensitive = false;
1944+
1945+ Gtk.CssProvider take_button_style_provider = new Gtk.CssProvider ();
1946+
1947+ try {
1948+ take_button_style_provider.load_from_data (TAKE_BUTTON_STYLESHEET, -1);
1949+ } catch (Error e) {
1950+ warning ("Styling take button failed: %s", e.message);
1951+ }
1952+
1953+ Gtk.StyleContext take_button_style_context = take_button.get_style_context ();
1954+ take_button_style_context.add_provider (take_button_style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
1955+ take_button_style_context.add_class ("take-button");
1956+ take_button_style_context.add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION);
1957+ take_button_style_context.add_class (Gtk.STYLE_CLASS_RAISED);
1958+
1959+ mode_button = new Granite.Widgets.ModeButton ();
1960+ mode_button.append_icon (PHOTO_ICON_SYMBOLIC, Gtk.IconSize.BUTTON);
1961+ mode_button.append_icon (VIDEO_ICON_SYMBOLIC, Gtk.IconSize.BUTTON);
1962+ mode_button.sensitive = false;
1963+
1964+ this.set_custom_title (take_button);
1965+ this.pack_end (mode_button);
1966+ }
1967+
1968+ private void connect_signals () {
1969+ settings.action_type_changed.connect (update_take_button_icon);
1970+
1971+ take_button.clicked.connect (() => {
1972+ if (settings.get_action_type () == Utils.ActionType.PHOTO) {
1973+ take_photo_clicked ();
1974+ } else {
1975+ if (is_recording) {
1976+ stop_recording_clicked ();
1977+ } else {
1978+ start_recording_clicked ();
1979+ }
1980+ }
1981+ });
1982+
1983+ mode_button.mode_changed.connect (() => {
1984+ settings.set_action_type (mode_button.selected == 0 ? Utils.ActionType.PHOTO : Utils.ActionType.VIDEO);
1985+ });
1986+ }
1987+
1988+ private void update_take_button_icon () {
1989+ string icon_name;
1990+ Utils.ActionType action_type = settings.get_action_type ();
1991+
1992+ if (action_type == Utils.ActionType.PHOTO) {
1993+ icon_name = PHOTO_ICON_SYMBOLIC;
1994+ } else {
1995+ icon_name = (is_recording ? STOP_ICON_SYMBOLIC : VIDEO_ICON_SYMBOLIC);
1996+ }
1997+
1998+ ((Gtk.Image)take_button.image).set_from_icon_name (icon_name, Gtk.IconSize.BUTTON);
1999+ mode_button.set_active ((int)(action_type == Utils.ActionType.VIDEO));
2000+ }
2001+}
2002\ No newline at end of file
2003
2004=== added file 'src/Widgets/LoadingView.vala'
2005--- src/Widgets/LoadingView.vala 1970-01-01 00:00:00 +0000
2006+++ src/Widgets/LoadingView.vala 2016-01-19 15:51:17 +0000
2007@@ -0,0 +1,57 @@
2008+/*
2009+ * Copyright (c) 2011-2016 Snap Developers (http://launchpad.net/snap-elementary)
2010+ *
2011+ * This program is free software; you can redistribute it and/or
2012+ * modify it under the terms of the GNU General Public
2013+ * License as published by the Free Software Foundation; either
2014+ * version 2 of the License, or (at your option) any later version.
2015+ *
2016+ * This program is distributed in the hope that it will be useful,
2017+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2018+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2019+ * General Public License for more details.
2020+ *
2021+ * You should have received a copy of the GNU General Public
2022+ * License along with this program; if not, write to the
2023+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2024+ * Boston, MA 02111-1307, USA.
2025+ *
2026+ * Authored by: Marcus Wichelmann <marcus.wichelmann@hotmail.de>
2027+ */
2028+
2029+public class Snap.Widgets.LoadingView : Gtk.Box {
2030+ private Gtk.Grid inner_grid;
2031+
2032+ private Gtk.Spinner spinner;
2033+ private Gtk.Label status_label;
2034+
2035+ public LoadingView () {
2036+ Object (orientation: Gtk.Orientation.HORIZONTAL);
2037+
2038+ build_ui ();
2039+ }
2040+
2041+ public void set_status (string status) {
2042+ status_label.set_label (status);
2043+ }
2044+
2045+ private void build_ui () {
2046+ this.override_background_color (Gtk.StateFlags.NORMAL, { 0, 0, 0, 1 });
2047+ this.override_color (Gtk.StateFlags.NORMAL, { 1, 1, 1, 1 });
2048+
2049+ inner_grid = new Gtk.Grid ();
2050+ inner_grid.halign = Gtk.Align.CENTER;
2051+ inner_grid.valign = Gtk.Align.CENTER;
2052+
2053+ spinner = new Gtk.Spinner ();
2054+ spinner.active = true;
2055+
2056+ status_label = new Gtk.Label (_("Searching for video devices…"));
2057+ status_label.margin_top = 12;
2058+
2059+ inner_grid.attach (spinner, 0, 0, 1, 1);
2060+ inner_grid.attach (status_label, 0, 1, 1, 1);
2061+
2062+ this.pack_start (inner_grid);
2063+ }
2064+}
2065\ No newline at end of file
2066
2067=== removed file 'src/Widgets/NoCamera.vala'
2068--- src/Widgets/NoCamera.vala 2015-02-26 12:35:06 +0000
2069+++ src/Widgets/NoCamera.vala 1970-01-01 00:00:00 +0000
2070@@ -1,32 +0,0 @@
2071-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2072-/***
2073-Copyright (C) 2014 elementary Developers and Artem Anufrij
2074-
2075-This program is free software: you can redistribute it and/or modify it
2076-under the terms of the GNU Lesser General Public License version 3, as published
2077-by the Free Software Foundation.
2078-
2079-This program is distributed in the hope that it will be useful, but
2080-WITHOUT ANY WARRANTY; without even the implied warranties of
2081-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2082-PURPOSE. See the GNU General Public License for more details.
2083-
2084-You should have received a copy of the GNU General Public License along
2085-with this program. If not, see <http://www.gnu.org/licenses/>.
2086-
2087-Authors : Artem Anufrij <artem.anufrij@live.de>
2088-***/
2089-
2090-namespace Snap.Widgets {
2091-
2092- public class NoCamera : Gtk.ScrolledWindow {
2093- Gtk.Label no_camera_label;
2094-
2095- public class NoCamera () {
2096- no_camera_label = new Gtk.Label ("");
2097- no_camera_label.set_markup ("<span color='gray'>%s</span>".printf(_("Your webcam has not been detected. Please be sure you plugged it in.")));
2098- this.add (no_camera_label);
2099- this.show_all ();
2100- }
2101- }
2102-}
2103
2104=== modified file 'src/config.vala.cmake'
2105--- src/config.vala.cmake 2012-05-25 15:00:03 +0000
2106+++ src/config.vala.cmake 2016-01-19 15:51:17 +0000
2107@@ -1,12 +1,12 @@
2108-namespace Constants {
2109-public const string DATADIR = "@DATADIR@";
2110-public const string PKGDATADIR = "@PKGDATADIR@";
2111-public const string GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@";
2112-public const string RELEASE_NAME = "@RELEASE_NAME@";
2113-public const string VERSION = "@VERSION@";
2114-public const string VERSION_INFO = "@VERSION_INFO@";
2115-public const string PLUGINDIR = "@PLUGINDIR@";
2116-/* Translation template for .desktop file */
2117-public const string COMMENT = N_("Take photos with your web cam");
2118-public const string GENERIC = N_("Photo Booth");
2119+namespace Snap.Config {
2120+ public const string DATADIR = "@DATADIR@";
2121+ public const string PKGDATADIR = "@PKGDATADIR@";
2122+ public const string GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@";
2123+ public const string RELEASE_NAME = "@RELEASE_NAME@";
2124+ public const string VERSION = "@VERSION@";
2125+ public const string VERSION_INFO = "@VERSION_INFO@";
2126+ public const string PLUGINDIR = "@PLUGINDIR@";
2127+ /* Translation template for .desktop file */
2128+ public const string COMMENT = N_("Take photos with your web cam");
2129+ public const string GENERIC = N_("Photo Booth");
2130 }

Subscribers

People subscribed via source and target branches