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
G_DEFINE_TYPE(GtkMagnifier,gtk_magnifier,GTK_TYPE_WIDGET)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, g_value_get_object (value));
61 break;
62
63 case PROP_MAGNIFICATION:
64 _gtk_magnifier_set_magnification (magnifier, g_value_get_double (value));
65 break;
66
67 case PROP_RESIZE:
68 _gtk_magnifier_set_resize (magnifier, 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
_gtk_magnifier_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)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, gtk_widget_paintable_get_widget (GTK_WIDGET_PAINTABLE (magnifier->paintable)));
88 break;
89
90 case PROP_MAGNIFICATION:
91 g_value_set_double (value, magnifier->magnification);
92 break;
93
94 case PROP_RESIZE:
95 g_value_set_boolean (value, magnifier->resize);
96 break;
97
98 default:
99 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
100 }
101 }
102
103 static void
gtk_magnifier_snapshot(GtkWidget * widget,GtkSnapshot * snapshot)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 (GTK_WIDGET_PAINTABLE (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 (magnifier->paintable);
116 paintable_height = gdk_paintable_get_intrinsic_height (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, &GRAPHENE_POINT_INIT (width / 2, height / 2));
123 gtk_snapshot_scale (snapshot, magnifier->magnification, magnifier->magnification);
124 gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (
125 - CLAMP (magnifier->x, 0, paintable_width),
126 - CLAMP (magnifier->y, 0, paintable_height)));
127
128 gdk_paintable_snapshot (magnifier->paintable, snapshot, paintable_width, paintable_height);
129 gtk_snapshot_restore (snapshot);
130 }
131
132 static void
gtk_magnifier_measure(GtkWidget * widget,GtkOrientation orientation,int for_size,int * minimum,int * natural,int * minimum_baseline,int * natural_baseline)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 (magnifier->paintable);
148 else
149 size = magnifier->magnification * gdk_paintable_get_intrinsic_height (magnifier->paintable);
150 }
151 else
152 size = 0;
153
154 *minimum = size;
155 *natural = size;
156 }
157
158 static void
gtk_magnifier_dispose(GObject * object)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
gtk_magnifier_class_init(GtkMagnifierClass * klass)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 (object_class,
185 PROP_INSPECTED,
186 g_param_spec_object ("inspected",
187 P_("Inspected"),
188 P_("Inspected widget"),
189 GTK_TYPE_WIDGET,
190 G_PARAM_READWRITE));
191 g_object_class_install_property (object_class,
192 PROP_MAGNIFICATION,
193 g_param_spec_double ("magnification",
194 P_("magnification"),
195 P_("magnification"),
196 1, G_MAXDOUBLE, 1,
197 G_PARAM_READWRITE));
198 g_object_class_install_property (object_class,
199 PROP_RESIZE,
200 g_param_spec_boolean ("resize",
201 P_("resize"),
202 P_("resize"),
203 FALSE,
204 G_PARAM_READWRITE));
205
206 gtk_widget_class_set_css_name (widget_class, "magnifier");
207 }
208
209 static void
gtk_magnifier_init(GtkMagnifier * magnifier)210 gtk_magnifier_init (GtkMagnifier *magnifier)
211 {
212 GtkWidget *widget = GTK_WIDGET (magnifier);
213
214 gtk_widget_set_overflow (widget, 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 *
_gtk_magnifier_new(GtkWidget * inspected)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 "inspected", inspected,
230 NULL);
231 }
232
233 GtkWidget *
_gtk_magnifier_get_inspected(GtkMagnifier * magnifier)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 (GTK_WIDGET_PAINTABLE (magnifier->paintable));
239 }
240
241 void
_gtk_magnifier_set_inspected(GtkMagnifier * magnifier,GtkWidget * inspected)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 (GTK_WIDGET_PAINTABLE (magnifier->paintable), inspected);
249
250 g_object_notify (G_OBJECT (magnifier), "inspected");
251 }
252
253 void
_gtk_magnifier_set_coords(GtkMagnifier * magnifier,double x,double y)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
_gtk_magnifier_get_coords(GtkMagnifier * magnifier,double * x,double * y)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
_gtk_magnifier_set_magnification(GtkMagnifier * magnifier,double magnification)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), "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
_gtk_magnifier_get_magnification(GtkMagnifier * magnifier)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
_gtk_magnifier_set_resize(GtkMagnifier * magnifier,gboolean resize)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
_gtk_magnifier_get_resize(GtkMagnifier * magnifier)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