adg: provide example on how to customize a style
[adg.git] / src / adg / adg-fill-style.c
blob68a56d1f943feb9cf9985930b642bc4f749217b7
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2017 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-fill-style
23 * @short_description: Generic pattern fill
25 * A style defining a generic fill based on cairo_pattern_t.
27 * Since: 1.0
28 **/
30 /**
31 * AdgFillStyle:
33 * All fields are private and should not be used directly.
34 * Use its public methods instead.
36 * Since: 1.0
37 **/
39 /**
40 * AdgFillStyleClass:
41 * @set_extents: virtual method that specifies where a specific fill style
42 * must be applied. It is called by #AdgHatch in the rendering
43 * phase passing with its boundary box as argument.
45 * The default <function>set_extents</function> implementation simply sets
46 * the extents owned by the fill style instance to the one provided, so the
47 * last call has precedence. Any derived class can override it to customize
48 * this behavior, for example to keep the greatest boundary box instead of
49 * the last one.
51 * Since: 1.0
52 **/
55 #include "adg-internal.h"
56 #include "adg-style.h"
57 #include "adg-cairo-fallback.h"
59 #include "adg-fill-style.h"
60 #include "adg-fill-style-private.h"
63 G_DEFINE_ABSTRACT_TYPE(AdgFillStyle, adg_fill_style, ADG_TYPE_STYLE)
65 enum {
66 PROP_0,
67 PROP_PATTERN
71 static void _adg_finalize (GObject *object);
72 static void _adg_get_property (GObject *object,
73 guint prop_id,
74 GValue *value,
75 GParamSpec *pspec);
76 static void _adg_set_property (GObject *object,
77 guint prop_id,
78 const GValue *value,
79 GParamSpec *pspec);
80 static void _adg_apply (AdgStyle *style,
81 AdgEntity *entity,
82 cairo_t *cr);
83 static void _adg_set_extents (AdgFillStyle *fill_style,
84 const CpmlExtents *extents);
87 static void
88 adg_fill_style_class_init(AdgFillStyleClass *klass)
90 GObjectClass *gobject_class;
91 AdgStyleClass *style_class;
92 GParamSpec *param;
94 gobject_class = (GObjectClass *) klass;
95 style_class = (AdgStyleClass *) klass;
97 g_type_class_add_private(klass, sizeof(AdgFillStylePrivate));
99 gobject_class->finalize = _adg_finalize;
100 gobject_class->get_property = _adg_get_property;
101 gobject_class->set_property = _adg_set_property;
103 style_class->apply = _adg_apply;
105 klass->set_extents = _adg_set_extents;
107 param = g_param_spec_boxed("pattern",
108 P_("Pattern"),
109 P_("The cairo pattern set for this entity"),
110 CAIRO_GOBJECT_TYPE_PATTERN,
111 G_PARAM_READWRITE);
112 g_object_class_install_property(gobject_class, PROP_PATTERN, param);
115 static void
116 adg_fill_style_init(AdgFillStyle *fill_style)
118 AdgFillStylePrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(fill_style,
119 ADG_TYPE_FILL_STYLE,
120 AdgFillStylePrivate);
122 data->pattern = NULL;
124 fill_style->data = data;
127 static void
128 _adg_finalize(GObject *object)
130 AdgFillStylePrivate *data = ((AdgFillStyle *) object)->data;
132 if (data->pattern != NULL) {
133 cairo_pattern_destroy(data->pattern);
134 data->pattern = NULL;
138 static void
139 _adg_get_property(GObject *object, guint prop_id,
140 GValue *value, GParamSpec *pspec)
142 AdgFillStylePrivate *data = ((AdgFillStyle *) object)->data;
144 switch (prop_id) {
145 case PROP_PATTERN:
146 g_value_set_boxed(value, data->pattern);
147 break;
148 default:
149 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
150 break;
154 static void
155 _adg_set_property(GObject *object, guint prop_id,
156 const GValue *value, GParamSpec *pspec)
158 AdgFillStylePrivate *data = ((AdgFillStyle *) object)->data;
159 cairo_pattern_t *old_pattern;
161 switch (prop_id) {
162 case PROP_PATTERN:
163 old_pattern = data->pattern;
164 data->pattern = g_value_get_boxed(value);
166 if (data->pattern)
167 cairo_pattern_reference(data->pattern);
168 if (old_pattern)
169 cairo_pattern_destroy(old_pattern);
170 break;
171 default:
172 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
173 break;
179 * adg_fill_style_set_pattern:
180 * @fill_style: an #AdgFillStyle
181 * @pattern: the new pattern
183 * <note><para>
184 * This function is only useful in new fill implementations.
185 * </para></note>
187 * Sets a new pattern on @fill_style. A new reference is added to
188 * @pattern with cairo_pattern_reference() and the old pattern
189 * (if any) is unreferenced with cairo_pattern_destroy().
191 * Since: 1.0
193 void
194 adg_fill_style_set_pattern(AdgFillStyle *fill_style,
195 cairo_pattern_t *pattern)
197 g_return_if_fail(ADG_IS_FILL_STYLE(fill_style));
198 g_object_set(fill_style, "pattern", pattern, NULL);
202 * adg_fill_style_get_pattern:
203 * @fill_style: an #AdgFillStyle
205 * Gets the current pattern binded to @fill_style.
207 * Returns: (transfer none): the current pattern
209 * Since: 1.0
211 cairo_pattern_t *
212 adg_fill_style_get_pattern(AdgFillStyle *fill_style)
214 AdgFillStylePrivate *data;
216 g_return_val_if_fail(ADG_IS_FILL_STYLE(fill_style), NULL);
218 data = fill_style->data;
220 return data->pattern;
224 * adg_fill_style_set_extents:
225 * @fill_style: an #AdgFillStyle
226 * @extents: the new extents
228 * <note><para>
229 * This function is only useful in new fill style implementations.
230 * </para></note>
232 * Forcibly sets new extents on @fill_style. Any fill style class
233 * that want to make some kind of customization can override the
234 * <function>set_extents</function> virtual method to intercept
235 * any extents change.
237 * Sets new extents on @fill_style. These extents are usually set
238 * by the arrange() method of the entity using this filling style.
240 * Since: 1.0
242 void
243 adg_fill_style_set_extents(AdgFillStyle *fill_style,
244 const CpmlExtents *extents)
246 AdgFillStyleClass *klass;
248 g_return_if_fail(ADG_IS_FILL_STYLE(fill_style));
249 g_return_if_fail(extents != NULL);
251 klass = ADG_FILL_STYLE_GET_CLASS(fill_style);
253 if (klass->set_extents)
254 klass->set_extents(fill_style, extents);
258 * adg_fill_style_get_extents:
259 * @fill_style: an #AdgFillStyle
261 * Stores a copy of the extents of @fill_style in @extents.
262 * This struct specifies the maximum portion (in global space)
263 * this fill style should be applied: it will clamped by the
264 * entities as needed.
266 * Returns: (transfer none): the extents of @fill_style or <constant>NULL</constant> on errors.
268 * Since: 1.0
270 const CpmlExtents *
271 adg_fill_style_get_extents(AdgFillStyle *fill_style)
273 AdgFillStylePrivate *data;
275 g_return_val_if_fail(ADG_IS_FILL_STYLE(fill_style), NULL);
277 data = fill_style->data;
279 return &data->extents;
283 static void
284 _adg_apply(AdgStyle *style, AdgEntity *entity, cairo_t *cr)
286 AdgFillStylePrivate *data = ((AdgFillStyle *) style)->data;
288 if (data->pattern == NULL)
289 g_warning(_("%s: pattern undefined for type '%s'"),
290 G_STRLOC, g_type_name(G_OBJECT_TYPE(style)));
291 else
292 cairo_set_source(cr, data->pattern);
295 static void
296 _adg_set_extents(AdgFillStyle *fill_style, const CpmlExtents *extents)
298 AdgFillStylePrivate *data = fill_style->data;
300 cpml_extents_copy(&data->extents, extents);