]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrwlayer.c
Allow uploading a single track via the GPS layer interface.
[andy/viking.git] / src / viktrwlayer.c
index 4a05cc186906ea5ee9bca07acc02f5339ee53921..60082ce5a07af410a56a01dab2374a4dfcfdc463 100644 (file)
@@ -80,7 +80,14 @@ static gboolean return_true (gpointer a, gpointer b, gpointer c) { return TRUE;
 static g_hash_table_remove_all (GHashTable *ght) { g_hash_table_foreach_remove ( ght, (GHRFunc) return_true, FALSE ); }
 #endif
 
+#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
+// This is currently broken as Google have disabled the KML output in Google Maps API v3
+// It has been ifdefed out in the hope that Route Finding functionality will be restored one day...
+// Only have 'JSON' and 'XML' see:
+// https://developers.google.com/maps/documentation/directions/#DirectionsResponses
 #define GOOGLE_DIRECTIONS_STRING "maps.google.com/maps?q=from:%s,%s+to:%s,%s&output=kml"
+#endif
+
 #define VIK_TRW_LAYER_TRACK_GC 16
 #define VIK_TRW_LAYER_TRACK_GC_RATES 10
 #define VIK_TRW_LAYER_TRACK_GC_MIN 0
@@ -135,6 +142,9 @@ struct _VikTrwLayer {
   gdouble track_draw_speed_factor;
   GArray *track_gc;
   GdkGC *current_track_gc;
+  // Separate GC for a track's potential new point as drawn via separate method
+  //  (compared to the actual track points drawn in the main trw_layer_draw_track function)
+  GdkGC *current_track_newpoint_gc;
   GdkGC *track_bg_gc;
   GdkGC *waypoint_gc;
   GdkGC *waypoint_text_gc;
@@ -142,8 +152,8 @@ struct _VikTrwLayer {
   GdkFont *waypoint_font;
   VikTrack *current_track;
   guint16 ct_x1, ct_y1, ct_x2, ct_y2;
-  gboolean ct_sync_done;
-
+  gboolean draw_sync_done;
+  gboolean draw_sync_do;
 
   VikCoordMode coord_mode;
 
@@ -231,6 +241,7 @@ static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] );
 static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] );
 static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] );
 static void trw_layer_goto_track_center ( gpointer pass_along[6] );
+static void trw_layer_merge_by_segment ( gpointer pass_along[6] );
 static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] );
 static void trw_layer_merge_with_other ( gpointer pass_along[6] );
 static void trw_layer_append_track ( gpointer pass_along[6] );
@@ -305,12 +316,14 @@ static gboolean tool_begin_track_click ( VikTrwLayer *vtl, GdkEventButton *event
 static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp);
 static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); 
 static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp ); 
+static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
 static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp ); 
 static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp);
 static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
+#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
 static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp);
 static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
-
+#endif
 
 static void cached_pixbuf_free ( CachedPixbuf *cp );
 static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name );
