Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c8929a3
examples: rename DummyLayer gdkdrawable leftover
johnny-bit Aug 22, 2026
868e22d
examples: DummyLayer paint overlay in do_draw
johnny-bit Aug 22, 2026
ce881ca
examples: use MapPoint.new_degrees in DummyLayer
johnny-bit Aug 22, 2026
d5abcba
examples: start mapviewer.py at Home
johnny-bit Aug 22, 2026
28f4def
docs: layer_draw gets widget cairo_t
johnny-bit Aug 22, 2026
c611bdd
examples: Python right-double uses track_add
johnny-bit Aug 22, 2026
0e631f3
test: MapLayer.do_draw gets widget cairo_t
johnny-bit Aug 22, 2026
3516601
examples: polygon.c points via new_degrees
johnny-bit Aug 22, 2026
d983253
examples: editable_track.c uses new_degrees
johnny-bit Aug 22, 2026
287fe04
examples: stop printing osmgpsmap.__file__
johnny-bit Aug 22, 2026
0aa0c28
examples: image_add from cairo pixbuf
johnny-bit Aug 22, 2026
e0269df
docs: README how to draw on the map
johnny-bit Aug 22, 2026
806d840
test: GI convert_screen_to_geographic arity
johnny-bit Aug 23, 2026
c85baf2
examples: fix tooltip convert_screen_to_geographic
johnny-bit Aug 23, 2026
0a844a9
examples: C triple-right recreates click track
johnny-bit Aug 23, 2026
165c02a
examples: ignore button masks on double-click
johnny-bit Aug 23, 2026
437a930
examples: disable auto-center in mapviewers
johnny-bit Aug 23, 2026
ac58f06
examples: poi.png or cairo star for markers
johnny-bit Aug 23, 2026
d302aec
docs: README drawing how-to from examples/
johnny-bit Aug 23, 2026
da7b1fe
docs: fix typos in examples and layer header
johnny-bit Aug 24, 2026
57837b2
examples: set mapviewer.py user-agent
johnny-bit Aug 25, 2026
0e9bf62
examples: sync C Home with Python Timaru
johnny-bit Aug 25, 2026
1f78e76
examples: NULL g_last_image after remove
johnny-bit Aug 25, 2026
121fe6c
examples: rename DummyLayer to DrawLayer
johnny-bit Aug 27, 2026
c582a58
examples: add DrawLayer to mapviewer.c
johnny-bit Aug 28, 2026
0d87936
examples: fix Load Map URI dropping layers
johnny-bit Aug 28, 2026
0bf6691
examples: cairo star if poi.png missing
johnny-bit Aug 29, 2026
1623853
examples: draw fallback star with cairo_rotate, not sin/cos
johnny-bit Aug 29, 2026
89cef3f
ci: add python3-gi-cairo for layer draw
johnny-bit Aug 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
libgirepository1.0-dev \
python3-gi \
python3-cairo \
python3-gi-cairo \
gir1.2-gtk-3.0 \
gir1.2-gdkpixbuf-2.0 \
xvfb
Expand Down
2 changes: 1 addition & 1 deletion examples/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,5 @@ editable_track_LDADD = \
$(top_builddir)/src/libosmgpsmap-1.0.la

## Misc
EXTRA_DIST = poi.png mapviewer.ui mapviewer.js README
EXTRA_DIST = poi.png mapviewer.ui mapviewer.py mapviewer.js README

42 changes: 32 additions & 10 deletions examples/README
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
osm-gps-map example applications

Run C and Python demos from this directory (examples) so they find mapviewer.ui
and poi.png.

If running uninstalled, you probably need to tell GObject introspection where
to find the bindings. Do the following from the example directory:

export LD_LIBRARY_PATH=../src/.libs/
export GI_TYPELIB_PATH=../src/

