+
+/*** Edit trackpoint ****/
+
+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_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_name = 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;
+
+ 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.) */
+ VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
+ VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_track_name));
+ gint x, y;
+ g_assert ( current_tr );
+
+ 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 ) {
+ marker_begin_move ( t, event->x, event->y );
+ return TRUE;
+ }
+
+ vtl->last_tpl = vtl->current_tpl;
+ vtl->last_tp_track_name = vtl->current_tp_track_name;
+ }
+
+ g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, ¶ms);
+
+ if ( params.closest_tp )
+ {
+ vtl->current_tpl = params.closest_tpl;
+ vtl->current_tp_track_name = params.closest_track_name;
+ vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, vtl->current_tp_track_name ) );
+ trw_layer_tpwin_init ( vtl );
+ vik_layer_emit_update ( VIK_LAYER(vtl) );
+ return TRUE;
+ }
+
+ /* these aren't the droids you're looking for */
+ return FALSE;
+}
+
+static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *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 && 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 );
+ }
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean tool_edit_trackpoint_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 ( event->button != 1)
+ 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 && tp != vtl->current_tpl->data )
+ new_coord = tp->coord;
+ }
+
+ VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
+
+ marker_end_move ( t );
+
+ /* 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 );
+
+ vik_layer_emit_update ( VIK_LAYER(vtl) );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*** Magic Scissors ***/
+static gpointer tool_magic_scissors_create ( VikWindow *vw, VikViewport *vvp)
+{
+ return vvp;
+}
+
+static gboolean tool_magic_scissors_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+{
+ VikCoord tmp;
+ if ( !vtl ) return FALSE;
+ vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp );
+ if ( event->button == 3 && vtl->magic_scissors_current_track ) {
+ VikCoord *new_end;
+ new_end = vik_track_cut_back_to_double_point ( vtl->magic_scissors_current_track );
+ if ( new_end ) {
+ vtl->magic_scissors_coord = *new_end;
+ g_free ( new_end );
+ vik_layer_emit_update ( VIK_LAYER(vtl) );
+ /* remove last ' to:...' */
+ if ( vtl->magic_scissors_current_track->comment ) {
+ gchar *last_to = strrchr ( vtl->magic_scissors_current_track->comment, 't' );
+ if ( last_to && (last_to - vtl->magic_scissors_current_track->comment > 1) ) {
+ gchar *new_comment = g_strndup ( vtl->magic_scissors_current_track->comment,
+ last_to - vtl->magic_scissors_current_track->comment - 1);
+ vik_track_set_comment_no_copy ( vtl->magic_scissors_current_track, new_comment );
+ }
+ }
+ }
+ }
+ else if ( vtl->magic_scissors_started || (event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track) ) {
+ struct LatLon start, end;
+ gchar startlat[G_ASCII_DTOSTR_BUF_SIZE], startlon[G_ASCII_DTOSTR_BUF_SIZE];
+ gchar endlat[G_ASCII_DTOSTR_BUF_SIZE], endlon[G_ASCII_DTOSTR_BUF_SIZE];
+ gchar *url;
+
+ vik_coord_to_latlon ( &(vtl->magic_scissors_coord), &start );
+ vik_coord_to_latlon ( &(tmp), &end );
+ vtl->magic_scissors_coord = tmp; /* for continuations */
+
+ /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
+ if ( event->state & GDK_CONTROL_MASK && vtl->magic_scissors_current_track ) {
+ vtl->magic_scissors_append = TRUE; // merge tracks. keep started true.
+ } else {
+ vtl->magic_scissors_check_added_track = TRUE;
+ vtl->magic_scissors_started = FALSE;
+ }
+
+ url = g_strdup_printf(GOOGLE_DIRECTIONS_STRING,
+ g_ascii_dtostr (startlat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) start.lat),
+ g_ascii_dtostr (startlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) start.lon),
+ g_ascii_dtostr (endlat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lat),
+ g_ascii_dtostr (endlon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) end.lon));
+ a_babel_convert_from_url ( vtl, url, "kml", NULL, NULL );
+ g_free ( url );
+
+ /* see if anything was done -- a track was added or appended to */
+ if ( vtl->magic_scissors_check_added_track && vtl->magic_scissors_added_track_name ) {
+ VikTrack *tr;
+
+ tr = g_hash_table_lookup ( vtl->tracks, vtl->magic_scissors_added_track_name );
+
+ if ( tr )
+ vik_track_set_comment_no_copy ( tr, g_strdup_printf("from: %f,%f to: %f%f", start.lat, start.lon, end.lat, end.lon ) );
+
+ vtl->magic_scissors_current_track = tr;
+
+ g_free ( vtl->magic_scissors_added_track_name );
+ vtl->magic_scissors_added_track_name = NULL;
+ } else if ( vtl->magic_scissors_append == FALSE && vtl->magic_scissors_current_track ) {
+ /* magic_scissors_append was originally TRUE but set to FALSE by filein_add_track */
+ gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->magic_scissors_current_track->comment, end.lat, end.lon );
+ vik_track_set_comment_no_copy ( vtl->magic_scissors_current_track, new_comment );
+ }
+ vtl->magic_scissors_check_added_track = FALSE;
+ vtl->magic_scissors_append = FALSE;
+
+ vik_layer_emit_update ( VIK_LAYER(vtl) );
+ } else {
+ vtl->magic_scissors_started = TRUE;
+ vtl->magic_scissors_coord = tmp;
+ vtl->magic_scissors_current_track = NULL;
+ }
+ return TRUE;
+}
+
+/*** 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 )
+ {
+ 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. */
+ }
+ }
+}
+
+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] )
+ {
+ /* 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 ) )
+ {
+ a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch eog to open file.") );
+ g_error_free ( err );
+ }
+ g_free ( cmd );
+#endif /* WINDOWS */
+ return TRUE; /* found a match */
+ }
+ else
+ return FALSE; /* go through other layers, searching for a match */
+}
+
+/***************************************************************************
+ ** End tool code
+ ***************************************************************************/
+
+
+
+
+
+static void image_wp_make_list ( char *name, VikWaypoint *wp, GSList **pics )
+{
+ if ( wp->image && ( ! a_thumbnails_exists ( wp->image ) ) )
+ *pics = g_slist_append ( *pics, (gpointer) g_strdup ( wp->image ) );
+}
+
+static void create_thumbnails_thread ( GSList *pics, gpointer threaddata )
+{
+ guint total = g_slist_length(pics), done = 0;
+ while ( pics )
+ {
+ a_thumbnails_create ( (gchar *) pics->data );
+ a_background_thread_progress ( threaddata, ((gdouble) ++done) / total );
+ pics = pics->next;
+ }
+}
+
+static void free_pics_slist ( GSList *pics )