Allow camera to be NULL
[entangle:entangle.git] / src / frontend / entangle-control-panel.c
1 /*
2  *  Entangle: Tethered Camera Control & Capture
3  *
4  *  Copyright (C) 2009-2012 Daniel P. Berrange
5  *
6  *  This program is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include <config.h>
22
23 #include <string.h>
24 #include <glib/gi18n.h>
25 #include <math.h>
26
27 #include "entangle-debug.h"
28 #include "entangle-control-panel.h"
29 #include "entangle-control-button.h"
30 #include "entangle-control-choice.h"
31 #include "entangle-control-date.h"
32 #include "entangle-control-group.h"
33 #include "entangle-control-range.h"
34 #include "entangle-control-text.h"
35 #include "entangle-control-toggle.h"
36
37 #define ENTANGLE_CONTROL_PANEL_GET_PRIVATE(obj)                             \
38     (G_TYPE_INSTANCE_GET_PRIVATE((obj), ENTANGLE_TYPE_CONTROL_PANEL, EntangleControlPanelPrivate))
39
40 struct _EntangleControlPanelPrivate {
41     EntangleCamera *camera;
42
43     gboolean hasControls;
44 };
45
46 G_DEFINE_TYPE(EntangleControlPanel, entangle_control_panel, GTK_TYPE_VBOX);
47
48 enum {
49     PROP_O,
50     PROP_CAMERA,
51     PROP_HAS_CONTROLS,
52 };
53
54
55 static void do_control_remove(GtkWidget *widget,
56                               gpointer data)
57 {
58     g_return_if_fail(ENTANGLE_IS_CONTROL_PANEL(data));
59
60     EntangleControlPanel *panel = data;
61
62     gtk_container_remove(GTK_CONTAINER(panel), widget);
63 }
64
65
66 static void do_update_control_finish(GObject *src,
67                                      GAsyncResult *res,
68                                      gpointer data)
69 {
70     g_return_if_fail(ENTANGLE_IS_CONTROL_PANEL(data));
71
72     GError *error = NULL;
73
74     if (!entangle_camera_save_controls_finish(ENTANGLE_CAMERA(src), res, &error)) {
75         GtkWidget *msg = gtk_message_dialog_new(NULL,
76                                                 0,
77                                                 GTK_MESSAGE_ERROR,
78                                                 GTK_BUTTONS_OK,
79                                                 _("Camera control update failed"));
80         gtk_window_set_title(GTK_WINDOW(msg),
81                              _("Entangle: Camera control update failed"));
82         gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg),
83                                                  "%s",
84                                                  error->message);
85         g_signal_connect_swapped(msg,
86                                  "response",
87                                  G_CALLBACK (gtk_widget_destroy),
88                                  msg);
89         gtk_widget_show_all(msg);
90         g_error_free(error);
91     }
92 }
93
94
95 static void do_refresh_control_entry(GObject *object,
96                                      GParamSpec *pspec G_GNUC_UNUSED,
97                                      gpointer data)
98 {
99     GtkWidget *widget = GTK_WIDGET(data);
100     gchar *text;
101     gdk_threads_enter();
102     g_object_get(object, "value", &text, NULL);
103     if (GTK_IS_LABEL(widget))
104         gtk_label_set_text(GTK_LABEL(widget), text);
105     else
106         gtk_entry_set_text(GTK_ENTRY(widget), text);
107     g_free(text);
108     gdk_threads_leave();
109 }
110
111
112 static void do_update_control_entry(GtkWidget *widget,
113                                     GdkEventFocus *ev G_GNUC_UNUSED,
114                                     gpointer data)
115 {
116     g_return_if_fail(ENTANGLE_IS_CONTROL_PANEL(data));
117
118     EntangleControlText *control = g_object_get_data(G_OBJECT(widget), "control");
119     EntangleControlPanel *panel = ENTANGLE_CONTROL_PANEL(data);
120     EntangleControlPanelPrivate *priv = panel->priv;
121     const char *text;
122
123     text = gtk_entry_get_text(GTK_ENTRY(widget));
124
125     ENTANGLE_DEBUG("entry [%s]", text);
126     gdk_threads_leave();
127     g_object_set(control, "value", text, NULL);
128     gdk_threads_enter();
129
130     entangle_camera_save_controls_async(priv->camera,
131                                         NULL,
132                                         do_update_control_finish,
133                                         panel);
134 }
135
136
137 static void do_refresh_control_range(GObject *object,
138                                      GParamSpec *pspec G_GNUC_UNUSED,
139                                      gpointer data)
140 {
141     GtkWidget *widget = GTK_WIDGET(data);
142     gfloat val;
143
144     gdk_threads_enter();
145     g_object_get(object, "value", &val, NULL);
146     if (GTK_IS_LABEL(widget)) {
147         gchar *text = g_strdup_printf("%0.02f", val);
148         gtk_label_set_text(GTK_LABEL(widget), text);
149         g_free(text);
150     } else {
151         gtk_range_set_value(GTK_RANGE(widget), val);
152     }
153     gdk_threads_leave();
154 }
155
156
157 static void do_update_control_range(GtkRange *widget G_GNUC_UNUSED,
158                                     GtkScrollType scroll G_GNUC_UNUSED,
159                                     gdouble value,
160                                     gpointer data)
161 {
162     g_return_if_fail(ENTANGLE_IS_CONTROL_PANEL(data));
163
164     EntangleControlText *control = g_object_get_data(G_OBJECT(widget), "control");
165     EntangleControlPanel *panel = ENTANGLE_CONTROL_PANEL(data);
166     EntangleControlPanelPrivate *priv = panel->priv;
167
168     ENTANGLE_DEBUG("range [%lf]", value);
169     gdk_threads_leave();
170     g_object_set(control, "value", (float)value, NULL);
171     gdk_threads_enter();
172
173     entangle_camera_save_controls_async(priv->camera,
174                                         NULL,
175                                         do_update_control_finish,
176                                         panel);
177 }
178
179
180 static void do_refresh_control_combo(GObject *object,
181                                      GParamSpec *pspec G_GNUC_UNUSED,
182                                      gpointer data)
183 {
184     GtkWidget *widget = GTK_WIDGET(data);
185     gchar *text;
186
187     gdk_threads_enter();
188     g_object_get(object, "value", &text, NULL);
189
190     if (GTK_IS_LABEL(widget)) {
191         gtk_label_set_text(GTK_LABEL(widget), text);
192     } else {
193         int active = 0;
194         for (int n = 0 ; n < entangle_control_choice_entry_count(ENTANGLE_CONTROL_CHOICE(object)) ; n++) {
195             if (g_strcmp0(text, entangle_control_choice_entry_get(ENTANGLE_CONTROL_CHOICE(object), n)) == 0)
196                 active = n;
197         }
198         gtk_combo_box_set_active(GTK_COMBO_BOX(widget), active);
199     }
200     g_free(text);
201     gdk_threads_leave();
202 }
203
204
205 static void do_update_control_combo(GtkComboBox *widget,
206                                     gpointer data)
207 {
208     g_return_if_fail(ENTANGLE_IS_CONTROL_PANEL(data));
209
210     EntangleControlChoice *control = g_object_get_data(G_OBJECT(widget), "control");
211     EntangleControlPanel *panel = ENTANGLE_CONTROL_PANEL(data);
212     EntangleControlPanelPrivate *priv = panel->priv;
213     GtkTreeIter iter;
214     char *text = NULL;
215     GtkTreeModel *model = gtk_combo_box_get_model(widget);
216
217     if (gtk_combo_box_get_active_iter(widget, &iter))
218         gtk_tree_model_get(model, &iter, 0, &text, -1);
219
220     ENTANGLE_DEBUG("combo [%s]", text);
221     gdk_threads_leave();
222     g_object_set(control, "value", text, NULL);
223     gdk_threads_enter();
224
225     g_free(text);
226
227     entangle_camera_save_controls_async(priv->camera,
228                                         NULL,
229                                         do_update_control_finish,
230                                         panel);
231 }
232
233
234 static void do_refresh_control_toggle(GObject *object,
235                                       GParamSpec *pspec G_GNUC_UNUSED,
236                                       gpointer data)
237 {
238     GtkWidget *widget = GTK_WIDGET(data);
239     gboolean state;
240
241     gdk_threads_enter();
242     g_object_get(object, "value", &state, NULL);
243     if (GTK_IS_LABEL(widget))
244         gtk_label_set_text(GTK_LABEL(widget), state ? _("On") : _("Off"));
245     else
246         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
247                                      state);
248     gdk_threads_leave();
249 }
250
251
252 static void do_update_control_toggle(GtkToggleButton *widget,
253                                      gpointer data)
254 {
255     g_return_if_fail(ENTANGLE_IS_CONTROL_PANEL(data));
256
257     EntangleControlChoice *control = g_object_get_data(G_OBJECT(widget), "control");
258     EntangleControlPanel *panel = ENTANGLE_CONTROL_PANEL(data);
259     EntangleControlPanelPrivate *priv = panel->priv;
260     gboolean active;
261
262     active = gtk_toggle_button_get_active(widget);
263     ENTANGLE_DEBUG("toggle [%d]", active);
264     gdk_threads_leave();
265     g_object_set(control, "value", active, NULL);
266     gdk_threads_enter();
267
268     entangle_camera_save_controls_async(priv->camera,
269                                         NULL,
270                                         do_update_control_finish,
271                                         panel);
272 }
273
274 static void do_setup_control_group(EntangleControlPanel *panel,
275                                    GtkVBox *box,
276                                    EntangleControlGroup *grp)
277 {
278     g_return_if_fail(ENTANGLE_IS_CONTROL_PANEL(panel));
279     g_return_if_fail(ENTANGLE_IS_CONTROL_GROUP(grp));
280
281     EntangleControlPanelPrivate *priv = panel->priv;
282     int i;
283
284     GtkWidget *frame = gtk_expander_new(entangle_control_get_label(ENTANGLE_CONTROL(grp)));
285     GtkWidget *subbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
286
287     gtk_container_add(GTK_CONTAINER(frame), subbox);
288     gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0);
289
290     gtk_expander_set_expanded(GTK_EXPANDER(frame), TRUE);
291     gtk_container_set_border_width(GTK_CONTAINER(subbox), 6);
292
293     for (i = 0 ; i < entangle_control_group_count(grp) ; i++) {
294         EntangleControl *control = entangle_control_group_get(grp, i);
295
296         priv->hasControls = TRUE;
297
298         ENTANGLE_DEBUG("Build control %d %s",
299                        entangle_control_get_id(control),
300                        entangle_control_get_label(control));
301
302         if (ENTANGLE_IS_CONTROL_BUTTON(control)) {
303             GtkWidget *value;
304
305             value = gtk_button_new_with_label(entangle_control_get_label(control));
306             if (entangle_control_get_readonly(control))
307                 gtk_widget_set_sensitive(value, FALSE);
308             gtk_container_add(GTK_CONTAINER(subbox), value);
309         } else if (ENTANGLE_IS_CONTROL_CHOICE(control)) {
310             GtkCellRenderer *cell;
311             GtkListStore *store;
312             GtkWidget *label;
313             GtkWidget *value;
314             char *text;
315             int active = -1;
316
317             /*
318              * Need todo better here
319              *
320              *  If there's only two entries 0/1, turn into toggle
321              *  If there's a continuous sequence of numbers turn
322              *      into a spinbutton
323              *
324              *  Some sequences of numbers are nonsene, and need to
325              *  be turned in to real labels.
326              *
327              *   eg Shutter speed 0.00025 should be presented 1/4000
328              */
329
330             label = gtk_label_new(entangle_control_get_label(control));
331             gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
332             gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
333             gtk_widget_set_tooltip_text(label, entangle_control_get_info(control));
334             gtk_container_add(GTK_CONTAINER(subbox), label);
335
336             store = gtk_list_store_new(1, G_TYPE_STRING);
337             value = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
338             g_object_unref (store);
339
340             cell = gtk_cell_renderer_text_new();
341             gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(value), cell, TRUE);
342             gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(value), cell,
343                                            "text", 0,
344                                            NULL);
345
346             g_object_get(control, "value", &text, NULL);
347             for (int n = 0 ; n < entangle_control_choice_entry_count(ENTANGLE_CONTROL_CHOICE(control)) ; n++) {
348                 GtkTreeIter iter;
349                 if (g_strcmp0(text, entangle_control_choice_entry_get(ENTANGLE_CONTROL_CHOICE(control), n)) == 0)
350                     active = n;
351                 gtk_list_store_append(store, &iter);
352                 gtk_list_store_set(store, &iter, 0,
353                                    entangle_control_choice_entry_get(ENTANGLE_CONTROL_CHOICE(control), n),
354                                    -1);
355             }
356
357             if (entangle_control_get_readonly(control))
358                 gtk_widget_set_sensitive(value, FALSE);
359             gtk_combo_box_set_active(GTK_COMBO_BOX(value), active);
360
361             g_object_set_data(G_OBJECT(value), "control", control);
362             g_signal_connect(value, "changed",
363                              G_CALLBACK(do_update_control_combo), panel);
364             g_signal_connect(control, "notify::value",
365                              G_CALLBACK(do_refresh_control_combo), value);
366             gtk_container_add(GTK_CONTAINER(subbox), value);
367         } else if (ENTANGLE_IS_CONTROL_DATE(control)) {
368             GtkWidget *label;
369             GtkWidget *value;
370             int date;
371
372             label = gtk_label_new(entangle_control_get_label(control));
373             gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
374             gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
375             gtk_widget_set_tooltip_text(label, entangle_control_get_info(control));
376             gtk_container_add(GTK_CONTAINER(subbox), label);
377
378             value = gtk_entry_new();
379             g_object_get(control, "value", &date, NULL);
380             if (entangle_control_get_readonly(control))
381                 gtk_widget_set_sensitive(value, FALSE);
382             //gtk_entry_set_text(GTK_ENTRY(value), text);
383             gtk_container_add(GTK_CONTAINER(subbox), value);
384         } else if (ENTANGLE_IS_CONTROL_RANGE(control)) {
385             GtkWidget *label;
386             GtkWidget *value;
387             gfloat offset;
388             gdouble min = entangle_control_range_get_min(ENTANGLE_CONTROL_RANGE(control));
389             gdouble max = entangle_control_range_get_max(ENTANGLE_CONTROL_RANGE(control));
390             gboolean forceReadonly = FALSE;
391
392             if (fabs(min-max) < 0.005) {
393                 forceReadonly = TRUE;
394                 max += 1;
395             }
396
397             label = gtk_label_new(entangle_control_get_label(control));
398             gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
399             gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
400             gtk_widget_set_tooltip_text(label, entangle_control_get_info(control));
401             gtk_container_add(GTK_CONTAINER(subbox), label);
402
403             value = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,
404                                              min, max,
405                                              entangle_control_range_get_step(ENTANGLE_CONTROL_RANGE(control)));
406             g_object_get(control, "value", &offset, NULL);
407             gtk_range_set_value(GTK_RANGE(value), offset);
408             if (entangle_control_get_readonly(control) || forceReadonly)
409                 gtk_widget_set_sensitive(value, FALSE);
410             g_object_set_data(G_OBJECT(value), "control", control);
411             g_signal_connect(value, "change-value",
412                              G_CALLBACK(do_update_control_range), panel);
413             g_signal_connect(control, "notify::value",
414                              G_CALLBACK(do_refresh_control_range), value);
415             gtk_container_add(GTK_CONTAINER(subbox), value);
416         } else if (ENTANGLE_IS_CONTROL_TEXT(control)) {
417             GtkWidget *label;
418             GtkWidget *value;
419             const char *text;
420
421             label = gtk_label_new(entangle_control_get_label(control));
422             gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
423             gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
424             gtk_widget_set_tooltip_text(label, entangle_control_get_info(control));
425             gtk_container_add(GTK_CONTAINER(subbox), label);
426
427             value = gtk_entry_new();
428             g_object_get(control, "value", &text, NULL);
429             gtk_entry_set_text(GTK_ENTRY(value), text);
430             if (entangle_control_get_readonly(control))
431                 gtk_widget_set_sensitive(value, FALSE);
432             g_object_set_data(G_OBJECT(value), "control", control);
433             g_signal_connect(value, "focus-out-event",
434                              G_CALLBACK(do_update_control_entry), panel);
435             g_signal_connect(control, "notify::value",
436                              G_CALLBACK(do_refresh_control_entry), value);
437             gtk_container_add(GTK_CONTAINER(subbox), value);
438         } else if (ENTANGLE_IS_CONTROL_TOGGLE(control)) {
439             GtkWidget *value;
440             gboolean active;
441
442             value = gtk_check_button_new_with_label(entangle_control_get_label(control));
443             g_object_get(control, "value", &active, NULL);
444             gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(value), active);
445             if (entangle_control_get_readonly(control))
446                 gtk_widget_set_sensitive(value, FALSE);
447             g_object_set_data(G_OBJECT(value), "control", control);
448             g_signal_connect(value, "toggled",
449                              G_CALLBACK(do_update_control_toggle), panel);
450             g_signal_connect(control, "notify::value",
451                              G_CALLBACK(do_refresh_control_toggle), value);
452             gtk_container_add(GTK_CONTAINER(subbox), value);
453         }
454     }
455 }
456
457 static void do_setup_control_group_ro(EntangleControlPanel *panel,
458                                       GtkVBox *box,
459                                       EntangleControlGroup *grp)
460 {
461     g_return_if_fail(ENTANGLE_IS_CONTROL_PANEL(panel));
462     g_return_if_fail(ENTANGLE_IS_CONTROL_GROUP(grp));
463
464     EntangleControlPanelPrivate *priv = panel->priv;
465     int i;
466
467     GtkWidget *frame = gtk_expander_new(entangle_control_get_label(ENTANGLE_CONTROL(grp)));
468     GtkWidget *subbox = gtk_table_new(entangle_control_group_count(grp), 2, FALSE);
469
470     gtk_container_add(GTK_CONTAINER(frame), subbox);
471     gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0);
472
473     gtk_expander_set_expanded(GTK_EXPANDER(frame), TRUE);
474     gtk_container_set_border_width(GTK_CONTAINER(subbox), 6);
475
476     for (i = 0 ; i < entangle_control_group_count(grp) ; i++) {
477         EntangleControl *control = entangle_control_group_get(grp, i);
478         GtkWidget *label;
479         GtkWidget *value = NULL;
480
481         priv->hasControls = TRUE;
482
483         ENTANGLE_DEBUG("Build control %d %s",
484                        entangle_control_get_id(control),
485                        entangle_control_get_label(control));
486
487         if (ENTANGLE_IS_CONTROL_CHOICE(control)) {
488             char *text;
489
490             g_object_get(control, "value", &text, NULL);
491             value = gtk_label_new(text);
492             g_object_set_data(G_OBJECT(value), "control", control);
493             g_signal_connect(control, "notify::value",
494                              G_CALLBACK(do_refresh_control_combo), value);
495         } else if (ENTANGLE_IS_CONTROL_DATE(control)) {
496             int date;
497             gchar *text;
498
499             value = gtk_entry_new();
500             g_object_get(control, "value", &date, NULL);
501             text = g_strdup_printf("%d", date);
502             value = gtk_label_new(text);
503             g_free(text);
504             g_object_set_data(G_OBJECT(value), "control", control);
505         } else if (ENTANGLE_IS_CONTROL_RANGE(control)) {
506             float offset;
507             gchar *text;
508
509             g_object_get(control, "value", &offset, NULL);
510             text = g_strdup_printf("%0.02f", offset);
511             value = gtk_label_new(text);
512             g_free(text);
513             g_object_set_data(G_OBJECT(value), "control", control);
514             g_signal_connect(control, "notify::value",
515                              G_CALLBACK(do_refresh_control_range), value);
516         } else if (ENTANGLE_IS_CONTROL_TEXT(control)) {
517             const gchar *text;
518
519             g_object_get(control, "value", &text, NULL);
520             value = gtk_label_new(text);
521             g_object_set_data(G_OBJECT(value), "control", control);
522             g_signal_connect(control, "notify::value",
523                              G_CALLBACK(do_refresh_control_entry), value);
524         } else if (ENTANGLE_IS_CONTROL_TOGGLE(control)) {
525             gboolean active;
526             gchar *text;
527
528             g_object_get(control, "value", &active, NULL);
529             text = g_strdup_printf("%s", active ? "Yes" : "No");
530             value = gtk_label_new(text);
531             g_free(text);
532             g_object_set_data(G_OBJECT(value), "control", control);
533             g_signal_connect(control, "notify::value",
534                              G_CALLBACK(do_refresh_control_toggle), value);
535         }
536
537         if (value) {
538             gchar *text = g_strdup_printf("<b>%s</b>",
539                                           entangle_control_get_label(control));
540             label = gtk_label_new("");
541             gtk_label_set_markup(GTK_LABEL(label), text);
542             g_free(text);
543             gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
544             gtk_misc_set_alignment(GTK_MISC(value), 0, 0);
545             gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
546             gtk_widget_set_tooltip_text(label, entangle_control_get_info(control));
547             gtk_table_attach(GTK_TABLE(subbox), label, 0, 1, i, i+1, GTK_EXPAND|GTK_FILL, GTK_EXPAND, 3, 3);
548             gtk_table_attach(GTK_TABLE(subbox), value, 1, 2, i, i+1, GTK_FILL, GTK_EXPAND, 3, 3);
549         }
550
551     }
552 }
553
554 static void do_setup_camera(EntangleControlPanel *panel)
555 {
556     g_return_if_fail(ENTANGLE_IS_CONTROL_PANEL(panel));
557
558     EntangleControlPanelPrivate *priv = panel->priv;
559     EntangleControlGroup *root;
560     EntangleControl *grp;
561
562     gtk_container_foreach(GTK_CONTAINER(panel), do_control_remove, panel);
563
564     if (!priv->camera) {
565         GtkWidget *label = gtk_label_new("No camera connected");
566         gtk_container_add(GTK_CONTAINER(panel), label);
567         gtk_widget_show_all(GTK_WIDGET(panel));
568         return;
569     }
570
571     root = entangle_camera_get_controls(priv->camera, NULL);
572
573     if (!root) {
574         GtkWidget *label = gtk_label_new("No controls available");
575         gtk_container_add(GTK_CONTAINER(panel), label);
576         gtk_widget_show_all(GTK_WIDGET(panel));
577         return;
578     }
579
580     if ((grp = entangle_control_group_get_by_path(ENTANGLE_CONTROL_GROUP(root),
581                                                   "/main/status")))
582         do_setup_control_group_ro(panel, GTK_VBOX(panel), ENTANGLE_CONTROL_GROUP(grp));
583
584     if ((grp = entangle_control_group_get_by_path(ENTANGLE_CONTROL_GROUP(root),
585                                                   "/main/settings")))
586         do_setup_control_group(panel, GTK_VBOX(panel), ENTANGLE_CONTROL_GROUP(grp));
587
588     if ((grp = entangle_control_group_get_by_path(ENTANGLE_CONTROL_GROUP(root),
589                                                   "/main/imgsettings")))
590         do_setup_control_group(panel, GTK_VBOX(panel), ENTANGLE_CONTROL_GROUP(grp));
591
592     if ((grp = entangle_control_group_get_by_path(ENTANGLE_CONTROL_GROUP(root),
593                                                   "/main/capturesettings")))
594         do_setup_control_group(panel, GTK_VBOX(panel), ENTANGLE_CONTROL_GROUP(grp));
595
596     gtk_widget_show_all(GTK_WIDGET(panel));
597     g_object_unref(root);
598 }
599
600 static void entangle_control_panel_get_property(GObject *object,
601                                                 guint prop_id,
602                                                 GValue *value,
603                                                 GParamSpec *pspec)
604 {
605     EntangleControlPanel *panel = ENTANGLE_CONTROL_PANEL(object);
606     EntangleControlPanelPrivate *priv = panel->priv;
607
608     switch (prop_id)
609         {
610         case PROP_CAMERA:
611             g_value_set_object(value, priv->camera);
612             break;
613
614         case PROP_HAS_CONTROLS:
615             g_value_set_boolean(value, priv->hasControls);
616             break;
617
618         default:
619             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
620         }
621 }
622
623
624 static void entangle_control_panel_set_property(GObject *object,
625                                                 guint prop_id,
626                                                 const GValue *value,
627                                                 GParamSpec *pspec)
628 {
629     EntangleControlPanel *panel = ENTANGLE_CONTROL_PANEL(object);
630
631     ENTANGLE_DEBUG("Set prop on control panel %d", prop_id);
632
633     switch (prop_id)
634         {
635         case PROP_CAMERA:
636             entangle_control_panel_set_camera(panel, g_value_get_object(value));
637             break;
638
639         default:
640             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
641         }
642 }
643
644
645 static void entangle_control_panel_finalize(GObject *object)
646 {
647     EntangleControlPanel *panel = ENTANGLE_CONTROL_PANEL(object);
648     EntangleControlPanelPrivate *priv = panel->priv;
649
650     if (priv->camera)
651         g_object_unref(priv->camera);
652
653     G_OBJECT_CLASS (entangle_control_panel_parent_class)->finalize (object);
654 }
655
656
657 static void entangle_control_panel_class_init(EntangleControlPanelClass *klass)
658 {
659     GObjectClass *object_class = G_OBJECT_CLASS(klass);
660
661     object_class->finalize = entangle_control_panel_finalize;
662     object_class->get_property = entangle_control_panel_get_property;
663     object_class->set_property = entangle_control_panel_set_property;
664
665     g_object_class_install_property(object_class,
666                                     PROP_CAMERA,
667                                     g_param_spec_object("camera",
668                                                         "Camera",
669                                                         "Camera to managed",
670                                                         ENTANGLE_TYPE_CAMERA,
671                                                         G_PARAM_READWRITE |
672                                                         G_PARAM_STATIC_NAME |
673                                                         G_PARAM_STATIC_NICK |
674                                                         G_PARAM_STATIC_BLURB));
675
676     g_object_class_install_property(object_class,
677                                     PROP_CAMERA,
678                                     g_param_spec_boolean("has-controls",
679                                                          "Has Controls",
680                                                          "Has Controls",
681                                                          FALSE,
682                                                          G_PARAM_READABLE |
683                                                          G_PARAM_STATIC_NAME |
684                                                          G_PARAM_STATIC_NICK |
685                                                          G_PARAM_STATIC_BLURB));
686
687     g_type_class_add_private(klass, sizeof(EntangleControlPanelPrivate));
688 }
689
690
691 EntangleControlPanel *entangle_control_panel_new(void)
692 {
693     return ENTANGLE_CONTROL_PANEL(g_object_new(ENTANGLE_TYPE_CONTROL_PANEL, NULL));
694 }
695
696
697 static void entangle_control_panel_init(EntangleControlPanel *panel)
698 {
699     panel->priv = ENTANGLE_CONTROL_PANEL_GET_PRIVATE(panel);
700
701     gtk_container_set_border_width(GTK_CONTAINER(panel), 0);
702
703     do_setup_camera(panel);
704 }
705
706
707 void entangle_control_panel_set_camera(EntangleControlPanel *panel,
708                                        EntangleCamera *cam)
709 {
710     g_return_if_fail(ENTANGLE_IS_CONTROL_PANEL(panel));
711     g_return_if_fail(!cam || ENTANGLE_IS_CAMERA(cam));
712
713     EntangleControlPanelPrivate *priv = panel->priv;
714
715     if (priv->camera)
716         g_object_unref(priv->camera);
717     priv->camera = cam;
718     if (priv->camera)
719         g_object_ref(priv->camera);
720     do_setup_camera(panel);
721 }
722
723
724 EntangleCamera *entangle_control_panel_get_camera(EntangleControlPanel *panel)
725 {
726     g_return_val_if_fail(ENTANGLE_IS_CONTROL_PANEL(panel), NULL);
727
728     EntangleControlPanelPrivate *priv = panel->priv;
729
730     return priv->camera;
731 }
732
733
734 gboolean entangle_control_panel_get_has_controls(EntangleControlPanel *panel)
735 {
736     g_return_val_if_fail(ENTANGLE_IS_CONTROL_PANEL(panel), FALSE);
737
738     EntangleControlPanelPrivate *priv = panel->priv;
739
740     return priv->hasControls;
741 }
742
743
744 /*
745  * Local variables:
746  *  c-indent-level: 4
747  *  c-basic-offset: 4
748  *  indent-tabs-mode: nil
749  *  tab-width: 8
750  * End:
751  */