~ubuntu-branches/ubuntu/raring/fyre/raring

« back to all changes in this revision

Viewing changes to src/parameter-editor.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Haas
  • Date: 2005-05-25 21:59:19 UTC
  • Revision ID: james.westby@ubuntu.com-20050525215919-jawtso5ic23qb401
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c; c-basic-offset: 4; -*-
 
2
 *
 
3
 * parameter-editor.c - Automatically constructs a GUI for editing the
 
4
 *                      parameters of a ParameterHolder instance.
 
5
 *
 
6
 * Fyre - rendering and interactive exploration of chaotic functions
 
7
 * Copyright (C) 2004-2005 David Trowbridge and Micah Dowty
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or
 
10
 * modify it under the terms of the GNU General Public License
 
11
 * as published by the Free Software Foundation; either version 2
 
12
 * of the License, or (at your option) any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 * GNU General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU General Public License
 
20
 * along with this program; if not, write to the Free Software
 
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
22
 *
 
23
 */
 
24
 
 
25
#include "parameter-editor.h"
 
26
#include "color-button.h"
 
27
#include <gtk/gtk.h>
 
28
#include <string.h>
 
29
 
 
30
static void parameter_editor_class_init(ParameterEditorClass *klass);
 
31
static void parameter_editor_init(ParameterEditor *self);
 
32
static void parameter_editor_finalize(GObject *object);
 
33
 
 
34
static void parameter_editor_attach(ParameterEditor *self, ParameterHolder *holder);
 
35
static void parameter_editor_add_paramspec(ParameterEditor *self, GParamSpec *spec);
 
36
static void parameter_editor_add_group_heading(ParameterEditor *self, const gchar *group);
 
37
static void parameter_editor_add_row(ParameterEditor *self, GParamSpec *spec, GtkWidget *row);
 
38
static void parameter_editor_add_dependency(ParameterEditor *self, GtkWidget *widget, const gchar *dependency_name);
 
39
static void parameter_editor_add_labeled_row(ParameterEditor *self, GParamSpec *spec, GtkWidget *row);
 
40
 
 
41
static void parameter_editor_connect_notify(ParameterEditor *self,
 
42
                                            GtkWidget       *widget,
 
43
                                            const gchar     *property_name,
 
44
                                            GCallback        func);
 
45
 
 
46
static void parameter_editor_add_numeric(ParameterEditor *self, GParamSpec *spec);
 
47
static void parameter_editor_add_color(ParameterEditor *self, GParamSpec *spec);
 
48
static void parameter_editor_add_boolean(ParameterEditor *self, GParamSpec *spec);
 
49
static void parameter_editor_add_enum(ParameterEditor *self, GParamSpec *spec);
 
50
 
 
51
static void on_changed_numeric(GtkWidget *widget, ParameterEditor *self);
 
52
static void on_changed_color(GtkWidget *widget, ParameterEditor *self);
 
53
static void on_changed_boolean(GtkWidget *widget, ParameterEditor *self);
 
54
static void on_changed_enum(GtkWidget *widget, ParameterEditor *self);
 
55
 
 
56
static void on_notify_numeric(ParameterHolder *holder, GParamSpec *spec, GtkWidget *widget);
 
57
static void on_notify_color(ParameterHolder *holder, GParamSpec *spec, GtkWidget *widget);
 
58
static void on_notify_opacity(ParameterHolder *holder, GParamSpec *spec, GtkWidget *widget);
 
59
static void on_notify_boolean(ParameterHolder *holder, GParamSpec *spec, GtkWidget *widget);
 
60
static void on_notify_dependency(ParameterHolder *holder, GParamSpec *spec, GtkWidget *widget);
 
61
static void on_notify_enum(ParameterHolder *holder, GParamSpec *spec, GtkWidget *widget);
 
62
 
 
63
 
 
64
/************************************************************************************/
 
65
/**************************************************** Initialization / Finalization */
 
66
/************************************************************************************/
 
