/** \brief Manage toggling of Ground Track. * \param item The menu item that was toggled. * \param data Pointer to the GtkPolarView structure. * */ static void track_toggled (GtkCheckMenuItem *item, gpointer data) { GtkPolarView *pv = GTK_POLAR_VIEW (data); sat_obj_t *obj = NULL; sat_t *sat; qth_t *qth; gint idx,i; GooCanvasItemModel *root; pass_detail_t *detail; guint num; GooCanvasPoints *points; gfloat x,y; guint32 col; guint tres,ttidx; /* get satellite object */ obj = SAT_OBJ(g_object_get_data (G_OBJECT (item), "obj")); sat = SAT(g_object_get_data (G_OBJECT (item), "sat")); qth = (qth_t *)(g_object_get_data (G_OBJECT (item), "qth")); if (obj == NULL) { sat_log_log (SAT_LOG_LEVEL_BUG, _("%s:%d: Failed to get satellite object."), __FILE__, __LINE__); return; } /* toggle flag */ obj->showtrack = !obj->showtrack; gtk_check_menu_item_set_active (item, obj->showtrack); root = goo_canvas_get_root_item_model (GOO_CANVAS (pv->canvas)); if (obj->showtrack) { /* add sky track */ /* create points */ num = g_slist_length (obj->pass->details); if (num == 0) { sat_log_log (SAT_LOG_LEVEL_BUG, _("%s:%d: Pass has no details."), __FILE__, __LINE__); return; } /* time resolution for time ticks; we need 3 additional points to AOS and LOS ticks. */ tres = (num-2) / (TRACK_TICK_NUM-1); points = goo_canvas_points_new (num); /* first point should be (aos_az,0.0) */ azel_to_xy (pv, obj->pass->aos_az, 0.0, &x, &y); points->coords[0] = (double) x; points->coords[1] = (double) y; obj->trtick[0] = create_time_tick (pv, obj->pass->aos, x, y); ttidx = 1; for (i = 1; i < num-1; i++) { detail = PASS_DETAIL(g_slist_nth_data (obj->pass->details, i)); if (detail->el >=0.0) azel_to_xy (pv, detail->az, detail->el, &x, &y); points->coords[2*i] = (double) x; points->coords[2*i+1] = (double) y; if (!(i % tres)) { /* create a time tick */ if (ttidx<TRACK_TICK_NUM) obj->trtick[ttidx] = create_time_tick (pv, detail->time, x, y); ttidx++; } } /* last point should be (los_az, 0.0) */ azel_to_xy (pv, obj->pass->los_az, 0.0, &x, &y); points->coords[2*(num-1)] = (double) x; points->coords[2*(num-1)+1] = (double) y; /* create poly-line */ col = mod_cfg_get_int (pv->cfgdata, MOD_CFG_POLAR_SECTION, MOD_CFG_POLAR_TRACK_COL, SAT_CFG_INT_POLAR_TRACK_COL); obj->track = goo_canvas_polyline_model_new (root, FALSE, 0, "points", points, "line-width", 1.0, "stroke-color-rgba", col, "line-cap", CAIRO_LINE_CAP_SQUARE, "line-join", CAIRO_LINE_JOIN_MITER, NULL); goo_canvas_points_unref (points); /* put track on the bottom of the sack */ goo_canvas_item_model_lower (obj->track, NULL); } else { /* delete sky track */ idx = goo_canvas_item_model_find_child (root, obj->track); if (idx != -1) { goo_canvas_item_model_remove_child (root, idx); } for (i = 0; i < TRACK_TICK_NUM; i++) { idx = goo_canvas_item_model_find_child (root, obj->trtick[i]); if (idx != -1) { goo_canvas_item_model_remove_child (root, idx); } } } }
/** \brief Show details about a satellite pass. * \param parent The parent widget. * \param satname The name of the satellite. * \param qth Pointer to the QTH data. * \param pass The pass info. * \param toplevel The toplevel window or NULL. * * This function creates a dialog window containing a notebook with three pages: * 1. A list showing the details of a pass * 2. Polar plot of the pass * 3. Az/El plot of the pass * * Reference to the parent widget is needed to acquire the correct top-level * window, otherwise simply using the main window would bring that to front * covering any possible module windows. This would be unfortunate in the case * of fullscreen modules. * */ void show_pass (const gchar *satname, qth_t *qth, pass_t *pass, GtkWidget *toplevel) { GtkWidget *dialog; /* the dialogue window */ GtkWidget *notebook; /* the notebook widet */ GtkWidget *list; GtkListStore *liststore; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeIter item; GtkWidget *swin; /* scrolled window containing the list view */ GtkWidget *polar; /* polar plot */ GtkWidget *azel; /* Az/El plot */ GtkWidget *hbox; /* hbox used in tab headers */ GtkWidget *image; /* icon used in tab header */ gchar *title; guint flags; guint i, num; pass_detail_t *detail; gchar *buff; gint retcode; gdouble doppler; gdouble delay; gdouble loss; obs_astro_t astro; gdouble ra,dec; /* get columns flags */ flags = sat_cfg_get_int (SAT_CFG_INT_PRED_SINGLE_COL); /* create list */ list = gtk_tree_view_new (); gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (list), TRUE); for (i = 0; i < SINGLE_PASS_COL_NUMBER; i++) { renderer = gtk_cell_renderer_text_new (); g_object_set (G_OBJECT (renderer), "xalign", SINGLE_PASS_COL_XALIGN[i], NULL); column = gtk_tree_view_column_new_with_attributes (_(SINGLE_PASS_COL_TITLE[i]), renderer, "text", i, NULL); gtk_tree_view_insert_column (GTK_TREE_VIEW (list), column, -1); /* only aligns the headers */ gtk_tree_view_column_set_alignment (column, 0.5); /* set cell data function; allows to format data before rendering */ check_and_set_single_cell_renderer (column, renderer, i); /* hide columns that have not been specified */ if (!(flags & (1 << i))) { gtk_tree_view_column_set_visible (column, FALSE); } } /* create and fill model */ liststore = gtk_list_store_new (SINGLE_PASS_COL_NUMBER, G_TYPE_DOUBLE, // time G_TYPE_DOUBLE, // az G_TYPE_DOUBLE, // el G_TYPE_DOUBLE, // ra G_TYPE_DOUBLE, // dec G_TYPE_DOUBLE, // range G_TYPE_DOUBLE, // range rate G_TYPE_DOUBLE, // lat G_TYPE_DOUBLE, // lon G_TYPE_STRING, // SSP G_TYPE_DOUBLE, // footprint G_TYPE_DOUBLE, // alt G_TYPE_DOUBLE, // vel G_TYPE_DOUBLE, // doppler G_TYPE_DOUBLE, // loss G_TYPE_DOUBLE, // delay G_TYPE_DOUBLE, // ma G_TYPE_DOUBLE, // phase G_TYPE_STRING); // visibility /* add rows to list store */ num = g_slist_length (pass->details); for (i = 0; i < num; i++) { detail = PASS_DETAIL(g_slist_nth_data (pass->details, i)); gtk_list_store_append (liststore, &item); gtk_list_store_set (liststore, &item, SINGLE_PASS_COL_TIME, detail->time, SINGLE_PASS_COL_AZ, detail->az, SINGLE_PASS_COL_EL, detail->el, SINGLE_PASS_COL_RANGE, detail->range, SINGLE_PASS_COL_RANGE_RATE, detail->range_rate, SINGLE_PASS_COL_LAT, detail->lat, SINGLE_PASS_COL_LON, detail->lon, SINGLE_PASS_COL_FOOTPRINT, detail->footprint, SINGLE_PASS_COL_ALT, detail->alt, SINGLE_PASS_COL_VEL, detail->velo, SINGLE_PASS_COL_MA, detail->ma, SINGLE_PASS_COL_PHASE, detail->phase, -1); /* SINGLE_PASS_COL_RA */ /* SINGLE_PASS_COL_DEC */ if (flags & (SINGLE_PASS_FLAG_RA | SINGLE_PASS_FLAG_DEC)) { Calc_RADec (detail->time, detail->az, detail->el, qth, &astro); ra = Degrees(astro.ra); dec = Degrees(astro.dec); gtk_list_store_set (liststore, &item, SINGLE_PASS_COL_RA, ra, SINGLE_PASS_COL_DEC, dec, -1); } /* SINGLE_PASS_COL_SSP */ if (flags & SINGLE_PASS_FLAG_SSP) { buff = g_try_malloc (7); retcode = longlat2locator (detail->lon, detail->lat, buff, 3); if (retcode == RIG_OK) { buff[6] = '\0'; gtk_list_store_set (liststore, &item, SINGLE_PASS_COL_SSP, buff, -1); } g_free (buff); } /* SINGLE_PASS_COL_DOPPLER */ if (flags & SINGLE_PASS_FLAG_DOPPLER) { doppler = -100.0e06 * (detail->range_rate / 299792.4580); // Hz gtk_list_store_set (liststore, &item, SINGLE_PASS_COL_DOPPLER, doppler, -1); } /* SINGLE_PASS_COL_LOSS */ if (flags & SINGLE_PASS_FLAG_LOSS) { loss = 72.4 + 20.0*log10(detail->range); // dB gtk_list_store_set (liststore, &item, SINGLE_PASS_COL_LOSS, loss, -1); } /* SINGLE_PASS_COL_DELAY */ if (flags & SINGLE_PASS_FLAG_DELAY) { delay = detail->range / 299.7924580; // msec gtk_list_store_set (liststore, &item, SINGLE_PASS_COL_DELAY, delay, -1); } /* SINGLE_PASS_COL_VIS */ if (flags & SINGLE_PASS_FLAG_VIS) { buff = g_strdup_printf ("%c", vis_to_chr (detail->vis)); gtk_list_store_set (liststore, &item, SINGLE_PASS_COL_VIS, buff, -1); g_free (buff); } } /* connect model to tree view */ gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (liststore)); g_object_unref (liststore); /* scrolled window */ swin = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_container_add (GTK_CONTAINER (swin), list); /* create notebook and add pages */ notebook = gtk_notebook_new (); image = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_MENU); hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("Data")), FALSE, TRUE, 5); gtk_widget_show_all (hbox); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), swin, hbox); /* polar plot */ polar = gtk_polar_plot_new (qth, pass); buff = icon_file_name ("gpredict-polar-small.png"); image = gtk_image_new_from_file (buff); g_free (buff); hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("Polar")), FALSE, TRUE, 5); gtk_widget_show_all (hbox); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), polar, hbox); /* Az/El plot */ azel = gtk_azel_plot_new (qth, pass); buff = icon_file_name ("gpredict-azel-small.png"); image = gtk_image_new_from_file (buff); g_free (buff); hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("Az/El")), FALSE, TRUE, 5); gtk_widget_show_all (hbox); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), azel, hbox); /* create dialog */ title = g_strdup_printf (_("Pass details for %s (orbit %d)"), satname, pass->orbit); /* use NULL as parent to avoid conflict when using undocked windows as parents. */ dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW (toplevel), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_PRINT, RESPONSE_PRINT, GTK_STOCK_SAVE, RESPONSE_SAVE, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); g_free (title); /* Make Close button default */ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE); /* window icon */ buff = icon_file_name ("gpredict-sat-list.png"); gtk_window_set_icon_from_file (GTK_WINDOW (dialog), buff, NULL); g_free (buff); /* allow interaction with other windows */ gtk_window_set_modal (GTK_WINDOW (dialog), FALSE); g_object_set_data (G_OBJECT (dialog), "sat", (gpointer) satname); g_object_set_data (G_OBJECT (dialog), "qth", qth); g_object_set_data (G_OBJECT (dialog), "pass", pass); g_signal_connect (dialog, "response", G_CALLBACK (single_pass_response), NULL); g_signal_connect (dialog, "destroy", G_CALLBACK (single_pass_dialog_destroy), NULL); g_signal_connect (dialog, "delete_event", G_CALLBACK (single_pass_dialog_delete), NULL); gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area(GTK_DIALOG(dialog))), notebook); gtk_window_set_default_size (GTK_WINDOW (dialog), -1, 300); gtk_widget_show_all (dialog); }