Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2008-2009 Pierre-Luc Beaudoin <pierre-luc@pierlux.com>
3 : : * Copyright (C) 2011-2013 Jiri Techet <techet@gmail.com>
4 : : * Copyright (C) 2019 Marcus Lundblad <ml@update.uu.se>
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2.1 of the License, or (at your option) any later version.
10 : : *
11 : : * This library is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General Public
17 : : * License along with this library; if not, write to the Free Software
18 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : : */
20 : :
21 : : /**
22 : : * ShumateMarkerLayer:
23 : : *
24 : : * Displays markers on the map. It is responsible for positioning markers
25 : : * correctly, marker selections and group marker operations.
26 : : */
27 : :
28 : : #include "shumate-marker-layer.h"
29 : : #include "shumate-marker-private.h"
30 : : #include "shumate-inspector-settings-private.h"
31 : :
32 : : #include "shumate-enum-types.h"
33 : :
34 : : #include <cairo/cairo-gobject.h>
35 : : #include <glib.h>
36 : :
37 : : enum
38 : : {
39 : : PROP_SELECTION_MODE = 1,
40 : : N_PROPERTIES
41 : : };
42 : :
43 : : static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
44 : :
45 : : enum
46 : : {
47 : : MARKER_SELECTED,
48 : : MARKER_UNSELECTED,
49 : : LAST_SIGNAL
50 : : };
51 : :
52 : : static guint signals[LAST_SIGNAL];
53 : :
54 : :
55 : : struct _ShumateMarkerLayer
56 : : {
57 : : ShumateLayer parent_instance;
58 : :
59 : : GtkSelectionMode mode;
60 : : GList *selected;
61 : :
62 : : int n_children;
63 : : };
64 : :
65 [ + + + - ]: 493 : G_DEFINE_TYPE (ShumateMarkerLayer, shumate_marker_layer, SHUMATE_TYPE_LAYER);
66 : :
67 : : static void
68 : 0 : on_click_gesture_released (ShumateMarkerLayer *self,
69 : : int n_press,
70 : : double x,
71 : : double y,
72 : : GtkGestureClick *gesture)
73 : : {
74 : 0 : GtkWidget *self_widget = GTK_WIDGET (self);
75 : 0 : GtkWidget *child;
76 : 0 : ShumateMarker *marker;
77 : :
78 : 0 : child = gtk_widget_pick (self_widget, x, y, GTK_PICK_DEFAULT);
79 [ # # ]: 0 : if (!child)
80 : : return;
81 : :
82 [ # # # # ]: 0 : while (child != NULL && gtk_widget_get_parent (child) != self_widget)
83 : 0 : child = gtk_widget_get_parent (child);
84 : :
85 : 0 : marker = SHUMATE_MARKER (child);
86 [ # # ]: 0 : if (!marker)
87 : : return;
88 : :
89 [ # # ]: 0 : if (shumate_marker_is_selected (marker)) {
90 [ # # ]: 0 : if (self->mode != GTK_SELECTION_BROWSE) {
91 : 0 : shumate_marker_layer_unselect_marker (self, marker);
92 : : }
93 : : }
94 : : else {
95 : 0 : shumate_marker_layer_select_marker (self, marker);
96 : : }
97 : : }
98 : :
99 : : static void
100 : 208 : update_marker_visibility (ShumateMarkerLayer *layer,
101 : : ShumateMarker *marker)
102 : : {
103 : 208 : ShumateViewport *viewport;
104 : 208 : ShumateMapSource *map_source;
105 : 208 : gboolean within_viewport;
106 : 208 : double lon, lat;
107 : 208 : double x, y;
108 : 208 : int marker_width, marker_height;
109 : 208 : int width, height;
110 : :
111 [ + - ]: 208 : g_assert (SHUMATE_IS_MARKER_LAYER (layer));
112 : :
113 : 208 : viewport = shumate_layer_get_viewport (SHUMATE_LAYER (layer));
114 : 208 : map_source = shumate_viewport_get_reference_map_source (viewport);
115 [ + - ]: 208 : if (!map_source)
116 : 208 : return;
117 : :
118 : 0 : lon = shumate_location_get_longitude (SHUMATE_LOCATION (marker));
119 : 0 : lat = shumate_location_get_latitude (SHUMATE_LOCATION (marker));
120 : :
121 : 0 : width = gtk_widget_get_width (GTK_WIDGET (layer));
122 : 0 : height = gtk_widget_get_height (GTK_WIDGET (layer));
123 : :
124 : 0 : gtk_widget_measure (GTK_WIDGET (marker), GTK_ORIENTATION_HORIZONTAL, -1, 0, &marker_width, NULL, NULL);
125 : 0 : gtk_widget_measure (GTK_WIDGET (marker), GTK_ORIENTATION_VERTICAL, -1, 0, &marker_height, NULL, NULL);
126 : :
127 : 0 : shumate_viewport_location_to_widget_coords (viewport, GTK_WIDGET (layer), lat, lon, &x, &y);
128 : 0 : x = floorf (x - marker_width/2.f);
129 : 0 : y = floorf (y - marker_height/2.f);
130 : :
131 [ # # ]: 0 : within_viewport = x > -marker_width && x <= width &&
132 [ # # # # : 0 : y > -marker_height && y <= height &&
# # ]
133 [ # # # # ]: 0 : marker_width < width && marker_height < height;
134 : :
135 : 0 : gtk_widget_set_child_visible (GTK_WIDGET (marker), within_viewport);
136 : :
137 [ # # ]: 0 : if (within_viewport)
138 : : {
139 : 0 : graphene_rect_t bounds;
140 : :
141 [ # # ]: 0 : if (gtk_widget_compute_bounds (GTK_WIDGET (marker), GTK_WIDGET (layer), &bounds))
142 [ # # # # ]: 0 : if (bounds.origin.x != (int)x || bounds.origin.y != (int)y)
143 : 0 : gtk_widget_queue_allocate (GTK_WIDGET (layer));
144 : : }
145 : : }
146 : :
147 : : static void
148 : 0 : shumate_marker_layer_reposition_markers (ShumateMarkerLayer *self)
149 : : {
150 : 0 : GtkWidget *child;
151 : :
152 : 0 : for (child = gtk_widget_get_first_child (GTK_WIDGET (self));
153 [ # # ]: 0 : child != NULL;
154 : 0 : child = gtk_widget_get_next_sibling (child))
155 : : {
156 : 0 : update_marker_visibility (self, SHUMATE_MARKER (child));
157 : : }
158 : 0 : }
159 : :
160 : : static void
161 : 0 : on_viewport_changed (ShumateMarkerLayer *self,
162 : : GParamSpec *pspec,
163 : : ShumateViewport *view)
164 : : {
165 [ # # ]: 0 : g_assert (SHUMATE_IS_MARKER_LAYER (self));
166 : :
167 : 0 : shumate_marker_layer_reposition_markers (self);
168 : 0 : }
169 : :
170 : : static void
171 : 0 : shumate_marker_layer_size_allocate (GtkWidget *widget,
172 : : int width,
173 : : int height,
174 : : int baseline)
175 : : {
176 : 0 : ShumateMarkerLayer *self = SHUMATE_MARKER_LAYER (widget);
177 : 0 : ShumateViewport *viewport;
178 : 0 : GtkAllocation allocation;
179 : 0 : GtkWidget *child;
180 : :
181 : 0 : viewport = shumate_layer_get_viewport (SHUMATE_LAYER (self));
182 : :
183 : 0 : for (child = gtk_widget_get_first_child (GTK_WIDGET (self));
184 [ # # ]: 0 : child != NULL;
185 : 0 : child = gtk_widget_get_next_sibling (child))
186 : : {
187 : 0 : gboolean within_viewport;
188 : 0 : double lon, lat;
189 : 0 : double x, y;
190 : 0 : int marker_width, marker_height;
191 : :
192 [ # # ]: 0 : if (!gtk_widget_should_layout (child))
193 : 0 : continue;
194 : :
195 : 0 : lon = shumate_location_get_longitude (SHUMATE_LOCATION (child));
196 : 0 : lat = shumate_location_get_latitude (SHUMATE_LOCATION (child));
197 : :
198 : 0 : gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, 0, &marker_width, NULL, NULL);
199 : 0 : gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, -1, 0, &marker_height, NULL, NULL);
200 : :
201 : 0 : shumate_viewport_location_to_widget_coords (viewport, widget, lat, lon, &x, &y);
202 : 0 : x = floorf (x - marker_width/2.f);
203 : 0 : y = floorf (y - marker_height/2.f);
204 : :
205 : 0 : allocation.x = x;
206 : 0 : allocation.y = y;
207 : 0 : allocation.width = marker_width;
208 : 0 : allocation.height = marker_height;
209 : :
210 [ # # ]: 0 : within_viewport = x > -allocation.width && x <= width &&
211 [ # # # # : 0 : y > -allocation.height && y <= height &&
# # ]
212 [ # # # # ]: 0 : allocation.width < width && allocation.height < height;
213 : :
214 : 0 : gtk_widget_set_child_visible (child, within_viewport);
215 : :
216 [ # # ]: 0 : if (within_viewport)
217 : 0 : gtk_widget_size_allocate (child, &allocation, -1);
218 : : }
219 : 0 : }
220 : :
221 : : static void
222 : 0 : shumate_marker_layer_get_property (GObject *object,
223 : : guint property_id,
224 : : GValue *value,
225 : : GParamSpec *pspec)
226 : : {
227 : 0 : ShumateMarkerLayer *self = SHUMATE_MARKER_LAYER (object);
228 : :
229 [ # # ]: 0 : switch (property_id)
230 : : {
231 : 0 : case PROP_SELECTION_MODE:
232 : 0 : g_value_set_enum (value, self->mode);
233 : 0 : break;
234 : :
235 : 0 : default:
236 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
237 : : }
238 : 0 : }
239 : :
240 : :
241 : : static void
242 : 0 : shumate_marker_layer_set_property (GObject *object,
243 : : guint property_id,
244 : : const GValue *value,
245 : : GParamSpec *pspec)
246 : : {
247 : 0 : ShumateMarkerLayer *self = SHUMATE_MARKER_LAYER (object);
248 : :
249 [ # # ]: 0 : switch (property_id)
250 : : {
251 : 0 : case PROP_SELECTION_MODE:
252 : 0 : shumate_marker_layer_set_selection_mode (self, g_value_get_enum (value));
253 : 0 : break;
254 : :
255 : 0 : default:
256 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
257 : : }
258 : 0 : }
259 : :
260 : :
261 : : static void
262 : 2 : shumate_marker_layer_dispose (GObject *object)
263 : : {
264 : 2 : ShumateMarkerLayer *self = SHUMATE_MARKER_LAYER (object);
265 : 2 : ShumateViewport *viewport = shumate_layer_get_viewport (SHUMATE_LAYER (self));
266 : 2 : GtkWidget *child;
267 : :
268 : 2 : g_signal_handlers_disconnect_by_data (viewport, self);
269 : :
270 [ + + ]: 6 : while ((child = gtk_widget_get_first_child (GTK_WIDGET (object))))
271 : 4 : gtk_widget_unparent (child);
272 : :
273 : 2 : G_OBJECT_CLASS (shumate_marker_layer_parent_class)->dispose (object);
274 : 2 : }
275 : :
276 : :
277 : : static void
278 : 2 : shumate_marker_layer_finalize (GObject *object)
279 : : {
280 : 2 : ShumateMarkerLayer *self = SHUMATE_MARKER_LAYER (object);
281 : :
282 : 2 : g_list_free (self->selected);
283 : :
284 : 2 : G_OBJECT_CLASS (shumate_marker_layer_parent_class)->finalize (object);
285 : 2 : }
286 : :
287 : : static void
288 : 10 : shumate_marker_layer_constructed (GObject *object)
289 : : {
290 : 10 : ShumateMarkerLayer *self = SHUMATE_MARKER_LAYER (object);
291 : 10 : ShumateViewport *viewport;
292 : :
293 : 10 : G_OBJECT_CLASS (shumate_marker_layer_parent_class)->constructed (object);
294 : :
295 : 10 : viewport = shumate_layer_get_viewport (SHUMATE_LAYER (self));
296 : 10 : g_signal_connect_swapped (viewport, "notify", G_CALLBACK (on_viewport_changed), self);
297 : 10 : }
298 : :
299 : : static char *
300 : 0 : shumate_marker_layer_get_debug_text (ShumateLayer *layer)
301 : : {
302 : 0 : ShumateMarkerLayer *self = SHUMATE_MARKER_LAYER (layer);
303 : 0 : return g_strdup_printf ("markers: %d, %d selected\n", self->n_children, g_list_length (self->selected));
304 : : }
305 : :
306 : : static void
307 : 3 : shumate_marker_layer_class_init (ShumateMarkerLayerClass *klass)
308 : : {
309 : 3 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
310 : 3 : GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
311 : 3 : ShumateLayerClass *layer_class = SHUMATE_LAYER_CLASS (klass);
312 : :
313 : 3 : object_class->dispose = shumate_marker_layer_dispose;
314 : 3 : object_class->finalize = shumate_marker_layer_finalize;
315 : 3 : object_class->get_property = shumate_marker_layer_get_property;
316 : 3 : object_class->set_property = shumate_marker_layer_set_property;
317 : 3 : object_class->constructed = shumate_marker_layer_constructed;
318 : :
319 : 3 : widget_class->size_allocate = shumate_marker_layer_size_allocate;
320 : :
321 : 3 : layer_class->get_debug_text = shumate_marker_layer_get_debug_text;
322 : :
323 : : /**
324 : : * ShumateMarkerLayer:selection-mode:
325 : : *
326 : : * Determines the type of selection that will be performed.
327 : : */
328 : 6 : obj_properties[PROP_SELECTION_MODE] =
329 : 3 : g_param_spec_enum ("selection-mode",
330 : : "Selection Mode",
331 : : "Determines the type of selection that will be performed.",
332 : : GTK_TYPE_SELECTION_MODE,
333 : : GTK_SELECTION_NONE,
334 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
335 : :
336 : 3 : g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties);
337 : :
338 : : /**
339 : : * ShumateMarkerLayer::marker-selected:
340 : : * @self: The marker layer emitting the signal
341 : : * @marker: The marker that was selected
342 : : *
343 : : * Emitted when a marker in the layer is selected.
344 : : */
345 : 6 : signals[MARKER_SELECTED] =
346 : 3 : g_signal_new ("marker-selected",
347 : : G_OBJECT_CLASS_TYPE (object_class),
348 : : G_SIGNAL_RUN_LAST,
349 : : 0, NULL, NULL, NULL,
350 : : G_TYPE_NONE,
351 : : 1, SHUMATE_TYPE_MARKER);
352 : :
353 : : /**
354 : : * ShumateMarkerLayer::marker-unselected:
355 : : * @self: The marker layer emitting the signal
356 : : * @marker: The marker that was unselected
357 : : *
358 : : * Emitted when a marker in the layer is unselected.
359 : : */
360 : 6 : signals[MARKER_UNSELECTED] =
361 : 3 : g_signal_new ("marker-unselected",
362 : : G_OBJECT_CLASS_TYPE (object_class),
363 : : G_SIGNAL_RUN_LAST,
364 : : 0, NULL, NULL, NULL,
365 : : G_TYPE_NONE,
366 : : 1, SHUMATE_TYPE_MARKER);
367 : 3 : }
368 : :
369 : :
370 : : static void
371 : 10 : shumate_marker_layer_init (ShumateMarkerLayer *self)
372 : : {
373 : 10 : GtkGesture *click_gesture;
374 : :
375 : 10 : self->mode = GTK_SELECTION_NONE;
376 : :
377 : 10 : click_gesture = gtk_gesture_click_new ();
378 : 10 : gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (click_gesture));
379 : 10 : g_signal_connect_swapped (click_gesture, "released", G_CALLBACK (on_click_gesture_released), self);
380 : 10 : }
381 : :
382 : : /**
383 : : * shumate_marker_layer_new:
384 : : * @viewport: the @ShumateViewport
385 : : *
386 : : * Creates a new instance of [class@MarkerLayer].
387 : : *
388 : : * Returns: a new [class@MarkerLayer] ready to be used as a container for the markers.
389 : : */
390 : : ShumateMarkerLayer *
391 : 10 : shumate_marker_layer_new (ShumateViewport *viewport)
392 : : {
393 : 10 : return g_object_new (SHUMATE_TYPE_MARKER_LAYER,
394 : : "viewport", viewport,
395 : : NULL);
396 : : }
397 : :
398 : :
399 : : /**
400 : : * shumate_marker_layer_new_full:
401 : : * @viewport: the @ShumateViewport
402 : : * @mode: Selection mode
403 : : *
404 : : * Creates a new instance of [class@MarkerLayer] with the specified selection mode.
405 : : *
406 : : * Returns: a new [class@MarkerLayer] ready to be used as a container for the markers.
407 : : */
408 : : ShumateMarkerLayer *
409 : 0 : shumate_marker_layer_new_full (ShumateViewport *viewport,
410 : : GtkSelectionMode mode)
411 : : {
412 : 0 : return g_object_new (SHUMATE_TYPE_MARKER_LAYER,
413 : : "selection-mode", mode,
414 : : "viewport", viewport,
415 : : NULL);
416 : : }
417 : :
418 : :
419 : : static void
420 : 0 : marker_position_notify (ShumateMarker *marker,
421 : : G_GNUC_UNUSED GParamSpec *pspec,
422 : : ShumateMarkerLayer *layer)
423 : : {
424 : 0 : update_marker_visibility (layer, marker);
425 : 0 : }
426 : :
427 : :
428 : : static void
429 : 0 : marker_move_by_cb (ShumateMarker *marker,
430 : : double dx,
431 : : double dy,
432 : : GdkEvent *event,
433 : : ShumateMarkerLayer *layer)
434 : : {
435 : : /*ShumateMarkerLayerPrivate *priv = shumate_marker_layer_get_instance_private (layer);
436 : : ShumateView *view = self->view;
437 : : double x, y, lat, lon;
438 : :
439 : : x = shumate_view_longitude_to_x (view, shumate_location_get_longitude (SHUMATE_LOCATION (marker)));
440 : : y = shumate_view_latitude_to_y (view, shumate_location_get_latitude (SHUMATE_LOCATION (marker)));
441 : :
442 : : x += dx;
443 : : y += dy;
444 : :
445 : : lon = shumate_view_x_to_longitude (view, x);
446 : : lat = shumate_view_y_to_latitude (view, y);
447 : :
448 : : shumate_location_set_location (SHUMATE_LOCATION (marker), lat, lon);*/
449 : 0 : }
450 : :
451 : :
452 : : /**
453 : : * shumate_marker_layer_add_marker:
454 : : * @self: a [class@MarkerLayer]
455 : : * @marker: a [class@Marker]
456 : : *
457 : : * Adds the marker to the layer.
458 : : */
459 : : void
460 : 208 : shumate_marker_layer_add_marker (ShumateMarkerLayer *self,
461 : : ShumateMarker *marker)
462 : : {
463 [ + - ]: 208 : g_return_if_fail (SHUMATE_IS_MARKER_LAYER (self));
464 [ - + ]: 208 : g_return_if_fail (SHUMATE_IS_MARKER (marker));
465 : :
466 : 208 : g_signal_connect_object (G_OBJECT (marker), "notify::latitude",
467 : : G_CALLBACK (marker_position_notify), self, 0);
468 : 208 : g_signal_connect_object (G_OBJECT (marker), "notify::longitude",
469 : : G_CALLBACK (marker_position_notify), self, 0);
470 : :
471 : : /*g_signal_connect (G_OBJECT (marker), "drag-motion",
472 : : G_CALLBACK (marker_move_by_cb), layer);*/
473 : :
474 : 208 : shumate_marker_set_selected (marker, FALSE);
475 : :
476 : 208 : gtk_widget_insert_before (GTK_WIDGET(marker), GTK_WIDGET (self), NULL);
477 : 208 : update_marker_visibility (self, marker);
478 : 208 : self->n_children++;
479 : : }
480 : :
481 : :
482 : : /**
483 : : * shumate_marker_layer_remove_all:
484 : : * @self: a [class@MarkerLayer]
485 : : *
486 : : * Removes all markers from the layer.
487 : : */
488 : : void
489 : 2 : shumate_marker_layer_remove_all (ShumateMarkerLayer *self)
490 : : {
491 : 2 : GtkWidget *child;
492 : :
493 [ + - ]: 2 : g_return_if_fail (SHUMATE_IS_MARKER_LAYER (self));
494 : :
495 : 2 : child = gtk_widget_get_first_child (GTK_WIDGET (self));
496 [ + + ]: 202 : while (child)
497 : : {
498 : 200 : GtkWidget *next = gtk_widget_get_next_sibling (child);
499 : :
500 : 200 : g_signal_handlers_disconnect_by_data (child, self);
501 : 200 : gtk_widget_unparent (child);
502 : :
503 : 200 : child = next;
504 : : }
505 : :
506 : 2 : self->n_children = 0;
507 : : }
508 : :
509 : :
510 : : /**
511 : : * shumate_marker_layer_get_markers:
512 : : * @self: a [class@MarkerLayer]
513 : : *
514 : : * Gets a copy of the list of all markers inserted into the layer. You should
515 : : * free the list but not its contents.
516 : : *
517 : : * Returns: (transfer container) (element-type ShumateMarker): the list
518 : : */
519 : : GList *
520 : 2 : shumate_marker_layer_get_markers (ShumateMarkerLayer *self)
521 : : {
522 : 2 : GList *list = NULL;
523 : 2 : GtkWidget *child;
524 : :
525 [ + - ]: 2 : g_return_val_if_fail (SHUMATE_IS_MARKER_LAYER (self), NULL);
526 : :
527 : 2 : for (child = gtk_widget_get_last_child (GTK_WIDGET (self));
528 [ + + ]: 6 : child != NULL;
529 : 4 : child = gtk_widget_get_prev_sibling (child))
530 : : {
531 : 4 : ShumateMarker *marker = SHUMATE_MARKER (child);
532 : 4 : list = g_list_prepend (list, marker);
533 : : }
534 : :
535 : : return list;
536 : : }
537 : :
538 : :
539 : : /**
540 : : * shumate_marker_layer_get_selected:
541 : : * @self: a [class@MarkerLayer]
542 : : *
543 : : * Gets a list of selected markers in the layer.
544 : : *
545 : : * Returns: (transfer container) (element-type ShumateMarker): the list
546 : : */
547 : : GList *
548 : 6 : shumate_marker_layer_get_selected (ShumateMarkerLayer *self)
549 : : {
550 [ + - ]: 6 : g_return_val_if_fail (SHUMATE_IS_MARKER_LAYER (self), FALSE);
551 : 6 : return g_list_copy (self->selected);
552 : : }
553 : :
554 : : static void
555 : 20 : update_debug_text (ShumateMarkerLayer *self)
556 : : {
557 [ - + ]: 20 : if (shumate_inspector_settings_get_show_debug_overlay (shumate_inspector_settings_get_default ()))
558 : 0 : gtk_widget_queue_draw (GTK_WIDGET (self));
559 : 20 : }
560 : :
561 : : /**
562 : : * shumate_marker_layer_select_marker:
563 : : * @self: a [class@MarkerLayer]
564 : : * @marker: a [class@Marker] that is a child of @self
565 : : *
566 : : * Selects a marker in this layer.
567 : : *
568 : : * If [class@MarkerLayer]:selection-mode is %GTK_SELECTION_SINGLE or
569 : : * %GTK_SELECTION_BROWSE, all other markers will be unselected. If the mode is
570 : : * %GTK_SELECTION_NONE or @marker is not selectable, nothing will happen.
571 : : *
572 : : * Returns: %TRUE if the marker is now selected, otherwise %FALSE
573 : : */
574 : : gboolean
575 : 14 : shumate_marker_layer_select_marker (ShumateMarkerLayer *self, ShumateMarker *marker)
576 : : {
577 [ + - ]: 14 : g_return_val_if_fail (SHUMATE_IS_MARKER_LAYER (self), FALSE);
578 [ - + ]: 14 : g_return_val_if_fail (SHUMATE_IS_MARKER (marker), FALSE);
579 [ - + ]: 14 : g_return_val_if_fail (gtk_widget_get_parent (GTK_WIDGET (marker)) == GTK_WIDGET (self), FALSE);
580 : :
581 [ + - ]: 14 : if (!shumate_marker_get_selectable (marker)) {
582 : : return FALSE;
583 : : }
584 : :
585 [ - + ]: 14 : if (shumate_marker_is_selected (marker)) {
586 : : return TRUE;
587 : : }
588 : :
589 [ + + - + ]: 14 : switch (self->mode) {
590 : : case GTK_SELECTION_NONE:
591 : : return FALSE;
592 : :
593 : 4 : case GTK_SELECTION_BROWSE:
594 : : case GTK_SELECTION_SINGLE:
595 : 4 : shumate_marker_layer_unselect_all_markers (self);
596 : :
597 : : /* fall through */
598 : 10 : case GTK_SELECTION_MULTIPLE:
599 : 10 : self->selected = g_list_prepend (self->selected, marker);
600 : 10 : shumate_marker_set_selected (marker, TRUE);
601 : 10 : update_debug_text (self);
602 : 10 : g_signal_emit (self, signals[MARKER_SELECTED], 0, marker);
603 : 10 : return TRUE;
604 : :
605 : 0 : default:
606 : 0 : g_assert_not_reached ();
607 : : }
608 : : }
609 : :
610 : :
611 : : /**
612 : : * shumate_marker_layer_unselect_marker:
613 : : * @self: a [class@MarkerLayer]
614 : : * @marker: a [class@Marker] that is a child of @self
615 : : *
616 : : * Unselects a marker in this layer.
617 : : *
618 : : * This works even if [class@MarkerLayer]:selection-mode is
619 : : * %GTK_SELECTION_BROWSE. Browse mode only prevents user interaction, not the
620 : : * program, from unselecting a marker.
621 : : */
622 : : void
623 : 10 : shumate_marker_layer_unselect_marker (ShumateMarkerLayer *self,
624 : : ShumateMarker *marker)
625 : : {
626 [ + - ]: 10 : g_return_if_fail (SHUMATE_IS_MARKER_LAYER (self));
627 [ - + ]: 10 : g_return_if_fail (SHUMATE_IS_MARKER (marker));
628 [ - + ]: 10 : g_return_if_fail (gtk_widget_get_parent (GTK_WIDGET (marker)) == GTK_WIDGET (self));
629 : :
630 [ + - ]: 10 : if (!shumate_marker_is_selected (marker)) {
631 : : return;
632 : : }
633 : :
634 : 10 : self->selected = g_list_remove (self->selected, marker);
635 : 10 : shumate_marker_set_selected (marker, FALSE);
636 : 10 : update_debug_text (self);
637 : 10 : g_signal_emit (self, signals[MARKER_UNSELECTED], 0, marker);
638 : : }
639 : :
640 : :
641 : : /**
642 : : * shumate_marker_layer_remove_marker:
643 : : * @self: a [class@MarkerLayer]
644 : : * @marker: a [class@Marker]
645 : : *
646 : : * Removes the marker from the layer.
647 : : */
648 : : void
649 : 2 : shumate_marker_layer_remove_marker (ShumateMarkerLayer *self,
650 : : ShumateMarker *marker)
651 : : {
652 [ + - ]: 2 : g_return_if_fail (SHUMATE_IS_MARKER_LAYER (self));
653 [ - + ]: 2 : g_return_if_fail (SHUMATE_IS_MARKER (marker));
654 [ - + ]: 2 : g_return_if_fail (gtk_widget_get_parent (GTK_WIDGET (marker)) == GTK_WIDGET (self));
655 : :
656 : 2 : g_signal_handlers_disconnect_by_func (G_OBJECT (marker),
657 : : G_CALLBACK (marker_position_notify), self);
658 : :
659 : 2 : g_signal_handlers_disconnect_by_func (marker,
660 : : G_CALLBACK (marker_move_by_cb), self);
661 : :
662 [ - + ]: 2 : if (shumate_marker_is_selected (marker)) {
663 : 0 : shumate_marker_layer_unselect_marker (self, marker);
664 : : }
665 : :
666 : 2 : gtk_widget_unparent (GTK_WIDGET (marker));
667 : 2 : self->n_children--;
668 : : }
669 : :
670 : :
671 : : /**
672 : : * shumate_marker_layer_unselect_all_markers:
673 : : * @self: a [class@MarkerLayer]
674 : : *
675 : : * Unselects all markers in the layer.
676 : : */
677 : : void
678 : 10 : shumate_marker_layer_unselect_all_markers (ShumateMarkerLayer *self)
679 : : {
680 : 0 : g_autoptr(GList) prev_selected = NULL;
681 : :
682 [ + - ]: 10 : g_return_if_fail (SHUMATE_IS_MARKER_LAYER (self));
683 : :
684 : 10 : prev_selected = g_list_copy (self->selected);
685 : :
686 [ + + ]: 20 : for (GList *l = prev_selected; l != NULL; l = l->next) {
687 : 10 : shumate_marker_layer_unselect_marker (self, SHUMATE_MARKER (l->data));
688 : : }
689 : : }
690 : :
691 : :
692 : : /**
693 : : * shumate_marker_layer_select_all_markers:
694 : : * @self: a [class@MarkerLayer]
695 : : *
696 : : * Selects all selectable markers in the layer.
697 : : */
698 : : void
699 : 2 : shumate_marker_layer_select_all_markers (ShumateMarkerLayer *self)
700 : : {
701 : 0 : g_autoptr(GList) children = NULL;
702 : :
703 [ + - ]: 2 : g_return_if_fail (SHUMATE_IS_MARKER_LAYER (self));
704 : :
705 : 2 : children = shumate_marker_layer_get_markers (self);
706 : :
707 [ + + ]: 6 : for (GList *l = children; l != NULL; l = l->next) {
708 : 4 : shumate_marker_layer_select_marker (self, SHUMATE_MARKER (l->data));
709 : : }
710 : : }
711 : :
712 : :
713 : : /**
714 : : * shumate_marker_layer_set_selection_mode:
715 : : * @self: a [class@MarkerLayer]
716 : : * @mode: a [enum@Gtk.SelectionMode] value
717 : : *
718 : : * Sets the selection mode of the layer.
719 : : *
720 : : * NOTE: changing selection mode to %GTK_SELECTION_NONE, %GTK_SELECTION_SINGLE
721 : : * or %GTK_SELECTION_BROWSE will clear all previously selected markers.
722 : : */
723 : : void
724 : 8 : shumate_marker_layer_set_selection_mode (ShumateMarkerLayer *self,
725 : : GtkSelectionMode mode)
726 : : {
727 [ + - ]: 8 : g_return_if_fail (SHUMATE_IS_MARKER_LAYER (self));
728 : :
729 [ + - ]: 8 : if (self->mode == mode)
730 : : return;
731 : :
732 : 8 : self->mode = mode;
733 : :
734 [ + + ]: 8 : if (mode != GTK_SELECTION_MULTIPLE)
735 : 4 : shumate_marker_layer_unselect_all_markers (self);
736 : :
737 : 8 : g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_SELECTION_MODE]);
738 : : }
739 : :
740 : :
741 : : /**
742 : : * shumate_marker_layer_get_selection_mode:
743 : : * @self: a [class@MarkerLayer]
744 : : *
745 : : * Gets the selection mode of the layer.
746 : : *
747 : : * Returns: the selection mode of the layer.
748 : : */
749 : : GtkSelectionMode
750 : 2 : shumate_marker_layer_get_selection_mode (ShumateMarkerLayer *self)
751 : : {
752 [ + - ]: 2 : g_return_val_if_fail (SHUMATE_IS_MARKER_LAYER (self), GTK_SELECTION_NONE);
753 : :
754 : 2 : return self->mode;
755 : : }
|