* ./mapviewer
C based demo app with many options. See '--help' for a list. Note, this
must be executed from the examples directory so it can find the mapviewer.ui
file.
C based demo app with many options. See '--help' for a list of options.
--editable-tracks makes the right-click track draggable.
* ./polygon
This example demonstrates editable polygons. Vertex points can be dragged.
This example demonstrates editable polygons. Vertices can be dragged.
Clicking mid-points divides the line and creates another vertex.
* ./editable_track
One editable track. Same degree constructor as polygon.
* ./mapviewer.py
Python version of the C demo app, with examples showing how to do custom
layers.
layers: DrawLayer class for cairo overlay, GPS, programmatic image_add,
and track_add.
* ./mapviewer.js
Javascript example using seed + gobject-introspection. If running uninstalled,
you probbably need to tell GObject introspection where to find the
bindings. Do the following from the example directory
# export LD_LIBRARY_PATH=../src/.libs/
# export GI_TYPELIB_PATH=../src/
Javascript example using seed + gobject-introspection.

Examples for drawing on the map:

* Double-left-click places a GPS point (blue ball+random heading).
* Double-right-click (or Ctrl+double-left) adds points to tracks.
Triple right click clears the track (a new empty track stays on the map).
This shows the use of track_add, add_point and track_remove
* Double-middle-click (or Shift+double-left) adds a marker via image_add.
Python: poi.png by default, or uncheck "Use poi.png for markers" to
paint a cairo star (programmatic pixbuf). C: poi.png, or a cairo star
if that file is missing. Triple middle click removes the last image.
* DrawLayer in mapviewer and mapviewer.py uses live cairo to draw a red house
at Home location (Timaru). Peak of the roof is at the lat/lon of
Home location.
4 changes: 2 additions & 2 deletions examples/editable_track.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ main (int argc,
OsmGpsMapTrack* track = osm_gps_map_track_new();

OsmGpsMapPoint* p1, *p2;
p1 = osm_gps_map_point_new_radians(1.25663706, -0.488692191);
p2 = osm_gps_map_point_new_radians(1.06465084, -0.750491578);
p1 = osm_gps_map_point_new_degrees(72.0, -28.0);
p2 = osm_gps_map_point_new_degrees(61.0, -43.0);

osm_gps_map_track_add_point(track, p1);
osm_gps_map_track_add_point(track, p2);
Expand Down
177 changes: 158 additions & 19 deletions examples/mapviewer.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
*/

#include <stdlib.h>
#include <math.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <cairo.h>

#include "osm-gps-map.h"

Expand Down Expand Up @@ -50,18 +50,141 @@ static GOptionEntry debug_entries[] =
};
#endif

/* Shared with mapviewer.py DrawLayer Home (Timaru). */
#define HOME_LAT -44.39
#define HOME_LON 171.25
#define HOME_ZOOM 12

typedef struct _DrawLayer {
GObject parent;
} DrawLayer;

typedef struct _DrawLayerClass {
GObjectClass parent_class;
} DrawLayerClass;

static void draw_layer_interface_init (OsmGpsMapLayerIface *iface);

G_DEFINE_TYPE_WITH_CODE (DrawLayer, draw_layer, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (OSM_TYPE_GPS_MAP_LAYER,
draw_layer_interface_init));

static void
draw_layer_draw (OsmGpsMapLayer *layer G_GNUC_UNUSED,
OsmGpsMap *map, cairo_t *cr)
{
OsmGpsMapPoint *pt;
gint x, y;

pt = osm_gps_map_point_new_degrees (HOME_LAT, HOME_LON);
osm_gps_map_convert_geographic_to_screen (map, pt, &x, &y);
osm_gps_map_point_free (pt);

cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.6);
cairo_move_to (cr, x, y);
cairo_line_to (cr, x + 12, y + 10);
cairo_line_to (cr, x + 12, y + 24);
cairo_line_to (cr, x - 12, y + 24);
cairo_line_to (cr, x - 12, y + 10);
cairo_close_path (cr);
cairo_fill (cr);
}

static void
draw_layer_render (OsmGpsMapLayer *layer G_GNUC_UNUSED,
OsmGpsMap *map G_GNUC_UNUSED)
{
}

static gboolean
draw_layer_busy (OsmGpsMapLayer *layer G_GNUC_UNUSED)
{
return FALSE;
}

static gboolean
draw_layer_button_press (OsmGpsMapLayer *layer G_GNUC_UNUSED,
OsmGpsMap *map G_GNUC_UNUSED,
GdkEventButton *event G_GNUC_UNUSED)
{
return FALSE;
}

