champlain-marker-layer.c 21.9 KB
Newer Older
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
1
/*
2
 * Copyright (C) 2008-2009 Pierre-Luc Beaudoin <pierre-luc@pierlux.com>
Jiří Techet's avatar
Jiří Techet committed
3
 * Copyright (C) 2011-2013 Jiri Techet <techet@gmail.com>
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
4 5
 *
 * This library is free software; you can redistribute it and/or
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
6
 * modify it under the terms of the GNU Lesser General Public
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
7
 * License as published by the Free Software Foundation; either
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
8
 * version 2.1 of the License, or (at your option) any later version.
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
9 10 11 12
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
13
 * Lesser General Public License for more details.
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
14
 *
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
15 16 17
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
18 19
 */

20
/**
21
 * SECTION:champlain-marker-layer
22 23
 * @short_description: A container for #ChamplainMarker
 *
Jiří Techet's avatar
Jiří Techet committed
24
 * A ChamplainMarkerLayer displays markers on the map. It is responsible for
Jiří Techet's avatar
Jiří Techet committed
25
 * positioning markers correctly, marker selections and group marker operations.
26 27
 */

Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
28 29
#include "config.h"

30
#include "champlain-marker-layer.h"
31 32

#include "champlain-defines.h"
33 34
#include "champlain-enum-types.h"
#include "champlain-private.h"
35
#include "champlain-view.h"
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
36 37 38 39

#include <clutter/clutter.h>
#include <glib.h>

40 41
static void exportable_interface_init (ChamplainExportableIface *iface);

42 43 44 45 46
struct _ChamplainMarkerLayerPrivate
{
  ChamplainSelectionMode mode;
  ChamplainView *view;
};
47

48 49 50
G_DEFINE_TYPE_WITH_CODE (ChamplainMarkerLayer, champlain_marker_layer, CHAMPLAIN_TYPE_LAYER,
    G_ADD_PRIVATE (ChamplainMarkerLayer)
    G_IMPLEMENT_INTERFACE (CHAMPLAIN_TYPE_EXPORTABLE, exportable_interface_init))
51

52 53
enum
{
54 55
  /* normal signals */
  LAST_SIGNAL
56 57
};

58 59 60
enum
{
  PROP_0,
61
  PROP_SELECTION_MODE,
62
  PROP_SURFACE,
63 64 65
};


66 67 68
static void set_surface (ChamplainExportable *exportable,
    cairo_surface_t *surface);
static cairo_surface_t *get_surface (ChamplainExportable *exportable);
69

70
static void marker_selected_cb (ChamplainMarker *marker,
71
    G_GNUC_UNUSED GParamSpec *arg1,
72
    ChamplainMarkerLayer *layer);
Jiří Techet's avatar
Jiří Techet committed
73

74 75 76
static void set_view (ChamplainLayer *layer,
    ChamplainView *view);

Jiří Techet's avatar
Jiří Techet committed
77 78
static ChamplainBoundingBox *get_bounding_box (ChamplainLayer *layer);

79

80
static void
81
champlain_marker_layer_get_property (GObject *object,
82
    guint property_id,
83
    G_GNUC_UNUSED GValue *value,
84
    GParamSpec *pspec)
85
{
86 87
  ChamplainMarkerLayer *self = CHAMPLAIN_MARKER_LAYER (object);
  ChamplainMarkerLayerPrivate *priv = self->priv;
Jiří Techet's avatar
Jiří Techet committed
88

89 90
  switch (property_id)
    {
91 92 93
    case PROP_SELECTION_MODE:
      g_value_set_enum (value, priv->mode);
      break;
Jiří Techet's avatar
Jiří Techet committed
94

95 96 97 98
    case PROP_SURFACE:
      g_value_set_boxed (value, get_surface (CHAMPLAIN_EXPORTABLE (self)));
      break;

99 100
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
101 102 103
    }
}

104

105
static void
106
champlain_marker_layer_set_property (GObject *object,
107
    guint property_id,
108
    G_GNUC_UNUSED const GValue *value,
109
    GParamSpec *pspec)
