[AdgDress] Added missing documentation
[adg.git] / adg / adg-dress.c
blobb0ac101441ebea5cc53b1fb182912293bc41cbb3
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009 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-dress
23 * @Section_Id:AdgDress
24 * @title: AdgDress
25 * @short_description: The ADG way to associate styles to entities
27 * The dress is a virtualization of an #AdgStyle instance. #AdgEntity
28 * objects do not directly refer to #AdgStyle but use #AdgDress values
29 * instead. This allows some advanced operations, such as overriding
30 * a dress only in a specific entity branch of the hierarchy or
31 * customize multiple entities at once.
32 **/
34 /**
35 * AdgDress:
37 * An index representing a virtual #AdgStyle.
38 **/
40 /**
41 * ADG_VALUE_HOLDS_DRESS:
42 * @value: a #GValue
44 * Checks whether a #GValue is actually holding an #AdgDress value or not.
46 * Returns: %TRUE is @value is holding an #AdgDress, %FALSE otherwise
47 **/
50 #include "adg-dress.h"
51 #include "adg-dress-private.h"
52 #include "adg-color-style.h"
53 #include "adg-line-style.h"
54 #include "adg-font-style.h"
55 #include "adg-dim-style.h"
58 static AdgDress quark_to_dress (GQuark quark);
59 static void dress_to_string (const GValue *src,
60 GValue *dst);
61 static void string_to_dress (const GValue *src,
62 GValue *dst);
63 static void param_class_init (GParamSpecClass *klass);
64 static gboolean value_validate (GParamSpec *spec,
65 GValue *value);
67 static guint array_append (AdgDressPrivate *data);
68 static AdgDressPrivate *
69 array_lookup (guint n);
70 static guint array_len (void);
73 GType
74 adg_dress_get_type(void)
76 static GType type = 0;
78 if (G_UNLIKELY(type == 0)) {
79 const GTypeInfo info = { 0, };
81 type = g_type_register_static(G_TYPE_INT, "AdgDress", &info, 0);
83 g_value_register_transform_func(type, G_TYPE_STRING, dress_to_string);
84 g_value_register_transform_func(G_TYPE_STRING, type, string_to_dress);
87 return type;
90 /**
91 * adg_dress_new:
92 * @name: the dress name
93 * @style: the style to associate
95 * Creates a new dress. It is a convenient wrapper of adg_dress_new_full()
96 * that uses as ancestor the G_TYPE_FROM_INSTANCE() of @style.
98 * After a succesfull call, a new reference is added to @style.
100 * Returns: the new #AdgDress value or #ADG_DRESS_UNDEFINED on errors
102 AdgDress
103 adg_dress_new(const gchar *name, AdgStyle *style)
105 return adg_dress_new_full(name, style, G_TYPE_FROM_INSTANCE(style));
109 * adg_dress_new_full:
110 * @name: the dress name
111 * @style: the style to associate
112 * @ancestor_type: the common ancestor type
114 * Creates a new dress, explicitely setting the ancestor type.
115 * @ancestor_type must be present in the @style hierarchy: check
116 * out the adg_dress_set_style() documentation to know what the
117 * ancestor type is used for.
119 * If a dress with the same name exists, a warning is raised and
120 * #ADG_DRESS_UNDEFINED is returned without further actions.
122 * After a succesfull call, a new reference is added to @style.
124 * Returns: the new #AdgDress value or #ADG_DRESS_UNDEFINED on errors
126 AdgDress
127 adg_dress_new_full(const gchar *name, AdgStyle *style, GType ancestor_type)
129 GQuark quark;
130 AdgDress dress;
131 AdgDressPrivate data;
133 g_return_val_if_fail(name != NULL, 0);
134 g_return_val_if_fail(style != NULL, 0);
135 g_return_val_if_fail(G_TYPE_CHECK_INSTANCE_TYPE(style, ancestor_type), 0);
137 quark = g_quark_from_string(name);
138 dress = quark_to_dress(quark);
140 if (dress > 0) {
141 g_warning("%s: `%s' name yet used by the `%d' dress",
142 G_STRLOC, name, dress);
143 return ADG_DRESS_UNDEFINED;
146 data.quark = quark;
147 data.style = style;
148 data.ancestor_type = ancestor_type;
150 g_object_ref(style);
152 return array_append(&data) - 1;
156 * adg_dress_are_related:
157 * @dress1: an #AdgDress
158 * @dress2: another #AdgDress
160 * Checks whether @dress1 and @dress2 are related, that is
161 * if they have the same ancestor type as returned by
162 * adg_dress_get_ancestor_type().
164 * Returns: %TRUE if the dresses are related, %FALSE otherwise
166 gboolean
167 adg_dress_are_related(AdgDress dress1, AdgDress dress2)
169 GType ancestor_type1, ancestor_type2;
171 ancestor_type1 = adg_dress_get_ancestor_type(dress1);
172 if (ancestor_type1 <= 0)
173 return FALSE;
175 ancestor_type2 = adg_dress_get_ancestor_type(dress2);
176 if (ancestor_type2 <= 0)
177 return FALSE;
179 return ancestor_type1 == ancestor_type2;
183 * adg_dress_set:
184 * @dress: a pointer to an #AdgDress
185 * @src: the source dress
187 * Copies @src in @dress. This operation can be succesful only if
188 * @dress is #ADG_DRESS_UNDEFINED or if it contains a dress related
189 * to @src, that is adg_dress_are_related() returns %TRUE.
191 * Returns: %TRUE on copy done, %FALSE on copy failed or not needed
193 gboolean
194 adg_dress_set(AdgDress *dress, AdgDress src)
196 if (*dress == src)
197 return FALSE;
199 if (*dress != ADG_DRESS_UNDEFINED &&
200 !adg_dress_are_related(*dress, src)) {
201 const gchar *dress_name;
202 const gchar *src_name;
204 dress_name = adg_dress_name(*dress);
205 if (dress_name == NULL)
206 dress_name = "UNDEFINED";
208 src_name = adg_dress_name(src);
209 if (src_name == NULL)
210 src_name = "UNDEFINED";
212 g_warning("%s: `%d' (%s) and `%d' (%s) dresses are not related",
213 G_STRLOC, *dress, dress_name, src, src_name);
215 return FALSE;
218 *dress = src;
220 return TRUE;
224 * adg_dress_name:
225 * @dress: an #AdgDress
227 * Gets the name associated to @dress. No warnings are raised if
228 * @dress is not found.
230 * Returns: the requested name or %NULL if not found
232 const gchar *
233 adg_dress_name(AdgDress dress)
235 if (dress <= 0 || dress >= array_len())
236 return NULL;
238 return g_quark_to_string(array_lookup(dress)->quark);
242 * adg_dress_from_name:
243 * @name: the name of a dress
245 * Gets the dress binded to a @name string. No warnings are raised
246 * if the dress is not found.
248 * Returns: the #AdgDress code or #ADG_DRESS_UNDEFINED if not found
250 AdgDress
251 adg_dress_from_name(const gchar *name)
253 return quark_to_dress(g_quark_try_string(name));
257 * adg_dress_get_ancestor_type:
258 * @dress: an #AdgDress
260 * Gets the base type that should be present in every #AdgStyle
261 * acceptable by @dress.
263 * Returns: the ancestor type
265 GType
266 adg_dress_get_ancestor_type(AdgDress dress)
268 AdgDressPrivate *data;
270 if (dress <= 0 || dress >= array_len())
271 return 0;
273 data = array_lookup(dress);
275 return data->ancestor_type;
279 * adg_dress_get_style:
280 * @dress: an #AdgDress
282 * Gets the style associated to @dress. No warnings are raised
283 * if the dress is not found.
285 * Returns: the requested #AdgStyle derived instance or %NULL if not found
287 AdgStyle *
288 adg_dress_get_style(AdgDress dress)
290 AdgDressPrivate *data;
292 if (dress <= 0 || dress >= array_len())
293 return NULL;
295 data = array_lookup(dress);
297 return data->style;
301 * adg_dress_set_style:
302 * @dress: an #AdgDress
303 * @style: the new style
305 * Associates a new @style to @dress. If the dress does not exist
306 * (it was not previously created by adg_dress_new()), a warning
307 * message is raised and the function fails.
309 * @style is checked for compatibily with @dress. Any dress holds
310 * an ancestor type: if this type is not found in the @style
311 * hierarchy, a warning message is raised the function fails.
313 * After a succesfull call, the reference to the old style (if any)
314 * is dropped while a new reference to @style is added.
316 void
317 adg_dress_set_style(AdgDress dress, AdgStyle *style)
319 AdgDressPrivate *data;
321 if (dress <= 0 || dress >= array_len()) {
322 g_warning("%s: `%d' dress undefined", G_STRLOC, dress);
323 return;
326 data = array_lookup(dress);
328 if (data->style == style)
329 return;
331 /* Check if the new style is compatible with this dress */
332 if (!G_TYPE_CHECK_INSTANCE_TYPE(style, data->ancestor_type)) {
333 g_warning("%s: `%s' is not compatible with `%s' for `%s' dress",
334 G_STRLOC, g_type_name(G_TYPE_FROM_INSTANCE(style)),
335 g_type_name(data->ancestor_type), adg_dress_name(dress));
336 return;
339 if (data->style != NULL)
340 g_object_unref(data->style);
342 data->style = style;
344 if (data->style != NULL)
345 g_object_ref(data->style);
349 * adg_dress_accept_style:
350 * @dress: an #AdgDress
351 * @style: the #AdgStyle to check
353 * Checks whether @style could be associated to @dress using
354 * adg_dress_set_style().
356 * Returns: %TRUE if @dress can accept @style, %FALSE otherwise
358 gboolean
359 adg_dress_accept_style(AdgDress dress, AdgStyle *style)
361 GType ancestor_type = adg_dress_get_ancestor_type(dress);
363 g_return_val_if_fail(ancestor_type > 0, FALSE);
364 g_return_val_if_fail(ADG_IS_STYLE(style), FALSE);
366 return G_TYPE_CHECK_INSTANCE_TYPE(style, ancestor_type);
370 static AdgDress
371 quark_to_dress(GQuark quark)
373 AdgDress dress;
374 AdgDressPrivate *data;
376 for (dress = 0; dress < array_len(); ++dress) {
377 data = array_lookup(dress);
379 if (data->quark == quark)
380 return dress;
383 return ADG_DRESS_UNDEFINED;
386 static void
387 dress_to_string(const GValue *src, GValue *dst)
389 g_value_set_string(dst, adg_dress_name(g_value_get_int(src)));
392 static void
393 string_to_dress(const GValue *src, GValue *dst)
395 g_value_set_int(dst, adg_dress_from_name(g_value_get_string(src)));
399 typedef struct _AdgParamSpecDress AdgParamSpecDress;
401 struct _AdgParamSpecDress {
402 GParamSpecInt parent;
403 AdgDress source_dress;
407 GType
408 _adg_param_spec_dress_get_type(void)
410 static GType type = 0;
412 if (G_UNLIKELY(type == 0)) {
413 const GTypeInfo info = {
414 sizeof(GParamSpecClass),
415 NULL,
416 NULL,
417 (GClassInitFunc) param_class_init,
418 NULL,
419 NULL,
420 sizeof(AdgParamSpecDress),
424 type = g_type_register_static(G_TYPE_PARAM_INT,
425 "AdgParamSpecDress", &info, 0);
428 return type;
431 static void
432 param_class_init(GParamSpecClass *klass)
434 klass->value_type = ADG_TYPE_DRESS;
435 klass->value_validate = value_validate;
438 static gboolean
439 value_validate(GParamSpec *spec, GValue *value)
441 AdgParamSpecDress *fspec;
442 AdgDress dress, new_dress;
444 fspec = (AdgParamSpecDress *) spec;
445 dress = value->data[0].v_int;
446 new_dress = ADG_DRESS_UNDEFINED;
448 adg_dress_set(&new_dress, dress);
449 value->data[0].v_int = new_dress;
451 return dress != new_dress;
456 * adg_param_spec_dress:
457 * @name: canonical name
458 * @nick: nickname of the param
459 * @blurb: brief desciption
460 * @dress: the #AdgDress dress
461 * @flags: a combination of #GParamFlags
463 * Creates a param spec to hold a dress value.
465 * Returns: the newly allocated #GParamSpec
467 GParamSpec *
468 adg_param_spec_dress(const gchar *name, const gchar *nick, const gchar *blurb,
469 AdgDress dress, GParamFlags flags)
471 AdgParamSpecDress *fspec;
473 if (dress <= 0 || dress >= array_len()) {
474 g_warning("%s: `%d' dress undefined", G_STRLOC, dress);
475 return NULL;
478 fspec = g_param_spec_internal(ADG_TYPE_PARAM_SPEC_DRESS,
479 name, nick, blurb, flags);
480 fspec->source_dress = dress;
482 return (GParamSpec *) fspec;
487 * ADG_DRESS_UNDEFINED:
489 * A value reperesenting an undefined #AdgDress.
493 * ADG_DRESS_COLOR_REGULAR:
495 * The default builtin #AdgDress color. This dress will be resolved
496 * to an #AdgColorStyle instance.
498 AdgDress
499 _adg_dress_color_regular(void)
501 static AdgDress dress = 0;
503 if (G_UNLIKELY(dress == 0)) {
504 AdgStyle *style = g_object_new(ADG_TYPE_COLOR_STYLE, NULL);
506 dress = adg_dress_new("color-regular", style);
507 g_object_unref(style);
510 return dress;
514 * ADG_DRESS_COLOR_DIMENSION:
516 * The builtin #AdgDress color used by dimensioning items. This dress
517 * will be resolved to an #AdgColorStyle instance.
519 AdgDress
520 _adg_dress_color_dimension(void)
522 static AdgDress dress = 0;
524 if (G_UNLIKELY(dress == 0)) {
525 AdgStyle *style = g_object_new(ADG_TYPE_COLOR_STYLE,
526 "red", 0.75, NULL);
528 dress = adg_dress_new("color-dimension", style);
529 g_object_unref(style);
532 return dress;
536 * ADG_DRESS_LINE_REGULAR:
538 * The default builtin #AdgDress line. This dress will be resolved
539 * to an #AdgLineStyle instance.
541 AdgDress
542 _adg_dress_line_regular(void)
544 static AdgDress dress = 0;
546 if (G_UNLIKELY(dress == 0)) {
547 AdgStyle *style = g_object_new(ADG_TYPE_LINE_STYLE,
548 "width", 2., NULL);
550 dress = adg_dress_new("line-regular", style);
551 g_object_unref(style);
554 return dress;
558 * ADG_DRESS_LINE_DIMENSION:
560 * The builtin #AdgDress line type used by base and extension lines in
561 * dimensioning. This dress will be resolved to an #AdgLineStyle instance.
563 AdgDress
564 _adg_dress_line_dimension(void)
566 static AdgDress dress = 0;
568 if (G_UNLIKELY(dress == 0)) {
569 AdgStyle *style = g_object_new(ADG_TYPE_LINE_STYLE,
570 "color-dress", ADG_DRESS_COLOR_DIMENSION,
571 "antialias", CAIRO_ANTIALIAS_NONE,
572 "width", 1., NULL);
574 dress = adg_dress_new("line-dimension", style);
575 g_object_unref(style);
578 return dress;
582 * ADG_DRESS_TEXT_REGULAR:
584 * The default builtin #AdgDress font. This dress will be resolved
585 * to an #AdgFontStyle instance.
587 AdgDress
588 _adg_dress_text_regular(void)
590 static AdgDress dress = 0;
592 if (G_UNLIKELY(dress == 0)) {
593 AdgStyle *style = g_object_new(ADG_TYPE_FONT_STYLE,
594 "family", "Serif",
595 "size", 14., NULL);
597 dress = adg_dress_new("text-regular", style);
598 g_object_unref(style);
601 return dress;
605 * ADG_DRESS_TEXT_VALUE:
607 * The builtin #AdgDress font used to render the nominal value of a
608 * dimension. This dress will be resolved to an #AdgFontStyle instance.
610 AdgDress
611 _adg_dress_text_value(void)
613 static AdgDress dress = 0;
615 if (G_UNLIKELY(dress == 0)) {
616 AdgStyle *style = g_object_new(ADG_TYPE_FONT_STYLE,
617 "family", "Sans",
618 "weight", CAIRO_FONT_WEIGHT_BOLD,
619 "size", 12., NULL);
621 dress = adg_dress_new("text-value", style);
622 g_object_unref(style);
625 return dress;
629 * ADG_DRESS_TEXT_LIMIT:
631 * The builtin #AdgDress font used to render the tolerances or both
632 * the upper and lower values of a dimension. This dress will be
633 * resolved to an #AdgFontStyle instance.
635 AdgDress
636 _adg_dress_text_limit(void)
638 static AdgDress dress = 0;
640 if (G_UNLIKELY(dress == 0)) {
641 AdgStyle *style = g_object_new(ADG_TYPE_FONT_STYLE,
642 "family", "Sans",
643 "size", 8., NULL);
645 dress = adg_dress_new("text-limit", style);
646 g_object_unref(style);
649 return dress;
653 * ADG_DRESS_DIMENSION_REGULAR:
655 * The default builtin #AdgDress dimensioning style. This dress
656 * will be resolved to an #AdgDimStyle instance.
658 AdgDress
659 _adg_dress_dimension_regular(void)
661 static AdgDress dress = 0;
663 if (G_UNLIKELY(dress == 0)) {
664 AdgStyle *style = g_object_new(ADG_TYPE_DIM_STYLE, NULL);
666 dress = adg_dress_new("dimension-regular", style);
667 g_object_unref(style);
670 return dress;
674 static GArray * array_singleton (void) G_GNUC_CONST;
676 static GArray *
677 array_singleton(void)
679 static GArray *array = NULL;
681 if (array == NULL) {
682 const AdgDressPrivate data = { 0, };
684 array = g_array_new(FALSE, FALSE, sizeof(AdgDressPrivate));
686 /* Reserve the first item for the undefined dress */
687 g_array_append_val(array, data);
690 return array;
693 static guint
694 array_append(AdgDressPrivate *data)
696 return g_array_append_val(array_singleton(), *data)->len;
699 static AdgDressPrivate *
700 array_lookup(guint n)
702 return &g_array_index(array_singleton(), AdgDressPrivate, n);
705 static guint
706 array_len(void)
708 return array_singleton()->len;