67
 
 
68
GType parameter_editor_get_type(void) {
 
69
    static GType pe_type = 0;
 
70
 
 
71
    if (!pe_type) {
 
72
        static const GTypeInfo pe_info = {
 
73
            sizeof(ParameterEditorClass),
 
74
            NULL, /* base_init */
 
75
            NULL, /* base_finalize */
 
76
            (GClassInitFunc) parameter_editor_class_init,
 
77
            NULL, /* class_finalize */
 
78
            NULL, /* class_data */
 
79
            sizeof(ParameterEditor),
 
80
            0,
 
81
            (GInstanceInitFunc) parameter_editor_init,
 
82
        };
 
83
 
 
84
        pe_type = g_type_register_static(GTK_TYPE_VBOX, "ParameterEditor", &pe_info, 0);
 
85
    }
 
86
 
 
87
    return pe_type;
 
88
}
 
89
 
 
90
static void parameter_editor_class_init(ParameterEditorClass *klass) {
 
91
    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
92
 
 
93
    gobject_class->finalize = parameter_editor_finalize;
 
94
}
 
95
 
 
96
static void parameter_editor_init(ParameterEditor *self) {
 
97
    self->label_sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
 
98
}
 
99
 
 
100
static void parameter_editor_finalize(GObject *object) {
 
101
    ParameterEditor *self = PARAMETER_EDITOR(object);
 
102
 
 
103
    if (self->holder) {
 
104
        g_object_unref(self->holder);
 
105
        self->holder = NULL;
 
106
    }
 
107
 
 
108
    if (self->label_sizegroup) {
 
109
        g_object_unref(self->label_sizegroup);
 
110
        self->label_sizegroup = NULL;
 
111
    }
 
112
 
 
113
    if (self->previous_group) {
 
114
        g_free(self->previous_group);
 
115
        self->previous_group = NULL;
 
116
    }
 
117
}
 
118
 
 
119
GtkWidget* parameter_editor_new(ParameterHolder *holder) {
 
120
    ParameterEditor *self = g_object_new(parameter_editor_get_type(), NULL);
 
121
    parameter_editor_attach(self, holder);
 
122
    return GTK_WIDGET(self);
 
123
}
 
124
 
 
125
 
 
126
/************************************************************************************/
 
127
/********************************************************************* GUI Building */
 
128
/************************************************************************************/
 
129
 
 
130
static void parameter_editor_attach(ParameterEditor *self, ParameterHolder *holder) {
 
131
    /* Attach this parameter editor to a holder, adding widgets for
 
132
     * each paramspec in the holder with a PARAM_IN_GUI flag
 
133
     */
 
134
    GParamSpec** properties;
 
135
    guint n_properties;
 
136
    int i;
 
137
 
 
138
    self->holder = g_object_ref(holder);
 
139
 
 
140
    properties = g_object_class_list_properties(G_OBJECT_GET_CLASS(holder), &n_properties);
 
141
    for (i=0; i<n_properties; i++) {
 
142
        if (properties[i]->flags & PARAM_IN_GUI)
 
143
            parameter_editor_add_paramspec(self, properties[i]);
 
144
    }
 
145
    g_free(properties);
 
146
}
 
147
 
 
148
static void parameter_editor_add_paramspec(ParameterEditor *self, GParamSpec *spec) {
 
149
    const gchar *group;
 
150
 
 
151
    /* Get this parameter's group name, adding a new group header if it's changed */
 
152
    group = param_spec_get_group(spec);
 
153
    if (group) {
 
154
        if ((!self->previous_group) || strcmp((void *) group, self->previous_group))
 
155
            parameter_editor_add_group_heading(self, group);
 
156
        if (self->previous_group)
 
157
            g_free(self->previous_group);
 
158
        self->previous_group = g_strdup(group);
 
159
    }
 
160
 
 
161
    /* Pick a type-dependent procedure for adding this parameter to the GUI */
 
162
 
 
163
    if (spec->value_type == G_TYPE_DOUBLE)
 
164
        parameter_editor_add_numeric(self, spec);
 
165
 
 
166
    else if (spec->value_type == G_TYPE_UINT)
 
167
        parameter_editor_add_numeric(self, spec);
 
168
 
 
169
    else if (spec->value_type == GDK_TYPE_COLOR)
 
170
        parameter_editor_add_color(self, spec);
 
171
 
 
172
    else if (spec->value_type == G_TYPE_BOOLEAN)
 
173
        parameter_editor_add_boolean(self, spec);
 
174
 
 
175
    else if (g_type_is_a (spec->value_type, G_TYPE_ENUM))
 
176
        parameter_editor_add_enum (self, spec);
 
177
 
 
178
    else
 
179
        g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
 
180
              "Can't edit values of type %s",
 
181
              g_type_name(spec->value_type));
 
