1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpcanvaspassepartout.c
5 * Copyright (C) 2010 Sven Neumann <sven@gimp.org>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <gegl.h>
24 #include <gtk/gtk.h>
25
26 #include "display-types.h"
27
28 #include "gimpcanvas-style.h"
29 #include "gimpcanvasitem-utils.h"
30 #include "gimpcanvaspassepartout.h"
31 #include "gimpdisplayshell.h"
32 #include "gimpdisplayshell-scale.h"
33
34
35 enum
36 {
37 PROP_0,
38 PROP_OPACITY,
39 };
40
41
42 typedef struct _GimpCanvasPassePartoutPrivate GimpCanvasPassePartoutPrivate;
43
44 struct _GimpCanvasPassePartoutPrivate
45 {
46 gdouble opacity;
47 };
48
49 #define GET_PRIVATE(item) \
50 ((GimpCanvasPassePartoutPrivate *) gimp_canvas_passe_partout_get_instance_private ((GimpCanvasPassePartout *) (item)))
51
52
53 /* local function prototypes */
54
55 static void gimp_canvas_passe_partout_set_property (GObject *object,
56 guint property_id,
57 const GValue *value,
58 GParamSpec *pspec);
59 static void gimp_canvas_passe_partout_get_property (GObject *object,
60 guint property_id,
61 GValue *value,
62 GParamSpec *pspec);
63 static void gimp_canvas_passe_partout_draw (GimpCanvasItem *item,
64 cairo_t *cr);
65 static cairo_region_t * gimp_canvas_passe_partout_get_extents (GimpCanvasItem *item);
66 static void gimp_canvas_passe_partout_fill (GimpCanvasItem *item,
67 cairo_t *cr);
68
69
G_DEFINE_TYPE_WITH_PRIVATE(GimpCanvasPassePartout,gimp_canvas_passe_partout,GIMP_TYPE_CANVAS_RECTANGLE)70 G_DEFINE_TYPE_WITH_PRIVATE (GimpCanvasPassePartout, gimp_canvas_passe_partout,
71 GIMP_TYPE_CANVAS_RECTANGLE)
72
73 #define parent_class gimp_canvas_passe_partout_parent_class
74
75
76 static void
77 gimp_canvas_passe_partout_class_init (GimpCanvasPassePartoutClass *klass)
78 {
79 GObjectClass *object_class = G_OBJECT_CLASS (klass);
80 GimpCanvasItemClass *item_class = GIMP_CANVAS_ITEM_CLASS (klass);
81
82 object_class->set_property = gimp_canvas_passe_partout_set_property;
83 object_class->get_property = gimp_canvas_passe_partout_get_property;
84
85 item_class->draw = gimp_canvas_passe_partout_draw;
86 item_class->get_extents = gimp_canvas_passe_partout_get_extents;
87 item_class->fill = gimp_canvas_passe_partout_fill;
88
89 g_object_class_install_property (object_class, PROP_OPACITY,
90 g_param_spec_double ("opacity", NULL, NULL,
91 0.0,
92 1.0, 0.5,
93 GIMP_PARAM_READWRITE));
94 }
95
96 static void
gimp_canvas_passe_partout_init(GimpCanvasPassePartout * passe_partout)97 gimp_canvas_passe_partout_init (GimpCanvasPassePartout *passe_partout)
98 {
99 }
100
101 static void
gimp_canvas_passe_partout_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)102 gimp_canvas_passe_partout_set_property (GObject *object,
103 guint property_id,
104 const GValue *value,
105 GParamSpec *pspec)
106 {
107 GimpCanvasPassePartoutPrivate *priv = GET_PRIVATE (object);
108
109 switch (property_id)
110 {
111 case PROP_OPACITY:
112 priv->opacity = g_value_get_double (value);
113 break;
114
115 default:
116 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
117 break;
118 }
119 }
120
121 static void
gimp_canvas_passe_partout_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)122 gimp_canvas_passe_partout_get_property (GObject *object,
123 guint property_id,
124 GValue *value,
125 GParamSpec *pspec)
126 {
127 GimpCanvasPassePartoutPrivate *priv = GET_PRIVATE (object);
128
129 switch (property_id)
130 {
131 case PROP_OPACITY:
132 g_value_set_double (value, priv->opacity);
133 break;
134
135 default:
136 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
137 break;
138 }
139 }
140
141 static void
gimp_canvas_passe_partout_draw(GimpCanvasItem * item,cairo_t * cr)142 gimp_canvas_passe_partout_draw (GimpCanvasItem *item,
143 cairo_t *cr)
144 {
145 GimpDisplayShell *shell = gimp_canvas_item_get_shell (item);
146 gint x, y;
147 gint w, h;
148
149 if (! gimp_display_shell_get_infinite_canvas (shell))
150 {
151 x = -shell->offset_x;
152 y = -shell->offset_y;
153
154 gimp_display_shell_scale_get_image_size (shell, &w, &h);
155 }
156 else
157 {
158 gimp_canvas_item_untransform_viewport (item, &x, &y, &w, &h);
159 }
160
161 cairo_rectangle (cr, x, y, w, h);
162
163 GIMP_CANVAS_ITEM_CLASS (parent_class)->draw (item, cr);
164 }
165
166 static cairo_region_t *
gimp_canvas_passe_partout_get_extents(GimpCanvasItem * item)167 gimp_canvas_passe_partout_get_extents (GimpCanvasItem *item)
168 {
169 GimpDisplayShell *shell = gimp_canvas_item_get_shell (item);
170 cairo_rectangle_int_t rectangle;
171
172 if (! gimp_display_shell_get_infinite_canvas (shell))
173 {
174 cairo_region_t *inner;
175 cairo_region_t *outer;
176
177 rectangle.x = - shell->offset_x;
178 rectangle.y = - shell->offset_y;
179 gimp_display_shell_scale_get_image_size (shell,
180 &rectangle.width,
181 &rectangle.height);
182
183 outer = cairo_region_create_rectangle (&rectangle);
184
185 inner = GIMP_CANVAS_ITEM_CLASS (parent_class)->get_extents (item);
186
187 cairo_region_xor (outer, inner);
188
189 cairo_region_destroy (inner);
190
191 return outer;
192 }
193 else
194 {
195 gimp_canvas_item_untransform_viewport (item,
196 &rectangle.x,
197 &rectangle.y,
198 &rectangle.width,
199 &rectangle.height);
200
201 return cairo_region_create_rectangle (&rectangle);
202 }
203 }
204
205 static void
gimp_canvas_passe_partout_fill(GimpCanvasItem * item,cairo_t * cr)206 gimp_canvas_passe_partout_fill (GimpCanvasItem *item,
207 cairo_t *cr)
208 {
209 GimpCanvasPassePartoutPrivate *priv = GET_PRIVATE (item);
210
211 cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
212 cairo_clip (cr);
213
214 gimp_canvas_set_passe_partout_style (gimp_canvas_item_get_canvas (item), cr);
215 cairo_paint_with_alpha (cr, priv->opacity);
216 }
217
218 GimpCanvasItem *
gimp_canvas_passe_partout_new(GimpDisplayShell * shell,gdouble x,gdouble y,gdouble width,gdouble height)219 gimp_canvas_passe_partout_new (GimpDisplayShell *shell,
220 gdouble x,
221 gdouble y,
222 gdouble width,
223 gdouble height)
224 {
225 g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), NULL);
226
227 return g_object_new (GIMP_TYPE_CANVAS_PASSE_PARTOUT,
228 "shell", shell,
229 "x", x,
230 "y", y,
231 "width", width,
232 "height", height,
233 "filled", TRUE,
234 NULL);
235 }
236