Used a static GPtrArray to store line styles
[adg.git] / adg / adg-line-style.c
blobeff260dd9b530396b78bead95c32ec12b595357d
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2008, Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 /**
22 * SECTION:line-style
23 * @title: AdgLineStyle
24 * @short_description: Line style related stuff
26 * Contains parameters on how to draw lines such as width, cap mode, join mode
27 * and dash composition, if used.
30 #include "adg-line-style.h"
31 #include "adg-line-style-private.h"
32 #include "adg-intl.h"
33 #include "adg-util.h"
35 #define PARENT_CLASS ((AdgStyleClass *) adg_line_style_parent_class)
38 enum
40 PROP_0,
41 PROP_WIDTH,
42 PROP_CAP,
43 PROP_JOIN,
44 PROP_MITER_LIMIT,
45 PROP_ANTIALIAS,
46 PROP_DASH
50 static void get_property (GObject *object,
51 guint prop_id,
52 GValue *value,
53 GParamSpec *pspec);
54 static void set_property (GObject *object,
55 guint prop_id,
56 const GValue *value,
57 GParamSpec *pspec);
59 static AdgStyle*from_id (gint id);
60 static void apply (AdgStyle *style,
61 cairo_t *cr);
63 static GPtrArray *pool = NULL;
66 G_DEFINE_TYPE (AdgLineStyle, adg_line_style, ADG_TYPE_STYLE)
69 static void
70 adg_line_style_class_init (AdgLineStyleClass *klass)
72 GObjectClass *gobject_class;
73 AdgStyleClass *style_class;
74 GParamSpec *param;
76 gobject_class = (GObjectClass *) klass;
77 style_class = (AdgStyleClass *) klass;
79 g_type_class_add_private (klass, sizeof (AdgLineStylePrivate));
81 gobject_class->get_property = get_property;
82 gobject_class->set_property = set_property;
84 style_class->from_id = from_id;
85 style_class->apply = apply;
87 param = g_param_spec_double ("width",
88 P_("Line Width"),
89 P_("The line thickness in device unit"),
90 0., G_MAXDOUBLE, 2.,
91 G_PARAM_READWRITE);
92 g_object_class_install_property (gobject_class, PROP_WIDTH, param);
94 param = g_param_spec_int ("cap",
95 P_("Line Cap"),
96 P_("The line cap mode"),
97 G_MININT, G_MAXINT, CAIRO_LINE_CAP_ROUND,
98 G_PARAM_READWRITE);
99 g_object_class_install_property (gobject_class, PROP_CAP, param);
101 param = g_param_spec_int ("join",
102 P_("Line Join"),
103 P_("The line join mode"),
104 G_MININT, G_MAXINT, CAIRO_LINE_JOIN_MITER,
105 G_PARAM_READWRITE);
106 g_object_class_install_property (gobject_class, PROP_JOIN, param);
108 param = g_param_spec_double ("miter-limit",
109 P_("Miter Limit"),
110 P_("Whether the lines should be joined with a bevel instead of a miter"),
111 0., G_MAXDOUBLE, 10.,
112 G_PARAM_READWRITE);
113 g_object_class_install_property (gobject_class, PROP_MITER_LIMIT, param);
115 param = g_param_spec_int ("antialias",
116 P_("Antialiasing Mode"),
117 P_("Type of antialiasing to do when rendering lines"),
118 G_MININT, G_MAXINT, CAIRO_ANTIALIAS_DEFAULT,
119 G_PARAM_READWRITE);
120 g_object_class_install_property (gobject_class, PROP_ANTIALIAS, param);
122 /* TODO: PROP_DASH (PROP_DASHES, PROP_NUM_DASHES, PROP_DASH_OFFSET) */
125 static void
126 adg_line_style_init (AdgLineStyle *line_style)
128 AdgLineStylePrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (line_style,
129 ADG_TYPE_LINE_STYLE,
130 AdgLineStylePrivate);
132 priv->width = 2.;
133 priv->cap = CAIRO_LINE_CAP_ROUND;
134 priv->join = CAIRO_LINE_JOIN_MITER;
135 priv->miter_limit = 10.;
136 priv->antialias = CAIRO_ANTIALIAS_DEFAULT;
137 priv->dashes = NULL;
138 priv->num_dashes = 0;
139 priv->dash_offset = 0.;
141 line_style->priv = priv;
144 static void
145 get_property (GObject *object,
146 guint prop_id,
147 GValue *value,
148 GParamSpec *pspec)
150 AdgLineStyle *line_style = (AdgLineStyle *) object;
152 switch (prop_id)
154 case PROP_WIDTH:
155 g_value_set_double (value, line_style->priv->width);
156 break;
157 case PROP_CAP:
158 g_value_set_int (value, line_style->priv->cap);
159 break;
160 case PROP_JOIN:
161 g_value_set_int (value, line_style->priv->join);
162 break;
163 case PROP_MITER_LIMIT:
164 g_value_set_double (value, line_style->priv->miter_limit);
165 break;
166 case PROP_ANTIALIAS:
167 g_value_set_int (value, line_style->priv->antialias);
168 break;
169 case PROP_DASH:
170 /* TODO */
171 break;
172 default:
173 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
174 break;
178 static void
179 set_property (GObject *object,
180 guint prop_id,
181 const GValue *value,
182 GParamSpec *pspec)
184 AdgLineStyle *line_style = (AdgLineStyle *) object;
186 switch (prop_id)
188 case PROP_WIDTH:
189 line_style->priv->width = g_value_get_double (value);
190 break;
191 case PROP_CAP:
192 line_style->priv->cap = g_value_get_int (value);
193 break;
194 case PROP_JOIN:
195 line_style->priv->join = g_value_get_int (value);
196 break;
197 case PROP_MITER_LIMIT:
198 line_style->priv->miter_limit = g_value_get_double (value);
199 break;
200 case PROP_ANTIALIAS:
201 line_style->priv->antialias = g_value_get_int (value);
202 break;
203 case PROP_DASH:
204 /* TODO */
205 break;
206 default:
207 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
208 break;
214 * adg_line_style_new:
216 * Constructs a new line style initialized with default params.
218 * Return value: a new line style
220 AdgStyle *
221 adg_line_style_new (void)
223 return g_object_new (ADG_TYPE_LINE_STYLE, NULL);
227 * adg_line_style_get_width:
228 * @line_style: an #AdgLineStyle object
230 * Gets the line thickness value (in paper units).
232 * Return value: the requested width
234 gdouble
235 adg_line_style_get_width (AdgLineStyle *line_style)
237 g_return_val_if_fail (ADG_IS_LINE_STYLE (line_style), 0.);
239 return line_style->priv->width;
243 * adg_line_style_set_width:
244 * @line_style: an #AdgLineStyle object
245 * @width: the new width
247 * Sets a new line thickness value.
249 void
250 adg_line_style_set_width (AdgLineStyle *line_style,
251 gdouble width)
253 g_return_if_fail (ADG_IS_LINE_STYLE (line_style));
255 line_style->priv->width = width;
256 g_object_notify ((GObject *) line_style, "width");
260 * adg_line_style_get_cap:
261 * @line_style: an #AdgLineStyle object
263 * Gets the line cap mode.
265 * Return value: the requested line cap mode
267 cairo_line_cap_t
268 adg_line_style_get_cap (AdgLineStyle *line_style)
270 g_return_val_if_fail (ADG_IS_LINE_STYLE (line_style), CAIRO_LINE_CAP_BUTT);
272 return line_style->priv->cap;
276 * adg_line_style_set_cap:
277 * @line_style: an #AdgLineStyle object
278 * @cap: the new cap mode
280 * Sets a new line cap mode.
282 void
283 adg_line_style_set_cap (AdgLineStyle *line_style,
284 cairo_line_cap_t cap)
286 g_return_if_fail (ADG_IS_LINE_STYLE (line_style));
288 line_style->priv->cap = cap;
289 g_object_notify ((GObject *) line_style, "cap");
293 * adg_line_style_get_join:
294 * @line_style: an #AdgLineStyle object
296 * Gets the line join mode.
298 * Return value: the requested line join mode
300 cairo_line_join_t
301 adg_line_style_get_join (AdgLineStyle *line_style)
303 g_return_val_if_fail (ADG_IS_LINE_STYLE (line_style), CAIRO_LINE_JOIN_MITER);
305 return line_style->priv->join;
309 * adg_line_style_set_join:
310 * @line_style: an #AdgLineStyle object
311 * @join: the new join mode
313 * Sets a new line join mode.
315 void
316 adg_line_style_set_join (AdgLineStyle *line_style,
317 cairo_line_join_t join)
319 g_return_if_fail (ADG_IS_LINE_STYLE (line_style));
321 line_style->priv->join = join;
322 g_object_notify ((GObject *) line_style, "join");
326 * adg_line_style_get_miter_limit:
327 * @line_style: an #AdgLineStyle object
329 * Gets the line miter limit value. The miter limit is used to determine
330 * whether the lines should be joined with a bevel instead of a miter.
332 * Return value: the requested miter limit
334 gdouble
335 adg_line_style_get_miter_limit (AdgLineStyle *line_style)
337 g_return_val_if_fail (ADG_IS_LINE_STYLE (line_style), 0.);
339 return line_style->priv->miter_limit;
343 * adg_line_style_set_miter_limit:
344 * @line_style: an #AdgLineStyle object
345 * @miter_limit: the new miter limit
347 * Sets a new miter limit value.
349 void
350 adg_line_style_set_miter_limit (AdgLineStyle *line_style,
351 gdouble miter_limit)
353 g_return_if_fail (ADG_IS_LINE_STYLE (line_style));
355 line_style->priv->miter_limit = miter_limit;
356 g_object_notify ((GObject *) line_style, "miter-limit");
360 * adg_line_style_get_antialias:
361 * @line_style: an #AdgLineStyle object
363 * Gets the antialias mode used.
365 * Return value: the requested antialias mode
367 cairo_antialias_t
368 adg_line_style_get_antialias (AdgLineStyle *line_style)
370 g_return_val_if_fail (ADG_IS_LINE_STYLE (line_style), CAIRO_ANTIALIAS_DEFAULT);
372 return line_style->priv->antialias;
376 * adg_line_style_set_antialias:
377 * @line_style: an #AdgLineStyle object
378 * @antialias: the new antialias mode
380 * Sets a new antialias mode.
382 void
383 adg_line_style_set_antialias (AdgLineStyle *line_style,
384 cairo_antialias_t antialias)
386 g_return_if_fail (ADG_IS_LINE_STYLE (line_style));
388 line_style->priv->antialias = antialias;
389 g_object_notify ((GObject *) line_style, "antialias");
393 static AdgStyle *
394 from_id (gint id)
396 if G_UNLIKELY (pool == NULL)
398 cairo_pattern_t *pattern;
400 pool = g_ptr_array_sized_new (ADG_LINE_STYLE_LAST);
402 pool->pdata[ADG_LINE_STYLE_DRAW] = g_object_new (ADG_TYPE_LINE_STYLE,
403 "width", 2.,
404 NULL);
406 pattern = cairo_pattern_create_rgb (0., 1., 0.);
407 pool->pdata[ADG_LINE_STYLE_CENTER] = g_object_new (ADG_TYPE_LINE_STYLE,
408 "pattern", pattern,
409 "width", 0.75,
410 NULL);
411 cairo_pattern_destroy (pattern);
413 pattern = cairo_pattern_create_rgba (0., 0., 0., 0.5);
414 pool->pdata[ADG_LINE_STYLE_HIDDEN] = g_object_new (ADG_TYPE_LINE_STYLE,
415 "pattern", pattern,
416 "width", 0.75,
417 NULL);
418 cairo_pattern_destroy (pattern);
420 pattern = cairo_pattern_create_rgb (0., 0., 1.);
421 pool->pdata[ADG_LINE_STYLE_XATCH] = g_object_new (ADG_TYPE_LINE_STYLE,
422 "pattern", pattern,
423 "width", 1.25,
424 NULL);
425 cairo_pattern_destroy (pattern);
427 pool->pdata[ADG_LINE_STYLE_DIM] = g_object_new (ADG_TYPE_LINE_STYLE,
428 "width", 0.75,
429 NULL);
431 pool->len = ADG_LINE_STYLE_LAST;
434 g_return_val_if_fail (id < pool->len, NULL);
435 return (AdgStyle *) g_ptr_array_index (pool, id);
438 static void
439 apply (AdgStyle *style,
440 cairo_t *cr)
442 AdgLineStyle *line_style;
443 gdouble device_width;
444 gdouble dummy = 0.;
446 line_style = (AdgLineStyle *) style;
448 PARENT_CLASS->apply (style, cr);
450 device_width = line_style->priv->width;
451 cairo_device_to_user_distance (cr, &device_width, &dummy);
452 cairo_set_line_width (cr, device_width);
454 cairo_set_line_cap (cr, line_style->priv->cap);
455 cairo_set_line_join (cr, line_style->priv->join);
456 cairo_set_miter_limit (cr, line_style->priv->miter_limit);
457 cairo_set_antialias (cr, line_style->priv->antialias);
459 if (line_style->priv->num_dashes > 0)
461 g_return_if_fail (line_style->priv->dashes != NULL);
463 cairo_set_dash (cr, line_style->priv->dashes, line_style->priv->num_dashes,
464 line_style->priv->dash_offset);