[AdgArrowStyle] Hidden private struct
[adg.git] / adg / adg-line-style.c
blob20b12d63ef19155980f1794c3f674285146a7d6f
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009 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 Lesser 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 * Lesser 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., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
20 /**
21 * SECTION:line-style
22 * @title: AdgLineStyle
23 * @short_description: Line style related stuff
25 * Contains parameters on how to draw lines such as width, cap mode, join mode
26 * and dash composition, if used.
29 #include "adg-line-style.h"
30 #include "adg-line-style-private.h"
31 #include "adg-context.h"
32 #include "adg-intl.h"
33 #include "adg-util.h"
36 enum {
37 PROP_0,
38 PROP_WIDTH,
39 PROP_CAP,
40 PROP_JOIN,
41 PROP_MITER_LIMIT,
42 PROP_ANTIALIAS,
43 PROP_DASH
47 static void get_property (GObject *object,
48 guint prop_id,
49 GValue *value,
50 GParamSpec *pspec);
51 static void set_property (GObject *object,
52 guint prop_id,
53 const GValue *value,
54 GParamSpec *pspec);
55 static GPtrArray * get_pool (void);
56 static void apply (AdgStyle *style,
57 cairo_t *cr);
60 G_DEFINE_TYPE(AdgLineStyle, adg_line_style, ADG_TYPE_STYLE)
63 static void
64 adg_line_style_class_init(AdgLineStyleClass *klass)
66 GObjectClass *gobject_class;
67 AdgStyleClass *style_class;
68 GParamSpec *param;
70 gobject_class = (GObjectClass *) klass;
71 style_class = (AdgStyleClass *) klass;
73 g_type_class_add_private(klass, sizeof(AdgLineStylePrivate));
75 gobject_class->get_property = get_property;
76 gobject_class->set_property = set_property;
78 style_class->get_pool = get_pool;
79 style_class->apply = apply;
81 param = g_param_spec_double("width",
82 P_("Line Width"),
83 P_("The line thickness in device unit"),
84 0., G_MAXDOUBLE, 2., G_PARAM_READWRITE);
85 g_object_class_install_property(gobject_class, PROP_WIDTH, param);
87 param = g_param_spec_int("cap",
88 P_("Line Cap"),
89 P_("The line cap mode"),
90 G_MININT, G_MAXINT, CAIRO_LINE_CAP_ROUND,
91 G_PARAM_READWRITE);
92 g_object_class_install_property(gobject_class, PROP_CAP, param);
94 param = g_param_spec_int("join",
95 P_("Line Join"),
96 P_("The line join mode"),
97 G_MININT, G_MAXINT, CAIRO_LINE_JOIN_MITER,
98 G_PARAM_READWRITE);
99 g_object_class_install_property(gobject_class, PROP_JOIN, param);
101 param = g_param_spec_double("miter-limit",
102 P_("Miter Limit"),
104 ("Whether the lines should be joined with a bevel instead of a miter"),
105 0., G_MAXDOUBLE, 10., G_PARAM_READWRITE);
106 g_object_class_install_property(gobject_class, PROP_MITER_LIMIT,
107 param);
109 param = g_param_spec_int("antialias",
110 P_("Antialiasing Mode"),
112 ("Type of antialiasing to do when rendering lines"),
113 G_MININT, G_MAXINT, CAIRO_ANTIALIAS_DEFAULT,
114 G_PARAM_READWRITE);
115 g_object_class_install_property(gobject_class, PROP_ANTIALIAS, param);
117 /* TODO: PROP_DASH (PROP_DASHES, PROP_NUM_DASHES, PROP_DASH_OFFSET) */
120 static void
121 adg_line_style_init(AdgLineStyle *line_style)
123 AdgLineStylePrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE(line_style,
124 ADG_TYPE_LINE_STYLE,
125 AdgLineStylePrivate);
127 priv->width = 2.;
128 priv->cap = CAIRO_LINE_CAP_ROUND;
129 priv->join = CAIRO_LINE_JOIN_MITER;
130 priv->miter_limit = 10.;
131 priv->antialias = CAIRO_ANTIALIAS_DEFAULT;
132 priv->dashes = NULL;
133 priv->num_dashes = 0;
134 priv->dash_offset = 0.;
136 line_style->priv = priv;
139 static void
140 get_property(GObject *object,
141 guint prop_id, GValue *value, GParamSpec *pspec)
143 AdgLineStyle *line_style = (AdgLineStyle *) object;
145 switch (prop_id) {
146 case PROP_WIDTH:
147 g_value_set_double(value, line_style->priv->width);
148 break;
149 case PROP_CAP:
150 g_value_set_int(value, line_style->priv->cap);
151 break;
152 case PROP_JOIN:
153 g_value_set_int(value, line_style->priv->join);
154 break;
155 case PROP_MITER_LIMIT:
156 g_value_set_double(value, line_style->priv->miter_limit);
157 break;
158 case PROP_ANTIALIAS:
159 g_value_set_int(value, line_style->priv->antialias);
160 break;
161 case PROP_DASH:
162 /* TODO */
163 break;
164 default:
165 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
166 break;
170 static void
171 set_property(GObject *object,
172 guint prop_id, const GValue *value, GParamSpec *pspec)
174 AdgLineStyle *line_style = (AdgLineStyle *) object;
176 switch (prop_id) {
177 case PROP_WIDTH:
178 line_style->priv->width = g_value_get_double(value);
179 break;
180 case PROP_CAP:
181 line_style->priv->cap = g_value_get_int(value);
182 break;
183 case PROP_JOIN:
184 line_style->priv->join = g_value_get_int(value);
185 break;
186 case PROP_MITER_LIMIT:
187 line_style->priv->miter_limit = g_value_get_double(value);
188 break;
189 case PROP_ANTIALIAS:
190 line_style->priv->antialias = g_value_get_int(value);
191 break;
192 case PROP_DASH:
193 /* TODO */
194 break;
195 default:
196 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
197 break;
203 * adg_line_style_get_slot:
205 * Gets the slot id for this style class.
207 * Return value: the slot
209 AdgStyleSlot
210 adg_line_style_get_slot(void)
212 static AdgStyleSlot slot = -1;
214 if (G_UNLIKELY(slot < 0))
215 slot = adg_context_get_slot(ADG_TYPE_LINE_STYLE);
217 return slot;
221 * adg_line_style_new:
223 * Constructs a new line style initialized with default params.
225 * Return value: a new line style
227 AdgStyle *
228 adg_line_style_new(void)
230 return g_object_new(ADG_TYPE_LINE_STYLE, NULL);
234 * adg_line_style_get_width:
235 * @line_style: an #AdgLineStyle object
237 * Gets the line thickness value (in paper units).
239 * Return value: the requested width
241 gdouble
242 adg_line_style_get_width(AdgLineStyle *line_style)
244 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), 0.);
246 return line_style->priv->width;
250 * adg_line_style_set_width:
251 * @line_style: an #AdgLineStyle object
252 * @width: the new width
254 * Sets a new line thickness value.
256 void
257 adg_line_style_set_width(AdgLineStyle *line_style, gdouble width)
259 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
261 line_style->priv->width = width;
262 g_object_notify((GObject *) line_style, "width");
266 * adg_line_style_get_cap:
267 * @line_style: an #AdgLineStyle object
269 * Gets the line cap mode.
271 * Return value: the requested line cap mode
273 cairo_line_cap_t
274 adg_line_style_get_cap(AdgLineStyle *line_style)
276 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
277 CAIRO_LINE_CAP_BUTT);
279 return line_style->priv->cap;
283 * adg_line_style_set_cap:
284 * @line_style: an #AdgLineStyle object
285 * @cap: the new cap mode
287 * Sets a new line cap mode.
289 void
290 adg_line_style_set_cap(AdgLineStyle *line_style, cairo_line_cap_t cap)
292 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
294 line_style->priv->cap = cap;
295 g_object_notify((GObject *) line_style, "cap");
299 * adg_line_style_get_join:
300 * @line_style: an #AdgLineStyle object
302 * Gets the line join mode.
304 * Return value: the requested line join mode
306 cairo_line_join_t
307 adg_line_style_get_join(AdgLineStyle *line_style)
309 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
310 CAIRO_LINE_JOIN_MITER);
312 return line_style->priv->join;
316 * adg_line_style_set_join:
317 * @line_style: an #AdgLineStyle object
318 * @join: the new join mode
320 * Sets a new line join mode.
322 void
323 adg_line_style_set_join(AdgLineStyle *line_style, cairo_line_join_t join)
325 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
327 line_style->priv->join = join;
328 g_object_notify((GObject *) line_style, "join");
332 * adg_line_style_get_miter_limit:
333 * @line_style: an #AdgLineStyle object
335 * Gets the line miter limit value. The miter limit is used to determine
336 * whether the lines should be joined with a bevel instead of a miter.
338 * Return value: the requested miter limit
340 gdouble
341 adg_line_style_get_miter_limit(AdgLineStyle *line_style)
343 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), 0.);
345 return line_style->priv->miter_limit;
349 * adg_line_style_set_miter_limit:
350 * @line_style: an #AdgLineStyle object
351 * @miter_limit: the new miter limit
353 * Sets a new miter limit value.
355 void
356 adg_line_style_set_miter_limit(AdgLineStyle *line_style,
357 gdouble miter_limit)
359 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
361 line_style->priv->miter_limit = miter_limit;
362 g_object_notify((GObject *) line_style, "miter-limit");
366 * adg_line_style_get_antialias:
367 * @line_style: an #AdgLineStyle object
369 * Gets the antialias mode used.
371 * Return value: the requested antialias mode
373 cairo_antialias_t
374 adg_line_style_get_antialias(AdgLineStyle *line_style)
376 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
377 CAIRO_ANTIALIAS_DEFAULT);
379 return line_style->priv->antialias;
383 * adg_line_style_set_antialias:
384 * @line_style: an #AdgLineStyle object
385 * @antialias: the new antialias mode
387 * Sets a new antialias mode.
389 void
390 adg_line_style_set_antialias(AdgLineStyle *line_style,
391 cairo_antialias_t antialias)
393 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
395 line_style->priv->antialias = antialias;
396 g_object_notify((GObject *) line_style, "antialias");
400 static GPtrArray *
401 get_pool(void)
403 static GPtrArray *pool = NULL;
405 if (G_UNLIKELY(pool == NULL)) {
406 cairo_pattern_t *pattern;
408 pool = g_ptr_array_sized_new(ADG_LINE_STYLE_LAST);
410 pool->pdata[ADG_LINE_STYLE_DRAW] =
411 g_object_new(ADG_TYPE_LINE_STYLE, "width", 2., NULL);
413 pattern = cairo_pattern_create_rgb(0., 1., 0.);
414 pool->pdata[ADG_LINE_STYLE_CENTER] =
415 g_object_new(ADG_TYPE_LINE_STYLE, "pattern", pattern, "width",
416 0.75, NULL);
417 cairo_pattern_destroy(pattern);
419 pattern = cairo_pattern_create_rgba(0., 0., 0., 0.5);
420 pool->pdata[ADG_LINE_STYLE_HIDDEN] =
421 g_object_new(ADG_TYPE_LINE_STYLE, "pattern", pattern, "width",
422 0.75, NULL);
423 cairo_pattern_destroy(pattern);
425 pattern = cairo_pattern_create_rgb(0., 0., 1.);
426 pool->pdata[ADG_LINE_STYLE_HATCH] =
427 g_object_new(ADG_TYPE_LINE_STYLE, "pattern", pattern, "width",
428 1.25, NULL);
429 cairo_pattern_destroy(pattern);
431 pool->pdata[ADG_LINE_STYLE_DIM] = g_object_new(ADG_TYPE_LINE_STYLE,
432 "width", 0.75,
433 NULL);
435 pool->len = ADG_LINE_STYLE_LAST;
438 return pool;
441 static void
442 apply(AdgStyle *style, cairo_t *cr)
444 AdgLineStyle *line_style;
445 AdgStyleClass *style_class;
446 gdouble device_width;
447 gdouble dummy = 0.;
449 line_style = (AdgLineStyle *) style;
450 style_class = (AdgStyleClass *) adg_line_style_parent_class;
452 if (style_class->apply != NULL)
453 style_class->apply(style, cr);
455 device_width = line_style->priv->width;
456 cairo_device_to_user_distance(cr, &device_width, &dummy);
457 cairo_set_line_width(cr, device_width);
459 cairo_set_line_cap(cr, line_style->priv->cap);
460 cairo_set_line_join(cr, line_style->priv->join);
461 cairo_set_miter_limit(cr, line_style->priv->miter_limit);
462 cairo_set_antialias(cr, line_style->priv->antialias);
464 if (line_style->priv->num_dashes > 0) {
465 g_return_if_fail(line_style->priv->dashes != NULL);
467 cairo_set_dash(cr, line_style->priv->dashes,
468 line_style->priv->num_dashes,
469 line_style->priv->dash_offset);