182
}
 
183
 
 
184
static void parameter_editor_add_group_heading(ParameterEditor *self, const gchar *group) {
 
185
    GtkWidget *label;
 
186
    gchar *markup;
 
187
 
 
188
    /* Add a separator if this isn't the first group */
 
189
    if (self->previous_group)
 
190
        gtk_box_pack_start(GTK_BOX(self), gtk_hseparator_new(), FALSE, FALSE, 4);
 
191
 
 
192
    /* Make a label with the group name bold and centered */
 
193
    markup = g_strdup_printf("<b>%s</b>", group);
 
194
    label = gtk_label_new(NULL);
 
195
    gtk_label_set_markup(GTK_LABEL(label), markup);
 
196
    g_free(markup);
 
197
    gtk_box_pack_start(GTK_BOX(self), label, FALSE, FALSE, 4);
 
198
}
 
199
 
 
200
static void parameter_editor_add_row(ParameterEditor *self, GParamSpec *spec, GtkWidget *row) {
 
201
    const gchar *dep;
 
202
 
 
203
    gtk_box_pack_start(GTK_BOX(self), row, FALSE, FALSE, 2);
 
204
 
 
205
    dep = param_spec_get_dependency(spec);
 
206
    if (dep)
 
207
        parameter_editor_add_dependency(self, row, dep);
 
208
}
 
209
 
 
210
static void parameter_editor_add_labeled_row(ParameterEditor *self, GParamSpec *spec, GtkWidget *row) {
 
211
    GtkWidget *hbox, *label;
 
212
    gchar *text;
 
213
 
 
214
    hbox = gtk_hbox_new(FALSE, 0);
 
215
    text = g_strdup_printf("%s:", g_param_spec_get_nick(spec));
 
216
    label = gtk_label_new(text);
 
217
    g_free(text);
 
218
    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 
219
    gtk_size_group_add_widget(self->label_sizegroup, label);
 
220
    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 6);
 
221
    gtk_box_pack_start(GTK_BOX(hbox), row, TRUE, TRUE, 6);
 
222
 
 
223
    parameter_editor_add_row(self, spec, hbox);
 
224
}
 
225
 
 
226
static void parameter_editor_add_dependency(ParameterEditor *self, GtkWidget *widget, const gchar *dependency_name) {
 
227
    /* Add a notify callback to our dependency that enables or disables the given widget.
 
228
     * Call the notify callback once right away to set up our initial sensitivity.
 
229
     */
 
230
    gchar *signal_name;
 
231
    GParamSpec *spec;
 
232
 
 
233
    signal_name = g_strdup_printf("notify::%s", dependency_name);
 
234
    g_signal_connect(self->holder, signal_name, G_CALLBACK(on_notify_dependency), widget);
 
235
    g_free(signal_name);
 
236
 
 
237
    spec = g_object_class_find_property(G_OBJECT_GET_CLASS(self->holder), dependency_name);
 
238
    on_notify_dependency(self->holder, spec, widget);
 
239
}
 
240
 
 
241
 
 
242
/************************************************************************************/
 
243
/********************************************************************* Type Editors */
 
244
/************************************************************************************/
 
245
 
 
246
static void parameter_editor_connect_notify(ParameterEditor *self,
 
247
                                            GtkWidget       *widget,
 
248
                                            const gchar     *property_name,
 
249
                                            GCallback        func) {
 
250
    /* Connect to the notify::<property> signal so we can update the
 
251
     * GUI automatically when someone else changes the property. The
 
252
     * callback needs to know which widget is associated with this property,
 
253
     * and it needs a pointer to our ParameterEditor instance. We do this by
 
254
     * passing the widget as user_data but using g_object_set_data to
 
255
     * attach the ParameterEditor to the widget.
 
256
     */
 
257
    gchar *signal_name;
 
258
    signal_name = g_strdup_printf("notify::%s", property_name);
 
259
    g_object_set_data(G_OBJECT(widget), "ParameterEditor", self);
 
260
    g_signal_connect(self->holder, signal_name, func, widget);
 
261
    g_free(signal_name);
 
262
}
 