@@ -335,36 +348,54 @@ static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_na
 static VikToolInterface trw_layer_tools[] = {
   { { "CreateWaypoint", "vik-icon-Create Waypoint", N_("Create _Waypoint"), "<control><shift>W", N_("Create Waypoint"), 0 },
     (VikToolConstructorFunc) tool_new_waypoint_create,    NULL, NULL, NULL,
-    (VikToolMouseFunc) tool_new_waypoint_click,    NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf },
+    (VikToolMouseFunc) tool_new_waypoint_click,    NULL, NULL, (VikToolKeyFunc) NULL,
+    FALSE,
+    GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf },
 
   { { "CreateTrack", "vik-icon-Create Track", N_("Create _Track"), "<control><shift>T", N_("Create Track"), 0 },
     (VikToolConstructorFunc) tool_new_track_create,       NULL, NULL, NULL,
-    (VikToolMouseFunc) tool_new_track_click, (VikToolMouseMoveFunc) tool_new_track_move, NULL,
-    (VikToolKeyFunc) tool_new_track_key_press, GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf },
+    (VikToolMouseFunc) tool_new_track_click,
+    (VikToolMouseMoveFunc) tool_new_track_move,
+    (VikToolMouseFunc) tool_new_track_release,
+    (VikToolKeyFunc) tool_new_track_key_press,
+    TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing
+    GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf },
 
   { { "BeginTrack", "vik-icon-Begin Track", N_("_Begin Track"), "<control><shift>B", N_("Begin Track"), 0 },
     (VikToolConstructorFunc) tool_begin_track_create,       NULL, NULL, NULL,
-    (VikToolMouseFunc) tool_begin_track_click,       NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_begintr_pixbuf },
+    (VikToolMouseFunc) tool_begin_track_click,       NULL, NULL, (VikToolKeyFunc) NULL,
+    FALSE,
+    GDK_CURSOR_IS_PIXMAP, &cursor_begintr_pixbuf },
 
   { { "EditWaypoint", "vik-icon-Edit Waypoint", N_("_Edit Waypoint"), "<control><shift>E", N_("Edit Waypoint"), 0 },
     (VikToolConstructorFunc) tool_edit_waypoint_create,   NULL, NULL, NULL,
     (VikToolMouseFunc) tool_edit_waypoint_click,   
     (VikToolMouseMoveFunc) tool_edit_waypoint_move,
-    (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf },
+    (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL,
+    FALSE,
+    GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf },
 
   { { "EditTrackpoint", "vik-icon-Edit Trackpoint", N_("Edit Trac_kpoint"), "<control><shift>K", N_("Edit Trackpoint"), 0 },
     (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL,
     (VikToolMouseFunc) tool_edit_trackpoint_click,
     (VikToolMouseMoveFunc) tool_edit_trackpoint_move,
-    (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf },
+    (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL,
+    FALSE,
+    GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf },
 
   { { "ShowPicture", "vik-icon-Show Picture", N_("Show P_icture"), "<control><shift>I", N_("Show Picture"), 0 },
     (VikToolConstructorFunc) tool_show_picture_create,    NULL, NULL, NULL,
-    (VikToolMouseFunc) tool_show_picture_click,    NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf },
+    (VikToolMouseFunc) tool_show_picture_click,    NULL, NULL, (VikToolKeyFunc) NULL,
+    FALSE,
+    GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf },
 
+#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
   { { "RouteFinder", "vik-icon-Route Finder", N_("Route _Finder"), "<control><shift>F", N_("Route Finder"), 0 },
     (VikToolConstructorFunc) tool_route_finder_create,  NULL, NULL, NULL,
-    (VikToolMouseFunc) tool_route_finder_click, NULL, NULL, (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf },
+    (VikToolMouseFunc) tool_route_finder_click, NULL, NULL, (VikToolKeyFunc) NULL,
+    FALSE,
+    GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf },
+#endif
 };
 enum { TOOL_CREATE_WAYPOINT=0, TOOL_CREATE_TRACK, TOOL_BEGIN_TRACK, TOOL_EDIT_WAYPOINT, TOOL_EDIT_TRACKPOINT, TOOL_SHOW_PICTURE, NUM_TOOLS };
 
@@ -945,7 +976,8 @@ static VikTrwLayer* trw_layer_new ( gint drawmode )
   rv->moving_tp = FALSE;
   rv->moving_wp = FALSE;
 
-  rv->ct_sync_done = TRUE;
+  rv->draw_sync_done = TRUE;
+  rv->draw_sync_do = TRUE;
 
   rv->route_finder_started = FALSE;
   rv->route_finder_check_added_track = FALSE;
@@ -1505,6 +1537,11 @@ static void trw_layer_free_track_gcs ( VikTrwLayer *vtl )
     g_object_unref ( vtl->current_track_gc );
     vtl->current_track_gc = NULL;
   }
+  if ( vtl->current_track_newpoint_gc )
+  {
+    g_object_unref ( vtl->current_track_newpoint_gc );
+    vtl->current_track_newpoint_gc = NULL;
+  }
 
   if ( ! vtl->track_gc )
     return;