110
{
111
  ChamplainMarkerLayer *self = CHAMPLAIN_MARKER_LAYER (object);
Jiří Techet's avatar
Jiří Techet committed
112

113 114
  switch (property_id)
    {
115
    case PROP_SELECTION_MODE:
116
      champlain_marker_layer_set_selection_mode (self, g_value_get_enum (value));
117
      break;
Jiří Techet's avatar
Jiří Techet committed
118

119 120 121 122
    case PROP_SURFACE:
      set_surface (CHAMPLAIN_EXPORTABLE (object), g_value_get_boxed (value));
      break;

123 124 125 126
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    }
}
127 128


129
static void
130
champlain_marker_layer_dispose (GObject *object)
131
{
132 133
  ChamplainMarkerLayer *self = CHAMPLAIN_MARKER_LAYER (object);
  ChamplainMarkerLayerPrivate *priv = self->priv;
Jiří Techet's avatar
Jiří Techet committed
134

135
  if (priv->view != NULL)
136
    set_view (CHAMPLAIN_LAYER (self), NULL);
137

138
  G_OBJECT_CLASS (champlain_marker_layer_parent_class)->dispose (object);
139 140
}

141

142
static void
143
champlain_marker_layer_finalize (GObject *object)
144
{
145
  G_OBJECT_CLASS (champlain_marker_layer_parent_class)->finalize (object);
146 147
}

148

149
static void
150
champlain_marker_layer_class_init (ChamplainMarkerLayerClass *klass)
151 152
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
153
  ChamplainLayerClass *layer_class = CHAMPLAIN_LAYER_CLASS (klass);
154

155 156 157 158
  object_class->finalize = champlain_marker_layer_finalize;
  object_class->dispose = champlain_marker_layer_dispose;
  object_class->get_property = champlain_marker_layer_get_property;
  object_class->set_property = champlain_marker_layer_set_property;
Jiří Techet's avatar
Jiří Techet committed
159

160
  layer_class->set_view = set_view;
Jiří Techet's avatar
Jiří Techet committed
161 162
  layer_class->get_bounding_box = get_bounding_box;

163
  /**
164
   * ChamplainMarkerLayer:selection-mode:
165 166 167 168 169 170 171 172 173 174 175 176 177
   *
   * Determines the type of selection that will be performed.
   *
   * Since: 0.10
   */
  g_object_class_install_property (object_class,
      PROP_SELECTION_MODE,
      g_param_spec_enum ("selection-mode",
          "Selection Mode",
          "Determines the type of selection that will be performed.",
          CHAMPLAIN_TYPE_SELECTION_MODE,
          CHAMPLAIN_SELECTION_NONE,
          CHAMPLAIN_PARAM_READWRITE));
178 179 180 181

    g_object_class_override_property (object_class,
      PROP_SURFACE,
      "surface");
182 183
}

184

185
static void
186
champlain_marker_layer_init (ChamplainMarkerLayer *self)
187
{
188
  ChamplainMarkerLayerPrivate *priv = champlain_marker_layer_get_instance_private (self);
Jiří Techet's avatar
Jiří Techet committed
189

190
  self->priv = priv;
191 192
  priv->mode = CHAMPLAIN_SELECTION_NONE;
  priv->view = NULL;
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
193 194
}

195

196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
static void
set_surface (ChamplainExportable *exportable,
     cairo_surface_t *surface)
{
  /* no need */
}

