1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpcanvaspen.c
5  * Copyright (C) 2010 Michael Natterer <mitch@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 "libgimpbase/gimpbase.h"
27 #include "libgimpcolor/gimpcolor.h"
28 #include "libgimpmath/gimpmath.h"
29 
30 #include "display-types.h"
31 
32 #include "core/gimpcontext.h"
33 #include "core/gimpparamspecs.h"
34 
35 #include "gimpcanvas-style.h"
36 #include "gimpcanvaspen.h"
37 #include "gimpdisplayshell.h"
38 
39 
40 enum
41 {
42   PROP_0,
43   PROP_COLOR,
44   PROP_WIDTH
45 };
46 
47 
48 typedef struct _GimpCanvasPenPrivate GimpCanvasPenPrivate;
49 
50 struct _GimpCanvasPenPrivate
51 {
52   GimpRGB color;
53   gint    width;
54 };
55 
56 #define GET_PRIVATE(pen) \
57         ((GimpCanvasPenPrivate *) gimp_canvas_pen_get_instance_private ((GimpCanvasPen *) (pen)))
58 
59 
60 /*  local function prototypes  */
61 
62 static void             gimp_canvas_pen_set_property (GObject        *object,
63                                                       guint           property_id,
64                                                       const GValue   *value,
65                                                       GParamSpec     *pspec);
66 static void             gimp_canvas_pen_get_property (GObject        *object,
67                                                       guint           property_id,
68                                                       GValue         *value,
69                                                       GParamSpec     *pspec);
70 static cairo_region_t * gimp_canvas_pen_get_extents  (GimpCanvasItem *item);
71 static void             gimp_canvas_pen_stroke       (GimpCanvasItem *item,
72                                                       cairo_t        *cr);
73 
74 
G_DEFINE_TYPE_WITH_PRIVATE(GimpCanvasPen,gimp_canvas_pen,GIMP_TYPE_CANVAS_POLYGON)75 G_DEFINE_TYPE_WITH_PRIVATE (GimpCanvasPen, gimp_canvas_pen,
76                             GIMP_TYPE_CANVAS_POLYGON)
77 
78 #define parent_class gimp_canvas_pen_parent_class
79 
80 
81 static void
82 gimp_canvas_pen_class_init (GimpCanvasPenClass *klass)
83 {
84   GObjectClass        *object_class = G_OBJECT_CLASS (klass);
85   GimpCanvasItemClass *item_class   = GIMP_CANVAS_ITEM_CLASS (klass);
86 
87   object_class->set_property = gimp_canvas_pen_set_property;
88   object_class->get_property = gimp_canvas_pen_get_property;
89 
90   item_class->get_extents    = gimp_canvas_pen_get_extents;
91   item_class->stroke         = gimp_canvas_pen_stroke;
92 
93   g_object_class_install_property (object_class, PROP_COLOR,
94                                    gimp_param_spec_rgb ("color", NULL, NULL,
95                                                         FALSE, NULL,
96                                                         GIMP_PARAM_READWRITE));
97 
98   g_object_class_install_property (object_class, PROP_WIDTH,
99                                    g_param_spec_int ("width", NULL, NULL,
100                                                      1, G_MAXINT, 1,
101                                                      GIMP_PARAM_READWRITE));
102 }
103 
104 static void
gimp_canvas_pen_init(GimpCanvasPen * pen)105 gimp_canvas_pen_init (GimpCanvasPen *pen)
106 {
107 }
108 
109 static void
gimp_canvas_pen_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)110 gimp_canvas_pen_set_property (GObject      *object,
111                               guint         property_id,
112                               const GValue *value,
113                               GParamSpec   *pspec)
114 {
115   GimpCanvasPenPrivate *private = GET_PRIVATE (object);
116 
117   switch (property_id)
118     {
119     case PROP_COLOR:
120       gimp_value_get_rgb (value, &private->color);
121       break;
122     case PROP_WIDTH:
123       private->width = g_value_get_int (value);
124       break;
125 
126     default:
127       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
128       break;
129     }
130 }
131 
132 static void
gimp_canvas_pen_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)133 gimp_canvas_pen_get_property (GObject    *object,
134                               guint       property_id,
135                               GValue     *value,
136                               GParamSpec *pspec)
137 {
138   GimpCanvasPenPrivate *private = GET_PRIVATE (object);
139 
140   switch (property_id)
141     {
142     case PROP_COLOR:
143       gimp_value_set_rgb (value, &private->color);
144       break;
145     case PROP_WIDTH:
146       g_value_set_int (value, private->width);
147       break;
148 
149     default:
150       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
151       break;
152     }
153 }
154 
155 static cairo_region_t *
gimp_canvas_pen_get_extents(GimpCanvasItem * item)156 gimp_canvas_pen_get_extents (GimpCanvasItem *item)
157 {
158   GimpCanvasPenPrivate *private = GET_PRIVATE (item);
159   cairo_region_t       *region;
160 
161   region = GIMP_CANVAS_ITEM_CLASS (parent_class)->get_extents (item);
162 
163   if (region)
164     {
165       cairo_rectangle_int_t rectangle;
166 
167       cairo_region_get_extents (region, &rectangle);
168 
169       rectangle.x      -= ceil (private->width / 2.0);
170       rectangle.y      -= ceil (private->width / 2.0);
171       rectangle.width  += private->width + 1;
172       rectangle.height += private->width + 1;
173 
174       cairo_region_union_rectangle (region, &rectangle);
175     }
176 
177   return region;
178 }
179 
180 static void
gimp_canvas_pen_stroke(GimpCanvasItem * item,cairo_t * cr)181 gimp_canvas_pen_stroke (GimpCanvasItem *item,
182                         cairo_t        *cr)
183 {
184   GimpCanvasPenPrivate *private = GET_PRIVATE (item);
185 
186   gimp_canvas_set_pen_style (gimp_canvas_item_get_canvas (item), cr,
187                              &private->color, private->width);
188   cairo_stroke (cr);
189 }
190 
191 GimpCanvasItem *
gimp_canvas_pen_new(GimpDisplayShell * shell,const GimpVector2 * points,gint n_points,GimpContext * context,GimpActiveColor color,gint width)192 gimp_canvas_pen_new (GimpDisplayShell  *shell,
193                      const GimpVector2 *points,
194                      gint               n_points,
195                      GimpContext       *context,
196                      GimpActiveColor    color,
197                      gint               width)
198 {
199   GimpCanvasItem *item;
200   GimpArray      *array;
201   GimpRGB         rgb;
202 
203   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), NULL);
204   g_return_val_if_fail (points != NULL && n_points > 1, NULL);
205   g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
206 
207   array = gimp_array_new ((const guint8 *) points,
208                           n_points * sizeof (GimpVector2), TRUE);
209 
210   switch (color)
211     {
212     case GIMP_ACTIVE_COLOR_FOREGROUND:
213       gimp_context_get_foreground (context, &rgb);
214       break;
215 
216     case GIMP_ACTIVE_COLOR_BACKGROUND:
217       gimp_context_get_background (context, &rgb);
218       break;
219     }
220 
221   item = g_object_new (GIMP_TYPE_CANVAS_PEN,
222                        "shell",  shell,
223                        "points", array,
224                        "color",  &rgb,
225                        "width",  width,
226                        NULL);
227 
228   gimp_array_free (array);
229 
230   return item;
231 }
232