Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2008 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 : : * ShumateMarker:
23 : : *
24 : : * Markers represent points of interest on a map. Markers need to be
25 : : * placed on a layer (a [class@MarkerLayer]). Layers have to be added to a
26 : : * [class@Map] for the markers to show on the map.
27 : : *
28 : : * A marker is nothing more than a regular [class@Gtk.Widget]. You can draw on
29 : : * it what ever you want. Set the marker's position on the map using
30 : : * [method@Location.set_location].
31 : : *
32 : : * This is a base class of all markers. A typical usage of a marker is for
33 : : * instance to add a [class@Gtk.Image] with a pin image and add the
34 : : * [class@Gtk.GestureClick] controller to listen to click events and show
35 : : * a [class@Gtk.Popover] with the description of the marker.
36 : : */
37 : :
38 : : #include "shumate-marker.h"
39 : : #include "shumate-marker-private.h"
40 : :
41 : : #include "shumate.h"
42 : : #include "shumate-marshal.h"
43 : : #include "shumate-tile.h"
44 : :
45 : : #include <glib.h>
46 : : #include <glib-object.h>
47 : : #include <gtk/gtk.h>
48 : :
49 : : enum
50 : : {
51 : : PROP_SELECTABLE = 1,
52 : : PROP_CHILD,
53 : : N_PROPERTIES,
54 : :
55 : : PROP_LONGITUDE,
56 : : PROP_LATITUDE,
57 : : };
58 : :
59 : : static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
60 : :
61 : : typedef struct
62 : : {
63 : : double lon;
64 : : double lat;
65 : :
66 : : gboolean selected;
67 : :
68 : : gboolean selectable;
69 : :
70 : : float click_x;
71 : : float click_y;
72 : : gboolean moved;
73 : :
74 : : GtkWidget *child;
75 : : } ShumateMarkerPrivate;
76 : :
77 : : static void location_interface_init (ShumateLocationInterface *iface);
78 : : static void buildable_interface_init (GtkBuildableIface *iface);
79 : :
80 [ + + + - ]: 1246 : G_DEFINE_TYPE_WITH_CODE (ShumateMarker, shumate_marker, GTK_TYPE_WIDGET,
81 : : G_ADD_PRIVATE (ShumateMarker)
82 : : G_IMPLEMENT_INTERFACE (SHUMATE_TYPE_LOCATION, location_interface_init)
83 : : G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_interface_init));
84 : :
85 : : static GtkBuildableIface *parent_buildable_iface;
86 : :
87 : : static void
88 : 0 : shumate_marker_set_location (ShumateLocation *location,
89 : : double latitude,
90 : : double longitude)
91 : : {
92 : 0 : ShumateMarker *marker = (ShumateMarker *) location;
93 : 0 : ShumateMarkerPrivate *priv = shumate_marker_get_instance_private (marker);
94 : :
95 [ # # ]: 0 : g_assert (SHUMATE_IS_MARKER (location));
96 : :
97 [ # # # # ]: 0 : priv->lon = CLAMP (longitude, SHUMATE_MIN_LONGITUDE, SHUMATE_MAX_LONGITUDE);
98 [ # # # # ]: 0 : priv->lat = CLAMP (latitude, SHUMATE_MIN_LATITUDE, SHUMATE_MAX_LATITUDE);
99 : :
100 : 0 : g_object_notify (G_OBJECT (location), "latitude");
101 : 0 : g_object_notify (G_OBJECT (location), "longitude");
102 : 0 : }
103 : :
104 : :
105 : : static double
106 : 0 : shumate_marker_get_latitude (ShumateLocation *location)
107 : : {
108 : 0 : ShumateMarker *marker = (ShumateMarker *) location;
109 : 0 : ShumateMarkerPrivate *priv = shumate_marker_get_instance_private (marker);
110 : :
111 [ # # ]: 0 : g_assert (SHUMATE_IS_MARKER (location));
112 : :
113 : 0 : return priv->lat;
114 : : }
115 : :
116 : :
117 : : static double
118 : 0 : shumate_marker_get_longitude (ShumateLocation *location)
119 : : {
120 : 0 : ShumateMarker *marker = (ShumateMarker *) location;
121 : 0 : ShumateMarkerPrivate *priv = shumate_marker_get_instance_private (marker);
122 : :
123 [ # # ]: 0 : g_assert (SHUMATE_IS_MARKER (location));
124 : :
125 : 0 : return priv->lon;
126 : : }
127 : :
128 : : static void
129 : 0 : shumate_marker_add_child (GtkBuildable *buildable,
130 : : GtkBuilder *builder,
131 : : GObject *child,
132 : : const char *type)
133 : : {
134 [ # # # # : 0 : if (GTK_IS_WIDGET (child))
# # # # ]
135 : 0 : shumate_marker_set_child (SHUMATE_MARKER (buildable), GTK_WIDGET (child));
136 : : else
137 : 0 : parent_buildable_iface->add_child (buildable, builder, child, type);
138 : 0 : }
139 : :
140 : : static void
141 : 0 : shumate_marker_get_property (GObject *object,
142 : : guint prop_id,
143 : : GValue *value,
144 : : GParamSpec *pspec)
145 : : {
146 : 0 : ShumateMarker *marker = SHUMATE_MARKER (object);
147 : 0 : ShumateMarkerPrivate *priv = shumate_marker_get_instance_private (marker);
148 : :
149 [ # # # # : 0 : switch (prop_id)
# ]
150 : : {
151 : 0 : case PROP_LONGITUDE:
152 : 0 : g_value_set_double (value, priv->lon);
153 : 0 : break;
154 : :
155 : 0 : case PROP_LATITUDE:
156 : 0 : g_value_set_double (value, priv->lat);
157 : 0 : break;
158 : :
159 : 0 : case PROP_SELECTABLE:
160 : 0 : g_value_set_boolean (value, priv->selectable);
161 : 0 : break;
162 : :
163 : 0 : case PROP_CHILD:
164 : 0 : g_value_set_object (value, priv->child);
165 : 0 : break;
166 : :
167 : 0 : default:
168 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
169 : : }
170 : 0 : }
171 : :
172 : :
173 : : static void
174 : 0 : shumate_marker_set_property (GObject *object,
175 : : guint prop_id,
176 : : const GValue *value,
177 : : GParamSpec *pspec)
178 : : {
179 : 0 : ShumateMarker *marker = SHUMATE_MARKER (object);
180 : 0 : ShumateMarkerPrivate *priv = shumate_marker_get_instance_private (marker);
181 : :
182 [ # # # # : 0 : switch (prop_id)
# ]
183 : : {
184 : 0 : case PROP_LONGITUDE:
185 : : {
186 : 0 : double lon = g_value_get_double (value);
187 : 0 : shumate_marker_set_location (SHUMATE_LOCATION (marker), priv->lat, lon);
188 : 0 : break;
189 : : }
190 : :
191 : 0 : case PROP_LATITUDE:
192 : : {
193 : 0 : double lat = g_value_get_double (value);
194 : 0 : shumate_marker_set_location (SHUMATE_LOCATION (marker), lat, priv->lon);
195 : 0 : break;
196 : : }
197 : :
198 : 0 : case PROP_SELECTABLE:
199 : : {
200 : 0 : gboolean bvalue = g_value_get_boolean (value);
201 : 0 : shumate_marker_set_selectable (marker, bvalue);
202 : 0 : break;
203 : : }
204 : :
205 : 0 : case PROP_CHILD:
206 : : {
207 : 0 : GtkWidget *child = g_value_get_object (value);
208 : 0 : shumate_marker_set_child (marker, child);
209 : 0 : break;
210 : : }
211 : :
212 : 0 : default:
213 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
214 : : }
215 : 0 : }
216 : :
217 : : static void
218 : 206 : shumate_marker_dispose (GObject *object)
219 : : {
220 : 206 : ShumateMarker *marker = SHUMATE_MARKER (object);
221 : :
222 : 206 : shumate_marker_set_child (marker, NULL);
223 : :
224 : 206 : G_OBJECT_CLASS (shumate_marker_parent_class)->dispose (object);
225 : 206 : }
226 : :
227 : : static void
228 : 5 : shumate_marker_class_init (ShumateMarkerClass *klass)
229 : : {
230 : 5 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
231 : 5 : GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
232 : :
233 : 5 : object_class->get_property = shumate_marker_get_property;
234 : 5 : object_class->set_property = shumate_marker_set_property;
235 : 5 : object_class->dispose = shumate_marker_dispose;
236 : :
237 : : /**
238 : : * ShumateMarker:child:
239 : : *
240 : : * The child widget of the marker
241 : : */
242 : 10 : obj_properties[PROP_CHILD] =
243 : 5 : g_param_spec_object ("child",
244 : : "Child",
245 : : "The child widget of the marker",
246 : : GTK_TYPE_WIDGET,
247 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
248 : :
249 : : /**
250 : : * ShumateMarker:selectable:
251 : : *
252 : : * The selectable state of the marker
253 : : */
254 : 10 : obj_properties[PROP_SELECTABLE] =
255 : 5 : g_param_spec_boolean ("selectable",
256 : : "Selectable",
257 : : "The draggable state of the marker",
258 : : FALSE,
259 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
260 : :
261 : 5 : g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties);
262 : :
263 : 5 : g_object_class_override_property (object_class,
264 : : PROP_LONGITUDE,
265 : : "longitude");
266 : :
267 : 5 : g_object_class_override_property (object_class,
268 : : PROP_LATITUDE,
269 : : "latitude");
270 : :
271 : 5 : gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
272 : 5 : gtk_widget_class_set_css_name (widget_class, "map-marker");
273 : 5 : }
274 : :
275 : : static void
276 : 210 : shumate_marker_init (ShumateMarker *self)
277 : : {
278 : 210 : ShumateMarkerPrivate *priv = shumate_marker_get_instance_private (self);
279 : :
280 : 210 : priv->lat = 0;
281 : 210 : priv->lon = 0;
282 : 210 : priv->selected = FALSE;
283 : 210 : priv->selectable = TRUE;
284 : 210 : }
285 : :
286 : : static void
287 : 5 : location_interface_init (ShumateLocationInterface *iface)
288 : : {
289 : 5 : iface->get_latitude = shumate_marker_get_latitude;
290 : 5 : iface->get_longitude = shumate_marker_get_longitude;
291 : 5 : iface->set_location = shumate_marker_set_location;
292 : 5 : }
293 : :
294 : : static void
295 : 5 : buildable_interface_init (GtkBuildableIface *iface)
296 : : {
297 : 5 : parent_buildable_iface = g_type_interface_peek_parent (iface);
298 : 5 : iface->add_child = shumate_marker_add_child;
299 : 5 : }
300 : :
301 : : /**
302 : : * shumate_marker_new:
303 : : *
304 : : * Creates an instance of #ShumateMarker.
305 : : *
306 : : * Returns: a new #ShumateMarker.
307 : : */
308 : : ShumateMarker *
309 : 2 : shumate_marker_new (void)
310 : : {
311 : 2 : return SHUMATE_MARKER (g_object_new (SHUMATE_TYPE_MARKER, NULL));
312 : : }
313 : :
314 : : /**
315 : : * shumate_marker_is_selected:
316 : : * @marker: a #ShumateMarker
317 : : *
318 : : * Checks whether the marker is selected.
319 : : *
320 : : * Returns: %TRUE if the marker is selected, otherwise %FALSE
321 : : */
322 : : gboolean
323 : 50 : shumate_marker_is_selected (ShumateMarker *marker)
324 : : {
325 : 50 : ShumateMarkerPrivate *priv = shumate_marker_get_instance_private (marker);
326 : :
327 [ + - ]: 50 : g_return_val_if_fail (SHUMATE_IS_MARKER (marker), FALSE);
328 : :
329 : 50 : return priv->selected;
330 : : }
331 : :
332 : :
333 : : /**
334 : : * shumate_marker_set_selectable:
335 : : * @marker: a #ShumateMarker
336 : : * @value: the selectable state
337 : : *
338 : : * Sets the marker as selectable or not.
339 : : */
340 : : void
341 : 0 : shumate_marker_set_selectable (ShumateMarker *marker,
342 : : gboolean value)
343 : : {
344 : 0 : ShumateMarkerPrivate *priv = shumate_marker_get_instance_private (marker);
345 : :
346 [ # # ]: 0 : g_return_if_fail (SHUMATE_IS_MARKER (marker));
347 : :
348 : 0 : priv->selectable = value;
349 : :
350 : 0 : g_object_notify_by_pspec (G_OBJECT (marker), obj_properties[PROP_SELECTABLE]);
351 : : }
352 : :
353 : :
354 : : /**
355 : : * shumate_marker_get_selectable:
356 : : * @marker: a #ShumateMarker
357 : : *
358 : : * Checks whether the marker is selectable.
359 : : *
360 : : * Returns: the selectable or not state of the marker.
361 : : */
362 : : gboolean
363 : 16 : shumate_marker_get_selectable (ShumateMarker *marker)
364 : : {
365 : 16 : ShumateMarkerPrivate *priv = shumate_marker_get_instance_private (marker);
366 : :
367 [ + - ]: 16 : g_return_val_if_fail (SHUMATE_IS_MARKER (marker), FALSE);
368 : :
369 : 16 : return priv->selectable;
370 : : }
371 : :
372 : : /**
373 : : * shumate_marker_get_child:
374 : : * @marker: a #ShumateMarker
375 : : *
376 : : * Retrieves the current child of @marker.
377 : : *
378 : : * Returns: (transfer none) (nullable): a #GtkWidget.
379 : : */
380 : : GtkWidget *
381 : 0 : shumate_marker_get_child (ShumateMarker *marker)
382 : : {
383 : 0 : ShumateMarkerPrivate *priv = shumate_marker_get_instance_private (marker);
384 : :
385 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_MARKER (marker), NULL);
386 : :
387 : 0 : return priv->child;
388 : : }
389 : :
390 : : /**
391 : : * shumate_marker_set_child:
392 : : * @marker: a #ShumateMarker
393 : : * @child: (nullable): a #GtkWidget
394 : : *
395 : : * Sets the child widget of @marker.
396 : : */
397 : : void
398 : 210 : shumate_marker_set_child (ShumateMarker *marker,
399 : : GtkWidget *child)
400 : : {
401 : 210 : ShumateMarkerPrivate *priv = shumate_marker_get_instance_private (marker);
402 : :
403 [ + - ]: 210 : g_return_if_fail (SHUMATE_IS_MARKER (marker));
404 : :
405 [ + + ]: 210 : if (priv->child == child)
406 : : return;
407 : :
408 [ + + ]: 4 : g_clear_pointer (&priv->child, gtk_widget_unparent);
409 : :
410 : 4 : priv->child = child;
411 : :
412 [ + + ]: 4 : if (priv->child)
413 : 2 : gtk_widget_set_parent (priv->child, GTK_WIDGET (marker));
414 : :
415 : 4 : g_object_notify_by_pspec (G_OBJECT (marker), obj_properties[PROP_CHILD]);
416 : : }
417 : :
418 : : /**
419 : : * PRIVATE:shumate_marker_set_selected:
420 : : * @marker: a #ShumateMarker
421 : : * @value: %TRUE to select the marker, %FALSE to unselect it
422 : : *
423 : : * Sets the selected state flag of the marker widget.
424 : : */
425 : : void
426 : 228 : shumate_marker_set_selected (ShumateMarker *marker, gboolean value)
427 : : {
428 : 228 : ShumateMarkerPrivate *priv = shumate_marker_get_instance_private (marker);
429 : :
430 [ + + ]: 228 : if (priv->selected == value)
431 : : return;
432 : :
433 : 20 : priv->selected = value;
434 : :
435 [ + + ]: 20 : if (value) {
436 : 10 : gtk_widget_set_state_flags (GTK_WIDGET (marker),
437 : : GTK_STATE_FLAG_SELECTED, FALSE);
438 : : } else {
439 : 10 : gtk_widget_unset_state_flags (GTK_WIDGET (marker),
440 : : GTK_STATE_FLAG_SELECTED);
441 : : }
442 : : }
|