static cairo_surface_t *
get_surface (ChamplainExportable *exportable)
{
  g_return_val_if_fail (CHAMPLAIN_IS_MARKER_LAYER (exportable), NULL);

  ClutterActorIter iter;
  ClutterActor *child;
  ChamplainMarkerLayer *layer = CHAMPLAIN_MARKER_LAYER (exportable);
  ChamplainMarkerLayerPrivate *priv = layer->priv;
  cairo_surface_t *surface = NULL;
  cairo_t *cr;
  gboolean has_marker = FALSE;

  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (layer));
  while (clutter_actor_iter_next (&iter, &child))
    {
      ChamplainMarker *marker = CHAMPLAIN_MARKER (child);

      if (CHAMPLAIN_IS_EXPORTABLE (marker))
        {
          gfloat x, y, tx, ty;
          gint origin_x, origin_y;
          cairo_surface_t *marker_surface;
          ChamplainExportable *exportable;

          if (!has_marker)
            {
              gfloat width, height;

              width = 256;
              height = 256;
              if (priv->view != NULL)
                clutter_actor_get_size (CLUTTER_ACTOR (priv->view),&width, &height);
              surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
              has_marker = TRUE;
            }

          exportable = CHAMPLAIN_EXPORTABLE (marker);
          marker_surface = champlain_exportable_get_surface (exportable);

          champlain_view_get_viewport_origin (priv->view, &origin_x, &origin_y);
          clutter_actor_get_translation (CLUTTER_ACTOR (marker), &tx, &ty, NULL);
          clutter_actor_get_position (CLUTTER_ACTOR (marker), &x, &y);

          cr = cairo_create (surface);
          cairo_set_source_surface (cr, marker_surface,
                                    (x + tx) - origin_x,
                                    (y + ty) - origin_y);
          cairo_paint (cr);
          cairo_destroy (cr);
        }
    }

  return surface;
}

static void
exportable_interface_init (ChamplainExportableIface *iface)
{
  iface->get_surface = get_surface;
  iface->set_surface = set_surface;
}


267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
/**
 * champlain_marker_layer_new:
 *
 * Creates a new instance of #ChamplainMarkerLayer.
 *
 * Returns: a new #ChamplainMarkerLayer ready to be used as a container for the markers.
 *
 * Since: 0.10
 */
ChamplainMarkerLayer *
champlain_marker_layer_new ()
{
  return g_object_new (CHAMPLAIN_TYPE_MARKER_LAYER, NULL);
}


Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
283
/**
284
 * champlain_marker_layer_new_full:
285
 * @mode: Selection mode
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
286
 *
287
 * Creates a new instance of #ChamplainMarkerLayer with the specified selection mode.
288
 *
Jiří Techet's avatar
Jiří Techet committed
289
 * Returns: a new #ChamplainMarkerLayer ready to be used as a container for the markers.
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
290
 *
Jiří Techet's avatar
Jiří Techet committed
291
 * Since: 0.10
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
292
 */
293 294
ChamplainMarkerLayer *
champlain_marker_layer_new_full (ChamplainSelectionMode mode)
295
{
296
  return g_object_new (CHAMPLAIN_TYPE_MARKER_LAYER, "selection-mode", mode, NULL);
297 298 299 300
}


static void
301 302 303
set_selected_all_but_one (ChamplainMarkerLayer *layer,
    ChamplainMarker *not_selected,
    gboolean select)
304
{
305 306
  ClutterActorIter iter;
  ClutterActor *child;
Jiří Techet's avatar
Jiří Techet committed
307

308 309
  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (layer));
  while (clutter_actor_iter_next (&iter, &child))
310
    {
311
      ChamplainMarker *marker = CHAMPLAIN_MARKER (child);
Jiří Techet's avatar
Jiří Techet committed
312

313
      if (marker != not_selected)
314
        {
Jiří Techet's avatar
Jiří Techet committed
315 316
          g_signal_handlers_block_by_func (marker,
              G_CALLBACK (marker_selected_cb),
317 318
              layer);

319
          champlain_marker_set_selected (marker, select);
320
          champlain_marker_set_selectable (marker, layer->priv->mode != CHAMPLAIN_SELECTION_NONE);
321

Jiří Techet's avatar
Jiří Techet committed
322 323
          g_signal_handlers_unblock_by_func (marker,
              G_CALLBACK (marker_selected_cb),
324
              layer);
325 326 327 328 329
        }
    }
}


330
static void
331
marker_selected_cb (ChamplainMarker *marker,
332
    G_GNUC_UNUSED GParamSpec *arg1,
333
    ChamplainMarkerLayer *layer)
334
{
335
  if (layer->priv->mode == CHAMPLAIN_SELECTION_SINGLE && champlain_marker_get_selected (marker))
336
    set_selected_all_but_one (layer, marker, FALSE);
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
337
}
338

