Renamed Xatch to Hatch
[adg.git] / adg / adg-line-style.c
blobd6741d48a360bbc7e58189bc48c5949cb1e35ca9
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.
20 /**
21 * SECTION:line-style
22 * @title: AdgLineStyle
23 * @short_description: Line style related stuff
25 * Contains parameters on how to draw lines such as width, cap mode, join mode
26 * and dash composition, if used.
29 #include "adg-line-style.h"
30 #include "adg-line-style-private.h"
31 #include "adg-context.h"
32 #include "adg-intl.h"
33 #include "adg-util.h"
35 #define PARENT_CLASS ((AdgStyleClass *) adg_line_style_parent_class)
38 enum {
39 PROP_0,
40 PROP_WIDTH,
41 PROP_CAP,
42 PROP_JOIN,
43 PROP_MITER_LIMIT,
44 PROP_ANTIALIAS,
45 PROP_DASH
49 static void get_property (GObject *object,
50 guint prop_id,
51 GValue *value,
52 GParamSpec *pspec);
53 static void set_property (GObject *object,
54 guint prop_id,
55 const GValue *value,
56 GParamSpec *pspec);
57 static GPtrArray * get_pool (void);
58 static void apply (AdgStyle *style,
59 cairo_t *cr);
62 G_DEFINE_TYPE(AdgLineStyle, adg_line_style, ADG_TYPE_STYLE)
65 static void
66 adg_line_style_class_init(AdgLineStyleClass *klass)
68 GObjectClass *gobject_class;
69 AdgStyleClass *style_class;
70 GParamSpec *param;
72 gobject_class = (GObjectClass *) klass;
73 style_class = (AdgStyleClass *) klass;
75 g_type_class_add_private(klass, sizeof(AdgLineStylePrivate));
77 gobject_class->get_property = get_property;
78 gobject_class->set_property = set_property;
80 style_class->get_pool = get_pool;
81 style_class->apply = apply;
83 param = g_param_spec_double("width",
84 P_("Line Width"),
85 P_("The line thickness in device unit"),
86 0., G_MAXDOUBLE, 2., G_PARAM_READWRITE);
87 g_object_class_install_property(gobject_class, PROP_WIDTH, param);
89 param = g_param_spec_int("cap",
90 P_("Line Cap"),
91 P_("The line cap mode"),
92 G_MININT, G_MAXINT, CAIRO_LINE_CAP_ROUND,
93 G_PARAM_READWRITE);
94 g_object_class_install_property(gobject_class, PROP_CAP, param);
96 param = g_param_spec_int("join",
97 P_("Line Join"),
98 P_("The line join mode"),
99 G_MININT, G_MAXINT, CAIRO_LINE_JOIN_MITER,
100 G_PARAM_READWRITE);
101 g_object_class_install_property(gobject_class, PROP_JOIN, param);
103 param = g_param_spec_double("miter-limit",
104 P_("Miter Limit"),
106 ("Whether the lines should be joined with a bevel instead of a miter"),
107 0., G_MAXDOUBLE, 10., G_PARAM_READWRITE);
108 g_object_class_install_property(gobject_class, PROP_MITER_LIMIT,
109 param);
111 param = g_param_spec_int("antialias",
112 P_("Antialiasing Mode"),
114 ("Type of antialiasing to do when rendering lines"),
115 G_MININT, G_MAXINT, CAIRO_ANTIALIAS_DEFAULT,
116 G_PARAM_READWRITE);
117 g_object_class_install_property(gobject_class, PROP_ANTIALIAS, param);
119 /* TODO: PROP_DASH (PROP_DASHES, PROP_NUM_DASHES, PROP_DASH_OFFSET) */
122 static void
123 adg_line_style_init(AdgLineStyle *line_style)
125 AdgLineStylePrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE(line_style,
126 ADG_TYPE_LINE_STYLE,
127 AdgLineStylePrivate);
129 priv->width = 2.;
130 priv->cap = CAIRO_LINE_CAP_ROUND;
131 priv->join = CAIRO_LINE_JOIN_MITER;
132 priv->miter_limit = 10.;
133 priv->antialias = CAIRO_ANTIALIAS_DEFAULT;
134 priv->dashes = NULL;
135 priv->num_dashes = 0;
136 priv->dash_offset = 0.;
138 line_style->priv = priv;
141 static void
142 get_property(GObject *object,
143 guint prop_id, GValue *value, GParamSpec *pspec)
145 AdgLineStyle *line_style = (AdgLineStyle *) object;
147 switch (prop_id) {
148 case PROP_WIDTH:
149 g_value_set_double(value, line_style->priv->width);
150 break;
151 case PROP_CAP:
152 g_value_set_int(value, line_style->priv->cap);
153 break;
154 case PROP_JOIN:
155 g_value_set_int(value, line_style->priv->join);
156 break;
157 case PROP_MITER_LIMIT:
158 g_value_set_double(value, line_style->priv->miter_limit);
159 break;
160 case PROP_ANTIALIAS:
161 g_value_set_int(value, line_style->priv->antialias);
162 break;
163 case PROP_DASH:
164 /* TODO */
165 break;
166 default:
167 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
168 break;
172 static void
173 set_property(GObject *object,
174 guint prop_id, const GValue *value, GParamSpec *pspec)
176 AdgLineStyle *line_style = (AdgLineStyle *) object;
178 switch (prop_id) {
179 case PROP_WIDTH:
180 line_style->priv->width = g_value_get_double(value);
181 break;
182 case PROP_CAP:
183 line_style->priv->cap = g_value_get_int(value);
184 break;
185 case PROP_JOIN:
186 line_style->priv->join = g_value_get_int(value);
187 break;
188 case PROP_MITER_LIMIT:
189 line_style->priv->miter_limit = g_value_get_double(value);
190 break;
191 case PROP_ANTIALIAS:
192 line_style->priv->antialias = g_value_get_int(value);
193 break;
194 case PROP_DASH:
195 /* TODO */
196 break;
197 default:
198 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
199 break;
205 * adg_line_style_get_slot:
207 * Gets the slot id for this style class.
209 * Return value: the slot
211 AdgStyleSlot
212 adg_line_style_get_slot(void)
214 static AdgStyleSlot slot = -1;
216 if (G_UNLIKELY(slot < 0))
217 slot = adg_context_get_slot(ADG_TYPE_LINE_STYLE);
219 return slot;
223 * adg_line_style_new:
225 * Constructs a new line style initialized with default params.
227 * Return value: a new line style
229 AdgStyle *
230 adg_line_style_new(void)
232 return g_object_new(ADG_TYPE_LINE_STYLE, NULL);
236 * adg_line_style_get_width:
237 * @line_style: an #AdgLineStyle object
239 * Gets the line thickness value (in paper units).
241 * Return value: the requested width
243 gdouble
244 adg_line_style_get_width(AdgLineStyle *line_style)
246 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), 0.);
248 return line_style->priv->width;
252 * adg_line_style_set_width:
253 * @line_style: an #AdgLineStyle object
254 * @width: the new width
256 * Sets a new line thickness value.
258 void
259 adg_line_style_set_width(AdgLineStyle *line_style, gdouble width)
261 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
263 line_style->priv->width = width;
264 g_object_notify((GObject *) line_style, "width");
268 * adg_line_style_get_cap:
269 * @line_style: an #AdgLineStyle object
271 * Gets the line cap mode.
273 * Return value: the requested line cap mode
275 cairo_line_cap_t
276 adg_line_style_get_cap(AdgLineStyle *line_style)
278 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
279 CAIRO_LINE_CAP_BUTT);
281 return line_style->priv->cap;
285 * adg_line_style_set_cap:
286 * @line_style: an #AdgLineStyle object
287 * @cap: the new cap mode
289 * Sets a new line cap mode.
291 void
292 adg_line_style_set_cap(AdgLineStyle *line_style, cairo_line_cap_t cap)
294 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
296 line_style->priv->cap = cap;
297 g_object_notify((GObject *) line_style, "cap");
301 * adg_line_style_get_join:
302 * @line_style: an #AdgLineStyle object
304 * Gets the line join mode.
306 * Return value: the requested line join mode
308 cairo_line_join_t
309 adg_line_style_get_join(AdgLineStyle *line_style)
311 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
312 CAIRO_LINE_JOIN_MITER);
314 return line_style->priv->join;
318 * adg_line_style_set_join:
319 * @line_style: an #AdgLineStyle object
320 * @join: the new join mode
322 * Sets a new line join mode.
324 void
325 adg_line_style_set_join(AdgLineStyle *line_style, cairo_line_join_t join)
327 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
329 line_style->priv->join = join;
330 g_object_notify((GObject *) line_style, "join");
334 * adg_line_style_get_miter_limit:
335 * @line_style: an #AdgLineStyle object
337 * Gets the line miter limit value. The miter limit is used to determine
338 * whether the lines should be joined with a bevel instead of a miter.
340 * Return value: the requested miter limit
342 gdouble
343 adg_line_style_get_miter_limit(AdgLineStyle *line_style)
345 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style), 0.);
347 return line_style->priv->miter_limit;
351 * adg_line_style_set_miter_limit:
352 * @line_style: an #AdgLineStyle object
353 * @miter_limit: the new miter limit
355 * Sets a new miter limit value.
357 void
358 adg_line_style_set_miter_limit(AdgLineStyle *line_style,
359 gdouble miter_limit)
361 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
363 line_style->priv->miter_limit = miter_limit;
364 g_object_notify((GObject *) line_style, "miter-limit");
368 * adg_line_style_get_antialias:
369 * @line_style: an #AdgLineStyle object
371 * Gets the antialias mode used.
373 * Return value: the requested antialias mode
375 cairo_antialias_t
376 adg_line_style_get_antialias(AdgLineStyle *line_style)
378 g_return_val_if_fail(ADG_IS_LINE_STYLE(line_style),
379 CAIRO_ANTIALIAS_DEFAULT);
381 return line_style->priv->antialias;
385 * adg_line_style_set_antialias:
386 * @line_style: an #AdgLineStyle object
387 * @antialias: the new antialias mode
389 * Sets a new antialias mode.
391 void
392 adg_line_style_set_antialias(AdgLineStyle *line_style,
393 cairo_antialias_t antialias)
395 g_return_if_fail(ADG_IS_LINE_STYLE(line_style));
397 line_style->priv->antialias = antialias;
398 g_object_notify((GObject *) line_style, "antialias");
402 static GPtrArray *
403 get_pool(void)
405 static GPtrArray *pool = NULL;
407 if (G_UNLIKELY(pool == NULL)) {
408 cairo_pattern_t *pattern;
410 pool = g_ptr_array_sized_new(ADG_LINE_STYLE_LAST);
412 pool->pdata[ADG_LINE_STYLE_DRAW] =
413 g_object_new(ADG_TYPE_LINE_STYLE, "width", 2., NULL);
415 pattern = cairo_pattern_create_rgb(0., 1., 0.);
416 pool->pdata[ADG_LINE_STYLE_CENTER] =
417 g_object_new(ADG_TYPE_LINE_STYLE, "pattern", pattern, "width",
418 0.75, NULL);
419 cairo_pattern_destroy(pattern);
421 pattern = cairo_pattern_create_rgba(0., 0., 0., 0.5);
422 pool->pdata[ADG_LINE_STYLE_HIDDEN] =
423 g_object_new(ADG_TYPE_LINE_STYLE, "pattern", pattern, "width",
424 0.75, NULL);
425 cairo_pattern_destroy(pattern);
427 pattern = cairo_pattern_create_rgb(0., 0., 1.);
428 pool->pdata[ADG_LINE_STYLE_HATCH] =
429 g_object_new(ADG_TYPE_LINE_STYLE, "pattern", pattern, "width",
430 1.25, NULL);
431 cairo_pattern_destroy(pattern);
433 pool->pdata[ADG_LINE_STYLE_DIM] = g_object_new(ADG_TYPE_LINE_STYLE,
434 "width", 0.75,
435 NULL);
437 pool->len = ADG_LINE_STYLE_LAST;
440 return pool;
443 static void
444 apply(AdgStyle *style, cairo_t *cr)
446 AdgLineStyle *line_style;
447 gdouble device_width;
448 gdouble dummy = 0.;
450 line_style = (AdgLineStyle *) style;
452 PARENT_CLASS->apply(style, cr);
454 device_width = line_style->priv->width;
455 cairo_device_to_user_distance(cr, &device_width, &dummy);
456 cairo_set_line_width(cr, device_width);
458 cairo_set_line_cap(cr, line_style->priv->cap);
459 cairo_set_line_join(cr, line_style->priv->join);
460 cairo_set_miter_limit(cr, line_style->priv->miter_limit);
461 cairo_set_antialias(cr, line_style->priv->antialias);
463 if (line_style->priv->num_dashes > 0) {
464 g_return_if_fail(line_style->priv->dashes != NULL);
466 cairo_set_dash(cr, line_style->priv->dashes,
467 line_style->priv->num_dashes,
468 line_style->priv->dash_offset);