]> git.sur5r.net Git - glabels/blob - glabels1/src/propertybox.c
b8fe294611f1efd807b36ef1162338f15e43be1e
[glabels] / glabels1 / src / propertybox.c
1 /* Modified version of gnome-propertybox from gnome-libs-1.4 */
2 /* Primarily removed the "help" button and changed the names.*/
3 /*  -Jim Evins 11/25/2001 */
4
5 /* gnome-propertybox.c - Property dialog box.
6
7    Copyright (C) 1998 Tom Tromey
8
9    This library is free software; you can redistribute it and/or
10    modify it under the terms of the GNU Library General Public License
11    as published by the Free Software Foundation; either version 2, or
12    (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 GNU
17    Library General Public License for more details.
18
19    You should have received a copy of the GNU Library General Public
20    License along with this program; if not, write to the Free Software
21    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22    02111-1307, USA.  */
23
24 /* Note that the property box is constructed so that we could later
25    change how the buttons work.  For instance, we could put an Apply
26    button inside each page; this kind of Apply button would only
27    affect the current page.  Please do not change the API in a way
28    that would violate this goal.  */
29
30 #include <config.h>
31
32 #include "propertybox.h"
33 #include <libgnome/gnome-util.h>
34 #include <libgnomeui/gnome-stock.h>
35 #include <libgnome/gnome-config.h>
36 #include <gtk/gtk.h>
37 #include <libgnomeui/gnome-preferences.h>
38
39 enum {
40         APPLY,
41         LAST_SIGNAL
42 };
43
44 typedef void (*glPropertyBoxSignal) (GtkObject * object,
45                                      gint arg,
46                                      gpointer data);
47
48 static void gl_property_box_class_init (glPropertyBoxClass * klass);
49 static void gl_property_box_init (glPropertyBox * property_box);
50 static void gl_property_box_marshal_signal (GtkObject * object,
51                                             GtkSignalFunc func,
52                                             gpointer func_data,
53                                             GtkArg * args);
54 static void gl_property_box_destroy (GtkObject * object);
55
56 /*
57  * These four are called from dialog_clicked_cb(), depending
58  * on which button was clicked.
59  */
60 static void global_apply (glPropertyBox * property_box);
61 static void apply_and_close (glPropertyBox * property_box);
62 static void just_close (glPropertyBox * property_box);
63
64 static void dialog_clicked_cb (GnomeDialog * dialog,
65                                gint button,
66                                gpointer data);
67
68 static GnomeDialogClass *parent_class = NULL;
69
70 static gint property_box_signals[LAST_SIGNAL] = { 0 };
71
72 /**
73  * gl_property_box_get_type:
74  *
75  * Internal routine that returns the GtkType of the
76  * glPropertyBox widget
77  */
78 guint
79 gl_property_box_get_type (void)
80 {
81         static guint property_box_type = 0;
82
83         if (!property_box_type) {
84                 GtkTypeInfo property_box_info = {
85                         "glPropertyBox",
86                         sizeof (glPropertyBox),
87                         sizeof (glPropertyBoxClass),
88                         (GtkClassInitFunc) gl_property_box_class_init,
89                         (GtkObjectInitFunc) gl_property_box_init,
90                         (GtkArgSetFunc) NULL,
91                         (GtkArgGetFunc) NULL
92                 };
93
94                 property_box_type = gtk_type_unique (gnome_dialog_get_type (),
95                                                      &property_box_info);
96         }
97
98         return property_box_type;
99 }
100
101 static void
102 gl_property_box_class_init (glPropertyBoxClass * klass)
103 {
104         GtkObjectClass *object_class;
105         GtkWidgetClass *widget_class;
106         GtkWindowClass *window_class;
107
108         object_class = (GtkObjectClass *) klass;
109         widget_class = (GtkWidgetClass *) klass;
110         window_class = (GtkWindowClass *) klass;
111
112         object_class->destroy = gl_property_box_destroy;
113
114         parent_class = gtk_type_class (gnome_dialog_get_type ());
115
116         property_box_signals[APPLY] =
117             gtk_signal_new ("apply",
118                             GTK_RUN_LAST,
119                             object_class->type,
120                             GTK_SIGNAL_OFFSET (glPropertyBoxClass,
121                                                apply),
122                             gl_property_box_marshal_signal,
123                             GTK_TYPE_NONE, 1, GTK_TYPE_INT);
124
125         gtk_object_class_add_signals (object_class, property_box_signals,
126                                       LAST_SIGNAL);
127
128         klass->apply = NULL;
129 }
130
131 static void
132 gl_property_box_marshal_signal (GtkObject * object,
133                                 GtkSignalFunc func,
134                                 gpointer func_data,
135                                 GtkArg * args)
136 {
137         glPropertyBoxSignal rfunc;
138
139         rfunc = (glPropertyBoxSignal) func;
140         (*rfunc) (object, GTK_VALUE_INT (args[0]), func_data);
141 }
142
143 static void
144 gl_property_box_init (glPropertyBox * property_box)
145 {
146         GList *button_list;
147
148         property_box->notebook = gtk_notebook_new ();
149
150         if (gnome_preferences_get_property_box_apply ()) {
151                 gnome_dialog_append_buttons (GNOME_DIALOG (property_box),
152                                              GNOME_STOCK_BUTTON_OK,
153                                              GNOME_STOCK_BUTTON_APPLY,
154                                              GNOME_STOCK_BUTTON_CLOSE, NULL);
155         } else {
156                 gnome_dialog_append_buttons (GNOME_DIALOG (property_box),
157                                              GNOME_STOCK_BUTTON_OK,
158                                              GNOME_STOCK_BUTTON_CANCEL, NULL);
159         }
160
161         gnome_dialog_set_default (GNOME_DIALOG (property_box), 0);
162
163         /* This is sort of unattractive */
164
165         button_list = GNOME_DIALOG (property_box)->buttons;
166
167         property_box->ok_button = GTK_WIDGET (button_list->data);
168         button_list = button_list->next;
169
170         if (gnome_preferences_get_property_box_apply ()) {
171                 property_box->apply_button = GTK_WIDGET (button_list->data);
172                 button_list = button_list->next;
173                 gtk_widget_set_sensitive (property_box->apply_button, FALSE);
174         } else
175                 property_box->apply_button = 0;
176
177         property_box->cancel_button = GTK_WIDGET (button_list->data);
178         button_list = button_list->next;
179
180         gtk_signal_connect (GTK_OBJECT (property_box), "clicked",
181                             GTK_SIGNAL_FUNC (dialog_clicked_cb), NULL);
182
183         gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (property_box)->vbox),
184                             property_box->notebook, TRUE, TRUE, 0);
185
186         gtk_widget_show (property_box->notebook);
187 }
188
189 static void
190 gl_property_box_destroy (GtkObject * object)
191 {
192         glPropertyBox *property_box;
193
194         g_return_if_fail (object != NULL);
195         g_return_if_fail (GL_IS_PROPERTY_BOX (object));
196
197         property_box = GL_PROPERTY_BOX (object);
198
199         GTK_OBJECT_CLASS (parent_class)->destroy (object);
200 }
201
202 /**
203  * gl_property_box_new: [constructor]
204  *
205  * Creates a new glPropertyBox widget.  The PropertyBox widget
206  * is useful for making consistent configuration dialog boxes.
207  *
208  * When a setting has been made to a property in the PropertyBox
209  * your program needs to invoke the gl_property_box_changed to signal
210  * a change (this will enable the Ok/Apply buttons).
211  *
212  * Returns a newly created glPropertyBox widget.
213  */
214 GtkWidget *
215 gl_property_box_new (void)
216 {
217         return gtk_type_new (gl_property_box_get_type ());
218 }
219
220 static void
221 dialog_clicked_cb (GnomeDialog * dialog,
222                    gint button,
223                    gpointer data)
224 {
225         glPropertyBox *pbox;
226         GtkWidget *page;
227         GList *list;
228         gboolean dirty = FALSE;
229
230         g_return_if_fail (dialog != NULL);
231         g_return_if_fail (GL_IS_PROPERTY_BOX (dialog));
232
233         pbox = GL_PROPERTY_BOX (dialog);
234
235         if (GTK_NOTEBOOK (pbox->notebook)->cur_page != NULL) {
236
237                 for (list = GTK_NOTEBOOK (pbox->notebook)->children;
238                      list != NULL; list = list->next) {
239                         GtkNotebookPage *page = list->data;
240                         g_assert (page != NULL);
241
242                         dirty =
243                             GPOINTER_TO_INT (gtk_object_get_data
244                                              (GTK_OBJECT (page->child),
245                                               GL_PROPERTY_BOX_DIRTY));
246
247                         if (dirty)
248                                 break;
249                 }
250         } else {
251                 page = NULL;
252                 dirty = FALSE;
253         }
254
255         /* Choose which style we did */
256         if (pbox->apply_button) {
257                 switch (button) {
258                 case 0:
259                         if (dirty)
260                                 apply_and_close (GL_PROPERTY_BOX (dialog));
261                         else
262                                 just_close (GL_PROPERTY_BOX (dialog));
263                         break;
264                 case 1:
265                         global_apply (GL_PROPERTY_BOX (dialog));
266                         break;
267                 case 2:
268                         just_close (GL_PROPERTY_BOX (dialog));
269                         break;
270                 default:
271                         g_assert_not_reached ();
272                 }
273         } else {
274                 switch (button) {
275                 case 0:
276                         if (dirty)
277                                 apply_and_close (GL_PROPERTY_BOX (dialog));
278                         else
279                                 just_close (GL_PROPERTY_BOX (dialog));
280                         break;
281                 case 1:
282                         just_close (GL_PROPERTY_BOX (dialog));
283                         break;
284                 default:
285                         g_assert_not_reached ();
286                 }
287         }
288 }
289
290 static void
291 set_sensitive (glPropertyBox * property_box,
292                gint dirty)
293 {
294         if (property_box->apply_button)
295                 gtk_widget_set_sensitive (property_box->apply_button, dirty);
296 }
297
298 /**
299  * gl_property_box_changed:
300  * @property_box: The glPropertyBox that contains the changed data
301  *
302  * When a setting has changed, the code needs to invoke this routine
303  * to make the Ok/Apply buttons sensitive.
304  */
305 void
306 gl_property_box_changed (glPropertyBox * property_box)
307 {
308         GtkWidget *page;
309
310         g_return_if_fail (property_box != NULL);
311         g_return_if_fail (GL_IS_PROPERTY_BOX (property_box));
312         g_return_if_fail (property_box->notebook);
313         g_return_if_fail (GTK_NOTEBOOK (property_box->notebook)->cur_page);
314
315         page = GTK_NOTEBOOK (property_box->notebook)->cur_page->child;
316         g_assert (page != NULL);
317
318         gtk_object_set_data (GTK_OBJECT (page),
319                              GL_PROPERTY_BOX_DIRTY, GINT_TO_POINTER (1));
320
321         set_sensitive (property_box, 1);
322 }
323
324 /**
325  * gl_property_box_set_modified:
326  * @property_box: The glPropertyBox that contains the changed data
327  * @state:        The state.  TRUE means modified, FALSE means unmodified.
328  *
329  * This sets the modified flag of the glPropertyBox to the value in @state.
330  * Affects whether the OK/Apply buttons are sensitive.
331  */
332 void
333 gl_property_box_set_modified (glPropertyBox * property_box,
334                               gboolean state)
335 {
336         GtkWidget *page;
337
338         g_return_if_fail (property_box != NULL);
339         g_return_if_fail (GL_IS_PROPERTY_BOX (property_box));
340         g_return_if_fail (property_box->notebook);
341         g_return_if_fail (GTK_NOTEBOOK (property_box->notebook)->cur_page);
342
343         page = GTK_NOTEBOOK (property_box->notebook)->cur_page->child;
344         g_assert (page != NULL);
345
346         gtk_object_set_data (GTK_OBJECT (page),
347                              GL_PROPERTY_BOX_DIRTY,
348                              GINT_TO_POINTER (state ? 1 : 0));
349
350         set_sensitive (property_box, state);
351 }
352
353 static void
354 global_apply (glPropertyBox * property_box)
355 {
356         GList *list;
357         gint n;
358
359         g_return_if_fail (GTK_NOTEBOOK (property_box->notebook)->children !=
360                           NULL);
361
362         for (list = GTK_NOTEBOOK (property_box->notebook)->children, n = 0;
363              list != NULL; list = g_list_next (list), n++) {
364                 /* FIXME: there should be a way to report an error
365                    during Apply.  That way we could prevent closing
366                    the window if there were a problem.  */
367                 GtkNotebookPage *page = list->data;
368                 if (gtk_object_get_data (GTK_OBJECT (page->child),
369                                          GL_PROPERTY_BOX_DIRTY)) {
370                         gtk_signal_emit (GTK_OBJECT (property_box),
371                                          property_box_signals[APPLY], n);
372                         gtk_object_set_data (GTK_OBJECT (page->child),
373                                              GL_PROPERTY_BOX_DIRTY,
374                                              GINT_TO_POINTER (0));
375                 }
376         }
377
378         /* Emit an apply signal with a button of -1.  This means we
379            just finished a global apply.  Is this a hack?  */
380         gtk_signal_emit (GTK_OBJECT (property_box),
381                          property_box_signals[APPLY], (gint) - 1);
382
383         /* Doesn't matter which item we use. */
384         set_sensitive (property_box, 0);
385 }
386
387 static void
388 just_close (glPropertyBox * property_box)
389 {
390         gnome_dialog_close (GNOME_DIALOG (property_box));
391 }
392
393 static void
394 apply_and_close (glPropertyBox * property_box)
395 {
396         global_apply (property_box);
397         just_close (property_box);
398 }
399
400 /**
401  * gl_property_box_append_page:
402  * @property_box: The property box where we are inserting a new page
403  * @child:        The widget that is being inserted
404  * @tab_label:    The widget used as the label for this confiugration page
405  *
406  * Appends a new page to the glPropertyBox.
407  *
408  * Returns the assigned index of the page inside the glPropertyBox or
409  * -1 if one of the arguments is invalid.
410  */
411 gint
412 gl_property_box_append_page (glPropertyBox * property_box,
413                              GtkWidget * child,
414                              GtkWidget * tab_label)
415 {
416         g_return_val_if_fail (property_box != NULL, -1);
417         g_return_val_if_fail (GL_IS_PROPERTY_BOX (property_box), -1);
418         g_return_val_if_fail (child != NULL, -1);
419         g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
420         g_return_val_if_fail (tab_label != NULL, -1);
421         g_return_val_if_fail (GTK_IS_WIDGET (tab_label), -1);
422
423         gtk_notebook_append_page (GTK_NOTEBOOK (property_box->notebook),
424                                   child, tab_label);
425
426         return g_list_length (GTK_NOTEBOOK (property_box->notebook)->children) -
427             1;
428 }