339

340
static void
341
set_marker_position (ChamplainMarkerLayer *layer, ChamplainMarker *marker)
342
{
343
  ChamplainMarkerLayerPrivate *priv = layer->priv;
344
  gint x, y, origin_x, origin_y;
Jiří Techet's avatar
Jiří Techet committed
345

346 347 348 349
  /* layer not yet added to the view */
  if (priv->view == NULL)
    return;

350
  champlain_view_get_viewport_origin (priv->view, &origin_x, &origin_y);
Jiří Techet's avatar
Jiří Techet committed
351 352 353 354
  x = champlain_view_longitude_to_x (priv->view,
        champlain_location_get_longitude (CHAMPLAIN_LOCATION (marker))) + origin_x;
  y = champlain_view_latitude_to_y (priv->view,
        champlain_location_get_latitude (CHAMPLAIN_LOCATION (marker))) + origin_y;
355 356 357 358 359 360

  clutter_actor_set_position (CLUTTER_ACTOR (marker), x, y);
}


static void
361
marker_position_notify (ChamplainMarker *marker,
362
    G_GNUC_UNUSED GParamSpec *pspec,
363
    ChamplainMarkerLayer *layer)
364 365 366 367 368 369
{
  set_marker_position (layer, marker);
}


static void
370
marker_move_by_cb (ChamplainMarker *marker,
371 372
    gdouble dx,
    gdouble dy,
373
    ClutterEvent *event,
374
    ChamplainMarkerLayer *layer)
375
{
376
  ChamplainMarkerLayerPrivate *priv = layer->priv;
377 378 379
  ChamplainView *view = priv->view;
  gdouble x, y, lat, lon;

380 381
  x = champlain_view_longitude_to_x (view, champlain_location_get_longitude (CHAMPLAIN_LOCATION (marker)));
  y = champlain_view_latitude_to_y (view, champlain_location_get_latitude (CHAMPLAIN_LOCATION (marker)));
Jiří Techet's avatar
Jiří Techet committed
382

383 384 385 386 387
  x += dx;
  y += dy;

  lon = champlain_view_x_to_longitude (view, x);
  lat = champlain_view_y_to_latitude (view, y);
Jiří Techet's avatar
Jiří Techet committed
388

389
  champlain_location_set_location (CHAMPLAIN_LOCATION (marker), lat, lon);
390 391 392
}


393 394 395 396 397 398 399
/**
 * champlain_marker_layer_add_marker:
 * @layer: a #ChamplainMarkerLayer
 * @marker: a #ChamplainMarker
 *
 * Adds the marker to the layer.
 *
Jiří Techet's avatar
Jiří Techet committed
400
 * Since: 0.10
401 402 403 404 405 406 407 408
 */
void
champlain_marker_layer_add_marker (ChamplainMarkerLayer *layer,
    ChamplainMarker *marker)
{
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));
  g_return_if_fail (CHAMPLAIN_IS_MARKER (marker));

409 410 411 412 413 414 415 416 417 418
  champlain_marker_set_selectable (marker, layer->priv->mode != CHAMPLAIN_SELECTION_NONE);

  g_signal_connect (G_OBJECT (marker), "notify::selected",
      G_CALLBACK (marker_selected_cb), layer);

  g_signal_connect (G_OBJECT (marker), "notify::latitude",
      G_CALLBACK (marker_position_notify), layer);

  g_signal_connect (G_OBJECT (marker), "drag-motion",
      G_CALLBACK (marker_move_by_cb), layer);
Jiří Techet's avatar
Jiří Techet committed
419

420
  clutter_actor_add_child (CLUTTER_ACTOR (layer), CLUTTER_ACTOR (marker));
421
  set_marker_position (layer, marker);
422 423 424
}


Jiří Techet's avatar
Jiří Techet committed
425 426 427 428 429 430 431 432
/**
 * champlain_marker_layer_remove_all:
 * @layer: a #ChamplainMarkerLayer
 *
 * Removes all markers from the layer.
 *
 * Since: 0.10
 */
