adg: inherit AdgDress from GEnum
[adg.git] / src / adg / adg-line-style.c
blobd44c31315e05db6b3e2c13331a60308c1f7d8abc
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011,2012,2013 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.
21 /**
22 * SECTION:adg-line-style
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.
28 * Since: 1.0
29 **/
31 /**
32 * AdgLineStyle:
34 * All fields are private and should not be used directly.
35 * Use its public methods instead.
37 * Since: 1.0
38 **/
41 #include "adg-internal.h"
42 #include "adg-dress.h"
43 #include "adg-style.h"
44 #include "adg-dash.h"
46 #include "adg-line-style.h"
47 #include "adg-line-style-private.h"
50 G_DEFINE_TYPE(AdgLineStyle, adg_line_style, ADG_TYPE_STYLE)
52 enum {
53 PROP_0,
54 PROP_COLOR_DRESS,
55 PROP_WIDTH,
56 PROP_CAP,
57 PROP_JOIN,
58 PROP_MITER_LIMIT,
59 PROP_ANTIALIAS,
60 PROP_DASH
64 static void _adg_get_property (GObject *object,
65 guint prop_id,
66 GValue *value,
67 GParamSpec *pspec);
68 static void _adg_set_property (GObject *object,
69 guint prop_id,
70 const GValue *value,
71 GParamSpec *pspec);
72 static gboolean _adg_change_dash (AdgLineStyle *style,
73 const AdgDash *dash);
74 static void _adg_apply (AdgStyle *style,
75 AdgEntity *entity,
76 cairo_t *cr);
79 static void
80 adg_line_style_class_init(AdgLineStyleClass *klass)
82 GObjectClass *gobject_class;
83 AdgStyleClass *style_class;
84 GParamSpec *param;
86 gobject_class = (GObjectClass *) klass;
87 style_class = (AdgStyleClass *) klass;
89 g_type_class_add_private(klass, sizeof(AdgLineStylePrivate));
91 gobject_class->get_property = _adg_get_property;
92 gobject_class->set_property = _adg_set_property;
94 style_class->apply = _adg_apply;
96 param = adg_param_spec_dress("color-dress",
97 P_("Color Dress"),
98 P_("The color dress to bind to this line style"),
99 ADG_DRESS_COLOR,
100 G_PARAM_READWRITE);
101 g_object_class_install_property(gobject_class, PROP_COLOR_DRESS, param);
103 param = g_param_spec_double("width",
104 P_("Line Width"),
105 P_("The line thickness in device unit"),
106 0., G_MAXDOUBLE, 2., G_PARAM_READWRITE);
107 g_object_class_install_property(gobject_class, PROP_WIDTH, param);
109 param = g_param_spec_int("cap",
110 P_("Line Cap"),
111 P_("The line cap mode"),
112 G_MININT, G_MAXINT, CAIRO_LINE_CAP_ROUND,
113 G_PARAM_READWRITE);
114 g_object_class_install_property(gobject_class, PROP_CAP, param);
116 param = g_param_spec_int("join",
117 P_("Line Join"),
118 P_("The line join mode"),
119 G_MININT, G_MAXINT, CAIRO_LINE_JOIN_MITER,
120 G_PARAM_READWRITE);
121 g_object_class_install_property(gobject_class, PROP_JOIN, param);
123 param = g_param_spec_double("miter-limit",
124 P_("Miter Limit"),
125 P_("Whether the lines should be joined with a bevel instead of a miter"),
126 0., G_MAXDOUBLE, 10., G_PARAM_READWRITE);
127 g_object_class_install_property(gobject_class, PROP_MITER_LIMIT,
128 param);
130 param = g_param_spec_int("antialias",
131 P_("Antialiasing Mode"),
132 P_("Type of antialiasing to do when rendering lines"),
133 G_MININT, G_MAXINT, CAIRO_ANTIALIAS_DEFAULT,
134 G_PARAM_READWRITE);
135 g_object_class_install_property(gobject_class, PROP_ANTIALIAS, param);
137 param = g_param_spec_boxed("dash",
138 P_("Dash Pattern"),
139 P_("The dash pattern to be used while stroking a path"),
140 ADG_TYPE_DASH, G_PARAM_READWRITE);
141 g_object_class_install_property(gobject_class, PROP_DASH, param);
144 static void
145 adg_line_style_init(AdgLineStyle *line_style)
147 AdgLineStylePrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(line_style,
148 ADG_TYPE_LINE_STYLE,
149 AdgLineStylePrivate);
151 data->color_dress = ADG_DRESS_COLOR;
152 data->width = 2.;
153 data->cap = CAIRO_LINE_CAP_ROUND;
154 data->join = CAIRO_LINE_JOIN_MITER;
155 data->miter_limit = 10.;
156 data->antialias = CAIRO_ANTIALIAS_DEFAULT;
157 data->dash = NULL;
159 line_style->data = data;
162 static void
163 _adg_get_property(GObject *object, guint prop_id,
164 GValue *value, GParamSpec *pspec)
166 AdgLineStylePrivate *data = ((AdgLineStyle *) object)->data;
168 switch (prop_id) {
169 case PROP_COLOR_DRESS:
170 g_value_set_enum(value, data->color_dress);
171 break;
172 case PROP_WIDTH:
173 g_value_set_double(value, data->width);
174 break;
175 case PROP_CAP:
176 g_value_set_int(value, data->cap);
177 break;
178 case PROP_JOIN:
179 g_value_set_int(value, data->join);
180 break;
181 case PROP_MITER_LIMIT:
182 g_value_set_double(value, data->miter_limit);
183 break;
184 case PROP_ANTIALIAS:
185 g_value_set_int(value, data->antialias);
186 break;
187 case PROP_DASH:
188 g_value_set_boxed(value, data->dash);
189 break;
190 default:
191 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
192 break;
196 static void
197 _adg_set_property(GObject *object, guint prop_id,
198 const GValue *value, GParamSpec *pspec)
200 AdgLineStyle *line_style;
201 AdgLineStylePrivate *data;
203 line_style = (AdgLineStyle *) object;
204 data = line_style->data;
206 switch (prop_id) {
207 case PROP_COLOR_DRESS:
208 data->color_dress = g_value_get_enum(value);
209 break;
210 case PROP_WIDTH:
211 data->width = g_value_get_double(value);
212 break;
213 case PROP_CAP:
214 data->cap = g_value_get_int(value);
215 break;
216 case PROP_JOIN:
217 data->join = g_value_get_int(value);
218 break;
219 case PROP_MITER_LIMIT:
220 data->miter_limit = g_value_get_double(value);
221 break;
222 case PROP_ANTIALIAS:
223 data->antialias = g_value_get_int(value);
224 break;
225 case PROP_DASH:
226 _adg_change_dash(line_style, g_value_get_boxed(value));
227 break;
228 default:
229 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
230 break;
236 * adg_line_style_new:
238 * Constructs a new line style initialized with default params.
240 * Returns: (transfer full): a new line style.
242 * Since: 1.0
244 AdgLineStyle *
245 adg_line_style_new(void)
247 return g_object_new(ADG_TYPE_LINE_STYLE, NULL);
251 * adg_line_style_set_color_dress:
252 * @line_style: an #AdgLineStyle
253 * @dress: the new color dress to use
255 * Sets a new color dress on @line_style. The new dress
256 * should be related to the original dress: you cannot
257 * set a dress used for line styles to a dress managing
258 * fonts.
260 * The validation of the new dress is done by calling
261 * adg_dress_are_related() with @dress and the previous
262 * dress as arguments: check out its documentation for
263 * details on what is a related dress.
265 * Since: 1.0
267 void
268 adg_line_style_set_color_dress(AdgLineStyle *line_style, AdgDress dress)
270 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
271 g_object_set(line_style, "color-dress", dress, NULL);
275 * adg_line_style_get_color_dress:
276 * @line_style: an #AdgLineStyle
278 * Gets the color dress used by @line_style.
280 * Returns: (transfer none): the current color dress.
282 * Since: 1.0
284 AdgDress
285 adg_line_style_get_color_dress(AdgLineStyle *line_style)
287 AdgLineStylePrivate *data;
289 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), ADG_DRESS_UNDEFINED);
291 data = line_style->data;
293 return data->color_dress;
297 * adg_line_style_set_width:
298 * @line_style: an #AdgLineStyle object
299 * @width: the new width
301 * Sets a new line thickness value.
303 * Since: 1.0
305 void
306 adg_line_style_set_width(AdgLineStyle *line_style, gdouble width)
308 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
309 g_object_set(line_style, "width", width, NULL);
313 * adg_line_style_get_width:
314 * @line_style: an #AdgLineStyle object
316 * Gets the line thickness value (in global space).
318 * Returns: the requested width.
320 * Since: 1.0
322 gdouble
323 adg_line_style_get_width(AdgLineStyle *line_style)
325 AdgLineStylePrivate *data;
327 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), 0.);
329 data = line_style->data;
331 return data->width;
335 * adg_line_style_set_cap:
336 * @line_style: an #AdgLineStyle object
337 * @cap: (type gint): the new cap mode
339 * Sets a new line cap mode.
341 * Since: 1.0
343 void
344 adg_line_style_set_cap(AdgLineStyle *line_style, cairo_line_cap_t cap)
346 AdgLineStylePrivate *data;
348 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
350 data = line_style->data;
351 data->cap = cap;
353 g_object_notify((GObject *) line_style, "cap");
357 * adg_line_style_get_cap:
358 * @line_style: an #AdgLineStyle object
360 * Gets the line cap mode.
362 * Returns: (type gint) (transfer none): the requested line cap mode.
364 * Since: 1.0
366 cairo_line_cap_t
367 adg_line_style_get_cap(AdgLineStyle *line_style)
369 AdgLineStylePrivate *data;
371 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
372 CAIRO_LINE_CAP_BUTT);
374 data = line_style->data;
376 return data->cap;
380 * adg_line_style_set_join:
381 * @line_style: an #AdgLineStyle object
382 * @join: (type gint): the new join mode
384 * Sets a new line join mode.
386 * Since: 1.0
388 void
389 adg_line_style_set_join(AdgLineStyle *line_style, cairo_line_join_t join)
391 AdgLineStylePrivate *data;
393 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
395 data = line_style->data;
396 data->join = join;
398 g_object_notify((GObject *) line_style, "join");
402 * adg_line_style_get_join:
403 * @line_style: an #AdgLineStyle object
405 * Gets the line join mode.
407 * Returns: (type gint) (transfer none): the requested line join mode.
409 * Since: 1.0
411 cairo_line_join_t
412 adg_line_style_get_join(AdgLineStyle *line_style)
414 AdgLineStylePrivate *data;
416 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
417 CAIRO_LINE_JOIN_MITER);
419 data = line_style->data;
421 return data->join;
425 * adg_line_style_set_miter_limit:
426 * @line_style: an #AdgLineStyle object
427 * @miter_limit: the new miter limit
429 * Sets a new miter limit value.
431 * Since: 1.0
433 void
434 adg_line_style_set_miter_limit(AdgLineStyle *line_style, gdouble miter_limit)
436 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
437 g_object_set(line_style, "miter-limit", miter_limit, NULL);
441 * adg_line_style_get_miter_limit:
442 * @line_style: an #AdgLineStyle object
444 * Gets the line miter limit value. The miter limit is used to determine
445 * whether the lines should be joined with a bevel instead of a miter.
447 * Returns: the requested miter limit
449 * Since: 1.0
451 gdouble
452 adg_line_style_get_miter_limit(AdgLineStyle *line_style)
454 AdgLineStylePrivate *data;
456 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), 0.);
458 data = line_style->data;
460 return data->miter_limit;
464 * adg_line_style_set_antialias:
465 * @line_style: an #AdgLineStyle object
466 * @antialias: (type gint): the new antialias mode
468 * Sets a new antialias mode.
470 * Since: 1.0
472 void
473 adg_line_style_set_antialias(AdgLineStyle *line_style,
474 cairo_antialias_t antialias)
476 AdgLineStylePrivate *data;
478 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
480 data = line_style->data;
481 data->antialias = antialias;
483 g_object_notify((GObject *) line_style, "antialias");
487 * adg_line_style_get_antialias:
488 * @line_style: an #AdgLineStyle object
490 * Gets the antialias mode used.
492 * Returns: (type gint) (transfer none): the requested antialias mode.
494 * Since: 1.0
496 cairo_antialias_t
497 adg_line_style_get_antialias(AdgLineStyle *line_style)
499 AdgLineStylePrivate *data;
501 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
502 CAIRO_ANTIALIAS_DEFAULT);
504 data = line_style->data;
506 return data->antialias;
510 * adg_line_style_set_dash:
511 * @line_style: an #AdgLineStyle object
512 * @dash: the new #AdgDash pattern
514 * Sets the dash pattern of @line_style to @dash: all future rendering with
515 * this line style will use this pattern.
517 * @line_style will embed a copy of @dash: this means that after this call,
518 * @dash can be freed (with adg_dash_destroy()) if no more needed.
520 * Since: 1.0
522 void
523 adg_line_style_set_dash(AdgLineStyle *line_style, const AdgDash *dash)
525 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
527 if (_adg_change_dash(line_style, dash))
528 g_object_notify((GObject *) line_style, "dash");
532 * adg_line_style_get_dash:
533 * @line_style: an #AdgLineStyle object
535 * Gets the dash pattern currently active on @line_style. A %NULL value is
536 * returned when no dash pattern is active.
538 * The returned pattern is owned by @line_style: you are not allowed to modify
539 * or free it. If something needs to be changed, work on a duplicate and reset
540 * the new pattern, such as:
542 * |[
543 * AdgDash *dash, *new_dash;
545 * dash = adg_line_style_get_dash(line_style);
546 * if (dash == NULL)
547 * new_dash = adg_dash_new();
548 * else
549 * new_dash = adg_dash_dup(dash);
551 * // ...modify new_dash as needed...
553 * adg_line_style_set_dash(line_style, new_dash);
554 * adg_dash_destroy(new_dash);
555 * ]|
557 * <note><para>
558 * Getting #AdgLineStyle:dash via the #GObject property mechanism returns
559 * a duplicate instead, so you must free it when done.
560 * </para></note>
562 * |[
563 * g_object_get(line_style, "dash", &dash, NULL);
564 * // Here dash is a duplicate: modifying it will not affect line_style
565 * adg_dash_destroy(dash);
566 * ]|
568 * Returns: the current dash pattern or %NULL on errors.
570 * Since: 1.0
572 const AdgDash *
573 adg_line_style_get_dash(AdgLineStyle *line_style)
575 AdgLineStylePrivate *data;
577 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), NULL);
579 data = line_style->data;
580 return data->dash;
584 static gboolean
585 _adg_change_dash(AdgLineStyle *line_style, const AdgDash *dash)
587 AdgLineStylePrivate *data = line_style->data;
589 if (data->dash == dash)
590 return FALSE;
592 if (data->dash != NULL) {
593 adg_dash_destroy(data->dash);
594 data->dash = NULL;
597 if (dash != NULL) {
598 data->dash = adg_dash_dup(dash);
601 return TRUE;
604 static void
605 _adg_apply(AdgStyle *style, AdgEntity *entity, cairo_t *cr)
607 AdgLineStylePrivate *data = ((AdgLineStyle *) style)->data;
609 adg_entity_apply_dress(entity, data->color_dress, cr);
610 cairo_set_line_width(cr, data->width);
611 cairo_set_line_cap(cr, data->cap);
612 cairo_set_line_join(cr, data->join);
613 cairo_set_miter_limit(cr, data->miter_limit);
614 cairo_set_antialias(cr, data->antialias);
616 if (data->dash != NULL) {
617 cairo_set_dash(cr,
618 adg_dash_get_dashes(data->dash),
619 adg_dash_get_num_dashes(data->dash),
620 adg_dash_get_offset(data->dash));