tests: additional checks on container types
[adg.git] / src / adg / adg-line-style.c
blobddb5976f122c1066e2cb8c8685314f8c9d7547cc
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2015 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-style.h"
43 #include "adg-dash.h"
44 #include "adg-dress.h"
45 #include "adg-param-dress.h"
47 #include "adg-line-style.h"
48 #include "adg-line-style-private.h"
51 G_DEFINE_TYPE(AdgLineStyle, adg_line_style, ADG_TYPE_STYLE)
53 enum {
54 PROP_0,
55 PROP_COLOR_DRESS,
56 PROP_WIDTH,
57 PROP_CAP,
58 PROP_JOIN,
59 PROP_MITER_LIMIT,
60 PROP_ANTIALIAS,
61 PROP_DASH
65 static void _adg_get_property (GObject *object,
66 guint prop_id,
67 GValue *value,
68 GParamSpec *pspec);
69 static void _adg_set_property (GObject *object,
70 guint prop_id,
71 const GValue *value,
72 GParamSpec *pspec);
73 static gboolean _adg_change_dash (AdgLineStyle *style,
74 const AdgDash *dash);
75 static void _adg_apply (AdgStyle *style,
76 AdgEntity *entity,
77 cairo_t *cr);
80 static void
81 adg_line_style_class_init(AdgLineStyleClass *klass)
83 GObjectClass *gobject_class;
84 AdgStyleClass *style_class;
85 GParamSpec *param;
87 gobject_class = (GObjectClass *) klass;
88 style_class = (AdgStyleClass *) klass;
90 g_type_class_add_private(klass, sizeof(AdgLineStylePrivate));
92 gobject_class->get_property = _adg_get_property;
93 gobject_class->set_property = _adg_set_property;
95 style_class->apply = _adg_apply;
97 param = adg_param_spec_dress("color-dress",
98 P_("Color Dress"),
99 P_("The color dress to bind to this line style"),
100 ADG_DRESS_COLOR,
101 G_PARAM_READWRITE);
102 g_object_class_install_property(gobject_class, PROP_COLOR_DRESS, param);
104 param = g_param_spec_double("width",
105 P_("Line Width"),
106 P_("The line thickness in device unit"),
107 0., G_MAXDOUBLE, 2., G_PARAM_READWRITE);
108 g_object_class_install_property(gobject_class, PROP_WIDTH, param);
110 param = g_param_spec_int("cap",
111 P_("Line Cap"),
112 P_("The line cap mode"),
113 G_MININT, G_MAXINT, CAIRO_LINE_CAP_ROUND,
114 G_PARAM_READWRITE);
115 g_object_class_install_property(gobject_class, PROP_CAP, param);
117 param = g_param_spec_int("join",
118 P_("Line Join"),
119 P_("The line join mode"),
120 G_MININT, G_MAXINT, CAIRO_LINE_JOIN_MITER,
121 G_PARAM_READWRITE);
122 g_object_class_install_property(gobject_class, PROP_JOIN, param);
124 param = g_param_spec_double("miter-limit",
125 P_("Miter Limit"),
126 P_("Whether the lines should be joined with a bevel instead of a miter"),
127 0., G_MAXDOUBLE, 10., G_PARAM_READWRITE);
128 g_object_class_install_property(gobject_class, PROP_MITER_LIMIT,
129 param);
131 param = g_param_spec_int("antialias",
132 P_("Antialiasing Mode"),
133 P_("Type of antialiasing to do when rendering lines"),
134 G_MININT, G_MAXINT, CAIRO_ANTIALIAS_DEFAULT,
135 G_PARAM_READWRITE);
136 g_object_class_install_property(gobject_class, PROP_ANTIALIAS, param);
138 param = g_param_spec_boxed("dash",
139 P_("Dash Pattern"),
140 P_("The dash pattern to be used while stroking a path"),
141 ADG_TYPE_DASH, G_PARAM_READWRITE);
142 g_object_class_install_property(gobject_class, PROP_DASH, param);
145 static void
146 adg_line_style_init(AdgLineStyle *line_style)
148 AdgLineStylePrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(line_style,
149 ADG_TYPE_LINE_STYLE,
150 AdgLineStylePrivate);
152 data->color_dress = ADG_DRESS_COLOR;
153 data->width = 2.;
154 data->cap = CAIRO_LINE_CAP_ROUND;
155 data->join = CAIRO_LINE_JOIN_MITER;
156 data->miter_limit = 10.;
157 data->antialias = CAIRO_ANTIALIAS_DEFAULT;
158 data->dash = NULL;
160 line_style->data = data;
163 static void
164 _adg_get_property(GObject *object, guint prop_id,
165 GValue *value, GParamSpec *pspec)
167 AdgLineStylePrivate *data = ((AdgLineStyle *) object)->data;
169 switch (prop_id) {
170 case PROP_COLOR_DRESS:
171 g_value_set_enum(value, data->color_dress);
172 break;
173 case PROP_WIDTH:
174 g_value_set_double(value, data->width);
175 break;
176 case PROP_CAP:
177 g_value_set_int(value, data->cap);
178 break;
179 case PROP_JOIN:
180 g_value_set_int(value, data->join);
181 break;
182 case PROP_MITER_LIMIT:
183 g_value_set_double(value, data->miter_limit);
184 break;
185 case PROP_ANTIALIAS:
186 g_value_set_int(value, data->antialias);
187 break;
188 case PROP_DASH:
189 g_value_set_boxed(value, data->dash);
190 break;
191 default:
192 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
193 break;
197 static void
198 _adg_set_property(GObject *object, guint prop_id,
199 const GValue *value, GParamSpec *pspec)
201 AdgLineStyle *line_style;
202 AdgLineStylePrivate *data;
204 line_style = (AdgLineStyle *) object;
205 data = line_style->data;
207 switch (prop_id) {
208 case PROP_COLOR_DRESS:
209 data->color_dress = g_value_get_enum(value);
210 break;
211 case PROP_WIDTH:
212 data->width = g_value_get_double(value);
213 break;
214 case PROP_CAP:
215 data->cap = g_value_get_int(value);
216 break;
217 case PROP_JOIN:
218 data->join = g_value_get_int(value);
219 break;
220 case PROP_MITER_LIMIT:
221 data->miter_limit = g_value_get_double(value);
222 break;
223 case PROP_ANTIALIAS:
224 data->antialias = g_value_get_int(value);
225 break;
226 case PROP_DASH:
227 _adg_change_dash(line_style, g_value_get_boxed(value));
228 break;
229 default:
230 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
231 break;
237 * adg_line_style_new:
239 * Constructs a new line style initialized with default params.
241 * Returns: (transfer full): a new line style.
243 * Since: 1.0
245 AdgLineStyle *
246 adg_line_style_new(void)
248 return g_object_new(ADG_TYPE_LINE_STYLE, NULL);
252 * adg_line_style_set_color_dress:
253 * @line_style: an #AdgLineStyle
254 * @dress: the new color dress to use
256 * Sets a new color dress on @line_style. The new dress
257 * should be related to the original dress: you cannot
258 * set a dress used for line styles to a dress managing
259 * fonts.
261 * The validation of the new dress is done by calling
262 * adg_dress_are_related() with @dress and the previous
263 * dress as arguments: check out its documentation for
264 * details on what is a related dress.
266 * Since: 1.0
268 void
269 adg_line_style_set_color_dress(AdgLineStyle *line_style, AdgDress dress)
271 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
272 g_object_set(line_style, "color-dress", dress, NULL);
276 * adg_line_style_get_color_dress:
277 * @line_style: an #AdgLineStyle
279 * Gets the color dress used by @line_style.
281 * Returns: (transfer none): the current color dress.
283 * Since: 1.0
285 AdgDress
286 adg_line_style_get_color_dress(AdgLineStyle *line_style)
288 AdgLineStylePrivate *data;
290 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), ADG_DRESS_UNDEFINED);
292 data = line_style->data;
294 return data->color_dress;
298 * adg_line_style_set_width:
299 * @line_style: an #AdgLineStyle object
300 * @width: the new width
302 * Sets a new line thickness value.
304 * Since: 1.0
306 void
307 adg_line_style_set_width(AdgLineStyle *line_style, gdouble width)
309 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
310 g_object_set(line_style, "width", width, NULL);
314 * adg_line_style_get_width:
315 * @line_style: an #AdgLineStyle object
317 * Gets the line thickness value (in global space).
319 * Returns: the requested width.
321 * Since: 1.0
323 gdouble
324 adg_line_style_get_width(AdgLineStyle *line_style)
326 AdgLineStylePrivate *data;
328 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), 0.);
330 data = line_style->data;
332 return data->width;
336 * adg_line_style_set_cap:
337 * @line_style: an #AdgLineStyle object
338 * @cap: (type gint): the new cap mode
340 * Sets a new line cap mode.
342 * Since: 1.0
344 void
345 adg_line_style_set_cap(AdgLineStyle *line_style, cairo_line_cap_t cap)
347 AdgLineStylePrivate *data;
349 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
351 data = line_style->data;
352 data->cap = cap;
354 g_object_notify((GObject *) line_style, "cap");
358 * adg_line_style_get_cap:
359 * @line_style: an #AdgLineStyle object
361 * Gets the line cap mode.
363 * Returns: (type gint) (transfer none): the requested line cap mode.
365 * Since: 1.0
367 cairo_line_cap_t
368 adg_line_style_get_cap(AdgLineStyle *line_style)
370 AdgLineStylePrivate *data;
372 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
373 CAIRO_LINE_CAP_BUTT);
375 data = line_style->data;
377 return data->cap;
381 * adg_line_style_set_join:
382 * @line_style: an #AdgLineStyle object
383 * @join: (type gint): the new join mode
385 * Sets a new line join mode.
387 * Since: 1.0
389 void
390 adg_line_style_set_join(AdgLineStyle *line_style, cairo_line_join_t join)
392 AdgLineStylePrivate *data;
394 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
396 data = line_style->data;
397 data->join = join;
399 g_object_notify((GObject *) line_style, "join");
403 * adg_line_style_get_join:
404 * @line_style: an #AdgLineStyle object
406 * Gets the line join mode.
408 * Returns: (type gint) (transfer none): the requested line join mode.
410 * Since: 1.0
412 cairo_line_join_t
413 adg_line_style_get_join(AdgLineStyle *line_style)
415 AdgLineStylePrivate *data;
417 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
418 CAIRO_LINE_JOIN_MITER);
420 data = line_style->data;
422 return data->join;
426 * adg_line_style_set_miter_limit:
427 * @line_style: an #AdgLineStyle object
428 * @miter_limit: the new miter limit
430 * Sets a new miter limit value.
432 * Since: 1.0
434 void
435 adg_line_style_set_miter_limit(AdgLineStyle *line_style, gdouble miter_limit)
437 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
438 g_object_set(line_style, "miter-limit", miter_limit, NULL);
442 * adg_line_style_get_miter_limit:
443 * @line_style: an #AdgLineStyle object
445 * Gets the line miter limit value. The miter limit is used to determine
446 * whether the lines should be joined with a bevel instead of a miter.
448 * Returns: the requested miter limit
450 * Since: 1.0
452 gdouble
453 adg_line_style_get_miter_limit(AdgLineStyle *line_style)
455 AdgLineStylePrivate *data;
457 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), 0.);
459 data = line_style->data;
461 return data->miter_limit;
465 * adg_line_style_set_antialias:
466 * @line_style: an #AdgLineStyle object
467 * @antialias: (type gint): the new antialias mode
469 * Sets a new antialias mode.
471 * Since: 1.0
473 void
474 adg_line_style_set_antialias(AdgLineStyle *line_style,
475 cairo_antialias_t antialias)
477 AdgLineStylePrivate *data;
479 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
481 data = line_style->data;
482 data->antialias = antialias;
484 g_object_notify((GObject *) line_style, "antialias");
488 * adg_line_style_get_antialias:
489 * @line_style: an #AdgLineStyle object
491 * Gets the antialias mode used.
493 * Returns: (type gint) (transfer none): the requested antialias mode.
495 * Since: 1.0
497 cairo_antialias_t
498 adg_line_style_get_antialias(AdgLineStyle *line_style)
500 AdgLineStylePrivate *data;
502 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
503 CAIRO_ANTIALIAS_DEFAULT);
505 data = line_style->data;
507 return data->antialias;
511 * adg_line_style_set_dash:
512 * @line_style: an #AdgLineStyle object
513 * @dash: the new #AdgDash pattern
515 * Sets the dash pattern of @line_style to @dash: all future rendering with
516 * this line style will use this pattern.
518 * The @line_style will embed a copy of @dash: this means that, after this
519 * call, @dash can be freed (with adg_dash_destroy()) if no more needed.
521 * Since: 1.0
523 void
524 adg_line_style_set_dash(AdgLineStyle *line_style, const AdgDash *dash)
526 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
528 if (_adg_change_dash(line_style, dash))
529 g_object_notify((GObject *) line_style, "dash");
533 * adg_line_style_get_dash:
534 * @line_style: an #AdgLineStyle object
536 * Gets the dash pattern currently active on @line_style.
537 * A <constant>NULL</constant> value is returned when no dash pattern is active.
539 * The returned pattern is owned by @line_style: you are not allowed to modify
540 * or free it. If something needs to be changed, work on a duplicate and reset
541 * the new pattern, such as:
543 * <informalexample><programlisting language="C">
544 * AdgDash *dash, *new_dash;
546 * dash = adg_line_style_get_dash(line_style);
547 * if (dash == NULL)
548 * new_dash = adg_dash_new();
549 * else
550 * new_dash = adg_dash_dup(dash);
552 * // ...modify new_dash as needed...
554 * adg_line_style_set_dash(line_style, new_dash);
555 * adg_dash_destroy(new_dash);
556 * </programlisting></informalexample>
558 * <note><para>
559 * Getting #AdgLineStyle:dash via the #GObject property mechanism returns
560 * a duplicate instead, so you must free it when done.
561 * </para></note>
563 * <informalexample><programlisting language="C">
564 * g_object_get(line_style, "dash", &dash, NULL);
565 * // Here dash is a duplicate: modifying it will not affect line_style
566 * adg_dash_destroy(dash);
567 * </programlisting></informalexample>
569 * Returns: the current dash pattern or <constant>NULL</constant> on errors.
571 * Since: 1.0
573 const AdgDash *
574 adg_line_style_get_dash(AdgLineStyle *line_style)
576 AdgLineStylePrivate *data;
578 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), NULL);
580 data = line_style->data;
581 return data->dash;
585 static gboolean
586 _adg_change_dash(AdgLineStyle *line_style, const AdgDash *dash)
588 AdgLineStylePrivate *data = line_style->data;
590 if (data->dash == dash)
591 return FALSE;
593 if (data->dash != NULL) {
594 adg_dash_destroy(data->dash);
595 data->dash = NULL;
598 if (dash != NULL) {
599 data->dash = adg_dash_dup(dash);
602 return TRUE;
605 static void
606 _adg_apply(AdgStyle *style, AdgEntity *entity, cairo_t *cr)
608 AdgLineStylePrivate *data = ((AdgLineStyle *) style)->data;
610 adg_entity_apply_dress(entity, data->color_dress, cr);
611 cairo_set_line_width(cr, data->width);
612 cairo_set_line_cap(cr, data->cap);
613 cairo_set_line_join(cr, data->join);
614 cairo_set_miter_limit(cr, data->miter_limit);
615 cairo_set_antialias(cr, data->antialias);
617 if (data->dash != NULL) {
618 cairo_set_dash(cr,
619 adg_dash_get_dashes(data->dash),
620 adg_dash_get_num_dashes(data->dash),
621 adg_dash_get_offset(data->dash));