Jiří Techet's avatar
Jiří Techet committed
433 434
void
champlain_marker_layer_remove_all (ChamplainMarkerLayer *layer)
435
{
436 437
  ClutterActorIter iter;
  ClutterActor *child;
Jiří Techet's avatar
Jiří Techet committed
438

439 440
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));

441 442
  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (layer));
  while (clutter_actor_iter_next (&iter, &child))
443
    {
444
      GObject *marker = G_OBJECT (child);
Jiří Techet's avatar
Jiří Techet committed
445

446 447 448 449 450
      g_signal_handlers_disconnect_by_func (marker,
          G_CALLBACK (marker_selected_cb), layer);

      g_signal_handlers_disconnect_by_func (marker,
          G_CALLBACK (marker_position_notify), layer);
451 452 453

      g_signal_handlers_disconnect_by_func (marker,
          G_CALLBACK (marker_move_by_cb), layer);
454 455
          
      clutter_actor_iter_remove (&iter);
456 457 458 459
    }
}


Jiří Techet's avatar
Jiří Techet committed
460 461 462 463
/**
 * champlain_marker_layer_get_markers:
 * @layer: a #ChamplainMarkerLayer
 *
464 465
 * Gets a copy of the list of all markers inserted into the layer. You should
 * free the list but not its contents.
Jiří Techet's avatar
Jiří Techet committed
466
 *
467
 * Returns: (transfer container) (element-type ChamplainMarker): the list
Jiří Techet's avatar
Jiří Techet committed
468 469 470
 *
 * Since: 0.10
 */
471 472 473
GList *
champlain_marker_layer_get_markers (ChamplainMarkerLayer *layer)
{
474 475
  GList *lst;
  
476
  lst = clutter_actor_get_children (CLUTTER_ACTOR (layer));
477
  return g_list_reverse (lst);
478 479 480
}


481 482 483 484
/**
 * champlain_marker_layer_get_selected:
 * @layer: a #ChamplainMarkerLayer
 *
485
 * Gets a list of selected markers in the layer.
Jiří Techet's avatar
Jiří Techet committed
486
 *
487 488 489 490 491 492 493 494 495 496 497
 * Returns: (transfer container) (element-type ChamplainMarker): the list
 *
 * Since: 0.10
 */
GList *
champlain_marker_layer_get_selected (ChamplainMarkerLayer *layer)
{
  GList *selected = NULL;

  g_return_val_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer), NULL);

498 499
  ClutterActorIter iter;
  ClutterActor *child;
Jiří Techet's avatar
Jiří Techet committed
500

501 502
  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (layer));
  while (clutter_actor_iter_next (&iter, &child))
503
    {
504
      ChamplainMarker *marker = CHAMPLAIN_MARKER (child);
505 506

      if (champlain_marker_get_selected (marker))
507
        selected = g_list_prepend (selected, marker);
508 509 510 511 512 513
    }

  return selected;
}


514
/**
515 516
 * champlain_marker_layer_remove_marker:
 * @layer: a #ChamplainMarkerLayer
517
 * @marker: a #ChamplainMarker
518 519 520
 *
 * Removes the marker from the layer.
 *
Jiří Techet's avatar
Jiří Techet committed
521
 * Since: 0.10
522 523
 */
void
524
champlain_marker_layer_remove_marker (ChamplainMarkerLayer *layer,
525
    ChamplainMarker *marker)
526
{
527
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));
528
  g_return_if_fail (CHAMPLAIN_IS_MARKER (marker));
529

530
  g_signal_handlers_disconnect_by_func (G_OBJECT (marker),
531
      G_CALLBACK (marker_selected_cb), layer);
532

533 534 535
  g_signal_handlers_disconnect_by_func (G_OBJECT (marker),
      G_CALLBACK (marker_position_notify), layer);

536 537 538
  g_signal_handlers_disconnect_by_func (marker,
      G_CALLBACK (marker_move_by_cb), layer);

539
  clutter_actor_remove_child (CLUTTER_ACTOR (layer), CLUTTER_ACTOR (marker));
