1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <gegl.h>
21 #include <gtk/gtk.h>
22
23 #include "libgimpbase/gimpbase.h"
24 #include "libgimpwidgets/gimpwidgets.h"
25
26 #include "dialogs-types.h"
27
28 #include "core/gimpcontext.h"
29 #include "core/gimpimage.h"
30 #include "core/gimp-utils.h"
31
32 #include "widgets/gimphelp-ids.h"
33 #include "widgets/gimpviewabledialog.h"
34
35 #include "print-size-dialog.h"
36
37 #include "gimp-intl.h"
38
39
40 #define RESPONSE_RESET 1
41 #define SB_WIDTH 8
42
43
44 typedef struct _PrintSizeDialog PrintSizeDialog;
45
46 struct _PrintSizeDialog
47 {
48 GimpImage *image;
49 GimpSizeEntry *size_entry;
50 GimpSizeEntry *resolution_entry;
51 GimpChainButton *chain;
52 gdouble xres;
53 gdouble yres;
54 GimpResolutionCallback callback;
55 gpointer user_data;
56 };
57
58
59 /* local function prototypes */
60
61 static void print_size_dialog_free (PrintSizeDialog *private);
62 static void print_size_dialog_response (GtkWidget *dialog,
63 gint response_id,
64 PrintSizeDialog *private);
65 static void print_size_dialog_reset (PrintSizeDialog *private);
66
67 static void print_size_dialog_size_changed (GtkWidget *widget,
68 PrintSizeDialog *private);
69 static void print_size_dialog_resolution_changed (GtkWidget *widget,
70 PrintSizeDialog *private);
71 static void print_size_dialog_set_size (PrintSizeDialog *private,
72 gdouble width,
73 gdouble height);
74 static void print_size_dialog_set_resolution (PrintSizeDialog *private,
75 gdouble xres,
76 gdouble yres);
77
78
79 /* public functions */
80
81 GtkWidget *
print_size_dialog_new(GimpImage * image,GimpContext * context,const gchar * title,const gchar * role,GtkWidget * parent,GimpHelpFunc help_func,const gchar * help_id,GimpResolutionCallback callback,gpointer user_data)82 print_size_dialog_new (GimpImage *image,
83 GimpContext *context,
84 const gchar *title,
85 const gchar *role,
86 GtkWidget *parent,
87 GimpHelpFunc help_func,
88 const gchar *help_id,
89 GimpResolutionCallback callback,
90 gpointer user_data)
91 {
92 PrintSizeDialog *private;
93 GtkWidget *dialog;
94 GtkWidget *frame;
95 GtkWidget *table;
96 GtkWidget *entry;
97 GtkWidget *label;
98 GtkWidget *width;
99 GtkWidget *height;
100 GtkWidget *hbox;
101 GtkWidget *chain;
102 GtkAdjustment *adj;
103 GList *focus_chain = NULL;
104
105 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
106 g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
107 g_return_val_if_fail (callback != NULL, NULL);
108
109 private = g_slice_new0 (PrintSizeDialog);
110
111 private->image = image;
112 private->callback = callback;
113 private->user_data = user_data;
114
115 gimp_image_get_resolution (image, &private->xres, &private->yres);
116
117 dialog = gimp_viewable_dialog_new (GIMP_VIEWABLE (image), context,
118 title, role,
119 GIMP_ICON_DOCUMENT_PRINT_RESOLUTION, title,
120 parent,
121 help_func, help_id,
122
123 _("_Reset"), RESPONSE_RESET,
124 _("_Cancel"), GTK_RESPONSE_CANCEL,
125 _("_OK"), GTK_RESPONSE_OK,
126
127 NULL);
128
129 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
130 RESPONSE_RESET,
131 GTK_RESPONSE_OK,
132 GTK_RESPONSE_CANCEL,
133 -1);
134
135 gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
136
137 g_object_weak_ref (G_OBJECT (dialog),
138 (GWeakNotify) print_size_dialog_free, private);
139
140 g_signal_connect (dialog, "response",
141 G_CALLBACK (print_size_dialog_response),
142 private);
143
144 frame = gimp_frame_new (_("Print Size"));
145 gtk_container_set_border_width (GTK_CONTAINER (frame), 12);
146 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
147 frame, FALSE, FALSE, 0);
148 gtk_widget_show (frame);
149
150 table = gtk_table_new (4, 3, FALSE);
151 gtk_table_set_col_spacing (GTK_TABLE (table), 0, 6);
152 gtk_table_set_row_spacings (GTK_TABLE (table), 12);
153 gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
154 gtk_table_set_row_spacing (GTK_TABLE (table), 2, 2);
155 gtk_container_add (GTK_CONTAINER (frame), table);
156 gtk_widget_show (table);
157
158 /* the print size entry */
159
160 adj = (GtkAdjustment *) gtk_adjustment_new (1, 1, 1, 1, 10, 0);
161 width = gimp_spin_button_new (adj, 1.0, 2);
162 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (width), TRUE);
163 gtk_entry_set_width_chars (GTK_ENTRY (width), SB_WIDTH);
164
165 adj = (GtkAdjustment *) gtk_adjustment_new (1, 1, 1, 1, 10, 0);
166 height = gimp_spin_button_new (adj, 1.0, 2);
167 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (height), TRUE);
168 gtk_entry_set_width_chars (GTK_ENTRY (height), SB_WIDTH);
169
170 entry = gimp_size_entry_new (0, gimp_get_default_unit (), "%p",
171 FALSE, FALSE, FALSE, SB_WIDTH,
172 GIMP_SIZE_ENTRY_UPDATE_SIZE);
173 private->size_entry = GIMP_SIZE_ENTRY (entry);
174
175 label = gtk_label_new_with_mnemonic (_("_Width:"));
176 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
177 gtk_label_set_mnemonic_widget (GTK_LABEL (label), width);
178 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
179 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
180 gtk_widget_show (label);
181
182 label = gtk_label_new_with_mnemonic (_("H_eight:"));
183 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
184 gtk_label_set_mnemonic_widget (GTK_LABEL (label), height);
185 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
186 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
187 gtk_widget_show (label);
188
189 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
190 gtk_table_attach_defaults (GTK_TABLE (table), hbox, 1, 2, 0, 2);
191 gtk_widget_show (hbox);
192
193 gtk_table_set_row_spacing (GTK_TABLE (entry), 0, 2);
194 gtk_table_set_col_spacing (GTK_TABLE (entry), 1, 6);
195
196 gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
197 gtk_widget_show (entry);
198
199 gimp_size_entry_add_field (GIMP_SIZE_ENTRY (entry),
200 GTK_SPIN_BUTTON (height), NULL);
201 gtk_table_attach_defaults (GTK_TABLE (entry), height, 0, 1, 1, 2);
202 gtk_widget_show (height);
203
204 gimp_size_entry_add_field (GIMP_SIZE_ENTRY (entry),
205 GTK_SPIN_BUTTON (width), NULL);
206 gtk_table_attach_defaults (GTK_TABLE (entry), width, 0, 1, 0, 1);
207 gtk_widget_show (width);
208
209 gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (entry), 0,
210 private->xres, FALSE);
211 gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (entry), 1,
212 private->yres, FALSE);
213
214 gimp_size_entry_set_refval_boundaries
215 (GIMP_SIZE_ENTRY (entry), 0, GIMP_MIN_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE);
216 gimp_size_entry_set_refval_boundaries
217 (GIMP_SIZE_ENTRY (entry), 1, GIMP_MIN_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE);
218
219 gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (entry), 0,
220 gimp_image_get_width (image));
221 gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (entry), 1,
222 gimp_image_get_height (image));
223
224 /* the resolution entry */
225
226 adj = (GtkAdjustment *) gtk_adjustment_new (1, 1, 1, 1, 10, 0);
227 width = gimp_spin_button_new (adj, 1.0, 2);
228 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (width), TRUE);
229 gtk_entry_set_width_chars (GTK_ENTRY (width), SB_WIDTH);
230
231 adj = (GtkAdjustment *) gtk_adjustment_new (1, 1, 1, 1, 10, 0);
232 height = gimp_spin_button_new (adj, 1.0, 2);
233 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (height), TRUE);
234 gtk_entry_set_width_chars (GTK_ENTRY (height), SB_WIDTH);
235
236 label = gtk_label_new_with_mnemonic (_("_X resolution:"));
237 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
238 gtk_label_set_mnemonic_widget (GTK_LABEL (label), width);
239 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
240 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
241 gtk_widget_show (label);
242
243 label = gtk_label_new_with_mnemonic (_("_Y resolution:"));
244 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
245 gtk_label_set_mnemonic_widget (GTK_LABEL (label), height);
246 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
247 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
248 gtk_widget_show (label);
249
250 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
251 gtk_table_attach_defaults (GTK_TABLE (table), hbox, 1, 2, 2, 4);
252 gtk_widget_show (hbox);
253
254 entry = gimp_size_entry_new (0, gimp_image_get_unit (image), _("pixels/%a"),
255 FALSE, FALSE, FALSE, SB_WIDTH,
256 GIMP_SIZE_ENTRY_UPDATE_RESOLUTION);
257 private->resolution_entry = GIMP_SIZE_ENTRY (entry);
258
259 gtk_table_set_row_spacing (GTK_TABLE (entry), 0, 2);
260 gtk_table_set_col_spacing (GTK_TABLE (entry), 1, 2);
261 gtk_table_set_col_spacing (GTK_TABLE (entry), 2, 2);
262
263 gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
264 gtk_widget_show (entry);
265
266 gimp_size_entry_add_field (GIMP_SIZE_ENTRY (entry),
267 GTK_SPIN_BUTTON (height), NULL);
268 gtk_table_attach_defaults (GTK_TABLE (entry), height, 0, 1, 1, 2);
269 gtk_widget_show (height);
270
271 gimp_size_entry_add_field (GIMP_SIZE_ENTRY (entry),
272 GTK_SPIN_BUTTON (width), NULL);
273 gtk_table_attach_defaults (GTK_TABLE (entry), width, 0, 1, 0, 1);
274 gtk_widget_show (width);
275
276 gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (entry), 0,
277 GIMP_MIN_RESOLUTION,
278 GIMP_MAX_RESOLUTION);
279 gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (entry), 1,
280 GIMP_MIN_RESOLUTION,
281 GIMP_MAX_RESOLUTION);
282
283 gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (entry), 0, private->xres);
284 gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (entry), 1, private->yres);
285
286 chain = gimp_chain_button_new (GIMP_CHAIN_RIGHT);
287 if (ABS (private->xres - private->yres) < GIMP_MIN_RESOLUTION)
288 gimp_chain_button_set_active (GIMP_CHAIN_BUTTON (chain), TRUE);
289 gtk_table_attach_defaults (GTK_TABLE (entry), chain, 1, 2, 0, 2);
290 gtk_widget_show (chain);
291
292 private->chain = GIMP_CHAIN_BUTTON (chain);
293
294 focus_chain = g_list_prepend (focus_chain, GIMP_SIZE_ENTRY (entry)->unitmenu);
295 focus_chain = g_list_prepend (focus_chain, chain);
296 focus_chain = g_list_prepend (focus_chain, height);
297 focus_chain = g_list_prepend (focus_chain, width);
298
299 gtk_container_set_focus_chain (GTK_CONTAINER (entry), focus_chain);
300 g_list_free (focus_chain);
301
302 g_signal_connect (private->size_entry, "value-changed",
303 G_CALLBACK (print_size_dialog_size_changed),
304 private);
305 g_signal_connect (private->resolution_entry, "value-changed",
306 G_CALLBACK (print_size_dialog_resolution_changed),
307 private);
308
309 return dialog;
310 }
311
312
313 /* private functions */
314
315 static void
print_size_dialog_free(PrintSizeDialog * private)316 print_size_dialog_free (PrintSizeDialog *private)
317 {
318 g_slice_free (PrintSizeDialog, private);
319 }
320
321 static void
print_size_dialog_response(GtkWidget * dialog,gint response_id,PrintSizeDialog * private)322 print_size_dialog_response (GtkWidget *dialog,
323 gint response_id,
324 PrintSizeDialog *private)
325 {
326 GimpSizeEntry *entry = private->resolution_entry;
327
328 switch (response_id)
329 {
330 case RESPONSE_RESET:
331 print_size_dialog_reset (private);
332 break;
333
334 case GTK_RESPONSE_OK:
335 private->callback (dialog,
336 private->image,
337 gimp_size_entry_get_refval (entry, 0),
338 gimp_size_entry_get_refval (entry, 1),
339 gimp_size_entry_get_unit (entry),
340 private->user_data);
341 break;
342
343 default:
344 gtk_widget_destroy (dialog);
345 break;
346 }
347 }
348
349 static void
print_size_dialog_reset(PrintSizeDialog * private)350 print_size_dialog_reset (PrintSizeDialog *private)
351 {
352 gdouble xres, yres;
353
354 gimp_size_entry_set_unit (private->resolution_entry,
355 gimp_get_default_unit ());
356
357 gimp_image_get_resolution (private->image, &xres, &yres);
358 print_size_dialog_set_resolution (private, xres, yres);
359 }
360
361 static void
print_size_dialog_size_changed(GtkWidget * widget,PrintSizeDialog * private)362 print_size_dialog_size_changed (GtkWidget *widget,
363 PrintSizeDialog *private)
364 {
365 GimpImage *image = private->image;
366 gdouble width;
367 gdouble height;
368 gdouble xres;
369 gdouble yres;
370 gdouble scale;
371
372 scale = gimp_unit_get_factor (gimp_size_entry_get_unit (private->size_entry));
373
374 width = gimp_size_entry_get_value (private->size_entry, 0);
375 height = gimp_size_entry_get_value (private->size_entry, 1);
376
377 xres = scale * gimp_image_get_width (image) / MAX (0.001, width);
378 yres = scale * gimp_image_get_height (image) / MAX (0.001, height);
379
380 xres = CLAMP (xres, GIMP_MIN_RESOLUTION, GIMP_MAX_RESOLUTION);
381 yres = CLAMP (yres, GIMP_MIN_RESOLUTION, GIMP_MAX_RESOLUTION);
382
383 print_size_dialog_set_resolution (private, xres, yres);
384 print_size_dialog_set_size (private,
385 gimp_image_get_width (image),
386 gimp_image_get_height (image));
387 }
388
389 static void
print_size_dialog_resolution_changed(GtkWidget * widget,PrintSizeDialog * private)390 print_size_dialog_resolution_changed (GtkWidget *widget,
391 PrintSizeDialog *private)
392 {
393 GimpSizeEntry *entry = private->resolution_entry;
394 gdouble xres = gimp_size_entry_get_refval (entry, 0);
395 gdouble yres = gimp_size_entry_get_refval (entry, 1);
396
397 print_size_dialog_set_resolution (private, xres, yres);
398 }
399
400 static void
print_size_dialog_set_size(PrintSizeDialog * private,gdouble width,gdouble height)401 print_size_dialog_set_size (PrintSizeDialog *private,
402 gdouble width,
403 gdouble height)
404 {
405 g_signal_handlers_block_by_func (private->size_entry,
406 print_size_dialog_size_changed,
407 private);
408
409 gimp_size_entry_set_refval (private->size_entry, 0, width);
410 gimp_size_entry_set_refval (private->size_entry, 1, height);
411
412 g_signal_handlers_unblock_by_func (private->size_entry,
413 print_size_dialog_size_changed,
414 private);
415 }
416
417 static void
print_size_dialog_set_resolution(PrintSizeDialog * private,gdouble xres,gdouble yres)418 print_size_dialog_set_resolution (PrintSizeDialog *private,
419 gdouble xres,
420 gdouble yres)
421 {
422 if (private->chain && gimp_chain_button_get_active (private->chain))
423 {
424 if (xres != private->xres)
425 yres = xres;
426 else
427 xres = yres;
428 }
429
430 private->xres = xres;
431 private->yres = yres;
432
433 g_signal_handlers_block_by_func (private->resolution_entry,
434 print_size_dialog_resolution_changed,
435 private);
436
437 gimp_size_entry_set_refval (private->resolution_entry, 0, xres);
438 gimp_size_entry_set_refval (private->resolution_entry, 1, yres);
439
440 g_signal_handlers_unblock_by_func (private->resolution_entry,
441 print_size_dialog_resolution_changed,
442 private);
443
444 g_signal_handlers_block_by_func (private->size_entry,
445 print_size_dialog_size_changed,
446 private);
447
448 gimp_size_entry_set_resolution (private->size_entry, 0, xres, TRUE);
449 gimp_size_entry_set_resolution (private->size_entry, 1, yres, TRUE);
450
451 g_signal_handlers_unblock_by_func (private->size_entry,
452 print_size_dialog_size_changed,
453 private);
454 }
455