doc: update copyright line for 2019
[adg.git] / src / adg / adg-dim-style.c
blobe59810d965a4a40fb3d3a87881b3586763886363
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2019 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(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_set_marker (AdgMarkerData *marker_data,
130 AdgMarker *marker);
131 static void _adg_free_marker (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 g_type_class_add_private(klass, sizeof(AdgDimStylePrivate));
146 gobject_class->finalize = _adg_finalize;
147 gobject_class->get_property = _adg_get_property;
148 gobject_class->set_property = _adg_set_property;
150 style_class->clone = _adg_clone;
151 style_class->apply = _adg_apply;
153 param = g_param_spec_object("marker1",
154 P_("First Marker"),
155 P_("The template entity to use as first marker"),
156 ADG_TYPE_MARKER,
157 G_PARAM_WRITABLE);
158 g_object_class_install_property(gobject_class, PROP_MARKER1, param);
160 param = g_param_spec_object("marker2",
161 P_("Second Marker"),
162 P_("The template entity to use as second marker"),
163 ADG_TYPE_MARKER,
164 G_PARAM_WRITABLE);
165 g_object_class_install_property(gobject_class, PROP_MARKER2, param);
167 param = adg_param_spec_dress("color-dress",
168 P_("Color Dress"),
169 P_("Color dress for the whole dimension"),
170 ADG_DRESS_COLOR_DIMENSION,
171 G_PARAM_READWRITE);
172 g_object_class_install_property(gobject_class, PROP_COLOR_DRESS, param);
174 param = adg_param_spec_dress("value-dress",
175 P_("Value Dress"),
176 P_("Font dress for the nominal value of the dimension"),
177 ADG_DRESS_FONT_QUOTE_TEXT,
178 G_PARAM_READWRITE);
179 g_object_class_install_property(gobject_class, PROP_VALUE_DRESS, param);
181 param = adg_param_spec_dress("min-dress",
182 P_("Minimum Limit Dress"),
183 P_("Font dress for the lower limit value"),
184 ADG_DRESS_FONT_QUOTE_ANNOTATION,
185 G_PARAM_READWRITE);
186 g_object_class_install_property(gobject_class, PROP_MIN_DRESS, param);
188 param = adg_param_spec_dress("max-dress",
189 P_("Maximum Limit Dress"),
190 P_("Font dress for the upper limit value"),
191 ADG_DRESS_FONT_QUOTE_ANNOTATION,
192 G_PARAM_READWRITE);
193 g_object_class_install_property(gobject_class, PROP_MAX_DRESS, param);
195 param = adg_param_spec_dress("line-dress",
196 P_("Line Dress"),
197 P_("Line dress for the baseline and the extension lines"),
198 ADG_DRESS_LINE_DIMENSION,
199 G_PARAM_READWRITE);
200 g_object_class_install_property(gobject_class, PROP_LINE_DRESS, param);
202 param = g_param_spec_double("from-offset",
203 P_("From Offset"),
204 P_("Offset (in global space) of the extension lines from the path to the quote"),
205 0, G_MAXDOUBLE, 5,
206 G_PARAM_READWRITE);
207 g_object_class_install_property(gobject_class, PROP_FROM_OFFSET, param);
209 param = g_param_spec_double("to-offset",
210 P_("To Offset"),
211 P_("How many extend (in global space) the extension lines after hitting the baseline"),
212 0, G_MAXDOUBLE, 5,
213 G_PARAM_READWRITE);
214 g_object_class_install_property(gobject_class, PROP_TO_OFFSET, param);
216 param = g_param_spec_double("beyond",
217 P_("Beyond Length"),
218 P_("How much the baseline should be extended (in global space) beyond the extension lines on dimensions with outside markers"),
219 0, G_MAXDOUBLE, 20,
220 G_PARAM_READWRITE);
221 g_object_class_install_property(gobject_class, PROP_BEYOND, param);
223 param = g_param_spec_double("baseline-spacing",
224 P_("Baseline Spacing"),
225 P_("Distance between two consecutive baselines while stacking dimensions"),
226 0, G_MAXDOUBLE, 32,
227 G_PARAM_READWRITE);
228 g_object_class_install_property(gobject_class, PROP_BASELINE_SPACING, param);
230 param = g_param_spec_double("limits-spacing",
231 P_("Limits Spacing"),
232 P_("Distance between limits/tolerances"),
233 -G_MAXDOUBLE, G_MAXDOUBLE, 2,
234 G_PARAM_READWRITE);
235 g_object_class_install_property(gobject_class, PROP_LIMITS_SPACING, param);
237 param = g_param_spec_boxed("quote-shift",
238 P_("Quote Shift"),
239 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)"),
240 CPML_TYPE_PAIR,
241 G_PARAM_READWRITE);
242 g_object_class_install_property(gobject_class, PROP_QUOTE_SHIFT, param);
244 param = g_param_spec_boxed("limits-shift",
245 P_("Limits Shift"),
246 P_("Used to specify a smooth displacement (in global space) for the limits/tolerances by taking as reference the perfect compact position"),
247 CPML_TYPE_PAIR,
248 G_PARAM_READWRITE);
249 g_object_class_install_property(gobject_class, PROP_LIMITS_SHIFT, param);
251 param = g_param_spec_string("number-format",
252 P_("Number Format"),
253 P_("The format (in printf style) of the numeric component of the basic value"),
254 "%-.7g",
255 G_PARAM_READWRITE);
256 g_object_class_install_property(gobject_class, PROP_NUMBER_FORMAT, param);
258 param = g_param_spec_string("number-arguments",
259 P_("Number Arguments"),
260 P_("The arguments to pass to the format function: see adg_dim_style_set_number_arguments() for further details"),
261 "d",
262 G_PARAM_READWRITE);
263 g_object_class_install_property(gobject_class, PROP_NUMBER_ARGUMENTS, param);
265 param = g_param_spec_string("number-tag",
266 P_("Number Tag"),
267 P_("The tag to substitute inside the value template string"),
268 "<>",
269 G_PARAM_READWRITE);
270 g_object_class_install_property(gobject_class, PROP_NUMBER_TAG, param);
272 param = g_param_spec_int("decimals",
273 P_("Rounded Value Decimals"),
274 P_("Number of significant decimals to use in the format string for rounded values (-1 to disable)"),
275 -1, G_MAXINT,
277 G_PARAM_READWRITE);
278 g_object_class_install_property(gobject_class, PROP_DECIMALS, param);
280 param = g_param_spec_int("rounding",
281 P_("Raw Value Decimals"),
282 P_("Number of significant decimals the raw value must be rounded to (-1 to disable)"),
283 -1, G_MAXINT,
285 G_PARAM_READWRITE);
286 g_object_class_install_property(gobject_class, PROP_ROUNDING, param);
289 static void
290 adg_dim_style_init(AdgDimStyle *dim_style)
292 AdgDimStylePrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(dim_style,
293 ADG_TYPE_DIM_STYLE,
294 AdgDimStylePrivate);
296 data->marker1.type = 0;
297 data->marker1.n_parameters = 0;
298 data->marker1.parameters = NULL;
299 data->marker2.type = 0;
300 data->marker2.n_parameters = 0;
301 data->marker2.parameters = NULL;
302 data->color_dress = ADG_DRESS_COLOR_DIMENSION;
303 data->value_dress = ADG_DRESS_FONT_QUOTE_TEXT;
304 data->min_dress = ADG_DRESS_FONT_QUOTE_ANNOTATION;
305 data->max_dress = ADG_DRESS_FONT_QUOTE_ANNOTATION;
306 data->line_dress = ADG_DRESS_LINE_DIMENSION;
307 data->marker_dress = ADG_DRESS_UNDEFINED;
308 data->from_offset = 6;
309 data->to_offset = 6;
310 data->beyond = 20;
311 data->baseline_spacing = 32;
312 data->limits_spacing = 0;
313 data->quote_shift.x = 4;
314 data->quote_shift.y = -1;
315 data->limits_shift.x = +2;
316 data->limits_shift.y = +2;
317 data->number_format = g_strdup("%-.7g");
318 data->number_arguments = g_strdup("d");
319 data->number_tag = g_strdup("<>");
320 data->decimals = 2;
321 data->rounding = 6;
323 dim_style->data = data;
326 static void
327 _adg_finalize(GObject *object)
329 AdgDimStylePrivate *data = ((AdgDimStyle *) object)->data;
331 _adg_free_marker(&data->marker1);
332 _adg_free_marker(&data->marker2);
334 g_free(data->number_format);
335 data->number_format = NULL;
337 g_free(data->number_arguments);
338 data->number_arguments = NULL;
340 g_free(data->number_tag);
341 data->number_tag = NULL;
344 static void
345 _adg_get_property(GObject *object, guint prop_id,
346 GValue *value, GParamSpec *pspec)
348 AdgDimStylePrivate *data = ((AdgDimStyle *) object)->data;
350 switch (prop_id) {
351 case PROP_COLOR_DRESS:
352 g_value_set_enum(value, data->color_dress);
353 break;
354 case PROP_VALUE_DRESS:
355 g_value_set_enum(value, data->value_dress);
356 break;
357 case PROP_MIN_DRESS:
358 g_value_set_enum(value, data->min_dress);
359 break;
360 case PROP_MAX_DRESS:
361 g_value_set_enum(value, data->max_dress);
362 break;
363 case PROP_LINE_DRESS:
364 g_value_set_enum(value, data->line_dress);
365 break;
366 case PROP_FROM_OFFSET:
367 g_value_set_double(value, data->from_offset);
368 break;
369 case PROP_TO_OFFSET:
370 g_value_set_double(value, data->to_offset);
371 break;
372 case PROP_BEYOND:
373 g_value_set_double(value, data->beyond);
374 break;
375 case PROP_BASELINE_SPACING:
376 g_value_set_double(value, data->baseline_spacing);
377 break;
378 case PROP_LIMITS_SPACING:
379 g_value_set_double(value, data->limits_spacing);
380 break;
381 case PROP_QUOTE_SHIFT:
382 g_value_set_boxed(value, &data->quote_shift);
383 break;
384 case PROP_LIMITS_SHIFT:
385 g_value_set_boxed(value, &data->limits_shift);
386 break;
387 case PROP_NUMBER_FORMAT:
388 g_value_set_string(value, data->number_format);
389 break;
390 case PROP_NUMBER_ARGUMENTS:
391 g_value_set_string(value, data->number_arguments);
392 break;
393 case PROP_NUMBER_TAG:
394 g_value_set_string(value, data->number_tag);
395 break;
396 case PROP_DECIMALS:
397 g_value_set_int(value, data->decimals);
398 break;
399 case PROP_ROUNDING:
400 g_value_set_int(value, data->rounding);
401 break;
402 default:
403 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
404 break;
408 static void
409 _adg_set_property(GObject *object, guint prop_id,
410 const GValue *value, GParamSpec *pspec)
412 AdgDimStyle *dim_style;
413 AdgDimStylePrivate *data;
415 dim_style = (AdgDimStyle *) object;
416 data = dim_style->data;
418 switch (prop_id) {
419 case PROP_MARKER1:
420 _adg_set_marker(&data->marker1, g_value_get_object(value));
421 break;
422 case PROP_MARKER2:
423 _adg_set_marker(&data->marker2, g_value_get_object(value));
424 break;
425 case PROP_COLOR_DRESS:
426 data->color_dress = g_value_get_enum(value);
427 break;
428 case PROP_VALUE_DRESS:
429 data->value_dress = g_value_get_enum(value);
430 break;
431 case PROP_MIN_DRESS:
432 data->min_dress = g_value_get_enum(value);
433 break;
434 case PROP_MAX_DRESS:
435 data->max_dress = g_value_get_enum(value);
436 break;
437 case PROP_LINE_DRESS:
438 data->line_dress = g_value_get_enum(value);
439 break;
440 case PROP_FROM_OFFSET:
441 data->from_offset = g_value_get_double(value);
442 break;
443 case PROP_TO_OFFSET:
444 data->to_offset = g_value_get_double(value);
445 break;
446 case PROP_BEYOND:
447 data->beyond = g_value_get_double(value);
448 break;
449 case PROP_BASELINE_SPACING:
450 data->baseline_spacing = g_value_get_double(value);
451 break;
452 case PROP_LIMITS_SPACING:
453 data->limits_spacing = g_value_get_double(value);
454 break;
455 case PROP_QUOTE_SHIFT:
456 cpml_pair_copy(&data->quote_shift, g_value_get_boxed(value));
457 break;
458 case PROP_LIMITS_SHIFT:
459 cpml_pair_copy(&data->limits_shift, g_value_get_boxed(value));
460 break;
461 case PROP_NUMBER_FORMAT:
462 g_free(data->number_format);
463 data->number_format = g_value_dup_string(value);
464 break;
465 case PROP_NUMBER_ARGUMENTS: {
466 const gchar *arguments = g_value_get_string(value);
467 g_return_if_fail(arguments == NULL || strspn(arguments, VALID_FORMATS) == strlen(arguments));
468 g_free(data->number_arguments);
469 data->number_arguments = g_strdup(arguments);
470 break;
472 case PROP_NUMBER_TAG:
473 g_free(data->number_tag);
474 data->number_tag = g_value_dup_string(value);
475 break;
476 case PROP_DECIMALS:
477 data->decimals = g_value_get_int(value);
478 break;
479 case PROP_ROUNDING:
480 data->rounding = g_value_get_int(value);
481 break;
482 default:
483 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
484 break;
490 * adg_dim_style_new:
492 * Constructs a new empty dimension style initialized with default params.
494 * Returns: (transfer full): a newly created dimension style.
496 * Since: 1.0
498 AdgDimStyle *
499 adg_dim_style_new(void)
501 return g_object_new(ADG_TYPE_DIM_STYLE, NULL);
505 * adg_dim_style_set_marker1:
506 * @dim_style: an #AdgStyle
507 * @marker: an #AdgMarker derived entity
509 * Uses @marker as entity template to generate a new marker entity
510 * when a call to adg_dim_style_marker1_new() is made. It is allowed
511 * to pass <constant>NULL</constant> as @marker, in which case the
512 * template data of the first marker are unset.
514 * This method duplicates internally the property values of @marker,
515 * so any further change to @marker does not affect @dim_style anymore.
516 * This also means @marker could be destroyed without problems after
517 * this call because @dim_style uses only its property values and does
518 * not add any references to @marker.
520 * Since: 1.0
522 void
523 adg_dim_style_set_marker1(AdgDimStyle *dim_style, AdgMarker *marker)
525 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
526 g_object_set(dim_style, "marker1", marker, NULL);
530 * adg_dim_style_marker1_new:
531 * @dim_style: an #AdgDimStyle
533 * Creates a new marker entity by cloning the #AdgDimStyle:marker1
534 * object. The returned entity should be unreferenced with
535 * g_object_unref() when no longer needed.
537 * Returns: (transfer full): a newly created marker or <constant>NULL</constant> if the #AdgDimStyle:marker1 property is not set or on errors.
539 * Since: 1.0
541 AdgMarker *
542 adg_dim_style_marker1_new(AdgDimStyle *dim_style)
544 AdgDimStylePrivate *data;
546 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
548 data = dim_style->data;
550 return _adg_marker_new(&data->marker1);
554 * adg_dim_style_set_marker2:
555 * @dim_style: an #AdgStyle
556 * @marker: an #AdgMarker derived entity
558 * Uses @marker as entity template to generate a new marker entity
559 * when a call to adg_dim_style_marker2_new() is made. It is allowed
560 * to pass <constant>NULL</constant> as @marker, in which case the
561 * template data of the second marker are unset.
563 * This method duplicates internally the property values of @marker,
564 * so any further change to @marker does not affect @dim_style anymore.
565 * This also means @marker could be destroyed without problems after
566 * this call because @dim_style uses only its property values and does
567 * not add any references to @marker.
569 * Since: 1.0
571 void
572 adg_dim_style_set_marker2(AdgDimStyle *dim_style, AdgMarker *marker)
574 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
575 g_object_set(dim_style, "marker2", marker, NULL);
579 * adg_dim_style_marker2_new:
580 * @dim_style: an #AdgDimStyle
582 * Creates a new marker entity by cloning the #AdgDimStyle:marker2
583 * object. The returned entity should be unreferenced with
584 * g_object_unref() when no longer needed.
586 * Returns: (transfer full): a newly created marker or <constant>NULL</constant> if the #AdgDimStyle:marker2 property is not set or on errors.
588 * Since: 1.0
590 AdgMarker *
591 adg_dim_style_marker2_new(AdgDimStyle *dim_style)
593 AdgDimStylePrivate *data;
595 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
597 data = dim_style->data;
599 return _adg_marker_new(&data->marker2);
603 * adg_dim_style_set_color_dress:
604 * @dim_style: an #AdgDimStyle object
605 * @dress: the new color dress
607 * Sets a new color dress on @dim_style.
609 * Since: 1.0
611 void
612 adg_dim_style_set_color_dress(AdgDimStyle *dim_style, AdgDress dress)
614 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
615 g_object_set(dim_style, "color-dress", dress, NULL);
619 * adg_dim_style_get_color_dress:
620 * @dim_style: an #AdgDimStyle object
622 * Gets the @dim_style color dress to be used. This dress should be
623 * intended as a fallback color as it could be overriden by more
624 * specific dresses, such as a color explicitely specified on the
625 * #AdgDimStyle:value-dress.
627 * Returns: (transfer none): the color dress.
629 * Since: 1.0
631 AdgDress
632 adg_dim_style_get_color_dress(AdgDimStyle *dim_style)
634 AdgDimStylePrivate *data;
636 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), ADG_DRESS_UNDEFINED);
638 data = dim_style->data;
640 return data->color_dress;
644 * adg_dim_style_set_value_dress:
645 * @dim_style: an #AdgDimStyle object
646 * @dress: the new basic value font style
648 * Sets a new dress on @dim_style for the basic value.
650 * Since: 1.0
652 void
653 adg_dim_style_set_value_dress(AdgDimStyle *dim_style, AdgDress dress)
655 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
656 g_object_set(dim_style, "value-dress", dress, NULL);
660 * adg_dim_style_get_value_dress:
661 * @dim_style: an #AdgDimStyle object
663 * Gets the font dress to be used for the basic value of dimensions
664 * with @dim_style.
666 * Returns: (transfer none): the font dress.
668 * Since: 1.0
670 AdgDress
671 adg_dim_style_get_value_dress(AdgDimStyle *dim_style)
673 AdgDimStylePrivate *data;
675 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), ADG_DRESS_UNDEFINED);
677 data = dim_style->data;
679 return data->value_dress;
683 * adg_dim_style_set_min_dress:
684 * @dim_style: an #AdgDimStyle object
685 * @dress: the new lower limit dress
687 * Sets a new dress on @dim_style for the lower limit value.
689 * Since: 1.0
691 void
692 adg_dim_style_set_min_dress(AdgDimStyle *dim_style, AdgDress dress)
694 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
695 g_object_set(dim_style, "min-dress", dress, NULL);
699 * adg_dim_style_get_min_dress:
700 * @dim_style: an #AdgDimStyle object
702 * Gets the @dim_style dress to be used for the lower limit.
704 * Returns: (transfer none): the lower limit dress.
706 * Since: 1.0
708 AdgDress
709 adg_dim_style_get_min_dress(AdgDimStyle *dim_style)
711 AdgDimStylePrivate *data;
713 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), ADG_DRESS_UNDEFINED);
715 data = dim_style->data;
717 return data->min_dress;
721 * adg_dim_style_set_max_dress:
722 * @dim_style: an #AdgDimStyle object
723 * @dress: the new upper limit dress
725 * Sets a new dress on @dim_style for the upper limit value.
727 * Since: 1.0
729 void
730 adg_dim_style_set_max_dress(AdgDimStyle *dim_style, AdgDress dress)
732 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
733 g_object_set(dim_style, "max-dress", dress, NULL);
737 * adg_dim_style_get_max_dress:
738 * @dim_style: an #AdgDimStyle object
740 * Gets the @dim_style dress to be used for the upper limit.
742 * Returns: (transfer none): the upper limit dress.
744 * Since: 1.0
746 AdgDress
747 adg_dim_style_get_max_dress(AdgDimStyle *dim_style)
749 AdgDimStylePrivate *data;
751 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), ADG_DRESS_UNDEFINED);
753 data = dim_style->data;
755 return data->max_dress;
759 * adg_dim_style_set_line_dress:
760 * @dim_style: an #AdgDimStyle object
761 * @dress: the new line dress
763 * Sets a new line dress on @dim_style.
765 * Since: 1.0
767 void
768 adg_dim_style_set_line_dress(AdgDimStyle *dim_style, AdgDress dress)
770 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
771 g_object_set(dim_style, "line-dress", dress, NULL);
775 * adg_dim_style_get_line_dress:
776 * @dim_style: an #AdgDimStyle object
778 * Gets the line dress to be used for rendering the base and
779 * the extension lines with @dim_style.
781 * Returns: (transfer none): the line dress.
783 * Since: 1.0
785 AdgDress
786 adg_dim_style_get_line_dress(AdgDimStyle *dim_style)
788 AdgDimStylePrivate *data;
790 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), ADG_DRESS_UNDEFINED);
792 data = dim_style->data;
794 return data->line_dress;
798 * adg_dim_style_set_from_offset:
799 * @dim_style: an #AdgDimStyle object
800 * @offset: the new offset
802 * Sets a new value in the #AdgDimStyle:from-offset property.
804 * Since: 1.0
806 void
807 adg_dim_style_set_from_offset(AdgDimStyle *dim_style, gdouble offset)
809 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
810 g_object_set(dim_style, "from-offset", offset, NULL);
814 * adg_dim_style_get_from_offset:
815 * @dim_style: an #AdgDimStyle object
817 * Gets the distance (in global space) the extension lines must keep from the
818 * sensed points.
820 * Returns: the requested distance.
822 * Since: 1.0
824 gdouble
825 adg_dim_style_get_from_offset(AdgDimStyle *dim_style)
827 AdgDimStylePrivate *data;
829 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), 0);
831 data = dim_style->data;
833 return data->from_offset;
837 * adg_dim_style_set_to_offset:
838 * @dim_style: an #AdgDimStyle object
839 * @offset: the new offset
841 * Sets a new value in the #AdgDimStyle:to-offset property.
843 * Since: 1.0
845 void
846 adg_dim_style_set_to_offset(AdgDimStyle *dim_style, gdouble offset)
848 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
849 g_object_set(dim_style, "to-offset", offset, NULL);
853 * adg_dim_style_get_to_offset:
854 * @dim_style: an #AdgDimStyle object
856 * Gets how much (in global space) the extension lines must extend after
857 * crossing the baseline.
859 * Returns: the requested distance.
861 * Since: 1.0
863 gdouble
864 adg_dim_style_get_to_offset(AdgDimStyle *dim_style)
866 AdgDimStylePrivate *data;
868 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), 0);
870 data = dim_style->data;
872 return data->to_offset;
876 * adg_dim_style_set_beyond:
877 * @dim_style: an #AdgDimStyle object
878 * @beyond: the new length
880 * Sets a new value in the #AdgDimStyle:beyond property.
882 * Since: 1.0
884 void
885 adg_dim_style_set_beyond(AdgDimStyle *dim_style, gdouble beyond)
887 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
888 g_object_set(dim_style, "beyond", beyond, NULL);
892 * adg_dim_style_get_beyond:
893 * @dim_style: an #AdgDimStyle object
895 * Gets how much (in global space) the baseline should extend beyond
896 * the extension lines on dimension with outside markers.
898 * Returns: the requested beyond length.
900 * Since: 1.0
902 gdouble
903 adg_dim_style_get_beyond(AdgDimStyle *dim_style)
905 AdgDimStylePrivate *data;
907 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), 0);
909 data = dim_style->data;
911 return data->beyond;
915 * adg_dim_style_set_baseline_spacing:
916 * @dim_style: an #AdgDimStyle object
917 * @spacing: the new spacing
919 * Sets a new value in the #AdgDimStyle:baseline-spacing value.
921 * Since: 1.0
923 void
924 adg_dim_style_set_baseline_spacing(AdgDimStyle *dim_style, gdouble spacing)
926 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
927 g_object_set(dim_style, "baseline-spacing", spacing, NULL);
931 * adg_dim_style_get_baseline_spacing:
932 * @dim_style: an #AdgDimStyle object
934 * Gets the distance between two consecutive baselines
935 * while stacking dimensions.
937 * Returns: the requested spacing.
939 * Since: 1.0
941 gdouble
942 adg_dim_style_get_baseline_spacing(AdgDimStyle *dim_style)
944 AdgDimStylePrivate *data;
946 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), 0);
948 data = dim_style->data;
950 return data->baseline_spacing;
954 * adg_dim_style_set_limits_spacing:
955 * @dim_style: an #AdgDimStyle object
956 * @spacing: the new spacing
958 * Sets a new #AdgDimStyle:limits-spacing value.
960 * Since: 1.0
962 void
963 adg_dim_style_set_limits_spacing(AdgDimStyle *dim_style, gdouble spacing)
965 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
966 g_object_set(dim_style, "limits-spacing", spacing, NULL);
970 * adg_dim_style_get_limits_spacing:
971 * @dim_style: an #AdgDimStyle object
973 * Gets the distance (in global space) between the limits/tolerances.
975 * Returns: the requested spacing.
977 * Since: 1.0
979 gdouble
980 adg_dim_style_get_limits_spacing(AdgDimStyle *dim_style)
982 AdgDimStylePrivate *data;
984 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), 0);
986 data = dim_style->data;
988 return data->limits_spacing;
992 * adg_dim_style_set_quote_shift:
993 * @dim_style: an #AdgDimStyle object
994 * @shift: the new displacement
996 * Sets a new #AdgDimStyle:quote-shift value.
998 * Since: 1.0
1000 void
1001 adg_dim_style_set_quote_shift(AdgDimStyle *dim_style, const CpmlPair *shift)
1003 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
1004 g_object_set(dim_style, "quote-shift", shift, NULL);
1008 * adg_dim_style_get_quote_shift:
1009 * @dim_style: an #AdgDimStyle object
1011 * Gets the smooth displacement of the quote. The returned pointer refers
1012 * to an internal allocated struct and must not be modified or freed.
1014 * Returns: (transfer none): the requested shift.
1016 * Since: 1.0
1018 const CpmlPair *
1019 adg_dim_style_get_quote_shift(AdgDimStyle *dim_style)
1021 AdgDimStylePrivate *data;
1023 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
1025 data = dim_style->data;
1027 return &data->quote_shift;
1031 * adg_dim_style_set_limits_shift:
1032 * @dim_style: an #AdgDimStyle object
1033 * @shift: the new displacement
1035 * Sets a new #AdgDimStyle:limits-shift value.
1037 * Since: 1.0
1039 void
1040 adg_dim_style_set_limits_shift(AdgDimStyle *dim_style, const CpmlPair *shift)
1042 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
1043 g_object_set(dim_style, "limits-shift", shift, NULL);
1047 * adg_dim_style_get_limits_shift:
1048 * @dim_style: an #AdgDimStyle object
1050 * Gets the smooth displacement for the limits. The returned pointer
1051 * refers to an internal allocated struct and must not be modified or freed.
1053 * Returns: (transfer none): the requested shift.
1055 * Since: 1.0
1057 const CpmlPair *
1058 adg_dim_style_get_limits_shift(AdgDimStyle *dim_style)
1060 AdgDimStylePrivate *data;
1062 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
1064 data = dim_style->data;
1066 return &data->limits_shift;
1070 * adg_dim_style_set_number_format:
1071 * @dim_style: an #AdgDimStyle object
1072 * @format: the new format to adopt
1074 * Sets a new value in the #AdgDimStyle:number-format property.
1076 * @format is similar to a printf() style format string but only 'e', 'E',
1077 * 'f', 'F', 'g' and 'G' specifiers are allowed. For reference, the
1078 * implementation leverages the g_ascii_formatd() GLib function. If you want
1079 * to use special characters (%"(", %")" and %"%") as literals you need to
1080 * escape them with a backslash.
1082 * You can use round parenthesis to group together one or more % directives
1083 * with other related literals. In that case, when the value bound to the
1084 * directive will be 0, the whole group will disappear. Some example:
1086 * |[
1087 * AdgDim *dim;
1088 * AdgDimStyle *dim_style;
1089 * gchar *text;
1091 * dim = ADG_DIM(adg_ldim_new());
1092 * dim_style = ADG_DIM_STYLE(adg_entity_style(ADG_ENTITY(dim), ADG_DRESS_DIMENSION));
1094 * adg_dim_style_set_number_arguments(dim_style, "dD");
1095 * adg_dim_style_set_number_format(dim_style, "(%g)( truncated to %g)");
1097 * text = adg_dim_get_text(dim, 1.2);
1098 * g_print("%s\n", text); // Prints "1.2 truncated to 1"
1099 * g_free(text);
1101 * text = adg_dim_get_text(dim, 0.2);
1102 * g_print("%s\n", text); // Prints "0.2"
1103 * g_free(text);
1105 * text = adg_dim_get_text(dim, 0);
1106 * g_print("%s\n", text); // Prints ""
1107 * g_free(text);
1108 * ]|
1110 * Groups can be nested and can have more than one value, in which case all
1111 * the values contained in a group must be 0 in order to let it disappear.
1112 * This comes in handy for removing trailing 0 fields. A typical example is
1113 * the sexagesimal representation of angles:
1115 * |[
1116 * adg_dim_style_set_number_arguments(dim_style, "DMs");
1117 * adg_dim_style_set_number_format(dim_style, "%g°(%g'(%g\"))");
1119 * text = adg_dim_get_text(dim, 1.5);
1120 * g_print("%s\n", text); // Prints "1°30'"
1121 * g_free(text);
1123 * text = adg_dim_get_text(dim, 2.002777);
1124 * g_print("%s\n", text); // Prints "2°0'10\""
1125 * g_free(text);
1126 * ]|
1128 * Since: 1.0
1130 void
1131 adg_dim_style_set_number_format(AdgDimStyle *dim_style, const gchar *format)
1133 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
1134 g_object_set(dim_style, "number-format", format, NULL);
1138 * adg_dim_style_get_number_format:
1139 * @dim_style: an #AdgDimStyle object
1141 * Gets the number format (in printf style) of this quoting style. The
1142 * returned pointer refers to internally managed text that must not be
1143 * modified or freed.
1145 * Returns: (transfer none): the requested format.
1147 * Since: 1.0
1149 const gchar *
1150 adg_dim_style_get_number_format(AdgDimStyle *dim_style)
1152 AdgDimStylePrivate *data;
1154 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
1156 data = dim_style->data;
1158 return data->number_format;
1162 * adg_dim_style_set_number_arguments:
1163 * @dim_style: an #AdgDimStyle object
1164 * @arguments: the arguments to pass to the formatting function
1166 * A string that identifies the arguments to pass to the formatting function.
1167 * See adg_dim_style_convert() to know the allowed character that can be
1168 * included into this string.
1170 * The number of arguments (i.e. the @arguments length) must match the
1171 * #AdgDimStyle:number-format property (i.e. the number of % directives
1172 * included in that property). See adg_dim_style_set_number_format() for more
1173 * technical details and some examples.
1175 * Since: 1.0
1177 void
1178 adg_dim_style_set_number_arguments(AdgDimStyle *dim_style, const gchar *arguments)
1180 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
1181 g_object_set(dim_style, "number-arguments", arguments, NULL);
1185 * adg_dim_style_get_number_arguments:
1186 * @dim_style: an #AdgDimStyle object
1188 * Gets the arguments used by the formatting function. See
1189 * adg_dim_style_set_number_arguments() for details on what this means.
1191 * Returns: (transfer none): the requested arguments.
1193 * Since: 1.0
1195 const gchar *
1196 adg_dim_style_get_number_arguments(AdgDimStyle *dim_style)
1198 AdgDimStylePrivate *data;
1200 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
1202 data = dim_style->data;
1204 return data->number_arguments;
1208 * adg_dim_style_set_number_tag:
1209 * @dim_style: an #AdgDimStyle object
1210 * @tag: the new tag
1212 * Sets a new tag in the #AdgDimStyle:number-tag property.
1214 * Since: 1.0
1216 void
1217 adg_dim_style_set_number_tag(AdgDimStyle *dim_style, const gchar *tag)
1219 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
1220 g_object_set(dim_style, "number-tag", tag, NULL);
1224 * adg_dim_style_get_number_tag:
1225 * @dim_style: an #AdgDimStyle object
1227 * Gets the number tag of @dim_style. This tag will be used while
1228 * generating the set values of the dimensions bound to this style:
1229 * check the #AdgDim:value documentation for further details.
1231 * The returned pointer refers to internally managed text that
1232 * must not be modified or freed.
1234 * Returns: (transfer none): the requested tag.
1236 * Since: 1.0
1238 const gchar *
1239 adg_dim_style_get_number_tag(AdgDimStyle *dim_style)
1241 AdgDimStylePrivate *data;
1243 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), NULL);
1245 data = dim_style->data;
1247 return data->number_tag;
1251 * adg_dim_style_set_decimals:
1252 * @dim_style: an #AdgDimStyle object
1253 * @decimals: number of significant decimals
1255 * Sets a new value in the #AdgDimStyle:decimals property.
1257 * Since: 1.0
1259 void
1260 adg_dim_style_set_decimals(AdgDimStyle *dim_style, gint decimals)
1262 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
1263 g_object_set(dim_style, "decimals", decimals, NULL);
1267 * adg_dim_style_get_decimals:
1268 * @dim_style: an #AdgDimStyle object
1270 * Gets the decimals the value of a dimension will be rounded to before the
1271 * rendering.
1273 * Returns: the number of significant decimals or -2 on errors.
1275 * Since: 1.0
1277 gint
1278 adg_dim_style_get_decimals(AdgDimStyle *dim_style)
1280 AdgDimStylePrivate *data;
1282 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), -2);
1284 data = dim_style->data;
1286 return data->decimals;
1290 * adg_dim_style_set_rounding:
1291 * @dim_style: an #AdgDimStyle object
1292 * @rounding: number of significant decimals of the raw value
1294 * Sets a new value in the #AdgDimStyle:rounding property.
1296 * Since: 1.0
1298 void
1299 adg_dim_style_set_rounding(AdgDimStyle *dim_style, gint rounding)
1301 g_return_if_fail(ADG_IS_DIM_STYLE(dim_style));
1302 g_object_set(dim_style, "rounding", rounding, NULL);
1306 * adg_dim_style_get_rounding:
1307 * @dim_style: an #AdgDimStyle object
1309 * Gets the number of decimals the raw value must be rounded to.
1311 * Returns: the number of significant decimals or -2 on errors.
1313 * Since: 1.0
1315 gint
1316 adg_dim_style_get_rounding(AdgDimStyle *dim_style)
1318 AdgDimStylePrivate *data;
1320 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), -2);
1322 data = dim_style->data;
1324 return data->rounding;
1328 * adg_dim_style_convert:
1329 * @dim_style: an #AdgDimStyle object
1330 * @value: (inout): the value to convert
1331 * @format: the convertion to apply
1333 * Converts @value using the specific @format algorithm and store the
1334 * result in @value itself. If @value is %NULL, nothing is performed.
1336 * In the following the allowed values for @format:
1337 * - 'a': the raw @value, i.e. no conversion is performed;
1338 * - 'i': the raw number of minutes, i.e. the fractional part of @value x 60
1339 * - 'e': the raw number of seconds, i.e. the fractional part of the raw
1340 * number of minutes x 60
1341 * - 'D': the truncated value of the raw value ('a');
1342 * - 'd': the rounded value of the raw value ('a');
1343 * - 'M': the truncated value of the raw number of minutes ('i');
1344 * - 'm': the rounded value of the raw number of minutes ('i');
1345 * - 'S': the truncated value of the raw number of seconds ('e');
1346 * - 's': the rounded value of the raw number of seconds ('e');
1348 * The rounding is done according to the number of decimal specified in
1349 * #AdgDimStyle:decimals.
1351 * Returns: %TRUE if @value has been converted, %FALSE on errors.
1353 * Since: 1.0
1355 gboolean
1356 adg_dim_style_convert(AdgDimStyle *dim_style, gdouble *value, gchar format)
1358 AdgDimStylePrivate *data;
1360 g_return_val_if_fail(ADG_IS_DIM_STYLE(dim_style), FALSE);
1362 /* Inout parameter not provided: just return FALSE */
1363 if (value == NULL) {
1364 return FALSE;
1367 data = dim_style->data;
1369 /* Round the raw value, if requested */
1370 if (data->rounding > -1) {
1371 gdouble coefficient = pow(10, data->rounding);
1372 *value = round(*value * coefficient) / coefficient;
1375 switch (format) {
1377 case 'a': /* Raw value */
1378 break;
1380 case 'i': /* Raw minutes */
1381 *value = (*value - (gint) *value) * 60;
1382 break;
1384 case 'e': /* Raw seconds */
1385 adg_dim_style_convert(dim_style, value, 'i');
1386 *value = (*value - (gint) *value) * 60;
1387 break;
1389 case 'D': /* Truncated value */
1390 *value = (gint) *value;
1391 break;
1393 case 'd': /* Rounded value */
1394 *value = adg_round(*value, data->decimals);
1395 break;
1397 case 'M': /* Truncated minutes */
1398 adg_dim_style_convert(dim_style, value, 'i');
1399 *value = (gint) *value;
1400 break;
1402 case 'm': /* Rounded minutes */
1403 adg_dim_style_convert(dim_style, value, 'i');
1404 *value = adg_round(*value, data->decimals);
1405 break;
1407 case 'S': /* Truncated seconds */
1408 adg_dim_style_convert(dim_style, value, 'e');
1409 *value = (gint) *value;
1410 break;
1412 case 's': /* Rounded seconds */
1413 adg_dim_style_convert(dim_style, value, 'e');
1414 *value = adg_round(*value, data->decimals);
1415 break;
1417 default:
1418 g_return_val_if_reached(FALSE);
1419 return FALSE;
1422 return TRUE;
1426 static AdgStyle *
1427 _adg_clone(AdgStyle *style)
1429 AdgDimStyle *dim_style;
1430 AdgMarker *marker;
1432 dim_style = (AdgDimStyle *) adg_object_clone(G_OBJECT(style));
1434 /* Manually clone the marker because the underlying properties are
1435 * writable only */
1436 marker = adg_dim_style_marker1_new((AdgDimStyle *) style);
1437 adg_dim_style_set_marker1(dim_style, marker);
1438 g_object_unref(marker);
1440 marker = adg_dim_style_marker2_new((AdgDimStyle *) style);
1441 adg_dim_style_set_marker2(dim_style, marker);
1442 g_object_unref(marker);
1444 return (AdgStyle *) dim_style;
1447 static void
1448 _adg_apply(AdgStyle *style, AdgEntity *entity, cairo_t *cr)
1450 AdgDimStylePrivate *data = ((AdgDimStyle *) style)->data;
1451 adg_entity_apply_dress(entity, data->color_dress, cr);
1454 static AdgMarker *
1455 _adg_marker_new(const AdgMarkerData *marker_data)
1457 if (marker_data->type == 0)
1458 return NULL;
1460 return g_object_newv(marker_data->type,
1461 marker_data->n_parameters,
1462 marker_data->parameters);
1465 static void
1466 _adg_set_marker(AdgMarkerData *marker_data, AdgMarker *marker)
1468 g_return_if_fail(marker == NULL || ADG_IS_MARKER(marker));
1470 /* Free the previous marker data, if any */
1471 _adg_free_marker(marker_data);
1473 if (marker) {
1474 GObject *object;
1475 GParamSpec **specs;
1476 GParamSpec *spec;
1477 GParameter *parameter;
1478 guint n;
1480 object = (GObject *) marker;
1481 specs = g_object_class_list_properties(G_OBJECT_GET_CLASS(marker),
1482 &marker_data->n_parameters);
1484 marker_data->type = G_TYPE_FROM_INSTANCE(marker);
1485 marker_data->parameters = g_new0(GParameter, marker_data->n_parameters);
1487 for (n = 0; n < marker_data->n_parameters; ++n) {
1488 spec = specs[n];
1489 parameter = &marker_data->parameters[n];
1491 /* Using intern strings because GParameter:name is const.
1492 * GObject properties are internally managed using non-static
1493 * GQuark, so g_intern_string() is the way to go */
1494 parameter->name = g_intern_string(spec->name);
1496 g_value_init(&parameter->value, spec->value_type);
1497 g_object_get_property(object, spec->name, &parameter->value);
1500 g_free(specs);
1504 static void
1505 _adg_free_marker(AdgMarkerData *marker_data)
1507 guint n;
1509 for (n = 0; n < marker_data->n_parameters; ++n)
1510 g_value_unset(&marker_data->parameters[n].value);
1512 marker_data->type = 0;
1513 marker_data->n_parameters = 0;
1514 marker_data->parameters = NULL;