static void
draw_layer_interface_init (OsmGpsMapLayerIface *iface)
{
iface->render = draw_layer_render;
iface->draw = draw_layer_draw;
iface->busy = draw_layer_busy;
iface->button_press = draw_layer_button_press;
}

static void
draw_layer_class_init (DrawLayerClass *klass G_GNUC_UNUSED)
{
}

static void
draw_layer_init (DrawLayer *self G_GNUC_UNUSED)
{
}

static GdkPixbuf *g_star_image = NULL;
static OsmGpsMapImage *g_last_image = NULL;
static OsmGpsMapTrack *g_click_track = NULL;

/* Programmatic marker if poi.png is missing. Live cairo overlay is DrawLayer. */
static GdkPixbuf *
star_pixbuf_new (int size)
{
cairo_surface_t *surface;
cairo_t *cr;
GdkPixbuf *pixbuf;
int i;
double outer = size / 2.0 - 1.0;
double inner = size / 5.0;

surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, size, size);
cr = cairo_create (surface);

cairo_translate (cr, size / 2.0, size / 2.0);
cairo_move_to (cr, 0, -outer);
for (i = 1; i < 10; i++) {
cairo_rotate (cr, G_PI / 5.0);
cairo_line_to (cr, 0, (i % 2 == 0) ? -outer : -inner);
}
cairo_close_path (cr);
cairo_set_source_rgb (cr, 1.0, 0.85, 0.0);
cairo_fill_preserve (cr);
cairo_set_source_rgb (cr, 0.75, 0.45, 0.0);
cairo_set_line_width (cr, 1);
cairo_stroke (cr);

pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, size, size);
cairo_destroy (cr);
cairo_surface_destroy (surface);
return pixbuf;
}

static OsmGpsMapTrack *
click_track_new (void)
{
OsmGpsMapTrack *track = osm_gps_map_track_new ();
if (opt_editable_tracks)
g_object_set (track, "editable", TRUE, NULL);
return track;
}

static gboolean
on_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
on_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data G_GNUC_UNUSED)
{
OsmGpsMapPoint coord;
float lat, lon;
OsmGpsMap *map = OSM_GPS_MAP(widget);
OsmGpsMapTrack *othertrack = OSM_GPS_MAP_TRACK(user_data);
/* 2BUTTON_PRESS often has BUTTONn_MASK set; ignore those, keep Shift/Ctrl. */
GdkModifierType mods = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK);

int left_button = (event->button == 1) && (event->state == 0);
int left_button = (event->button == 1) && (mods == 0);
int middle_button = (event->button == 2) || ((event->button == 1) && (event->state & GDK_SHIFT_MASK));
int right_button = (event->button == 3) || ((event->button == 1) && (event->state & GDK_CONTROL_MASK));

Expand All @@ -70,11 +193,16 @@ on_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_d

if (event->type == GDK_3BUTTON_PRESS) {
if (middle_button) {
if (g_last_image)
if (g_last_image) {
osm_gps_map_image_remove (map, g_last_image);
g_last_image = NULL;
}
}
if (right_button) {
osm_gps_map_track_remove(map, othertrack);
osm_gps_map_track_remove (map, g_click_track);
g_object_unref (g_click_track);
g_click_track = click_track_new ();
osm_gps_map_track_add (map, g_click_track);
}
} else if (event->type == GDK_2BUTTON_PRESS) {
if (left_button) {
Expand All @@ -83,14 +211,14 @@ on_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_d
lon,
g_random_double_range(0,360));
}
if (middle_button) {
if (middle_button && g_star_image) {
g_last_image = osm_gps_map_image_add (map,
lat,
lon,
g_star_image);
}
if (right_button) {
osm_gps_map_track_add_point(othertrack, &coord);
osm_gps_map_track_add_point(g_click_track, &coord);
}
}

Expand All @@ -105,7 +233,7 @@ on_map_changed_event (GtkWidget *widget, gpointer user_data)
OsmGpsMap *map = OSM_GPS_MAP(widget);