@@ -1531,6 +1568,12 @@ static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp )
   vtl->current_track_gc = vik_viewport_new_gc ( vp, "#FF0000", 2 );
   gdk_gc_set_line_attributes ( vtl->current_track_gc, 2, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
 
+  // 'newpoint' gc is exactly the same as the current track gc
+  if ( vtl->current_track_newpoint_gc )
+    g_object_unref ( vtl->current_track_newpoint_gc );
+  vtl->current_track_newpoint_gc = vik_viewport_new_gc ( vp, "#FF0000", 2 );
+  gdk_gc_set_line_attributes ( vtl->current_track_newpoint_gc, 2, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
+
   vtl->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC );
 
   gc[0] = vik_viewport_new_gc ( vp, "#2d870a", width ); /* below range */
@@ -3433,6 +3476,7 @@ static void trw_layer_extend_track_end ( gpointer pass_along[6] )
     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) );
 }
 
+#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
 /**
  * extend a track using route finder
  */
@@ -3451,6 +3495,7 @@ static void trw_layer_extend_track_end_route_finder ( gpointer pass_along[6] )
     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &last_coord) ;
 
 }
+#endif
 
 static void trw_layer_apply_dem_data ( gpointer pass_along[6] )
 {
@@ -3788,6 +3833,20 @@ static void trw_layer_append_track ( gpointer pass_along[6] )
   }
 }
 
+/* merge by segments */
+static void trw_layer_merge_by_segment ( gpointer pass_along[6] )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
+  VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
+  guint segments = vik_track_merge_segments ( trk );
+  // NB currently no need to redraw as segments not actually shown on the display
+  // However inform the user of what happened:
+  gchar str[64];
+  const gchar *tmp_str = ngettext("%d segment merged", "%d segments merged", segments);
+  g_snprintf(str, 64, tmp_str, segments);
+  a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str );
+}
+
 /* merge by time routine */
 static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
 {
@@ -4952,6 +5011,11 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
     gtk_widget_show ( item );
 
+    item = gtk_menu_item_new_with_mnemonic ( _("Merge _Segments") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_segment), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
+    gtk_widget_show ( item );
+
     item = gtk_menu_item_new_with_mnemonic ( _("_Append Track...") );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_track), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
@@ -5039,11 +5103,13 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
 
+#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
     item = gtk_image_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") );
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("Route Finder", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_route_finder), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
+#endif
 
 #ifdef VIK_CONFIG_OPENSTREETMAP
     item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
@@ -5203,27 +5269,30 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
 
     GList *new_tpl;
 
+    // Find available adjacent trackpoint
     if ( (new_tpl = vtl->current_tpl->next) || (new_tpl = vtl->current_tpl->prev) )
     {
       if ( VIK_TRACKPOINT(vtl->current_tpl->data)->newsegment && vtl->current_tpl->next )
         VIK_TRACKPOINT(vtl->current_tpl->next->data)->newsegment = TRUE; /* don't concat segments on del */
 
-      tr->trackpoints = g_list_remove_link ( tr->trackpoints, vtl->current_tpl ); /* this nulls current_tpl->prev and next */
+      // Delete current trackpoint
+      vik_trackpoint_free ( vtl->current_tpl->data );
+      tr->trackpoints = g_list_delete_link ( tr->trackpoints, vtl->current_tpl );
+
+      // Set to current to the available adjacent trackpoint
+      vtl->current_tpl = new_tpl;
 
-      /* at this point the old trackpoint exists, but the list links are correct (new), so it is safe to do this. */
+      // Reset dialog with the available adjacent trackpoint
       if ( vtl->current_tp_track )
         vik_trw_layer_tpwin_set_tp ( vtl->tpwin, new_tpl, vtl->current_tp_track->name );
 
-      g_free ( vtl->current_tpl->data ); /* TODO: vik_trackpoint_free() */
-      g_list_free_1 ( vtl->current_tpl );
-      vtl->current_tpl = new_tpl;
       vik_layer_emit_update(VIK_LAYER(vtl), FALSE);
     }
     else
     {
-      tr->trackpoints = g_list_remove_link ( tr->trackpoints, vtl->current_tpl );
-      g_free ( vtl->current_tpl->data ); /* TODO longone: vik_trackpoint_new() and vik_trackpoint_free() */
-      g_list_free_1 ( vtl->current_tpl );
+      // Delete current trackpoint
+      vik_trackpoint_free ( vtl->current_tpl->data );
+      tr->trackpoints = g_list_delete_link ( tr->trackpoints, vtl->current_tpl );
       trw_layer_cancel_current_tp ( vtl, FALSE );
     }
   }
