doc: update copyright line for 2021
[adg.git] / src / adg / adg-dim-style.c
blobcbaf02a52935889f474c77ba4407928d24835b78
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-dim-style
23 * @short_description: Dimension style related stuff
25 * Contains parameters on how to build dimensions such as the format of the
26 * label, the different font styles (for value and limits), line style,
27 * offsets of the various dimension components etc.
29 * A typical use case is to set the quote of angular dimensions in sexagesimal
30 * units. To do this, use something similar to the following code:
32 * |[
33 * AdgDimStyle *dim_style = ADG_DIM_STYLE(adg_style_clone(adg_dress_get_fallback(adg_dress_dimension)));
35 * // Set the decimals and rounding properties
36 * adg_dim_style_set_decimals(dim_style, 0);
37 * adg_dim_style_set_rounding(dim_style, 3);
39 * // Set the arguments and the format of the quote number
40 * adg_dim_style_set_number_arguments(dim_style, "Dm");
41 * adg_dim_style_set_number_format(dim_style, "%g°(%g')");
42 * ]|
44 * After that you can apply the new style to the
45 * <constant>ADG_DRESS_DIMENSION</constant> of the entity you want to change,
46 * e.g.:
48 * |[
49 * adg_entity_set_style(my_angular_dimension,
50 * ADG_DRESS_DIMENSION,
51 * ADG_STYLE(dim_style));
52 * ]|
54 * Since: 1.0
57 /**
58 * AdgDimStyle:
60 * All fields are private and should not be used directly.
61 * Use its public methods instead.
63 * Since: 1.0
64 **/
67 #include "adg-internal.h"
68 #include "adg-style.h"
69 #include "adg-font-style.h"
70 #include "adg-dash.h"
71 #include "adg-line-style.h"
72 #include "adg-model.h"
73 #include "adg-trail.h"
74 #include "adg-marker.h"
75 #include "adg-dress.h"
76 #include "adg-param-dress.h"
78 #include "adg-dim-style.h"
79 #include "adg-dim-style-private.h"
81 #include <string.h>
82 #include <math.h>
85 #define VALID_FORMATS "aieDdMmSs"
88 G_DEFINE_TYPE_WITH_PRIVATE(AdgDimStyle, adg_dim_style, ADG_TYPE_STYLE)
90 enum {
91 PROP_0,
92 PROP_MARKER1,
93 PROP_MARKER2,
94 PROP_COLOR_DRESS,
95 PROP_VALUE_DRESS,
96 PROP_MIN_DRESS,
97 PROP_MAX_DRESS,
98 PROP_LINE_DRESS,
99 PROP_FROM_OFFSET,
100 PROP_TO_OFFSET,
101 PROP_BEYOND,
102 PROP_BASELINE_SPACING,
103 PROP_LIMITS_SPACING,
104 PROP_QUOTE_SHIFT,
105 PROP_LIMITS_SHIFT,
106 PROP_NUMBER_FORMAT,
107 PROP_NUMBER_ARGUMENTS,
108 PROP_NUMBER_TAG,
109 PROP_DECIMALS,
110 PROP_ROUNDING,
114 static void _adg_finalize (GObject *object);
115 static void _adg_get_property (GObject *object,
116 guint prop_id,
117 GValue *value,
118 GParamSpec *pspec);
119 static void _adg_set_property (GObject *object,
120 guint prop_id,
121 const GValue *value,
122 GParamSpec *pspec);
123 static AdgStyle * _adg_clone (AdgStyle *style);
124 static void _adg_apply (AdgStyle *style,
125 AdgEntity *entity,
126 cairo_t *cr);
127 static AdgMarker * _adg_marker_new (const AdgMarkerData
128 *marker_data);
129 static void _adg_marker_data_set (AdgMarkerData *marker_data,
130 AdgMarker *marker);
131 static void _adg_marker_data_unset (AdgMarkerData *marker_data);
134 static void
135 adg_dim_style_class_init(AdgDimStyleClass *klass)
137 GObjectClass *gobject_class;
138 AdgStyleClass *style_class;
139 GParamSpec *param;
141 gobject_class = (GObjectClass *) klass;
142 style_class = (AdgStyleClass *) klass;
144 gobject_class->finalize = _adg_finalize;
145 gobject_class->get_property = _adg_get_property;
146 gobject_class->set_property = _adg_set_property;
148 style_class->clone = _adg_clone;
149 style_class->apply = _adg_apply;
151 param = g_param_spec_object("marker1",
152 P_("First Marker"),
153 P_("The template entity to use as first marker"),
154 ADG_TYPE_MARKER,
155 G_PARAM_WRITABLE);
156 g_object_class_install_property(gobject_class, PROP_MARKER1, param);
158 param = g_param_spec_object("marker2",
159 P_("Second Marker"),
160 P_("The template entity to use as second marker"),
161 ADG_TYPE_MARKER,
162 G_PARAM_WRITABLE);
163 g_object_class_install_property(gobject_class, PROP_MARKER2, param);
165 param = adg_param_spec_dress("color-dress",
166 P_("Color Dress"),
167 P_("Color dress for the whole dimension"),
168 ADG_DRESS_COLOR_DIMENSION,
169 G_PARAM_READWRITE);
170 g_object_class_install_property(gobject_class, PROP_COLOR_DRESS, param);
172 param = adg_param_spec_dress("value-dress",
173 P_("Value Dress"),
174 P_("Font dress for the nominal value of the dimension"),
175 ADG_DRESS_FONT_QUOTE_TEXT,
176 G_PARAM_READWRITE);
177 g_object_class_install_property(gobject_class, PROP_VALUE_DRESS, param);
179 param = adg_param_spec_dress("min-dress",
180 P_("Minimum Limit Dress"),
181 P_("Font dress for the lower limit value"),
182 ADG_DRESS_FONT_QUOTE_ANNOTATION,
183 G_PARAM_READWRITE);
184 g_object_class_install_property(gobject_class, PROP_MIN_DRESS, param);
186 param = adg_param_spec_dress("max-dress",
187 P_("Maximum Limit Dress"),
188 P_("Font dress for the upper limit value"),
189 ADG_DRESS_FONT_QUOTE_ANNOTATION,
190 G_PARAM_READWRITE);
191 g_object_class_install_property(gobject_class, PROP_MAX_DRESS, param);
193 param = adg_param_spec_dress("line-dress",
194 P_("Line Dress"),
195 P_("Line dress for the baseline and the extension lines"),
196 ADG_DRESS_LINE_DIMENSION,
197 G_PARAM_READWRITE);
198 g_object_class_install_property(gobject_class, PROP_LINE_DRESS, param);
200 param = g_param_spec_double("from-offset",
201 P_("From Offset"),
202 P_("Offset (in global space) of the extension lines from the path to the quote"),
203 0, G_MAXDOUBLE, 5,
204 G_PARAM_READWRITE);
205 g_object_class_install_property(gobject_class, PROP_FROM_OFFSET, param);
207 param = g_param_spec_double("to-offset",
208 P_("To Offset"),
209 P_("How many extend (in global space) the extension lines after hitting the baseline"),
210 0, G_MAXDOUBLE, 5,
211 G_PARAM_READWRITE);
212 g_object_class_install_property(gobject_class, PROP_TO_OFFSET, param);
214 param = g_param_spec_double("beyond",
215 P_("Beyond Length"),
216 P_("How much the baseline should be extended (in global space) beyond the extension lines on dimensions with outside markers"),
217 0, G_MAXDOUBLE, 20,
218 G_PARAM_READWRITE);
219 g_object_class_install_property(gobject_class, PROP_BEYOND, param);
221 param = g_param_spec_double("baseline-spacing",
222 P_("Baseline Spacing"),
223 P_("Distance between two consecutive baselines while stacking dimensions"),
224 0, G_MAXDOUBLE, 32,
225 G_PARAM_READWRITE);
226 g_object_class_install_property(gobject_class, PROP_BASELINE_SPACING, param);
228 param = g_param_spec_double("limits-spacing",
229 P_("Limits Spacing"),
230 P_("Distance between limits/tolerances"),
231 -G_MAXDOUBLE, G_MAXDOUBLE, 2,
232 G_PARAM_READWRITE);
233 g_object_class_install_property(gobject_class, PROP_LIMITS_SPACING, param);
235 param = g_param_spec_boxed("quote-shift",
236 P_("Quote Shift"),
237 P_("Used to specify a smooth displacement (in global space) of the quote by taking as reference the perfect compact position (the middle of the baseline on common linear dimension, for instance)"),
238 CPML_TYPE_PAIR,
239 G_PARAM_READWRITE);
240 g_object_class_install_property(gobject_class, PROP_QUOTE_SHIFT, param);
242 param = g_param_spec_boxed("limits-shift",
243 P_("Limits Shift"),
244 P_("Used to specify a smooth displacement (in global space) for the limits/tolerances by taking as reference the perfect compact position"),
245 CPML_TYPE_PAIR,
246 G_PARAM_READWRITE);
247 g_object_class_install_property(gobject_class, PROP_LIMITS_SHIFT, param);
249 param = g_param_spec_string("number-format",
250 P_("Number Format"),
251 P_("The format (in printf style) of the numeric component of the basic value"),
252 "%-.7g",
253 G_PARAM_READWRITE);
254 g_object_class_install_property(gobject_class, PROP_NUMBER_FORMAT, param);
256 param = g_param_spec_string("number-arguments",
257 P_("Number Arguments"),
258 P_("The arguments to pass to the format function: see adg_dim_style_set_number_arguments() for further details"),
259 "d",
260 G_PARAM_READWRITE);
261 g_object_class_install_property(gobject_class, PROP_NUMBER_ARGUMENTS, param);
263 param = g_param_spec_string("number-tag",
264 P_("Number Tag"),
265 P_("The tag to substitute inside the value template string"),
266 "<>",
267 G_PARAM_READWRITE);
268 g_object_class_install_property(gobject_class, PROP_NUMBER_TAG, param);
270 param = g_param_spec_int("decimals",
271 P_("Rounded Value Decimals"),
272 P_("Number of significant decimals to use in the format string for rounded values (-1 to disable)"),
273 -1, G_MAXINT,
275 G_PARAM_READWRITE);
276 g_object_class_install_property(gobject_class, PROP_DECIMALS, param);
278 param = g_param_spec_int("rounding",
279 P_("Raw Value Decimals"),
280 P_("Number of significant decimals the raw value must be rounded to (-1 to disable)"),
281 -1, G_MAXINT,
283 G_PARAM_READWRITE);
284 g_object_class_install_property(gobject_class, PROP_ROUNDING, param);
287 static void
288 adg_dim_style_init(AdgDimStyle *dim_style)
290 AdgDimStylePrivate *data = adg_dim_style_get_instance_private(dim_style);
291 data->marker1.type = 0;
292 data->marker1.n_properties = 0;
293 data->marker1.names = NULL;
294 data->marker1.values = NULL;
295 data->marker2.type = 0;
296 data->marker2.n_properties = 0;
297 data->marker2.names = NULL;
298 data->marker2.values = NULL;
299 data->color_dress = ADG_DRESS_COLOR_DIMENSION;
300 data->value_dress = ADG_DRESS_FONT_QUOTE_TEXT;
301 data->min_dress = ADG_DRESS_FONT_QUOTE_ANNOTATION;
302 data->max_dress = ADG_DRESS_FONT_QUOTE_ANNOTATION;
303 data->line_dress = ADG_DRESS_LINE_DIMENSION;
304 data->marker_dress = ADG_DRESS_UNDEFINED;
305 data->from_offset = 6;
306 data->to_offset = 6;
307 data->beyond = 20;
308 data->baseline_spacing = 32;
309 data->limits_spacing = 0;
310 data->quote_shift.x = 4;
311 data->quote_shift.y = -1;
312 data->limits_shift.x = +2;
313 data->limits_shift.y = +2;
314 data->number_format = g_strdup("%-.7g");
315 data->number_arguments = g_strdup("d");
316 data->number_tag = g_strdup("<>");
317 data->decimals = 2;
318 data->rounding = 6;
321 static void
322 _adg_finalize(GObject *object)
324 AdgDimStylePrivate *data = adg_dim_style_get_instance_private((AdgDimStyle *) object);
326 _adg_marker_data_unset(&data->marker1);
327 _adg_marker_data_unset(&data->marker2);
329 g_free(data->number_format);
330 data->number_format = NULL;
332 g_free(data->number_arguments);
333 data->number_arguments = NULL;
335 g_free(data->number_tag);
336 data->number_tag = NULL;
339 static void
340 _adg_get_property(GObject *object, guint prop_id,
341 GValue *value, GParamSpec *pspec)
343 AdgDimStylePrivate *data = adg_dim_style_get_instance_private((AdgDimStyle *) object);
345 switch (prop_id) {
346 case PROP_COLOR_DRESS:
347 g_value_set_enum(value, data->color_dress);
348 break;
349 case PROP_VALUE_DRESS:
350 g_value_set_enum(value, data->value_dress);
351 break;
352 case PROP_MIN_DRESS:
353 g_value_set_enum(value, data->min_dress);
354 break;
355 case PROP_MAX_DRESS:
356 g_value_set_enum(value, data->max_dress);
357 break;
358 case PROP_LINE_DRESS:
359 g_value_set_enum(value, data->line_dress);
360 break;
361 case PROP_FROM_OFFSET:
362 g_value_set_double(value, data->from_offset);
363 break;
364 case PROP_TO_OFFSET:
365 g_value_set_double(value, data->to_offset);
366 break;
367 case PROP_BEYOND:
368 g_value_set_double(value, data->beyond);
369 break;
370 case PROP_BASELINE_SPACING:
371 g_value_set_double(value, data->baseline_spacing);
372 break;
373 case PROP_LIMITS_SPACING:
374 g_value_set_double(value, data->limits_spacing);
375 break;
376 case PROP_QUOTE_SHIFT:
377 g_value_set_boxed(value, &data->quote_shift);
378 break;
379 case PROP_LIMITS_SHIFT:
380 g_value_set_boxed(value, &data->limits_shift);
381 break;
382 case PROP_NUMBER_FORMAT:
383 g_value_set_string(value, data->number_format);
384 break;
385 case PROP_NUMBER_ARGUMENTS:
386 g_value_set_string(value, data->number_arguments);
387 break;
388 case PROP_NUMBER_TAG:
389 g_value_set_string(value, data->number_tag);
390 break;
391 case PROP_DECIMALS:
392 g_value_set_int(value, data->decimals);
393 break;
394 case PROP_ROUNDING:
395 g_value_set_int(value, data->rounding);
396 break;
397 default:
398 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
399 break;
403 static void
404 _adg_set_property(GObject *object, guint prop_id,
405 const GValue *value, GParamSpec *pspec)
407 AdgDimStyle *dim_style = (AdgDimStyle *) object;
408 AdgDimStylePrivate *data = adg_dim_style_get_instance_private(dim_style);
410 switch (prop_id) {
411 case PROP_MARKER1:
412 _adg_marker_data_set(&data->marker1, g_value_get_object(value));
413 break;
414 case PROP_MARKER2:
415 _adg_marker_data_set(&data->marker2, g_value_get_object(value));
416 break;
417 case PROP_COLOR_DRESS:
418 data->color_dress = g_value_get_enum(value);
419 break;
420 case PROP_VALUE_DRESS:
421 data->value_dress = g_value_get_enum(value);
422 break;
423 case PROP_MIN_DRESS:
424 data->min_dress = g_value_get_enum(value);
425 break;
426 case PROP_MAX_DRESS:
427 data->max_dress = g_value_get_enum(value);
428 break;
429 case PROP_LINE_DRESS:
430 data->line_dress = g_value_get_enum(value);
431 break;
432 case PROP_FROM_OFFSET:
433 data->from_offset = g_value_get_double(value);
434 break;
435 case PROP_TO_OFFSET:
436 data->to_offset = g_value_get_double(value);
437 break;
438 case PROP_BEYOND:
439 data->beyond = g_value_get_double(value);
440 break;
441 case PROP_BASELINE_SPACING:
442 data->baseline_spacing = g_value_get_double(value);
443 break;
444 case PROP_LIMITS_SPACING:
445 data->limits_spacing = g_value_get_double(value);
446 break;
447 case PROP_QUOTE_SHIFT:
448 cpml_pair_copy(&data->quote_shift, g_value_get_boxed(value));
449 break;
450 case PROP_LIMITS_SHIFT:
451 cpml_pair_copy(&data->limits_shift, g_value_get_boxed(value));
452 break;
453 case PROP_NUMBER_FORMAT:
454 g_free(data->number_format);
455 data->number_format = g_value_dup_string(value);
456 break;
457 case PROP_NUMBER_ARGUMENTS: {
458 const gchar *arguments = g_value_get_string(value);
459 g_return_if_fail(arguments == NULL || strspn(arguments, VALID_FORMATS) == strlen(arguments));
460 g_free(data->number_arguments);
461 data->number_arguments = g_strdup(arguments);
462 break;
464 case PROP_NUMBER_TAG:
465 g_free(data->number_tag);
466 data->number_tag = g_value_dup_string(value);
467 break;
468 case PROP_DECIMALS:
469 data->decimals = g_value_get_int(value);
470 break;
471 case PROP_ROUNDING:
472 data->rounding = g_value_get_int(value);
473 break;
474 default:
475 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
476 break;
482 * adg_dim_style_new:
484 * Constructs a new empty dimension style initialized with default params.
486 * Returns: (transfer full): a newly created dimension style.
488 * Since: 1.0
490 AdgDimStyle *
491 adg_dim_style_new(void)
493 return g_object_new(ADG_TYPE_DIM_STYLE, NULL);
497 * adg_dim_style_set_marker1:
498 * @dim_style: an #AdgStyle
499 * @marker: an #AdgMarker derived entity
501 * Uses @marker as entity template to generate a new marker entity
502 * when a call to adg_dim_style_marker1_new() is made. It is allowed
503 * to pass <constant>NULL</constant> as @marker, in which case the
504 * template data of the first marker are unset.
506 * This method duplicates internally the property values of @marker,
507 * so any further change to @marker does not affect @dim_style anymore.
508 * This also means @marker could be destroyed without problems after
509 * this call because @dim_style uses only its property values and does
510 * not add any references to @marker.
512 * Since: 1.0
514 void
515 adg_dim_style_set_marker1(AdgDimStyle *dim_style, AdgMarker *marker)
517 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
518 g_object_set(dim_style, "marker1", marker, NULL);
522 * adg_dim_style_marker1_new:
523 * @dim_style: an #AdgDimStyle
525 * Creates a new marker entity by cloning the #AdgDimStyle:marker1
526 * object. The returned entity should be unreferenced with
527 * g_object_unref() when no longer needed.
529 * Returns: (transfer full): a newly created marker or <constant>NULL</constant> if the #AdgDimStyle:marker1 property is not set or on errors.
531 * Since: 1.0
533 AdgMarker *
534 adg_dim_style_marker1_new(AdgDimStyle *dim_style)
536 AdgDimStylePrivate *data;
538 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
540 data = adg_dim_style_get_instance_private(dim_style);
541 return _adg_marker_new(&data->marker1);
545 * adg_dim_style_set_marker2:
546 * @dim_style: an #AdgStyle
547 * @marker: an #AdgMarker derived entity
549 * Uses @marker as entity template to generate a new marker entity
550 * when a call to adg_dim_style_marker2_new() is made. It is allowed
551 * to pass <constant>NULL</constant> as @marker, in which case the
552 * template data of the second marker are unset.
554 * This method duplicates internally the property values of @marker,
555 * so any further change to @marker does not affect @dim_style anymore.
556 * This also means @marker could be destroyed without problems after
557 * this call because @dim_style uses only its property values and does
558 * not add any references to @marker.
560 * Since: 1.0
562 void
563 adg_dim_style_set_marker2(AdgDimStyle *dim_style, AdgMarker *marker)
565 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
566 g_object_set(dim_style, "marker2", marker, NULL);
570 * adg_dim_style_marker2_new:
571 * @dim_style: an #AdgDimStyle
573 * Creates a new marker entity by cloning the #AdgDimStyle:marker2
574 * object. The returned entity should be unreferenced with
575 * g_object_unref() when no longer needed.
577 * Returns: (transfer full): a newly created marker or <constant>NULL</constant> if the #AdgDimStyle:marker2 property is not set or on errors.
579 * Since: 1.0
581 AdgMarker *
582 adg_dim_style_marker2_new(AdgDimStyle *dim_style)
584 AdgDimStylePrivate *data;
586 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
588 data = adg_dim_style_get_instance_private(dim_style);
589 return _adg_marker_new(&data->marker2);
593 * adg_dim_style_set_color_dress:
594 * @dim_style: an #AdgDimStyle object
595 * @dress: the new color dress
597 * Sets a new color dress on @dim_style.
599 * Since: 1.0
601 void
602 adg_dim_style_set_color_dress(AdgDimStyle *dim_style, AdgDress dress)
604 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
605 g_object_set(dim_style, "color-dress", dress, NULL);
609 * adg_dim_style_get_color_dress:
610 * @dim_style: an #AdgDimStyle object
612 * Gets the @dim_style color dress to be used. This dress should be
613 * intended as a fallback color as it could be overriden by more
614 * specific dresses, such as a color explicitely specified on the
615 * #AdgDimStyle:value-dress.
617 * Returns: (transfer none): the color dress.
619 * Since: 1.0
621 AdgDress
622 adg_dim_style_get_color_dress(AdgDimStyle *dim_style)
624 AdgDimStylePrivate *data;
626 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), ADG_DRESS_UNDEFINED);
628 data = adg_dim_style_get_instance_private(dim_style);
629 return data->color_dress;
633 * adg_dim_style_set_value_dress:
634 * @dim_style: an #AdgDimStyle object
635 * @dress: the new basic value font style
637 * Sets a new dress on @dim_style for the basic value.
639 * Since: 1.0
641 void
642 adg_dim_style_set_value_dress(AdgDimStyle *dim_style, AdgDress dress)
644 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
645 g_object_set(dim_style, "value-dress", dress, NULL);
649 * adg_dim_style_get_value_dress:
650 * @dim_style: an #AdgDimStyle object
652 * Gets the font dress to be used for the basic value of dimensions
653 * with @dim_style.
655 * Returns: (transfer none): the font dress.
657 * Since: 1.0
659 AdgDress
660 adg_dim_style_get_value_dress(AdgDimStyle *dim_style)
662 AdgDimStylePrivate *data;
664 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), ADG_DRESS_UNDEFINED);
666 data = adg_dim_style_get_instance_private(dim_style);
667 return data->value_dress;
671 * adg_dim_style_set_min_dress:
672 * @dim_style: an #AdgDimStyle object
673 * @dress: the new lower limit dress
675 * Sets a new dress on @dim_style for the lower limit value.
677 * Since: 1.0
679 void
680 adg_dim_style_set_min_dress(AdgDimStyle *dim_style, AdgDress dress)
682 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
683 g_object_set(dim_style, "min-dress", dress, NULL);
687 * adg_dim_style_get_min_dress:
688 * @dim_style: an #AdgDimStyle object
690 * Gets the @dim_style dress to be used for the lower limit.
692 * Returns: (transfer none): the lower limit dress.
694 * Since: 1.0
696 AdgDress
697 adg_dim_style_get_min_dress(AdgDimStyle *dim_style)
699 AdgDimStylePrivate *data;
701 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), ADG_DRESS_UNDEFINED);
703 data = adg_dim_style_get_instance_private(dim_style);
704 return data->min_dress;
708 * adg_dim_style_set_max_dress:
709 * @dim_style: an #AdgDimStyle object
710 * @dress: the new upper limit dress
712 * Sets a new dress on @dim_style for the upper limit value.
714 * Since: 1.0
716 void
717 adg_dim_style_set_max_dress(AdgDimStyle *dim_style, AdgDress dress)
719 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
720 g_object_set(dim_style, "max-dress", dress, NULL);
724 * adg_dim_style_get_max_dress:
725 * @dim_style: an #AdgDimStyle object
727 * Gets the @dim_style dress to be used for the upper limit.
729 * Returns: (transfer none): the upper limit dress.
731 * Since: 1.0
733 AdgDress
734 adg_dim_style_get_max_dress(AdgDimStyle *dim_style)
736 AdgDimStylePrivate *data;
738 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), ADG_DRESS_UNDEFINED);
740 data = adg_dim_style_get_instance_private(dim_style);
741 return data->max_dress;
745 * adg_dim_style_set_line_dress:
746 * @dim_style: an #AdgDimStyle object
747 * @dress: the new line dress
749 * Sets a new line dress on @dim_style.
751 * Since: 1.0
753 void
754 adg_dim_style_set_line_dress(AdgDimStyle *dim_style, AdgDress dress)
756 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
757 g_object_set(dim_style, "line-dress", dress, NULL);
761 * adg_dim_style_get_line_dress:
762 * @dim_style: an #AdgDimStyle object
764 * Gets the line dress to be used for rendering the base and
765 * the extension lines with @dim_style.
767 * Returns: (transfer none): the line dress.
769 * Since: 1.0
771 AdgDress
772 adg_dim_style_get_line_dress(AdgDimStyle *dim_style)
774 AdgDimStylePrivate *data;
776 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), ADG_DRESS_UNDEFINED);
778 data = adg_dim_style_get_instance_private(dim_style);
779 return data->line_dress;
783 * adg_dim_style_set_from_offset:
784 * @dim_style: an #AdgDimStyle object
785 * @offset: the new offset
787 * Sets a new value in the #AdgDimStyle:from-offset property.
789 * Since: 1.0
791 void
792 adg_dim_style_set_from_offset(AdgDimStyle *dim_style, gdouble offset)
794 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
795 g_object_set(dim_style, "from-offset", offset, NULL);
799 * adg_dim_style_get_from_offset:
800 * @dim_style: an #AdgDimStyle object
802 * Gets the distance (in global space) the extension lines must keep from the
803 * sensed points.
805 * Returns: the requested distance.
807 * Since: 1.0
809 gdouble
810 adg_dim_style_get_from_offset(AdgDimStyle *dim_style)
812 AdgDimStylePrivate *data;
814 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), 0);
816 data = adg_dim_style_get_instance_private(dim_style);
817 return data->from_offset;
821 * adg_dim_style_set_to_offset:
822 * @dim_style: an #AdgDimStyle object
823 * @offset: the new offset
825 * Sets a new value in the #AdgDimStyle:to-offset property.
827 * Since: 1.0
829 void
830 adg_dim_style_set_to_offset(AdgDimStyle *dim_style, gdouble offset)
832 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
833 g_object_set(dim_style, "to-offset", offset, NULL);
837 * adg_dim_style_get_to_offset:
838 * @dim_style: an #AdgDimStyle object
840 * Gets how much (in global space) the extension lines must extend after
841 * crossing the baseline.
843 * Returns: the requested distance.
845 * Since: 1.0
847 gdouble
848 adg_dim_style_get_to_offset(AdgDimStyle *dim_style)
850 AdgDimStylePrivate *data;
852 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), 0);
854 data = adg_dim_style_get_instance_private(dim_style);
855 return data->to_offset;
859 * adg_dim_style_set_beyond:
860 * @dim_style: an #AdgDimStyle object
861 * @beyond: the new length
863 * Sets a new value in the #AdgDimStyle:beyond property.
865 * Since: 1.0
867 void
868 adg_dim_style_set_beyond(AdgDimStyle *dim_style, gdouble beyond)
870 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
871 g_object_set(dim_style, "beyond", beyond, NULL);
875 * adg_dim_style_get_beyond:
876 * @dim_style: an #AdgDimStyle object
878 * Gets how much (in global space) the baseline should extend beyond
879 * the extension lines on dimension with outside markers.
881 * Returns: the requested beyond length.
883 * Since: 1.0
885 gdouble
886 adg_dim_style_get_beyond(AdgDimStyle *dim_style)
888 AdgDimStylePrivate *data;
890 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), 0);
892 data = adg_dim_style_get_instance_private(dim_style);
893 return data->beyond;
897 * adg_dim_style_set_baseline_spacing:
898 * @dim_style: an #AdgDimStyle object
899 * @spacing: the new spacing
901 * Sets a new value in the #AdgDimStyle:baseline-spacing value.
903 * Since: 1.0
905 void
906 adg_dim_style_set_baseline_spacing(AdgDimStyle *dim_style, gdouble spacing)
908 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
909 g_object_set(dim_style, "baseline-spacing", spacing, NULL);
913 * adg_dim_style_get_baseline_spacing:
914 * @dim_style: an #AdgDimStyle object
916 * Gets the distance between two consecutive baselines
917 * while stacking dimensions.
919 * Returns: the requested spacing.
921 * Since: 1.0
923 gdouble
924 adg_dim_style_get_baseline_spacing(AdgDimStyle *dim_style)
926 AdgDimStylePrivate *data;
928 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), 0);
930 data = adg_dim_style_get_instance_private(dim_style);
931 return data->baseline_spacing;
935 * adg_dim_style_set_limits_spacing:
936 * @dim_style: an #AdgDimStyle object
937 * @spacing: the new spacing
939 * Sets a new #AdgDimStyle:limits-spacing value.
941 * Since: 1.0
943 void
944 adg_dim_style_set_limits_spacing(AdgDimStyle *dim_style, gdouble spacing)
946 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
947 g_object_set(dim_style, "limits-spacing", spacing, NULL);
951 * adg_dim_style_get_limits_spacing:
952 * @dim_style: an #AdgDimStyle object
954 * Gets the distance (in global space) between the limits/tolerances.
956 * Returns: the requested spacing.
958 * Since: 1.0
960 gdouble
961 adg_dim_style_get_limits_spacing(AdgDimStyle *dim_style)
963 AdgDimStylePrivate *data;
965 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), 0);
967 data = adg_dim_style_get_instance_private(dim_style);
968 return data->limits_spacing;
972 * adg_dim_style_set_quote_shift:
973 * @dim_style: an #AdgDimStyle object
974 * @shift: the new displacement
976 * Sets a new #AdgDimStyle:quote-shift value.
978 * Since: 1.0
980 void
981 adg_dim_style_set_quote_shift(AdgDimStyle *dim_style, const CpmlPair *shift)
983 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
984 g_object_set(dim_style, "quote-shift", shift, NULL);
988 * adg_dim_style_get_quote_shift:
989 * @dim_style: an #AdgDimStyle object
991 * Gets the smooth displacement of the quote. The returned pointer refers
992 * to an internal allocated struct and must not be modified or freed.
994 * Returns: (transfer none): the requested shift.
996 * Since: 1.0
998 const CpmlPair *
999 adg_dim_style_get_quote_shift(AdgDimStyle *dim_style)
1001 AdgDimStylePrivate *data;
1003 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
1005 data = adg_dim_style_get_instance_private(dim_style);
1006 return &data->quote_shift;
1010 * adg_dim_style_set_limits_shift:
1011 * @dim_style: an #AdgDimStyle object
1012 * @shift: the new displacement
1014 * Sets a new #AdgDimStyle:limits-shift value.
1016 * Since: 1.0
1018 void
1019 adg_dim_style_set_limits_shift(AdgDimStyle *dim_style, const CpmlPair *shift)
1021 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
1022 g_object_set(dim_style, "limits-shift", shift, NULL);
1026 * adg_dim_style_get_limits_shift:
1027 * @dim_style: an #AdgDimStyle object
1029 * Gets the smooth displacement for the limits. The returned pointer
1030 * refers to an internal allocated struct and must not be modified or freed.
1032 * Returns: (transfer none): the requested shift.
1034 * Since: 1.0
1036 const CpmlPair *
1037 adg_dim_style_get_limits_shift(AdgDimStyle *dim_style)
1039 AdgDimStylePrivate *data;
1041 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
1043 data = adg_dim_style_get_instance_private(dim_style);
1044 return &data->limits_shift;
1048 * adg_dim_style_set_number_format:
1049 * @dim_style: an #AdgDimStyle object
1050 * @format: the new format to adopt
1052 * Sets a new value in the #AdgDimStyle:number-format property.
1054 * @format is similar to a printf() style format string but only 'e', 'E',
1055 * 'f', 'F', 'g' and 'G' specifiers are allowed. For reference, the
1056 * implementation leverages the g_ascii_formatd() GLib function. If you want
1057 * to use special characters (%"(", %")" and %"%") as literals you need to
1058 * escape them with a backslash.
1060 * You can use round parenthesis to group together one or more % directives
1061 * with other related literals. In that case, when the value bound to the
1062 * directive will be 0, the whole group will disappear. Some example:
1064 * |[
1065 * AdgDim *dim;
1066 * AdgDimStyle *dim_style;
1067 * gchar *text;
1069 * dim = ADG_DIM(adg_ldim_new());
1070 * dim_style = ADG_DIM_STYLE(adg_entity_style(ADG_ENTITY(dim), ADG_DRESS_DIMENSION));
1072 * adg_dim_style_set_number_arguments(dim_style, "dD");
1073 * adg_dim_style_set_number_format(dim_style, "(%g)( truncated to %g)");
1075 * text = adg_dim_get_text(dim, 1.2);
1076 * g_print("%s\n", text); // Prints "1.2 truncated to 1"
1077 * g_free(text);
1079 * text = adg_dim_get_text(dim, 0.2);
1080 * g_print("%s\n", text); // Prints "0.2"
1081 * g_free(text);
1083 * text = adg_dim_get_text(dim, 0);
1084 * g_print("%s\n", text); // Prints ""
1085 * g_free(text);
1086 * ]|
1088 * Groups can be nested and can have more than one value, in which case all
1089 * the values contained in a group must be 0 in order to let it disappear.
1090 * This comes in handy for removing trailing 0 fields. A typical example is
1091 * the sexagesimal representation of angles:
1093 * |[
1094 * adg_dim_style_set_number_arguments(dim_style, "DMs");
1095 * adg_dim_style_set_number_format(dim_style, "%g°(%g'(%g\"))");
1097 * text = adg_dim_get_text(dim, 1.5);
1098 * g_print("%s\n", text); // Prints "1°30'"
1099 * g_free(text);
1101 * text = adg_dim_get_text(dim, 2.002777);
1102 * g_print("%s\n", text); // Prints "2°0'10\""
1103 * g_free(text);
1104 * ]|
1106 * Since: 1.0
1108 void
1109 adg_dim_style_set_number_format(AdgDimStyle *dim_style, const gchar *format)
1111 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
1112 g_object_set(dim_style, "number-format", format, NULL);
1116 * adg_dim_style_get_number_format:
1117 * @dim_style: an #AdgDimStyle object
1119 * Gets the number format (in printf style) of this quoting style. The
1120 * returned pointer refers to internally managed text that must not be
1121 * modified or freed.
1123 * Returns: (transfer none): the requested format.
1125 * Since: 1.0
1127 const gchar *
1128 adg_dim_style_get_number_format(AdgDimStyle *dim_style)
1130 AdgDimStylePrivate *data;
1132 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
1134 data = adg_dim_style_get_instance_private(dim_style);
1135 return data->number_format;
1139 * adg_dim_style_set_number_arguments:
1140 * @dim_style: an #AdgDimStyle object
1141 * @arguments: the arguments to pass to the formatting function
1143 * A string that identifies the arguments to pass to the formatting function.
1144 * See adg_dim_style_convert() to know the allowed character that can be
1145 * included into this string.
1147 * The number of arguments (i.e. the @arguments length) must match the
1148 * #AdgDimStyle:number-format property (i.e. the number of % directives
1149 * included in that property). See adg_dim_style_set_number_format() for more
1150 * technical details and some examples.
1152 * Since: 1.0
1154 void
1155 adg_dim_style_set_number_arguments(AdgDimStyle *dim_style, const gchar *arguments)
1157 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
1158 g_object_set(dim_style, "number-arguments", arguments, NULL);
1162 * adg_dim_style_get_number_arguments:
1163 * @dim_style: an #AdgDimStyle object
1165 * Gets the arguments used by the formatting function. See
1166 * adg_dim_style_set_number_arguments() for details on what this means.
1168 * Returns: (transfer none): the requested arguments.
1170 * Since: 1.0
1172 const gchar *
1173 adg_dim_style_get_number_arguments(AdgDimStyle *dim_style)
1175 AdgDimStylePrivate *data;
1177 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
1179 data = adg_dim_style_get_instance_private(dim_style);
1180 return data->number_arguments;
1184 * adg_dim_style_set_number_tag:
1185 * @dim_style: an #AdgDimStyle object
1186 * @tag: the new tag
1188 * Sets a new tag in the #AdgDimStyle:number-tag property.
1190 * Since: 1.0
1192 void
1193 adg_dim_style_set_number_tag(AdgDimStyle *dim_style, const gchar *tag)
1195 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
1196 g_object_set(dim_style, "number-tag", tag, NULL);
1200 * adg_dim_style_get_number_tag:
1201 * @dim_style: an #AdgDimStyle object
1203 * Gets the number tag of @dim_style. This tag will be used while
1204 * generating the set values of the dimensions bound to this style:
1205 * check the #AdgDim:value documentation for further details.
1207 * The returned pointer refers to internally managed text that
1208 * must not be modified or freed.
1210 * Returns: (transfer none): the requested tag.
1212 * Since: 1.0
1214 const gchar *
1215 adg_dim_style_get_number_tag(AdgDimStyle *dim_style)
1217 AdgDimStylePrivate *data;
1219 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
1221 data = adg_dim_style_get_instance_private(dim_style);
1222 return data->number_tag;
1226 * adg_dim_style_set_decimals:
1227 * @dim_style: an #AdgDimStyle object
1228 * @decimals: number of significant decimals
1230 * Sets a new value in the #AdgDimStyle:decimals property.
1232 * Since: 1.0
1234 void
1235 adg_dim_style_set_decimals(AdgDimStyle *dim_style, gint decimals)
1237 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
1238 g_object_set(dim_style, "decimals", decimals, NULL);
1242 * adg_dim_style_get_decimals:
1243 * @dim_style: an #AdgDimStyle object
1245 * Gets the decimals the value of a dimension will be rounded to before the
1246 * rendering.
1248 * Returns: the number of significant decimals or -2 on errors.
1250 * Since: 1.0
1252 gint
1253 adg_dim_style_get_decimals(AdgDimStyle *dim_style)
1255 AdgDimStylePrivate *data;
1257 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), -2);
1259 data = adg_dim_style_get_instance_private(dim_style);
1260 return data->decimals;
1264 * adg_dim_style_set_rounding:
1265 * @dim_style: an #AdgDimStyle object
1266 * @rounding: number of significant decimals of the raw value
1268 * Sets a new value in the #AdgDimStyle:rounding property.
1270 * Since: 1.0
1272 void
1273 adg_dim_style_set_rounding(AdgDimStyle *dim_style, gint rounding)
1275 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
1276 g_object_set(dim_style, "rounding", rounding, NULL);
1280 * adg_dim_style_get_rounding:
1281 * @dim_style: an #AdgDimStyle object
1283 * Gets the number of decimals the raw value must be rounded to.
1285 * Returns: the number of significant decimals or -2 on errors.
1287 * Since: 1.0
1289 gint
1290 adg_dim_style_get_rounding(AdgDimStyle *dim_style)
1292 AdgDimStylePrivate *data;
1294 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), -2);
1296 data = adg_dim_style_get_instance_private(dim_style);
1297 return data->rounding;
1301 * adg_dim_style_convert:
1302 * @dim_style: an #AdgDimStyle object
1303 * @value: (inout): the value to convert
1304 * @format: the convertion to apply
1306 * Converts @value using the specific @format algorithm and store the
1307 * result in @value itself. If @value is %NULL, nothing is performed.
1309 * In the following the allowed values for @format:
1310 * - 'a': the raw @value, i.e. no conversion is performed;
1311 * - 'i': the raw number of minutes, i.e. the fractional part of @value x 60
1312 * - 'e': the raw number of seconds, i.e. the fractional part of the raw
1313 * number of minutes x 60
1314 * - 'D': the truncated value of the raw value ('a');
1315 * - 'd': the rounded value of the raw value ('a');
1316 * - 'M': the truncated value of the raw number of minutes ('i');
1317 * - 'm': the rounded value of the raw number of minutes ('i');
1318 * - 'S': the truncated value of the raw number of seconds ('e');
1319 * - 's': the rounded value of the raw number of seconds ('e');
1321 * The rounding is done according to the number of decimal specified in
1322 * #AdgDimStyle:decimals.
1324 * Returns: %TRUE if @value has been converted, %FALSE on errors.
1326 * Since: 1.0
1328 gboolean
1329 adg_dim_style_convert(AdgDimStyle *dim_style, gdouble *value, gchar format)
1331 AdgDimStylePrivate *data;
1333 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), FALSE);
1335 /* Inout parameter not provided: just return FALSE */
1336 if (value == NULL) {
1337 return FALSE;
1340 data = adg_dim_style_get_instance_private(dim_style);
1342 /* Round the raw value, if requested */
1343 if (data->rounding > -1) {
1344 gdouble coefficient = pow(10, data->rounding);
1345 *value = round(*value * coefficient) / coefficient;
1348 switch (format) {
1350 case 'a': /* Raw value */
1351 break;
1353 case 'i': /* Raw minutes */
1354 *value = (*value - (gint) *value) * 60;
1355 break;
1357 case 'e': /* Raw seconds */
1358 adg_dim_style_convert(dim_style, value, 'i');
1359 *value = (*value - (gint) *value) * 60;
1360 break;
1362 case 'D': /* Truncated value */
1363 *value = (gint) *value;
1364 break;
1366 case 'd': /* Rounded value */
1367 *value = adg_round(*value, data->decimals);
1368 break;
1370 case 'M': /* Truncated minutes */
1371 adg_dim_style_convert(dim_style, value, 'i');
1372 *value = (gint) *value;
1373 break;
1375 case 'm': /* Rounded minutes */
1376 adg_dim_style_convert(dim_style, value, 'i');
1377 *value = adg_round(*value, data->decimals);
1378 break;
1380 case 'S': /* Truncated seconds */
1381 adg_dim_style_convert(dim_style, value, 'e');
1382 *value = (gint) *value;
1383 break;
1385 case 's': /* Rounded seconds */
1386 adg_dim_style_convert(dim_style, value, 'e');
1387 *value = adg_round(*value, data->decimals);
1388 break;
1390 default:
1391 g_return_val_if_reached(FALSE);
1392 return FALSE;
1395 return TRUE;
1399 static AdgStyle *
1400 _adg_clone(AdgStyle *style)
1402 AdgDimStyle *dim_style;
1403 AdgMarker *marker;
1405 dim_style = (AdgDimStyle *) adg_object_clone(G_OBJECT(style));
1407 /* Manually clone the marker because the underlying properties are
1408 * writable only */
1409 marker = adg_dim_style_marker1_new((AdgDimStyle *) style);
1410 adg_dim_style_set_marker1(dim_style, marker);
1411 g_object_unref(marker);
1413 marker = adg_dim_style_marker2_new((AdgDimStyle *) style);
1414 adg_dim_style_set_marker2(dim_style, marker);
1415 g_object_unref(marker);
1417 return (AdgStyle *) dim_style;
1420 static void
1421 _adg_apply(AdgStyle *style, AdgEntity *entity, cairo_t *cr)
1423 AdgDimStylePrivate *data = adg_dim_style_get_instance_private((AdgDimStyle *) style);
1424 adg_entity_apply_dress(entity, data->color_dress, cr);
1427 static AdgMarker *
1428 _adg_marker_new(const AdgMarkerData *marker_data)
1430 if (marker_data->type == 0)
1431 return NULL;
1433 return (AdgMarker *) g_object_new_with_properties(marker_data->type,
1434 marker_data->n_properties,
1435 marker_data->names,
1436 marker_data->values);
1439 static void
1440 _adg_marker_data_set(AdgMarkerData *marker_data, AdgMarker *marker)
1442 g_return_if_fail(marker == NULL || ADG_IS_MARKER(marker));
1444 /* Free the previous marker data, if any */
1445 _adg_marker_data_unset(marker_data);
1447 if (marker) {
1448 GObject *object;
1449 GParamSpec **specs;
1450 GParamSpec *spec;
1451 guint n;
1452 GValue *value;
1454 object = (GObject *) marker;
1455 specs = g_object_class_list_properties(G_OBJECT_GET_CLASS(marker),
1456 &marker_data->n_properties);
1458 marker_data->type = G_TYPE_FROM_INSTANCE(marker);
1459 marker_data->names = g_new0(const gchar *, marker_data->n_properties);
1460 marker_data->values = g_new0(GValue, marker_data->n_properties);
1462 for (n = 0; n < marker_data->n_properties; ++n) {
1463 spec = specs[n];
1465 /* Using intern strings because `name` is const.
1466 * GObject properties are internally managed using non-static
1467 * GQuark, so g_intern_string() is the way to go */
1468 marker_data->names[n] = g_intern_string(spec->name);
1470 value = &marker_data->values[n];
1471 g_value_init(value, spec->value_type);
1472 g_object_get_property(object, spec->name, value);
1475 g_free(specs);
1479 static void
1480 _adg_marker_data_unset(AdgMarkerData *marker_data)
1482 guint n;
1484 for (n = 0; n < marker_data->n_properties; ++n) {
1485 g_value_unset(&marker_data->values[n]);
1488 g_free(marker_data->names);
1489 g_free(marker_data->values);
1491 marker_data->type = 0;
1492 marker_data->n_properties = 0;
1493 marker_data->names = NULL;
1494 marker_data->values = NULL;