2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include <glib/gi18n.h>
35 #include "viktrwlayer.h"
36 #include "viktrwlayer_propwin.h"
37 #include "vikwaypoint.h"
42 #include "vikviewport.h" /* ugh */
43 #include "viktreeview.h" /* ugh */
44 #include <gdk-pixbuf/gdk-pixdata.h>
45 #include "viklayer.h" /* ugh */
46 #include "vikaggregatelayer.h"
47 #include "viklayerspanel.h" /* ugh */
49 #define PROFILE_WIDTH 600
50 #define PROFILE_HEIGHT 300
51 #define MIN_ALT_DIFF 100.0
52 #define MIN_SPEED_DIFF 20.0
54 typedef struct _propsaved
{
60 typedef struct _propwidgets
{
66 GtkWidget
*w_track_length
;
67 GtkWidget
*w_tp_count
;
68 GtkWidget
*w_segment_count
;
69 GtkWidget
*w_duptp_count
;
70 GtkWidget
*w_max_speed
;
71 GtkWidget
*w_avg_speed
;
72 GtkWidget
*w_avg_dist
;
73 GtkWidget
*w_elev_range
;
74 GtkWidget
*w_elev_gain
;
75 GtkWidget
*w_time_start
;
76 GtkWidget
*w_time_end
;
77 GtkWidget
*w_time_dur
;
78 GtkWidget
*w_dist_time
;
79 PropSaved elev_graph_saved_img
;
80 PropSaved speed_graph_saved_img
;
83 static PropWidgets
*prop_widgets_new()
85 PropWidgets
*widgets
= g_malloc0(sizeof(PropWidgets
));
90 static void prop_widgets_free(PropWidgets
*widgets
)
93 if (widgets
->elev_graph_saved_img
.img
)
94 g_object_unref(widgets
->elev_graph_saved_img
.img
);
95 if (widgets
->speed_graph_saved_img
.img
)
96 g_object_unref(widgets
->speed_graph_saved_img
.img
);
100 static void minmax_alt(const gdouble
*altitudes
, gdouble
*min
, gdouble
*max
)
105 for ( i
=0; i
< PROFILE_WIDTH
; i
++ ) {
106 if ( altitudes
[i
] != VIK_DEFAULT_ALTITUDE
) {
107 if ( altitudes
[i
] > *max
)
109 if ( altitudes
[i
] < *min
)
117 static void set_center_at_graph_position(gdouble event_x
, gint img_width
, VikLayersPanel
*vlp
, VikTrack
*tr
, gboolean time_base
)
119 VikTrackpoint
*trackpoint
;
120 gdouble x
= event_x
- img_width
/ 2 + PROFILE_WIDTH
/ 2 - MARGIN
/ 2;
123 if (x
> PROFILE_WIDTH
)
127 trackpoint
= vik_track_get_closest_tp_by_percentage_time ( tr
, (gdouble
) x
/ PROFILE_WIDTH
, NULL
);
129 trackpoint
= vik_track_get_closest_tp_by_percentage_dist ( tr
, (gdouble
) x
/ PROFILE_WIDTH
, NULL
);
132 VikCoord coord
= trackpoint
->coord
;
133 vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(vlp
), &coord
);
134 vik_layers_panel_emit_update ( vlp
);
138 static void draw_graph_mark(GtkWidget
*image
, gdouble x
, GdkGC
*gc
, PropSaved
*saved_img
)
141 const int saved_width
= 5;
143 gtk_image_get_pixmap(GTK_IMAGE(image
), &pix
, NULL
);
144 if (saved_img
->saved
) {
145 gdk_draw_image(GDK_DRAWABLE(pix
), gc
, saved_img
->img
, 0, 0,
146 saved_img
->pos
, 0, -1, -1);
147 saved_img
->saved
= FALSE
;
148 gtk_widget_queue_draw_area(image
, saved_img
->pos
, 0,
149 saved_img
->img
->width
, saved_img
->img
->height
);
151 if ((x
>= MARGIN
) && (x
< (PROFILE_WIDTH
+ MARGIN
))) {
153 gdk_drawable_copy_to_image(GDK_DRAWABLE(pix
), saved_img
->img
,
154 x
- (saved_width
/2), 0, 0, 0, saved_img
->img
->width
, saved_img
->img
->height
);
156 saved_img
->img
= gdk_drawable_copy_to_image(GDK_DRAWABLE(pix
),
157 saved_img
->img
, x
- (saved_width
/2), 0, 0, 0, saved_width
, PROFILE_HEIGHT
);
158 saved_img
->pos
= x
- (saved_width
/2);
159 saved_img
->saved
= TRUE
;
160 gdk_draw_line (GDK_DRAWABLE(pix
), gc
, x
, 0, x
, image
->allocation
.height
);
161 /* redraw the area which contains the line, saved_width is just convenient */
162 gtk_widget_queue_draw_area(image
, x
- saved_width
/2, 0, saved_width
, PROFILE_HEIGHT
);
166 static void track_graph_click( GtkWidget
*event_box
, GdkEventButton
*event
, gpointer
*pass_along
, gboolean is_vt_graph
)
168 VikTrack
*tr
= pass_along
[0];
169 VikLayersPanel
*vlp
= pass_along
[1];
170 PropWidgets
*widgets
= pass_along
[2];
171 GList
*child
= gtk_container_get_children(GTK_CONTAINER(event_box
));
172 GtkWidget
*image
= GTK_WIDGET(child
->data
);
173 GtkWidget
*window
= gtk_widget_get_toplevel(GTK_WIDGET(event_box
));
176 set_center_at_graph_position(event
->x
, event_box
->allocation
.width
, vlp
, tr
, is_vt_graph
);
177 draw_graph_mark(image
, event
->x
, window
->style
->black_gc
,
178 is_vt_graph
? &widgets
->speed_graph_saved_img
: &widgets
->elev_graph_saved_img
);
183 static gboolean
track_profile_click( GtkWidget
*event_box
, GdkEventButton
*event
, gpointer
*pass_along
)
185 track_graph_click(event_box
, event
, pass_along
, FALSE
);
186 return TRUE
; /* don't call other (further) callbacks */
189 static gboolean
track_vt_click( GtkWidget
*event_box
, GdkEventButton
*event
, gpointer
*pass_along
)
191 track_graph_click(event_box
, event
, pass_along
, TRUE
);
192 return TRUE
; /* don't call other (further) callbacks */
195 void track_profile_move( GtkWidget
*image
, GdkEventMotion
*event
, gpointer
*pass_along
)
197 VikTrack
*tr
= pass_along
[0];
198 PropWidgets
*widgets
= pass_along
[2];
199 int mouse_x
, mouse_y
;
200 GdkModifierType state
;
203 gdk_window_get_pointer (event
->window
, &mouse_x
, &mouse_y
, &state
);
207 gdouble x
= mouse_x
- image
->allocation
.width
/ 2 + PROFILE_WIDTH
/ 2 - MARGIN
/ 2;
210 if (x
> PROFILE_WIDTH
)
213 gdouble meters_from_start
;
214 VikTrackpoint
*trackpoint
= vik_track_get_closest_tp_by_percentage_dist ( tr
, (gdouble
) x
/ PROFILE_WIDTH
, &meters_from_start
);
215 if (trackpoint
&& widgets
->w_dist_time
) {
216 static gchar tmp_buf
[20];
217 g_snprintf(tmp_buf
, sizeof(tmp_buf
), "%.0f m", meters_from_start
);
218 gtk_label_set_text(GTK_LABEL(widgets
->w_dist_time
), tmp_buf
);
222 void track_vt_move( GtkWidget
*image
, GdkEventMotion
*event
, gpointer
*pass_along
)
224 VikTrack
*tr
= pass_along
[0];
225 PropWidgets
*widgets
= pass_along
[2];
226 int mouse_x
, mouse_y
;
227 GdkModifierType state
;
230 gdk_window_get_pointer (event
->window
, &mouse_x
, &mouse_y
, &state
);
234 gdouble x
= mouse_x
- image
->allocation
.width
/ 2 + PROFILE_WIDTH
/ 2 - MARGIN
/ 2;
237 if (x
> PROFILE_WIDTH
)
240 time_t seconds_from_start
;
241 VikTrackpoint
*trackpoint
= vik_track_get_closest_tp_by_percentage_time ( tr
, (gdouble
) x
/ PROFILE_WIDTH
, &seconds_from_start
);
242 if (trackpoint
&& widgets
->w_dist_time
) {
243 static gchar tmp_buf
[20];
245 h
= seconds_from_start
/3600;
246 m
= (seconds_from_start
- h
*3600)/60;
247 s
= seconds_from_start
- (3600*h
) - (60*m
);
248 g_snprintf(tmp_buf
, sizeof(tmp_buf
), "%02d:%02d:%02d", h
, m
, s
);
250 gtk_label_set_text(GTK_LABEL(widgets
->w_dist_time
), tmp_buf
);
254 static void draw_dem_alt_speed_dist(VikTrack
*tr
, GdkDrawable
*pix
, GdkGC
*alt_gc
, GdkGC
*speed_gc
, gdouble alt_offset
, gdouble alt_diff
, gint width
, gint height
, gint margin
)
258 gdouble max_speed
= 0;
259 gdouble total_length
= vik_track_get_length_including_gaps(tr
);
261 for (iter
= tr
->trackpoints
->next
; iter
; iter
= iter
->next
) {
262 if (!isnan(VIK_TRACKPOINT(iter
->data
)->speed
))
263 max_speed
= MAX(max_speed
, VIK_TRACKPOINT(iter
->data
)->speed
);
265 max_speed
= max_speed
* 110 / 100;
267 for (iter
= tr
->trackpoints
->next
; iter
; iter
= iter
->next
) {
268 int x
, y_alt
, y_speed
;
269 gint16 elev
= a_dems_get_elev_by_coord(&(VIK_TRACKPOINT(iter
->data
)->coord
), VIK_DEM_INTERPOL_BEST
);
271 dist
+= vik_coord_diff ( &(VIK_TRACKPOINT(iter
->data
)->coord
),
272 &(VIK_TRACKPOINT(iter
->prev
->data
)->coord
) );
273 x
= (width
* dist
)/total_length
+ margin
;
274 if ( elev
!= VIK_DEM_INVALID_ELEVATION
) {
275 y_alt
= height
- ((height
* elev
)/alt_diff
);
276 gdk_draw_rectangle(GDK_DRAWABLE(pix
), alt_gc
, TRUE
, x
-2, y_alt
-2, 4, 4);
278 if (!isnan(VIK_TRACKPOINT(iter
->data
)->speed
)) {
279 y_speed
= height
- (height
* VIK_TRACKPOINT(iter
->data
)->speed
)/max_speed
;
280 gdk_draw_rectangle(GDK_DRAWABLE(pix
), speed_gc
, TRUE
, x
-2, y_speed
-2, 4, 4);
285 GtkWidget
*vik_trw_layer_create_profile ( GtkWidget
*window
, VikTrack
*tr
, gpointer vlp
, PropWidgets
*widgets
, gdouble
*min_alt
, gdouble
*max_alt
)
289 gdouble
*altitudes
= vik_track_make_elevation_map ( tr
, PROFILE_WIDTH
);
292 gpointer
*pass_along
;
295 if ( altitudes
== NULL
) {
296 *min_alt
= *max_alt
= VIK_DEFAULT_ALTITUDE
;
300 pix
= gdk_pixmap_new( window
->window
, PROFILE_WIDTH
+ MARGIN
, PROFILE_HEIGHT
, -1 );
301 image
= gtk_image_new_from_pixmap ( pix
, NULL
);
303 GdkGC
*no_alt_info
= gdk_gc_new ( window
->window
);
304 GdkGC
*dem_alt_gc
= gdk_gc_new ( window
->window
);
305 GdkGC
*gps_speed_gc
= gdk_gc_new ( window
->window
);
308 gdk_color_parse ( "yellow", &color
);
309 gdk_gc_set_rgb_fg_color ( no_alt_info
, &color
);
310 gdk_color_parse ( "green", &color
);
311 gdk_gc_set_rgb_fg_color ( dem_alt_gc
, &color
);
312 gdk_color_parse ( "red", &color
);
313 gdk_gc_set_rgb_fg_color ( gps_speed_gc
, &color
);
316 minmax_alt(altitudes
, min_alt
, max_alt
);
318 maxa
= *max_alt
+ ((*max_alt
- *min_alt
) * 0.25);
320 /* clear the image */
321 gdk_draw_rectangle(GDK_DRAWABLE(pix
), window
->style
->bg_gc
[0],
322 TRUE
, 0, 0, MARGIN
, PROFILE_HEIGHT
);
323 gdk_draw_rectangle(GDK_DRAWABLE(pix
), window
->style
->mid_gc
[0],
324 TRUE
, MARGIN
, 0, PROFILE_WIDTH
, PROFILE_HEIGHT
);
327 #define LABEL_FONT "Sans 8"
328 for (i
=0; i
<=LINES
; i
++) {
329 PangoFontDescription
*pfd
;
330 PangoLayout
*pl
= gtk_widget_create_pango_layout (GTK_WIDGET(image
), NULL
);
333 pfd
= pango_font_description_from_string (LABEL_FONT
);
334 pango_layout_set_font_description (pl
, pfd
);
335 pango_font_description_free (pfd
);
336 sprintf(s
, "%8dm", (int)(mina
+ (LINES
-i
)*(maxa
-mina
)/LINES
));
337 pango_layout_set_text(pl
, s
, -1);
338 gdk_draw_layout(GDK_DRAWABLE(pix
), window
->style
->fg_gc
[0], 0,
339 CLAMP((int)i
*PROFILE_HEIGHT
/LINES
- 5, 0, PROFILE_HEIGHT
-15), pl
);
341 gdk_draw_line (GDK_DRAWABLE(pix
), window
->style
->dark_gc
[0],
342 MARGIN
, PROFILE_HEIGHT
/LINES
* i
, MARGIN
+ PROFILE_WIDTH
, PROFILE_HEIGHT
/LINES
* i
);
345 /* draw elevations */
346 for ( i
= 0; i
< PROFILE_WIDTH
; i
++ )
347 if ( altitudes
[i
] == VIK_DEFAULT_ALTITUDE
)
348 gdk_draw_line ( GDK_DRAWABLE(pix
), no_alt_info
,
349 i
+ MARGIN
, 0, i
+ MARGIN
, PROFILE_HEIGHT
);
351 gdk_draw_line ( GDK_DRAWABLE(pix
), window
->style
->dark_gc
[3],
352 i
+ MARGIN
, PROFILE_HEIGHT
, i
+ MARGIN
, PROFILE_HEIGHT
-PROFILE_HEIGHT
*(altitudes
[i
]-mina
)/(maxa
-mina
) );
354 draw_dem_alt_speed_dist(tr
, GDK_DRAWABLE(pix
), dem_alt_gc
, gps_speed_gc
, mina
, maxa
- mina
, PROFILE_WIDTH
, PROFILE_HEIGHT
, MARGIN
);
357 gdk_draw_rectangle(GDK_DRAWABLE(pix
), window
->style
->black_gc
, FALSE
, MARGIN
, 0, PROFILE_WIDTH
-1, PROFILE_HEIGHT
-1);
361 g_object_unref ( G_OBJECT(pix
) );
362 g_free ( altitudes
);
363 g_object_unref ( G_OBJECT(no_alt_info
) );
364 g_object_unref ( G_OBJECT(dem_alt_gc
) );
365 g_object_unref ( G_OBJECT(gps_speed_gc
) );
367 pass_along
= g_malloc ( sizeof(gpointer
) * 3 ); /* FIXME: mem leak -- never be freed */
370 pass_along
[2] = widgets
;
372 eventbox
= gtk_event_box_new ();
373 g_signal_connect ( G_OBJECT(eventbox
), "button_press_event", G_CALLBACK(track_profile_click
), pass_along
);
374 g_signal_connect ( G_OBJECT(eventbox
), "motion_notify_event", G_CALLBACK(track_profile_move
), pass_along
);
375 g_signal_connect_swapped ( G_OBJECT(eventbox
), "destroy", G_CALLBACK(g_free
), pass_along
);
376 gtk_container_add ( GTK_CONTAINER(eventbox
), image
);
377 gtk_widget_set_events (eventbox
, GDK_BUTTON_PRESS_MASK
378 | GDK_POINTER_MOTION_MASK
379 | GDK_POINTER_MOTION_HINT_MASK
);
386 #define MTOK(v) ( (v)*3.6) /* m/s to km/h */
388 #define MTOK(v) ( (v)*3600.0/1000.0 * 0.6214) /* m/s to mph - we'll handle this globally eventually but for now ...*/
391 GtkWidget
*vik_trw_layer_create_vtdiag ( GtkWidget
*window
, VikTrack
*tr
, gpointer vlp
, PropWidgets
*widgets
)
398 gpointer
*pass_along
;
400 pass_along
= g_malloc ( sizeof(gpointer
) * 3 ); /* FIXME: mem leak -- never be freed */
403 pass_along
[2] = widgets
;
405 gdouble
*speeds
= vik_track_make_speed_map ( tr
, PROFILE_WIDTH
);
406 if ( speeds
== NULL
)
409 pix
= gdk_pixmap_new( window
->window
, PROFILE_WIDTH
+ MARGIN
, PROFILE_HEIGHT
, -1 );
410 image
= gtk_image_new_from_pixmap ( pix
, NULL
);
412 for (i
=0; i
<PROFILE_WIDTH
; i
++) {
413 speeds
[i
] = MTOK(speeds
[i
]);
416 minmax_alt(speeds
, &mins
, &maxs
);
418 mins
= 0; /* splines sometimes give negative speeds */
419 maxs
= maxs
+ ((maxs
- mins
) * 0.1);
420 if (maxs
-mins
< MIN_SPEED_DIFF
) {
421 maxs
= mins
+ MIN_SPEED_DIFF
;
424 /* clear the image */
425 gdk_draw_rectangle(GDK_DRAWABLE(pix
), window
->style
->bg_gc
[0],
426 TRUE
, 0, 0, MARGIN
, PROFILE_HEIGHT
);
427 gdk_draw_rectangle(GDK_DRAWABLE(pix
), window
->style
->mid_gc
[0],
428 TRUE
, MARGIN
, 0, PROFILE_WIDTH
, PROFILE_HEIGHT
);
431 /* XXX this can go out, it's just a helpful dev tool */
434 GdkGC
**colors
[8] = { window
->style
->bg_gc
, window
->style
->fg_gc
,
435 window
->style
->light_gc
,
436 window
->style
->dark_gc
, window
->style
->mid_gc
,
437 window
->style
->text_gc
, window
->style
->base_gc
,
438 window
->style
->text_aa_gc
};
439 for (i
=0; i
<5; i
++) {
440 for (j
=0; j
<8; j
++) {
441 gdk_draw_rectangle(GDK_DRAWABLE(pix
), colors
[j
][i
],
442 TRUE
, i
*20, j
*20, 20, 20);
443 gdk_draw_rectangle(GDK_DRAWABLE(pix
), window
->style
->black_gc
,
444 FALSE
, i
*20, j
*20, 20, 20);
451 #define LABEL_FONT "Sans 8"
452 for (i
=0; i
<=LINES
; i
++) {
453 PangoFontDescription
*pfd
;
454 PangoLayout
*pl
= gtk_widget_create_pango_layout (GTK_WIDGET(image
), NULL
);
457 pfd
= pango_font_description_from_string (LABEL_FONT
);
458 pango_layout_set_font_description (pl
, pfd
);
459 pango_font_description_free (pfd
);
461 sprintf(s
, "%5dkm/h", (int)(mins
+ (LINES
-i
)*(maxs
-mins
)/LINES
));
463 sprintf(s
, "%8dmph", (int)(mins
+ (LINES
-i
)*(maxs
-mins
)/LINES
));
465 pango_layout_set_text(pl
, s
, -1);
466 gdk_draw_layout(GDK_DRAWABLE(pix
), window
->style
->fg_gc
[0], 0,
467 CLAMP((int)i
*PROFILE_HEIGHT
/LINES
- 5, 0, PROFILE_HEIGHT
-15), pl
);
469 gdk_draw_line (GDK_DRAWABLE(pix
), window
->style
->dark_gc
[0],
470 MARGIN
, PROFILE_HEIGHT
/LINES
* i
, MARGIN
+ PROFILE_WIDTH
, PROFILE_HEIGHT
/LINES
* i
);
474 for ( i
= 0; i
< PROFILE_WIDTH
; i
++ )
475 gdk_draw_line ( GDK_DRAWABLE(pix
), window
->style
->dark_gc
[3],
476 i
+ MARGIN
, PROFILE_HEIGHT
, i
+ MARGIN
, PROFILE_HEIGHT
-PROFILE_HEIGHT
*(speeds
[i
]-mins
)/(maxs
-mins
) );
480 GdkGC
*gps_speed_gc
= gdk_gc_new ( window
->window
);
483 gdk_color_parse ( "red", &color
);
484 gdk_gc_set_rgb_fg_color ( gps_speed_gc
, &color
);
486 time_t beg_time
= VIK_TRACKPOINT(tr
->trackpoints
->data
)->timestamp
;
487 time_t dur
= VIK_TRACKPOINT(g_list_last(tr
->trackpoints
)->data
)->timestamp
- beg_time
;
489 for (iter
= tr
->trackpoints
; iter
; iter
= iter
->next
) {
490 gdouble gps_speed
= VIK_TRACKPOINT(iter
->data
)->speed
;
491 if (isnan(gps_speed
))
493 int x
= MARGIN
+ PROFILE_WIDTH
* (VIK_TRACKPOINT(iter
->data
)->timestamp
- beg_time
) / dur
;
494 int y
= PROFILE_HEIGHT
- PROFILE_HEIGHT
*(MTOK(gps_speed
) - mins
)/(maxs
- mins
);
495 gdk_draw_rectangle(GDK_DRAWABLE(pix
), gps_speed_gc
, TRUE
, x
-2, y
-2, 4, 4);
499 gdk_draw_rectangle(GDK_DRAWABLE(pix
), window
->style
->black_gc
, FALSE
, MARGIN
, 0, PROFILE_WIDTH
-1, PROFILE_HEIGHT
-1);
501 g_object_unref ( G_OBJECT(pix
) );
502 g_object_unref ( G_OBJECT(gps_speed_gc
) );
505 eventbox
= gtk_event_box_new ();
506 g_signal_connect ( G_OBJECT(eventbox
), "button_press_event", G_CALLBACK(track_vt_click
), pass_along
);
507 g_signal_connect ( G_OBJECT(eventbox
), "motion_notify_event", G_CALLBACK(track_vt_move
), pass_along
);
508 g_signal_connect_swapped ( G_OBJECT(eventbox
), "destroy", G_CALLBACK(g_free
), pass_along
);
509 gtk_container_add ( GTK_CONTAINER(eventbox
), image
);
510 gtk_widget_set_events (eventbox
, GDK_BUTTON_PRESS_MASK
511 | GDK_POINTER_MOTION_MASK
512 | GDK_POINTER_MOTION_HINT_MASK
);
519 static void propwin_response_cb( GtkDialog
*dialog
, gint resp
, PropWidgets
*widgets
)
521 VikTrack
*tr
= widgets
->tr
;
522 VikTrwLayer
*vtl
= widgets
->vtl
;
524 /* FIXME: check and make sure the track still exists before doing anything to it */
525 /* Note: destroying diaglog (eg, parent window exit) won't give "response" */
527 case GTK_RESPONSE_DELETE_EVENT
: /* received delete event (not from buttons) */
528 case GTK_RESPONSE_REJECT
:
530 case GTK_RESPONSE_ACCEPT
:
531 vik_track_set_comment(tr
, gtk_entry_get_text(GTK_ENTRY(widgets
->w_comment
)));
533 case VIK_TRW_LAYER_PROPWIN_REVERSE
:
534 vik_track_reverse(tr
);
535 vik_layer_emit_update ( VIK_LAYER(vtl
) );
537 case VIK_TRW_LAYER_PROPWIN_DEL_DUP
:
538 vik_track_remove_dup_points(tr
);
539 /* above operation could have deleted current_tp or last_tp */
540 trw_layer_cancel_tps_of_track ( vtl
, widgets
->track_name
);
541 vik_layer_emit_update ( VIK_LAYER(vtl
) );
543 case VIK_TRW_LAYER_PROPWIN_SPLIT
:
545 /* get new tracks, add them, resolve naming conflicts (free if cancel), and delete old. old can still exist on clipboard. */
547 VikTrack
**tracks
= vik_track_split_into_segments(tr
, &ntracks
);
550 for ( i
= 0; i
< ntracks
; i
++ )
552 g_assert ( tracks
[i
] );
553 new_tr_name
= g_strdup_printf("%s #%d", widgets
->track_name
, i
+1);
554 /* if ( (wp_exists) && (! overwrite) ) */
555 /* don't need to upper case new_tr_name because old tr name was uppercase */
556 if ( vik_trw_layer_get_track(vtl
, new_tr_name
) &&
557 ( ! a_dialog_overwrite ( VIK_GTK_WINDOW_FROM_LAYER(vtl
), "The track \"%s\" exists, do you wish to overwrite it?", new_tr_name
) ) )
559 gchar
*new_new_tr_name
= a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl
), vik_trw_layer_get_tracks(vtl
) );
560 g_free ( new_tr_name
);
562 new_tr_name
= new_new_tr_name
;
566 vik_track_free ( tracks
[i
] );
570 vik_trw_layer_add_track ( vtl
, new_tr_name
, tracks
[i
] );
575 /* Don't let track destroy this dialog */
576 vik_track_clear_property_dialog(tr
);
577 vik_trw_layer_delete_track ( vtl
, widgets
->track_name
);
578 vik_layer_emit_update ( VIK_LAYER(vtl
) ); /* chase thru the hoops */
583 fprintf(stderr
, "DEBUG: unknown response\n");
587 /* Keep same behaviour for now: destroy dialog if click on any button */
588 prop_widgets_free(widgets
);
589 vik_track_clear_property_dialog(tr
);
590 gtk_widget_destroy ( GTK_WIDGET(dialog
) );
593 void vik_trw_layer_propwin_run ( GtkWindow
*parent
, VikTrwLayer
*vtl
, VikTrack
*tr
, gpointer vlp
, gchar
*track_name
)
595 /* FIXME: free widgets when destroy signal received */
596 PropWidgets
*widgets
= prop_widgets_new();
600 widgets
->track_name
= track_name
;
601 gchar
*title
= g_strdup_printf(_("%s - Track Properties"), track_name
);
602 GtkWidget
*dialog
= gtk_dialog_new_with_buttons (title
,
604 GTK_DIALOG_DESTROY_WITH_PARENT
| GTK_DIALOG_NO_SEPARATOR
,
605 GTK_STOCK_CANCEL
, GTK_RESPONSE_REJECT
,
606 _("Split Segments"), VIK_TRW_LAYER_PROPWIN_SPLIT
,
607 _("Reverse"), VIK_TRW_LAYER_PROPWIN_REVERSE
,
608 _("Delete Dupl."), VIK_TRW_LAYER_PROPWIN_DEL_DUP
,
609 GTK_STOCK_OK
, GTK_RESPONSE_ACCEPT
,
612 g_signal_connect(dialog
, "response", G_CALLBACK(propwin_response_cb
), widgets
);
613 //fprintf(stderr, "DEBUG: dialog=0x%p\n", dialog);
616 guint32 tp_count
, seg_count
;
618 gdouble min_alt
, max_alt
;
619 GtkWidget
*profile
= vik_trw_layer_create_profile(GTK_WIDGET(parent
),tr
, vlp
, widgets
, &min_alt
,&max_alt
);
620 GtkWidget
*vtdiag
= vik_trw_layer_create_vtdiag(GTK_WIDGET(parent
), tr
, vlp
, widgets
);
621 GtkWidget
*graphs
= gtk_notebook_new();
623 GtkWidget
*content
[20];
627 static gchar
*label_texts
[] = { N_("<b>Comment:</b>"), N_("<b>Track Length:</b>"), N_("<b>Trackpoints:</b>"), N_("<b>Segments:</b>"), N_("<b>Duplicate Points:</b>"), N_("<b>Max Speed:</b>"), N_("<b>Avg. Speed:</b>"), N_("<b>Avg. Dist. Between TPs:</b>"), N_("<b>Elevation Range:</b>"), N_("<b>Total Elevation Gain/Loss:</b>"), N_("<b>Start:</b>"), N_("<b>End:</b>"), N_("<b>Duration:</b>"), N_("<b>Track Distance/Time:</b>") };
628 static gchar tmp_buf
[50];
632 widgets
->w_comment
= gtk_entry_new ();
634 gtk_entry_set_text ( GTK_ENTRY(widgets
->w_comment
), tr
->comment
);
635 g_signal_connect_swapped ( widgets
->w_comment
, "activate", G_CALLBACK(a_dialog_response_accept
), GTK_DIALOG(dialog
) );
636 content
[cnt
++] = widgets
->w_comment
;
638 tr_len
= vik_track_get_length(tr
);
639 g_snprintf(tmp_buf
, sizeof(tmp_buf
), "%.2f m", tr_len
);
640 widgets
->w_track_length
= content
[cnt
++] = gtk_label_new ( tmp_buf
);
642 tp_count
= vik_track_get_tp_count(tr
);
643 g_snprintf(tmp_buf
, sizeof(tmp_buf
), "%u", tp_count
);
644 widgets
->w_tp_count
= content
[cnt
++] = gtk_label_new ( tmp_buf
);
646 seg_count
= vik_track_get_segment_count(tr
) ;
647 g_snprintf(tmp_buf
, sizeof(tmp_buf
), "%u", seg_count
);
648 widgets
->w_segment_count
= content
[cnt
++] = gtk_label_new ( tmp_buf
);
650 g_snprintf(tmp_buf
, sizeof(tmp_buf
), "%lu", vik_track_get_dup_point_count(tr
) );
651 widgets
->w_duptp_count
= content
[cnt
++] = gtk_label_new ( tmp_buf
);
653 tmp_speed
= vik_track_get_max_speed(tr
);
654 if ( tmp_speed
== 0 )
655 g_snprintf(tmp_buf
, sizeof(tmp_buf
), _("No Data"));
657 g_snprintf(tmp_buf
, sizeof(tmp_buf
), "%.2f m/s (%.0f km/h)", tmp_speed
, MTOK(tmp_speed
) );
658 widgets
->w_max_speed
= content
[cnt
++] = gtk_label_new ( tmp_buf
);
660 tmp_speed
= vik_track_get_average_speed(tr
);
661 if ( tmp_speed
== 0 )
662 g_snprintf(tmp_buf
, sizeof(tmp_buf
), _("No Data"));
664 g_snprintf(tmp_buf
, sizeof(tmp_buf
), "%.2f m/s (%.0f km/h)", tmp_speed
, MTOK(tmp_speed
) );
665 widgets
->w_avg_speed
= content
[cnt
++] = gtk_label_new ( tmp_buf
);
667 g_snprintf(tmp_buf
, sizeof(tmp_buf
), "%.2f m", (tp_count
- seg_count
) == 0 ? 0 : tr_len
/ ( tp_count
- seg_count
) );
668 widgets
->w_avg_dist
= content
[cnt
++] = gtk_label_new ( tmp_buf
);
670 if ( min_alt
== VIK_DEFAULT_ALTITUDE
)
671 g_snprintf(tmp_buf
, sizeof(tmp_buf
), _("No Data"));
673 g_snprintf(tmp_buf
, sizeof(tmp_buf
), "%.0f m - %.0f m", min_alt
, max_alt
);
674 widgets
->w_elev_range
= content
[cnt
++] = gtk_label_new ( tmp_buf
);
676 vik_track_get_total_elevation_gain(tr
, &max_alt
, &min_alt
);
677 if ( min_alt
== VIK_DEFAULT_ALTITUDE
)
678 g_snprintf(tmp_buf
, sizeof(tmp_buf
), _("No Data"));
680 g_snprintf(tmp_buf
, sizeof(tmp_buf
), "%.0f m / %.0f m", max_alt
, min_alt
);
681 widgets
->w_elev_gain
= content
[cnt
++] = gtk_label_new ( tmp_buf
);
684 #define PACK(w) gtk_box_pack_start (GTK_BOX(right_vbox), w, FALSE, FALSE, 0);
685 gtk_box_pack_start (GTK_BOX(right_vbox
), e_cmt
, FALSE
, FALSE
, 0);
698 if ( tr
->trackpoints
&& VIK_TRACKPOINT(tr
->trackpoints
->data
)->timestamp
)
701 t1
= VIK_TRACKPOINT(tr
->trackpoints
->data
)->timestamp
;
702 t2
= VIK_TRACKPOINT(g_list_last(tr
->trackpoints
)->data
)->timestamp
;
704 strncpy(tmp_buf
, ctime(&t1
), sizeof(tmp_buf
));
705 tmp_buf
[sizeof(tmp_buf
)-1] = 0;
707 widgets
->w_time_start
= content
[cnt
++] = gtk_label_new(tmp_buf
);
709 strncpy(tmp_buf
, ctime(&t2
), sizeof(tmp_buf
));
710 tmp_buf
[sizeof(tmp_buf
)-1] = 0;
712 widgets
->w_time_end
= content
[cnt
++] = gtk_label_new(tmp_buf
);
714 g_snprintf(tmp_buf
, sizeof(tmp_buf
), _("%d minutes"), (int)(t2
-t1
)/60);
715 widgets
->w_time_dur
= content
[cnt
++] = gtk_label_new(tmp_buf
);
717 widgets
->w_time_start
= content
[cnt
++] = gtk_label_new(_("No Data"));
718 widgets
->w_time_end
= content
[cnt
++] = gtk_label_new(_("No Data"));
719 widgets
->w_time_dur
= content
[cnt
++] = gtk_label_new(_("No Data"));
721 widgets
->w_dist_time
= content
[cnt
++] = gtk_label_new(_("No Data"));
723 table
= GTK_TABLE(gtk_table_new (cnt
, 2, FALSE
));
724 gtk_table_set_col_spacing (table
, 0, 10);
725 for (i
=0; i
<cnt
; i
++) {
728 label
= gtk_label_new(NULL
);
729 gtk_misc_set_alignment ( GTK_MISC(label
), 1, 0 );
730 gtk_label_set_markup ( GTK_LABEL(label
), _(label_texts
[i
]) );
731 gtk_table_attach_defaults ( table
, label
, 0, 1, i
, i
+1 );
732 if (GTK_IS_MISC(content
[i
])) {
733 gtk_misc_set_alignment ( GTK_MISC(content
[i
]), 0, 0 );
735 gtk_table_attach_defaults ( table
, content
[i
], 1, 2, i
, i
+1 );
738 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog
)->vbox
), GTK_WIDGET(table
), FALSE
, FALSE
, 0);
741 gtk_notebook_append_page(GTK_NOTEBOOK(graphs
), profile
, gtk_label_new(_("Elevation-distance")));
744 gtk_notebook_append_page(GTK_NOTEBOOK(graphs
), vtdiag
, gtk_label_new(_("Speed-time")));
746 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog
)->vbox
), graphs
, FALSE
, FALSE
, 0);
749 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog
), VIK_TRW_LAYER_PROPWIN_SPLIT
, FALSE
);
750 if (vik_track_get_dup_point_count(tr
) <= 0)
751 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog
), VIK_TRW_LAYER_PROPWIN_DEL_DUP
, FALSE
);
753 vik_track_set_property_dialog(tr
, dialog
);
754 gtk_widget_show_all ( dialog
);