]> git.sur5r.net Git - glabels/blob - glabels1/src/prop_size.c
Initial revision
[glabels] / glabels1 / src / prop_size.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  prop_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 "prop_size.h"
26 #include "prefs.h"
27
28 #include "debug.h"
29
30 /*===========================================*/
31 /* Private types                             */
32 /*===========================================*/
33
34 enum {
35         CHANGED,
36         LAST_SIGNAL
37 };
38
39 typedef void (*glPropSizeSignal) (GtkObject * object, gpointer data);
40
41 /*===========================================*/
42 /* Private globals                           */
43 /*===========================================*/
44
45 static GtkContainerClass *parent_class;
46
47 static gint prop_size_signals[LAST_SIGNAL] = { 0 };
48
49 /*===========================================*/
50 /* Local function prototypes                 */
51 /*===========================================*/
52
53 static void gl_prop_size_class_init (glPropSizeClass * class);
54 static void gl_prop_size_init (glPropSize * size);
55 static void gl_prop_size_destroy (GtkObject * object);
56 static void gl_prop_size_construct (glPropSize * size, gchar * label);
57
58 static void aspect_toggle_cb (GtkToggleButton * togglebutton,
59                               gpointer user_data);
60 static void w_spin_cb (GtkSpinButton * spinbutton, gpointer user_data);
61 static void h_spin_cb (GtkSpinButton * spinbutton, gpointer user_data);
62 \f
63 /*================================================================*/
64 /* Boilerplate Object stuff.                                      */
65 /*================================================================*/
66 guint
67 gl_prop_size_get_type (void)
68 {
69         static guint prop_size_type = 0;
70
71         if (!prop_size_type) {
72                 GtkTypeInfo prop_size_info = {
73                         "glPropSize",
74                         sizeof (glPropSize),
75                         sizeof (glPropSizeClass),
76                         (GtkClassInitFunc) gl_prop_size_class_init,
77                         (GtkObjectInitFunc) gl_prop_size_init,
78                         (GtkArgSetFunc) NULL,
79                         (GtkArgGetFunc) NULL,
80                 };
81
82                 prop_size_type =
83                     gtk_type_unique (gtk_vbox_get_type (), &prop_size_info);
84         }
85
86         return prop_size_type;
87 }
88
89 static void
90 gl_prop_size_class_init (glPropSizeClass * class)
91 {
92         GtkObjectClass *object_class;
93         GtkWidgetClass *widget_class;
94
95         object_class = (GtkObjectClass *) class;
96         widget_class = (GtkWidgetClass *) class;
97
98         parent_class = gtk_type_class (gtk_vbox_get_type ());
99
100         object_class->destroy = gl_prop_size_destroy;
101
102         prop_size_signals[CHANGED] =
103             gtk_signal_new ("changed", GTK_RUN_LAST, object_class->type,
104                             GTK_SIGNAL_OFFSET (glPropSizeClass, changed),
105                             gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
106         gtk_object_class_add_signals (object_class, prop_size_signals,
107                                       LAST_SIGNAL);
108
109         class->changed = NULL;
110 }
111
112 static void
113 gl_prop_size_init (glPropSize * size)
114 {
115         size->aspect_ratio = 1.0;
116
117         size->w_spin = NULL;
118         size->h_spin = NULL;
119
120         size->units_label = NULL;
121
122         size->aspect_checkbox = NULL;
123 }
124
125 static void
126 gl_prop_size_destroy (GtkObject * object)
127 {
128         glPropSize *size;
129         glPropSizeClass *class;
130
131         g_return_if_fail (object != NULL);
132         g_return_if_fail (GL_IS_PROP_SIZE (object));
133
134         size = GL_PROP_SIZE (object);
135         class = GL_PROP_SIZE_CLASS (GTK_OBJECT (size)->klass);
136
137         GTK_OBJECT_CLASS (parent_class)->destroy (object);
138 }
139
140 GtkWidget *
141 gl_prop_size_new (gchar * label)
142 {
143         glPropSize *size;
144
145         size = gtk_type_new (gl_prop_size_get_type ());
146
147         gl_prop_size_construct (size, label);
148
149         return GTK_WIDGET (size);
150 }
151 \f
152 /*============================================================*/
153 /* Construct composite widget.                                */
154 /*============================================================*/
155 static void
156 gl_prop_size_construct (glPropSize * size,
157                         gchar * label)
158 {
159         GtkWidget *wvbox, *wframe, *wtable, *wlabel;
160         GtkObject *w_adjust, *h_adjust;
161         const gchar *units_string;
162         gdouble units_per_point, climb_rate;
163         gint digits;
164
165         units_string = gl_prefs_get_units_string ();
166         units_per_point = gl_prefs_get_units_per_point ();
167         climb_rate = gl_prefs_get_units_step_size ();
168         digits = gl_prefs_get_units_precision ();
169
170         wvbox = GTK_WIDGET (size);
171
172         wframe = gtk_frame_new (label);
173         gtk_box_pack_start (GTK_BOX (wvbox), wframe, FALSE, FALSE, 0);
174
175         wtable = gtk_table_new (3, 3, TRUE);
176         gtk_container_set_border_width (GTK_CONTAINER (wtable), 10);
177         gtk_table_set_row_spacings (GTK_TABLE (wtable), 5);
178         gtk_table_set_col_spacings (GTK_TABLE (wtable), 5);
179         gtk_container_add (GTK_CONTAINER (wframe), wtable);
180
181         /* W Label */
182         wlabel = gtk_label_new (_("Width:"));
183         gtk_misc_set_alignment (GTK_MISC (wlabel), 0, 0.5);
184         gtk_label_set_justify (GTK_LABEL (wlabel), GTK_JUSTIFY_RIGHT);
185         gtk_table_attach_defaults (GTK_TABLE (wtable), wlabel, 0, 1, 0, 1);
186         /* W spin */
187         w_adjust = gtk_adjustment_new (climb_rate, climb_rate, 100.0,
188                                        climb_rate, 10.0, 10.0);
189         size->w_spin = gtk_spin_button_new (GTK_ADJUSTMENT (w_adjust),
190                                             climb_rate, digits);
191         gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON (size->w_spin),
192                                            TRUE);
193         gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (size->w_spin), TRUE);
194         gtk_table_attach_defaults (GTK_TABLE (wtable), size->w_spin,
195                                    1, 2, 0, 1);
196
197         /* H label */
198         wlabel = gtk_label_new (_("Height:"));
199         gtk_misc_set_alignment (GTK_MISC (wlabel), 0, 0.5);
200         gtk_label_set_justify (GTK_LABEL (wlabel), GTK_JUSTIFY_RIGHT);
201         gtk_table_attach_defaults (GTK_TABLE (wtable), wlabel, 0, 1, 1, 2);
202         /* H spin */
203         h_adjust = gtk_adjustment_new (climb_rate, climb_rate,
204                                        100.0, climb_rate, 10.0, 10.0);
205         size->h_spin = gtk_spin_button_new (GTK_ADJUSTMENT (h_adjust),
206                                             climb_rate, digits);
207         gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON (size->h_spin),
208                                            TRUE);
209         gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (size->h_spin), TRUE);
210         gtk_table_attach_defaults (GTK_TABLE (wtable), size->h_spin,
211                                    1, 2, 1, 2);
212
213         /* Units */
214         size->units_label = gtk_label_new (units_string);
215         gtk_misc_set_alignment (GTK_MISC (size->units_label), 0, 0.5);
216         gtk_table_attach_defaults (GTK_TABLE (wtable),
217                                    size->units_label, 2, 3, 1, 2);
218
219         /* Maintain aspect ratio checkbox */
220         size->aspect_checkbox =
221             gtk_check_button_new_with_label (_
222                                              ("Maintain current aspect ratio"));
223         gtk_table_attach_defaults (GTK_TABLE (wtable), size->aspect_checkbox, 0,
224                                    3, 2, 3);
225
226         /* Connect signals to controls */
227         gtk_signal_connect (GTK_OBJECT (size->aspect_checkbox), "toggled",
228                             GTK_SIGNAL_FUNC (aspect_toggle_cb), size);
229         gtk_signal_connect (GTK_OBJECT (size->w_spin), "changed",
230                             GTK_SIGNAL_FUNC (w_spin_cb), size);
231         gtk_signal_connect (GTK_OBJECT (size->h_spin), "changed",
232                             GTK_SIGNAL_FUNC (h_spin_cb), size);
233 }
234 \f
235 /*--------------------------------------------------------------------------*/
236 /* PRIVATE.  Maintain aspect ratio checkbox callback.                       */
237 /*--------------------------------------------------------------------------*/
238 static void
239 aspect_toggle_cb (GtkToggleButton * togglebutton,
240                   gpointer user_data)
241 {
242         glPropSize *size = GL_PROP_SIZE (user_data);
243         GtkAdjustment *w_adjust, *h_adjust;
244
245         if (gtk_toggle_button_get_active (togglebutton)) {
246
247                 size->w =
248                     gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON
249                                                         (size->w_spin));
250                 size->h =
251                     gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON
252                                                         (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         gtk_signal_handler_block_by_func (GTK_OBJECT (size->w_spin),
274                                           GTK_SIGNAL_FUNC (w_spin_cb),
275                                           user_data);
276         gtk_signal_handler_block_by_func (GTK_OBJECT (size->h_spin),
277                                           GTK_SIGNAL_FUNC (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         gtk_signal_handler_unblock_by_func (GTK_OBJECT (size->w_spin),
288                                             GTK_SIGNAL_FUNC (w_spin_cb),
289                                             user_data);
290         gtk_signal_handler_unblock_by_func (GTK_OBJECT (size->h_spin),
291                                             GTK_SIGNAL_FUNC (h_spin_cb),
292                                             user_data);
293
294         /* Emit our "changed" signal */
295         gtk_signal_emit (GTK_OBJECT (size), prop_size_signals[CHANGED]);
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         glPropSize *size = GL_PROP_SIZE (user_data);
307         GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (size->aspect_checkbox);
308
309         size->w =
310             gtk_spin_button_get_value_as_float (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                 gtk_signal_handler_block_by_func (GTK_OBJECT (size->h_spin),
318                                                   GTK_SIGNAL_FUNC (h_spin_cb),
319                                                   user_data);
320                 gtk_spin_button_set_value (GTK_SPIN_BUTTON (size->h_spin),
321                                            size->h);
322                 gtk_signal_handler_unblock_by_func (GTK_OBJECT (size->h_spin),
323                                                     GTK_SIGNAL_FUNC (h_spin_cb),
324                                                     user_data);
325         }
326
327         /* Emit our "changed" signal */
328         gtk_signal_emit (GTK_OBJECT (size), prop_size_signals[CHANGED]);
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         glPropSize *size = GL_PROP_SIZE (user_data);
340         GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (size->aspect_checkbox);
341
342         size->h =
343             gtk_spin_button_get_value_as_float (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                 gtk_signal_handler_block_by_func (GTK_OBJECT (size->w_spin),
351                                                   GTK_SIGNAL_FUNC (w_spin_cb),
352                                                   user_data);
353                 gtk_spin_button_set_value (GTK_SPIN_BUTTON (size->w_spin),
354                                            size->w);
355                 gtk_signal_handler_unblock_by_func (GTK_OBJECT (size->w_spin),
356                                                     GTK_SIGNAL_FUNC (w_spin_cb),
357                                                     user_data);
358         }
359
360         /* Emit our "changed" signal */
361         gtk_signal_emit (GTK_OBJECT (size), prop_size_signals[CHANGED]);
362
363 }
364 \f
365 /*====================================================================*/
366 /* query values from controls.                                        */
367 /*====================================================================*/
368 void
369 gl_prop_size_get_size (glPropSize * 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_as_float (GTK_SPIN_BUTTON
379                                                  (size->w_spin));
380         *h = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON
381                                                  (size->h_spin));
382
383         *keep_aspect_ratio_flag =
384             gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
385                                           (size->aspect_checkbox));
386
387         /* convert everything back to our internal units (points) */
388         *w /= units_per_point;
389         *h /= units_per_point;
390 }
391
392 /*====================================================================*/
393 /* set values and ranges for controls.                                */
394 /*====================================================================*/
395 void
396 gl_prop_size_set_params (glPropSize * size,
397                          gdouble w,
398                          gdouble h,
399                          gboolean keep_aspect_ratio_flag,
400                          gdouble w_max,
401                          gdouble h_max)
402 {
403         GtkObject *w_adjust, *h_adjust;
404         const gchar *units_string;
405         gdouble units_per_point, climb_rate;
406         gint digits;
407
408         units_string = gl_prefs_get_units_string ();
409         units_per_point = gl_prefs_get_units_per_point ();
410         climb_rate = gl_prefs_get_units_step_size ();
411         digits = gl_prefs_get_units_precision ();
412
413         /* Put everything into our display units */
414         size->w = w * units_per_point;
415         size->h = h * units_per_point;
416         size->w_max = w_max * units_per_point;
417         size->h_max = h_max * units_per_point;
418
419         /* Squirrel away copies of our original maximums */
420         size->w_max_orig = size->w_max;
421         size->h_max_orig = size->h_max;
422
423         size->aspect_ratio = size->h / size->w;
424         if (keep_aspect_ratio_flag) {
425
426                 /* When tracking aspect ratio, adjust one of the maxes */
427                 if ((size->h_max / size->w_max) < size->aspect_ratio) {
428                         size->w_max = size->h_max / size->aspect_ratio;
429                 } else {
430                         size->h_max = size->w_max * size->aspect_ratio;
431                 }
432
433                 /* before adjusting w & h, limit to max values */
434                 if (size->w > size->w_max)
435                         size->w = size->w_max;
436                 if (size->h > size->h_max)
437                         size->h = size->h_max;
438
439         }
440
441         /* update W/H spin controls */
442         w_adjust = gtk_adjustment_new (size->w, climb_rate, size->w_max,
443                                        climb_rate, 10.0, 10.0);
444         gtk_spin_button_configure (GTK_SPIN_BUTTON (size->w_spin),
445                                    GTK_ADJUSTMENT (w_adjust), climb_rate,
446                                    digits);
447         h_adjust =
448             gtk_adjustment_new (size->h, climb_rate, size->h_max, climb_rate,
449                                 10.0, 10.0);
450         gtk_spin_button_configure (GTK_SPIN_BUTTON (size->h_spin),
451                                    GTK_ADJUSTMENT (h_adjust), climb_rate,
452                                    digits);
453
454         gtk_label_set_text (GTK_LABEL (size->units_label), units_string);
455
456         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (size->aspect_checkbox),
457                                       keep_aspect_ratio_flag);
458
459 }