1 | /* GTK - The GIMP Toolkit |
2 | * Copyright © 2013 Carlos Garnacho <carlosg@gnome.org> |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library 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 GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | #include "config.h" |
19 | #include "gtk/gtk.h" |
20 | #include "gtkmagnifierprivate.h" |
21 | #include "gtkwidgetprivate.h" |
22 | #include "gtksnapshot.h" |
23 | #include "gtkintl.h" |
24 | |
25 | enum { |
26 | PROP_INSPECTED = 1, |
27 | PROP_RESIZE, |
28 | PROP_MAGNIFICATION |
29 | }; |
30 | |
31 | struct _GtkMagnifier |
32 | { |
33 | GtkWidget parent_instance; |
34 | |
35 | GdkPaintable *paintable; |
36 | double magnification; |
37 | int x; |
38 | int y; |
39 | gboolean resize; |
40 | }; |
41 | |
42 | typedef struct |
43 | { |
44 | GtkWidgetClass parent_class; |
45 | } GtkMagnifierClass; |
46 | |
47 | G_DEFINE_TYPE (GtkMagnifier, gtk_magnifier, GTK_TYPE_WIDGET) |
48 | |
49 | static void |
50 | _gtk_magnifier_set_property (GObject *object, |
51 | guint param_id, |
52 | const GValue *value, |
53 | GParamSpec *pspec) |
54 | { |
55 | GtkMagnifier *magnifier = GTK_MAGNIFIER (object); |
56 | |
57 | switch (param_id) |
58 | { |
59 | case PROP_INSPECTED: |
60 | _gtk_magnifier_set_inspected (magnifier, inspected: g_value_get_object (value)); |
61 | break; |
62 | |
63 | case PROP_MAGNIFICATION: |
64 | _gtk_magnifier_set_magnification (magnifier, magnification: g_value_get_double (value)); |
65 | break; |
66 | |
67 | case PROP_RESIZE: |
68 | _gtk_magnifier_set_resize (magnifier, resize: g_value_get_boolean (value)); |
69 | break; |
70 | |
71 | default: |
72 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); |
73 | } |
74 | } |
75 | |
76 | static void |
77 | _gtk_magnifier_get_property (GObject *object, |
78 | guint param_id, |
79 | GValue *value, |
80 | GParamSpec *pspec) |
81 | { |
82 | GtkMagnifier *magnifier = GTK_MAGNIFIER (object); |
83 | |
84 | switch (param_id) |
85 | { |
86 | case PROP_INSPECTED: |
87 | g_value_set_object (value, v_object: gtk_widget_paintable_get_widget (self: GTK_WIDGET_PAINTABLE (ptr: magnifier->paintable))); |
88 | break; |
89 | |
90 | case PROP_MAGNIFICATION: |
91 | g_value_set_double (value, v_double: magnifier->magnification); |
92 | break; |
93 | |
94 | case PROP_RESIZE: |
95 | g_value_set_boolean (value, v_boolean: magnifier->resize); |
96 | break; |
97 | |
98 | default: |
99 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); |
100 | } |
101 | } |
102 | |
103 | static void |
104 | gtk_magnifier_snapshot (GtkWidget *widget, |
105 | GtkSnapshot *snapshot) |
106 | { |
107 | GtkMagnifier *magnifier = GTK_MAGNIFIER (widget); |
108 | double width, height, paintable_width, paintable_height; |
109 | |
110 | if (gtk_widget_paintable_get_widget (self: GTK_WIDGET_PAINTABLE (ptr: magnifier->paintable)) == NULL) |
111 | return; |
112 | |
113 | width = gtk_widget_get_width (widget); |
114 | height = gtk_widget_get_height (widget); |
115 | paintable_width = gdk_paintable_get_intrinsic_width (paintable: magnifier->paintable); |
116 | paintable_height = gdk_paintable_get_intrinsic_height (paintable: magnifier->paintable); |
117 | if (paintable_width <= 0.0 || paintable_height <= 0.0) |
118 | return; |
119 | |
120 | gtk_snapshot_save (snapshot); |
121 | if (!magnifier->resize) |
122 | gtk_snapshot_translate (snapshot, point: &GRAPHENE_POINT_INIT (width / 2, height / 2)); |
123 | gtk_snapshot_scale (snapshot, factor_x: magnifier->magnification, factor_y: magnifier->magnification); |
124 | gtk_snapshot_translate (snapshot, point: &GRAPHENE_POINT_INIT ( |
125 | - CLAMP (magnifier->x, 0, paintable_width), |
126 | - CLAMP (magnifier->y, 0, paintable_height))); |
127 | |
128 | gdk_paintable_snapshot (paintable: magnifier->paintable, snapshot, width: paintable_width, height: paintable_height); |
129 | gtk_snapshot_restore (snapshot); |
130 | } |
131 | |
132 | static void |
133 | gtk_magnifier_measure (GtkWidget *widget, |
134 | GtkOrientation orientation, |
135 | int for_size, |
136 | int *minimum, |
137 | int *natural, |
138 | int *minimum_baseline, |
139 | int *natural_baseline) |
140 | { |
141 | GtkMagnifier *magnifier = GTK_MAGNIFIER (widget); |
142 | int size; |
143 | |
144 | if (magnifier->resize) |
145 | { |
146 | if (orientation == GTK_ORIENTATION_HORIZONTAL) |
147 | size = magnifier->magnification * gdk_paintable_get_intrinsic_width (paintable: magnifier->paintable); |
148 | else |
149 | size = magnifier->magnification * gdk_paintable_get_intrinsic_height (paintable: magnifier->paintable); |
150 | } |
151 | else |
152 | size = 0; |
153 | |
154 | *minimum = size; |
155 | *natural = size; |
156 | } |
157 | |
158 | static void |
159 | gtk_magnifier_dispose (GObject *object) |
160 | { |
161 | GtkMagnifier *magnifier = GTK_MAGNIFIER (object); |
162 | |
163 | if (magnifier->paintable) |
164 | _gtk_magnifier_set_inspected (magnifier, NULL); |
165 | |
166 | g_clear_object (&magnifier->paintable); |
167 | |
168 | G_OBJECT_CLASS (gtk_magnifier_parent_class)->dispose (object); |
169 | } |
170 | |
171 | static void |
172 | gtk_magnifier_class_init (GtkMagnifierClass *klass) |
173 | { |
174 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
175 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
176 | |
177 | object_class->set_property = _gtk_magnifier_set_property; |
178 | object_class->get_property = _gtk_magnifier_get_property; |
179 | object_class->dispose = gtk_magnifier_dispose; |
180 | |
181 | widget_class->snapshot = gtk_magnifier_snapshot; |
182 | widget_class->measure = gtk_magnifier_measure; |
183 | |
184 | g_object_class_install_property (oclass: object_class, |
185 | property_id: PROP_INSPECTED, |
186 | pspec: g_param_spec_object (name: "inspected" , |
187 | P_("Inspected" ), |
188 | P_("Inspected widget" ), |
189 | GTK_TYPE_WIDGET, |
190 | flags: G_PARAM_READWRITE)); |
191 | g_object_class_install_property (oclass: object_class, |
192 | property_id: PROP_MAGNIFICATION, |
193 | pspec: g_param_spec_double (name: "magnification" , |
194 | P_("magnification" ), |
195 | P_("magnification" ), |
196 | minimum: 1, G_MAXDOUBLE, default_value: 1, |
197 | flags: G_PARAM_READWRITE)); |
198 | g_object_class_install_property (oclass: object_class, |
199 | property_id: PROP_RESIZE, |
200 | pspec: g_param_spec_boolean (name: "resize" , |
201 | P_("resize" ), |
202 | P_("resize" ), |
203 | FALSE, |
204 | flags: G_PARAM_READWRITE)); |
205 | |
206 | gtk_widget_class_set_css_name (widget_class, name: "magnifier" ); |
207 | } |
208 | |
209 | static void |
210 | gtk_magnifier_init (GtkMagnifier *magnifier) |
211 | { |
212 | GtkWidget *widget = GTK_WIDGET (magnifier); |
213 | |
214 | gtk_widget_set_overflow (widget, overflow: GTK_OVERFLOW_HIDDEN); |
215 | |
216 | magnifier->magnification = 1; |
217 | magnifier->resize = FALSE; |
218 | magnifier->paintable = gtk_widget_paintable_new (NULL); |
219 | g_signal_connect_swapped (magnifier->paintable, "invalidate-contents" , G_CALLBACK (gtk_widget_queue_draw), magnifier); |
220 | g_signal_connect_swapped (magnifier->paintable, "invalidate-size" , G_CALLBACK (gtk_widget_queue_resize), magnifier); |
221 | } |
222 | |
223 | GtkWidget * |
224 | _gtk_magnifier_new (GtkWidget *inspected) |
225 | { |
226 | g_return_val_if_fail (GTK_IS_WIDGET (inspected), NULL); |
227 | |
228 | return g_object_new (GTK_TYPE_MAGNIFIER, |
229 | first_property_name: "inspected" , inspected, |
230 | NULL); |
231 | } |
232 | |
233 | GtkWidget * |
234 | _gtk_magnifier_get_inspected (GtkMagnifier *magnifier) |
235 | { |
236 | g_return_val_if_fail (GTK_IS_MAGNIFIER (magnifier), NULL); |
237 | |
238 | return gtk_widget_paintable_get_widget (self: GTK_WIDGET_PAINTABLE (ptr: magnifier->paintable)); |
239 | } |
240 | |
241 | void |
242 | _gtk_magnifier_set_inspected (GtkMagnifier *magnifier, |
243 | GtkWidget *inspected) |
244 | { |
245 | g_return_if_fail (GTK_IS_MAGNIFIER (magnifier)); |
246 | g_return_if_fail (inspected == NULL || GTK_IS_WIDGET (inspected)); |
247 | |
248 | gtk_widget_paintable_set_widget (self: GTK_WIDGET_PAINTABLE (ptr: magnifier->paintable), widget: inspected); |
249 | |
250 | g_object_notify (G_OBJECT (magnifier), property_name: "inspected" ); |
251 | } |
252 | |
253 | void |
254 | _gtk_magnifier_set_coords (GtkMagnifier *magnifier, |
255 | double x, |
256 | double y) |
257 | { |
258 | g_return_if_fail (GTK_IS_MAGNIFIER (magnifier)); |
259 | |
260 | if (magnifier->x == x && magnifier->y == y) |
261 | return; |
262 | |
263 | magnifier->x = x; |
264 | magnifier->y = y; |
265 | |
266 | if (gtk_widget_is_visible (GTK_WIDGET (magnifier))) |
267 | gtk_widget_queue_draw (GTK_WIDGET (magnifier)); |
268 | } |
269 | |
270 | void |
271 | _gtk_magnifier_get_coords (GtkMagnifier *magnifier, |
272 | double *x, |
273 | double *y) |
274 | { |
275 | g_return_if_fail (GTK_IS_MAGNIFIER (magnifier)); |
276 | |
277 | if (x) |
278 | *x = magnifier->x; |
279 | |
280 | if (y) |
281 | *y = magnifier->y; |
282 | } |
283 | |
284 | void |
285 | _gtk_magnifier_set_magnification (GtkMagnifier *magnifier, |
286 | double magnification) |
287 | { |
288 | g_return_if_fail (GTK_IS_MAGNIFIER (magnifier)); |
289 | |
290 | if (magnifier->magnification == magnification) |
291 | return; |
292 | |
293 | magnifier->magnification = magnification; |
294 | g_object_notify (G_OBJECT (magnifier), property_name: "magnification" ); |
295 | |
296 | if (magnifier->resize) |
297 | gtk_widget_queue_resize (GTK_WIDGET (magnifier)); |
298 | |
299 | if (gtk_widget_is_visible (GTK_WIDGET (magnifier))) |
300 | gtk_widget_queue_draw (GTK_WIDGET (magnifier)); |
301 | } |
302 | |
303 | double |
304 | _gtk_magnifier_get_magnification (GtkMagnifier *magnifier) |
305 | { |
306 | g_return_val_if_fail (GTK_IS_MAGNIFIER (magnifier), 1); |
307 | |
308 | return magnifier->magnification; |
309 | } |
310 | |
311 | void |
312 | _gtk_magnifier_set_resize (GtkMagnifier *magnifier, |
313 | gboolean resize) |
314 | { |
315 | g_return_if_fail (GTK_IS_MAGNIFIER (magnifier)); |
316 | |
317 | if (magnifier->resize == resize) |
318 | return; |
319 | |
320 | magnifier->resize = resize; |
321 | |
322 | gtk_widget_queue_resize (GTK_WIDGET (magnifier)); |
323 | } |
324 | |
325 | gboolean |
326 | _gtk_magnifier_get_resize (GtkMagnifier *magnifier) |
327 | { |
328 | g_return_val_if_fail (GTK_IS_MAGNIFIER (magnifier), FALSE); |
329 | |
330 | return magnifier->resize; |
331 | } |
332 | |