1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpcanvascursor.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 "libgimpmath/gimpmath.h"
28 
29 #include "display-types.h"
30 
31 #include "core/gimp-cairo.h"
32 
33 #include "gimpcanvascursor.h"
34 #include "gimpdisplayshell.h"
35 
36 
37 #define GIMP_CURSOR_SIZE 7
38 
39 
40 enum
41 {
42   PROP_0,
43   PROP_X,
44   PROP_Y
45 };
46 
47 
48 typedef struct _GimpCanvasCursorPrivate GimpCanvasCursorPrivate;
49 
50 struct _GimpCanvasCursorPrivate
51 {
52   gdouble x;
53   gdouble y;
54 };
55 
56 #define GET_PRIVATE(cursor) \
57         ((GimpCanvasCursorPrivate *) gimp_canvas_cursor_get_instance_private ((GimpCanvasCursor *) (cursor)))
58 
59 
60 /*  local function prototypes  */
61 
62 static void             gimp_canvas_cursor_set_property (GObject        *object,
63                                                          guint           property_id,
64                                                          const GValue   *value,
65                                                          GParamSpec     *pspec);
66 static void             gimp_canvas_cursor_get_property (GObject        *object,
67                                                          guint           property_id,
68                                                          GValue         *value,
69                                                          GParamSpec     *pspec);
70 static void             gimp_canvas_cursor_draw         (GimpCanvasItem *item,
71                                                          cairo_t        *cr);
72 static cairo_region_t * gimp_canvas_cursor_get_extents  (GimpCanvasItem *item);
73 
74 
G_DEFINE_TYPE_WITH_PRIVATE(GimpCanvasCursor,gimp_canvas_cursor,GIMP_TYPE_CANVAS_ITEM)75 G_DEFINE_TYPE_WITH_PRIVATE (GimpCanvasCursor, gimp_canvas_cursor,
76                             GIMP_TYPE_CANVAS_ITEM)
77 
78 #define parent_class gimp_canvas_cursor_parent_class
79 
80 
81 static void
82 gimp_canvas_cursor_class_init (GimpCanvasCursorClass *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_cursor_set_property;
88   object_class->get_property = gimp_canvas_cursor_get_property;
89 
90   item_class->draw           = gimp_canvas_cursor_draw;
91   item_class->get_extents    = gimp_canvas_cursor_get_extents;
92 
93   g_object_class_install_property (object_class, PROP_X,
94                                    g_param_spec_double ("x", NULL, NULL,
95                                                         -GIMP_MAX_IMAGE_SIZE,
96                                                         GIMP_MAX_IMAGE_SIZE, 0,
97                                                         GIMP_PARAM_READWRITE));
98 
99   g_object_class_install_property (object_class, PROP_Y,
100                                    g_param_spec_double ("y", NULL, NULL,
101                                                         -GIMP_MAX_IMAGE_SIZE,
102                                                         GIMP_MAX_IMAGE_SIZE, 0,
103                                                         GIMP_PARAM_READWRITE));
104 }
105 
106 static void
gimp_canvas_cursor_init(GimpCanvasCursor * cursor)107 gimp_canvas_cursor_init (GimpCanvasCursor *cursor)
108 {
109   gimp_canvas_item_set_line_cap (GIMP_CANVAS_ITEM (cursor),
110                                  CAIRO_LINE_CAP_SQUARE);
111 }
112 
113 static void
gimp_canvas_cursor_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)114 gimp_canvas_cursor_set_property (GObject      *object,
115                                  guint         property_id,
116                                  const GValue *value,
117                                  GParamSpec   *pspec)
118 {
119   GimpCanvasCursorPrivate *private = GET_PRIVATE (object);
120 
121   switch (property_id)
122     {
123     case PROP_X:
124       private->x = g_value_get_double (value);
125       break;
126     case PROP_Y:
127       private->y = g_value_get_double (value);
128       break;
129 
130     default:
131       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
132       break;
133     }
134 }
135 
136 static void
gimp_canvas_cursor_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)137 gimp_canvas_cursor_get_property (GObject    *object,
138                                  guint       property_id,
139                                  GValue     *value,
140                                  GParamSpec *pspec)
141 {
142   GimpCanvasCursorPrivate *private = GET_PRIVATE (object);
143 
144   switch (property_id)
145     {
146     case PROP_X:
147       g_value_set_double (value, private->x);
148       break;
149     case PROP_Y:
150       g_value_set_double (value, private->y);
151       break;
152 
153     default:
154       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
155       break;
156     }
157 }
158 
159 static void
gimp_canvas_cursor_draw(GimpCanvasItem * item,cairo_t * cr)160 gimp_canvas_cursor_draw (GimpCanvasItem *item,
161                          cairo_t        *cr)
162 {
163   GimpCanvasCursorPrivate *private = GET_PRIVATE (item);
164   gdouble                  x, y;
165 
166   x = floor (private->x) + 0.5;
167   y = floor (private->y) + 0.5;
168 
169   cairo_move_to (cr, x - GIMP_CURSOR_SIZE, y);
170   cairo_line_to (cr, x + GIMP_CURSOR_SIZE, y);
171 
172   cairo_move_to (cr, x, y - GIMP_CURSOR_SIZE);
173   cairo_line_to (cr, x, y + GIMP_CURSOR_SIZE);
174 
175   _gimp_canvas_item_stroke (item, cr);
176 }
177 
178 static cairo_region_t *
gimp_canvas_cursor_get_extents(GimpCanvasItem * item)179 gimp_canvas_cursor_get_extents (GimpCanvasItem *item)
180 {
181   GimpCanvasCursorPrivate *private = GET_PRIVATE (item);
182   cairo_rectangle_int_t    rectangle;
183   gdouble                  x, y;
184 
185   x = floor (private->x) + 0.5;
186   y = floor (private->y) + 0.5;
187 
188   rectangle.x      = floor (x - GIMP_CURSOR_SIZE - 1.5);
189   rectangle.y      = floor (y - GIMP_CURSOR_SIZE - 1.5);
190   rectangle.width  = ceil (x + GIMP_CURSOR_SIZE + 1.5) - rectangle.x;
191   rectangle.height = ceil (y + GIMP_CURSOR_SIZE + 1.5) - rectangle.y;
192 
193   return cairo_region_create_rectangle (&rectangle);
194 }
195 
196 GimpCanvasItem *
gimp_canvas_cursor_new(GimpDisplayShell * shell)197 gimp_canvas_cursor_new (GimpDisplayShell *shell)
198 {
199   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), NULL);
200 
201   return g_object_new (GIMP_TYPE_CANVAS_CURSOR,
202                        "shell", shell,
203                        NULL);
204 }
205 
206 void
gimp_canvas_cursor_set(GimpCanvasItem * cursor,gdouble x,gdouble y)207 gimp_canvas_cursor_set (GimpCanvasItem *cursor,
208                         gdouble         x,
209                         gdouble         y)
210 {
211   GimpCanvasCursorPrivate *private;
212 
213   g_return_if_fail (GIMP_IS_CANVAS_CURSOR (cursor));
214 
215   private = GET_PRIVATE (cursor);
216 
217   if (private->x != x || private->y != y)
218     {
219       gimp_canvas_item_begin_change (cursor);
220 
221       g_object_set (cursor,
222                     "x", x,
223                     "y", y,
224                     NULL);
225 
226       gimp_canvas_item_end_change (cursor);
227     }
228 }
229