@@ -5588,20 +5657,31 @@ static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEve
   VikTrack *track = (VikTrack*)vik_window_get_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
   if ( track && track->visible ) {
 
-    if ( vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ) {
+    if ( track->name ) {
 
       if ( vtl->track_right_click_menu )
-       gtk_object_sink ( GTK_OBJECT(vtl->track_right_click_menu) );
+        gtk_object_sink ( GTK_OBJECT(vtl->track_right_click_menu) );
 
       vtl->track_right_click_menu = GTK_MENU ( gtk_menu_new () );
       
-      trw_layer_sublayer_add_menu_items ( vtl,
-                                         vtl->track_right_click_menu,
-                                         NULL,
-                                         VIK_TRW_LAYER_SUBLAYER_TRACK,
-                                         vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ),
-                                         g_hash_table_lookup ( vtl->tracks_iters, vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ),
-                                         vvp);
+      trku_udata udataU;
+      udataU.trk  = track;
+      udataU.uuid = NULL;
+
+      gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udataU );
+
+      if ( trkf && udataU.uuid ) {
+
+        GtkTreeIter *iter = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid );
+
+        trw_layer_sublayer_add_menu_items ( vtl,
+                                            vtl->track_right_click_menu,
+                                            NULL,
+                                            VIK_TRW_LAYER_SUBLAYER_TRACK,
+                                            udataU.uuid,
+                                            iter,
+                                            vvp );
+      }
 
       gtk_menu_popup ( vtl->track_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
        
@@ -5612,19 +5692,30 @@ static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEve
   /* See if a waypoint is selected */
   VikWaypoint *waypoint = (VikWaypoint*)vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
   if ( waypoint && waypoint->visible ) {
-    if ( vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ) {
+    if ( waypoint->name ) {
 
       if ( vtl->wp_right_click_menu )
-       gtk_object_sink ( GTK_OBJECT(vtl->wp_right_click_menu) );
+        gtk_object_sink ( GTK_OBJECT(vtl->wp_right_click_menu) );
 
       vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
-      trw_layer_sublayer_add_menu_items ( vtl,
-                                         vtl->wp_right_click_menu,
-                                         NULL,
-                                         VIK_TRW_LAYER_SUBLAYER_WAYPOINT,
-                                         vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ),
-                                         g_hash_table_lookup ( vtl->waypoints_iters, vik_window_get_selected_name ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) ) ),
-                                         vvp);
+
+      wpu_udata udata;
+      udata.wp   = waypoint;
+      udata.uuid = NULL;
+
+      gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+
+      if ( wpf && udata.uuid ) {
+        GtkTreeIter *iter = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
+
+        trw_layer_sublayer_add_menu_items ( vtl,
+                                            vtl->wp_right_click_menu,
+                                            NULL,
+                                            VIK_TRW_LAYER_SUBLAYER_WAYPOINT,
+                                            udata.uuid,
+                                            iter,
+                                            vvp );
+      }
       gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
 
       return TRUE;
@@ -5871,25 +5962,29 @@ static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp)
 
 typedef struct {
   VikTrwLayer *vtl;
-  VikViewport *vvp;
-  gint x1,y1,x2,y2,x3,y3;
-  const gchar* str;
-} new_track_move_passalong_t;
-
-/* sync and undraw, but only when we have time */
-static gboolean ct_sync ( gpointer passalong )
-{
-  new_track_move_passalong_t *p = (new_track_move_passalong_t *) passalong;
+  GdkDrawable *drawable;
+  GdkGC *gc;
+  GdkPixmap *pixmap;
+} draw_sync_t;
 
