]> git.sur5r.net Git - glabels/blob - glabels2/src/wdgt-size.c
Initial revision
[glabels] / glabels2 / src / wdgt-size.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  wdgt_size.c:  size properties widget module
5  *
6  *  Copyright (C) 2001-2002  Jim Evins <evins@snaught.com>.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21  */
22
23 #include <config.h>
24
25 #include "wdgt-size.h"
26 #include "prefs.h"
27 #include "marshal.h"
28
29 #include "debug.h"
30
31 /*===========================================*/
32 /* Private types                             */
33 /*===========================================*/
34
35 enum {
36         CHANGED,
37         LAST_SIGNAL
38 };
39
40 typedef void (*glWdgtSizeSignal) (GObject * object, gpointer data);
41
42 /*===========================================*/
43 /* Private globals                           */
44 /*===========================================*/
45
46 static GObjectClass *parent_class;
47
48 static gint wdgt_size_signals[LAST_SIGNAL] = { 0 };
49
50 /*===========================================*/
51 /* Local function prototypes                 */
52 /*===========================================*/
53
54 static void gl_wdgt_size_class_init (glWdgtSizeClass * class);
55 static void gl_wdgt_size_instance_init (glWdgtSize * size);
56 static void gl_wdgt_size_finalize (GObject * object);
57 static void gl_wdgt_size_construct (glWdgtSize * size, gchar * label);
58
59 static void aspect_toggle_cb (GtkToggleButton * togglebutton,
60                               gpointer user_data);
61 static void w_spin_cb (GtkSpinButton * spinbutton, gpointer user_data);
62 static void h_spin_cb (GtkSpinButton * spinbutton, gpointer user_data);
63 \f
64 /*================================================================*/
65 /* Boilerplate Object stuff.                                      */
66 /*================================================================*/
67 guint
68 gl_wdgt_size_get_type (void)
69 {
70         static guint wdgt_size_type = 0;
71
72         if (!wdgt_size_type) {
73                 GTypeInfo wdgt_size_info = {
74                         sizeof (glWdgtSizeClass),
75                         NULL,
76                         NULL,
77                         (GClassInitFunc) gl_wdgt_size_class_init,
78                         NULL,
79                         NULL,
80                         sizeof (glWdgtSize),
81                         0,
82                         (GInstanceInitFunc) gl_wdgt_size_instance_init,
83                 };
84
85                 wdgt_size_type =
86                     g_type_register_static (gtk_vbox_get_type (),
87                                             "glWdgtSize", &wdgt_size_info, 0);
88         }
89
90         return wdgt_size_type;
91 }
92
93 static void
94 gl_wdgt_size_class_init (glWdgtSizeClass * class)
95 {
96         GObjectClass *object_class;
97
98         object_class = (GObjectClass *) class;
99
100         parent_class = gtk_type_class (gtk_vbox_get_type ());
101
102         object_class->finalize = gl_wdgt_size_finalize;
103
104         wdgt_size_signals[CHANGED] =
105             g_signal_new ("changed",
106                           G_OBJECT_CLASS_TYPE(object_class),
107                           G_SIGNAL_RUN_LAST,
108                           G_STRUCT_OFFSET (glWdgtSizeClass, changed),
109                           NULL, NULL,
110                           gl_marshal_VOID__VOID,
111                           G_TYPE_NONE, 0);
112
113 }
114
115 static void
116 gl_wdgt_size_instance_init (glWdgtSize * size)
117 {
118         size->aspect_ratio = 1.0;
119
120         size->w_spin = NULL;
121         size->h_spin = NULL;
122
123         size->units_label = NULL;
124
125         size->aspect_checkbox = NULL;
126 }
127
128 static void
129 gl_wdgt_size_finalize (GObject * object)
130 {
131         glWdgtSize *size;
132         glWdgtSizeClass *class;
133
134         g_return_if_fail (object != NULL);
135         g_return_if_fail (GL_IS_WDGT_SIZE (object));
136
137         size = GL_WDGT_SIZE (object);
138
139         G_OBJECT_CLASS (parent_class)->finalize (object);
140 }
141
142 GtkWidget *
143 gl_wdgt_size_new (gchar * label)
144 {
145         glWdgtSize *size;
146
147         size = g_object_new (gl_wdgt_size_get_type (), NULL);
148
149         gl_wdgt_size_construct (size, label);
150
151         return GTK_WIDGET (size);
152 }
153 \f
154 /*============================================================*/
155 /* Construct composite widget.                                */
156 /*============================================================*/
157 static void
158 gl_wdgt_size_construct (glWdgtSize * size,
159                         gchar * label)
160 {
161         GtkWidget *wvbox, *wframe, *wtable, *wlabel;
162         GtkObject *w_adjust, *h_adjust;
163         const gchar *units_string;
164         gdouble units_per_point, climb_rate;
165         gint digits;
166
167         units_string = gl_prefs_get_units_string ();
168         units_per_point = gl_prefs_get_units_per_point ();
169         climb_rate = gl_prefs_get_units_step_size ();
170         digits = gl_prefs_get_units_precision ();
171
172         wvbox = GTK_WIDGET (size);
173
174         wframe = gtk_frame_new (label);
175         gtk_box_pack_start (GTK_BOX (wvbox), wframe, FALSE, FALSE, 0);
176
177         wtable = gtk_table_new (3, 3, TRUE);
178         gtk_container_set_border_width (GTK_CONTAINER (wtable), 10);
179         gtk_table_set_row_spacings (GTK_TABLE (wtable), 5);
180         gtk_table_set_col_spacings (GTK_TABLE (wtable), 5);
181         gtk_container_add (GTK_CONTAINER (wframe), wtable);
182
183         /* W Label */
184         wlabel = gtk_label_new (_("Width:"));
185         gtk_misc_set_alignment (GTK_MISC (wlabel), 0, 0.5);
186         gtk_label_set_justify (GTK_LABEL (wlabel), GTK_JUSTIFY_RIGHT);
187         gtk_table_attach_defaults (GTK_TABLE (wtable), wlabel, 0, 1, 0, 1);
188         /* W spin */
189         w_adjust = gtk_adjustment_new (climb_rate, climb_rate, 100.0,
190                                        climb_rate, 10.0, 10.0);
191         size->w_spin = gtk_spin_button_new (GTK_ADJUSTMENT (w_adjust),
192                                             climb_rate, digits);
193         gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON (size->w_spin),
194                                            TRUE);
195         gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (size->w_spin), TRUE);
196         gtk_table_attach_defaults (GTK_TABLE (wtable), size->w_spin,
197                                    1, 2, 0, 1);
198
199         /* H label */
200         wlabel = gtk_label_new (_("Height:"));
201         gtk_misc_set_alignment (GTK_MISC (wlabel), 0, 0.5);
202         gtk_label_set_justify (GTK_LABEL (wlabel), GTK_JUSTIFY_RIGHT);
203         gtk_table_attach_defaults (GTK_TABLE (wtable), wlabel, 0, 1, 1, 2);
204         /* H spin */
205         h_adjust = gtk_adjustment_new (climb_rate, climb_rate,
206                                        100.0, climb_rate, 10.0, 10.0);
207         size->h_spin = gtk_spin_button_new (GTK_ADJUSTMENT (h_adjust),
208                                             climb_rate, digits);
209         gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON (size->h_spin),
210                                            TRUE);
211         gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (size->h_spin), TRUE);
212         gtk_table_attach_defaults (GTK_TABLE (wtable), size->h_spin,
213                                    1, 2, 1, 2);
214
215         /* Units */
216         size->units_label = gtk_label_new (units_string);
217         gtk_misc_set_alignment (GTK_MISC (size->units_label), 0, 0.5);
218         gtk_table_attach_defaults (GTK_TABLE (wtable),
219                                    size->units_label, 2, 3, 1, 2);
220
221         /* Maintain aspect ratio checkbox */
222         size->aspect_checkbox =
223             gtk_check_button_new_with_label (_
224                                              ("Maintain current aspect ratio"));
225         gtk_table_attach_defaults (GTK_TABLE (wtable), size->aspect_checkbox, 0,
226                                    3, 2, 3);
227
228         /* Connect signals to controls */
229         g_signal_connect (G_OBJECT (size->aspect_checkbox), "toggled",
230                           G_CALLBACK (aspect_toggle_cb), size);
231         g_signal_connect (G_OBJECT (size->w_spin), "changed",
232                           G_CALLBACK (w_spin_cb), size);
233         g_signal_connect (G_OBJECT (size->h_spin), "changed",
234                           G_CALLBACK (h_spin_cb), size);
235 }
236 \f
237 /*--------------------------------------------------------------------------*/
238 /* PRIVATE.  Maintain aspect ratio checkbox callback.                       */
239 /*--------------------------------------------------------------------------*/
240 static void
241 aspect_toggle_cb (GtkToggleButton * togglebutton,
242                   gpointer user_data)
243 {
244         glWdgtSize *size = GL_WDGT_SIZE (user_data);
245         GtkAdjustment *w_adjust, *h_adjust;
246
247         if (gtk_toggle_button_get_active (togglebutton)) {
248
249                 size->w =
250                     gtk_spin_button_get_value (GTK_SPIN_BUTTON(size->w_spin));
251                 size->h =
252                     gtk_spin_button_get_value (GTK_SPIN_BUTTON(size->h_spin));
253
254                 size->aspect_ratio = size->h / size->w;
255
256                 /* We have a new aspect ratio, adjust one of the maxes accordingly */
257                 if ((size->h_max_orig / size->w_max_orig) < size->aspect_ratio) {
258                         size->w_max = size->h_max_orig / size->aspect_ratio;
259                         size->h_max = size->h_max_orig;
260                 } else {
261                         size->w_max = size->w_max_orig;
262                         size->h_max = size->w_max_orig * size->aspect_ratio;
263                 }
264
265         } else {
266
267                 /* Reset maximums */
268                 size->w_max = size->w_max_orig;
269                 size->h_max = size->h_max_orig;
270
271         }
272
273         g_signal_handlers_block_by_func (GTK_OBJECT (size->w_spin),
274                                           G_CALLBACK (w_spin_cb),
275                                           user_data);
276         g_signal_handlers_block_by_func (GTK_OBJECT (size->h_spin),
277                                           G_CALLBACK (h_spin_cb),
278                                           user_data);
279         w_adjust =
280             gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (size->w_spin));
281         w_adjust->upper = size->w_max;
282         gtk_spin_button_update (GTK_SPIN_BUTTON (size->w_spin));
283         h_adjust =
284             gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (size->h_spin));
285         h_adjust->upper = size->h_max;
286         gtk_spin_button_update (GTK_SPIN_BUTTON (size->h_spin));
287         g_signal_handlers_unblock_by_func (GTK_OBJECT (size->w_spin),
288                                             G_CALLBACK (w_spin_cb),
289                                             user_data);
290         g_signal_handlers_unblock_by_func (GTK_OBJECT (size->h_spin),
291                                             G_CALLBACK (h_spin_cb),
292                                             user_data);
293
294         /* Emit our "changed" signal */
295         g_signal_emit (G_OBJECT (size), wdgt_size_signals[CHANGED], 0);
296
297 }
298 \f
299 /*--------------------------------------------------------------------------*/
300 /* PRIVATE.  W spin button changed callback.                                */
301 /*--------------------------------------------------------------------------*/
302 static void
303 w_spin_cb (GtkSpinButton * spinbutton,
304            gpointer user_data)
305 {
306         glWdgtSize *size = GL_WDGT_SIZE (user_data);
307         GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (size->aspect_checkbox);
308
309         size->w =
310             gtk_spin_button_get_value (GTK_SPIN_BUTTON (size->w_spin));
311
312         if (gtk_toggle_button_get_active (toggle)) {
313
314                 size->h = size->w * size->aspect_ratio;
315
316                 /* Update our sibling control, blocking recursion. */
317                 g_signal_handlers_block_by_func (GTK_OBJECT (size->h_spin),
318                                                   G_CALLBACK (h_spin_cb),
319                                                   user_data);
320                 gtk_spin_button_set_value (GTK_SPIN_BUTTON (size->h_spin),
321                                            size->h);
322                 g_signal_handlers_unblock_by_func (GTK_OBJECT (size->h_spin),
323                                                     G_CALLBACK (h_spin_cb),
324                                                     user_data);
325         }
326
327         /* Emit our "changed" signal */
328         g_signal_emit (G_OBJECT (size), wdgt_size_signals[CHANGED], 0);
329
330 }
331
332 /*--------------------------------------------------------------------------*/
333 /* PRIVATE.  H spin button changed callback.                                */
334 /*--------------------------------------------------------------------------*/
335 static void
336 h_spin_cb (GtkSpinButton * spinbutton,
337            gpointer user_data)
338 {
339         glWdgtSize *size = GL_WDGT_SIZE (user_data);
340         GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (size->aspect_checkbox);
341
342         size->h =
343             gtk_spin_button_get_value (GTK_SPIN_BUTTON (size->h_spin));
344
345         if (gtk_toggle_button_get_active (toggle)) {
346
347                 size->w = size->h / size->aspect_ratio;
348
349                 /* Update our sibling control, blocking recursion. */
350                 g_signal_handlers_block_by_func (GTK_OBJECT (size->w_spin),
351                                                   G_CALLBACK (w_spin_cb),
352                                                   user_data);
353                 gtk_spin_button_set_value (GTK_SPIN_BUTTON (size->w_spin),
354                                            size->w);
355                 g_signal_handlers_unblock_by_func (GTK_OBJECT (size->w_spin),
356                                                     G_CALLBACK (w_spin_cb),
357                                                     user_data);
358         }
359
360         /* Emit our "changed" signal */
361         g_signal_emit (G_OBJECT (size), wdgt_size_signals[CHANGED], 0);
362
363 }
364 \f
365 /*====================================================================*/
366 /* query values from controls.                                        */
367 /*====================================================================*/
368 void
369 gl_wdgt_size_get_size (glWdgtSize * size,
370                        gdouble * w,
371                        gdouble * h,
372                        gboolean * keep_aspect_ratio_flag)
373 {
374         gdouble units_per_point;
375
376         units_per_point = gl_prefs_get_units_per_point ();
377
378         *w = gtk_spin_button_get_value (GTK_SPIN_BUTTON(size->w_spin));
379         *h = gtk_spin_button_get_value (GTK_SPIN_BUTTON(size->h_spin));
380
381         *keep_aspect_ratio_flag =
382             gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
383                                           (size->aspect_checkbox));
384
385         /* convert everything back to our internal units (points) */
386         *w /= units_per_point;
387         *h /= units_per_point;
388 }
389
390 /*====================================================================*/
391 /* set values and ranges for controls.                                */
392 /*====================================================================*/
393 void
394 gl_wdgt_size_set_params (glWdgtSize * size,
395                          gdouble w,
396                          gdouble h,
397                          gboolean keep_aspect_ratio_flag,
398                          gdouble w_max,
399                          gdouble h_max)
400 {
401         GtkObject *w_adjust, *h_adjust;
402         const gchar *units_string;
403         gdouble units_per_point, climb_rate;
404         gint digits;
405
406         units_string = gl_prefs_get_units_string ();
407         units_per_point = gl_prefs_get_units_per_point ();
408         climb_rate = gl_prefs_get_units_step_size ();
409         digits = gl_prefs_get_units_precision ();
410
411         /* Put everything into our display units */
412         size->w = w * units_per_point;
413         size->h = h * units_per_point;
414         size->w_max = w_max * units_per_point;
415         size->h_max = h_max * units_per_point;
416
417         /* Squirrel away copies of our original maximums */
418         size->w_max_orig = size->w_max;
419         size->h_max_orig = size->h_max;
420
421         size->aspect_ratio = size->h / size->w;
422         if (keep_aspect_ratio_flag) {
423
424                 /* When tracking aspect ratio, adjust one of the maxes */
425                 if ((size->h_max / size->w_max) < size->aspect_ratio) {
426                         size->w_max = size->h_max / size->aspect_ratio;
427                 } else {
428                         size->h_max = size->w_max * size->aspect_ratio;
429                 }
430
431                 /* before adjusting w & h, limit to max values */
432                 if (size->w > size->w_max)
433                         size->w = size->w_max;
434                 if (size->h > size->h_max)
435                         size->h = size->h_max;
436
437         }
438
439         /* update W/H spin controls */
440         w_adjust = gtk_adjustment_new (size->w, climb_rate, size->w_max,
441                                        climb_rate, 10.0, 10.0);
442         gtk_spin_button_configure (GTK_SPIN_BUTTON (size->w_spin),
443                                    GTK_ADJUSTMENT (w_adjust), climb_rate,
444                                    digits);
445         h_adjust =
446             gtk_adjustment_new (size->h, climb_rate, size->h_max, climb_rate,
447                                 10.0, 10.0);
448         gtk_spin_button_configure (GTK_SPIN_BUTTON (size->h_spin),
449                                    GTK_ADJUSTMENT (h_adjust), climb_rate,
450                                    digits);
451
452         gtk_label_set_text (GTK_LABEL (size->units_label), units_string);
453
454         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (size->aspect_checkbox),
455                                       keep_aspect_ratio_flag);
456
457 }
458
459 /*====================================================================*/
460 /* set size only.                                                     */
461 /*====================================================================*/
462 void
463 gl_wdgt_size_set_size (glWdgtSize * size,
464                        gdouble w,
465                        gdouble h)
466 {
467         gdouble units_per_point;
468
469         units_per_point = gl_prefs_get_units_per_point ();
470
471         /* Put everything into our display units */
472         size->w = w * units_per_point;
473         size->h = h * units_per_point;
474
475         /* update aspect ratio */
476         size->aspect_ratio = size->h / size->w;
477
478         /* update W/H spin controls */
479         g_signal_handlers_block_by_func (GTK_OBJECT (size->w_spin),
480                                          G_CALLBACK (w_spin_cb),
481                                          size);
482         g_signal_handlers_block_by_func (GTK_OBJECT (size->h_spin),
483                                          G_CALLBACK (h_spin_cb),
484                                          size);
485         gtk_spin_button_set_value (GTK_SPIN_BUTTON (size->w_spin), size->w);
486         gtk_spin_button_set_value (GTK_SPIN_BUTTON (size->h_spin), size->h);
487         g_signal_handlers_unblock_by_func (GTK_OBJECT (size->w_spin),
488                                            G_CALLBACK (w_spin_cb),
489                                            size);
490         g_signal_handlers_unblock_by_func (GTK_OBJECT (size->h_spin),
491                                            G_CALLBACK (h_spin_cb),
492                                            size);
493 }