static void gtk_gps_finalize (GObject *object);
static void gtk_gps_size_request (GtkWidget *widget, GtkRequisition *requisition);
static void gtk_gps_size_allocate (GtkWidget *widget, GtkAllocation *allocate);
-static gint gtk_gps_expose (GtkWidget *widget, GdkEventExpose *event);
+static gboolean gtk_gps_expose (GtkWidget *widget, GdkEventExpose *event);
static void gtk_gps_realize (GtkWidget *widget);
static void gtk_gps_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void gtk_gps_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
-static gint gtk_gps_paint(GtkGps *gps);
+static void gtk_gps_paint_by_mode(GtkGps *gps);
+static gboolean gtk_gps_refresh_cb(GtkWidget *widget);
G_DEFINE_TYPE(GtkGps, gtk_gps, GTK_TYPE_WIDGET);
}
static void
-gtk_gps_class_init (GtkGpsClass *class)
+gtk_gps_class_init(GtkGpsClass *class)
{
GObjectClass *object_class;
GtkWidgetClass *widget_class;
}
static void
-gtk_gps_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+gtk_gps_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
GtkGps *gps;
+
g_return_if_fail(GTK_IS_GPS(object));
+
gps=GTK_GPS(object);
switch (prop_id) {
default:
}
static void
-gtk_gps_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+gtk_gps_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
GtkGps *gps;
+
g_return_if_fail(GTK_IS_GPS(object));
+
gps=GTK_GPS(object);
switch (prop_id) {
default:
}
static void
-gtk_gps_init (GtkGps *gps)
+gtk_gps_init(GtkGps *gps)
{
-g_printf("%s()\n", __PRETTY_FUNCTION__);
-
-gps->satinview=0;
-gps->satinuse=0;
-gps->gc1=NULL;
-gps->gc2=NULL;
-gps->gc3=NULL;
-gps->width=400;
+gps->gc_w=NULL;
+gps->gc_s=NULL;
+gps->gc_sf=NULL;
+gps->width=300;
gps->height=300;
+gps->size=300;
+gps->esid=0;
+}
+
+static gboolean
+gtk_gps_cb_button_press(GtkWidget * widget, GdkEventButton * event)
+{
+GtkGps *gps;
+
+gps=GTK_GPS(widget);
+
+if (event->button==1) {
+ switch (gps->display_mode) {
+ case GTK_GPS_MODE_SKY:
+ gps->display_mode=GTK_GPS_MODE_SIGNAL;
+ break;
+ case GTK_GPS_MODE_SIGNAL:
+ default:
+ gps->display_mode=GTK_GPS_MODE_SKY;
+ break;
+ }
+}
+gtk_widget_queue_draw_area(widget, 0, 0, gps->width, gps->height);
+return FALSE;
}
GtkWidget*
-gtk_gps_new(void)
+gtk_gps_new(GtkGpsMode display_mode, GpsData *data)
{
GtkGps *gps;
-gps = gtk_type_new(gtk_gps_get_type ());
+GtkWidget *widget;
+
+gps=gtk_type_new(gtk_gps_get_type ());
+gps->display_mode=display_mode;
+gps->data=data;
+widget=GTK_WIDGET(gps);
+
+/* Allow switching if mode is combined */
+if (display_mode==GTK_GPS_MODE_COMBINED) {
+ g_signal_connect(G_OBJECT(widget), "button_press_event", G_CALLBACK(gtk_gps_cb_button_press), NULL);
+ display_mode=GTK_GPS_MODE_SKY;
+}
+
+gps->context=gtk_widget_get_pango_context(widget);
+gps->layout=pango_layout_new(gps->context);
+gps->fontdesc=pango_font_description_new();
+pango_font_description_set_family(gps->fontdesc, "Sans Serif");
+pango_font_description_set_size(gps->fontdesc, 10*PANGO_SCALE);
+pango_layout_set_font_description(gps->layout, gps->fontdesc);
+pango_layout_set_alignment(gps->layout, PANGO_ALIGN_CENTER);
+
+gps->esid=g_timeout_add(1000,(GSourceFunc)gtk_gps_refresh_cb, gps);
+
return GTK_WIDGET(gps);
}
{
GtkGps *gps;
-g_printf("%s()\n", __PRETTY_FUNCTION__);
-
g_return_if_fail(GTK_IS_GPS(object));
gps=GTK_GPS(object);
+g_source_remove(gps->esid);
if (GTK_WIDGET(object)->parent && GTK_WIDGET_MAPPED(object)) {
gtk_widget_unmap(GTK_WIDGET(object));
}
{
GtkGps *gps;
-g_printf("%s()\n", __PRETTY_FUNCTION__);
-
g_return_if_fail(GTK_IS_GPS(widget));
-g_return_if_fail(requisition != NULL);
+g_return_if_fail(requisition!=NULL);
gps = GTK_GPS (widget);
-requisition->width=400;
-requisition->height=300;
-gps->width=400 - 10;
-gps->height=300 - 10;
+requisition->width=300;
+gps->width=300;
+
+if (gps->display_mode==GTK_GPS_MODE_SKY) {
+ requisition->height=400;
+ gps->height=400;
+} else {
+ requisition->height=200;
+ gps->height=200;
+}
+gps->size=300;
}
static void
{
GtkGps *gps;
-g_printf("%s()\n", __PRETTY_FUNCTION__);
-
g_return_if_fail(GTK_IS_GPS(widget));
g_return_if_fail(allocation!=NULL);
allocation->width, allocation->height);
}
-gps->width=allocation->width-PADDING;
-gps->height=allocation->height-PADDING;
+gps->width=allocation->width;
+gps->height=allocation->height;
+gps->size=MIN(gps->width, gps->height);
+
+gps->fs=gps->size/22;
+BOUND(gps->fs, 10, 24);
+
+pango_font_description_set_size(gps->fontdesc, (gps->fs-3)*PANGO_SCALE);
+pango_layout_set_font_description(gps->layout, gps->fontdesc);
}
static void
GdkWindowAttr attributes;
gint attributes_mask;
-g_printf("%s()\n", __PRETTY_FUNCTION__);
-
g_return_if_fail (GTK_IS_GPS(widget));
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
gps=GTK_GPS(widget);
attributes.height=widget->allocation.height;
attributes.wclass=GDK_INPUT_OUTPUT;
attributes.window_type=GDK_WINDOW_CHILD;
-attributes.event_mask=gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK ;
+attributes.event_mask=gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
attributes.visual=gtk_widget_get_visual(widget);
attributes.colormap=gtk_widget_get_colormap(widget);
gdk_window_set_user_data(widget->window, widget);
gtk_style_set_background(widget->style, widget->window, GTK_STATE_ACTIVE);
-gps->sat_details_context=gtk_widget_get_pango_context(widget);
-gps->sat_details_layout=pango_layout_new(gps->sat_details_context);
-gps->sat_details_fontdesc=pango_font_description_new();
-pango_font_description_set_family(gps->sat_details_fontdesc, "Sans Serif");
-pango_font_description_set_size(gps->sat_details_fontdesc, 12*PANGO_SCALE);
-pango_layout_set_font_description(gps->sat_details_layout, gps->sat_details_fontdesc);
-pango_layout_set_alignment(gps->sat_details_layout, PANGO_ALIGN_CENTER);
-
-if (!gps->gc1) {
+/* No fix */
+if (!gps->gc_s) {
color.red=0;
color.green=0;
- color.blue=0;
- gps->gc1=gdk_gc_new(widget->window);
- gdk_gc_set_rgb_fg_color(gps->gc1, &color);
+ color.blue=0x1000;
+ gps->gc_s=gdk_gc_new(widget->window);
+ gdk_gc_set_rgb_fg_color(gps->gc_s, &color);
}
-if (!gps->gc2) {
+/* Fix color */
+if (!gps->gc_sf) {
color.red=0;
- color.green=0;
- color.blue=0xffff;
- gps->gc2=gdk_gc_new(widget->window);
- gdk_gc_set_rgb_fg_color(gps->gc2, &color);
+ color.green=0xdfff;
+ color.blue=0;
+ gps->gc_sf=gdk_gc_new(widget->window);
+ gdk_gc_set_rgb_fg_color(gps->gc_sf, &color);
}
-if (!gps->gc3) {
+if (!gps->gc_w) {
color.red=0xffff;
color.green=0xffff;
color.blue=0xffff;
- gps->gc3=gdk_gc_new(widget->window);
- gdk_gc_set_rgb_fg_color(gps->gc3, &color);
+ gps->gc_w=gdk_gc_new(widget->window);
+ gdk_gc_set_rgb_fg_color(gps->gc_w, &color);
}
}
-static gint
-gtk_gps_paint(GtkGps *gps)
+static void
+gtk_gps_paint_sky(GtkGps *gps)
{
GdkGC *gc;
GtkWidget *widget;
-guint i, j, x, y, size, halfsize, xoffset, yoffset;
+guint i, x, y, size, halfsize, xoffset, yoffset;
guint x1, y1, x0, y0;
gfloat tmp;
gchar buffer[16];
guint line[12]={0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330};
-g_printf("%s()\n", __PRETTY_FUNCTION__);
-
widget=GTK_WIDGET(gps);
+g_return_if_fail(gps->data);
+
if (!GTK_WIDGET_MAPPED(widget))
- return TRUE;
+ return;
x0=0;
y0=0;
-size=MIN(gps->width, gps->height);
+size=gps->size-PADDING;
halfsize=size/2;
if (gps->width>gps->height) {
- xoffset=x0+(gps->width-gps->height-PADDING)/2;
+ xoffset=x0+(gps->width-gps->height)/2;
yoffset=y0+5;
} else {
xoffset=x0+5;
- yoffset=y0+(gps->height-gps->width-PADDING)/2;
+ yoffset=y0+(gps->height-gps->width)/2;
}
/* 90 */
xoffset + size / 6 * 2, yoffset + size / 6 * 2,
size / 6 * 2, size / 6 * 2, 0, 64 * 360);
-for (i = 0; i < 6; i++) {
- /* line */
+for (i = 0; i < 12; i++) {
+ gfloat sint, cost;
+
tmp = (line[i] * (1.f / 180.f)) * G_PI;
+ sint=sinf(tmp);
+ cost=cosf(tmp);
+ /* line */
gdk_draw_line(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
- xoffset + halfsize + (halfsize - 2) * sinf(tmp),
- yoffset + halfsize - (halfsize - 2) * cosf(tmp),
- xoffset + halfsize - (halfsize - 2) * sinf(tmp),
- yoffset + halfsize + (halfsize - 2) * cosf(tmp));
-}
+ xoffset + halfsize + (halfsize - 2) * sint,
+ yoffset + halfsize - (halfsize - 2) * cost,
+ xoffset + halfsize - (halfsize - 2) * sint,
+ yoffset + halfsize + (halfsize - 2) * cost);
+
+ /* Skip angle text if there is no space */
+ if (size<100)
+ continue;
-for (i = 0; i < 12; i++) {
- tmp = (line[i] * (1.f / 180.f)) * G_PI;
- /* azimuth */
if (line[i] == 0)
g_snprintf(buffer, 16, "N");
else
g_snprintf(buffer, 16, "%d°", line[i]);
- pango_layout_set_text(gps->sat_details_layout, buffer, -1);
- pango_layout_get_pixel_size(gps->sat_details_layout, &x, &y);
+ pango_layout_set_text(gps->layout, buffer, -1);
+ pango_layout_get_pixel_size(gps->layout, &x, &y);
gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
- (xoffset + halfsize + (halfsize - size / 12) * sinf(tmp)) - x / 2,
- (yoffset + halfsize - (halfsize - size / 12) * cosf(tmp)) - y / 2,
- gps->sat_details_layout);
+ (xoffset + halfsize + (halfsize - size / 12) * sint) - x / 2,
+ (yoffset + halfsize - (halfsize - size / 12) * cost) - y / 2,
+ gps->layout);
+
}
-/* elevation 30 */
-tmp = (30 * (1.f / 180.f)) * G_PI;
-g_snprintf(buffer, 16, "30°");
-pango_layout_set_text(gps->sat_details_layout, buffer, -1);
-pango_layout_get_pixel_size(gps->sat_details_layout, &x, &y);
-gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
+if (size>100) {
+ tmp = (30 * (1.f / 180.f)) * G_PI;
+ /* elevation 30 */
+ g_snprintf(buffer, 16, "30°");
+ pango_layout_set_text(gps->layout, buffer, -1);
+ pango_layout_get_pixel_size(gps->layout, &x, &y);
+ gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
(xoffset + halfsize + size / 6 * 2 * sinf(tmp)) - x / 2,
(yoffset + halfsize - size / 6 * 2 * cosf(tmp)) - y / 2,
- gps->sat_details_layout);
-
-/* elevation 60 */
-tmp = (30 * (1.f / 180.f)) * G_PI;
-g_snprintf(buffer, 16, "60°");
-pango_layout_set_text(gps->sat_details_layout, buffer, -1);
-pango_layout_get_pixel_size(gps->sat_details_layout, &x, &y);
-gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
+ gps->layout);
+
+ /* elevation 60 */
+ g_snprintf(buffer, 16, "60°");
+ pango_layout_set_text(gps->layout, buffer, -1);
+ pango_layout_get_pixel_size(gps->layout, &x, &y);
+ gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
(xoffset + halfsize + size / 6 * sinf(tmp)) - x / 2,
(yoffset + halfsize - size / 6 * cosf(tmp)) - y / 2,
- gps->sat_details_layout);
+ gps->layout);
+}
-for (i=0;i<gps->satinview;i++) {
+for (i=0;i<gps->data->satinview;i++) {
/* Sat used or not */
- gc=gps->gc1;
- for (j=0;j<gps->satinuse;j++) {
- if (gps->satforfix[j]==gps->gps_sat[i].prn) {
- gc=gps->gc2;
- break;
- }
- }
+ gc=(gps->data->sat[i].fix==TRUE) ? gps->gc_sf : gps->gc_s;
- tmp = (gps->gps_sat[i].azimuth * (1.f / 180.f)) * G_PI;
- x = xoffset + halfsize + (90 - gps->gps_sat[i].elevation) * halfsize / 90 * sinf(tmp);
- y = yoffset + halfsize - (90 - gps->gps_sat[i].elevation) * halfsize / 90 * cosf(tmp);
+ tmp = (gps->data->sat[i].azimuth * (1.f / 180.f)) * G_PI;
+ x = xoffset + halfsize + (90 - gps->data->sat[i].elevation) * halfsize / 90 * sinf(tmp);
+ y = yoffset + halfsize - (90 - gps->data->sat[i].elevation) * halfsize / 90 * cosf(tmp);
- gdk_draw_arc(widget->window, gc, TRUE, x - 10, y - 10, 20, 20, 0, 64 * 360);
+ gdk_draw_arc(widget->window, gc, TRUE, x-gps->fs, y-gps->fs, gps->fs+8, gps->fs+8, 0, 64 * 360);
- g_snprintf(buffer, 6, "%02d", gps->gps_sat[i].prn);
- pango_layout_set_text(gps->sat_details_layout, buffer, -1);
- pango_layout_get_pixel_size(gps->sat_details_layout, &x1, &y1);
- gdk_draw_layout(widget->window, gps->gc3, x - x1 / 2, y - y1 / 2, gps->sat_details_layout);
+ g_snprintf(buffer, 6, "%02d", gps->data->sat[i].prn);
+ pango_layout_set_text(gps->layout, buffer, -1);
+ pango_layout_get_pixel_size(gps->layout, &x1, &y1);
+ gdk_draw_layout(widget->window, gps->gc_w, x-gps->fs/2-x1/2+2, y-gps->fs/2-y1/2+2, gps->layout);
}
-g_printf("%s(): return\n", __PRETTY_FUNCTION__);
-return TRUE;
+return;
}
-static gint
-gtk_gps_expose(GtkWidget *widget, GdkEventExpose *event)
+static void
+gtk_gps_paint_signals(GtkGps *gps)
{
-g_return_val_if_fail(GTK_IS_GPS(widget), FALSE);
-g_return_val_if_fail(event != NULL, FALSE);
+GdkGC *gc;
+GtkWidget *widget;
+guint step, i, snr_height, bymargin, xoffset, yoffset;
+guint x, y, x1, y1;
+gchar tmp[32];
+
+widget=GTK_WIDGET(gps);
+
+if (!GTK_WIDGET_MAPPED(widget))
+ return;
+
+xoffset=0;
+yoffset=0;
+
+/* Bootom margin - 12% */
+bymargin = gps->height * 0.88f;
+
+/* Bottom line */
+gdk_draw_line(widget->window,
+ widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
+ xoffset + 5, yoffset + bymargin,
+ xoffset + gps->width - 10 - 2, yoffset + bymargin);
+gdk_draw_line(widget->window,
+ widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
+ xoffset + 5, yoffset + bymargin - 1,
+ xoffset + gps->width - 10 - 2, yoffset + bymargin - 1);
+
+if (gps->data->satinview==0)
+ return;
+
+/* Left margin - 5pix, Right margin - 5pix */
+step = (gps->width - 10) / gps->data->satinview;
+
+for (i=0;i<gps->data->satinview;i++) {
+ /* Sat used or not */
+ gc=(gps->data->sat[i].fix) ? gps->gc_sf : gps->gc_s;
+
+ x = 5 + i * step;
+ snr_height = gps->data->sat[i].snr * gps->height * 0.78f / 100;
+ y = gps->height * 0.1f + (gps->height * 0.78f - snr_height);
+
+ /* draw sat rectangle... */
+ gdk_draw_rectangle(widget->window,
+ gc, TRUE,
+ xoffset + x,
+ yoffset + y, step - 2, snr_height);
+
+ if (gps->data->sat[i].snr>0) {
+ /* ...snr.. */
+ g_snprintf(tmp, 32, "%02d", gps->data->sat[i].snr);
+ pango_layout_set_text(gps->layout, tmp, 2);
+ pango_layout_get_pixel_size(gps->layout, &x1, &y1);
+ gdk_draw_layout(widget->window,
+ widget->style->fg_gc[GTK_STATE_NORMAL],
+ xoffset + x + ((step - 2) - x1) / 2,
+ yoffset + y - 15,
+ gps->layout);
+ }
+
+ /* ...and sat number */
+ g_snprintf(tmp, 32, "%02d", gps->data->sat[i].prn);
+ pango_layout_set_text(gps->layout, tmp, 2);
+ pango_layout_get_pixel_size(gps->layout, &x1, &y1);
+ gdk_draw_layout(widget->window,
+ widget->style->fg_gc[GTK_STATE_NORMAL],
+ xoffset + x + ((step - 2) - x1) / 2,
+ yoffset + bymargin + 1,
+ gps->layout);
+}
-gtk_gps_paint(GTK_GPS(widget));
-return TRUE;
}
-void
-gtk_gps_set_satellite_data(GtkWidget *widget, guint sat, gboolean fix, guint prn, guint elevation, guint azimuth, guint snr)
+static void
+gtk_gps_paint_by_mode(GtkGps *gps)
+{
+g_return_if_fail(GTK_IS_GPS(gps));
+
+switch (gps->display_mode) {
+ case GTK_GPS_MODE_SIGNAL:
+ gtk_gps_paint_signals(gps);
+ break;
+ case GTK_GPS_MODE_SKY:
+ default:
+ gtk_gps_paint_sky(gps);
+ break;
+}
+}
+
+static gboolean
+gtk_gps_refresh_cb(GtkWidget *widget)
{
GtkGps *gps;
-g_printf("%s()\n", __PRETTY_FUNCTION__);
-g_return_if_fail(GTK_IS_GPS (widget));
+g_return_val_if_fail(GTK_IS_GPS(widget), FALSE);
+
+if ((GTK_WIDGET_MAPPED(widget)==FALSE) || (GTK_WIDGET_VISIBLE(widget)==FALSE))
+ return TRUE;
gps=GTK_GPS(widget);
+gtk_widget_queue_draw_area(widget, 0, 0, gps->width, gps->height);
+return TRUE;
+}
+
+static gboolean
+gtk_gps_expose(GtkWidget *widget, GdkEventExpose *event)
+{
+GtkGps *gps;
-if (sat>12)
- sat=12;
+g_return_val_if_fail(GTK_IS_GPS(widget), FALSE);
+g_return_val_if_fail(event != NULL, FALSE);
-BOUND(elevation, 0, 90);
-BOUND(azimuth, 0, 360);
-BOUND(snr, 0, 99);
-gps->gps_sat[sat].prn=prn;
-gps->gps_sat[sat].elevation=elevation;
-gps->gps_sat[sat].azimuth=azimuth;
-gps->gps_sat[sat].snr=snr;
-if (fix)
- gps->satforfix[sat]=prn;
-else
- gps->satforfix[sat]=-1;
-g_printf("%s(): return\n", __PRETTY_FUNCTION__);
+gps=GTK_GPS(widget);
+gtk_gps_paint_by_mode(gps);
+return TRUE;
}
void
-gtk_gps_set_satellite_in_view(GtkWidget *widget, guint sat)
+gtk_gps_refresh(GtkWidget *widget)
{
GtkGps *gps;
-g_printf("%s()\n", __PRETTY_FUNCTION__);
g_return_if_fail(GTK_IS_GPS(widget));
gps=GTK_GPS(widget);
-
-if (sat>12)
- sat=12;
-
-gps->satinview=sat;
-gtk_gps_paint(gps);
-
-g_printf("%s(): return\n", __PRETTY_FUNCTION__);
+gtk_widget_queue_draw_area(widget, 0, 0, gps->width, gps->height);
}