Add champlain_polygon_remote_point
[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 polygon to be drawn on the map
22  *
23  * A ChamplainPolygon is a set of point forming a shape on the map.  This API is based on Cairo's.
24  */
25
26 #include "config.h"
27
28 #include "champlain-polygon.h"
29
30 #include "champlain-defines.h"
31 #include "champlain-private.h"
32
33 #include <clutter/clutter.h>
34 #include <clutter-cairo/clutter-cairo.h>
35 #include <glib.h>
36
37 static ClutterColor DEFAULT_FILL_COLOR = {0xcc, 0x00, 0x00, 0xaa};
38 static ClutterColor DEFAULT_STROKE_COLOR = {0xa4, 0x00, 0x00, 0xff};
39
40 G_DEFINE_TYPE (ChamplainPolygon, champlain_polygon, G_TYPE_OBJECT)
41
42 #define GET_PRIVATE(o) \
43   (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHAMPLAIN_TYPE_POLYGON, ChamplainPolygonPrivate))
44
45 enum
46 {
47   PROP_0,
48   PROP_CLOSED_PATH,
49   PROP_STROKE_WIDTH,
50   PROP_STROKE_COLOR,
51   PROP_FILL,
52   PROP_FILL_COLOR,
53   PROP_STROKE,
54   PROP_VISIBLE,
55 };
56
57 static void
58 champlain_polygon_get_property (GObject *object,
59     guint property_id,
60     GValue *value,
61     GParamSpec *pspec)
62 {
63   ChamplainPolygonPrivate *priv = GET_PRIVATE (object);
64
65   switch (property_id)
66     {
67       case PROP_CLOSED_PATH:
68         g_value_set_boolean (value, priv->closed_path);
69         break;
70       case PROP_FILL:
71         g_value_set_boolean (value, priv->fill);
72         break;
73       case PROP_STROKE:
74         g_value_set_boolean (value, priv->stroke);
75         break;
76       case PROP_FILL_COLOR:
77         clutter_value_set_color (value, priv->fill_color);
78         break;
79       case PROP_STROKE_COLOR:
80         clutter_value_set_color (value, priv->stroke_color);
81         break;
82       case PROP_STROKE_WIDTH:
83         g_value_set_double (value, priv->stroke_width);
84         break;
85       case PROP_VISIBLE:
86         g_value_set_boolean (value, priv->visible);
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       case PROP_VISIBLE:
127         if (g_value_get_boolean (value) == TRUE)
128             champlain_polygon_show (CHAMPLAIN_POLYGON (object));
129         else
130             champlain_polygon_hide (CHAMPLAIN_POLYGON (object));
131         break;
132       default:
133         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
134     }
135 }
136
137 static void
138 champlain_polygon_dispose (GObject *object)
139 {
140   ChamplainPolygonPrivate *priv = GET_PRIVATE (object);
141
142   if (priv->actor != NULL)
143     {
144       g_object_unref (priv->actor);
145       priv->actor = NULL;
146     }
147
148   G_OBJECT_CLASS (champlain_polygon_parent_class)->dispose (object);
149 }
150
151 static void
152 champlain_polygon_finalize (GObject *object)
153 {
154   G_OBJECT_CLASS (champlain_polygon_parent_class)->finalize (object);
155 }
156
157 static void
158 champlain_polygon_class_init (ChamplainPolygonClass *klass)
159 {
160   GObjectClass *object_class = G_OBJECT_CLASS (klass);
161
162   g_type_class_add_private (klass, sizeof (ChamplainPolygonPrivate));
163
164   object_class->get_property = champlain_polygon_get_property;
165   object_class->set_property = champlain_polygon_set_property;
166   object_class->dispose = champlain_polygon_dispose;
167   object_class->finalize = champlain_polygon_finalize;
168
169   /**
170   * ChamplainPolygon:close-path:
171   *
172   * The shape is a closed path
173   *
174   * Since: 0.4
175   */
176   g_object_class_install_property (object_class,
177       PROP_CLOSED_PATH,
178       g_param_spec_boolean ("closed-path",
179           "Closed Path",
180           "The Path is Closed",
181           FALSE, CHAMPLAIN_PARAM_READWRITE));
182
183   /**
184   * ChamplainPolygon:fill:
185   *
186   * The shape should be filled
187   *
188   * Since: 0.4
189   */
190   g_object_class_install_property (object_class,
191       PROP_FILL,
192       g_param_spec_boolean ("fill",
193           "Fill",
194           "The shape is filled",
195           FALSE, CHAMPLAIN_PARAM_READWRITE));
196
197   /**
198   * ChamplainPolygon:stroke:
199   *
200   * The shape should be stroked
201   *
202   * Since: 0.4
203   */
204   g_object_class_install_property (object_class,
205       PROP_STROKE,
206       g_param_spec_boolean ("stroke",
207           "Stroke",
208           "The shape is stroked",
209           TRUE, CHAMPLAIN_PARAM_READWRITE));
210
211   /**
212   * ChamplainPolygon:stroke-color:
213   *
214   * The polygon's stroke color
215   *
216   * Since: 0.4
217   */
218   g_object_class_install_property (object_class,
219       PROP_STROKE_COLOR,
220       clutter_param_spec_color ("stroke-color",
221         "Stroke Color",
222         "The polygon's stroke color",
223         &DEFAULT_STROKE_COLOR,
224         CHAMPLAIN_PARAM_READWRITE));
225
226   /**
227   * ChamplainPolygon:text-color:
228   *
229   * The polygon's fill color
230   *
231   * Since: 0.4
232   */
233   g_object_class_install_property (object_class,
234       PROP_FILL_COLOR,
235       clutter_param_spec_color ("fill-color",
236           "Fill Color",
237           "The polygon's fill color",
238           &DEFAULT_FILL_COLOR,
239           CHAMPLAIN_PARAM_READWRITE));
240
241   /**
242   * ChamplainPolygon:stroke-width:
243   *
244   * The polygon's stroke width (in pixels)
245   *
246   * Since: 0.4
247   */
248   g_object_class_install_property (object_class,
249       PROP_STROKE_WIDTH,
250       g_param_spec_double ("stroke-width",
251           "Stroke Width",
252           "The polygon's stroke width",
253           0, 100.0,
254           2.0,
255           CHAMPLAIN_PARAM_READWRITE));
256
257   /**
258   * ChamplainPolygon:visible:
259   *
260   * Wether the polygon is visible
261   *
262   * Since: 0.4
263   */
264   g_object_class_install_property (object_class,
265       PROP_VISIBLE,
266       g_param_spec_boolean ("visible",
267           "Visible",
268           "The polygon's visibility",
269           TRUE,
270           CHAMPLAIN_PARAM_READWRITE));
271 }
272
273 static void
274 champlain_polygon_init (ChamplainPolygon *self)
275 {
276   self->priv = GET_PRIVATE (self);
277
278   self->priv->visible = TRUE;
279   self->priv->points = NULL;
280   self->priv->fill = FALSE;
281   self->priv->stroke = TRUE;
282   self->priv->stroke_width = 2.0;
283
284   self->priv->fill_color = clutter_color_copy (&DEFAULT_FILL_COLOR);
285   self->priv->stroke_color = clutter_color_copy (&DEFAULT_STROKE_COLOR);
286 }
287
288 /**
289  * champlain_polygon_new:
290  *
291  * Returns a new empty #ChamplainPolygon
292  *
293  * Since: 0.4
294  */
295 ChamplainPolygon *
296 champlain_polygon_new ()
297 {
298   return g_object_new (CHAMPLAIN_TYPE_POLYGON, NULL);
299 }
300
301 /**
302  * champlain_polygon_append_point:
303  * @polygon: The polygon
304  * @lat: the latitude
305  * @lon: the longitude
306  *
307  * Adds point at the end of the list of points in the polygon
308  *
309  * Returns the added point, should not be freed.
310  *
311  * Since: 0.4
312  */
313 ChamplainPoint *
314 champlain_polygon_append_point (ChamplainPolygon *self,
315     gdouble lat,
316     gdouble lon)
317 {
318   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (self), NULL);
319
320   ChamplainPoint *point = champlain_point_new (lat, lon);
321
322   self->priv->points = g_list_append (self->priv->points, point);
323   g_object_notify (G_OBJECT (self), "visible");
324   return point;
325 }
326
327 /**
328  * champlain_polygon_insert_point:
329  * @polygon: The polygon
330  * @lat: the latitude
331  * @lon: the longitude
332  * @pos: where to insert the point
333  *
334  * Adds point at the given position in the list of points in the polygon
335  *
336  * Returns the added point, should not be freed.
337  *
338  * Since: 0.4
339  */
340 ChamplainPoint *
341 champlain_polygon_insert_point (ChamplainPolygon *self,
342     gdouble lat,
343     gdouble lon,
344     gint pos)
345 {
346   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (self), NULL);
347
348   ChamplainPoint *point = champlain_point_new (lat, lon);
349
350   self->priv->points = g_list_insert (self->priv->points, point, pos);
351   g_object_notify (G_OBJECT (self), "visible");
352   return point;
353 }
354
355 /**
356  * champlain_polygon_remove_point:
357  * @polygon: The polygon
358  * @point: the #ChamplainPoint to remove
359  *
360  * Removes the point from the polygon.
361  *
362  * Since: 0.4
363  */
364 void
365 champlain_polygon_remove_point (ChamplainPolygon *self,
366     ChamplainPoint *point)
367 {
368   g_return_if_fail (CHAMPLAIN_IS_POLYGON (self));
369
370   self->priv->points = g_list_remove (self->priv->points, point);
371   g_object_notify (G_OBJECT (self), "visible");
372 }
373
374 /**
375  * champlain_polygon_clear_points:
376  * @polygon: The polygon
377  *
378  * Remove all points from the polygon
379  *
380  * Since: 0.4
381  */
382 void
383 champlain_polygon_clear_points (ChamplainPolygon *self)
384 {
385   g_return_if_fail (CHAMPLAIN_IS_POLYGON (self));
386
387   GList *next = self->priv->points;
388   while (next != NULL)
389   {
390     champlain_point_free (next->data);
391     next = g_list_next (next);
392   }
393   g_list_free (self->priv->points);
394   g_object_notify (G_OBJECT (self), "visible");
395 }
396
397 /**
398  * champlain_polygon_get_points:
399  * @polygon: The polygon
400  *
401  * Returns a list of all points from the polygon, it shouldn't be freed.
402  *
403  * Since: 0.4
404  */
405 GList *
406 champlain_polygon_get_points (ChamplainPolygon *self)
407 {
408   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (self), NULL);
409
410   return self->priv->points;
411 }
412
413 /**
414  * champlain_polygon_set_fill_color:
415  * @polygon: The polygon
416  * @color: The polygon's fill color or NULL to reset to the
417  *         default color. The color parameter is copied.
418  *
419  * Set the polygon's fill color.
420  *
421  * Since: 0.4
422  */
423 void
424 champlain_polygon_set_fill_color (ChamplainPolygon *polygon,
425     const ClutterColor *color)
426 {
427   g_return_if_fail (CHAMPLAIN_IS_POLYGON (polygon));
428
429   ChamplainPolygonPrivate *priv = polygon->priv;
430
431   if (priv->fill_color != NULL)
432     clutter_color_free (priv->fill_color);
433
434   if (color == NULL)
435      color = &DEFAULT_FILL_COLOR;
436
437   priv->fill_color = clutter_color_copy (color);
438   g_object_notify (G_OBJECT (polygon), "fill-color");
439 }
440
441 /**
442  * champlain_polygon_set_stoke_color:
443  * @polygon: The polygon
444  * @color: The polygon's stroke color or NULL to reset to the
445  *         default color. The color parameter is copied.
446  *
447  * Set the polygon's stroke color.
448  *
449  * Since: 0.4
450  */
451 void
452 champlain_polygon_set_stroke_color (ChamplainPolygon *polygon,
453     const ClutterColor *color)
454 {
455   g_return_if_fail (CHAMPLAIN_IS_POLYGON (polygon));
456
457   ChamplainPolygonPrivate *priv = polygon->priv;
458
459   if (priv->stroke_color != NULL)
460     clutter_color_free (priv->stroke_color);
461
462   if (color == NULL)
463      color = &DEFAULT_STROKE_COLOR;
464
465   priv->stroke_color = clutter_color_copy (color);
466   g_object_notify (G_OBJECT (polygon), "stroke-color");
467 }
468
469 /**
470  * champlain_polygon_get_color:
471  * @polygon: The polygon
472  *
473  * Returns the polygon's fill color.
474  *
475  * Since: 0.4
476  */
477 ClutterColor *
478 champlain_polygon_get_fill_color (ChamplainPolygon *polygon)
479 {
480   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (polygon), NULL);
481
482   return polygon->priv->fill_color;
483 }
484
485 /**
486  * champlain_polygon_get_stroke_color:
487  * @polygon: The polygon
488  *
489  * Returns the polygon's stroke color.
490  *
491  * Since: 0.4
492  */
493 ClutterColor *
494 champlain_polygon_get_stroke_color (ChamplainPolygon *polygon)
495 {
496   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (polygon), NULL);
497
498   return polygon->priv->stroke_color;
499 }
500
501 /**
502  * champlain_polygon_set_stroke:
503  * @polygon: The polygon
504  * @value: if the polygon is stroked
505  *
506  * Sets the polygon to have a stroke
507  *
508  * Since: 0.4
509  */
510 void
511 champlain_polygon_set_stroke (ChamplainPolygon *polygon,
512     gboolean value)
513 {
514   g_return_if_fail (CHAMPLAIN_IS_POLYGON (polygon));
515
516   polygon->priv->stroke = value;
517   g_object_notify (G_OBJECT (polygon), "stroke");
518 }
519
520 /**
521  * champlain_polygon_get_stroke:
522  * @polygon: The polygon
523  *
524  * Returns if the polygon has a stroke
525  *
526  * Since: 0.4
527  */
528 gboolean
529 champlain_polygon_get_stroke (ChamplainPolygon *polygon)
530 {
531   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (polygon), FALSE);
532
533   return polygon->priv->stroke;
534 }
535
536 /**
537  * champlain_polygon_set_fill:
538  * @polygon: The polygon
539  * @value: if the polygon is filled
540  *
541  * Sets the polygon to have be filled
542  *
543  * Since: 0.4
544  */
545 void
546 champlain_polygon_set_fill (ChamplainPolygon *polygon,
547     gboolean value)
548 {
549   g_return_if_fail (CHAMPLAIN_IS_POLYGON (polygon));
550
551   polygon->priv->fill = value;
552   g_object_notify (G_OBJECT (polygon), "fill");
553 }
554
555 /**
556  * champlain_polygon_get_fill:
557  * @polygon: The polygon
558  *
559  * Returns if the polygon is filled
560  *
561  * Since: 0.4
562  */
563 gboolean
564 champlain_polygon_get_fill (ChamplainPolygon *polygon)
565 {
566   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (polygon), FALSE);
567
568   return polygon->priv->fill;
569 }
570
571 /**
572  * champlain_polygon_set_stroke_width:
573  * @polygon: The polygon
574  * @value: the width of the stroke (in pixels)
575  *
576  * Sets the width of the stroke
577  *
578  * Since: 0.4
579  */
580 void
581 champlain_polygon_set_stroke_width (ChamplainPolygon *polygon,
582     gdouble value)
583 {
584   g_return_if_fail (CHAMPLAIN_IS_POLYGON (polygon));
585
586   polygon->priv->stroke_width = value;
587   g_object_notify (G_OBJECT (polygon), "stroke-width");
588 }
589
590 /**
591  * champlain_polygon_get_stroke_width:
592  * @polygon: The polygon
593  *
594  * Returns the width of the stroke
595  *
596  * Since: 0.4
597  */
598 gdouble
599 champlain_polygon_get_stroke_width (ChamplainPolygon *polygon)
600 {
601   g_return_val_if_fail (CHAMPLAIN_IS_POLYGON (polygon), 0);
602
603   return polygon->priv->stroke_width;
604 }
605
606 /**
607  * champlain_polygon_show:
608  * @polygon: The polygon
609  *
610  * Makes the polygon visible
611  *
612  * Since: 0.4
613  */
614 void
615 champlain_polygon_show (ChamplainPolygon *polygon)
616 {
617   g_return_if_fail (CHAMPLAIN_IS_POLYGON (polygon));
618
619   polygon->priv->visible = TRUE;
620   if (polygon->priv->actor != NULL)
621     clutter_actor_show (polygon->priv->actor);
622   g_object_notify (G_OBJECT (polygon), "visible");
623 }
624
625 /**
626  * champlain_polygon_hide:
627  * @polygon: The polygon
628  *
629  * Hides the polygon
630  *
631  * Since: 0.4
632  */
633 void
634 champlain_polygon_hide (ChamplainPolygon *polygon)
635 {
636   g_return_if_fail (CHAMPLAIN_IS_POLYGON (polygon));
637
638   polygon->priv->visible = FALSE;
639   if (polygon->priv->actor != NULL)
640     clutter_actor_hide (polygon->priv->actor);
641   g_object_notify (G_OBJECT (polygon), "visible");
642 }