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.
24 * @short_description: Base class for styling the rendering process
26 * The context is a collection of styles, one for each #AdgStyle derived
27 * class. To achieve this result, there is a common register where all
28 * the style derived class are stored and every #AdgContext instance keeps
29 * its own register of style instances (one instance per class).
31 * Although this could be implemented by accessing the underlying registers
32 * using GType id, to be able to access efficiently, that is O(1) magnitude,
33 * the concept of slot was introduced.
35 * The slot serves the same purpose than a GType, that is identify a type
36 * class, but the slots are a strict sequence starting from 0, useful to be
37 * used as an array index.
43 * All fields are private and should not be used directly.
44 * Use its public methods instead.
49 * @style_class: the new style class
50 * @user_data: the user provided data
52 * Callback to be used to get the default instance for
53 * newly registered style classes.
55 * Return value: the instance to use for the passed in style class
59 #include "adg-context.h"
60 #include "adg-context-private.h"
64 static AdgStyle
* context_filler (AdgStyleClass
*style_class
,
66 static void fill_style_slots (AdgContext
*context
,
69 static GPtrArray
*class_slots
= NULL
;
72 G_DEFINE_TYPE(AdgContext
, adg_context
, G_TYPE_OBJECT
)
76 adg_context_class_init(AdgContextClass
*klass
)
78 g_type_class_add_private(klass
, sizeof(AdgContextPrivate
));
82 adg_context_init(AdgContext
*context
)
84 AdgContextPrivate
*data
= G_TYPE_INSTANCE_GET_PRIVATE(context
,
88 data
->style_slots
= g_ptr_array_sized_new(class_slots
?
89 class_slots
->len
: 10);
90 data
->context_filler
= context_filler
;
91 data
->user_data
= NULL
;
98 * adg_context_get_slot:
99 * @type: an #AdgStyle type
101 * Gets the slot associated to @type. If not found, registers a new
102 * style family by assigning a new slot id to it: the internal register
103 * will keep a reference to this style class.
105 * Return value: the requested slot id
108 adg_context_get_slot(GType type
)
110 AdgStyleClass
*klass
= g_type_class_ref(type
);
112 g_return_val_if_fail(ADG_IS_STYLE_CLASS(klass
), -1);
114 if (G_UNLIKELY(class_slots
== NULL
)) {
115 class_slots
= g_ptr_array_sized_new(10);
118 for (n
= 0; n
< class_slots
->len
; ++n
)
119 if (class_slots
->pdata
[n
] == klass
)
123 g_ptr_array_add(class_slots
, klass
);
124 return class_slots
->len
- 1;
129 * @context_filler: callback to use to fill uninitialized styles
130 * @user_data: additional pointer to pass to @context_filler
132 * Constructs a new empty context. If @context_filler is %NULL, the default
133 * filler callback will be used (the new style instances will be %NULL).
135 * Return value: a new context
138 adg_context_new(AdgContextFiller context_filler
, gpointer user_data
)
140 AdgContext
*context
= g_object_new(ADG_TYPE_CONTEXT
, NULL
);
142 if (context_filler
) {
143 AdgContextPrivate
*data
= context
->data
;
145 data
->context_filler
= context_filler
;
146 data
->user_data
= user_data
;
153 * adg_context_get_style:
154 * @context: an #AdgContext instance
155 * @slot: the style slot where to get the style
157 * Gets a style instance from the specified @slot of @context.
159 * Return value: the style instance
162 adg_context_get_style(AdgContext
*context
, AdgStyleSlot slot
)
164 AdgContextPrivate
*data
;
165 GPtrArray
*style_slots
;
167 g_return_val_if_fail(ADG_IS_CONTEXT(context
), NULL
);
168 g_return_val_if_fail(slot
>= 0 && slot
< class_slots
->len
, NULL
);
170 data
= context
->data
;
171 style_slots
= data
->style_slots
;
173 if (G_UNLIKELY(slot
>= style_slots
->len
))
174 fill_style_slots(context
, slot
);
176 return (AdgStyle
*) g_ptr_array_index(style_slots
, slot
);
180 * adg_context_set_style:
181 * @context: an #AdgContext instance
182 * @style: the new style to include
184 * Sets a new style inside @context. The old style (if any)
185 * will be unreferenced while a new reference will be added to @style.
188 adg_context_set_style(AdgContext
*context
, AdgStyle
*style
)
190 AdgContextPrivate
*data
;
192 GPtrArray
*style_slots
;
194 g_return_if_fail(ADG_IS_CONTEXT(context
));
195 g_return_if_fail(ADG_IS_STYLE(style
));
197 data
= context
->data
;
198 slot
= adg_context_get_slot(G_TYPE_FROM_INSTANCE(style
));
199 style_slots
= data
->style_slots
;
203 if (G_LIKELY(slot
< style_slots
->len
)) {
204 g_object_unref(style_slots
->pdata
[slot
]);
205 style_slots
->pdata
[slot
] = style
;
207 fill_style_slots(context
, slot
- 1);
208 g_ptr_array_add(style_slots
, style
);
214 context_filler(AdgStyleClass
*style_class
, gpointer user_data
)
220 fill_style_slots(AdgContext
*context
, guint last_slot
)
222 AdgContextPrivate
*data
;
223 GPtrArray
*style_slots
;
224 AdgStyleClass
*klass
;
228 data
= context
->data
;
229 style_slots
= data
->style_slots
;
231 for (n
= style_slots
->len
; n
<= last_slot
; ++n
) {
232 klass
= (AdgStyleClass
*) g_ptr_array_index(class_slots
, n
);
233 style
= data
->context_filler(klass
, data
->user_data
);
234 g_object_ref((GObject
*) style
);
235 g_ptr_array_add(style_slots
, style
);