263
 
 
264
static void parameter_editor_add_numeric(ParameterEditor *self, GParamSpec *spec) {
 
265
    GtkWidget *spinner;
 
266
    GtkObject *adjustment;
 
267
    gdouble climb_rate = 0.1;
 
268
    int digits = 1;
 
269
    gdouble value = 0;
 
270
    gdouble upper = 1;
 
271
    gdouble lower = 0;
 
272
    gdouble step_increment = 0.1;
 
273
    gdouble page_increment = 0.1;
 
274
    gdouble page_size = 0;
 
275
    const ParameterIncrements *increments;
 
276
    GValue gv, double_gv;
 
277
 
 
278
    /* Look for upper and lower bounds in the GParamSpec to override our defaults */
 
279
    if (G_IS_PARAM_SPEC_DOUBLE(spec)) {
 
280
        GParamSpecDouble *s = G_PARAM_SPEC_DOUBLE(spec);
 
281
        upper = s->maximum;
 
282
        lower = s->minimum;
 
283
    }
 
284
    else if (G_IS_PARAM_SPEC_UINT(spec)) {
 
285
        GParamSpecUInt *s = G_PARAM_SPEC_UINT(spec);
 
286
        upper = s->maximum;
 
287
        lower = s->minimum;
 
288
    }
 
289
 
 
290
    /* Look for a ParameterIncrements structure attached to this parameter.
 
291
     * If we find one, set the increments and number of digits from it.
 
292
     */
 
293
    increments = param_spec_get_increments(spec);
 
294
    if (increments) {
 
295
        digits = increments->digits;
 
296
        step_increment = increments->step;
 
297
        page_increment = increments->page;
 
298
        climb_rate = increments->step;
 
299
    }
 
300
 
 
301
    /* Get the parameter's current value */
 
302
    memset(&gv, 0, sizeof(gv));
 
303
    memset(&double_gv, 0, sizeof(double_gv));
 
304
    g_value_init(&gv, spec->value_type);
 
305
    g_value_init(&double_gv, G_TYPE_DOUBLE);
 
306
    g_object_get_property(G_OBJECT(self->holder), spec->name, &gv);
 
307
    g_value_transform(&gv, &double_gv);
 
308
    value = g_value_get_double(&double_gv);
 
309
    g_value_unset(&gv);
 
310
    g_value_unset(&double_gv);
 
311
 
 
312
    adjustment = gtk_adjustment_new(value, lower, upper, step_increment, page_increment, page_size);
 
313
    spinner = gtk_spin_button_new(GTK_ADJUSTMENT(adjustment), climb_rate, digits);
 
314
 
 
315
    /* Set up our callback on change */
 
316
    g_object_set_data(G_OBJECT(spinner), "ParamSpec", spec);
 
317
    g_signal_connect(spinner, "value-changed", G_CALLBACK(on_changed_numeric), self);
 
318
 
 
319
    parameter_editor_connect_notify(self, spinner, spec->name, G_CALLBACK(on_notify_numeric));
 
320
    parameter_editor_add_labeled_row(self, spec, spinner);
 
321
}
 
322
 
 
323
static void parameter_editor_add_color(ParameterEditor *self, GParamSpec *spec) {
 
324
    GtkWidget *color_button;
 
325
    const gchar* opacity_property;
 
326
    guint16 opacity = 0xFFFF;
 
327
    GdkColor color = {0,0,0,0};
 
328
    GValue gv;
 
329
 
 
330
    /* See if this color property has a matching opacity property */
 
331
    opacity_property = g_param_spec_get_qdata(spec, g_quark_from_static_string("opacity-property"));
 
332
    if (opacity_property) {
 
333
 
 
334
        /* Get the current opacity */
 
335
        memset(&gv, 0, sizeof(gv));
 
336
        g_value_init(&gv, G_TYPE_UINT);
 
337
        g_object_get_property(G_OBJECT(self->holder), opacity_property, &gv);
 
338
        opacity = g_value_get_uint(&gv);
 
339
        g_value_unset(&gv);
 
340
    }
 
341
 
 
342
    /* Get the current color */
 
343
    memset(&gv, 0, sizeof(gv));
 
344
    g_value_init(&gv, GDK_TYPE_COLOR);
 
345
    g_object_get_property(G_OBJECT(self->holder), spec->name, &gv);
 
346
    color = *(GdkColor*)g_value_get_boxed(&gv);
 
347
    g_value_unset(&gv);
 
348
 
 
349
    color_button = color_button_new_with_defaults(g_param_spec_get_nick(spec), &color, opacity);
 
350
 
 
351
    /* Set up our callback on change */
 
352
    g_object_set_data(G_OBJECT(color_button), "ParamSpec", spec);
 
353
    g_signal_connect(color_button, "changed", G_CALLBACK(on_changed_color), self);
 
354
 
 
355
    parameter_editor_connect_notify(self, color_button, spec->name, G_CALLBACK(on_notify_color));
 
356
    if (opacity_property)
 
357
        parameter_editor_connect_notify(self, color_button, opacity_property, G_CALLBACK(on_notify_opacity));
 
358
 
 
359
    parameter_editor_add_labeled_row(self, spec, color_button);
 
360
}
 