-  vik_viewport_sync ( p->vvp );
-  gdk_gc_set_function ( p->vtl->current_track_gc, GDK_INVERT );
-  vik_viewport_draw_line ( p->vvp, p->vtl->current_track_gc, p->x1, p->y1, p->x2, p->y2 );
-  vik_viewport_draw_string (p->vvp, gdk_font_from_description (pango_font_description_from_string ("Sans 8")), p->vtl->current_track_gc, p->x3, p->y3, p->str);
-  gdk_gc_set_function ( p->vtl->current_track_gc, GDK_COPY );
-
-  g_free ( (gpointer) p->str ) ;
-  p->vtl->ct_sync_done = TRUE;
-  g_free ( p );
+/*
+ * Draw specified pixmap
+ */
+static gboolean draw_sync ( gpointer data )
+{
+  draw_sync_t *ds = (draw_sync_t*) data;
+  // Sometimes don't want to draw
+  //  normally because another update has taken precedent such as panning the display
+  //   which means this pixmap is no longer valid
+  if ( ds->vtl->draw_sync_do ) {
+    gdk_threads_enter();
+    gdk_draw_drawable (ds->drawable,
+                       ds->gc,
+                       ds->pixmap,
+                       0, 0, 0, 0, -1, -1);
+    ds->vtl->draw_sync_done = TRUE;
+    gdk_threads_leave();
+  }
   return FALSE;
 }
 
@@ -5967,16 +6062,41 @@ static void update_statusbar ( VikTrwLayer *vtl )
 static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp )
 {
   /* if we haven't sync'ed yet, we don't have time to do more. */
-  if ( vtl->ct_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
-    GList *iter = vtl->current_track->trackpoints;
-    new_track_move_passalong_t *passalong;
+  if ( vtl->draw_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
+    GList *iter = g_list_last ( vtl->current_track->trackpoints );
+
+    static GdkPixmap *pixmap = NULL;
+    int w1, h1, w2, h2;
+    // Need to check in case window has been resized
+    w1 = vik_viewport_get_width(vvp);
+    h1 = vik_viewport_get_height(vvp);
+    if (!pixmap) {
+      pixmap = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, w1, h1, -1 );
+    }
+    gdk_drawable_get_size (pixmap, &w2, &h2);
+    if (w1 != w2 || h1 != h2) {
+      g_object_unref ( G_OBJECT ( pixmap ) );
+      pixmap = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, w1, h1, -1 );
+    }
+
+    // Reset to background
+    gdk_draw_drawable (pixmap,
+                       vtl->current_track_newpoint_gc,
+                       vik_viewport_get_pixmap(vvp),
+                       0, 0, 0, 0, -1, -1);
+
+    draw_sync_t *passalong;
     gint x1, y1;
 
-    while ( iter->next )
-      iter = iter->next;
-    gdk_gc_set_function ( vtl->current_track_gc, GDK_INVERT );
     vik_viewport_coord_to_screen ( vvp, &(VIK_TRACKPOINT(iter->data)->coord), &x1, &y1 );
-    vik_viewport_draw_line ( vvp, vtl->current_track_gc, x1, y1, event->x, event->y );
+
+    // FOR SCREEN OVERLAYS WE MUST DRAW INTO THIS PIXMAP (when using the reset method)
+    //  otherwise using vik_viewport_draw_* functions puts the data into the base pixmap,
+    //  thus when we come to reset to the background it would include what we have already drawn!!
+    gdk_draw_line ( pixmap,
+                    vtl->current_track_newpoint_gc,
+                    x1, y1, event->x, event->y );
+    // Using this reset method is more reliable than trying to undraw previous efforts via the GDK_INVERT method
 
     /* Find out actual distance of current track */
     gdouble distance = vik_track_get_length (vtl->current_track);
@@ -6012,28 +6132,38 @@ static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMo
     /* offset from cursor a bit */
     xd = event->x + 10;
     yd = event->y - 10;
-    /* note attempted setting text using pango layouts - but the 'undraw' technique didn't work */
-    vik_viewport_draw_string (vvp, gdk_font_from_description (pango_font_description_from_string ("Sans 8")), vtl->current_track_gc, xd, yd, str);
 
-    gdk_gc_set_function ( vtl->current_track_gc, GDK_COPY );
+    PangoLayout *pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL);
+    PangoFontDescription *pfd = pango_font_description_from_string ("Sans 8"); // FIXME: settable option? global variable?
+    pango_layout_set_font_description (pl, pfd);
+    pango_font_description_free (pfd);
+
+    pango_layout_set_text (pl, str, -1);
+    gint wd, hd;
+    pango_layout_get_pixel_size ( pl, &wd, &hd );
 