540
}
541

542

543
/**
544 545
 * champlain_marker_layer_animate_in_all_markers:
 * @layer: a #ChamplainMarkerLayer
546
 *
547
 * Fade in all markers in the layer with an animation
548
 *
Jiří Techet's avatar
Jiří Techet committed
549
 * Since: 0.10
550 551
 */
void
552
champlain_marker_layer_animate_in_all_markers (ChamplainMarkerLayer *layer)
553
{
554 555
  ClutterActorIter iter;
  ClutterActor *child;
556 557
  guint delay = 0;

558
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));
559

560 561
  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (layer));
  while (clutter_actor_iter_next (&iter, &child))
562
    {
563
      ChamplainMarker *marker = CHAMPLAIN_MARKER (child);
564

565
      champlain_marker_animate_in_with_delay (marker, delay);
566
      delay += 50;
567 568 569
    }
}

570

571
/**
572 573
 * champlain_marker_layer_animate_out_all_markers:
 * @layer: a #ChamplainMarkerLayer
574
 *
575
 * Fade out all markers in the layer with an animation
576
 *
Jiří Techet's avatar
Jiří Techet committed
577
 * Since: 0.10
578 579
 */
void
580
champlain_marker_layer_animate_out_all_markers (ChamplainMarkerLayer *layer)
581
{
582 583
  ClutterActorIter iter;
  ClutterActor *child;
584 585
  guint delay = 0;

586
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));
587

588 589
  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (layer));
  while (clutter_actor_iter_next (&iter, &child))
590
    {
591
      ChamplainMarker *marker = CHAMPLAIN_MARKER (child);
592

593
      champlain_marker_animate_out_with_delay (marker, delay);
594
      delay += 50;
595 596 597
    }
}

598

599
/**
600 601
 * champlain_marker_layer_show_all_markers:
 * @layer: a #ChamplainMarkerLayer
602
 *
603
 * Shows all markers in the layer
604
 *
Jiří Techet's avatar
Jiří Techet committed
605
 * Since: 0.10
606 607
 */
void
608
champlain_marker_layer_show_all_markers (ChamplainMarkerLayer *layer)
609
{
610 611
  ClutterActorIter iter;
  ClutterActor *child;
612

613
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));
614

615 616
  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (layer));
  while (clutter_actor_iter_next (&iter, &child))
617
    {
618
      ClutterActor *actor = CLUTTER_ACTOR (child);
619

620
      clutter_actor_show (actor);
621
    }
622 623
}

Jiří Techet's avatar
Jiří Techet committed
624

625
/**
626 627
 * champlain_marker_layer_hide_all_markers:
 * @layer: a #ChamplainMarkerLayer
628
 *
629
 * Hides all the markers in the layer
630
 *
Jiří Techet's avatar
Jiří Techet committed
631
 * Since: 0.10
632 633
 */
void
634
champlain_marker_layer_hide_all_markers (ChamplainMarkerLayer *layer)
635
{
636 637
  ClutterActorIter iter;
  ClutterActor *child;
638

639
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));
640

641 642
  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (layer));
  while (clutter_actor_iter_next (&iter, &child))
643
    {
644
      ClutterActor *actor = CLUTTER_ACTOR (child);
645

646
      clutter_actor_hide (actor);
647
    }
648
}
649 650


Jiří Techet's avatar
Jiří Techet committed
651
/**
652
 * champlain_marker_layer_set_all_markers_draggable:
Jiří Techet's avatar
Jiří Techet committed
653 654
 * @layer: a #ChamplainMarkerLayer
 *
655
 * Sets all markers draggable in the layer
Jiří Techet's avatar
Jiří Techet committed
656 657 658
 *
 * Since: 0.10
 */
659
void
660
champlain_marker_layer_set_all_markers_draggable (ChamplainMarkerLayer *layer)
661
{
662 663
  ClutterActorIter iter;
  ClutterActor *child;
664

665
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));
666

667 668
  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (layer));
  while (clutter_actor_iter_next (&iter, &child))