361
 
 
362
static void parameter_editor_add_boolean(ParameterEditor *self, GParamSpec *spec) {
 
363
    GtkWidget *check;
 
364
    GValue gv;
 
365
 
 
366
    check = gtk_check_button_new();
 
367
 
 
368
    /* Get the parameter's current value */
 
369
    memset(&gv, 0, sizeof(gv));
 
370
    g_value_init(&gv, spec->value_type);
 
371
    g_object_get_property(G_OBJECT(self->holder), spec->name, &gv);
 
372
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), g_value_get_boolean(&gv));
 
373
    g_value_unset(&gv);
 
374
 
 
375
    /* Set up our callback on change */
 
376
    g_object_set_data(G_OBJECT(check), "ParamSpec", spec);
 
377
    g_signal_connect(check, "toggled", G_CALLBACK(on_changed_boolean), self);
 
378
 
 
379
    parameter_editor_connect_notify(self, check, spec->name, G_CALLBACK(on_notify_boolean));
 
380
    parameter_editor_add_labeled_row(self, spec, check);
 
381
}
 
382
 
 
383
static void parameter_editor_add_enum(ParameterEditor *self, GParamSpec *spec) {
 
384
    GtkWidget *combo;
 
385
    GValue gv;
 
386
    GEnumClass *klass;
 
387
    gint i;
 
388
#if (GTK_MINOR_VERSION < 4)
 
389
    GtkWidget *menu;
 
390
#endif
 
391
 
 
392
    klass = (GEnumClass*) g_type_class_ref (spec->value_type);
 
393
 
 
394
#if (GTK_MINOR_VERSION >= 4)
 
395
    combo = gtk_combo_box_new_text ();
 
396
    for (i = 0; i < klass->n_values; i++)
 
397
        {
 
398
            GEnumValue *value;
 
399
 
 
400
            value = g_enum_get_value (klass, i);
 
401
 
 
402
            gtk_combo_box_append_text (GTK_COMBO_BOX (combo), value->value_nick);
 
403
        }
 
404
#else
 
405
    combo = gtk_option_menu_new ();
 
406
    menu = gtk_menu_new ();
 
407
 
 
408
    for (i = 0; i < klass->n_values; i++)
 
409
        {
 
410
            GEnumValue *value;
 
411
 
 
412
            value = g_enum_get_value (klass, i);
 
413
 
 
414
            gtk_menu_shell_append (GTK_MENU_SHELL (menu), gtk_menu_item_new_with_label (value->value_nick));
 
415
        }
 
416
 
 
417
    gtk_option_menu_set_menu (GTK_OPTION_MENU (combo), menu);
 
418
#endif
 
419
 
 
420
    /* Get the parameter's current value */
 
421
    memset (&gv, 0, sizeof (gv));
 
422
    g_value_init (&gv, spec->value_type);
 
423
    g_object_get_property (G_OBJECT (self->holder), spec->name, &gv);
 
424
#if (GTK_MINOR_VERSION >= 4)
 
425
    gtk_combo_box_set_active (GTK_COMBO_BOX (combo), g_value_get_enum (&gv));
 
426
#else
 
427
    gtk_option_menu_set_history (GTK_OPTION_MENU (combo), g_value_get_enum (&gv));
 
428
#endif
 
429
    g_value_unset (&gv);
 
430
 
 
431
    /* Set up our callback on change */
 
432
    g_object_set_data (G_OBJECT (combo), "ParamSpec", spec);
 
433
    g_signal_connect (combo, "changed", G_CALLBACK (on_changed_enum), self);
 
434
 
 
435
    parameter_editor_connect_notify (self, combo, spec->name, G_CALLBACK (on_notify_enum));
 
436
    parameter_editor_add_labeled_row (self, spec, combo);
 
437
}
 
