X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/8c4f1350d63e7d8bee903123eed8a48263787265..812909d1812d7f659f21963eda01078b57e05430:/src/viktrwlayer.c?ds=sidebyside diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index c30fe042..9e338ad3 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -28,14 +28,17 @@ #include "viktrwlayer_pixmap.h" #include "viktrwlayer_tpwin.h" #include "viktrwlayer_propwin.h" +#include "garminsymbols.h" #include "thumbnails.h" #include "background.h" +#include "gpx.h" #include #include #include #include +#define GOOGLE_DIRECTIONS_STRING "(wget -O - \"http://maps.google.com/maps?q=%f,%f to %f,%f&output=js\" 2>/dev/null)" #define VIK_TRW_LAYER_TRACK_GC 13 #define VIK_TRW_LAYER_TRACK_GC_RATES 10 #define VIK_TRW_LAYER_TRACK_GC_MIN 0 @@ -53,6 +56,10 @@ #define TRACKPOINT_SIZE_APPROX 5 #define WAYPOINT_SIZE_APPROX 5 +#define MIN_STOP_LENGTH 15 +#define MAX_STOP_LENGTH 86400 +#define DRAW_ELEVATION_FACTOR 30 /* height of elevation plotting, sort of relative to zoom level ("mpp" that isn't mpp necessarily) */ + /* this is multiplied by user-inputted value from 1-100. */ enum { VIK_TRW_LAYER_SUBLAYER_TRACKS, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, @@ -72,12 +79,17 @@ struct _VikTrwLayer { gboolean tracks_visible, waypoints_visible; guint8 drawmode; guint8 drawpoints; + guint8 drawelevation; + guint8 elevation_factor; + guint8 drawstops; + guint32 stop_length; guint8 drawlines; guint8 line_thickness; guint8 bg_line_thickness; guint8 wp_symbol; guint8 wp_size; + gboolean wp_draw_symbols; gdouble velocity_min, velocity_max; GArray *track_gc; @@ -110,6 +122,10 @@ struct _VikTrwLayer { /* track editing tool -- more specifically, moving tps */ gboolean moving_tp; + /* magic scissors tool */ + gboolean magic_scissors_started; + VikCoord magic_scissors_coord; + gboolean drawlabels; gboolean drawimages; guint8 image_alpha; @@ -124,6 +140,9 @@ struct _VikTrwLayer { GtkMenu *wp_right_click_menu; + /* menu */ + VikStdLayerMenuItem menu_selection; + }; /* A caached waypoint image. */ @@ -143,6 +162,13 @@ struct DrawingParams { gdouble ce1, ce2, cn1, cn2; }; +static void vik_trw_layer_set_menu_selection(VikTrwLayer *vtl, guint16); +static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl); + +static void trw_layer_delete_item ( gpointer *pass_along ); +static void trw_layer_copy_item_cb( gpointer *pass_along); +static void trw_layer_cut_item_cb( gpointer *pass_along); + static void trw_layer_find_maxmin_waypoints ( const gchar *name, const VikWaypoint *w, struct LatLon maxmin[2] ); static void trw_layer_find_maxmin_tracks ( const gchar *name, GList **t, struct LatLon maxmin[2] ); @@ -172,28 +198,43 @@ static void trw_layer_realize_waypoint ( gchar *name, VikWaypoint *wp, gpointer static void trw_layer_realize_track ( gchar *name, VikTrack *track, gpointer pass_along[4] ); static void init_drawing_params ( struct DrawingParams *dp, VikViewport *vp ); -static gboolean tool_new_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); -static gboolean tool_new_track ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp ); +static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len ); +static VikTrwLayer *trw_layer_unmarshall( gpointer data, gint len, VikViewport *vvp ); + static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp ); static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id ); -static gpointer trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer ); -static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, gpointer item ); +static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer ); +static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len ); +static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len ); static void trw_layer_free_copied_item ( gint subtype, gpointer item ); +static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path ); static void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, const gchar *trk_name ); static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl ); static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy ); static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ); static void trw_layer_tpwin_init ( VikTrwLayer *vtl ); -static gboolean tool_edit_trackpoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); -static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); -static gboolean tool_show_picture ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); -static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); -static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); +static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp); +static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); +static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); +static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); +static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp); +static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); +static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp); +static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); +static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); +static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ); +static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp); +static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *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 ); +static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp); +static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); + static gboolean uppercase_exists_in_hash ( GHashTable *hash, const gchar *str ); @@ -206,14 +247,33 @@ static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikVie static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode ); +static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name); +static void waypoint_convert ( const gchar *name, VikWaypoint *wp, VikCoordMode *dest_mode ); +static void track_convert ( const gchar *name, VikTrack *tr, VikCoordMode *dest_mode ); + static VikToolInterface trw_layer_tools[] = { - { "Create Waypoint", (VikToolInterfaceFunc) tool_new_waypoint, NULL }, - { "Create Track", (VikToolInterfaceFunc) tool_new_track, NULL }, - { "Edit Waypoint", (VikToolInterfaceFunc) tool_edit_waypoint, (VikToolInterfaceFunc) tool_edit_waypoint_release }, - { "Edit Trackpoint", (VikToolInterfaceFunc) tool_edit_trackpoint, (VikToolInterfaceFunc) tool_edit_trackpoint_release }, - { "Show Picture", (VikToolInterfaceFunc) tool_show_picture, NULL }, -}; + { "Create Waypoint", (VikToolConstructorFunc) tool_new_waypoint_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_new_waypoint_click, NULL, NULL }, + { "Create Track", (VikToolConstructorFunc) tool_new_track_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_new_track_click, NULL, NULL }, + + { "Edit Waypoint", (VikToolConstructorFunc) tool_edit_waypoint_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_edit_waypoint_click, + (VikToolMouseFunc) tool_edit_waypoint_move, + (VikToolMouseFunc) tool_edit_waypoint_release }, + + { "Edit Trackpoint", (VikToolConstructorFunc) tool_edit_trackpoint_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_edit_trackpoint_click, + (VikToolMouseFunc) tool_edit_trackpoint_move, + (VikToolMouseFunc) tool_edit_trackpoint_release }, + + { "Show Picture", (VikToolConstructorFunc) tool_show_picture_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_show_picture_click, NULL, NULL }, + + { "Magic Scissors", (VikToolConstructorFunc) tool_magic_scissors_create, NULL, NULL, NULL, + (VikToolMouseFunc) tool_magic_scissors_click, NULL, NULL }, +}; /****** PARAMETERS ******/ @@ -223,6 +283,7 @@ enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES }; static gchar *params_drawmodes[] = { "Draw by Track", "Draw by Velocity", "All Tracks Black", 0 }; static gchar *params_wpsymbols[] = { "Filled Square", "Square", "Circle", "X", 0 }; + static VikLayerParamScale params_scales[] = { /* min max step digits */ { 1, 10, 1, 0 }, /* line_thickness */ @@ -234,15 +295,23 @@ static VikLayerParamScale params_scales[] = { { 5, 500, 5, 0 }, /* image cache_size */ { 0, 8, 1, 0 }, /* image cache_size */ { 1, 64, 1, 0 }, /* wpsize */ + { MIN_STOP_LENGTH, MAX_STOP_LENGTH, 1, 0 }, /* stop_length */ + { 1, 100, 1, 0 }, /* stop_length */ }; VikLayerParam trw_layer_params[] = { { "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES }, { "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES }, - { "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Track Drawing Mode:", VIK_LAYER_WIDGET_RADIOGROUP, params_drawmodes }, + { "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Track Drawing Mode:", VIK_LAYER_WIDGET_RADIOGROUP, NULL }, { "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, "Draw Track Lines", VIK_LAYER_WIDGET_CHECKBUTTON }, { "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, "Draw Trackpoints", VIK_LAYER_WIDGET_CHECKBUTTON }, + { "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, "Draw Elevation", VIK_LAYER_WIDGET_CHECKBUTTON }, + { "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Draw Elevation Height %:", VIK_LAYER_WIDGET_HSCALE, params_scales + 9 }, + + { "drawstops", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, "Draw Stops", VIK_LAYER_WIDGET_CHECKBUTTON }, + { "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Min Stop Length (seconds):", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 8 }, + { "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Track Thickness:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 0 }, { "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, "Track BG Thickness:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 6 }, { "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, "Track Background Color", VIK_LAYER_WIDGET_COLOR, 0 }, @@ -254,8 +323,9 @@ VikLayerParam trw_layer_params[] = { { "wptextcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, "Waypoint Text:", VIK_LAYER_WIDGET_COLOR, 0 }, { "wpbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, "Background:", VIK_LAYER_WIDGET_COLOR, 0 }, { "wpbgand", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, "Fake BG Color Translucency:", VIK_LAYER_WIDGET_CHECKBUTTON, 0 }, - { "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, "Waypoint symbol:", VIK_LAYER_WIDGET_RADIOGROUP, params_wpsymbols }, + { "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, "Waypoint marker:", VIK_LAYER_WIDGET_RADIOGROUP, NULL }, { "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, "Waypoint size:", VIK_LAYER_WIDGET_SPINBUTTON, params_scales + 7 }, + { "wpsyms", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, "Draw Waypoint Symbols:", VIK_LAYER_WIDGET_CHECKBUTTON }, { "drawimages", VIK_LAYER_PARAM_BOOLEAN, GROUP_IMAGES, "Draw Waypoint Images", VIK_LAYER_WIDGET_CHECKBUTTON }, { "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, "Image Size (pixels):", VIK_LAYER_WIDGET_HSCALE, params_scales + 3 }, @@ -263,7 +333,7 @@ VikLayerParam trw_layer_params[] = { { "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, "Image Memory Cache Size:", VIK_LAYER_WIDGET_HSCALE, params_scales + 5 }, }; -enum { PARAM_TV, PARAM_WV, PARAM_DM, PARAM_DL, PARAM_DP, PARAM_LT, PARAM_BLT, PARAM_TBGC, PARAM_VMIN, PARAM_VMAX, PARAM_DLA, PARAM_WPC, PARAM_WPTC, PARAM_WPBC, PARAM_WPBA, PARAM_WPSYM, PARAM_WPSIZE, PARAM_DI, PARAM_IS, PARAM_IA, PARAM_ICS, NUM_PARAMS }; +enum { PARAM_TV, PARAM_WV, PARAM_DM, PARAM_DL, PARAM_DP, PARAM_DE, PARAM_EF, PARAM_DS, PARAM_SL, PARAM_LT, PARAM_BLT, PARAM_TBGC, PARAM_VMIN, PARAM_VMAX, PARAM_DLA, PARAM_WPC, PARAM_WPTC, PARAM_WPBC, PARAM_WPBA, PARAM_WPSYM, PARAM_WPSIZE, PARAM_WPSYMS, PARAM_DI, PARAM_IS, PARAM_IA, PARAM_ICS, NUM_PARAMS }; /****** END PARAMETERS ******/ @@ -279,6 +349,8 @@ VikLayerInterface vik_trw_layer_interface = { params_groups, /* params_groups */ sizeof(params_groups)/sizeof(params_groups[0]), /* number of groups */ + VIK_MENU_ITEM_ALL, + (VikLayerFuncCreate) vik_trw_layer_create, (VikLayerFuncRealize) vik_trw_layer_realize, (VikLayerFuncPostRead) trw_layer_verify_thumbnails, @@ -288,6 +360,9 @@ VikLayerInterface vik_trw_layer_interface = { (VikLayerFuncDraw) vik_trw_layer_draw, (VikLayerFuncChangeCoordMode) trw_layer_change_coord_mode, + (VikLayerFuncSetMenuItemsSelection) vik_trw_layer_set_menu_selection, + (VikLayerFuncGetMenuItemsSelection) vik_trw_layer_get_menu_selection, + (VikLayerFuncAddMenuItems) vik_trw_layer_add_menu_items, (VikLayerFuncSublayerAddMenuItems) vik_trw_layer_sublayer_add_menu_items, @@ -295,6 +370,8 @@ VikLayerInterface vik_trw_layer_interface = { (VikLayerFuncSublayerToggleVisible) vik_trw_layer_sublayer_toggle_visible, (VikLayerFuncCopy) trw_layer_copy, + (VikLayerFuncMarshall) trw_layer_marshall, + (VikLayerFuncUnmarshall) trw_layer_unmarshall, (VikLayerFuncSetParam) trw_layer_set_param, (VikLayerFuncGetParam) trw_layer_get_param, @@ -302,21 +379,21 @@ VikLayerInterface vik_trw_layer_interface = { (VikLayerFuncReadFileData) a_gpspoint_read_file, (VikLayerFuncWriteFileData) a_gpspoint_write_file, + (VikLayerFuncDeleteItem) trw_layer_del_item, (VikLayerFuncCopyItem) trw_layer_copy_item, (VikLayerFuncPasteItem) trw_layer_paste_item, (VikLayerFuncFreeCopiedItem) trw_layer_free_copied_item, + + (VikLayerFuncDragDropRequest) trw_layer_drag_drop_request, }; /* for copy & paste (I think?) */ typedef struct { - gchar *name; - VikWaypoint *wp; -} NamedWaypoint; - -typedef struct { - gchar *name; - VikTrack *tr; -} NamedTrack; + guint len; + guint8 data[0]; + // gchar *name; + // VikWaypoint *wp; +} FlatItem; GType vik_trw_layer_get_type () { @@ -342,39 +419,95 @@ GType vik_trw_layer_get_type () return vtl_type; } +static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer ) +{ + static gpointer pass_along[5]; + if (!sublayer) { + return; + } + + pass_along[0] = vtl; + pass_along[1] = NULL; + pass_along[2] = (gpointer) subtype; + pass_along[3] = sublayer; + pass_along[4] = NULL; + + trw_layer_delete_item ( pass_along ); +} + +static void trw_layer_copy_item_cb( gpointer pass_along[5]) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + gint subtype = (gint)pass_along[2]; + gpointer * sublayer = pass_along[3]; + guint8 *data = NULL; + guint len; + + trw_layer_copy_item( vtl, subtype, sublayer, &data, &len); + + if (data) { + a_clipboard_copy( VIK_CLIPBOARD_DATA_SUBLAYER, VIK_LAYER_TRW, + subtype, len, data); + } +} + +static void trw_layer_cut_item_cb( gpointer pass_along[5]) +{ + trw_layer_copy_item_cb(pass_along); + trw_layer_delete_item(pass_along); +} -static gpointer trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer ) +static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len ) { - if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && sublayer ) - { - NamedWaypoint *nw = g_malloc ( sizeof ( NamedWaypoint ) ); - nw->name = g_strdup(sublayer); - nw->wp = vik_waypoint_copy ( g_hash_table_lookup ( vtl->waypoints, sublayer ) ); - return nw; + FlatItem *fi; + guint8 *id; + guint il; + + fprintf(stderr, "%s:%s() called\n", __FILE__, __PRETTY_FUNCTION__); + if (!sublayer) { + *item = NULL; + return; } - if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && sublayer ) + + if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { - NamedTrack *nt = g_malloc ( sizeof ( NamedTrack ) ); - nt->name = g_strdup(sublayer); - nt->tr = g_hash_table_lookup ( vtl->tracks, sublayer ); - vik_track_ref(nt->tr); - return nt; + vik_waypoint_marshall ( g_hash_table_lookup ( vtl->waypoints, sublayer ), &id, &il ); + } else { + vik_track_marshall ( g_hash_table_lookup ( vtl->tracks, sublayer ), &id, &il ); } - return NULL; + + *len = sizeof(FlatItem) + strlen(sublayer) + 1 + il; + fi = g_malloc ( *len ); + fi->len = strlen(sublayer) + 1; + memcpy(fi->data, sublayer, fi->len); + memcpy(fi->data + fi->len, id, il); + g_free(id); + *item = (guint8 *)fi; } -static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, gpointer item ) +static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len ) { - if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && item ) + FlatItem *fi = (FlatItem *) item; + + if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && fi ) { - NamedWaypoint *nw = (NamedWaypoint *) item; - vik_trw_layer_add_waypoint ( vtl, g_strdup(nw->name), vik_waypoint_copy(nw->wp) ); + VikWaypoint *w; + gchar *name; + + name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, (gchar *)fi->data); + w = vik_waypoint_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len); + vik_trw_layer_add_waypoint ( vtl, name, w ); + waypoint_convert(name, w, &vtl->coord_mode); return TRUE; } - if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && item ) + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && fi ) { - NamedTrack *nt = (NamedTrack *) item; - vik_trw_layer_add_track ( vtl, g_strdup(nt->name), vik_track_copy(nt->tr) ); + VikTrack *t; + gchar *name; + name = get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, (gchar *)fi->data); + t = vik_track_unmarshall(fi->data + fi->len, len - sizeof(*fi) - fi->len); + vik_trw_layer_add_track ( vtl, name, t ); + track_convert(name, t, &vtl->coord_mode); return TRUE; } return FALSE; @@ -382,19 +515,8 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, gpointer static void trw_layer_free_copied_item ( gint subtype, gpointer item ) { - if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT && item ) - { - NamedWaypoint *nw = (NamedWaypoint *) item; - g_free ( nw->name ); - vik_waypoint_free ( nw->wp ); - g_free ( nw ); - } - if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && item ) - { - NamedTrack *nt = (NamedTrack *) item; - g_free ( nt->name ); - vik_track_free ( nt->tr ); - g_free ( nt ); + if (item) { + g_free(item); } } @@ -411,7 +533,15 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara case PARAM_WV: vtl->waypoints_visible = data.b; break; case PARAM_DM: vtl->drawmode = data.u; break; case PARAM_DP: vtl->drawpoints = data.b; break; + case PARAM_DE: vtl->drawelevation = data.b; break; + case PARAM_DS: vtl->drawstops = data.b; break; case PARAM_DL: vtl->drawlines = data.b; break; + case PARAM_SL: if ( data.u >= MIN_STOP_LENGTH && data.u <= MAX_STOP_LENGTH ) + vtl->stop_length = data.u; + break; + case PARAM_EF: if ( data.u >= 1 && data.u <= 100 ) + vtl->elevation_factor = data.u; + break; case PARAM_LT: if ( data.u > 0 && data.u < 15 && data.u != vtl->line_thickness ) { vtl->line_thickness = data.u; @@ -448,6 +578,7 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara case PARAM_WPBA: gdk_gc_set_function(vtl->waypoint_bg_gc, data.b ? GDK_AND : GDK_COPY ); break; case PARAM_WPSYM: if ( data.u < WP_NUM_SYMBOLS ) vtl->wp_symbol = data.u; break; case PARAM_WPSIZE: if ( data.u > 0 && data.u <= 64 ) vtl->wp_size = data.u; break; + case PARAM_WPSYMS: vtl->wp_draw_symbols = data.b; break; } return TRUE; } @@ -461,6 +592,10 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id ) case PARAM_WV: rv.b = vtl->waypoints_visible; break; case PARAM_DM: rv.u = vtl->drawmode; break; case PARAM_DP: rv.b = vtl->drawpoints; break; + case PARAM_DE: rv.b = vtl->drawelevation; break; + case PARAM_EF: rv.u = vtl->elevation_factor; break; + case PARAM_DS: rv.b = vtl->drawstops; break; + case PARAM_SL: rv.u = vtl->stop_length; break; case PARAM_DL: rv.b = vtl->drawlines; break; case PARAM_LT: rv.u = vtl->line_thickness; break; case PARAM_BLT: rv.u = vtl->bg_line_thickness; break; @@ -478,6 +613,7 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id ) case PARAM_WPBA: rv.b = (vik_gc_get_function(vtl->waypoint_bg_gc)==GDK_AND); break; case PARAM_WPSYM: rv.u = vtl->wp_symbol; break; case PARAM_WPSIZE: rv.u = vtl->wp_size; break; + case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break; } return rv; } @@ -487,6 +623,59 @@ static void track_copy ( const gchar *name, VikTrack *tr, GHashTable *dest ) g_hash_table_insert ( dest, g_strdup ( name ), vik_track_copy(tr) ); } +static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len ) +{ + guint8 *pd, *dd; + gint pl, dl; + gchar *tmpname; + FILE *f; + + *data = NULL; + + if ((f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) { + a_gpx_write_file(vtl, f); + vik_layer_marshall_params(VIK_LAYER(vtl), &pd, &pl); + fclose(f); + g_file_get_contents(tmpname, (void *)&dd, (void *)&dl, NULL); + *len = sizeof(pl) + pl + dl; + *data = g_malloc(*len); + memcpy(*data, &pl, sizeof(pl)); + memcpy(*data + sizeof(pl), pd, pl); + memcpy(*data + sizeof(pl) + pl, dd, dl); + + g_free(pd); + g_free(dd); + remove(tmpname); + g_free(tmpname); + } +} + +static VikTrwLayer *trw_layer_unmarshall( gpointer data, gint len, VikViewport *vvp ) +{ + VikTrwLayer *rv = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, NULL, FALSE )); + guint pl; + gchar *tmpname; + FILE *f; + + + memcpy(&pl, data, sizeof(pl)); + data += sizeof(pl); + vik_layer_unmarshall_params ( VIK_LAYER(rv), data, pl, vvp ); + data += pl; + + if (!(f = fdopen(g_file_open_tmp (NULL, &tmpname, NULL), "r+"))) { + g_critical("couldn't open temp file\n"); + exit(1); + } + fwrite(data, len - pl - sizeof(pl), 1, f); + rewind(f); + a_gpx_read_file(rv, f); + fclose(f); + remove(tmpname); + g_free(tmpname); + return rv; +} + static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp ) { VikTrwLayer *rv = vik_trw_layer_new ( vtl->drawmode ); @@ -500,7 +689,11 @@ static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp ) rv->tracks_visible = vtl->tracks_visible; rv->waypoints_visible = vtl->waypoints_visible; rv->drawpoints = vtl->drawpoints; + rv->drawstops = vtl->drawstops; + rv->drawelevation = vtl->drawelevation; + rv->elevation_factor = vtl->elevation_factor; rv->drawlines = vtl->drawlines; + rv->stop_length = vtl->stop_length; rv->line_thickness = vtl->line_thickness; rv->bg_line_thickness = vtl->bg_line_thickness; rv->velocity_min = vtl->velocity_min; @@ -514,6 +707,7 @@ static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp ) rv->coord_mode = vtl->coord_mode; rv->wp_symbol = vtl->wp_symbol; rv->wp_size = vtl->wp_size; + rv->wp_draw_symbols = vtl->wp_draw_symbols; trw_layer_new_track_gcs ( rv, VIK_VIEWPORT(vp) ); @@ -534,8 +728,22 @@ static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp ) return rv; } +static GList * a_array_to_glist(gpointer data[]) +{ + GList *gl = NULL; + gpointer * p; + for (p = data; *p; p++) + gl = g_list_prepend(gl, *p); + return(g_list_reverse(gl)); +} + VikTrwLayer *vik_trw_layer_new ( gint drawmode ) { + if (trw_layer_params[PARAM_DM].widget_data == NULL) + trw_layer_params[PARAM_DM].widget_data = a_array_to_glist(params_drawmodes); + if (trw_layer_params[PARAM_WPSYM].widget_data == NULL) + trw_layer_params[PARAM_WPSYM].widget_data = a_array_to_glist(params_wpsymbols); + VikTrwLayer *rv = VIK_TRW_LAYER ( g_object_new ( VIK_TRW_LAYER_TYPE, NULL ) ); vik_layer_init ( VIK_LAYER(rv), VIK_LAYER_TRW ); @@ -548,6 +756,10 @@ VikTrwLayer *vik_trw_layer_new ( gint drawmode ) rv->waypoints_visible = rv->tracks_visible = TRUE; rv->drawmode = drawmode; rv->drawpoints = TRUE; + rv->drawstops = FALSE; + rv->drawelevation = FALSE; + rv->elevation_factor = 30; + rv->stop_length = 60; rv->drawlines = TRUE; rv->wplabellayout = NULL; rv->wp_right_click_menu = NULL; @@ -558,7 +770,7 @@ VikTrwLayer *vik_trw_layer_new ( gint drawmode ) rv->velocity_max = 5.0; rv->velocity_min = 0.0; rv->line_thickness = 1; - rv->line_thickness = 0; + rv->bg_line_thickness = 0; rv->current_wp = NULL; rv->current_wp_name = NULL; rv->current_track = NULL; @@ -566,6 +778,9 @@ VikTrwLayer *vik_trw_layer_new ( gint drawmode ) rv->current_tp_track_name = NULL; rv->moving_tp = FALSE; rv->moving_wp = FALSE; + + rv->magic_scissors_started = FALSE; + rv->waypoint_rightclick = FALSE; rv->last_tpl = NULL; rv->last_tp_track_name = NULL; @@ -688,11 +903,21 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr gboolean useoldvals = TRUE; gboolean drawpoints; + gboolean drawstops; + gboolean drawelevation; + gdouble min_alt, max_alt, alt_diff = 0; const guint8 tp_size_reg = 2; const guint8 tp_size_cur = 4; guint8 tp_size; + if ( dp->vtl->drawelevation ) + { + /* assume if it has elevation at the beginning, it has it throughout. not ness a true good assumption */ + if ( ( drawelevation = vik_track_get_minmax_alt ( track, &min_alt, &max_alt ) ) ) + alt_diff = max_alt - min_alt; + } + if ( ! track->visible ) return; @@ -701,9 +926,11 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr trw_layer_draw_track ( name, track, dp, TRUE ); if ( drawing_white_background ) - drawpoints = FALSE; - else + drawpoints = drawstops = FALSE; + else { drawpoints = dp->vtl->drawpoints; + drawstops = dp->vtl->drawstops; + } if (list) { int x, y, oldx, oldy; @@ -743,15 +970,10 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr if ( list->next ) { vik_viewport_draw_rectangle ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size ); -#if 0 - if ( VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) - vik_viewport_draw_line ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), x, y, x, y-(VIK_TRACKPOINT(list->next->data)->altitude-540)/5); -#endif - vik_viewport_draw_rectangle ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size ); /* stops */ - if (0 && VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > 60 ) + if ( drawstops && 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 ); } else @@ -776,28 +998,28 @@ static void trw_layer_draw_track ( const gchar *name, VikTrack *track, struct Dr vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y); } else { - GdkPoint tmp[4]; -#define FIXALTITUDE(what) (pow((VIK_TRACKPOINT((what))->altitude-330),2)/1500/dp->xmpp) - if ( list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) { - tmp[0].x = oldx; - tmp[0].y = oldy; - tmp[1].x = oldx; - tmp[1].y = oldy-FIXALTITUDE(list->data); - tmp[2].x = x; - tmp[2].y = y-FIXALTITUDE(list->next->data); - tmp[3].x = x; - tmp[3].y = y; - - GdkGC *tmp_gc; - if ( ((oldx - x) > 0 && (oldy - y) > 0) || ((oldx - x) < 0 && (oldy - y) < 0)) - tmp_gc = GTK_WIDGET(dp->vp)->style->light_gc[3]; - else - tmp_gc = GTK_WIDGET(dp->vp)->style->dark_gc[0]; - vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4); - } vik_viewport_draw_line ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), oldx, oldy, x, y); - if ( list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) { + if ( dp->vtl->drawelevation && list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) { + GdkPoint tmp[4]; + #define FIXALTITUDE(what) ((VIK_TRACKPOINT((what))->altitude-min_alt)/alt_diff*DRAW_ELEVATION_FACTOR*dp->vtl->elevation_factor/dp->xmpp) + if ( list && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) { + tmp[0].x = oldx; + tmp[0].y = oldy; + tmp[1].x = oldx; + tmp[1].y = oldy-FIXALTITUDE(list->data); + tmp[2].x = x; + tmp[2].y = y-FIXALTITUDE(list->next->data); + tmp[3].x = x; + tmp[3].y = y; + + GdkGC *tmp_gc; + if ( ((oldx - x) > 0 && (oldy - y) > 0) || ((oldx - x) < 0 && (oldy - y) < 0)) + tmp_gc = GTK_WIDGET(dp->vp)->style->light_gc[3]; + else + tmp_gc = GTK_WIDGET(dp->vp)->style->dark_gc[0]; + vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4); + } vik_viewport_draw_line ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, dp->track_gc_iter), oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data)); } } @@ -862,6 +1084,7 @@ static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct wp->coord.north_south > dp->cn1 && wp->coord.north_south < dp->cn2 ) ) { gint x, y; + GdkPixbuf *sym; vik_viewport_coord_to_screen ( dp->vp, &(wp->coord), &x, &y ); /* if in shrunken_cache, get that. If not, get and add to shrunken_cache */ @@ -934,7 +1157,10 @@ static void trw_layer_draw_waypoint ( const gchar *name, VikWaypoint *wp, struct } /* DRAW ACTUAL DOT */ - if ( wp == dp->vtl->current_wp ) { + if ( dp->vtl->wp_draw_symbols && wp->symbol && (sym = a_get_wp_sym(wp->symbol)) ) { + vik_viewport_draw_pixbuf ( dp->vp, sym, 0, 0, x - gdk_pixbuf_get_width(sym)/2, y - gdk_pixbuf_get_height(sym)/2, -1, -1 ); + } + else if ( wp == dp->vtl->current_wp ) { switch ( dp->vtl->wp_symbol ) { case WP_SYMBOL_FILLED_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, TRUE, x - (dp->vtl->wp_size), y - (dp->vtl->wp_size), dp->vtl->wp_size*2, dp->vtl->wp_size*2 ); break; case WP_SYMBOL_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, FALSE, x - (dp->vtl->wp_size), y - (dp->vtl->wp_size), dp->vtl->wp_size*2, dp->vtl->wp_size*2 ); break; @@ -1055,9 +1281,12 @@ VikTrwLayer *vik_trw_layer_create ( VikViewport *vp ) rv->has_verified_thumbnails = FALSE; rv->wp_symbol = WP_SYMBOL_FILLED_SQUARE; rv->wp_size = 4; + rv->wp_draw_symbols = TRUE; rv->coord_mode = vik_viewport_get_coord_mode ( vp ); + rv->menu_selection = vik_layer_get_interface(VIK_LAYER(rv)->type)->menu_items_selection; + return rv; } @@ -1263,6 +1492,11 @@ static void trw_layer_export_gpsmapper ( gpointer layer_and_vlp[2] ) trw_layer_export ( layer_and_vlp, FILE_TYPE_GPSMAPPER ); } +static void trw_layer_export_gpx ( gpointer layer_and_vlp[2] ) +{ + trw_layer_export ( layer_and_vlp, FILE_TYPE_GPX ); +} + static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] ) { GHashTable *wps = vik_trw_layer_get_waypoints ( VIK_TRW_LAYER(layer_and_vlp[0]) ); @@ -1314,17 +1548,17 @@ static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] ) gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikCoord *def_coord ) { gchar *name; - static VikWaypoint st_wp; - st_wp.coord = *def_coord; - st_wp.altitude = VIK_DEFAULT_ALTITUDE; + VikWaypoint *wp = vik_waypoint_new(); + wp->coord = *def_coord; + wp->altitude = VIK_DEFAULT_ALTITUDE; - if ( a_dialog_new_waypoint ( w, &name, &st_wp, vik_trw_layer_get_waypoints ( vtl ), vtl->coord_mode ) ) + if ( a_dialog_new_waypoint ( w, &name, wp, vik_trw_layer_get_waypoints ( vtl ), vtl->coord_mode ) ) { - VikWaypoint *wp = vik_waypoint_new(); - *wp = st_wp; + wp->visible = TRUE; vik_trw_layer_add_waypoint ( vtl, name, wp ); return TRUE; } + vik_waypoint_free(wp); return FALSE; } @@ -1369,6 +1603,11 @@ void vik_trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vl gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show ( item ); + item = gtk_menu_item_new_with_label ( "Export Layer as GPX" ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show ( item ); + item = gtk_menu_item_new_with_label ( "New Waypoint" ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); @@ -1419,11 +1658,11 @@ void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t ) #endif vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, iter ); g_hash_table_insert ( vtl->tracks_iters, name, iter ); - t->visible = TRUE; + /* t->visible = TRUE; */ } } else - t->visible = TRUE; + ; /* t->visible = TRUE; // this is now used by file input functions */ g_hash_table_insert ( vtl->tracks, name, t ); @@ -1452,8 +1691,91 @@ static void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, const gchar *trk_n else if (vtl->last_tp_track_name && g_strcasecmp(trk_name, vtl->last_tp_track_name) == 0) trw_layer_cancel_last_tp ( vtl ); } + +static gchar *get_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name) +{ + gint i = 2; + gchar *newname = g_strdup(name); + while ((sublayer_type == VIK_TRW_LAYER_SUBLAYER_TRACK) ? + (void *)vik_trw_layer_get_track(vtl, newname) : (void *)vik_trw_layer_get_waypoint(vtl, newname)) { + gchar *new_newname = g_strdup_printf("%s#%d", name, i); + g_free(newname); + newname = new_newname; + i++; + } + return newname; +} + +void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp ) +{ + vik_trw_layer_add_waypoint ( vtl, + get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, name), + wp ); +} +void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr ) +{ + vik_trw_layer_add_track ( vtl, + get_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, name), + tr ); +} + +static void trw_layer_enum_item ( const gchar *name, GList **tr, GList **l ) +{ + *l = g_list_append(*l, (gpointer)name); +} + +static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gchar *name, gint type ) +{ + gchar *newname = get_new_unique_sublayer_name(vtl_dest, type, name); + if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) { + VikTrack *t; + t = vik_track_copy(vik_trw_layer_get_track(vtl_src, name)); + vik_trw_layer_delete_track(vtl_src, name); + vik_trw_layer_add_track(vtl_dest, newname, t); + } + if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINT) { + VikWaypoint *w; + w = vik_waypoint_copy(vik_trw_layer_get_waypoint(vtl_src, name)); + vik_trw_layer_delete_waypoint(vtl_src, name); + vik_trw_layer_add_waypoint(vtl_dest, newname, w); + } +} + +static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path ) +{ + VikTreeview *vt = VIK_LAYER(vtl_src)->vt; + gint type = vik_treeview_item_get_data(vt, src_item_iter); + + if (!vik_treeview_item_get_pointer(vt, src_item_iter)) { + GList *items = NULL; + GList *iter; + + if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) { + g_hash_table_foreach ( vtl_src->tracks, (GHFunc)trw_layer_enum_item, &items); + } + if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINTS) { + g_hash_table_foreach ( vtl_src->waypoints, (GHFunc)trw_layer_enum_item, &items); + } + + iter = items; + while (iter) { + if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) { + trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_TRACK); + } else { + trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_WAYPOINT); + } + iter = iter->next; + } + if (items) + g_list_free(items); + } else { + gchar *name = vik_treeview_item_get_pointer(vt, src_item_iter); + trw_layer_move_item(vtl_src, vtl_dest, name, type); + } +} + -static gboolean trw_layer_delete_track ( VikTrwLayer *vtl, const gchar *trk_name ) +gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, const gchar *trk_name ) { VikTrack *t = g_hash_table_lookup ( vtl->tracks, trk_name ); gboolean was_visible = FALSE; @@ -1477,36 +1799,79 @@ static gboolean trw_layer_delete_track ( VikTrwLayer *vtl, const gchar *trk_name return was_visible; } +gboolean vik_trw_layer_delete_waypoint ( VikTrwLayer *vtl, const gchar *wp_name ) +{ + gboolean was_visible = FALSE; + VikWaypoint *wp; + + wp = g_hash_table_lookup ( vtl->waypoints, wp_name ); + if ( wp ) { + GtkTreeIter *it; + + if ( wp == vtl->current_wp ) { + vtl->current_wp = NULL; + vtl->current_wp_name = NULL; + vtl->moving_wp = FALSE; + } + + was_visible = wp->visible; + g_assert ( ( it = g_hash_table_lookup ( vtl->waypoints_iters, (gchar *) wp_name ) ) ); + vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it ); + g_hash_table_remove ( vtl->waypoints_iters, (gchar *) wp_name ); + g_hash_table_remove ( vtl->waypoints, wp_name ); /* last because this frees name */ + } + + return was_visible; +} + +static void remove_item_from_treeview(const gchar *name, GtkTreeIter *it, VikTreeview * vt) +{ + vik_treeview_item_delete (vt, it ); +} + +void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl ) +{ + + vtl->current_track = NULL; + if (vtl->current_tp_track_name) + trw_layer_cancel_current_tp(vtl, FALSE); + if (vtl->last_tp_track_name) + trw_layer_cancel_last_tp ( vtl ); + + g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt); + g_hash_table_remove_all(vtl->tracks_iters); + g_hash_table_remove_all(vtl->tracks); + + /* TODO: only update if the layer is visible (ticked) */ + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + +void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl ) +{ + vtl->current_wp = NULL; + vtl->current_wp_name = NULL; + vtl->moving_wp = FALSE; + + g_hash_table_foreach(vtl->waypoints_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt); + g_hash_table_remove_all(vtl->waypoints_iters); + g_hash_table_remove_all(vtl->waypoints); + + /* TODO: only update if the layer is visible (ticked) */ + vik_layer_emit_update ( VIK_LAYER(vtl) ); +} + static void trw_layer_delete_item ( gpointer pass_along[5] ) { VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); gboolean was_visible = FALSE; if ( (gint) pass_along[2] == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { - VikWaypoint *wp; - wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] ); - if ( wp ) - { - GtkTreeIter *it; - - if ( wp == vtl->current_wp ) { - vtl->current_wp = NULL; - vtl->current_wp_name = NULL; - vtl->moving_wp = FALSE; - } - - was_visible = wp->visible; - g_assert ( ( it = g_hash_table_lookup ( vtl->waypoints_iters, (gchar *) pass_along[3] ) ) ); - vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it ); - g_hash_table_remove ( vtl->waypoints_iters, (gchar *) pass_along[3] ); - g_hash_table_remove ( vtl->waypoints, pass_along[3] ); /* last because this frees name */ - } + was_visible = vik_trw_layer_delete_waypoint ( vtl, (gchar *) pass_along[3] ); } else { - was_visible = trw_layer_delete_track ( vtl, (gchar *) pass_along[3] ); + was_visible = vik_trw_layer_delete_track ( vtl, (gchar *) pass_along[3] ); } - if ( was_visible ) vik_layer_emit_update ( VIK_LAYER(vtl) ); } @@ -1572,12 +1937,11 @@ static void trw_layer_properties_item ( gpointer pass_along[5] ) } if ( new_tr_name ) vik_trw_layer_add_track ( vtl, new_tr_name, tracks[i] ); - } if ( tracks ) { g_free ( tracks ); - trw_layer_delete_track ( vtl, (gchar *) pass_along[3] ); + vik_trw_layer_delete_track ( vtl, (gchar *) pass_along[3] ); vik_layer_emit_update ( VIK_LAYER(vtl) ); /* chase thru the hoops */ } } @@ -1650,11 +2014,11 @@ static void find_nearby_track(gpointer key, gpointer value, gpointer user_data) p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data); if (!p1->has_timestamp || !p2->has_timestamp) { - printf("no timestamp\n"); + g_print("no timestamp\n"); return; } - /* printf("Got track named %s, times %d, %d\n", (gchar *)key, p1->timestamp, p2->timestamp); */ + /* g_print("Got track named %s, times %d, %d\n", (gchar *)key, p1->timestamp, p2->timestamp); */ if (abs(t1 - p2->timestamp) < thr*60 || /* p1 p2 t1 t2 */ abs(p1->timestamp - t2) < thr*60 @@ -1724,7 +2088,7 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ) t1 = ((VikTrackpoint *)trps->data)->timestamp; t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp; - /* printf("Original track times: %d and %d\n", t1, t2); */ + /* g_print("Original track times: %d and %d\n", t1, t2); */ params[0] = &nearby_tracks; params[1] = trps; params[2] = (gpointer)thr; @@ -1752,14 +2116,14 @@ static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] ) time_t t1, t2; t1 = get_first_trackpoint(l)->timestamp; t2 = get_last_trackpoint(l)->timestamp; - printf(" %20s: track %d - %d\n", (char *)l->data, (int)t1, (int)t2); + g_print(" %20s: track %d - %d\n", (char *)l->data, (int)t1, (int)t2); */ /* remove trackpoints from merged track, delete track */ tr->trackpoints = g_list_concat(tr->trackpoints, get_track(l)->trackpoints); get_track(l)->trackpoints = NULL; - trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), l->data); + vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), l->data); track_count ++; l = g_list_next(l); @@ -1807,7 +2171,7 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) while (iter) { ts = VIK_TRACKPOINT(iter->data)->timestamp; if (ts < prev_ts) { - printf("panic: ts < prev_ts: this should never happen!\n"); + g_print("panic: ts < prev_ts: this should never happen!\n"); return; } if (ts - prev_ts > thr*60) { @@ -1838,13 +2202,13 @@ static void trw_layer_split_by_timestamp ( gpointer pass_along[6] ) new_tr_name = g_strdup_printf("%s #%d", (gchar *) pass_along[3], i++); vik_trw_layer_add_track(VIK_TRW_LAYER(pass_along[0]), new_tr_name, tr); - /* fprintf(stderr, "adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp, + /* g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp, VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/ iter = g_list_next(iter); } g_list_free(newlists); - trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), (gchar *)pass_along[3]); + vik_trw_layer_delete_track(VIK_TRW_LAYER(pass_along[0]), (gchar *)pass_along[3]); vik_layer_emit_update(VIK_LAYER(pass_along[0])); } @@ -1893,12 +2257,12 @@ const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar return NULL; } - wp = vik_waypoint_copy ( VIK_WAYPOINT(g_hash_table_lookup ( l->waypoints, sublayer )) ); - g_hash_table_remove ( l->waypoints, sublayer ); - iter = g_hash_table_lookup ( l->waypoints_iters, sublayer ); g_hash_table_steal ( l->waypoints_iters, sublayer ); + wp = vik_waypoint_copy ( VIK_WAYPOINT(g_hash_table_lookup ( l->waypoints, sublayer )) ); + g_hash_table_remove ( l->waypoints, sublayer ); + rv = g_strdup(newname); for ( i = strlen(rv) - 1; i >= 0; i-- ) rv[i] = toupper(rv[i]); @@ -1933,7 +2297,7 @@ const gchar *vik_trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar return NULL; } - g_hash_table_lookup_extended ( l->tracks, sublayer, (gpointer *)&orig_key, (gpointer *)&tr ); + g_hash_table_lookup_extended ( l->tracks, sublayer, (void *)&orig_key, (void *)&tr ); g_hash_table_steal ( l->tracks, sublayer ); iter = g_hash_table_lookup ( l->tracks_iters, sublayer ); @@ -2000,6 +2364,16 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); + item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_CUT, NULL ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_cut_item_cb), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + + item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_COPY, NULL ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_copy_item_cb), pass_along ); + gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); + gtk_widget_show ( item ); + item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_DELETE, NULL ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_item), pass_along ); gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); @@ -2073,146 +2447,52 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, return rv; } -/* Params are: vvp, event, last match found or NULL */ -static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[2] ) -{ - if ( wp->image && wp->visible ) - { - gint x, y, slackx, slacky; - GdkEventButton *event = (GdkEventButton *) params[1]; - vik_viewport_coord_to_screen ( VIK_VIEWPORT(params[0]), &(wp->coord), &x, &y ); - slackx = wp->image_width / 2; - slacky = wp->image_height / 2; - if ( x <= event->x + slackx && x >= event->x - slackx - && y <= event->y + slacky && y >= event->y - slacky ) - { - params[2] = wp->image; /* we've found a match. however continue searching - * since we want to find the last match -- that - * is, the match that was drawn last. */ - } - } +/* to be called when last_tpl no long exists. */ +static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl ) +{ + if ( vtl->tpwin ) /* can't join with a non-existant TP. */ + vik_trw_layer_tpwin_disable_join ( vtl->tpwin ); + vtl->last_tpl = NULL; + vtl->last_tp_track_name = NULL; } -static gboolean tool_show_picture ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy ) { - gpointer params[3] = { vvp, event, NULL }; - g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params ); - if ( params[2] ) + if ( vtl->tpwin ) { - /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */ -#ifdef WINDOWS - ShellExecute(NULL, NULL, (char *) params[2], NULL, ".\\", 0); -#else /* WINDOWS */ - GError *err = NULL; - gchar *quoted_file = g_shell_quote ( (gchar *) params[2] ); - gchar *cmd = g_strdup_printf ( "eog %s", quoted_file ); - g_free ( quoted_file ); - if ( ! g_spawn_command_line_async ( cmd, &err ) ) + if ( destroy) { - a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), "Could not launch eog to open file." ); - g_error_free ( err ); + gtk_widget_destroy ( GTK_WIDGET(vtl->tpwin) ); + vtl->tpwin = NULL; } - g_free ( cmd ); -#endif /* WINDOWS */ - return TRUE; /* found a match */ + else + vik_trw_layer_tpwin_set_empty ( vtl->tpwin ); + } + if ( vtl->current_tpl ) + { + vtl->current_tpl = NULL; + vtl->current_tp_track_name = NULL; + vik_layer_emit_update(VIK_LAYER(vtl)); } - else - return FALSE; /* go through other layers, searching for a match */ } -static gboolean tool_new_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ) { - VikCoord coord; - 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) - vik_layer_emit_update ( VIK_LAYER(vtl) ); - return TRUE; -} - -typedef struct { - gint x, y; - gint closest_x, closest_y; - gchar *closest_track_name; - VikTrackpoint *closest_tp; - VikViewport *vvp; - GList *closest_tpl; -} TPSearchParams; - -static void track_search_closest_tp ( gchar *name, VikTrack *t, TPSearchParams *params ) -{ - GList *tpl = t->trackpoints; - VikTrackpoint *tp; - - if ( !t->visible ) - return; - - while (tpl) - { - gint x, y; - tp = VIK_TRACKPOINT(tpl->data); - - vik_viewport_coord_to_screen ( params->vvp, &(tp->coord), &x, &y ); - - if ( abs (x - params->x) <= TRACKPOINT_SIZE_APPROX && abs (y - params->y) <= TRACKPOINT_SIZE_APPROX && - ((!params->closest_tp) || /* was the old trackpoint we already found closer than this one? */ - abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y))) - { - params->closest_track_name = name; - params->closest_tp = tp; - params->closest_tpl = tpl; - params->closest_x = x; - params->closest_y = y; - } - tpl = tpl->next; - } -} - -/* to be called when last_tpl no long exists. */ -static void trw_layer_cancel_last_tp ( VikTrwLayer *vtl ) -{ - if ( vtl->tpwin ) /* can't join with a non-existant TP. */ - vik_trw_layer_tpwin_disable_join ( vtl->tpwin ); - vtl->last_tpl = NULL; - vtl->last_tp_track_name = NULL; -} - -static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy ) -{ - if ( vtl->tpwin ) - { - if ( destroy) - { - gtk_widget_destroy ( GTK_WIDGET(vtl->tpwin) ); - vtl->tpwin = NULL; - } - else - vik_trw_layer_tpwin_set_empty ( vtl->tpwin ); - } - if ( vtl->current_tpl ) - { - vtl->current_tpl = NULL; - vtl->current_tp_track_name = NULL; - vik_layer_emit_update(VIK_LAYER(vtl)); - } -} - -static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ) -{ - g_assert ( vtl->tpwin != NULL ); - if ( response == VIK_TRW_LAYER_TPWIN_CLOSE ) - trw_layer_cancel_current_tp ( vtl, TRUE ); - else if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev ) - { - gchar *name; - if ( ( name = a_dialog_new_track ( GTK_WINDOW(vtl->tpwin), vtl->tracks ) ) ) - { - VikTrack *tr = vik_track_new (); - GList *newglist = g_list_alloc (); - newglist->prev = NULL; - newglist->next = vtl->current_tpl->next; - newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data)); - tr->trackpoints = newglist; + g_assert ( vtl->tpwin != NULL ); + if ( response == VIK_TRW_LAYER_TPWIN_CLOSE ) + trw_layer_cancel_current_tp ( vtl, TRUE ); + else if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev ) + { + gchar *name; + if ( ( name = a_dialog_new_track ( GTK_WINDOW(vtl->tpwin), vtl->tracks ) ) ) + { + VikTrack *tr = vik_track_new (); + GList *newglist = g_list_alloc (); + newglist->prev = NULL; + newglist->next = vtl->current_tpl->next; + newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data)); + tr->trackpoints = newglist; vtl->current_tpl->next->prev = newglist; /* end old track here */ vtl->current_tpl->next = NULL; @@ -2305,7 +2585,7 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response ) /* if we did this before, trw_layer_delete_track would have canceled the current tp because * it was the current track. canceling the current tp would have set vtl->current_tpl to NULL */ - trw_layer_delete_track ( vtl, tmp ); + vik_trw_layer_delete_track ( vtl, tmp ); trw_layer_cancel_last_tp ( vtl ); /* same TP, can't join. */ vik_layer_emit_update(VIK_LAYER(vtl)); @@ -2329,6 +2609,77 @@ static void trw_layer_tpwin_init ( VikTrwLayer *vtl ) /* set layer name and TP data */ } +/*************************************************************************** + ** Tool code + ***************************************************************************/ + +/*** Utility data structures and functions ****/ + +typedef struct { + gint x, y; + gint closest_x, closest_y; + gchar *closest_wp_name; + VikWaypoint *closest_wp; + VikViewport *vvp; +} WPSearchParams; + +typedef struct { + gint x, y; + gint closest_x, closest_y; + gchar *closest_track_name; + VikTrackpoint *closest_tp; + VikViewport *vvp; + GList *closest_tpl; +} TPSearchParams; + +static void waypoint_search_closest_tp ( gchar *name, VikWaypoint *wp, WPSearchParams *params ) +{ + gint x, y; + if ( !wp->visible ) + return; + + vik_viewport_coord_to_screen ( params->vvp, &(wp->coord), &x, &y ); + + if ( abs (x - params->x) <= WAYPOINT_SIZE_APPROX && abs (y - params->y) <= WAYPOINT_SIZE_APPROX && + ((!params->closest_wp) || /* was the old waypoint we already found closer than this one? */ + abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y))) + { + params->closest_wp_name = name; + params->closest_wp = wp; + params->closest_x = x; + params->closest_y = y; + } +} + +static void track_search_closest_tp ( gchar *name, VikTrack *t, TPSearchParams *params ) +{ + GList *tpl = t->trackpoints; + VikTrackpoint *tp; + + if ( !t->visible ) + return; + + while (tpl) + { + gint x, y; + tp = VIK_TRACKPOINT(tpl->data); + + vik_viewport_coord_to_screen ( params->vvp, &(tp->coord), &x, &y ); + + if ( abs (x - params->x) <= TRACKPOINT_SIZE_APPROX && abs (y - params->y) <= TRACKPOINT_SIZE_APPROX && + ((!params->closest_tp) || /* was the old trackpoint we already found closer than this one? */ + abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y))) + { + params->closest_track_name = name; + params->closest_tp = tp; + params->closest_tpl = tpl; + params->closest_x = x; + params->closest_y = y; + } + tpl = tpl->next; + } +} + static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y ) { TPSearchParams params; @@ -2341,38 +2692,348 @@ static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikV return params.closest_tp; } -static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y ) +{ + WPSearchParams params; + params.x = x; + params.y = y; + params.vvp = vvp; + params.closest_wp = NULL; + params.closest_wp_name = NULL; + g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, ¶ms); + return params.closest_wp; +} + +/* background drawing hook, to be passed the viewport */ +static gboolean tool_sync_done = TRUE; + +static gboolean tool_sync(gpointer data) +{ + VikViewport *vvp = data; + gdk_threads_enter(); + vik_viewport_sync(vvp); + tool_sync_done = TRUE; + gdk_threads_leave(); + return FALSE; +} + +typedef struct { + VikViewport *vvp; + gboolean holding; + GdkGC *gc; + int oldx, oldy; +} tool_ed_t; + +static void marker_begin_move ( tool_ed_t *t, gint x, gint y ) +{ + t->holding = TRUE; + t->gc = vik_viewport_new_gc (t->vvp, "black", 2); + gdk_gc_set_function ( t->gc, GDK_INVERT ); + vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, x-3, y-3, 6, 6 ); + vik_viewport_sync(t->vvp); + t->oldx = x; + t->oldy = y; +} + +static void marker_moveto ( tool_ed_t *t, gint x, gint y ) +{ + VikViewport *vvp = t->vvp; + vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 ); + vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, x-3, y-3, 6, 6 ); + t->oldx = x; + t->oldy = y; + if (tool_sync_done) { + g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, tool_sync, vvp, NULL); + tool_sync_done = FALSE; + } +} + +static void marker_end_move ( tool_ed_t *t ) +{ + vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 ); + g_object_unref ( t->gc ); + t->holding = FALSE; +} + +/*** Edit waypoint ****/ + +static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp) +{ + tool_ed_t *t = g_new(tool_ed_t, 1); + t->vvp = vvp; + t->holding = FALSE; + return t; +} + +static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ) +{ + WPSearchParams params; + tool_ed_t *t = data; + VikViewport *vvp = t->vvp; + + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + + if ( t->holding ) { + return TRUE; + } + + if ( vtl->current_wp && vtl->current_wp->visible ) + { + /* first check if current WP is within area (other may be 'closer', but we want to move the current) */ + 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 ( event->button == 3 ) + vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */ + else { + marker_begin_move(t, event->x, event->y); + } + return TRUE; + } + } + + params.vvp = vvp; + params.x = event->x; + params.y = event->y; + params.closest_wp_name = NULL; + /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */ + params.closest_wp = NULL; + g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, ¶ms); + if ( vtl->current_wp == params.closest_wp && vtl->current_wp != NULL ) + { + /* how do we get here? I'm putting in the abort until we can figure it out. -alex */ + marker_begin_move(t, event->x, event->y); + printf("Abort: shouldn't be here\n"); + exit(1); + } + else if ( params.closest_wp ) + { + if ( event->button == 3 ) + vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */ + else + vtl->waypoint_rightclick = FALSE; + + vtl->current_wp = params.closest_wp; + vtl->current_wp_name = params.closest_wp_name; + + if ( params.closest_wp ) + vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ) ); + + /* could make it so don't update if old WP is off screen and new is null but oh well */ + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; + } + + vtl->current_wp = NULL; + vtl->current_wp_name = NULL; + vtl->waypoint_rightclick = FALSE; + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return FALSE; +} + +static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ) +{ + tool_ed_t *t = data; + VikViewport *vvp = t->vvp; + + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + + if ( t->holding ) { + VikCoord new_coord; + vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord ); + + /* snap to TP */ + if ( event->state & GDK_CONTROL_MASK ) + { + VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); + if ( tp ) + new_coord = tp->coord; + } + + /* snap to WP */ + if ( event->state & GDK_SHIFT_MASK ) + { + VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); + if ( wp && wp != vtl->current_wp ) + new_coord = wp->coord; + } + + { + gint x, y; + vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y ); + marker_moveto ( t, x, y ); + } + return TRUE; + } + return FALSE; +} + +static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ) +{ + tool_ed_t *t = data; + VikViewport *vvp = t->vvp; + + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + + if ( t->holding && event->button == 1 ) + { + VikCoord new_coord; + vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord ); + + /* snap to TP */ + if ( event->state & GDK_CONTROL_MASK ) + { + VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); + if ( tp ) + new_coord = tp->coord; + } + + /* snap to WP */ + if ( event->state & GDK_SHIFT_MASK ) + { + VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); + if ( wp && wp != vtl->current_wp ) + new_coord = wp->coord; + } + + marker_end_move ( t ); + + vtl->current_wp->coord = new_coord; + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; + } + /* PUT IN RIGHT PLACE!!! */ + if ( event->button == 3 && vtl->waypoint_rightclick ) + { + if ( 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 () ); + vik_trw_layer_sublayer_add_menu_items ( vtl, vtl->wp_right_click_menu, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, vtl->current_wp_name, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ) ); + gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() ); + vtl->waypoint_rightclick = FALSE; + } + return FALSE; +} + +/*** New track ****/ + +static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp) +{ + return vvp; +} + +static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +{ + VikTrackpoint *tp; + + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + + if ( event->button == 3 && vtl->current_track ) + { + /* undo */ + if ( vtl->current_track->trackpoints ) + { + GList *last = g_list_last(vtl->current_track->trackpoints); + g_free ( last->data ); + vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last ); + } + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; + } + + if ( event->type == GDK_2BUTTON_PRESS ) + { + /* subtract last (duplicate from double click) tp then end */ + if ( vtl->current_track && vtl->current_track->trackpoints && vtl->ct_x1 == vtl->ct_x2 && vtl->ct_y1 == vtl->ct_y2 ) + { + GList *last = g_list_last(vtl->current_track->trackpoints); + g_free ( last->data ); + vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last ); + /* undo last, then end */ + vtl->current_track = NULL; + } + return TRUE; + } + + if ( ! vtl->current_track ) + { + gchar *name; + if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks ) ) ) + { + vtl->current_track = vik_track_new(); + vtl->current_track->visible = TRUE; + vik_trw_layer_add_track ( vtl, name, vtl->current_track ); + } + else + return TRUE; + } + tp = vik_trackpoint_new(); + vik_viewport_screen_to_coord ( vvp, event->x, event->y, &(tp->coord) ); + + /* snap to other TP */ + if ( event->state & GDK_CONTROL_MASK ) + { + VikTrackpoint *other_tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); + if ( other_tp ) + tp->coord = other_tp->coord; + } + + tp->newsegment = FALSE; + tp->has_timestamp = FALSE; + tp->timestamp = 0; + tp->altitude = VIK_DEFAULT_ALTITUDE; + vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp ); + + vtl->ct_x1 = vtl->ct_x2; + vtl->ct_y1 = vtl->ct_y2; + vtl->ct_x2 = event->x; + vtl->ct_y2 = event->y; + + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; +} + + +/*** New waypoint ****/ + +static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp) { - if ( vtl->moving_tp ) - { - /* vtl->moving_tp_x, vtl->moving_tp_y, etc. */ - VikCoord new_coord; - vtl->moving_tp = FALSE; - vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord ); + return vvp; +} - /* snap to TP */ - if ( event->state & GDK_CONTROL_MASK ) - { - VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); - if ( tp && tp != vtl->current_tpl->data ) - new_coord = tp->coord; - } +static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +{ + VikCoord coord; + 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) + vik_layer_emit_update ( VIK_LAYER(vtl) ); + return TRUE; +} - VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord; - /* diff dist is diff from orig */ - vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name ); - /* can't join with itself! */ - trw_layer_cancel_last_tp ( vtl ); +/*** Edit trackpoint ****/ - vik_layer_emit_update ( VIK_LAYER(vtl) ); - return TRUE; - } - return FALSE; +static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp) +{ + tool_ed_t *t = g_new(tool_ed_t, 1); + t->vvp = vvp; + t->holding = FALSE; + return t; } -static gboolean tool_edit_trackpoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +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 @@ -2387,6 +3048,12 @@ static gboolean tool_edit_trackpoint ( VikTrwLayer *vtl, GdkEventButton *event, /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */ params.closest_tp = NULL; + if ( event->button != 1 ) + return FALSE; + + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + 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.) */ @@ -2399,9 +3066,8 @@ static gboolean tool_edit_trackpoint ( VikTrwLayer *vtl, GdkEventButton *event, if ( current_tr->visible && abs(x - event->x) < TRACKPOINT_SIZE_APPROX && - abs(y - event->y) < TRACKPOINT_SIZE_APPROX ) - { - vtl->moving_tp = TRUE; + abs(y - event->y) < TRACKPOINT_SIZE_APPROX ) { + marker_begin_move ( t, event->x, event->y ); return TRUE; } @@ -2421,217 +3087,171 @@ static gboolean tool_edit_trackpoint ( VikTrwLayer *vtl, GdkEventButton *event, return TRUE; } - /* these aren't the droids you're looking for */ return FALSE; } -typedef struct { - gint x, y; - gint closest_x, closest_y; - gchar *closest_wp_name; - VikWaypoint *closest_wp; - VikViewport *vvp; -} WPSearchParams; - -static void waypoint_search_closest_tp ( gchar *name, VikWaypoint *wp, WPSearchParams *params ) +static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ) { - gint x, y; - if ( !wp->visible ) - return; + tool_ed_t *t = data; + VikViewport *vvp = t->vvp; - vik_viewport_coord_to_screen ( params->vvp, &(wp->coord), &x, &y ); - - if ( abs (x - params->x) <= WAYPOINT_SIZE_APPROX && abs (y - params->y) <= WAYPOINT_SIZE_APPROX && - ((!params->closest_wp) || /* was the old waypoint we already found closer than this one? */ - abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y))) - { - params->closest_wp_name = name; - params->closest_wp = wp; - params->closest_x = x; - params->closest_y = y; - } -} + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; -static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) -{ - if ( vtl->moving_wp ) + if ( t->holding ) { VikCoord new_coord; - vtl->moving_wp = FALSE; + GdkGC *gc; vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord ); /* snap to TP */ if ( event->state & GDK_CONTROL_MASK ) { VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); - if ( tp ) + if ( tp && tp != vtl->current_tpl->data ) new_coord = tp->coord; } + // VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord; + { + gint x, y; + vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y ); + marker_moveto ( t, x, y ); + } - /* snap to WP */ - if ( event->state & GDK_SHIFT_MASK ) - { - VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); - if ( wp && wp != vtl->current_wp ) - new_coord = wp->coord; - } - - vtl->current_wp->coord = new_coord; - vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } - /* PUT IN RIGHT PLACE!!! */ - if ( vtl->waypoint_rightclick ) - { - if ( 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 () ); - vik_trw_layer_sublayer_add_menu_items ( vtl, vtl->wp_right_click_menu, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, vtl->current_wp_name, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ) ); - gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() ); - vtl->waypoint_rightclick = FALSE; - } return FALSE; } -static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y ) +static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data ) { - WPSearchParams params; - params.x = x; - params.y = y; - params.vvp = vvp; - params.closest_wp = NULL; - params.closest_wp_name = NULL; - g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, ¶ms); - return params.closest_wp; -} + tool_ed_t *t = data; + VikViewport *vvp = t->vvp; -static gboolean tool_edit_waypoint ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) -{ - WPSearchParams params; + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + if ( event->button != 1) + return FALSE; - if ( vtl->current_wp && vtl->current_wp->visible ) - { - /* first check if current WP is within area (other may be 'closer', but we want to move the current) */ - gint x, y; - vik_viewport_coord_to_screen ( vvp, &(vtl->current_wp->coord), &x, &y ); + if ( t->holding ) { + VikCoord new_coord; + vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord ); - if ( abs(x - event->x) < WAYPOINT_SIZE_APPROX && - abs(y - event->y) < WAYPOINT_SIZE_APPROX ) + /* snap to TP */ + if ( event->state & GDK_CONTROL_MASK ) { - if ( event->button == 3 ) - vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */ - else - vtl->moving_wp = TRUE; - return TRUE; + VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); + if ( tp && tp != vtl->current_tpl->data ) + new_coord = tp->coord; } - } - params.vvp = vvp; - params.x = event->x; - params.y = event->y; - params.closest_wp_name = NULL; - /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */ - params.closest_wp = NULL; - g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, ¶ms); - if ( vtl->current_wp == params.closest_wp && vtl->current_wp != NULL ) - { - vtl->moving_wp = TRUE; - } - else if ( params.closest_wp ) - { - if ( event->button == 3 ) - vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */ - else - vtl->waypoint_rightclick = FALSE; + VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord; - vtl->current_wp = params.closest_wp; - vtl->current_wp_name = params.closest_wp_name; - vtl->moving_wp = FALSE; + marker_end_move ( t ); - if ( params.closest_wp ) - vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_name ) ); + /* diff dist is diff from orig */ + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track_name ); + /* can't join with itself! */ + trw_layer_cancel_last_tp ( vtl ); - /* could make it so don't update if old WP is off screen and new is null but oh well */ vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; } - - vtl->current_wp = NULL; - vtl->current_wp_name = NULL; - vtl->moving_wp = FALSE; - vtl->waypoint_rightclick = FALSE; return FALSE; } -static gboolean tool_new_track ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) + +/*** Magic Scissors ***/ +static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp) { - VikTrackpoint *tp; + return vvp; +} - if ( event->button == 3 && vtl->current_track ) - { - /* undo */ - if ( vtl->current_track->trackpoints ) - { - GList *last = g_list_last(vtl->current_track->trackpoints); - g_free ( last->data ); - vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last ); - } +static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +{ + VikCoord tmp; + vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp ); + if ( vtl->magic_scissors_started ) { + struct LatLon start, end; + gchar *cmd; + vik_coord_to_latlon ( &(vtl->magic_scissors_coord), &start ); + vik_coord_to_latlon ( &(tmp), &end ); + cmd = g_strdup_printf(GOOGLE_DIRECTIONS_STRING, start.lat, start.lon, end.lat, end.lon ); + a_babel_convert_from_shellcommand ( vtl, cmd, "google", NULL, NULL ); + g_free ( cmd ); vik_layer_emit_update ( VIK_LAYER(vtl) ); - return TRUE; + } else { + vtl->magic_scissors_coord = tmp; } + vtl->magic_scissors_started = !vtl->magic_scissors_started; + return TRUE; +} - if ( event->type == GDK_2BUTTON_PRESS ) +/*** Show picture ****/ + +static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp) +{ + return vvp; +} + +/* Params are: vvp, event, last match found or NULL */ +static void tool_show_picture_wp ( char *name, VikWaypoint *wp, gpointer params[2] ) +{ + if ( wp->image && wp->visible ) { - /* subtract last (duplicate from double click) tp then end */ - if ( vtl->current_track && vtl->current_track->trackpoints && vtl->ct_x1 == vtl->ct_x2 && vtl->ct_y1 == vtl->ct_y2 ) + gint x, y, slackx, slacky; + GdkEventButton *event = (GdkEventButton *) params[1]; + + vik_viewport_coord_to_screen ( VIK_VIEWPORT(params[0]), &(wp->coord), &x, &y ); + slackx = wp->image_width / 2; + slacky = wp->image_height / 2; + if ( x <= event->x + slackx && x >= event->x - slackx + && y <= event->y + slacky && y >= event->y - slacky ) { - GList *last = g_list_last(vtl->current_track->trackpoints); - g_free ( last->data ); - vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last ); - /* undo last, then end */ - vtl->current_track = NULL; + params[2] = wp->image; /* we've found a match. however continue searching + * since we want to find the last match -- that + * is, the match that was drawn last. */ } - return TRUE; } +} - if ( ! vtl->current_track ) +static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ) +{ + gpointer params[3] = { vvp, event, NULL }; + if (!vtl || vtl->vl.type != VIK_LAYER_TRW) + return FALSE; + g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params ); + if ( params[2] ) { - gchar *name; - if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks ) ) ) + /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */ +#ifdef WINDOWS + ShellExecute(NULL, NULL, (char *) params[2], NULL, ".\\", 0); +#else /* WINDOWS */ + GError *err = NULL; + gchar *quoted_file = g_shell_quote ( (gchar *) params[2] ); + gchar *cmd = g_strdup_printf ( "eog %s", quoted_file ); + g_free ( quoted_file ); + if ( ! g_spawn_command_line_async ( cmd, &err ) ) { - vtl->current_track = vik_track_new(); - vtl->current_track->visible = TRUE; - vik_trw_layer_add_track ( vtl, name, vtl->current_track ); + a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), "Could not launch eog to open file." ); + g_error_free ( err ); } - else - return TRUE; + g_free ( cmd ); +#endif /* WINDOWS */ + return TRUE; /* found a match */ } - tp = vik_trackpoint_new(); - vik_viewport_screen_to_coord ( vvp, event->x, event->y, &(tp->coord) ); + else + return FALSE; /* go through other layers, searching for a match */ +} + +/*************************************************************************** + ** End tool code + ***************************************************************************/ - /* snap to other TP */ - if ( event->state & GDK_CONTROL_MASK ) - { - VikTrackpoint *other_tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y ); - if ( other_tp ) - tp->coord = other_tp->coord; - } - tp->newsegment = FALSE; - tp->has_timestamp = FALSE; - tp->timestamp = 0; - tp->altitude = VIK_DEFAULT_ALTITUDE; - vtl->current_track->trackpoints = g_list_append ( vtl->current_track->trackpoints, tp ); - vtl->ct_x1 = vtl->ct_x2; - vtl->ct_y1 = vtl->ct_y2; - vtl->ct_x2 = event->x; - vtl->ct_y2 = event->y; - vik_layer_emit_update ( VIK_LAYER(vtl) ); - return TRUE; -} static void image_wp_make_list ( char *name, VikWaypoint *wp, GSList **pics ) { @@ -2701,3 +3321,24 @@ static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mo g_hash_table_foreach ( vtl->tracks, (GHFunc) track_convert, &dest_mode ); } } + +VikWaypoint *vik_trw_layer_get_waypoint ( VikTrwLayer *vtl, gchar *name ) +{ + return g_hash_table_lookup ( vtl->waypoints, name ); +} + +VikTrack *vik_trw_layer_get_track ( VikTrwLayer *vtl, gchar *name ) +{ + return g_hash_table_lookup ( vtl->tracks, name ); +} + +static void vik_trw_layer_set_menu_selection(VikTrwLayer *vtl, guint16 selection) +{ + vtl->menu_selection = selection; +} + +static guint16 vik_trw_layer_get_menu_selection(VikTrwLayer *vtl) +{ + return(vtl->menu_selection); +} +