669
    {
670
      ChamplainMarker *marker = CHAMPLAIN_MARKER (child);
671

672
      champlain_marker_set_draggable (marker, TRUE);
673 674 675 676
    }
}


Jiří Techet's avatar
Jiří Techet committed
677
/**
678
 * champlain_marker_layer_set_all_markers_undraggable:
Jiří Techet's avatar
Jiří Techet committed
679 680
 * @layer: a #ChamplainMarkerLayer
 *
681
 * Sets all markers undraggable in the layer
Jiří Techet's avatar
Jiří Techet committed
682 683 684
 *
 * Since: 0.10
 */
685
void
686
champlain_marker_layer_set_all_markers_undraggable (ChamplainMarkerLayer *layer)
687
{
688 689
  ClutterActorIter iter;
  ClutterActor *child;
690

691
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));
692

693 694
  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (layer));
  while (clutter_actor_iter_next (&iter, &child))
695
    {
696
      ChamplainMarker *marker = CHAMPLAIN_MARKER (child);
697

698
      champlain_marker_set_draggable (marker, FALSE);
699
    }
700
}
701 702


703
/**
Jiří Techet's avatar
Jiří Techet committed
704
 * champlain_marker_layer_unselect_all_markers:
705
 * @layer: a #ChamplainMarkerLayer
706
 *
707
 * Unselects all markers in the layer.
708
 *
Jiří Techet's avatar
Jiří Techet committed
709
 * Since: 0.10
710 711
 */
void
Jiří Techet's avatar
Jiří Techet committed
712
champlain_marker_layer_unselect_all_markers (ChamplainMarkerLayer *layer)
713
{
714
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));
715

716
  set_selected_all_but_one (layer, NULL, FALSE);
717 718 719 720
}


/**
Jiří Techet's avatar
Jiří Techet committed
721
 * champlain_marker_layer_select_all_markers:
722
 * @layer: a #ChamplainMarkerLayer
723
 *
Jiří Techet's avatar
Jiří Techet committed
724
 * Selects all markers in the layer.
725
 *
Jiří Techet's avatar
Jiří Techet committed
726
 * Since: 0.10
727 728
 */
void
Jiří Techet's avatar
Jiří Techet committed
729
champlain_marker_layer_select_all_markers (ChamplainMarkerLayer *layer)
730
{
731
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));
732

733
  set_selected_all_but_one (layer, NULL, TRUE);
734 735 736 737
}


/**
738 739
 * champlain_marker_layer_set_selection_mode:
 * @layer: a #ChamplainMarkerLayer
740 741 742 743 744 745 746
 * @mode: a #ChamplainSelectionMode value
 *
 * Sets the selection mode of the layer.
 *
 * NOTE: changing selection mode to CHAMPLAIN_SELECTION_NONE or
 * CHAMPLAIN_SELECTION_SINGLE will clear all previously selected markers.
 *
Jiří Techet's avatar
Jiří Techet committed
747
 * Since: 0.10
748 749
 */
void
750
champlain_marker_layer_set_selection_mode (ChamplainMarkerLayer *layer,
751 752
    ChamplainSelectionMode mode)
{
753
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));
754 755 756 757 758

  if (layer->priv->mode == mode)
    return;
  layer->priv->mode = mode;

759 760
  if (mode != CHAMPLAIN_SELECTION_MULTIPLE)
    set_selected_all_but_one (layer, NULL, FALSE);
761 762 763 764 765 766

  g_object_notify (G_OBJECT (layer), "selection-mode");
}


/**
767 768
 * champlain_marker_layer_get_selection_mode:
 * @layer: a #ChamplainMarkerLayer
769 770 771 772 773
 *
 * Gets the selection mode of the layer.
 *
 * Returns: the selection mode of the layer.
 *
Jiří Techet's avatar
Jiří Techet committed
774
 * Since: 0.10
775 776
 */
ChamplainSelectionMode
777
champlain_marker_layer_get_selection_mode (ChamplainMarkerLayer *layer)
778
{
779
  g_return_val_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer), CHAMPLAIN_SELECTION_SINGLE);
780 781 782 783
  return layer->priv->mode;
}