438
 
 
439
 
 
440
/************************************************************************************/
 
441
/***************************************************************** Widget callbacks */
 
442
/************************************************************************************/
 
443
 
 
444
static void on_changed_numeric(GtkWidget *widget, ParameterEditor *self) {
 
445
    GParamSpec *spec = g_object_get_data(G_OBJECT(widget), "ParamSpec");
 
446
    GValue gv, double_gv;
 
447
 
 
448
    if (self->suppress_changed)
 
449
        return;
 
450
 
 
451
    /* Convert the current spinner value from a double to whatever type we need,
 
452
     * and set the property from that converted value.
 
453
     */
 
454
    memset(&gv, 0, sizeof(gv));
 
455
    memset(&double_gv, 0, sizeof(double_gv));
 
456
    g_value_init(&gv, spec->value_type);
 
457
    g_value_init(&double_gv, G_TYPE_DOUBLE);
 
458
    g_value_set_double(&double_gv, gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)));
 
459
    g_value_transform(&double_gv, &gv);
 
460
 
 
461
    self->suppress_notify = TRUE;
 
462
    g_object_set_property(G_OBJECT(self->holder), spec->name, &gv);
 
463
    self->suppress_notify = FALSE;
 
464
 
 
465
    g_value_unset(&gv);
 
466
    g_value_unset(&double_gv);
 
467
}
 
468
 
 
469
static void on_changed_color(GtkWidget *widget, ParameterEditor *self) {
 
470
    GParamSpec *spec = g_object_get_data(G_OBJECT(widget), "ParamSpec");
 
471
    GdkColor c;
 
472
    const gchar* opacity_property;
 
473
    guint opacity;
 
474
 
 
475
    if (self->suppress_changed)
 
476
        return;
 
477
 
 
478
    opacity_property = g_param_spec_get_qdata(spec, g_quark_from_static_string("opacity-property"));
 
479
    color_button_get_color(COLOR_BUTTON(widget), &c);
 
480
    opacity = color_button_get_alpha(COLOR_BUTTON(widget));
 
481
 
 
482
    /* Set both color and opacity if we have both. If we don't have
 
483
     * an opacity property, opacity_property will be NULL and the opacity
 
484
     * parameter will be ignored.
 
485
     */
 
486
    self->suppress_notify = TRUE;
 
487
    g_object_set(self->holder,
 
488
                 spec->name, &c,
 
489
                 opacity_property, opacity,
 
490
                 NULL);
 
491
    self->suppress_notify = FALSE;
 
492
}
 
493
 
 
494
static void on_changed_boolean(GtkWidget *widget, ParameterEditor *self) {
 
495
    GParamSpec *spec = g_object_get_data(G_OBJECT(widget), "ParamSpec");
 
496
    gboolean active;
 
497
 
 
498
    if (self->suppress_changed)
 
499
        return;
 
500
 
 
501
    active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
 
502
 
 
503
    self->suppress_notify = TRUE;
 
504
    g_object_set(self->holder,
 
505
                 spec->name, active,
 
506
                 NULL);
 
507
    self->suppress_notify = FALSE;
 
508
}
 
509
 
 
510
static void on_changed_enum(GtkWidget *widget, ParameterEditor *self) {
 
511
    GParamSpec *spec = g_object_get_data (G_OBJECT (widget), "ParamSpec");
 
512
    gint active;
 
513
 
 
514
    if (self->suppress_changed)
 
515
        return;
 
516
 
 
517
#if (GTK_MINOR_VERSION >= 4)
 
518
    active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
 
519
#else
 
520
    active = gtk_option_menu_get_history (GTK_OPTION_MENU (widget));
 
521
#endif
 
522
 
 
523
    self->suppress_notify = TRUE;
 
524
    g_object_set (self->holder,
 
525
                  spec->name,
 
526
                  active,
 
527
                  NULL);
 
528
    self->suppress_notify = FALSE;
 
529
}
 
530
 
 
531
 
 
532
/************************************************************************************/
 
533
/***************************************************************** Notify callbacks */
 
534
/************************************************************************************/
 
