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