784
static void
785
reposition (ChamplainMarkerLayer *layer)
786
{
787 788
  ClutterActorIter iter;
  ClutterActor *child;
789 790 791

  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));

792 793
  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (layer));
  while (clutter_actor_iter_next (&iter, &child))
794
    {
795
      ChamplainMarker *marker = CHAMPLAIN_MARKER (child);
Jiří Techet's avatar
Jiří Techet committed
796

797
      set_marker_position (layer, marker);
798 799 800
    }
}

801

802 803
static void
relocate_cb (G_GNUC_UNUSED GObject *gobject,
804
    ChamplainMarkerLayer *layer)
805
{
806
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));
Jiří Techet's avatar
Jiří Techet committed
807

808 809 810 811 812 813 814 815 816 817 818 819
  reposition (layer);
}


static void
zoom_reposition_cb (G_GNUC_UNUSED GObject *gobject,
    G_GNUC_UNUSED GParamSpec *arg1,
    ChamplainMarkerLayer *layer)
{
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer));

  reposition (layer);
820 821 822
}


Jiří Techet's avatar
Jiří Techet committed
823
static void
824
set_view (ChamplainLayer *layer,
825 826
    ChamplainView *view)
{
827
  g_return_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer) && (CHAMPLAIN_IS_VIEW (view) || view == NULL));
Jiří Techet's avatar
Jiří Techet committed
828

829
  ChamplainMarkerLayer *marker_layer = CHAMPLAIN_MARKER_LAYER (layer);
Jiří Techet's avatar
Jiří Techet committed
830

831
  if (marker_layer->priv->view != NULL)
832
    {
833
      g_signal_handlers_disconnect_by_func (marker_layer->priv->view,
Jiří Techet's avatar
Jiří Techet committed
834
          G_CALLBACK (relocate_cb), marker_layer);
835
      g_object_unref (marker_layer->priv->view);
836
    }
Jiří Techet's avatar
Jiří Techet committed
837

838
  marker_layer->priv->view = view;
839 840 841 842

  if (view != NULL)
    {
      g_object_ref (view);
Jiří Techet's avatar
Jiří Techet committed
843

844
      g_signal_connect (view, "layer-relocated",
Jiří Techet's avatar
Jiří Techet committed
845
          G_CALLBACK (relocate_cb), layer);
846

847 848 849 850
      g_signal_connect (view, "notify::zoom-level",
          G_CALLBACK (zoom_reposition_cb), layer);

      reposition (marker_layer);
851 852 853
    }
}

Jiří Techet's avatar
Jiří Techet committed
854 855 856

static ChamplainBoundingBox *
get_bounding_box (ChamplainLayer *layer)
857
{
858 859
  ClutterActorIter iter;
  ClutterActor *child;
860
  ChamplainBoundingBox *bbox;
861 862

  g_return_val_if_fail (CHAMPLAIN_IS_MARKER_LAYER (layer), NULL);
Jiří Techet's avatar
Jiří Techet committed
863

864
  bbox = champlain_bounding_box_new ();
865

866 867
  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (layer));
  while (clutter_actor_iter_next (&iter, &child))
868
    {
869
      ChamplainMarker *marker = CHAMPLAIN_MARKER (child);
870
      gdouble lat, lon;
Jiří Techet's avatar
Jiří Techet committed
871

872 873
      lat = champlain_location_get_latitude (CHAMPLAIN_LOCATION (marker));
      lon = champlain_location_get_longitude (CHAMPLAIN_LOCATION (marker));
874

Jiří Techet's avatar
Jiří Techet committed
875
      champlain_bounding_box_extend (bbox, lat, lon);
876
    }
877

Jiří Techet's avatar
Jiří Techet committed
878 879 880 881 882 883 884 885 886 887 888
  if (bbox->left == bbox->right)
    {
      bbox->left -= 0.0001;
      bbox->right += 0.0001;
    }

  if (bbox->bottom == bbox->top)
    {
      bbox->bottom -= 0.0001;
      bbox->top += 0.0001;
    }
889

890
  return bbox;
891
}