535
 
 
536
static void on_notify_numeric(ParameterHolder *holder, GParamSpec *spec, GtkWidget *widget) {
 
537
    ParameterEditor *self = g_object_get_data(G_OBJECT(widget), "ParameterEditor");
 
538
    GValue gv, double_gv;
 
539
 
 
540
    if (self->suppress_notify)
 
541
        return;
 
542
 
 
543
    /* Conver the current property value to a double and set our spin button */
 
544
    memset(&gv, 0, sizeof(gv));
 
545
    memset(&double_gv, 0, sizeof(double_gv));
 
546
    g_value_init(&gv, spec->value_type);
 
547
    g_value_init(&double_gv, G_TYPE_DOUBLE);
 
548
    g_object_get_property(G_OBJECT(holder), spec->name, &gv);
 
549
    g_value_transform(&gv, &double_gv);
 
550
 
 
551
    self->suppress_changed = TRUE;
 
552
    gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), g_value_get_double(&double_gv));
 
553
    self->suppress_changed = FALSE;
 
554
 
 
555
    g_value_unset(&gv);
 
556
    g_value_unset(&double_gv);
 
557
}
 
558
 
 
559
static void on_notify_color(ParameterHolder *holder, GParamSpec *spec, GtkWidget *widget) {
 
560
    ParameterEditor *self = g_object_get_data(G_OBJECT(widget), "ParameterEditor");
 
561
    GdkColor *c;
 
562
 
 
563
    if (self->suppress_notify)
 
564
        return;
 
565
 
 
566
    g_object_get(holder, spec->name, &c, NULL);
 
567
 
 
568
    self->suppress_changed = TRUE;
 
569
    color_button_set_color(COLOR_BUTTON(widget), c);
 
570
    self->suppress_changed = FALSE;
 
571
}
 
572
 
 
573
static void on_notify_opacity(ParameterHolder *holder, GParamSpec *spec, GtkWidget *widget) {
 
574
    ParameterEditor *self = g_object_get_data(G_OBJECT(widget), "ParameterEditor");
 
575
    guint opacity;
 
576
 
 
577
    if (self->suppress_notify)
 
578
        return;
 
579
 
 
580
    g_object_get(holder, spec->name, &opacity, NULL);
 
581
 
 
582
    self->suppress_changed = TRUE;
 
583
    color_button_set_alpha(COLOR_BUTTON(widget), opacity);
 
584
    self->suppress_changed = FALSE;
 
585
}
 
586
 
 
587
static void on_notify_boolean(ParameterHolder *holder, GParamSpec *spec, GtkWidget *widget) {
 
588
    ParameterEditor *self = g_object_get_data(G_OBJECT(widget), "ParameterEditor");
 
589
    gboolean active;
 
590
 
 
591
    if (self->suppress_notify)
 
592
        return;
 
593
 
 
594
    g_object_get(holder, spec->name, &active, NULL);
 
595
 
 
596
    self->suppress_changed = TRUE;
 
597
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), active);
 
598
    self->suppress_changed = FALSE;
 
599
}
 
600
 
 
601
static void on_notify_dependency(ParameterHolder *holder, GParamSpec *spec, GtkWidget *widget) {
 
602
    gboolean active;
 
603
    g_object_get(holder, spec->name, &active, NULL);
 
604
    gtk_widget_set_sensitive(widget, active);
 
605
}
 
606
 
 
607
static void on_notify_enum(ParameterHolder *holder, GParamSpec *spec, GtkWidget *widget) {
 
608
    ParameterEditor *self = g_object_get_data (G_OBJECT (widget), "ParameterEditor");
 
609
    GValue gv;
 
610
 
 
611
    if (self->suppress_notify)
 
612
        return;
 
613
 
 
614
    memset (&gv, 0, sizeof (gv));
 
615
    g_value_init (&gv, spec->value_type);
 
616
    g_object_get_property (G_OBJECT (holder), spec->name, &gv);
 
617
 
 
618
    self->suppress_changed = TRUE;
 
619
#if (GTK_MINOR_VERSION >= 4)
 
620
    gtk_combo_box_set_active (GTK_COMBO_BOX (widget), g_value_get_enum (&gv));
 
621
#else
 
622
    gtk_option_menu_set_history (GTK_OPTION_MENU (widget), g_value_get_enum (&gv));
 
623
#endif
 
624
    self->suppress_changed = FALSE;
 
625
 
 
626
    g_value_unset (&gv);
 
627
}
 
628
 
 
629
 
 
630
/* The End */