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