g_object_get(map, "latitude", &lat, "longitude", &lon, NULL);
gchar *msg = g_strdup_printf("Map Centre: lattitude %f longitude %f",lat,lon);
gchar *msg = g_strdup_printf("Map Centre: latitude %f longitude %f",lat,lon);
gtk_entry_set_text(entry, msg);
g_free(msg);

Expand Down Expand Up @@ -136,7 +264,7 @@ static gboolean
on_home_clicked_event (GtkWidget *widget, gpointer user_data)
{
OsmGpsMap *map = OSM_GPS_MAP(user_data);
osm_gps_map_set_center_and_zoom(map, -43.5326,172.6362,12);
osm_gps_map_set_center_and_zoom(map, HOME_LAT, HOME_LON, HOME_ZOOM);
return FALSE;
}

Expand Down Expand Up @@ -246,8 +374,7 @@ main (int argc, char **argv)
GtkWidget *widget;
GtkAccelGroup *ag;
OsmGpsMap *map;
OsmGpsMapLayer *osd;
OsmGpsMapTrack *rightclicktrack;
OsmGpsMapLayer *osd, *draw;
const char *repo_uri;
char *cachedir, *cachebasedir;
GError *error = NULL;
Expand Down Expand Up @@ -318,12 +445,16 @@ main (int argc, char **argv)
osm_gps_map_layer_add(OSM_GPS_MAP(map), osd);
g_object_unref(G_OBJECT(osd));

//Add a second track for right clicks
rightclicktrack = osm_gps_map_track_new();
draw = g_object_new (draw_layer_get_type (), NULL);
osm_gps_map_layer_add (OSM_GPS_MAP (map), draw);
g_object_unref (draw);

/* Stay put on gps_add so the blue blob is not under the OSD crosshair. */
g_object_set (map, "auto-center", FALSE, NULL);

if(opt_editable_tracks)
g_object_set(rightclicktrack, "editable", TRUE, NULL);
osm_gps_map_track_add(OSM_GPS_MAP(map), rightclicktrack);
g_click_track = click_track_new ();
osm_gps_map_track_add (OSM_GPS_MAP (map), g_click_track);
osm_gps_map_set_center_and_zoom (map, HOME_LAT, HOME_LON, HOME_ZOOM);

g_free(cachedir);
g_free(cachebasedir);
Expand All @@ -336,7 +467,15 @@ main (int argc, char **argv)
osm_gps_map_set_keyboard_shortcut(map, OSM_GPS_MAP_KEY_RIGHT, GDK_KEY_Right);

//Build the UI
g_star_image = gdk_pixbuf_new_from_file_at_size ("poi.png", 24,24,NULL);
{
GError *pixbuf_err = NULL;
g_star_image = gdk_pixbuf_new_from_file_at_size ("poi.png", 24, 24, &pixbuf_err);
if (!g_star_image) {
g_printerr ("poi.png: %s\n", pixbuf_err ? pixbuf_err->message : "missing");
g_clear_error (&pixbuf_err);
g_star_image = star_pixbuf_new (24);
}
}

builder = gtk_builder_new();
gtk_builder_add_from_file (builder, "mapviewer.ui", &error);
Expand Down Expand Up @@ -404,7 +543,7 @@ main (int argc, char **argv)
gtk_builder_get_object(builder, "star_yalign_adjustment"), "value-changed",
G_CALLBACK (on_star_align_changed), (gpointer) "y-align");
g_signal_connect (G_OBJECT (map), "button-press-event",
G_CALLBACK (on_button_press_event), (gpointer) rightclicktrack);
G_CALLBACK (on_button_press_event), NULL);
g_signal_connect (G_OBJECT (map), "changed",
G_CALLBACK (on_map_changed_event),
(gpointer) gtk_builder_get_object(builder, "text_entry"));
Expand Down
2 changes: 1 addition & 1 deletion examples/mapviewer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/seed

// You probbably need to tell GObject introspection where to find the bindings
// You probably need to tell GObject introspection where to find the bindings
// export LD_LIBRARY_PATH=../src/.libs/
// export GI_TYPELIB_PATH=../src/

Expand Down
Loading