]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrwlayer.c
Fix drawing of copied MBTiles map layers.
[andy/viking.git] / src / viktrwlayer.c
index 262650177917295b107b22a402541173982d0d7e..f69e03e4bb7a7904d6d2e789cf4b9e98cbde801d 100644 (file)
@@ -710,7 +710,7 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *i
 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 gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
-static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
+static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp, tool_ed_t *t );
 static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
 static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
 /* End Layer Interface function definitions */
@@ -777,28 +777,48 @@ VikLayerInterface vik_trw_layer_interface = {
 };
 
 static gboolean have_diary_program = FALSE;
+static gchar *diary_program = NULL;
+#define VIK_SETTINGS_EXTERNAL_DIARY_PROGRAM "external_diary_program"
+
 static gboolean have_geojson_export = FALSE;
 
+static gboolean have_astro_program = FALSE;
+static gchar *astro_program = NULL;
+#define VIK_SETTINGS_EXTERNAL_ASTRO_PROGRAM "external_astro_program"
 
 // NB Only performed once per program run
 static void vik_trwlayer_class_init ( VikTrwLayerClass *klass )
 {
-  if ( g_find_program_in_path( "rednotebook" ) ) {
-    gchar *stdout = NULL;
-    gchar *stderr = NULL;
+  if ( ! a_settings_get_string ( VIK_SETTINGS_EXTERNAL_DIARY_PROGRAM, &diary_program ) ) {
+#ifdef WINDOWS
+    //diary_program = g_strdup ( "C:\\Program Files\\Rednotebook\\rednotebook.exe" );
+    diary_program = g_strdup ( "C:/Progra~1/Rednotebook/rednotebook.exe" );
+#else
+    diary_program = g_strdup ( "rednotebook" );
+#endif
+  }
+  else {
+    // User specified so assume it works
+    have_diary_program = TRUE;
+  }
+
+  if ( g_find_program_in_path( diary_program ) ) {
+    gchar *mystdout = NULL;
+    gchar *mystderr = NULL;
     // Needs RedNotebook 1.7.3+ for support of opening on a specified date
-    if ( g_spawn_command_line_sync ( "rednotebook --version", &stdout, &stderr, NULL, NULL ) ) {
+    gchar *cmd = g_strconcat ( diary_program, " --version", NULL ); // "rednotebook --version"
+    if ( g_spawn_command_line_sync ( cmd, &mystdout, &mystderr, NULL, NULL ) ) {
       // Annoyingly 1.7.1|2|3 versions of RedNotebook prints the version to stderr!!
-      if ( stdout )
-        g_debug ("Diary: %s", stdout ); // Should be something like 'RedNotebook 1.4'
-      if ( stderr )
-        g_warning ("Diary: stderr: %s", stderr );
+      if ( mystdout )
+        g_debug ("Diary: %s", mystdout ); // Should be something like 'RedNotebook 1.4'
+      if ( mystderr )
+        g_warning ("Diary: stderr: %s", mystderr );
 
       gchar **tokens = NULL;
-      if ( stdout && g_strcmp0(stdout, "") )
-        tokens = g_strsplit(stdout, " ", 0);
-      else if ( stderr )
-        tokens = g_strsplit(stderr, " ", 0);
+      if ( mystdout && g_strcmp0(mystdout, "") )
+        tokens = g_strsplit(mystdout, " ", 0);
+      else if ( mystderr )
+        tokens = g_strsplit(mystderr, " ", 0);
 
       gint num = 0;
       gchar *token = tokens[num];
@@ -812,13 +832,31 @@ static void vik_trwlayer_class_init ( VikTrwLayerClass *klass )
       }
       g_strfreev ( tokens );
     }
-    g_free ( stdout );
-    g_free ( stderr );
+    g_free ( mystdout );
+    g_free ( mystderr );
+    g_free ( cmd );
   }
 
   if ( g_find_program_in_path ( a_geojson_program_export() ) ) {
     have_geojson_export = TRUE;
   }
+
+  // Astronomy Domain
+  if ( ! a_settings_get_string ( VIK_SETTINGS_EXTERNAL_ASTRO_PROGRAM, &astro_program ) ) {
+#ifdef WINDOWS
+    //astro_program = g_strdup ( "C:\\Program Files\\Stellarium\\stellarium.exe" );
+    astro_program = g_strdup ( "C:/Progra~1/Stellarium/stellarium.exe" );
+#else
+    astro_program = g_strdup ( "stellarium" );
+#endif
+  }
+  else {
+    // User specified so assume it works
+    have_astro_program = TRUE;
+  }
+  if ( g_find_program_in_path( astro_program ) ) {
+    have_astro_program = TRUE;
+  }
 }
 
 GType vik_trw_layer_get_type ()
@@ -2999,13 +3037,18 @@ static void set_statusbar_msg_info_trkpt ( VikTrwLayer *vtl, VikTrackpoint *trkp
 {
   gchar *statusbar_format_code = NULL;
   gboolean need2free = FALSE;
+  VikTrackpoint *trkpt_prev = NULL;
   if ( !a_settings_get_string ( VIK_SETTINGS_TRKPT_SELECTED_STATUSBAR_FORMAT, &statusbar_format_code ) ) {
     // Otherwise use default
     statusbar_format_code = g_strdup ( "KEATDN" );
     need2free = TRUE;
   }
+  else {
+    // Format code may want to show speed - so may need previous trkpt to work it out
+    trkpt_prev = vik_track_get_tp_prev ( vtl->current_tp_track, trkpt );
+  }
 
-  gchar *msg = vu_trackpoint_formatted_message ( statusbar_format_code, trkpt, NULL, vtl->current_tp_track );
+  gchar *msg = vu_trackpoint_formatted_message ( statusbar_format_code, trkpt, trkpt_prev, vtl->current_tp_track, NAN );
   vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
   g_free ( msg );
 
@@ -6596,14 +6639,17 @@ static void trw_layer_reverse ( menu_array_sublayer values )
 }
 
 /**
- * Open a diary at the specified date
+ * Open a program at the specified date
+ * Mainly for RedNotebook - http://rednotebook.sourceforge.net/
+ * But could work with any program that accepts a command line of --date=<date>
+ * FUTURE: Allow configuring of command line options + date format
  */
 static void trw_layer_diary_open ( VikTrwLayer *vtl, const gchar *date_str )
 {
   GError *err = NULL;
-  gchar *cmd = g_strdup_printf ( "%s%s", "rednotebook --date=", date_str );
+  gchar *cmd = g_strdup_printf ( "%s %s%s", diary_program, "--date=", date_str );
   if ( ! g_spawn_command_line_async ( cmd, &err ) ) {
-    a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch %s to open file."), "rednotebook" );
+    a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch %s to open file."), diary_program );
     g_error_free ( err );
   }
   g_free ( cmd );
@@ -6646,6 +6692,131 @@ static void trw_layer_diary ( menu_array_sublayer values )
   }
 }
 
+/**
+ * Open a program at the specified date
+ * Mainly for Stellarium - http://stellarium.org/
+ * But could work with any program that accepts the same command line options...
+ * FUTURE: Allow configuring of command line options + format or parameters
+ */
+static void trw_layer_astro_open ( VikTrwLayer *vtl, const gchar *date_str, const gchar *time_str, const gchar *lat_str, const gchar *lon_str, const gchar *alt_str )
+{
+  GError *err = NULL;
+  gchar *tmp;
+  g_file_open_tmp ( "vik-astro-XXXXXX.ini", &tmp, NULL );
+  gchar *cmd = g_strdup_printf ( "%s %s %s %s %s %s %s %s %s %s %s %s %s %s",
+                                  astro_program, "-c", tmp, "--full-screen no", "--sky-date", date_str, "--sky-time", time_str, "--latitude", lat_str, "--longitude", lon_str, "--altitude", alt_str );
+  g_warning ( "%s", cmd );
+  if ( ! g_spawn_command_line_async ( cmd, &err ) ) {
+    a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch %s"), astro_program );
+    g_warning ( "%s", err->message );
+    g_error_free ( err );
+  }
+  util_add_to_deletion_list ( tmp );
+  g_free ( tmp );
+  g_free ( cmd );
+}
+
+// Format of stellarium lat & lon seems designed to be particularly awkward
+//  who uses ' & " in the parameters for the command line?!
+// -1d4'27.48"
+// +53d58'16.65"
+static gchar *convert_to_dms ( gdouble dec )
+{
+  gdouble tmp;
+  gchar sign_c = ' ';
+  gint val_d, val_m;
+  gdouble val_s;
+  gchar *result = NULL;
+
+  if ( dec > 0 )
+    sign_c = '+';
+  else if ( dec < 0 )
+    sign_c = '-';
+  else // Nul value
+    sign_c = ' ';
+
+  // Degrees
+  tmp = fabs(dec);
+  val_d = (gint)tmp;
+
+  // Minutes
+  tmp = (tmp - val_d) * 60;
+  val_m = (gint)tmp;
+
+  // Seconds
+  val_s = (tmp - val_m) * 60;
+
+  // Format
+  result = g_strdup_printf ( "%c%dd%d\\\'%.4f\\\"", sign_c, val_d, val_m, val_s );
+  return result;
+}
+
+/**
+ * Open an astronomy program at the date & position of the track center, trackpoint or waypoint
+ */
+static void trw_layer_astro ( menu_array_sublayer values )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+
+  if ( GPOINTER_TO_INT(values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
+    VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
+    if ( ! trk )
+      return;
+
+    VikTrackpoint *tp = NULL;
+    if ( vtl->current_tpl )
+      // Current Trackpoint
+      tp = VIK_TRACKPOINT(vtl->current_tpl->data);
+    else if ( trk->trackpoints )
+      // Otherwise first trackpoint
+      tp = VIK_TRACKPOINT(trk->trackpoints->data);
+    else
+      // Give up
+      return;
+
+    if ( tp->has_timestamp ) {
+      gchar date_buf[20];
+      strftime (date_buf, sizeof(date_buf), "%Y%m%d", gmtime(&(tp->timestamp)));
+      gchar time_buf[20];
+      strftime (time_buf, sizeof(time_buf), "%H:%M:%S", gmtime(&(tp->timestamp)));
+      struct LatLon ll;
+      vik_coord_to_latlon ( &tp->coord, &ll );
+      gchar *lat_str = convert_to_dms ( ll.lat );
+      gchar *lon_str = convert_to_dms ( ll.lon );
+      gchar alt_buf[20];
+      snprintf (alt_buf, sizeof(alt_buf), "%d", (gint)round(tp->altitude) );
+      trw_layer_astro_open ( vtl, date_buf, time_buf, lat_str, lon_str, alt_buf);
+      g_free ( lat_str );
+      g_free ( lon_str );
+    }
+    else
+      a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This track has no date information.") );
+  }
+  else if ( GPOINTER_TO_INT(values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
+    VikWaypoint *wpt = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
+    if ( ! wpt )
+      return;
+
+    if ( wpt->has_timestamp ) {
+      gchar date_buf[20];
+      strftime (date_buf, sizeof(date_buf), "%Y%m%d", gmtime(&(wpt->timestamp)));
+      gchar time_buf[20];
+      strftime (time_buf, sizeof(time_buf), "%H:%M:%S", gmtime(&(wpt->timestamp)));
+      struct LatLon ll;
+      vik_coord_to_latlon ( &wpt->coord, &ll );
+      gchar *lat_str = convert_to_dms ( ll.lat );
+      gchar *lon_str = convert_to_dms ( ll.lon );
+      gchar alt_buf[20];
+      snprintf (alt_buf, sizeof(alt_buf), "%d", (gint)round(wpt->altitude) );
+      trw_layer_astro_open ( vtl, date_buf, time_buf, lat_str, lon_str, alt_buf );
+      g_free ( lat_str );
+      g_free ( lon_str );
+    }
+    else
+      a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This waypoint has no date information.") );
+  }
+}
+
 /**
  * Similar to trw_layer_enum_item, but this uses a sorted method
  */
@@ -8312,12 +8483,28 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
   }
 
   // Only made available if a suitable program is installed
-  if ( have_diary_program ) {
-    if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
-      item = gtk_image_menu_item_new_with_mnemonic ( _("Diar_y") );
+  if ( (have_astro_program || have_diary_program) &&
+       (subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) ) {
+    GtkWidget *external_submenu;
+    external_submenu = gtk_menu_new ();
+    item = gtk_image_menu_item_new_with_mnemonic ( _("Externa_l") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_EXECUTE, GTK_ICON_SIZE_MENU) );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+    gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), external_submenu );
+
+    if ( have_diary_program ) {
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_Diary") );
       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SPELL_CHECK, GTK_ICON_SIZE_MENU) );
       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_diary), pass_along );
