doc: update copyright line for 2021
[adg.git] / src / adg / adg-line-style.c
blob053e097911500321dfc10b818ee43b1206117d62
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2021 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_WITH_PRIVATE(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 gobject_class->get_property = _adg_get_property;
91 gobject_class->set_property = _adg_set_property;
93 style_class->apply = _adg_apply;
95 param = adg_param_spec_dress("color-dress",
96 P_("Color Dress"),
97 P_("The color dress to bind to this line style"),
98 ADG_DRESS_COLOR,
99 G_PARAM_READWRITE);
100 g_object_class_install_property(gobject_class, PROP_COLOR_DRESS, param);
102 param = g_param_spec_double("width",
103 P_("Line Width"),
104 P_("The line thickness in device unit"),
105 0., G_MAXDOUBLE, 2., G_PARAM_READWRITE);
106 g_object_class_install_property(gobject_class, PROP_WIDTH, param);
108 param = g_param_spec_int("cap",
109 P_("Line Cap"),
110 P_("The line cap mode"),
111 G_MININT, G_MAXINT, CAIRO_LINE_CAP_ROUND,
112 G_PARAM_READWRITE);
113 g_object_class_install_property(gobject_class, PROP_CAP, param);
115 param = g_param_spec_int("join",
116 P_("Line Join"),
117 P_("The line join mode"),
118 G_MININT, G_MAXINT, CAIRO_LINE_JOIN_MITER,
119 G_PARAM_READWRITE);
120 g_object_class_install_property(gobject_class, PROP_JOIN, param);
122 param = g_param_spec_double("miter-limit",
123 P_("Miter Limit"),
124 P_("Whether the lines should be joined with a bevel instead of a miter"),
125 0., G_MAXDOUBLE, 10., G_PARAM_READWRITE);
126 g_object_class_install_property(gobject_class, PROP_MITER_LIMIT,
127 param);
129 param = g_param_spec_int("antialias",
130 P_("Antialiasing Mode"),
131 P_("Type of antialiasing to do when rendering lines"),
132 G_MININT, G_MAXINT, CAIRO_ANTIALIAS_DEFAULT,
133 G_PARAM_READWRITE);
134 g_object_class_install_property(gobject_class, PROP_ANTIALIAS, param);
136 param = g_param_spec_boxed("dash",
137 P_("Dash Pattern"),
138 P_("The dash pattern to be used while stroking a path"),
139 ADG_TYPE_DASH, G_PARAM_READWRITE);
140 g_object_class_install_property(gobject_class, PROP_DASH, param);
143 static void
144 adg_line_style_init(AdgLineStyle *line_style)
146 AdgLineStylePrivate *data = adg_line_style_get_instance_private(line_style);
147 data->color_dress = ADG_DRESS_COLOR;
148 data->width = 2.;
149 data->cap = CAIRO_LINE_CAP_ROUND;
150 data->join = CAIRO_LINE_JOIN_MITER;
151 data->miter_limit = 10.;
152 data->antialias = CAIRO_ANTIALIAS_DEFAULT;
153 data->dash = NULL;
156 static void
157 _adg_get_property(GObject *object, guint prop_id,
158 GValue *value, GParamSpec *pspec)
160 AdgLineStylePrivate *data = adg_line_style_get_instance_private((AdgLineStyle *) object);
162 switch (prop_id) {
163 case PROP_COLOR_DRESS:
164 g_value_set_enum(value, data->color_dress);
165 break;
166 case PROP_WIDTH:
167 g_value_set_double(value, data->width);
168 break;
169 case PROP_CAP:
170 g_value_set_int(value, data->cap);
171 break;
172 case PROP_JOIN:
173 g_value_set_int(value, data->join);
174 break;
175 case PROP_MITER_LIMIT:
176 g_value_set_double(value, data->miter_limit);
177 break;
178 case PROP_ANTIALIAS:
179 g_value_set_int(value, data->antialias);
180 break;
181 case PROP_DASH:
182 g_value_set_boxed(value, data->dash);
183 break;
184 default:
185 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
186 break;
190 static void
191 _adg_set_property(GObject *object, guint prop_id,
192 const GValue *value, GParamSpec *pspec)
194 AdgLineStyle *line_style = (AdgLineStyle *) object;
195 AdgLineStylePrivate *data = adg_line_style_get_instance_private(line_style);
197 switch (prop_id) {
198 case PROP_COLOR_DRESS:
199 data->color_dress = g_value_get_enum(value);
200 break;
201 case PROP_WIDTH:
202 data->width = g_value_get_double(value);
203 break;
204 case PROP_CAP:
205 data->cap = g_value_get_int(value);
206 break;
207 case PROP_JOIN:
208 data->join = g_value_get_int(value);
209 break;
210 case PROP_MITER_LIMIT:
211 data->miter_limit = g_value_get_double(value);
212 break;
213 case PROP_ANTIALIAS:
214 data->antialias = g_value_get_int(value);
215 break;
216 case PROP_DASH:
217 _adg_change_dash(line_style, g_value_get_boxed(value));
218 break;
219 default:
220 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
221 break;
227 * adg_line_style_new:
229 * Constructs a new line style initialized with default params.
231 * Returns: (transfer full): a new line style.
233 * Since: 1.0
235 AdgLineStyle *
236 adg_line_style_new(void)
238 return g_object_new(ADG_TYPE_LINE_STYLE, NULL);
242 * adg_line_style_set_color_dress:
243 * @line_style: an #AdgLineStyle
244 * @dress: the new color dress to use
246 * Sets a new color dress on @line_style. The new dress
247 * should be related to the original dress: you cannot
248 * set a dress used for line styles to a dress managing
249 * fonts.
251 * The validation of the new dress is done by calling
252 * adg_dress_are_related() with @dress and the previous
253 * dress as arguments: check out its documentation for
254 * details on what is a related dress.
256 * Since: 1.0
258 void
259 adg_line_style_set_color_dress(AdgLineStyle *line_style, AdgDress dress)
261 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
262 g_object_set(line_style, "color-dress", dress, NULL);
266 * adg_line_style_get_color_dress:
267 * @line_style: an #AdgLineStyle
269 * Gets the color dress used by @line_style.
271 * Returns: (transfer none): the current color dress.
273 * Since: 1.0
275 AdgDress
276 adg_line_style_get_color_dress(AdgLineStyle *line_style)
278 AdgLineStylePrivate *data;
280 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), ADG_DRESS_UNDEFINED);
282 data = adg_line_style_get_instance_private(line_style);
283 return data->color_dress;
287 * adg_line_style_set_width:
288 * @line_style: an #AdgLineStyle object
289 * @width: the new width
291 * Sets a new line thickness value.
293 * Since: 1.0
295 void
296 adg_line_style_set_width(AdgLineStyle *line_style, gdouble width)
298 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
299 g_object_set(line_style, "width", width, NULL);
303 * adg_line_style_get_width:
304 * @line_style: an #AdgLineStyle object
306 * Gets the line thickness value (in global space).
308 * Returns: the requested width.
310 * Since: 1.0
312 gdouble
313 adg_line_style_get_width(AdgLineStyle *line_style)
315 AdgLineStylePrivate *data;
317 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), 0.);
319 data = adg_line_style_get_instance_private(line_style);
320 return data->width;
324 * adg_line_style_set_cap:
325 * @line_style: an #AdgLineStyle object
326 * @cap: (type gint): the new cap mode
328 * Sets a new line cap mode.
330 * Since: 1.0
332 void
333 adg_line_style_set_cap(AdgLineStyle *line_style, cairo_line_cap_t cap)
335 AdgLineStylePrivate *data;
337 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
339 data = adg_line_style_get_instance_private(line_style);
340 data->cap = cap;
341 g_object_notify((GObject *) line_style, "cap");
345 * adg_line_style_get_cap:
346 * @line_style: an #AdgLineStyle object
348 * Gets the line cap mode.
350 * Returns: (type gint): the requested line cap mode.
352 * Since: 1.0
354 cairo_line_cap_t
355 adg_line_style_get_cap(AdgLineStyle *line_style)
357 AdgLineStylePrivate *data;
359 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
360 CAIRO_LINE_CAP_BUTT);
362 data = adg_line_style_get_instance_private(line_style);
363 return data->cap;
367 * adg_line_style_set_join:
368 * @line_style: an #AdgLineStyle object
369 * @join: (type gint): the new join mode
371 * Sets a new line join mode.
373 * Since: 1.0
375 void
376 adg_line_style_set_join(AdgLineStyle *line_style, cairo_line_join_t join)
378 AdgLineStylePrivate *data;
380 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
382 data = adg_line_style_get_instance_private(line_style);
383 data->join = join;
384 g_object_notify((GObject *) line_style, "join");
388 * adg_line_style_get_join:
389 * @line_style: an #AdgLineStyle object
391 * Gets the line join mode.
393 * Returns: (type gint): the requested line join mode.
395 * Since: 1.0
397 cairo_line_join_t
398 adg_line_style_get_join(AdgLineStyle *line_style)
400 AdgLineStylePrivate *data;
402 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
403 CAIRO_LINE_JOIN_MITER);
405 data = adg_line_style_get_instance_private(line_style);
406 return data->join;
410 * adg_line_style_set_miter_limit:
411 * @line_style: an #AdgLineStyle object
412 * @miter_limit: the new miter limit
414 * Sets a new miter limit value.
416 * Since: 1.0
418 void
419 adg_line_style_set_miter_limit(AdgLineStyle *line_style, gdouble miter_limit)
421 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
422 g_object_set(line_style, "miter-limit", miter_limit, NULL);
426 * adg_line_style_get_miter_limit:
427 * @line_style: an #AdgLineStyle object
429 * Gets the line miter limit value. The miter limit is used to determine
430 * whether the lines should be joined with a bevel instead of a miter.
432 * Returns: the requested miter limit
434 * Since: 1.0
436 gdouble
437 adg_line_style_get_miter_limit(AdgLineStyle *line_style)
439 AdgLineStylePrivate *data;
441 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), 0.);
443 data = adg_line_style_get_instance_private(line_style);
444 return data->miter_limit;
448 * adg_line_style_set_antialias:
449 * @line_style: an #AdgLineStyle object
450 * @antialias: (type gint): the new antialias mode
452 * Sets a new antialias mode.
454 * Since: 1.0
456 void
457 adg_line_style_set_antialias(AdgLineStyle *line_style,
458 cairo_antialias_t antialias)
460 AdgLineStylePrivate *data;
462 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
464 data = adg_line_style_get_instance_private(line_style);
465 data->antialias = antialias;
466 g_object_notify((GObject *) line_style, "antialias");
470 * adg_line_style_get_antialias:
471 * @line_style: an #AdgLineStyle object
473 * Gets the antialias mode used.
475 * Returns: (type gint): the requested antialias mode.
477 * Since: 1.0
479 cairo_antialias_t
480 adg_line_style_get_antialias(AdgLineStyle *line_style)
482 AdgLineStylePrivate *data;
484 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
485 CAIRO_ANTIALIAS_DEFAULT);
487 data = adg_line_style_get_instance_private(line_style);
488 return data->antialias;
492 * adg_line_style_set_dash:
493 * @line_style: an #AdgLineStyle object
494 * @dash: the new #AdgDash pattern
496 * Sets the dash pattern of @line_style to @dash: all future rendering with
497 * this line style will use this pattern.
499 * The @line_style will embed a copy of @dash: this means that, after this
500 * call, @dash can be freed (with adg_dash_destroy()) if no more needed.
502 * Since: 1.0
504 void
505 adg_line_style_set_dash(AdgLineStyle *line_style, const AdgDash *dash)
507 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
509 if (_adg_change_dash(line_style, dash))
510 g_object_notify((GObject *) line_style, "dash");
514 * adg_line_style_get_dash:
515 * @line_style: an #AdgLineStyle object
517 * Gets the dash pattern currently active on @line_style.
518 * A <constant>NULL</constant> value is returned when no dash pattern is active.
520 * The returned pattern is owned by @line_style: you are not allowed to modify
521 * or free it. If something needs to be changed, work on a duplicate and reset
522 * the new pattern, such as:
524 * <informalexample><programlisting language="C">
525 * AdgDash *dash, *new_dash;
527 * dash = adg_line_style_get_dash(line_style);
528 * if (dash == NULL)
529 * new_dash = adg_dash_new();
530 * else
531 * new_dash = adg_dash_dup(dash);
533 * // ...modify new_dash as needed...
535 * adg_line_style_set_dash(line_style, new_dash);
536 * adg_dash_destroy(new_dash);
537 * </programlisting></informalexample>
539 * <note><para>
540 * Getting #AdgLineStyle:dash via the #GObject property mechanism returns
541 * a duplicate instead, so you must free it when done.
542 * </para></note>
544 * <informalexample><programlisting language="C">
545 * g_object_get(line_style, "dash", &dash, NULL);
546 * // Here dash is a duplicate: modifying it will not affect line_style
547 * adg_dash_destroy(dash);
548 * </programlisting></informalexample>
550 * Returns: the current dash pattern or <constant>NULL</constant> on errors.
552 * Since: 1.0
554 const AdgDash *
555 adg_line_style_get_dash(AdgLineStyle *line_style)
557 AdgLineStylePrivate *data;
559 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), NULL);
561 data = adg_line_style_get_instance_private(line_style);
562 return data->dash;
566 static gboolean
567 _adg_change_dash(AdgLineStyle *line_style, const AdgDash *dash)
569 AdgLineStylePrivate *data = adg_line_style_get_instance_private(line_style);
571 if (data->dash == dash)
572 return FALSE;
574 if (data->dash != NULL) {
575 adg_dash_destroy(data->dash);
576 data->dash = NULL;
579 if (dash != NULL) {
580 data->dash = adg_dash_dup(dash);
583 return TRUE;
586 static void
587 _adg_apply(AdgStyle *style, AdgEntity *entity, cairo_t *cr)
589 AdgLineStylePrivate *data = adg_line_style_get_instance_private((AdgLineStyle *) style);
591 adg_entity_apply_dress(entity, data->color_dress, cr);
592 cairo_set_line_width(cr, data->width);
593 cairo_set_line_cap(cr, data->cap);
594 cairo_set_line_join(cr, data->join);
595 cairo_set_miter_limit(cr, data->miter_limit);
596 cairo_set_antialias(cr, data->antialias);
598 if (data->dash != NULL) {
599 cairo_set_dash(cr,
600 adg_dash_get_dashes(data->dash),
601 adg_dash_get_num_dashes(data->dash),
602 adg_dash_get_offset(data->dash));