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.
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.
34 * All fields are private and should not be used directly.
35 * Use its public methods instead.
41 #include "adg-internal.h"
42 #include "adg-style.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
)
65 static void _adg_get_property (GObject
*object
,
69 static void _adg_set_property (GObject
*object
,
73 static gboolean
_adg_change_dash (AdgLineStyle
*style
,
75 static void _adg_apply (AdgStyle
*style
,
81 adg_line_style_class_init(AdgLineStyleClass
*klass
)
83 GObjectClass
*gobject_class
;
84 AdgStyleClass
*style_class
;
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",
97 P_("The color dress to bind to this line style"),
100 g_object_class_install_property(gobject_class
, PROP_COLOR_DRESS
, param
);
102 param
= g_param_spec_double("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",
110 P_("The line cap mode"),
111 G_MININT
, G_MAXINT
, CAIRO_LINE_CAP_ROUND
,
113 g_object_class_install_property(gobject_class
, PROP_CAP
, param
);
115 param
= g_param_spec_int("join",
117 P_("The line join mode"),
118 G_MININT
, G_MAXINT
, CAIRO_LINE_JOIN_MITER
,
120 g_object_class_install_property(gobject_class
, PROP_JOIN
, param
);
122 param
= g_param_spec_double("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
,
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
,
134 g_object_class_install_property(gobject_class
, PROP_ANTIALIAS
, param
);
136 param
= g_param_spec_boxed("dash",
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
);
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
;
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
;
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
);
163 case PROP_COLOR_DRESS
:
164 g_value_set_enum(value
, data
->color_dress
);
167 g_value_set_double(value
, data
->width
);
170 g_value_set_int(value
, data
->cap
);
173 g_value_set_int(value
, data
->join
);
175 case PROP_MITER_LIMIT
:
176 g_value_set_double(value
, data
->miter_limit
);
179 g_value_set_int(value
, data
->antialias
);
182 g_value_set_boxed(value
, data
->dash
);
185 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
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
);
198 case PROP_COLOR_DRESS
:
199 data
->color_dress
= g_value_get_enum(value
);
202 data
->width
= g_value_get_double(value
);
205 data
->cap
= g_value_get_int(value
);
208 data
->join
= g_value_get_int(value
);
210 case PROP_MITER_LIMIT
:
211 data
->miter_limit
= g_value_get_double(value
);
214 data
->antialias
= g_value_get_int(value
);
217 _adg_change_dash(line_style
, g_value_get_boxed(value
));
220 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
227 * adg_line_style_new:
229 * Constructs a new line style initialized with default params.
231 * Returns: (transfer full): a new line style.
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
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.
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.
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.
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.
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
);
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.
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
);
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.
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
);
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.
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
);
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.
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
);
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.
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
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.
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.
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.
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);
529 * new_dash = adg_dash_new();
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>
540 * Getting #AdgLineStyle:dash via the #GObject property mechanism returns
541 * a duplicate instead, so you must free it when done.
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.
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
);
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
)
574 if (data
->dash
!= NULL
) {
575 adg_dash_destroy(data
->dash
);
580 data
->dash
= adg_dash_dup(dash
);
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
) {
600 adg_dash_get_dashes(data
->dash
),
601 adg_dash_get_num_dashes(data
->dash
),
602 adg_dash_get_offset(data
->dash
));