-    passalong = g_new(new_track_move_passalong_t,1); /* freed by sync */
+    // Create a background block to make the text easier to read over the background map
+    GdkGC *background_block_gc = vik_viewport_new_gc ( vvp, "#cccccc", 1);
+    gdk_draw_rectangle (pixmap, background_block_gc, TRUE, xd-2, yd-2, wd+4, hd+2);
+    gdk_draw_layout (pixmap, vtl->current_track_newpoint_gc, xd, yd, pl);
+
+    g_object_unref ( G_OBJECT ( pl ) );
+    g_object_unref ( G_OBJECT ( background_block_gc ) );
+
+    passalong = g_new(draw_sync_t,1); // freed by draw_sync()
     passalong->vtl = vtl;
-    passalong->vvp = vvp;
-    passalong->x1 = x1;
-    passalong->y1 = y1;
-    passalong->x2 = event->x;
-    passalong->y2 = event->y;
-    passalong->x3 = xd;
-    passalong->y3 = yd;
-    passalong->str = str;
+    passalong->pixmap = pixmap;
+    passalong->drawable = GTK_WIDGET(vvp)->window;
+    passalong->gc = vtl->current_track_newpoint_gc;
 
     // Update statusbar with full gain/loss information
     statusbar_write (str, elev_gain, elev_loss, vtl);
 
-    /* this will sync and undraw when we have time to */
-    g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, ct_sync, passalong, NULL);
-    vtl->ct_sync_done = FALSE;
+    g_free ((gpointer)str);
+
+    // draw pixmap when we have time to
+    g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_sync, passalong, NULL);
+    vtl->draw_sync_done = FALSE;
     return VIK_LAYER_TOOL_ACK_GRAB_FOCUS;
   }
   return VIK_LAYER_TOOL_ACK;
@@ -6069,6 +6199,13 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event,
   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
     return FALSE;
 
+  if ( event->button == 2 ) {
+    // As the display is panning, the new track pixmap is now invalid so don't draw it
+    //  otherwise this drawing done results in flickering back to an old image
+    vtl->draw_sync_do = FALSE;
+    return FALSE;
+  }
+
   if ( event->button == 3 && vtl->current_track )
   {
     /* undo */
@@ -6141,6 +6278,15 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event,
   return TRUE;
 }
 
+static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+{
+  if ( event->button == 2 ) {
+    // Pan moving ended - enable potential point drawing again
+    vtl->draw_sync_do = TRUE;
+    vtl->draw_sync_done = TRUE;
+  }
+}
+
 /*** New waypoint ****/
 
 static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp)
@@ -6304,6 +6450,7 @@ static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton
 }
 
 
+#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
 /*** Route Finder ***/
 static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp)
 {
@@ -6379,6 +6526,7 @@ static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *even
   }
   return TRUE;
 }
+#endif
 
 /*** Show picture ****/