* Copyright (C) 2005-2008, Alex Foobarian <foobarian@gmail.com>
* Copyright (C) 2007, Quy Tonthat <qtonthat@gmail.com>
* Copyright (C) 2009, Hein Ragas <viking@ragas.nl>
- * Copyright (c) 2012, Rob Norris <rw_norris@hotmail.com>
+ * Copyright (c) 2012-2015, Rob Norris <rw_norris@hotmail.com>
* Copyright (c) 2012-2013, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
#include "acquire.h"
#include "datasources.h"
#include "datasource_gps.h"
+#include "vikexttools.h"
#include "vikexttool_datasources.h"
#include "ui_util.h"
#include "vikutils.h"
GdkGC *waypoint_text_gc; GdkColor waypoint_text_color;
GdkGC *waypoint_bg_gc; GdkColor waypoint_bg_color;
gboolean wpbgand;
- GdkFont *waypoint_font;
VikTrack *current_track; // ATM shared between new tracks and new routes
guint16 ct_x1, ct_y1, ct_x2, ct_y2;
gboolean draw_sync_done;
static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response );
static void trw_layer_tpwin_init ( VikTrwLayer *vtl );
+static void trw_layer_sort_all ( VikTrwLayer *vtl );
+
static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp);
static void tool_edit_trackpoint_destroy ( tool_ed_t *t );
static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
N_("None"),
N_("Name Ascending"),
N_("Name Descending"),
+ N_("Date Ascending"),
+ N_("Date Descending"),
NULL
};
static void trw_layer_free ( VikTrwLayer *trwlayer );
static void trw_layer_draw ( VikTrwLayer *l, gpointer data );
static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode );
+static time_t trw_layer_get_timestamp ( VikTrwLayer *vtl );
static void trw_layer_set_menu_selection ( VikTrwLayer *vtl, guint16 );
static guint16 trw_layer_get_menu_selection ( VikTrwLayer *vtl );
static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp );
(VikLayerFuncProperties) NULL,
(VikLayerFuncDraw) trw_layer_draw,
(VikLayerFuncChangeCoordMode) trw_layer_change_coord_mode,
+ (VikLayerFuncGetTimestamp) trw_layer_get_timestamp,
(VikLayerFuncSetMenuItemsSelection) trw_layer_set_menu_selection,
(VikLayerFuncGetMenuItemsSelection) trw_layer_get_menu_selection,
};
static gboolean have_diary_program = FALSE;
+static gchar *diary_program = NULL;
+#define VIK_SETTINGS_EXTERNAL_DIARY_PROGRAM "external_diary_program"
+
static gboolean have_geojson_export = FALSE;
+static gboolean have_astro_program = FALSE;
+static gchar *astro_program = NULL;
+#define VIK_SETTINGS_EXTERNAL_ASTRO_PROGRAM "external_astro_program"
// NB Only performed once per program run
static void vik_trwlayer_class_init ( VikTrwLayerClass *klass )
{
- if ( g_find_program_in_path( "rednotebook" ) ) {
+ if ( ! a_settings_get_string ( VIK_SETTINGS_EXTERNAL_DIARY_PROGRAM, &diary_program ) ) {
+#ifdef WINDOWS
+ //diary_program = g_strdup ( "C:\\Program Files\\Rednotebook\\rednotebook.exe" );
+ diary_program = g_strdup ( "C:/Progra~1/Rednotebook/rednotebook.exe" );
+#else
+ diary_program = g_strdup ( "rednotebook" );
+#endif
+ }
+ else {
+ // User specified so assume it works
+ have_diary_program = TRUE;
+ }
+
+ if ( g_find_program_in_path( diary_program ) ) {
gchar *mystdout = NULL;
gchar *mystderr = NULL;
// Needs RedNotebook 1.7.3+ for support of opening on a specified date
- if ( g_spawn_command_line_sync ( "rednotebook --version", &mystdout, &mystderr, NULL, NULL ) ) {
+ gchar *cmd = g_strconcat ( diary_program, " --version", NULL ); // "rednotebook --version"
+ if ( g_spawn_command_line_sync ( cmd, &mystdout, &mystderr, NULL, NULL ) ) {
// Annoyingly 1.7.1|2|3 versions of RedNotebook prints the version to stderr!!
- if ( stdout )
+ if ( mystdout )
g_debug ("Diary: %s", mystdout ); // Should be something like 'RedNotebook 1.4'
- if ( stderr )
+ if ( mystderr )
g_warning ("Diary: stderr: %s", mystderr );
gchar **tokens = NULL;
- if ( stdout && g_strcmp0(mystdout, "") )
+ if ( mystdout && g_strcmp0(mystdout, "") )
tokens = g_strsplit(mystdout, " ", 0);
- else if ( stderr )
+ else if ( mystderr )
tokens = g_strsplit(mystderr, " ", 0);
- gint num = 0;
- gchar *token = tokens[num];
- while ( token && num < 2 ) {
- if (num == 1) {
- if ( viking_version_to_number(token) >= viking_version_to_number("1.7.3") )
- have_diary_program = TRUE;
+ if ( tokens ) {
+ gint num = 0;
+ gchar *token = tokens[num];
+ while ( token && num < 2 ) {
+ if (num == 1) {
+ if ( viking_version_to_number(token) >= viking_version_to_number("1.7.3") )
+ have_diary_program = TRUE;
+ }
+ num++;
+ token = tokens[num];
}
- num++;
- token = tokens[num];
}
g_strfreev ( tokens );
}
g_free ( mystdout );
g_free ( mystderr );
+ g_free ( cmd );
}
if ( g_find_program_in_path ( a_geojson_program_export() ) ) {
have_geojson_export = TRUE;
}
+
+ // Astronomy Domain
+ if ( ! a_settings_get_string ( VIK_SETTINGS_EXTERNAL_ASTRO_PROGRAM, &astro_program ) ) {
+#ifdef WINDOWS
+ //astro_program = g_strdup ( "C:\\Program Files\\Stellarium\\stellarium.exe" );
+ astro_program = g_strdup ( "C:/Progra~1/Stellarium/stellarium.exe" );
+#else
+ astro_program = g_strdup ( "stellarium" );
+#endif
+ }
+ else {
+ // User specified so assume it works
+ have_astro_program = TRUE;
+ }
+ if ( g_find_program_in_path( astro_program ) ) {
+ have_astro_program = TRUE;
+ }
}
GType vik_trw_layer_get_type ()
const gchar *date_str;
const VikTrack *trk;
const VikWaypoint *wpt;
- gpointer *trk_id;
- gpointer *wpt_id;
+ gpointer trk_id;
+ gpointer wpt_id;
} date_finder_type;
static gboolean trw_layer_find_date_track ( const gpointer id, const VikTrack *trk, date_finder_type *df )
{
VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
gint subtype = GPOINTER_TO_INT (values[MA_SUBTYPE]);
- gpointer * sublayer = values[MA_SUBLAYER_ID];
+ gpointer sublayer = values[MA_SUBLAYER_ID];
guint8 *data = NULL;
guint len;
}
}
+static void image_cache_free ( VikTrwLayer *vtl )
+{
+ g_list_foreach ( vtl->image_cache->head, (GFunc)cached_pixbuf_free, NULL );
+ g_queue_free ( vtl->image_cache );
+}
+
static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
{
switch ( id )
case PARAM_IS: if ( data.u != vtl->image_size )
{
vtl->image_size = data.u;
- g_list_foreach ( vtl->image_cache->head, (GFunc) cached_pixbuf_free, NULL );
- g_queue_free ( vtl->image_cache );
+ image_cache_free ( vtl );
+ vtl->image_cache = g_queue_new ();
+ }
+ break;
+ case PARAM_IA: if ( data.u != vtl->image_alpha )
+ {
+ vtl->image_alpha = data.u;
+ image_cache_free ( vtl );
vtl->image_cache = g_queue_new ();
}
break;
- case PARAM_IA: vtl->image_alpha = data.u; break;
case PARAM_ICS: vtl->image_cache_size = data.u;
while ( vtl->image_cache->length > vtl->image_cache_size ) /* if shrinking cache_size, free pixbuf ASAP */
cached_pixbuf_free ( g_queue_pop_tail ( vtl->image_cache ) );
// Reuse pl to read the subtype from the data stream
memcpy(&pl, data+sizeof(gint), sizeof(pl));
+ // Also remember to (attempt to) convert each coordinate in case this is pasted into a different drawmode
if ( pl == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
VikTrack *trk = vik_track_unmarshall ( data + sizeof_len_and_subtype, 0 );
gchar *name = g_strdup ( trk->name );
vik_trw_layer_add_track ( vtl, name, trk );
g_free ( name );
+ vik_track_convert (trk, vtl->coord_mode);
}
if ( pl == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
VikWaypoint *wp = vik_waypoint_unmarshall ( data + sizeof_len_and_subtype, 0 );
gchar *name = g_strdup ( wp->name );
vik_trw_layer_add_waypoint ( vtl, name, wp );
g_free ( name );
+ waypoint_convert (NULL, wp, &vtl->coord_mode);
}
if ( pl == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
VikTrack *trk = vik_track_unmarshall ( data + sizeof_len_and_subtype, 0 );
gchar *name = g_strdup ( trk->name );
vik_trw_layer_add_route ( vtl, name, trk );
g_free ( name );
+ vik_track_convert (trk, vtl->coord_mode);
}
}
consumed_length += tlm_size + sizeof_len_and_subtype;
rv->metadata = vik_trw_metadata_new ();
rv->draw_sync_done = TRUE;
rv->draw_sync_do = TRUE;
+ rv->coord_mode = VIK_COORD_LATLON;
// Everything else is 0, FALSE or NULL
return rv;
if ( trwlayer->tracks_analysis_dialog != NULL )
gtk_widget_destroy ( GTK_WIDGET(trwlayer->tracks_analysis_dialog) );
- g_list_foreach ( trwlayer->image_cache->head, (GFunc) cached_pixbuf_free, NULL );
- g_queue_free ( trwlayer->image_cache );
+ image_cache_free ( trwlayer );
}
static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp, gboolean highlight )
case VIK_UNITS_DISTANCE_MILES:
units = g_strdup ( _("miles") );
break;
+ case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
+ units = g_strdup ( _("NM") );
+ break;
// VIK_UNITS_DISTANCE_KILOMETRES:
default:
units = g_strdup ( _("km") );
g_free ( ename );
}
+
+/**
+ * trw_layer_draw_point_names:
+ *
+ * Draw a point labels along a track
+ * This might slow things down if there's many tracks being displayed with this on.
+ */
+static void trw_layer_draw_point_names ( struct DrawingParams *dp, VikTrack *trk, gboolean drawing_highlight )
+{
+ GList *list = trk->trackpoints;
+ if (!list) return;
+ VikTrackpoint *tp = VIK_TRACKPOINT(list->data);
+ gchar *fgcolour;
+ if ( dp->vtl->drawmode == DRAWMODE_BY_TRACK )
+ fgcolour = gdk_color_to_string ( &(trk->color) );
+ else
+ fgcolour = gdk_color_to_string ( &(dp->vtl->track_color) );
+ gchar *bgcolour;
+ if ( drawing_highlight )
+ bgcolour = g_strdup ( vik_viewport_get_highlight_color ( dp->vp ) );
+ else
+ bgcolour = gdk_color_to_string ( &(dp->vtl->track_bg_color) );
+ if ( tp->name )
+ trw_layer_draw_track_label ( tp->name, fgcolour, bgcolour, dp, &tp->coord );
+ while ((list = g_list_next(list)))
+ {
+ tp = VIK_TRACKPOINT(list->data);
+ if ( tp->name )
+ trw_layer_draw_track_label ( tp->name, fgcolour, bgcolour, dp, &tp->coord );
+ };
+ g_free ( fgcolour );
+ g_free ( bgcolour );
+}
+
static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct DrawingParams *dp, gboolean draw_track_outline )
{
if ( ! track->visible )
tp = VIK_TRACKPOINT(list->data);
tp_size = (list == dp->vtl->current_tpl) ? tp_size_cur : tp_size_reg;
+ VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
+ // See if in a different lat/lon 'quadrant' so don't draw massively long lines (presumably wrong way around the Earth)
+ // Mainly to prevent wrong lines drawn when a track crosses the 180 degrees East-West longitude boundary
+ // (since vik_viewport_draw_line() only copes with pixel value and has no concept of the globe)
+ if ( dp->lat_lon &&
+ (( tp2->coord.east_west < -90.0 && tp->coord.east_west > 90.0 ) ||
+ ( tp2->coord.east_west > 90.0 && tp->coord.east_west < -90.0 )) ) {
+ useoldvals = FALSE;
+ continue;
+ }
/* check some stuff -- but only if we're in UTM and there's only ONE ZONE; or lat lon */
if ( (!dp->one_zone && !dp->lat_lon) || /* UTM & zones; do everything */
( ((!dp->one_zone) || tp->coord.utm_zone == dp->center->utm_zone) && /* only check zones if UTM & one_zone */
// Still need to process points to ensure 'stops' are drawn if required
if ( drawstops && drawpoints && ! draw_track_outline && list->next &&
(VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length) )
- vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, 11), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 );
+ vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, VIK_TRW_LAYER_TRACK_GC_STOP), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 );
goto skip;
}
- VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
if ( drawpoints || dp->vtl->drawlines ) {
// setup main_gc for both point and line drawing
if ( !drawing_highlight && (dp->vtl->drawmode == DRAWMODE_BY_SPEED) ) {
else {
if (useoldvals && dp->vtl->drawlines && (!tp->newsegment))
{
- VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
if ( dp->vtl->coord_mode != VIK_COORD_UTM || tp->coord.utm_zone == dp->center->utm_zone )
{
vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
if ( track->max_number_dist_labels > 0 ) {
trw_layer_draw_dist_labels ( dp, track, drawing_highlight );
}
+ trw_layer_draw_point_names (dp, track, drawing_highlight );
if ( track->draw_name_mode != TRACK_DRAWNAME_NO ) {
trw_layer_draw_track_name_labels ( dp, track, drawing_highlight );
}
cp->image = g_strdup ( image );
+ // Apply alpha setting to the image before the pixbuf gets stored in the cache
+ if ( dp->vtl->image_alpha != 255 )
+ cp->pixbuf = ui_pixbuf_set_alpha ( cp->pixbuf, dp->vtl->image_alpha );
+
/* needed so 'click picture' tool knows how big the pic is; we don't
* store it in cp because they may have been freed already. */
wp->image_width = gdk_pixbuf_get_width ( cp->pixbuf );
x - (w/2) - 2, y - (h/2) - 2, w + 4, h + 4 );
}
- if ( dp->vtl->image_alpha == 255 )
- vik_viewport_draw_pixbuf ( dp->vp, pixbuf, 0, 0, x - (w/2), y - (h/2), w, h );
- else
- vik_viewport_draw_pixbuf_with_alpha ( dp->vp, pixbuf, dp->vtl->image_alpha, 0, 0, x - (w/2), y - (h/2), w, h );
+ vik_viewport_draw_pixbuf ( dp->vp, pixbuf, 0, 0, x - (w/2), y - (h/2), w, h );
}
return; /* if failed to draw picture, default to drawing regular waypoint (below) */
}
gdk_pixbuf_fill ( pixbuf, pixel );
}
- vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), pixbuf, TRUE, TRUE );
+ time_t timestamp = 0;
+ VikTrackpoint *tpt = vik_track_get_tp_first(track);
+ if ( tpt && tpt->has_timestamp )
+ timestamp = tpt->timestamp;
+
+ vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), pixbuf, TRUE, timestamp );
if ( pixbuf )
g_object_unref (pixbuf);
{
GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
- vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_UINT (pass_along[4]), get_wp_sym_small (wp->symbol), TRUE, TRUE );
+ time_t timestamp = 0;
+ if ( wp->has_timestamp )
+ timestamp = wp->timestamp;
+
+ vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_UINT (pass_along[4]), get_wp_sym_small (wp->symbol), TRUE, timestamp );
*new_iter = *((GtkTreeIter *) pass_along[1]);
g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->waypoints_iters, id, new_iter );
static void trw_layer_add_sublayer_tracks ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
{
- vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE );
+ vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, FALSE, 0 );
}
static void trw_layer_add_sublayer_waypoints ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
{
- vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE );
+ vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, FALSE, 0 );
}
static void trw_layer_add_sublayer_routes ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
{
- vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->routes_iter), _("Routes"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_ROUTES, NULL, TRUE, FALSE );
+ vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->routes_iter), _("Routes"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_ROUTES, NULL, FALSE, 0 );
}
static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->waypoints_iter), vtl->waypoints_visible );
}
+ trw_layer_verify_thumbnails ( vtl, NULL );
+
+ trw_layer_sort_all ( vtl );
}
static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer )
return vtl->line_thickness;
}
+/*
+ * Build up multiple routes information
+ */
+static void trw_layer_routes_tooltip ( const gpointer id, VikTrack *tr, gdouble *length )
+{
+ *length = *length + vik_track_get_length (tr);
+}
+
// Structure to hold multiple track information for a layer
typedef struct {
gdouble length;
/*
* Build up layer multiple track information via updating the tooltip_tracks structure
*/
-static void trw_layer_tracks_tooltip ( const gchar *name, VikTrack *tr, tooltip_tracks *tt )
+static void trw_layer_tracks_tooltip ( const gpointer id, VikTrack *tr, tooltip_tracks *tt )
{
tt->length = tt->length + vik_track_get_length (tr);
*/
static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl )
{
- gchar tbuf1[32];
+ gchar tbuf1[64];
gchar tbuf2[64];
gchar tbuf3[64];
gchar tbuf4[10];
// Timing information if available
tbuf1[0] = '\0';
if ( tt.duration > 0 ) {
- g_snprintf (tbuf1, sizeof(tbuf1),
- _(" in %d:%02d hrs:mins"),
- (int)round(tt.duration/3600), (int)round((tt.duration/60)%60));
+ g_snprintf (tbuf1, sizeof(tbuf1),
+ _(" in %d:%02d hrs:mins"),
+ (int)(tt.duration/3600), (int)round(tt.duration/60.0)%60);
}
g_snprintf (tbuf2, sizeof(tbuf2),
_("\n%sTotal Length %.1f %s%s"),
tbuf3, len_in_units, tbuf4, tbuf1);
}
+ tbuf1[0] = '\0';
+ gdouble rlength = 0.0;
+ g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_routes_tooltip, &rlength );
+ if ( rlength > 0.0 ) {
+ gdouble len_in_units;
+ // Setup info dependent on distance units
+ switch ( a_vik_get_units_distance() ) {
+ case VIK_UNITS_DISTANCE_MILES:
+ g_snprintf (tbuf4, sizeof(tbuf4), "miles");
+ len_in_units = VIK_METERS_TO_MILES(rlength);
+ break;
+ case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
+ g_snprintf (tbuf4, sizeof(tbuf4), "NM");
+ len_in_units = VIK_METERS_TO_NAUTICAL_MILES(rlength);
+ break;
+ default:
+ g_snprintf (tbuf4, sizeof(tbuf4), "kms");
+ len_in_units = rlength/1000.0;
+ break;
+ }
+ g_snprintf (tbuf1, sizeof(tbuf1), _("\nTotal route length %.1f %s"), len_in_units, tbuf4);
+ }
+
// Put together all the elements to form compact tooltip text
g_snprintf (tmp_buf, sizeof(tmp_buf),
- _("Tracks: %d - Waypoints: %d - Routes: %d%s"),
- g_hash_table_size (vtl->tracks), g_hash_table_size (vtl->waypoints), g_hash_table_size (vtl->routes), tbuf2);
+ _("Tracks: %d - Waypoints: %d - Routes: %d%s%s"),
+ g_hash_table_size (vtl->tracks), g_hash_table_size (vtl->waypoints), g_hash_table_size (vtl->routes), tbuf2, tbuf1);
g_date_free (gdate_start);
g_date_free (gdate_end);
-
}
return tmp_buf;
if ( tr->trackpoints && vik_track_get_tp_first(tr)->has_timestamp ) {
// %x The preferred date representation for the current locale without the time.
strftime (time_buf1, sizeof(time_buf1), "%x: ", gmtime(&(vik_track_get_tp_first(tr)->timestamp)));
- time_t dur = vik_track_get_duration ( tr );
+ time_t dur = vik_track_get_duration ( tr, TRUE );
if ( dur > 0 )
- g_snprintf ( time_buf2, sizeof(time_buf2), _("- %d:%02d hrs:mins"), (int)round(dur/3600), (int)round((dur/60)%60) );
+ g_snprintf ( time_buf2, sizeof(time_buf2), _("- %d:%02d hrs:mins"), (int)(dur/3600), (int)round(dur/60.0)%60 );
}
// Get length and consider the appropriate distance units
gdouble tr_len = vik_track_get_length(tr);
statusbar_format_code = g_strdup ( "KEATDN" );
need2free = TRUE;
}
+ else {
+ // Format code may want to show speed - so may need previous trkpt to work it out
+ trkpt_prev = vik_track_get_tp_prev ( vtl->current_tp_track, trkpt );
+ }
gchar *msg = vu_trackpoint_formatted_message ( statusbar_format_code, trkpt, trkpt_prev, vtl->current_tp_track, NAN );
vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
GHashTable *vik_trw_layer_get_waypoints_iters ( VikTrwLayer *vtl )
{
- return vtl->waypoints;
+ return vtl->waypoints_iters;
}
gboolean vik_trw_layer_is_empty ( VikTrwLayer *vtl )
void trw_layer_zoom_to_show_latlons ( VikTrwLayer *vtl, VikViewport *vvp, struct LatLon maxmin[2] )
{
- /* First set the center [in case previously viewing from elsewhere] */
- /* Then loop through zoom levels until provided positions are in view */
- /* This method is not particularly fast - but should work well enough */
- struct LatLon average = { (maxmin[0].lat+maxmin[1].lat)/2, (maxmin[0].lon+maxmin[1].lon)/2 };
- VikCoord coord;
- vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average );
- vik_viewport_set_center_coord ( vvp, &coord, TRUE );
-
- /* Convert into definite 'smallest' and 'largest' positions */
- struct LatLon minmin;
- if ( maxmin[0].lat < maxmin[1].lat )
- minmin.lat = maxmin[0].lat;
- else
- minmin.lat = maxmin[1].lat;
-
- struct LatLon maxmax;
- if ( maxmin[0].lon > maxmin[1].lon )
- maxmax.lon = maxmin[0].lon;
- else
- maxmax.lon = maxmin[1].lon;
-
- /* Never zoom in too far - generally not that useful, as too close ! */
- /* Always recalculate the 'best' zoom level */
- gdouble zoom = 1.0;
- vik_viewport_set_zoom ( vvp, zoom );
-
- gdouble min_lat, max_lat, min_lon, max_lon;
- /* Should only be a maximum of about 18 iterations from min to max zoom levels */
- while ( zoom <= VIK_VIEWPORT_MAX_ZOOM ) {
- vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
- /* NB I think the logic used in this test to determine if the bounds is within view
- fails if track goes across 180 degrees longitude.
- Hopefully that situation is not too common...
- Mind you viking doesn't really do edge locations to well anyway */
- if ( min_lat < minmin.lat &&
- max_lat > minmin.lat &&
- min_lon < maxmax.lon &&
- max_lon > maxmax.lon )
- /* Found within zoom level */
- break;
-
- /* Try next */
- zoom = zoom * 2;
- vik_viewport_set_zoom ( vvp, zoom );
- }
+ vu_zoom_to_show_latlons ( vtl->coord_mode, vvp, maxmin );
}
gboolean vik_trw_layer_auto_set_view ( VikTrwLayer *vtl, VikViewport *vvp )
GtkWidget *label, *entry;
label = gtk_label_new(_("Waypoint Name:"));
- entry = gtk_entry_new();
+ entry = ui_entry_new ( NULL, GTK_ENTRY_ICON_SECONDARY );
gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dia))), label, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dia))), entry, FALSE, FALSE, 0);
- gtk_widget_show_all ( label );
- gtk_widget_show_all ( entry );
-
+ gtk_widget_show_all ( dia );
+ // 'ok' when press return in the entry
+ g_signal_connect_swapped ( entry, "activate", G_CALLBACK(a_dialog_response_accept), dia );
gtk_dialog_set_default_response ( GTK_DIALOG(dia), GTK_RESPONSE_ACCEPT );
while ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_ACCEPT )
udata.uuid = NULL;
// Hmmm, want key of it
- gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+ gpointer wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
if ( wpf && udata.uuid ) {
GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
/* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
instead return true if you want to update. */
- if ( vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), vik_viewport_get_center(vik_layers_panel_get_viewport(vlp))) && VIK_LAYER(vtl)->visible ) {
+ if ( vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), vik_viewport_get_center(vik_layers_panel_get_viewport(vlp))) ) {
trw_layer_calculate_bounds_waypoints ( vtl );
- vik_layers_panel_emit_update ( vlp );
+ if ( VIK_LAYER(vtl)->visible )
+ vik_layers_panel_emit_update ( vlp );
}
}
}
}
+static GtkWidget* create_external_submenu ( GtkMenu *menu )
+{
+ GtkWidget *external_submenu = gtk_menu_new ();
+ GtkWidget *item = gtk_image_menu_item_new_with_mnemonic ( _("Externa_l") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_EXECUTE, GTK_ICON_SIZE_MENU) );
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show ( item );
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), external_submenu );
+ return external_submenu;
+}
+
static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp )
{
static menu_array_layer pass_along;
gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
gtk_widget_show ( item );
- item = gtk_menu_item_new_with_mnemonic ( _("Export as _KML...") );
- g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_kml), pass_along );
- gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
- gtk_widget_show ( item );
+ if ( a_babel_available () ) {
+ item = gtk_menu_item_new_with_mnemonic ( _("Export as _KML...") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_kml), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
+ gtk_widget_show ( item );
+ }
if ( have_geojson_export ) {
item = gtk_menu_item_new_with_mnemonic ( _("Export as GEO_JSON...") );
gtk_widget_show ( item );
}
- item = gtk_menu_item_new_with_mnemonic ( _("Export via GPSbabel...") );
- g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_babel), pass_along );
- gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
- gtk_widget_show ( item );
+ if ( a_babel_available () ) {
+ item = gtk_menu_item_new_with_mnemonic ( _("Export via GPSbabel...") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_babel), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
+ gtk_widget_show ( item );
+ }
gchar* external1 = g_strdup_printf ( _("Open with External Program_1: %s"), a_vik_get_external_gpx_program_1() );
item = gtk_menu_item_new_with_mnemonic ( external1 );
gtk_widget_show ( item );
#endif
- item = gtk_menu_item_new_with_mnemonic ( _("From _File...") );
- g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_file_cb), pass_along );
- gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
- gtk_widget_set_tooltip_text (item, _("Import File With GPS_Babel..."));
- gtk_widget_show ( item );
+ if ( a_babel_available () ) {
+ item = gtk_menu_item_new_with_mnemonic ( _("From _File...") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_file_cb), pass_along );
+ gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
+ gtk_widget_set_tooltip_text (item, _("Import File With GPS_Babel..."));
+ gtk_widget_show ( item );
+ }
vik_ext_tool_datasources_add_menu_items_to_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), GTK_MENU (acquire_submenu) );
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
gtk_widget_set_sensitive ( item, (gboolean)(g_hash_table_size (vtl->waypoints)) );
+
+ GtkWidget *external_submenu = create_external_submenu ( menu );
+ // TODO: Should use selected layer's centre - rather than implicitly using the current viewport
+ vik_ext_tools_add_menu_items_to_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), GTK_MENU (external_submenu), NULL );
}
// Fake Waypoint UUIDs vi simple increasing integer
GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
+ time_t timestamp = 0;
+ if ( wp->has_timestamp )
+ timestamp = wp->timestamp;
+
// Visibility column always needed for waypoints
- vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, get_wp_sym_small (wp->symbol), TRUE, TRUE );
+ vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, get_wp_sym_small (wp->symbol), TRUE, timestamp );
// Actual setting of visibility dependent on the waypoint
vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible );
}
GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
+
+ time_t timestamp = 0;
+ VikTrackpoint *tpt = vik_track_get_tp_first(t);
+ if ( tpt && tpt->has_timestamp )
+ timestamp = tpt->timestamp;
+
// Visibility column always needed for tracks
- vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, GUINT_TO_POINTER(tr_uuid), VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
+ vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, GUINT_TO_POINTER(tr_uuid), VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, timestamp );
// Actual setting of visibility dependent on the track
vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
// Visibility column always needed for routes
- vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), iter, name, vtl, GUINT_TO_POINTER(rt_uuid), VIK_TRW_LAYER_SUBLAYER_ROUTE, NULL, TRUE, TRUE );
+ vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), iter, name, vtl, GUINT_TO_POINTER(rt_uuid), VIK_TRW_LAYER_SUBLAYER_ROUTE, NULL, TRUE, 0 ); // Routes don't have times
// Actual setting of visibility dependent on the route
vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
}
// If found a name already in use try adding 1 to it and we try again
if ( id ) {
- gchar *new_newname = g_strdup_printf("%s#%d", name, i);
+ const gchar *corename = newname;
+ gint newi = i;
+ // If name is already of the form text#N
+ // set name to text and i to N+1
+ gchar **tokens = g_regex_split_simple ( "#(\\d+)", newname, G_REGEX_CASELESS, 0 );
+ if ( tokens ) {
+ corename = tokens[0];
+ if ( tokens[1] ) {
+ newi = atoi ( tokens[1] ) + 1;
+ }
+ }
+ gchar *new_newname = g_strdup_printf("%s#%d", corename, newi);
+ g_strfreev ( tokens );
g_free(newname);
newname = new_newname;
i++;
// enforce end of current track equal to start of tr
VikTrackpoint *cur_end = vik_track_get_tp_last ( vtl->current_track );
VikTrackpoint *new_start = vik_track_get_tp_first ( tr );
- if ( ! vik_coord_equals ( &cur_end->coord, &new_start->coord ) ) {
- vik_track_add_trackpoint ( vtl->current_track,
- vik_trackpoint_copy ( cur_end ),
- FALSE );
+ if ( cur_end && new_start ) {
+ if ( ! vik_coord_equals ( &cur_end->coord, &new_start->coord ) ) {
+ vik_track_add_trackpoint ( vtl->current_track,
+ vik_trackpoint_copy ( cur_end ),
+ FALSE );
+ }
}
vik_track_steal_and_append_trackpoints ( vtl->current_track, tr );
*/
static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gpointer id, gint type )
{
+ // When an item is moved the name is checked to see if it clashes with an existing name
+ // in the destination layer and if so then it is allocated a new name
+
// TODO reconsider strategy when moving within layer (if anything...)
- gboolean rename = ( vtl_src != vtl_dest );
- if ( ! rename )
+ if ( vtl_src == vtl_dest )
return;
if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) {
VikTrack *trk = g_hash_table_lookup ( vtl_src->tracks, id );
- gchar *newname;
- if ( rename )
- newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
- else
- newname = g_strdup ( trk->name );
+ gchar *newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
VikTrack *trk2 = vik_track_copy ( trk, TRUE );
vik_trw_layer_add_track ( vtl_dest, newname, trk2 );
g_free ( newname );
vik_trw_layer_delete_track ( vtl_src, trk );
+ // Reset layer timestamps in case they have now changed
+ vik_treeview_item_set_timestamp ( vtl_dest->vl.vt, &vtl_dest->vl.iter, trw_layer_get_timestamp(vtl_dest) );
+ vik_treeview_item_set_timestamp ( vtl_src->vl.vt, &vtl_src->vl.iter, trw_layer_get_timestamp(vtl_src) );
}
if (type == VIK_TRW_LAYER_SUBLAYER_ROUTE) {
VikTrack *trk = g_hash_table_lookup ( vtl_src->routes, id );
- gchar *newname;
- if ( rename )
- newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
- else
- newname = g_strdup ( trk->name );
+ gchar *newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
VikTrack *trk2 = vik_track_copy ( trk, TRUE );
vik_trw_layer_add_route ( vtl_dest, newname, trk2 );
if (type == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) {
VikWaypoint *wp = g_hash_table_lookup ( vtl_src->waypoints, id );
- gchar *newname;
- if ( rename )
- newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, wp->name );
- else
- newname = g_strdup ( wp->name );
+ gchar *newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, wp->name );
VikWaypoint *wp2 = vik_waypoint_copy ( wp );
vik_trw_layer_add_waypoint ( vtl_dest, newname, wp2 );
// Recalculate bounds even if not renamed as maybe dragged between layers
trw_layer_calculate_bounds_waypoints ( vtl_dest );
trw_layer_calculate_bounds_waypoints ( vtl_src );
+ // Reset layer timestamps in case they have now changed
+ vik_treeview_item_set_timestamp ( vtl_dest->vl.vt, &vtl_dest->vl.iter, trw_layer_get_timestamp(vtl_dest) );
+ vik_treeview_item_set_timestamp ( vtl_src->vl.vt, &vtl_src->vl.iter, trw_layer_get_timestamp(vtl_src) );
}
}
udata.uuid = NULL;
// Hmmm, want key of it
- gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
+ gpointer trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
if ( trkf && udata.uuid ) {
/* could be current_tp, so we have to check */
udata.uuid = NULL;
// Hmmm, want key of it
- gpointer *trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
+ gpointer trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
if ( trkf && udata.uuid ) {
/* could be current_tp, so we have to check */
udata.uuid = NULL;
// Hmmm, want key of it
- gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+ gpointer wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
if ( wpf && udata.uuid ) {
GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
udata.uuid = NULL;
// Hmmm, want key of it
- gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid_by_name, (gpointer) &udata );
+ gpointer wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid_by_name, (gpointer) &udata );
vik_waypoint_free (udata.wp);
udata.uuid = NULL;
// Hmmm, want key of it
- gpointer *trkf = g_hash_table_find ( ht_tracks, (GHRFunc) trw_layer_track_find_uuid_by_name, &udata );
+ gpointer trkf = g_hash_table_find ( ht_tracks, (GHRFunc) trw_layer_track_find_uuid_by_name, &udata );
vik_track_free (udata.trk);
return;
was_visible = trw_layer_delete_waypoint ( vtl, wp );
trw_layer_calculate_bounds_waypoints ( vtl );
+ // Reset layer timestamp in case it has now changed
+ vik_treeview_item_set_timestamp ( vtl->vl.vt, &vtl->vl.iter, trw_layer_get_timestamp(vtl) );
}
}
else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
trk->name ) )
return;
was_visible = vik_trw_layer_delete_track ( vtl, trk );
+ // Reset layer timestamp in case it has now changed
+ vik_treeview_item_set_timestamp ( vtl->vl.vt, &vtl->vl.iter, trw_layer_get_timestamp(vtl) );
}
}
else
udataU.uuid = NULL;
// Need key of it for treeview update
- gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
+ gpointer wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
if ( wpf && udataU.uuid ) {
GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udataU.uuid );
udataU.uuid = NULL;
// Need key of it for treeview update
- gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
+ gpointer wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
if ( wpf && udataU.uuid ) {
GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udataU.uuid );
udata.trk = trk;
udata.uuid = NULL;
- gpointer *trkf = NULL;
+ gpointer trkf = NULL;
if ( trk->is_route )
trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
else
vik_track_anonymize_times ( track );
}
+static void trw_layer_interpolate_times ( menu_array_sublayer values )
+{
+ VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
+ VikTrack *track;
+ if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+ track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
+ else
+ track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
+
+ if ( track )
+ vik_track_interpolate_times ( track );
+}
+
static void trw_layer_extend_track_end ( menu_array_sublayer values )
{
VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
guint threshold = GPOINTER_TO_UINT (((gpointer *)user_data)[2]);
//g_print("Got track named %s, times %d, %d\n", trk->name, p1->timestamp, p2->timestamp);
- if (! (abs(t1 - p2->timestamp) < threshold ||
- /* p1 p2 t1 t2 */
- abs(p1->timestamp - t2) < threshold)
- /* t1 t2 p1 p2 */
- ) {
+ if (! (labs(t1 - p2->timestamp) < threshold ||
+ /* p1 p2 t1 t2 */
+ labs(p1->timestamp - t2) < threshold)
+ /* t1 t2 p1 p2 */
+ ) {
return;
}
}
udata.uuid = NULL;
// Also need id of newly created track
- gpointer *trkf;
+ gpointer trkf;
if ( tr->is_route )
trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
else
}
/**
- * Open a diary at the specified date
+ * Open a program at the specified date
+ * Mainly for RedNotebook - http://rednotebook.sourceforge.net/
+ * But could work with any program that accepts a command line of --date=<date>
+ * FUTURE: Allow configuring of command line options + date format
*/
static void trw_layer_diary_open ( VikTrwLayer *vtl, const gchar *date_str )
{
GError *err = NULL;
- gchar *cmd = g_strdup_printf ( "%s%s", "rednotebook --date=", date_str );
+ gchar *cmd = g_strdup_printf ( "%s %s%s", diary_program, "--date=", date_str );
if ( ! g_spawn_command_line_async ( cmd, &err ) ) {
- a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch %s to open file."), "rednotebook" );
+ a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch %s to open file."), diary_program );
g_error_free ( err );
}
g_free ( cmd );
}
}
+/**
+ * Open a program at the specified date
+ * Mainly for Stellarium - http://stellarium.org/
+ * But could work with any program that accepts the same command line options...
+ * FUTURE: Allow configuring of command line options + format or parameters
+ */
+static void trw_layer_astro_open ( VikTrwLayer *vtl, const gchar *date_str, const gchar *time_str, const gchar *lat_str, const gchar *lon_str, const gchar *alt_str )
+{
+ GError *err = NULL;
+ gchar *tmp;
+ gint fd = g_file_open_tmp ( "vik-astro-XXXXXX.ini", &tmp, &err );
+ if (fd < 0) {
+ g_warning ( "%s: Failed to open temporary file: %s", __FUNCTION__, err->message );
+ g_clear_error ( &err );
+ return;
+ }
+ gchar *cmd = g_strdup_printf ( "%s %s %s %s %s %s %s %s %s %s %s %s %s %s",
+ astro_program, "-c", tmp, "--full-screen no", "--sky-date", date_str, "--sky-time", time_str, "--latitude", lat_str, "--longitude", lon_str, "--altitude", alt_str );
+ g_warning ( "%s", cmd );
+ if ( ! g_spawn_command_line_async ( cmd, &err ) ) {
+ a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch %s"), astro_program );
+ g_warning ( "%s", err->message );
+ g_error_free ( err );
+ }
+ util_add_to_deletion_list ( tmp );
+ g_free ( tmp );
+ g_free ( cmd );
+}
+
+// Format of stellarium lat & lon seems designed to be particularly awkward
+// who uses ' & " in the parameters for the command line?!
+// -1d4'27.48"
+// +53d58'16.65"
+static gchar *convert_to_dms ( gdouble dec )
+{
+ gdouble tmp;
+ gchar sign_c = ' ';
+ gint val_d, val_m;
+ gdouble val_s;
+ gchar *result = NULL;
+
+ if ( dec > 0 )
+ sign_c = '+';
+ else if ( dec < 0 )
+ sign_c = '-';
+ else // Nul value
+ sign_c = ' ';
+
+ // Degrees
+ tmp = fabs(dec);
+ val_d = (gint)tmp;
+
+ // Minutes
+ tmp = (tmp - val_d) * 60;
+ val_m = (gint)tmp;
+
+ // Seconds
+ val_s = (tmp - val_m) * 60;
+
+ // Format
+ result = g_strdup_printf ( "%c%dd%d\\\'%.4f\\\"", sign_c, val_d, val_m, val_s );
+ return result;
+}
+
+/**
+ * Open an astronomy program at the date & position of the track center, trackpoint or waypoint
+ */
+static void trw_layer_astro ( menu_array_sublayer values )
+{
+ VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+
+ if ( GPOINTER_TO_INT(values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
+ VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
+ if ( ! trk )
+ return;
+
+ VikTrackpoint *tp = NULL;
+ if ( vtl->current_tpl )
+ // Current Trackpoint
+ tp = VIK_TRACKPOINT(vtl->current_tpl->data);
+ else if ( trk->trackpoints )
+ // Otherwise first trackpoint
+ tp = VIK_TRACKPOINT(trk->trackpoints->data);
+ else
+ // Give up
+ return;
+
+ if ( tp->has_timestamp ) {
+ gchar date_buf[20];
+ strftime (date_buf, sizeof(date_buf), "%Y%m%d", gmtime(&(tp->timestamp)));
+ gchar time_buf[20];
+ strftime (time_buf, sizeof(time_buf), "%H:%M:%S", gmtime(&(tp->timestamp)));
+ struct LatLon ll;
+ vik_coord_to_latlon ( &tp->coord, &ll );
+ gchar *lat_str = convert_to_dms ( ll.lat );
+ gchar *lon_str = convert_to_dms ( ll.lon );
+ gchar alt_buf[20];
+ snprintf (alt_buf, sizeof(alt_buf), "%d", (gint)round(tp->altitude) );
+ trw_layer_astro_open ( vtl, date_buf, time_buf, lat_str, lon_str, alt_buf);
+ g_free ( lat_str );
+ g_free ( lon_str );
+ }
+ else
+ a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This track has no date information.") );
+ }
+ else if ( GPOINTER_TO_INT(values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
+ VikWaypoint *wpt = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
+ if ( ! wpt )
+ return;
+
+ if ( wpt->has_timestamp ) {
+ gchar date_buf[20];
+ strftime (date_buf, sizeof(date_buf), "%Y%m%d", gmtime(&(wpt->timestamp)));
+ gchar time_buf[20];
+ strftime (time_buf, sizeof(time_buf), "%H:%M:%S", gmtime(&(wpt->timestamp)));
+ struct LatLon ll;
+ vik_coord_to_latlon ( &wpt->coord, &ll );
+ gchar *lat_str = convert_to_dms ( ll.lat );
+ gchar *lon_str = convert_to_dms ( ll.lon );
+ gchar alt_buf[20];
+ snprintf (alt_buf, sizeof(alt_buf), "%d", (gint)round(wpt->altitude) );
+ trw_layer_astro_open ( vtl, date_buf, time_buf, lat_str, lon_str, alt_buf );
+ g_free ( lat_str );
+ g_free ( lon_str );
+ }
+ else
+ a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This waypoint has no date information.") );
+ }
+}
+
/**
* Similar to trw_layer_enum_item, but this uses a sorted method
*/
udataU.uuid = NULL;
// Need want key of it for treeview update
- gpointer *trkf = g_hash_table_find ( track_table, (GHRFunc) trw_layer_track_find_uuid, &udataU );
+ gpointer trkf = g_hash_table_find ( track_table, (GHRFunc) trw_layer_track_find_uuid, &udataU );
if ( trkf && udataU.uuid ) {
if ( it ) {
vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, newname );
if ( ontrack )
- vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->wp_sort_order );
- else
- vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->wp_sort_order );
+ vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->track_sort_order );
+ else
+ vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->track_sort_order );
}
}
+ g_free ( newname );
// Start trying to find same names again...
track_names = NULL;
vik_layers_panel_emit_update ( vlp );
}
-static void trw_layer_sort_order_a2z ( menu_array_sublayer values )
+static void trw_layer_sort_order_specified ( VikTrwLayer *vtl, guint sublayer_type, vik_layer_sort_order_t order )
{
- VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
GtkTreeIter *iter;
- switch (GPOINTER_TO_INT (values[MA_SUBTYPE])) {
+ switch (sublayer_type) {
case VIK_TRW_LAYER_SUBLAYER_TRACKS:
iter = &(vtl->tracks_iter);
- vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
+ vtl->track_sort_order = order;
break;
case VIK_TRW_LAYER_SUBLAYER_ROUTES:
iter = &(vtl->routes_iter);
- vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
+ vtl->track_sort_order = order;
break;
default: // VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
iter = &(vtl->waypoints_iter);
- vtl->wp_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
+ vtl->wp_sort_order = order;
break;
}
- vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_ASCENDING );
+ vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, order );
+}
+
+static void trw_layer_sort_order_a2z ( menu_array_sublayer values )
+{
+ VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+ trw_layer_sort_order_specified ( vtl, GPOINTER_TO_INT(values[MA_SUBTYPE]), VL_SO_ALPHABETICAL_ASCENDING );
}
static void trw_layer_sort_order_z2a ( menu_array_sublayer values )
{
VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
- GtkTreeIter *iter;
+ trw_layer_sort_order_specified ( vtl, GPOINTER_TO_INT(values[MA_SUBTYPE]), VL_SO_ALPHABETICAL_DESCENDING );
+}
- switch (GPOINTER_TO_INT (values[MA_SUBTYPE])) {
- case VIK_TRW_LAYER_SUBLAYER_TRACKS:
- iter = &(vtl->tracks_iter);
- vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
- break;
- case VIK_TRW_LAYER_SUBLAYER_ROUTES:
- iter = &(vtl->routes_iter);
- vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
- break;
- default: // VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
- iter = &(vtl->waypoints_iter);
- vtl->wp_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
- break;
- }
+static void trw_layer_sort_order_timestamp_ascend ( menu_array_sublayer values )
+{
+ VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+ trw_layer_sort_order_specified ( vtl, GPOINTER_TO_INT(values[MA_SUBTYPE]), VL_SO_DATE_ASCENDING );
+}
- vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_DESCENDING );
+static void trw_layer_sort_order_timestamp_descend ( menu_array_sublayer values )
+{
+ VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+ trw_layer_sort_order_specified ( vtl, GPOINTER_TO_INT(values[MA_SUBTYPE]), VL_SO_DATE_DESCENDING );
}
/**
trw_layer_delete_track_by_name (vtl, l->data, vtl->tracks);
}
g_list_free(delete_list);
+ // Reset layer timestamps in case they have now changed
+ vik_treeview_item_set_timestamp ( vtl->vl.vt, &vtl->vl.iter, trw_layer_get_timestamp(vtl) );
+
vik_layer_emit_update( VIK_LAYER(vtl) );
}
}
trw_layer_waypoint_rename ( vtl, waypoint, newname );
+ g_free (newname);
+
// Start trying to find same names again...
waypoint_names = NULL;
g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
g_list_free(delete_list);
trw_layer_calculate_bounds_waypoints ( vtl );
+ // Reset layer timestamp in case it has now changed
+ vik_treeview_item_set_timestamp ( vtl->vl.vt, &vtl->vl.iter, trw_layer_get_timestamp(vtl) );
vik_layer_emit_update( VIK_LAYER(vtl) );
}
return len >= 3 && len <= 7 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5])) && (len < 7 || isalnum(str[6]));
}
+#ifndef WINDOWS
static void trw_layer_track_use_with_filter ( menu_array_sublayer values )
{
VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->tracks, values[MA_SUBLAYER_ID] );
a_acquire_set_filter_track ( trk );
}
+#endif
#ifdef VIK_CONFIG_GOOGLE
static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gpointer track_id )
{
VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->routes, values[MA_SUBLAYER_ID] );
if ( tr ) {
- gchar *escaped = uri_escape ( tr->comment );
+ gchar *escaped = g_uri_escape_string ( tr->comment, NULL, TRUE );
gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped );
open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(values[MA_VTL])), webpage);
g_free ( escaped );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_z2a), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item );
gtk_widget_show ( item );
+
+ item = gtk_image_menu_item_new_with_mnemonic ( _("Date Ascending") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SORT_ASCENDING, GTK_ICON_SIZE_MENU) );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_timestamp_ascend), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item );
+ gtk_widget_show ( item );
+
+ item = gtk_image_menu_item_new_with_mnemonic ( _("Date Descending") );
+ gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SORT_DESCENDING, GTK_ICON_SIZE_MENU) );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_timestamp_descend), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item );
+ gtk_widget_show ( item );
}
GtkWidget *upload_submenu = gtk_menu_new ();
gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
gtk_widget_show ( item );
- // Routes don't have timestamps - so this is only available for tracks
+ // Routes don't have timestamps - so these are only available for tracks
if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
item = gtk_image_menu_item_new_with_mnemonic ( _("_Anonymize Times") );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_anonymize_times), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
gtk_widget_set_tooltip_text (item, _("Shift timestamps to a relative offset from 1901-01-01"));
gtk_widget_show ( item );
+
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Interpolate Times") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_interpolate_times), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
+ gtk_widget_set_tooltip_text (item, _("Reset trackpoint timestamps between the first and last points such that track is traveled at equal speed"));
+ gtk_widget_show ( item );
}
if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
}
}
- // Only made available if a suitable program is installed
- if ( have_diary_program ) {
- if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
- item = gtk_image_menu_item_new_with_mnemonic ( _("Diar_y") );
+ GtkWidget *external_submenu = create_external_submenu ( menu );
+
+ // These are only made available if a suitable program is installed
+ if ( (have_astro_program || have_diary_program) &&
+ (subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) ) {
+
+ if ( have_diary_program ) {
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Diary") );
gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SPELL_CHECK, GTK_ICON_SIZE_MENU) );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_diary), pass_along );
- gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(external_submenu), item );
+ gtk_widget_set_tooltip_text (item, _("Open diary program at this date"));
+ gtk_widget_show ( item );
+ }
+
+ if ( have_astro_program ) {
+ item = gtk_image_menu_item_new_with_mnemonic ( _("_Astronomy") );
+ g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_astro), pass_along );
+ gtk_menu_shell_append ( GTK_MENU_SHELL(external_submenu), item );
+ gtk_widget_set_tooltip_text (item, _("Open astronomy program at this date and location"));
gtk_widget_show ( item );
}
}
+ if ( l->current_tpl || l->current_wp ) {
+ // For the selected point
+ VikCoord *vc;
+ if ( l->current_tpl )
+ vc = &(VIK_TRACKPOINT(l->current_tpl->data)->coord);
+ else
+ vc = &(l->current_wp->coord);
+ vik_ext_tools_add_menu_items_to_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l)), GTK_MENU (external_submenu), vc );
+ }
+ else {
+ // Otherwise for the selected sublayer
+ // TODO: Should use selected items centre - rather than implicitly using the current viewport
+ vik_ext_tools_add_menu_items_to_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l)), GTK_MENU (external_submenu), NULL );
+ }
+
+
#ifdef VIK_CONFIG_GOOGLE
if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && is_valid_google_route ( l, sublayer ) )
{
gtk_widget_show ( item );
#endif
+ // Currently filter with functions all use shellcommands and thus don't work in Windows
+#ifndef WINDOWS
item = gtk_image_menu_item_new_with_mnemonic ( _("Use with _Filter") );
gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_use_with_filter), pass_along );
gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
gtk_widget_show ( item );
+#endif
/* ATM This function is only available via the layers panel, due to needing a vlp */
if ( vlp ) {
gint x, y;
gint closest_x, closest_y;
gboolean draw_images;
- gpointer *closest_wp_id;
+ gpointer closest_wp_id;
VikWaypoint *closest_wp;
VikViewport *vvp;
} WPSearchParams;
udataU.trk = track;
udataU.uuid = NULL;
- gpointer *trkf;
+ gpointer trkf;
if ( track->is_route )
trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udataU );
else
udata.wp = waypoint;
udata.uuid = NULL;
- gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+ 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 );
gint x, y;
vik_viewport_coord_to_screen ( vvp, &(vtl->current_wp->coord), &x, &y );
- if ( abs(x - event->x) <= WAYPOINT_SIZE_APPROX &&
- abs(y - event->y) <= WAYPOINT_SIZE_APPROX )
+ if ( abs(x - (int)round(event->x)) <= WAYPOINT_SIZE_APPROX &&
+ abs(y - (int)round(event->y)) <= WAYPOINT_SIZE_APPROX )
{
if ( event->button == 3 )
vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
return FALSE;
vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
- if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible) {
+ if ( vik_trw_layer_new_waypoint (vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord) ) {
trw_layer_calculate_bounds_waypoints ( vtl );
- vik_layer_emit_update ( VIK_LAYER(vtl) );
+ if ( VIK_LAYER(vtl)->visible )
+ vik_layer_emit_update ( VIK_LAYER(vtl) );
}
return TRUE;
}
g_free ( t );
}
+/**
+ * tool_edit_trackpoint_click:
+ *
+ * On 'initial' click: search for the nearest trackpoint or routepoint and store it as the current trackpoint
+ * Then update the viewport, statusbar and edit dialog to draw the point as being selected and it's information.
+ * On subsequent clicks: (as the current trackpoint is defined) and the click is very near the same point
+ * then initiate the move operation to drag the point to a new destination.
+ * NB The current trackpoint will get reset elsewhere.
+ */
static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
{
tool_ed_t *t = data;
VikViewport *vvp = t->vvp;
TPSearchParams params;
- /* OUTDATED DOCUMENTATION:
- find 5 pixel range on each side. then put these UTM, and a pointer
- to the winning track name (and maybe the winning track itself), and a
- pointer to the winning trackpoint, inside an array or struct. pass
- this along, do a foreach on the tracks which will do a foreach on the
- trackpoints. */
params.vvp = vvp;
params.x = event->x;
params.y = event->y;
params.closest_track_id = NULL;
- /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
params.closest_tp = NULL;
params.closest_tpl = NULL;
vik_viewport_get_min_max_lat_lon ( vvp, &(params.bbox.south), &(params.bbox.north), &(params.bbox.west), &(params.bbox.east) );
if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
return FALSE;
- if ( !vtl->vl.visible || !vtl->tracks_visible || !vtl->routes_visible )
+ if ( !vtl->vl.visible || !(vtl->tracks_visible || vtl->routes_visible) )
return FALSE;
if ( vtl->current_tpl )
/* first check if it is within range of prev. tp. and if current_tp track is shown. (if it is, we are moving that trackpoint.) */
VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_id));
+ if ( !current_tr )
+ current_tr = VIK_TRACK(g_hash_table_lookup(vtl->routes, vtl->current_tp_id));
if ( !current_tr )
return FALSE;
vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y );
if ( current_tr->visible &&
- abs(x - event->x) < TRACKPOINT_SIZE_APPROX &&
- abs(y - event->y) < TRACKPOINT_SIZE_APPROX ) {
+ abs(x - (int)round(event->x)) < TRACKPOINT_SIZE_APPROX &&
+ abs(y - (int)round(event->y)) < TRACKPOINT_SIZE_APPROX ) {
marker_begin_move ( t, event->x, event->y );
return TRUE;
}
/* diff dist is diff from orig */
if ( vtl->tpwin )
- my_tpwin_set_tp ( vtl );
+ if ( vtl->current_tp_track )
+ my_tpwin_set_tp ( vtl );
vik_layer_emit_update ( VIK_LAYER(vtl) );
return TRUE;
thumbnail_create_thread_data *tctd = g_malloc ( sizeof(thumbnail_create_thread_data) );
tctd->vtl = vtl;
tctd->pics = pics;
- a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+ a_background_thread ( BACKGROUND_POOL_LOCAL,
+ VIK_GTK_WINDOW_FROM_LAYER(vtl),
tmp,
(vik_thr_func) create_thumbnails_thread,
tctd,
vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order );
}
+/**
+ * Get the earliest timestamp available from all tracks
+ */
+static time_t trw_layer_get_timestamp_tracks ( VikTrwLayer *vtl )
+{
+ time_t timestamp = 0;
+ GList *gl = g_hash_table_get_values ( vtl->tracks );
+ gl = g_list_sort ( gl, vik_track_compare_timestamp );
+ gl = g_list_first ( gl );
+
+ if ( gl ) {
+ // Only need to check the first track as they have been sorted by time
+ VikTrack *trk = (VikTrack*)gl->data;
+ // Assume trackpoints already sorted by time
+ VikTrackpoint *tpt = vik_track_get_tp_first(trk);
+ if ( tpt && tpt->has_timestamp ) {
+ timestamp = tpt->timestamp;
+ }
+ g_list_free ( gl );
+ }
+ return timestamp;
+}
+
+/**
+ * Get the earliest timestamp available from all waypoints
+ */
+static time_t trw_layer_get_timestamp_waypoints ( VikTrwLayer *vtl )
+{
+ time_t timestamp = 0;
+ GList *gl = g_hash_table_get_values ( vtl->waypoints );
+ GList *iter;
+ for (iter = g_list_first (gl); iter != NULL; iter = g_list_next (iter)) {
+ VikWaypoint *wpt = (VikWaypoint*)iter->data;
+ if ( wpt->has_timestamp ) {
+ // When timestamp not set yet - use the first value encountered
+ if ( timestamp == 0 )
+ timestamp = wpt->timestamp;
+ else if ( timestamp > wpt->timestamp )
+ timestamp = wpt->timestamp;
+ }
+ }
+ g_list_free ( gl );
+
+ return timestamp;
+}
+
+/**
+ * Get the earliest timestamp available for this layer
+ */
+static time_t trw_layer_get_timestamp ( VikTrwLayer *vtl )
+{
+ time_t timestamp_tracks = trw_layer_get_timestamp_tracks ( vtl );
+ time_t timestamp_waypoints = trw_layer_get_timestamp_waypoints ( vtl );
+ // NB routes don't have timestamps - hence they are not considered
+
+ if ( !timestamp_tracks && !timestamp_waypoints ) {
+ // Fallback to get time from the metadata when no other timestamps available
+ GTimeVal gtv;
+ if ( vtl->metadata && vtl->metadata->timestamp && g_time_val_from_iso8601 ( vtl->metadata->timestamp, >v ) )
+ return gtv.tv_sec;
+ }
+ if ( timestamp_tracks && !timestamp_waypoints )
+ return timestamp_tracks;
+ if ( timestamp_tracks && timestamp_waypoints && (timestamp_tracks < timestamp_waypoints) )
+ return timestamp_tracks;
+ return timestamp_waypoints;
+}
+
static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file )
{
if ( VIK_LAYER(vtl)->realized )
}
if ( need_to_set_time ) {
- // Could rewrite this as a general get first time of a TRW Layer function
GTimeVal timestamp;
timestamp.tv_usec = 0;
- gboolean has_timestamp = FALSE;
-
- GList *gl = NULL;
- gl = g_hash_table_get_values ( vtl->tracks );
- gl = g_list_sort ( gl, vik_track_compare_timestamp );
- gl = g_list_first ( gl );
-
- // Check times of tracks
- if ( gl ) {
- // Only need to check the first track as they have been sorted by time
- VikTrack *trk = (VikTrack*)gl->data;
- // Assume trackpoints already sorted by time
- VikTrackpoint *tpt = vik_track_get_tp_first(trk);
- if ( tpt && tpt->has_timestamp ) {
- timestamp.tv_sec = tpt->timestamp;
- has_timestamp = TRUE;
- }
- g_list_free ( gl );
- }
+ timestamp.tv_sec = trw_layer_get_timestamp ( vtl );
- if ( !has_timestamp ) {
- // 'Last' resort - current time
- // Get before waypoint tests - so that if a waypoint time value (in the past) is found it should be used
+ // No time found - so use 'now' for the metadata time
+ if ( timestamp.tv_sec == 0 ) {
g_get_current_time ( ×tamp );
-
- // Check times of waypoints
- gl = g_hash_table_get_values ( vtl->waypoints );
- GList *iter;
- for (iter = g_list_first (gl); iter != NULL; iter = g_list_next (iter)) {
- VikWaypoint *wpt = (VikWaypoint*)iter->data;
- if ( wpt->has_timestamp ) {
- if ( timestamp.tv_sec > wpt->timestamp ) {
- timestamp.tv_sec = wpt->timestamp;
- has_timestamp = TRUE;
- }
- }
- }
- g_list_free ( gl );
}
vtl->metadata->timestamp = g_time_val_to_iso8601 ( ×tamp );
}
// Convert from list of vmls to list of names. Allowing the user to select one of them
- gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer));
- VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer));
+ gchar **map_names = g_malloc_n(1 + num_maps, sizeof(gpointer));
+ VikMapsLayer **map_layers = g_malloc_n(1 + num_maps, sizeof(gpointer));
gchar **np = map_names;
VikMapsLayer **lp = map_layers;