-      gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(external_submenu), item );
+      gtk_widget_show ( item );
+    }
+
+    if ( have_astro_program ) {
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_Astronomy") );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_astro), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(external_submenu), item );
       gtk_widget_show ( item );
     }
   }
@@ -8821,7 +9008,7 @@ static void marker_moveto ( tool_ed_t *t, gint x, gint y );
 static void marker_end_move ( tool_ed_t *t );
 //
 
-static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t )
+static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp, tool_ed_t* t )
 {
   if ( t->holding ) {
     VikCoord new_coord;
@@ -8861,6 +9048,11 @@ static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *eve
 {
   if ( t->holding && event->button == 1 )
   {
+    // Prevent accidental (small) shifts when specific movement has not been requested
+    //  (as the click release has occurred within the click object detection area)
+    if ( !t->moving )
+      return FALSE;
+
     VikCoord new_coord;
     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
 
@@ -9183,6 +9375,7 @@ static void marker_begin_move ( tool_ed_t *t, gint x, gint y )
   vik_viewport_sync(t->vvp);
   t->oldx = x;
   t->oldy = y;
+  t->moving = FALSE;
 }
 
 static void marker_moveto ( tool_ed_t *t, gint x, gint y )
@@ -9192,6 +9385,7 @@ static void marker_moveto ( tool_ed_t *t, gint x, gint y )
   vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
   t->oldx = x;
   t->oldy = y;
+  t->moving = TRUE;
 
   if (tool_sync_done) {
     g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, tool_sync, vvp, NULL);
@@ -9204,6 +9398,7 @@ 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;
+  t->moving = FALSE;
 }
 
 /*** Edit waypoint ****/