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