1 /*
2 * goc-circle.c :
3 *
4 * Copyright (C) 2009 Jean Brefort (jean.brefort@normalesup.org)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 #include <goffice/goffice-config.h>
23 #include <goffice/goffice.h>
24 #include <gsf/gsf-impl-utils.h>
25
26 #include <glib/gi18n-lib.h>
27 #include <gsf/gsf-impl-utils.h>
28
29 /**
30 * SECTION:goc-circle
31 * @short_description: Circle.
32 *
33 * #GocCircle implements circle drawing in the canvas.
34 **/
35
36 static GocItemClass *parent_class;
37
38 enum {
39 CIRCLE_PROP_0,
40 CIRCLE_PROP_X,
41 CIRCLE_PROP_Y,
42 CIRCLE_PROP_R
43 };
44
45 static void
goc_circle_set_property(GObject * gobject,guint param_id,GValue const * value,GParamSpec * pspec)46 goc_circle_set_property (GObject *gobject, guint param_id,
47 GValue const *value, GParamSpec *pspec)
48 {
49 GocCircle *circle = GOC_CIRCLE (gobject);
50
51 switch (param_id) {
52 case CIRCLE_PROP_X:
53 circle->x = g_value_get_double (value);
54 break;
55
56 case CIRCLE_PROP_Y:
57 circle->y = g_value_get_double (value);
58 break;
59
60 case CIRCLE_PROP_R:
61 circle->radius = g_value_get_double (value);
62 break;
63
64 default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
65 return; /* NOTE : RETURN */
66 }
67 goc_item_bounds_changed (GOC_ITEM (gobject));
68 }
69
70 static void
goc_circle_get_property(GObject * gobject,guint param_id,GValue * value,GParamSpec * pspec)71 goc_circle_get_property (GObject *gobject, guint param_id,
72 GValue *value, GParamSpec *pspec)
73 {
74 GocCircle *circle = GOC_CIRCLE (gobject);
75
76 switch (param_id) {
77 case CIRCLE_PROP_X:
78 g_value_set_double (value, circle->x);
79 break;
80
81 case CIRCLE_PROP_Y:
82 g_value_set_double (value, circle->y);
83 break;
84
85 case CIRCLE_PROP_R:
86 g_value_set_double (value, circle->radius);
87 break;
88
89 default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
90 return; /* NOTE : RETURN */
91 }
92 }
93
94 static double
goc_circle_outline_extra_radius(GocItem * item)95 goc_circle_outline_extra_radius (GocItem *item)
96 {
97 GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
98
99 if (style->line.dash_type == GO_LINE_NONE)
100 return 0;
101
102 /* FIXME take transform into account */
103 return style->line.width > 0 ? style->line.width / 2. : .5;
104 }
105
106 static double
goc_circle_distance(GocItem * item,double x,double y,GocItem ** near_item)107 goc_circle_distance (GocItem *item, double x, double y, GocItem **near_item)
108 {
109 GocCircle *circle = GOC_CIRCLE (item);
110 double d, extra_dist = goc_circle_outline_extra_radius (item);
111 *near_item = item;
112 x -= circle->x;
113 y -= circle->y;
114 d = sqrt (x * x + y * y);
115 return MAX (d - circle->radius - extra_dist, 0);
116 }
117
118 static void
goc_circle_draw(GocItem const * item,cairo_t * cr)119 goc_circle_draw (GocItem const *item, cairo_t *cr)
120 {
121 GocCircle *circle = GOC_CIRCLE (item);
122 double scale = (circle->radius > 0.)? circle->radius: 1.e-10;
123
124 cairo_save (cr);
125 _goc_item_transform (item, cr, TRUE);
126 goc_group_cairo_transform (item->parent, cr, circle->x, circle->y);
127 cairo_scale (cr, scale, scale);
128 cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI);
129 cairo_restore (cr);
130 /* Fill the shape */
131 go_styled_object_fill (GO_STYLED_OBJECT (item), cr, TRUE);
132 /* Draw the line */
133 if (goc_styled_item_set_cairo_line (GOC_STYLED_ITEM (item), cr))
134 cairo_stroke (cr);
135 else
136 cairo_new_path (cr);
137 }
138
139 static void
goc_circle_update_bounds(GocItem * item)140 goc_circle_update_bounds (GocItem *item)
141 {
142 GocCircle *circle = GOC_CIRCLE (item);
143 double r = circle->radius + goc_circle_outline_extra_radius (item);
144 item->x0 = circle->x - r;
145 item->y0 = circle->y - r;
146 item->x1 = circle->x + r;
147 item->y1 = circle->y + r;
148 }
149
150 static void
goc_circle_copy(GocItem * dest,GocItem * source)151 goc_circle_copy (GocItem *dest, GocItem *source)
152 {
153 GocCircle *src = GOC_CIRCLE (source), *dst = GOC_CIRCLE (dest);
154
155 dst->x = src->x;
156 dst->y = src->y;
157 dst->radius = src->radius;
158 parent_class->copy (dest, source);
159 }
160
161 static void
goc_circle_init_style(G_GNUC_UNUSED GocStyledItem * item,GOStyle * style)162 goc_circle_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
163 {
164 style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL;
165 if (style->line.auto_dash)
166 style->line.dash_type = GO_LINE_SOLID;
167 if (style->line.auto_color)
168 style->line.color = GO_COLOR_BLACK;
169 if (style->fill.auto_type)
170 style->fill.type = GO_STYLE_FILL_PATTERN;
171 if (style->fill.auto_fore)
172 style->fill.pattern.fore = GO_COLOR_BLACK;
173 if (style->fill.auto_back)
174 style->fill.pattern.back = GO_COLOR_WHITE;
175 }
176
177 static void
goc_circle_class_init(GocItemClass * item_klass)178 goc_circle_class_init (GocItemClass *item_klass)
179 {
180 GObjectClass *obj_klass = (GObjectClass *) item_klass;
181 GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
182 parent_class = g_type_class_peek_parent (item_klass);
183
184 obj_klass->get_property = goc_circle_get_property;
185 obj_klass->set_property = goc_circle_set_property;
186 g_object_class_install_property (obj_klass, CIRCLE_PROP_X,
187 g_param_spec_double ("x",
188 _("x"),
189 _("The circle center horizontal position"),
190 -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
191 GSF_PARAM_STATIC | G_PARAM_READWRITE));
192 g_object_class_install_property (obj_klass, CIRCLE_PROP_Y,
193 g_param_spec_double ("y",
194 _("y"),
195 _("The circle center vertical position"),
196 -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
197 GSF_PARAM_STATIC | G_PARAM_READWRITE));
198 g_object_class_install_property (obj_klass, CIRCLE_PROP_R,
199 g_param_spec_double ("radius",
200 _("Radius"),
201 _("The circle radius"),
202 0., G_MAXDOUBLE, 0.,
203 GSF_PARAM_STATIC | G_PARAM_READWRITE));
204
205 gsi_klass->init_style = goc_circle_init_style;
206
207 item_klass->distance = goc_circle_distance;
208 item_klass->draw = goc_circle_draw;
209 item_klass->copy = goc_circle_copy;
210 item_klass->update_bounds = goc_circle_update_bounds;
211 }
212
213 GSF_CLASS (GocCircle, goc_circle,
214 goc_circle_class_init, NULL,
215 GOC_TYPE_STYLED_ITEM)
216