1 /*
2  *  object-editor-size-page.c
3  *  Copyright (C) 2003-2009  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of gLabels.
6  *
7  *  gLabels is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  gLabels is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #include "object-editor.h"
24 
25 #include <glib/gi18n.h>
26 #include <gtk/gtk.h>
27 #include <math.h>
28 
29 #include "prefs.h"
30 #include "wdgt-chain-button.h"
31 #include "builder-util.h"
32 #include "units-util.h"
33 
34 #include "object-editor-private.h"
35 
36 #include "debug.h"
37 
38 
39 /*===========================================*/
40 /* Private macros                            */
41 /*===========================================*/
42 
43 
44 /*===========================================*/
45 /* Private data types                        */
46 /*===========================================*/
47 
48 
49 /*===========================================*/
50 /* Private globals                           */
51 /*===========================================*/
52 
53 
54 /*===========================================*/
55 /* Local function prototypes                 */
56 /*===========================================*/
57 
58 static void aspect_toggle_cb                    (glObjectEditor        *editor);
59 static void size_reset_cb                       (glObjectEditor        *editor);
60 static void w_spin_cb                           (glObjectEditor        *editor);
61 static void h_spin_cb                           (glObjectEditor        *editor);
62 
63 
64 /*--------------------------------------------------------------------------*/
65 /* PRIVATE.  Prepare size page.                                             */
66 /*--------------------------------------------------------------------------*/
67 void
gl_object_editor_prepare_size_page(glObjectEditor * editor)68 gl_object_editor_prepare_size_page (glObjectEditor       *editor)
69 {
70         lglUnits      units;
71 	const gchar  *units_string;
72 	gdouble       climb_rate;
73 	gint          digits;
74 
75 	gl_debug (DEBUG_EDITOR, "START");
76 
77 	/* Extract widgets from XML tree. */
78         gl_builder_util_get_widgets (editor->priv->builder,
79                                      "size_page_vbox",          &editor->priv->size_page_vbox,
80                                      "size_w_spin",             &editor->priv->size_w_spin,
81                                      "size_h_spin",             &editor->priv->size_h_spin,
82                                      "size_w_units_label",      &editor->priv->size_w_units_label,
83                                      "size_h_units_label",      &editor->priv->size_h_units_label,
84                                      "size_aspect_vbox",        &editor->priv->size_aspect_vbox,
85                                      "size_reset_image_button", &editor->priv->size_reset_image_button,
86                                      NULL);
87 
88 	editor->priv->size_aspect_checkbutton = gl_wdgt_chain_button_new (GL_WDGT_CHAIN_RIGHT);
89         gtk_widget_set_tooltip_text (editor->priv->size_aspect_checkbutton, _("Lock aspect ratio."));
90 	gl_wdgt_chain_button_set_active (GL_WDGT_CHAIN_BUTTON(editor->priv->size_aspect_checkbutton),
91                                          TRUE);
92         gtk_box_pack_start (GTK_BOX (editor->priv->size_aspect_vbox),
93                             editor->priv->size_aspect_checkbutton,
94                             TRUE, TRUE, 0);
95 
96 
97 	/* Get configuration information */
98         units = gl_prefs_model_get_units (gl_prefs);
99 	units_string = lgl_units_get_name (units);
100 	editor->priv->units_per_point = lgl_units_get_units_per_point (units);
101 	climb_rate = gl_units_util_get_step_size (units);
102 	digits = gl_units_util_get_precision (units);
103 
104 	/* Modify widgets based on configuration */
105 	gtk_spin_button_set_digits (GTK_SPIN_BUTTON(editor->priv->size_w_spin), digits);
106 	gtk_spin_button_set_increments (GTK_SPIN_BUTTON(editor->priv->size_w_spin),
107 					climb_rate, 10.0*climb_rate);
108 	gtk_label_set_text (GTK_LABEL(editor->priv->size_w_units_label), units_string);
109 	gtk_spin_button_set_digits (GTK_SPIN_BUTTON(editor->priv->size_h_spin), digits);
110 	gtk_spin_button_set_increments (GTK_SPIN_BUTTON(editor->priv->size_h_spin),
111 					climb_rate, 10.0*climb_rate);
112 	gtk_label_set_text (GTK_LABEL(editor->priv->size_h_units_label), units_string);
113 
114 
115 	/* Connect signals */
116 	g_signal_connect_swapped (G_OBJECT (editor->priv->size_aspect_checkbutton),
117 				  "toggled",
118 				  G_CALLBACK (aspect_toggle_cb),
119 				  G_OBJECT (editor));
120 	g_signal_connect_swapped (G_OBJECT (editor->priv->size_w_spin),
121 				  "value-changed",
122 				  G_CALLBACK (w_spin_cb),
123 				  G_OBJECT (editor));
124 	g_signal_connect_swapped (G_OBJECT (editor->priv->size_h_spin),
125 				  "value-changed",
126 				  G_CALLBACK (h_spin_cb),
127 				  G_OBJECT (editor));
128         g_signal_connect_swapped (G_OBJECT (editor->priv->size_reset_image_button),
129                                   "clicked",
130                                   G_CALLBACK (size_reset_cb),
131                                   G_OBJECT (editor));
132 
133 	gl_debug (DEBUG_EDITOR, "END");
134 }
135 
136 
137 /*--------------------------------------------------------------------------*/
138 /* PRIVATE.  Maintain aspect ratio checkbox callback.                       */
139 /*--------------------------------------------------------------------------*/
140 static void
aspect_toggle_cb(glObjectEditor * editor)141 aspect_toggle_cb (glObjectEditor *editor)
142 {
143         glWdgtChainButton *toggle;
144 	gdouble            w, h;
145 
146 	gl_debug (DEBUG_EDITOR, "START");
147 
148 	toggle = GL_WDGT_CHAIN_BUTTON (editor->priv->size_aspect_checkbutton);
149 
150         if (gl_wdgt_chain_button_get_active (toggle)) {
151 
152                 w = gtk_spin_button_get_value (GTK_SPIN_BUTTON(editor->priv->size_w_spin));
153                 h = gtk_spin_button_get_value (GTK_SPIN_BUTTON(editor->priv->size_h_spin));
154 
155                 editor->priv->size_aspect_ratio = h / w;
156 
157         }
158 
159 	gl_debug (DEBUG_EDITOR, "END");
160 }
161 
162 
163 /*--------------------------------------------------------------------------*/
164 /* PRIVATE.  W spin button changed callback.                                */
165 /*--------------------------------------------------------------------------*/
166 static void
w_spin_cb(glObjectEditor * editor)167 w_spin_cb (glObjectEditor *editor)
168 {
169 	gdouble            w, h;
170         glWdgtChainButton *toggle;
171 
172 	gl_debug (DEBUG_EDITOR, "START");
173 
174 	toggle = GL_WDGT_CHAIN_BUTTON (editor->priv->size_aspect_checkbutton);
175 
176         if (gl_wdgt_chain_button_get_active (toggle)) {
177 
178 		w = gtk_spin_button_get_value (GTK_SPIN_BUTTON (editor->priv->size_w_spin));
179 
180                 h = w * editor->priv->size_aspect_ratio;
181 
182                 /* Update our sibling control, blocking recursion. */
183                 g_signal_handlers_block_by_func (G_OBJECT (editor->priv->size_h_spin), h_spin_cb, editor);
184                 gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->priv->size_h_spin), h);
185                 g_signal_handlers_unblock_by_func (G_OBJECT (editor->priv->size_h_spin), h_spin_cb, editor);
186         }
187 
188         gl_object_editor_size_changed_cb (editor);
189 
190 	gl_debug (DEBUG_EDITOR, "END");
191 }
192 
193 
194 /*--------------------------------------------------------------------------*/
195 /* PRIVATE.  H spin button changed callback.                                */
196 /*--------------------------------------------------------------------------*/
197 static void
h_spin_cb(glObjectEditor * editor)198 h_spin_cb (glObjectEditor *editor)
199 {
200 	gdouble            w, h;
201         glWdgtChainButton *toggle;
202 
203 	gl_debug (DEBUG_EDITOR, "START");
204 
205         toggle = GL_WDGT_CHAIN_BUTTON (editor->priv->size_aspect_checkbutton);
206 
207         if (gl_wdgt_chain_button_get_active (toggle)) {
208 
209 		h = gtk_spin_button_get_value (GTK_SPIN_BUTTON (editor->priv->size_h_spin));
210 
211                 w = h / editor->priv->size_aspect_ratio;
212 
213                 /* Update our sibling control, blocking recursion. */
214                 g_signal_handlers_block_by_func (G_OBJECT (editor->priv->size_w_spin), w_spin_cb, editor);
215                 gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->priv->size_w_spin), w);
216                 g_signal_handlers_unblock_by_func (G_OBJECT (editor->priv->size_w_spin), w_spin_cb, editor);
217         }
218 
219         gl_object_editor_size_changed_cb (editor);
220 
221 	gl_debug (DEBUG_EDITOR, "END");
222 }
223 
224 
225 /*--------------------------------------------------------------------------*/
226 /* PRIVATE.  Reset image size callback.                                     */
227 /*--------------------------------------------------------------------------*/
228 static void
size_reset_cb(glObjectEditor * editor)229 size_reset_cb (glObjectEditor *editor)
230 {
231 	gdouble w_base, h_base;
232 	gdouble w_max, h_max, wh_max;
233 	gdouble aspect_ratio;
234 
235 	gl_debug (DEBUG_EDITOR, "START");
236 
237 
238         g_signal_handlers_block_by_func (G_OBJECT (editor->priv->size_w_spin), w_spin_cb, editor);
239         g_signal_handlers_block_by_func (G_OBJECT (editor->priv->size_h_spin), h_spin_cb, editor);
240 
241 
242 	w_base = editor->priv->w_base;
243 	h_base = editor->priv->h_base;
244 
245 	w_max = editor->priv->w_max;
246 	h_max = editor->priv->h_max;
247         wh_max = MAX( w_max, h_max );
248 
249 	if ( (w_base > wh_max) || (h_base > wh_max) ) {
250 
251 		aspect_ratio = h_base / w_base;
252 
253 		if ( aspect_ratio < 1.0 ) {
254 			w_base = wh_max;
255 			h_base = wh_max * aspect_ratio;
256 
257 		} else {
258 			w_base = wh_max / aspect_ratio;
259 			h_base = wh_max;
260 		}
261 	}
262 
263 	w_base *= editor->priv->units_per_point;
264 	h_base *= editor->priv->units_per_point;
265 
266 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->priv->size_w_spin),
267 				   w_base);
268 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->priv->size_h_spin),
269 				   h_base);
270 
271 
272         g_signal_handlers_unblock_by_func (G_OBJECT (editor->priv->size_w_spin), w_spin_cb, editor);
273         g_signal_handlers_unblock_by_func (G_OBJECT (editor->priv->size_h_spin), h_spin_cb, editor);
274 
275 
276         gl_object_editor_size_changed_cb (editor);
277 
278 	gl_debug (DEBUG_EDITOR, "END");
279 }
280 
281 
282 /*****************************************************************************/
283 /* Set size.                                                                 */
284 /*****************************************************************************/
285 void
gl_object_editor_set_size(glObjectEditor * editor,gdouble w,gdouble h)286 gl_object_editor_set_size (glObjectEditor      *editor,
287                            gdouble              w,
288                            gdouble              h)
289 {
290 	gl_debug (DEBUG_EDITOR, "START");
291 
292 
293         g_signal_handlers_block_by_func (G_OBJECT (editor->priv->size_w_spin), w_spin_cb, editor);
294         g_signal_handlers_block_by_func (G_OBJECT (editor->priv->size_h_spin), h_spin_cb, editor);
295 
296 
297 	/* save a copy in internal units */
298 	editor->priv->w = w;
299 	editor->priv->h = h;
300 
301 	/* convert internal units to displayed units */
302 	gl_debug (DEBUG_EDITOR, "internal w,h = %g, %g", w, h);
303 	w *= editor->priv->units_per_point;
304 	h *= editor->priv->units_per_point;
305 	gl_debug (DEBUG_EDITOR, "display w,h = %g, %g", w, h);
306 
307 	/* Set widget values */
308 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->priv->size_w_spin), w);
309 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->priv->size_h_spin), h);
310 
311 	/* Update aspect ratio */
312 	editor->priv->size_aspect_ratio = h / w;
313 
314 
315         g_signal_handlers_unblock_by_func (G_OBJECT (editor->priv->size_w_spin), w_spin_cb, editor);
316         g_signal_handlers_unblock_by_func (G_OBJECT (editor->priv->size_h_spin), h_spin_cb, editor);
317 
318 
319 	gl_debug (DEBUG_EDITOR, "END");
320 }
321 
322 
323 /*****************************************************************************/
324 /* Set maximum size.                                                         */
325 /*****************************************************************************/
326 void
gl_object_editor_set_max_size(glObjectEditor * editor,gdouble w_max,gdouble h_max)327 gl_object_editor_set_max_size (glObjectEditor      *editor,
328 			       gdouble              w_max,
329 			       gdouble              h_max)
330 {
331 	gdouble tmp;
332         gdouble wh_max;
333 
334 	gl_debug (DEBUG_EDITOR, "START");
335 
336 
337         g_signal_handlers_block_by_func (G_OBJECT (editor->priv->size_w_spin), w_spin_cb, editor);
338         g_signal_handlers_block_by_func (G_OBJECT (editor->priv->size_h_spin), h_spin_cb, editor);
339 
340 
341         /* save a copy in internal units */
342         editor->priv->w_max = w_max;
343         editor->priv->h_max = h_max;
344 
345         /* convert internal units to displayed units */
346         gl_debug (DEBUG_EDITOR, "internal w_max,h_max = %g, %g", w_max, h_max);
347         w_max *= editor->priv->units_per_point;
348         h_max *= editor->priv->units_per_point;
349         wh_max = MAX( w_max, h_max );
350         gl_debug (DEBUG_EDITOR, "display w_max,h_max = %g, %g", w_max, h_max);
351 
352         /* Set widget values */
353         tmp = gtk_spin_button_get_value (GTK_SPIN_BUTTON (editor->priv->size_w_spin));
354         gtk_spin_button_set_range (GTK_SPIN_BUTTON (editor->priv->size_w_spin),
355                                    0.0, 2.0*wh_max);
356         gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->priv->size_w_spin), tmp);
357         tmp = gtk_spin_button_get_value (GTK_SPIN_BUTTON (editor->priv->size_h_spin));
358         gtk_spin_button_set_range (GTK_SPIN_BUTTON (editor->priv->size_h_spin),
359                                    0.0, 2.0*wh_max);
360         gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->priv->size_h_spin), tmp);
361 
362 
363         g_signal_handlers_unblock_by_func (G_OBJECT (editor->priv->size_w_spin), w_spin_cb, editor);
364         g_signal_handlers_unblock_by_func (G_OBJECT (editor->priv->size_h_spin), h_spin_cb, editor);
365 
366 
367 	gl_debug (DEBUG_EDITOR, "END");
368 }
369 
370 
371 /*****************************************************************************/
372 /* Set base or natural size of image.                                        */
373 /*****************************************************************************/
374 void
gl_object_editor_set_base_size(glObjectEditor * editor,gdouble w_base,gdouble h_base)375 gl_object_editor_set_base_size    (glObjectEditor      *editor,
376 				   gdouble              w_base,
377 				   gdouble              h_base)
378 {
379 	gl_debug (DEBUG_EDITOR, "Setting w_base = %g", w_base);
380 	gl_debug (DEBUG_EDITOR, "Setting h_base = %g", h_base);
381 
382 	editor->priv->w_base = w_base;
383 	editor->priv->h_base = h_base;
384 }
385 
386 
387 /*****************************************************************************/
388 /* Query size.                                                               */
389 /*****************************************************************************/
390 void
gl_object_editor_get_size(glObjectEditor * editor,gdouble * w,gdouble * h)391 gl_object_editor_get_size (glObjectEditor      *editor,
392 			   gdouble             *w,
393 			   gdouble             *h)
394 {
395 	gl_debug (DEBUG_EDITOR, "START");
396 
397 
398 	/* Get values from widgets */
399 	*w = gtk_spin_button_get_value (GTK_SPIN_BUTTON (editor->priv->size_w_spin));
400 	*h = gtk_spin_button_get_value (GTK_SPIN_BUTTON (editor->priv->size_h_spin));
401 
402 	/* convert everything back to our internal units (points) */
403 	*w /= editor->priv->units_per_point;
404 	*h /= editor->priv->units_per_point;
405 
406 	/* save a copy in internal units */
407 	editor->priv->w = *w;
408 	editor->priv->h = *h;
409 
410 	gl_debug (DEBUG_EDITOR, "END");
411 }
412 
413 
414 /*****************************************************************************/
415 /* PRIVATE. Prefs changed callback.  Update units related items.            */
416 /*****************************************************************************/
417 void
size_prefs_changed_cb(glObjectEditor * editor)418 size_prefs_changed_cb (glObjectEditor *editor)
419 {
420         lglUnits      units;
421 	const gchar  *units_string;
422 	gdouble       climb_rate;
423 	gint          digits;
424 
425 	gl_debug (DEBUG_EDITOR, "START");
426 
427 
428         g_signal_handlers_block_by_func (G_OBJECT (editor->priv->size_w_spin), w_spin_cb, editor);
429         g_signal_handlers_block_by_func (G_OBJECT (editor->priv->size_h_spin), h_spin_cb, editor);
430 
431 
432         /* Get new configuration information */
433         units = gl_prefs_model_get_units (gl_prefs);
434         units_string = lgl_units_get_name (units);
435         editor->priv->units_per_point = lgl_units_get_units_per_point (units);
436         climb_rate = gl_units_util_get_step_size (units);
437         digits = gl_units_util_get_precision (units);
438 
439 	/* Update characteristics of w_spin/h_spin */
440 	gtk_spin_button_set_digits (GTK_SPIN_BUTTON(editor->priv->size_w_spin), digits);
441 	gtk_spin_button_set_digits (GTK_SPIN_BUTTON(editor->priv->size_h_spin), digits);
442 	gtk_spin_button_set_increments (GTK_SPIN_BUTTON(editor->priv->size_w_spin),
443 					climb_rate, 10.0*climb_rate);
444 	gtk_spin_button_set_increments (GTK_SPIN_BUTTON(editor->priv->size_h_spin),
445 					climb_rate, 10.0*climb_rate);
446 
447 	/* Update units_labels */
448 	gtk_label_set_text (GTK_LABEL(editor->priv->size_w_units_label),
449 			    units_string);
450 	gtk_label_set_text (GTK_LABEL(editor->priv->size_h_units_label),
451 			    units_string);
452 
453 	/* Update values of w_spin/h_spin */
454 	gl_object_editor_set_size (editor, editor->priv->w, editor->priv->h);
455 	gl_object_editor_set_max_size (editor, editor->priv->w_max, editor->priv->h_max);
456 
457 
458         g_signal_handlers_unblock_by_func (G_OBJECT (editor->priv->size_w_spin), w_spin_cb, editor);
459         g_signal_handlers_unblock_by_func (G_OBJECT (editor->priv->size_h_spin), h_spin_cb, editor);
460 
461 
462 	gl_debug (DEBUG_EDITOR, "END");
463 }
464 
465 
466 
467 /*
468  * Local Variables:       -- emacs
469  * mode: C                -- emacs
470  * c-basic-offset: 8      -- emacs
471  * tab-width: 8           -- emacs
472  * indent-tabs-mode: nil  -- emacs
473  * End:                   -- emacs
474  */
475