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