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 "libgimpmath/gimpmath.h"
24 #include "libgimpwidgets/gimpwidgets.h"
25
26 #include "display-types.h"
27
28 #include "core/gimp.h"
29 #include "core/gimpviewable.h"
30
31 #include "widgets/gimphelp-ids.h"
32 #include "widgets/gimpviewabledialog.h"
33
34 #include "gimpdisplay.h"
35 #include "gimpdisplayshell.h"
36 #include "gimpdisplayshell-scale.h"
37 #include "gimpdisplayshell-scale-dialog.h"
38
39 #include "gimp-intl.h"
40
41
42 #define SCALE_EPSILON 0.0001
43 #define SCALE_EQUALS(a,b) (fabs ((a) - (b)) < SCALE_EPSILON)
44
45
46 typedef struct
47 {
48 GimpDisplayShell *shell;
49 GimpZoomModel *model;
50 GtkAdjustment *scale_adj;
51 GtkAdjustment *num_adj;
52 GtkAdjustment *denom_adj;
53 } ScaleDialogData;
54
55
56 /* local function prototypes */
57
58 static void gimp_display_shell_scale_dialog_response (GtkWidget *widget,
59 gint response_id,
60 ScaleDialogData *dialog);
61 static void gimp_display_shell_scale_dialog_free (ScaleDialogData *dialog);
62
63 static void update_zoom_values (GtkAdjustment *adj,
64 ScaleDialogData *dialog);
65
66
67
68 /* public functions */
69
70 /**
71 * gimp_display_shell_scale_dialog:
72 * @shell: the #GimpDisplayShell
73 *
74 * Constructs and displays a dialog allowing the user to enter a
75 * custom display scale.
76 **/
77 void
gimp_display_shell_scale_dialog(GimpDisplayShell * shell)78 gimp_display_shell_scale_dialog (GimpDisplayShell *shell)
79 {
80 ScaleDialogData *data;
81 GimpImage *image;
82 GtkWidget *toplevel;
83 GtkWidget *hbox;
84 GtkWidget *table;
85 GtkWidget *spin;
86 GtkWidget *label;
87 gint num, denom, row;
88
89 g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
90
91 if (shell->scale_dialog)
92 {
93 gtk_window_present (GTK_WINDOW (shell->scale_dialog));
94 return;
95 }
96
97 if (SCALE_EQUALS (shell->other_scale, 0.0))
98 {
99 /* other_scale not yet initialized */
100 shell->other_scale = gimp_zoom_model_get_factor (shell->zoom);
101 }
102
103 image = gimp_display_get_image (shell->display);
104
105 data = g_slice_new (ScaleDialogData);
106
107 data->shell = shell;
108 data->model = g_object_new (GIMP_TYPE_ZOOM_MODEL,
109 "value", fabs (shell->other_scale),
110 NULL);
111
112 shell->scale_dialog =
113 gimp_viewable_dialog_new (GIMP_VIEWABLE (image),
114 gimp_get_user_context (shell->display->gimp),
115 _("Zoom Ratio"), "display_scale",
116 "zoom-original",
117 _("Select Zoom Ratio"),
118 GTK_WIDGET (shell),
119 gimp_standard_help_func,
120 GIMP_HELP_VIEW_ZOOM_OTHER,
121
122 _("_Cancel"), GTK_RESPONSE_CANCEL,
123 _("_OK"), GTK_RESPONSE_OK,
124
125 NULL);
126
127 gtk_dialog_set_alternative_button_order (GTK_DIALOG (shell->scale_dialog),
128 GTK_RESPONSE_OK,
129 GTK_RESPONSE_CANCEL,
130 -1);
131
132 g_object_weak_ref (G_OBJECT (shell->scale_dialog),
133 (GWeakNotify) gimp_display_shell_scale_dialog_free, data);
134 g_object_weak_ref (G_OBJECT (shell->scale_dialog),
135 (GWeakNotify) g_object_unref, data->model);
136
137 g_object_add_weak_pointer (G_OBJECT (shell->scale_dialog),
138 (gpointer) &shell->scale_dialog);
139
140 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell));
141
142 gtk_window_set_transient_for (GTK_WINDOW (shell->scale_dialog),
143 GTK_WINDOW (toplevel));
144 gtk_window_set_destroy_with_parent (GTK_WINDOW (shell->scale_dialog), TRUE);
145
146 g_signal_connect (shell->scale_dialog, "response",
147 G_CALLBACK (gimp_display_shell_scale_dialog_response),
148 data);
149
150 table = gtk_table_new (2, 2, FALSE);
151 gtk_container_set_border_width (GTK_CONTAINER (table), 12);
152 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
153 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
154 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (shell->scale_dialog))),
155 table, TRUE, TRUE, 0);
156 gtk_widget_show (table);
157
158 row = 0;
159
160 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
161 gimp_table_attach_aligned (GTK_TABLE (table), 0, row++,
162 _("Zoom ratio:"), 0.0, 0.5,
163 hbox, 1, FALSE);
164
165 gimp_zoom_model_get_fraction (data->model, &num, &denom);
166
167 data->num_adj = (GtkAdjustment *)
168 gtk_adjustment_new (num, 1, 256, 1, 8, 0);
169 spin = gimp_spin_button_new (data->num_adj, 1.0, 0);
170 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin), TRUE);
171 gtk_entry_set_activates_default (GTK_ENTRY (spin), TRUE);
172 gtk_box_pack_start (GTK_BOX (hbox), spin, TRUE, TRUE, 0);
173 gtk_widget_show (spin);
174
175 label = gtk_label_new (":");
176 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
177 gtk_widget_show (label);
178
179 data->denom_adj = (GtkAdjustment *)
180 gtk_adjustment_new (denom, 1, 256, 1, 8, 0);
181 spin = gimp_spin_button_new (data->denom_adj, 1.0, 0);
182 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin), TRUE);
183 gtk_entry_set_activates_default (GTK_ENTRY (spin), TRUE);
184 gtk_box_pack_start (GTK_BOX (hbox), spin, TRUE, TRUE, 0);
185 gtk_widget_show (spin);
186
187 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
188 gimp_table_attach_aligned (GTK_TABLE (table), 0, row++,
189 _("Zoom:"), 0.0, 0.5,
190 hbox, 1, FALSE);
191
192 data->scale_adj = (GtkAdjustment *)
193 gtk_adjustment_new (fabs (shell->other_scale) * 100,
194 100.0 / 256.0, 25600.0,
195 10, 50, 0);
196 spin = gimp_spin_button_new (data->scale_adj, 1.0, 2);
197 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin), TRUE);
198 gtk_entry_set_activates_default (GTK_ENTRY (spin), TRUE);
199 gtk_box_pack_start (GTK_BOX (hbox), spin, TRUE, TRUE, 0);
200 gtk_widget_show (spin);
201
202 label = gtk_label_new ("%");
203 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
204 gtk_widget_show (label);
205
206 g_signal_connect (data->scale_adj, "value-changed",
207 G_CALLBACK (update_zoom_values), data);
208 g_signal_connect (data->num_adj, "value-changed",
209 G_CALLBACK (update_zoom_values), data);
210 g_signal_connect (data->denom_adj, "value-changed",
211 G_CALLBACK (update_zoom_values), data);
212
213 gtk_widget_show (shell->scale_dialog);
214 }
215
216 static void
gimp_display_shell_scale_dialog_response(GtkWidget * widget,gint response_id,ScaleDialogData * dialog)217 gimp_display_shell_scale_dialog_response (GtkWidget *widget,
218 gint response_id,
219 ScaleDialogData *dialog)
220 {
221 if (response_id == GTK_RESPONSE_OK)
222 {
223 gdouble scale;
224
225 scale = gtk_adjustment_get_value (dialog->scale_adj);
226
227 gimp_display_shell_scale (dialog->shell,
228 GIMP_ZOOM_TO,
229 scale / 100.0,
230 GIMP_ZOOM_FOCUS_BEST_GUESS);
231 }
232 else
233 {
234 /* need to emit "scaled" to get the menu updated */
235 gimp_display_shell_scaled (dialog->shell);
236 }
237
238 dialog->shell->other_scale = - fabs (dialog->shell->other_scale);
239
240 gtk_widget_destroy (dialog->shell->scale_dialog);
241 }
242
243 static void
gimp_display_shell_scale_dialog_free(ScaleDialogData * dialog)244 gimp_display_shell_scale_dialog_free (ScaleDialogData *dialog)
245 {
246 g_slice_free (ScaleDialogData, dialog);
247 }
248
249 static void
update_zoom_values(GtkAdjustment * adj,ScaleDialogData * dialog)250 update_zoom_values (GtkAdjustment *adj,
251 ScaleDialogData *dialog)
252 {
253 gint num, denom;
254 gdouble scale;
255
256 g_signal_handlers_block_by_func (dialog->scale_adj,
257 update_zoom_values,
258 dialog);
259 g_signal_handlers_block_by_func (dialog->num_adj,
260 update_zoom_values,
261 dialog);
262 g_signal_handlers_block_by_func (dialog->denom_adj,
263 update_zoom_values,
264 dialog);
265
266 if (adj == dialog->scale_adj)
267 {
268 scale = gtk_adjustment_get_value (dialog->scale_adj);
269
270 gimp_zoom_model_zoom (dialog->model, GIMP_ZOOM_TO, scale / 100.0);
271 gimp_zoom_model_get_fraction (dialog->model, &num, &denom);
272
273 gtk_adjustment_set_value (dialog->num_adj, num);
274 gtk_adjustment_set_value (dialog->denom_adj, denom);
275 }
276 else /* fraction adjustments */
277 {
278 scale = (gtk_adjustment_get_value (dialog->num_adj) /
279 gtk_adjustment_get_value (dialog->denom_adj));
280
281 gtk_adjustment_set_value (dialog->scale_adj, scale * 100);
282 }
283
284 g_signal_handlers_unblock_by_func (dialog->scale_adj,
285 update_zoom_values,
286 dialog);
287 g_signal_handlers_unblock_by_func (dialog->num_adj,
288 update_zoom_values,
289 dialog);
290 g_signal_handlers_unblock_by_func (dialog->denom_adj,
291 update_zoom_values,
292 dialog);
293 }
294