7 get_param_specs (GObject *object,
11 /* Use private interface for now, fix later */
12 *specs = G_OBJECT_GET_CLASS (object)->property_specs;
13 *n_specs = G_OBJECT_GET_CLASS (object)->n_property_specs;
17 g_object_connect_property (GObject *object,
18 const gchar *prop_name,
22 gchar *with_detail = g_strconcat ("notify::", prop_name, NULL);
24 g_signal_connect_data (object, with_detail,
38 free_object_property (ObjectProperty *p)
45 connect_controller (GObject *controller,
48 const gchar *prop_name,
53 p = g_new (ObjectProperty, 1);
55 p->prop = g_strdup (prop_name);
57 g_signal_connect_data (controller, signal, func, p,
58 (GDestroyNotify)free_object_property,
63 int_modified (GtkAdjustment *adj, gpointer data)
65 ObjectProperty *p = data;
67 g_object_set (p->obj, p->prop, (int) adj->value, NULL);
71 int_changed (GObject *object, GParamSpec *pspec, gpointer data)
73 GtkAdjustment *adj = GTK_ADJUSTMENT (data);
76 g_value_init (&val, G_TYPE_INT);
77 g_object_get_property (object, pspec->name, &val);
79 if (g_value_get_int (&val) != (int)adj->value)
80 gtk_adjustment_set_value (adj, g_value_get_int (&val));
87 string_modified (GtkEntry *entry, gpointer data)
89 ObjectProperty *p = data;
92 text = gtk_entry_get_text (entry);
94 g_object_set (p->obj, p->prop, text, NULL);
98 string_changed (GObject *object, GParamSpec *pspec, gpointer data)
100 GtkEntry *entry = GTK_ENTRY (data);
105 g_value_init (&val, G_TYPE_STRING);
106 g_object_get_property (object, pspec->name, &val);
108 str = g_value_get_string (&val);
111 text = gtk_entry_get_text (entry);
113 if (strcmp (str, text) != 0)
114 gtk_entry_set_text (entry, str);
116 g_value_unset (&val);
120 bool_modified (GtkToggleButton *tb, gpointer data)
122 ObjectProperty *p = data;
124 g_object_set (p->obj, p->prop, (int) tb->active, NULL);
128 bool_changed (GObject *object, GParamSpec *pspec, gpointer data)
130 GtkToggleButton *tb = GTK_TOGGLE_BUTTON (data);
133 g_value_init (&val, G_TYPE_BOOLEAN);
134 g_object_get_property (object, pspec->name, &val);
136 if (g_value_get_boolean (&val) != tb->active)
137 gtk_toggle_button_set_active (tb, g_value_get_boolean (&val));
139 gtk_label_set_text (GTK_LABEL (GTK_BIN (tb)->child), g_value_get_boolean (&val) ?
142 g_value_unset (&val);
146 create_prop_editor (GObject *object)
152 GtkWidget *prop_edit;
155 GParamSpec **specs = NULL;
159 win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
161 /* hold a strong ref to the object we're editing */
162 g_object_ref (G_OBJECT (object));
163 g_object_set_data_full (G_OBJECT (win), "model-object",
164 object, (GDestroyNotify)g_object_unref);
166 vbox = gtk_vbox_new (TRUE, 2);
168 sw = gtk_scrolled_window_new (NULL, NULL);
169 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
170 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
172 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), vbox);
173 gtk_container_add (GTK_CONTAINER (win), sw);
175 get_param_specs (object, &specs, &n_specs);
180 GParamSpec *spec = specs[i];
185 can_modify = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
186 (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
188 if ((spec->flags & G_PARAM_READABLE) == 0)
190 /* can't display unreadable properties */
195 switch (spec->value_type)
198 hbox = gtk_hbox_new (FALSE, 10);
199 label = gtk_label_new (spec->nick);
200 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
201 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
202 adj = GTK_ADJUSTMENT (gtk_adjustment_new (G_PARAM_SPEC_INT (spec)->default_value,
203 G_PARAM_SPEC_INT (spec)->minimum,
204 G_PARAM_SPEC_INT (spec)->maximum,
206 MAX ((G_PARAM_SPEC_INT (spec)->maximum -
207 G_PARAM_SPEC_INT (spec)->minimum) / 10, 1),
210 prop_edit = gtk_spin_button_new (adj, 1.0, 0);
211 gtk_box_pack_end (GTK_BOX (hbox), prop_edit, FALSE, FALSE, 0);
213 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
215 g_object_connect_property (object, spec->name,
216 GTK_SIGNAL_FUNC (int_changed),
220 connect_controller (G_OBJECT (adj), "value_changed",
221 object, spec->name, (GtkSignalFunc) int_modified);
225 hbox = gtk_hbox_new (FALSE, 10);
226 label = gtk_label_new (spec->nick);
227 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
228 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
230 prop_edit = gtk_entry_new ();
231 gtk_box_pack_end (GTK_BOX (hbox), prop_edit, FALSE, FALSE, 0);
233 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
235 g_object_connect_property (object, spec->name,
236 GTK_SIGNAL_FUNC (string_changed),
240 connect_controller (G_OBJECT (prop_edit), "changed",
241 object, spec->name, (GtkSignalFunc) string_modified);
245 hbox = gtk_hbox_new (FALSE, 10);
246 label = gtk_label_new (spec->nick);
247 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
248 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
250 prop_edit = gtk_toggle_button_new_with_label ("");
251 gtk_box_pack_end (GTK_BOX (hbox), prop_edit, FALSE, FALSE, 0);
253 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
255 g_object_connect_property (object, spec->name,
256 GTK_SIGNAL_FUNC (bool_changed),
260 connect_controller (G_OBJECT (prop_edit), "toggled",
261 object, spec->name, (GtkSignalFunc) bool_modified);
266 gchar *msg = g_strdup_printf ("%s: don't know how to edit type %s",
267 spec->nick, g_type_name (spec->value_type));
268 hbox = gtk_hbox_new (FALSE, 10);
269 label = gtk_label_new (msg);
271 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
272 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
273 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
281 gtk_widget_set_sensitive (prop_edit, FALSE);
283 /* set initial value */
284 g_object_notify (object, spec->name);
290 gtk_window_set_default_size (GTK_WINDOW (win), 300, 500);
292 gtk_widget_show_all (win);
303 gtk_init (&argc, &argv);
305 /* I didn't write the tree test yet, just the property editor to use
306 * inside the tree test ;-)
308 window = create_prop_editor (G_OBJECT (gtk_text_tag_new ("foo")));