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