1 /* GIMP LiquidRescale Plug-in
2 * Copyright (C) 2007-2010 Carlo Baldassi (the "Author") <carlobaldassi@gmail.com>.
3 * All Rights Reserved.
4 *
5 * The code in this file is taken from gimpwidgets.c
6 * Copyright (C) 2000 Michael Natterer <mitch@gimp.org>
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 Licence, 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, see <http://www.gnu.org.licences/>.
20 */
21
22 #include <libgimp/gimp.h>
23 #include <libgimp/gimpui.h>
24
25 #include "altsizeentry.h"
26 #include "altcoordinates.h"
27
28 typedef struct
29 {
30 GimpChainButton *chainbutton;
31 gboolean chain_constrains_ratio;
32 gdouble orig_x;
33 gdouble orig_y;
34 gdouble last_x;
35 gdouble last_y;
36 } AltCoordinatesData;
37
38
39 static void alt_coordinates_callback (GtkWidget *widget, AltCoordinatesData *data);
40 static void alt_coordinates_data_free (AltCoordinatesData *data);
41 static void alt_coordinates_chainbutton_toggled (GimpChainButton *button, AltSizeEntry *entry);
42
43
44 static void
alt_coordinates_callback(GtkWidget * widget,AltCoordinatesData * data)45 alt_coordinates_callback (GtkWidget *widget,
46 AltCoordinatesData *data)
47 {
48 gdouble new_x;
49 gdouble new_y;
50
51 new_x = alt_size_entry_get_refval (ALT_SIZE_ENTRY (widget), 0);
52 new_y = alt_size_entry_get_refval (ALT_SIZE_ENTRY (widget), 1);
53
54 if (gimp_chain_button_get_active (data->chainbutton))
55 {
56 if (data->chain_constrains_ratio)
57 {
58 if ((data->orig_x != 0) && (data->orig_y != 0))
59 {
60 if (ROUND (new_x) != ROUND (data->last_x))
61 {
62 data->last_x = new_x;
63 new_y = (new_x * data->orig_y) / data->orig_x;
64
65 alt_size_entry_set_refval (ALT_SIZE_ENTRY (widget), 1,
66 new_y);
67 data->last_y
68 = alt_size_entry_get_refval (ALT_SIZE_ENTRY (widget), 1);
69 }
70 else if (ROUND (new_y) != ROUND (data->last_y))
71 {
72 data->last_y = new_y;
73 new_x = (new_y * data->orig_x) / data->orig_y;
74
75 alt_size_entry_set_refval (ALT_SIZE_ENTRY (widget), 0,
76 new_x);
77 data->last_x
78 = alt_size_entry_get_refval (ALT_SIZE_ENTRY (widget), 0);
79 }
80 }
81 }
82 else
83 {
84 if (new_x != data->last_x)
85 {
86 new_y = new_x;
87
88 alt_size_entry_set_refval (ALT_SIZE_ENTRY (widget), 1, new_x);
89 data->last_y = data->last_x
90 = alt_size_entry_get_refval (ALT_SIZE_ENTRY (widget), 1);
91 }
92 else if (new_y != data->last_y)
93 {
94 new_x = new_y;
95
96 alt_size_entry_set_refval (ALT_SIZE_ENTRY (widget), 0, new_y);
97 data->last_x = data->last_y
98 = alt_size_entry_get_refval (ALT_SIZE_ENTRY (widget), 0);
99 }
100 }
101 }
102 else
103 {
104 if (new_x != data->last_x)
105 data->last_x = new_x;
106 if (new_y != data->last_y)
107 data->last_y = new_y;
108 }
109 }
110
111 static void
alt_coordinates_data_free(AltCoordinatesData * data)112 alt_coordinates_data_free (AltCoordinatesData *data)
113 {
114 g_slice_free (AltCoordinatesData, data);
115 }
116
117 static void
alt_coordinates_chainbutton_toggled(GimpChainButton * button,AltSizeEntry * entry)118 alt_coordinates_chainbutton_toggled (GimpChainButton *button,
119 AltSizeEntry *entry)
120 {
121 if (gimp_chain_button_get_active (button))
122 {
123 AltCoordinatesData *data;
124
125 data = g_object_get_data (G_OBJECT (entry), "alt-coordinates-data");
126
127 data->orig_x = alt_size_entry_get_refval (entry, 0);
128 data->orig_y = alt_size_entry_get_refval (entry, 1);
129 }
130 }
131
132 /**
133 * gimp_coordinates_new:
134 * @unit: The initial unit of the #GimpUnitMenu.
135 * @unit_format: A printf-like unit-format string as is used with
136 * gimp_unit_menu_new().
137 * @menu_show_pixels: %TRUE if the #GimpUnitMenu should contain an item
138 * for GIMP_UNIT_PIXEL.
139 * @menu_show_percent: %TRUE if the #GimpUnitMenu should contain an item
140 * for GIMP_UNIT_PERCENT.
141 * @spinbutton_width: The horizontal size of the #AltSizeEntry's
142 * #GtkSpinButton's.
143 * @update_policy: The update policy for the #AltSizeEntry.
144 * @chainbutton_active: %TRUE if the attached #GimpChainButton should be
145 * active.
146 * @chain_constrains_ratio: %TRUE if the chainbutton should constrain the
147 * fields' aspect ratio. If %FALSE, the values will
148 * be constrained.
149 * @xlabel: The label for the X coordinate.
150 * @x: The initial value of the X coordinate.
151 * @xres: The horizontal resolution in DPI.
152 * @lower_boundary_x: The lower boundary of the X coordinate.
153 * @upper_boundary_x: The upper boundary of the X coordinate.
154 * @xsize_0: The X value which will be treated as 0%.
155 * @xsize_100: The X value which will be treated as 100%.
156 * @ylabel: The label for the Y coordinate.
157 * @y: The initial value of the Y coordinate.
158 * @yres: The vertical resolution in DPI.
159 * @lower_boundary_y: The lower boundary of the Y coordinate.
160 * @upper_boundary_y: The upper boundary of the Y coordinate.
161 * @ysize_0: The Y value which will be treated as 0%.
162 * @ysize_100: The Y value which will be treated as 100%.
163 *
164 * Convenience function that creates a #AltSizeEntry with two fields for x/y
165 * coordinates/sizes with a #GimpChainButton attached to constrain either the
166 * two fields' values or the ratio between them.
167 *
168 * Returns: The new #AltSizeEntry.
169 **/
170 GtkWidget *
alt_coordinates_new(GimpUnit unit,const gchar * unit_format,gboolean menu_show_pixels,gboolean menu_show_percent,gint spinbutton_width,AltSizeEntryUpdatePolicy update_policy,gboolean chainbutton_active,gboolean chain_constrains_ratio,const gchar * xlabel,gdouble x,gdouble xres,gdouble lower_boundary_x,gdouble upper_boundary_x,gdouble xsize_0,gdouble xsize_100,const gchar * ylabel,gdouble y,gdouble yres,gdouble lower_boundary_y,gdouble upper_boundary_y,gdouble ysize_0,gdouble ysize_100)171 alt_coordinates_new (GimpUnit unit,
172 const gchar *unit_format,
173 gboolean menu_show_pixels,
174 gboolean menu_show_percent,
175 gint spinbutton_width,
176 AltSizeEntryUpdatePolicy update_policy,
177
178 gboolean chainbutton_active,
179 gboolean chain_constrains_ratio,
180
181 const gchar *xlabel,
182 gdouble x,
183 gdouble xres,
184 gdouble lower_boundary_x,
185 gdouble upper_boundary_x,
186 gdouble xsize_0, /* % */
187 gdouble xsize_100, /* % */
188
189 const gchar *ylabel,
190 gdouble y,
191 gdouble yres,
192 gdouble lower_boundary_y,
193 gdouble upper_boundary_y,
194 gdouble ysize_0, /* % */
195 gdouble ysize_100 /* % */)
196 {
197 AltCoordinatesData *data;
198 GtkObject *adjustment;
199 GtkWidget *spinbutton;
200 GtkWidget *sizeentry;
201 GtkWidget *chainbutton;
202
203 spinbutton = gimp_spin_button_new (&adjustment, 1, 0, 1, 1, 10, 0, 1, 2);
204
205 if (spinbutton_width > 0)
206 {
207 if (spinbutton_width < 17)
208 gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), spinbutton_width);
209 else
210 gtk_widget_set_size_request (spinbutton, spinbutton_width, -1);
211 }
212
213 sizeentry = alt_size_entry_new (1, unit, unit_format,
214 menu_show_pixels,
215 menu_show_percent,
216 FALSE,
217 spinbutton_width,
218 update_policy);
219 gtk_table_set_col_spacing (GTK_TABLE (sizeentry), 0, 4);
220 gtk_table_set_col_spacing (GTK_TABLE (sizeentry), 2, 4);
221 alt_size_entry_add_field (ALT_SIZE_ENTRY (sizeentry),
222 GTK_SPIN_BUTTON (spinbutton), NULL);
223 gtk_table_attach_defaults (GTK_TABLE (sizeentry), spinbutton, 1, 2, 0, 1);
224 gtk_widget_show (spinbutton);
225
226 alt_size_entry_set_unit (ALT_SIZE_ENTRY (sizeentry),
227 (update_policy == ALT_SIZE_ENTRY_UPDATE_RESOLUTION) ||
228 (menu_show_pixels == FALSE) ?
229 GIMP_UNIT_INCH : GIMP_UNIT_PIXEL);
230
231 alt_size_entry_set_resolution (ALT_SIZE_ENTRY (sizeentry), 0, xres, TRUE);
232 alt_size_entry_set_resolution (ALT_SIZE_ENTRY (sizeentry), 1, yres, TRUE);
233 alt_size_entry_set_refval_boundaries (ALT_SIZE_ENTRY (sizeentry), 0,
234 lower_boundary_x, upper_boundary_x);
235 alt_size_entry_set_refval_boundaries (ALT_SIZE_ENTRY (sizeentry), 1,
236 lower_boundary_y, upper_boundary_y);
237
238 if (menu_show_percent)
239 {
240 alt_size_entry_set_size (ALT_SIZE_ENTRY (sizeentry), 0,
241 xsize_0, xsize_100);
242 alt_size_entry_set_size (ALT_SIZE_ENTRY (sizeentry), 1,
243 ysize_0, ysize_100);
244 }
245
246 alt_size_entry_set_refval (ALT_SIZE_ENTRY (sizeentry), 0, x);
247 alt_size_entry_set_refval (ALT_SIZE_ENTRY (sizeentry), 1, y);
248
249 alt_size_entry_attach_label (ALT_SIZE_ENTRY (sizeentry),
250 xlabel, 0, 0, 0.0);
251 alt_size_entry_attach_label (ALT_SIZE_ENTRY (sizeentry),
252 ylabel, 1, 0, 0.0);
253
254 chainbutton = gimp_chain_button_new (GIMP_CHAIN_RIGHT);
255
256 if (chainbutton_active)
257 gimp_chain_button_set_active (GIMP_CHAIN_BUTTON (chainbutton), TRUE);
258
259 gtk_table_attach (GTK_TABLE (sizeentry), chainbutton, 2, 3, 0, 2,
260 GTK_SHRINK | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
261 gtk_widget_show (chainbutton);
262
263 data = g_slice_new (AltCoordinatesData);
264
265 data->chainbutton = GIMP_CHAIN_BUTTON (chainbutton);
266 data->chain_constrains_ratio = chain_constrains_ratio;
267 data->orig_x = x;
268 data->orig_y = y;
269 data->last_x = x;
270 data->last_y = y;
271
272 g_object_set_data_full (G_OBJECT (sizeentry), "alt-coordinates-data",
273 data,
274 (GDestroyNotify) alt_coordinates_data_free);
275
276 g_signal_connect (sizeentry, "value-changed",
277 G_CALLBACK (alt_coordinates_callback),
278 data);
279
280 g_object_set_data (G_OBJECT (sizeentry), "chainbutton", chainbutton);
281
282 g_signal_connect (chainbutton, "toggled",
283 G_CALLBACK (alt_coordinates_chainbutton_toggled),
284 sizeentry);
285
286 return sizeentry;
287 }
288
289