Have each ChamplainPolygon have their ClutterActor
[libchamplain:potyl-perl.git] / champlain / champlain-polygon.c
1 /*
2  * Copyright (C) 2009 Pierre-Luc Beaudoin <pierre-luc@pierlux.com>
3  *
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.1 of the License, or (at your option) any later version.
8  *
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.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 /**
20  * SECTION:champlain-polygon
21  * @short_description: A container for #ChamplainPolygon
22  *
23  * A ChamplainPolygon is little more than a #ClutterContainer. It keeps the
24  * polygons ordered so that they display correctly.
25  *
26  * Use #clutter_container_add to add polygons to the polygon and
27  * #clutter_container_remove to remove them.
28  */
29
30 #include "config.h"
31
32 #include "champlain-polygon.h"
33
34 #include "champlain-defines.h"
35 #include "champlain-private.h"
36
37 #include <clutter/clutter.h>
38 #include <clutter-cairo/clutter-cairo.h>
39 #include <glib.h>
40
41 static ClutterColor DEFAULT_FILL_COLOR = {0xcc, 0x00, 0x00, 0xaa};
42 static ClutterColor DEFAULT_STROKE_COLOR = {0xa4, 0x00, 0x00, 0xff};
43
44 G_DEFINE_TYPE (ChamplainPolygon, champlain_polygon, G_TYPE_OBJECT)
45
46 #define GET_PRIVATE(o) \
47   (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHAMPLAIN_TYPE_POLYGON, ChamplainPolygonPrivate))
48
49 enum
50 {
51   PROP_0,
52   PROP_CLOSED_PATH,
53   PROP_STROKE_WIDTH,
54   PROP_STROKE_COLOR,
55   PROP_FILL,
56   PROP_FILL_COLOR,
57   PROP_STROKE,
58 };
59
60 static void
61 champlain_polygon_get_property (GObject *object,
62     guint property_id,
63     GValue *value,
64     GParamSpec *pspec)
65 {
66   ChamplainPolygonPrivate *priv = GET_PRIVATE (object);
67
68   switch (property_id)
69     {
70       case PROP_CLOSED_PATH:
71         g_value_set_boolean (value, priv->closed_path);
72         break;
73       case PROP_FILL:
74         g_value_set_boolean (value, priv->fill);
75         break;
76       case PROP_STROKE:
77         g_value_set_boolean (value, priv->stroke);
78         break;
79       case PROP_FILL_COLOR:
80         clutter_value_set_color (value, priv->fill_color);
81         break;
82       case PROP_STROKE_COLOR:
83         clutter_value_set_color (value, priv->stroke_color);
84         break;
85       case PROP_STROKE_WIDTH:
86         g_value_set_double (value, priv->stroke_width);
87         break;
88       default:
89         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
90     }
91 }
92
93 static void
94 champlain_polygon_set_property (GObject *object,
95     guint property_id,
96     const GValue *value,
97     GParamSpec *pspec)
98 {
99   ChamplainPolygonPrivate *priv = GET_PRIVATE (object);
100
101   switch (property_id)
102     {
103       case PROP_CLOSED_PATH:
104         priv->closed_path = g_value_get_boolean (value);
105         break;
106       case PROP_FILL:
107         champlain_polygon_set_fill (CHAMPLAIN_POLYGON (object),
108             g_value_get_boolean (value));
109         break;
110       case PROP_STROKE:
111         champlain_polygon_set_stroke (CHAMPLAIN_POLYGON (object),
112             g_value_get_boolean (value));
113         break;
114       case PROP_FILL_COLOR:
115         champlain_polygon_set_fill_color (CHAMPLAIN_POLYGON (object),
116             clutter_value_get_color (value));
117         break;
118       case PROP_STROKE_COLOR:
119         champlain_polygon_set_stroke_color (CHAMPLAIN_POLYGON (object),
120             clutter_value_get_color (value));
121         break;
122       case PROP_STROKE_WIDTH:
123         champlain_polygon_set_stroke_width (CHAMPLAIN_POLYGON (object),
124             g_value_get_double (value));
125         break;
126       default:
127         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
128     }
129 }
130
131 static void
132 champlain_polygon_dispose (GObject *object)
133 {
134   //ChamplainPolygonPrivate *priv = GET_PRIVATE (object);
135
136   G_OBJECT_CLASS (champlain_polygon_parent_class)->dispose (object);
137 }
138
139 static void
140 champlain_polygon_finalize (GObject *object)
141 {
142   G_OBJECT_CLASS (champlain_polygon_parent_class)->finalize (object);
143 }
144
145 static void
146 champlain_polygon_class_init (ChamplainPolygonClass *klass)
147 {
148   GObjectClass *object_class = G_OBJECT_CLASS (klass);
149
150   g_type_class_add_private (klass, sizeof (ChamplainPolygonPrivate));
151
152   object_class->get_property = champlain_polygon_get_property;
153   object_class->set_property = champlain_polygon_set_property;
154   object_class->dispose = champlain_polygon_dispose;
155   object_class->finalize = champlain_polygon_finalize;
156
157   /**
158   * ChamplainPolygon:close-path:
159   *
160   * The shape is a closed path
161   *
162   * Since: 0.4
163   */
164   g_object_class_install_property (object_class,
165       PROP_CLOSED_PATH,
166       g_param_spec_boolean ("closed-path",
167           "Closed Path",
168           "The Path is Closed",
169           FALSE, CHAMPLAIN_PARAM_READWRITE));
170
171   /**
172   * ChamplainPolygon:fill:
173   *
174   * The shape should be filled
175   *
176   * Since: 0.4
177   */
178   g_object_class_install_property (object_class,
179       PROP_FILL,
180       g_param_spec_boolean ("fill",
181           "Fill",
182           "The shape is filled",
183           FALSE, CHAMPLAIN_PARAM_READWRITE));
184
185   /**
186   * ChamplainPolygon:stroke:
187   *
188   * The shape should be stroked
189   *
190   * Since: 0.4
191   */
192   g_object_class_install_property (object_class,
193       PROP_STROKE,
194       g_param_spec_boolean ("stroke",
195           "Stroke",
196           "The shape is stroked",
197           TRUE, CHAMPLAIN_PARAM_READWRITE));
198
199   /**
200   * ChamplainPolygon:stroke-color:
201   *
202   * The polygon's stroke color
203   *
204   * Since: 0.4
205   */
206   g_object_class_install_property (object_class,
207       PROP_STROKE_COLOR,
208       clutter_param_spec_color ("stroke-color",
209         "Stroke Color",
210         "The polygon's stroke color",
211         &DEFAULT_STROKE_COLOR,
212         CHAMPLAIN_PARAM_READWRITE));
213
214   /**
215   * ChamplainPolygon:text-color:
216   *
217   * The polygon's fill color
218   *
219   * Since: 0.4
220   */
221   g_object_class_install_property (object_class,
222       PROP_FILL_COLOR,
223       clutter_param_spec_color ("fill-color",
224           "Fill Color",
225           "The polygon's fill color",
226           &DEFAULT_FILL_COLOR,
227           CHAMPLAIN_PARAM_READWRITE));
228
229   /**
230   * ChamplainPolygon:stroke-width:
231   *
232   * The polygon's stroke width (in pixels)
233   *
234   * Since: 0.4
235   */
236   g_object_class_install_property (object_class,
237       PROP_STROKE_WIDTH,
238       g_param_spec_double ("stroke-width",
239           "Stroke Width",
240           "The polygon's stroke width",
241           0, 100.0,
242           2.0,
243           CHAMPLAIN_PARAM_READWRITE));
244 }
245
246 static void
247 champlain_polygon_init (ChamplainPolygon *self)
248 {
249   self->priv = GET_PRIVATE (self);
250
251   self->priv->points = NULL;
252   self->priv->fill = FALSE;
253   self->priv->stroke = TRUE;
254   self->priv->stroke_width = 2.0;
255
256   self->priv->fill_color = clutter_color_copy (&DEFAULT_FILL_COLOR);
257   self->priv->stroke_color = clutter_color_copy (&DEFAULT_STROKE_COLOR);
258   self->priv->actor = g_object_ref (clutter_cairo_new (800, 600));
259   clutter_actor_set_position (self->priv->actor, 0, 0);
260 }
261
262 /**
263  * champlain_polygon_new:
264  *
265  * Returns a new #ChamplainPolygon ready to be to draw polygons on the map
266  *
267  * Since: 0.4
268  */
269 ChamplainPolygon *
270 champlain_polygon_new ()
271 {
272   return g_object_new (CHAMPLAIN_TYPE_POLYGON, NULL);
273 }
274
275 /**
276  * champlain_polygon_append_point:
277  * @polygon: The polygon
278  * @lat: the latitude
279  * @lon: the longitude
280  *
281  * Adds point at the end of the list of points in the polygon
282  *
283  * Returns the added point, should not be freed.
284  *
285  * Since: 0.4
286  */
287 ChamplainPoint *
288 champlain_polygon_append_point (ChamplainPolygon *self,
289     gdouble lat,
290     gdouble lon)
291 {
292   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (self), NULL);
293
294   ChamplainPoint *point = g_new0 (ChamplainPoint, 1);
295   point->lat = lat;
296   point->lon = lon;
297
298   self->priv->points = g_list_append (self->priv->points, point);
299   return point;
300 }
301
302 /**
303  * champlain_polygon_insert_point:
304  * @polygon: The polygon
305  * @lat: the latitude
306  * @lon: the longitude
307  * @pos: where to insert the point
308  *
309  * Adds point at the given position in the list of points in the polygon
310  *
311  * Returns the added point, should not be freed.
312  *
313  * Since: 0.4
314  */
315 ChamplainPoint *
316 champlain_polygon_insert_point (ChamplainPolygon *self,
317     gdouble lat,
318     gdouble lon,
319     gint pos)
320 {
321   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (self), NULL);
322
323   ChamplainPoint *point = g_new0 (ChamplainPoint, 1);
324   point->lat = lat;
325   point->lon = lon;
326
327   self->priv->points = g_list_insert (self->priv->points, point, pos);
328   return point;
329 }
330
331 /**
332  * champlain_polygon_clear_points:
333  * @polygon: The polygon
334  *
335  * Remove all points from the polygon
336  *
337  * Since: 0.4
338  */
339 void
340 champlain_polygon_clear_points (ChamplainPolygon *self)
341 {
342   g_return_if_fail (CHAMPLAIN_IS_POLYGON (self));
343
344   GList *next = self->priv->points;
345   while (next != NULL)
346   {
347     g_free (next->data);
348     next = g_list_next (next);
349   }
350   g_list_free (self->priv->points);
351 }
352
353 /**
354  * champlain_polygon_get_points:
355  * @polygon: The polygon
356  *
357  * Returns a list of all points from the polygon, it shouldn't be freed.
358  *
359  * Since: 0.4
360  */
361 GList *
362 champlain_polygon_get_points (ChamplainPolygon *self)
363 {
364   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (self), NULL);
365
366   return self->priv->points;
367 }
368
369 /**
370  * champlain_polygon_set_fill_color:
371  * @polygon: The polygon
372  * @color: The polygon's fill color or NULL to reset to the
373  *         default color. The color parameter is copied.
374  *
375  * Set the polygon's fill color.
376  *
377  * Since: 0.4
378  */
379 void
380 champlain_polygon_set_fill_color (ChamplainPolygon *polygon,
381     const ClutterColor *color)
382 {
383   g_return_if_fail (CHAMPLAIN_IS_POLYGON (polygon));
384
385   ChamplainPolygonPrivate *priv = polygon->priv;
386
387   if (priv->fill_color != NULL)
388     clutter_color_free (priv->fill_color);
389
390   if (color == NULL)
391      color = &DEFAULT_FILL_COLOR;
392
393   priv->fill_color = clutter_color_copy (color);
394   g_object_notify (G_OBJECT (polygon), "fill-color");
395 }
396
397 /**
398  * champlain_polygon_set_stoke_color:
399  * @polygon: The polygon
400  * @color: The polygon's stroke color or NULL to reset to the
401  *         default color. The color parameter is copied.
402  *
403  * Set the polygon's stroke color.
404  *
405  * Since: 0.4
406  */
407 void
408 champlain_polygon_set_stroke_color (ChamplainPolygon *polygon,
409     const ClutterColor *color)
410 {
411   g_return_if_fail (CHAMPLAIN_IS_POLYGON (polygon));
412
413   ChamplainPolygonPrivate *priv = polygon->priv;
414
415   if (priv->stroke_color != NULL)
416     clutter_color_free (priv->stroke_color);
417
418   if (color == NULL)
419      color = &DEFAULT_STROKE_COLOR;
420
421   priv->stroke_color = clutter_color_copy (color);
422   g_object_notify (G_OBJECT (polygon), "stroke-color");
423 }
424
425 /**
426  * champlain_polygon_get_color:
427  * @polygon: The polygon
428  *
429  * Returns the polygon's fill color.
430  *
431  * Since: 0.4
432  */
433 ClutterColor *
434 champlain_polygon_get_fill_color (ChamplainPolygon *polygon)
435 {
436   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (polygon), NULL);
437
438   return polygon->priv->fill_color;
439 }
440
441 /**
442  * champlain_polygon_get_stroke_color:
443  * @polygon: The polygon
444  *
445  * Returns the polygon's stroke color.
446  *
447  * Since: 0.4
448  */
449 ClutterColor *
450 champlain_polygon_get_stroke_color (ChamplainPolygon *polygon)
451 {
452   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (polygon), NULL);
453
454   return polygon->priv->stroke_color;
455 }
456
457 /**
458  * champlain_polygon_set_stroke:
459  * @polygon: The polygon
460  * @value: if the polygon is stroked
461  *
462  * Sets the polygon to have a stroke
463  *
464  * Since: 0.4
465  */
466 void
467 champlain_polygon_set_stroke (ChamplainPolygon *polygon,
468     gboolean value)
469 {
470   g_return_if_fail (CHAMPLAIN_IS_POLYGON (polygon));
471
472   polygon->priv->stroke = value;
473 }
474
475 /**
476  * champlain_polygon_get_stroke:
477  * @polygon: The polygon
478  *
479  * Returns if the polygon has a stroke
480  *
481  * Since: 0.4
482  */
483 gboolean
484 champlain_polygon_get_stroke (ChamplainPolygon *polygon)
485 {
486   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (polygon), FALSE);
487
488   return polygon->priv->stroke;
489 }
490
491 /**
492  * champlain_polygon_set_fill:
493  * @polygon: The polygon
494  * @value: if the polygon is filled
495  *
496  * Sets the polygon to have be filled
497  *
498  * Since: 0.4
499  */
500 void
501 champlain_polygon_set_fill (ChamplainPolygon *polygon,
502     gboolean value)
503 {
504   g_return_if_fail (CHAMPLAIN_IS_POLYGON (polygon));
505
506   polygon->priv->fill = value;
507 }
508
509 /**
510  * champlain_polygon_get_fill:
511  * @polygon: The polygon
512  *
513  * Returns if the polygon is filled
514  *
515  * Since: 0.4
516  */
517 gboolean
518 champlain_polygon_get_fill (ChamplainPolygon *polygon)
519 {
520   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (polygon), FALSE);
521
522   return polygon->priv->fill;
523 }
524
525 /**
526  * champlain_polygon_set_stroke_width:
527  * @polygon: The polygon
528  * @value: the width of the stroke (in pixels)
529  *
530  * Sets the width of the stroke
531  *
532  * Since: 0.4
533  */
534 void
535 champlain_polygon_set_stroke_width (ChamplainPolygon *polygon,
536     gdouble value)
537 {
538   g_return_if_fail (CHAMPLAIN_IS_POLYGON (polygon));
539
540   polygon->priv->stroke_width = value;
541 }
542
543 /**
544  * champlain_polygon_get_stroke_width:
545  * @polygon: The polygon
546  *
547  * Returns the width of the stroke
548  *
549  * Since: 0.4
550  */
551 gdouble
552 champlain_polygon_get_stroke_width (ChamplainPolygon *polygon)
553 {
554   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (polygon), 0);
555
556   return polygon->priv->stroke_width;
557 }