From: Kaj-Michael Lang Date: Wed, 26 Sep 2007 12:11:53 +0000 (+0300) Subject: Start to make proper gtk widgets of the gps info displays. X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d8a0c923d92339983da372a24049b1b5d3bc20aa;p=mapper Start to make proper gtk widgets of the gps info displays. --- diff --git a/src/gtkgps.c b/src/gtkgps.c new file mode 100644 index 0000000..4f20b3d --- /dev/null +++ b/src/gtkgps.c @@ -0,0 +1,416 @@ +/* + * + * GtkGps: Display GPS information + * Copyright (C) 2007 Kaj-Michael Lang + * Originanl non-widget version Copyright Cezary Jackiewicz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include "gtkgps.h" + +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 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); + +G_DEFINE_TYPE(GtkGps, gtk_gps, GTK_TYPE_WIDGET); + +#define PADDING (15) + +#define BOUND(x, a, b) { \ + if((x) < (a)) \ + (x) = (a); \ + else if((x) > (b)) \ + (x) = (b); \ +} + +static void +gtk_gps_class_init (GtkGpsClass *class) +{ +GObjectClass *object_class; +GtkWidgetClass *widget_class; + +object_class = (GObjectClass*) class; +widget_class = (GtkWidgetClass*) class; + +object_class->finalize = gtk_gps_finalize; +object_class->set_property = gtk_gps_set_property; +object_class->get_property = gtk_gps_get_property; + +widget_class->size_request = gtk_gps_size_request; +widget_class->expose_event = gtk_gps_expose; +widget_class->realize = gtk_gps_realize; +widget_class->size_allocate = gtk_gps_size_allocate; +} + +static void +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: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; +} +} + +static void +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: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; +} +} + +static void +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->height=300; +} + +GtkWidget* +gtk_gps_new(void) +{ +GtkGps *gps; +gps = gtk_type_new(gtk_gps_get_type ()); +return GTK_WIDGET(gps); +} + +static void +gtk_gps_finalize(GObject *object) +{ +GtkGps *gps; + +g_printf("%s()\n", __PRETTY_FUNCTION__); + +g_return_if_fail(GTK_IS_GPS(object)); +gps=GTK_GPS(object); + +if (GTK_WIDGET(object)->parent && GTK_WIDGET_MAPPED(object)) { + gtk_widget_unmap(GTK_WIDGET(object)); +} + +G_OBJECT_CLASS(gtk_gps_parent_class)->finalize(object); +} + +static void +gtk_gps_size_request(GtkWidget *widget, GtkRequisition *requisition) +{ +GtkGps *gps; + +g_printf("%s()\n", __PRETTY_FUNCTION__); + +g_return_if_fail(GTK_IS_GPS(widget)); +g_return_if_fail(requisition != NULL); + +gps = GTK_GPS (widget); + +requisition->width=400; +requisition->height=300; +gps->width=400 - 10; +gps->height=300 - 10; +} + +static void +gtk_gps_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ +GtkGps *gps; + +g_printf("%s()\n", __PRETTY_FUNCTION__); + +g_return_if_fail(GTK_IS_GPS(widget)); +g_return_if_fail(allocation!=NULL); + +gps=GTK_GPS (widget); + +widget->allocation = *allocation; + +if (GTK_WIDGET_REALIZED (widget)) { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); +} + +gps->width=allocation->width-PADDING; +gps->height=allocation->height-PADDING; +} + +static void +gtk_gps_realize (GtkWidget *widget) +{ +GtkGps *gps; +GdkColor color; +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.x=widget->allocation.x; +attributes.y=widget->allocation.y; +attributes.width=widget->allocation.width; +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.visual=gtk_widget_get_visual(widget); +attributes.colormap=gtk_widget_get_colormap(widget); + +attributes_mask=GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + +widget->window=gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributes_mask); +widget->style=gtk_style_attach(widget->style, widget->window); + +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) { + 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); +} + +if (!gps->gc2) { + 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); +} + +if (!gps->gc3) { + 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); +} +} + +static gint +gtk_gps_paint(GtkGps *gps) +{ +GdkGC *gc; +GtkWidget *widget; +guint i, j, 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); + +if (!GTK_WIDGET_MAPPED(widget)) + return TRUE; + +x0=0; +y0=0; + +size=MIN(gps->width, gps->height); +halfsize=size/2; +if (gps->width>gps->height) { + xoffset=x0+(gps->width-gps->height-PADDING)/2; + yoffset=y0+5; +} else { + xoffset=x0+5; + yoffset=y0+(gps->height-gps->width-PADDING)/2; +} + +/* 90 */ +gdk_draw_arc(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE(widget)], + FALSE, + xoffset + 2, yoffset + 2, size - 4, size - 4, 0, 64 * 360); + +/* 60 */ +gdk_draw_arc(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE(widget)], + FALSE, + xoffset + size / 6, yoffset + size / 6, + size / 6 * 4, size / 6 * 4, 0, 64 * 360); + +/* 30 */ +gdk_draw_arc(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE(widget)], + FALSE, + xoffset + size / 6 * 2, yoffset + size / 6 * 2, + size / 6 * 2, size / 6 * 2, 0, 64 * 360); + +for (i = 0; i < 6; i++) { + /* line */ + tmp = (line[i] * (1.f / 180.f)) * G_PI; + 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)); +} + +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); + 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); +} + +/* 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], + (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], + (xoffset + halfsize + size / 6 * sinf(tmp)) - x / 2, + (yoffset + halfsize - size / 6 * cosf(tmp)) - y / 2, + gps->sat_details_layout); + +for (i=0;isatinview;i++) { + /* Sat used or not */ + gc=gps->gc1; + for (j=0;jsatinuse;j++) { + if (gps->satforfix[j]==gps->gps_sat[i].prn) { + gc=gps->gc2; + break; + } + } + + 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); + + gdk_draw_arc(widget->window, gc, TRUE, x - 10, y - 10, 20, 20, 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_printf("%s(): return\n", __PRETTY_FUNCTION__); +return TRUE; +} + +static gint +gtk_gps_expose(GtkWidget *widget, GdkEventExpose *event) +{ +g_return_val_if_fail(GTK_IS_GPS(widget), FALSE); +g_return_val_if_fail(event != NULL, FALSE); + +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) +{ +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; + +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__); +} + +void +gtk_gps_set_satellite_in_view(GtkWidget *widget, guint sat) +{ +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__); +} diff --git a/src/gtkgps.h b/src/gtkgps.h new file mode 100644 index 0000000..51f224e --- /dev/null +++ b/src/gtkgps.h @@ -0,0 +1,75 @@ +/* + * + * GtkGps: Display GPS satellite information + * Copyright (C) 2007 Kaj-Michael Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_GPS_H__ +#define __GTK_GPS_H__ + +#include + +G_BEGIN_DECLS + +#define GTK_GPS_TYPE (gtk_GPS_get_type ()) +#define GTK_GPS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_GPS_TYPE, GtkGps)) +#define GTK_GPS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_GPS_TYPE, GtkGpsClass)) +#define GTK_IS_GPS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_GPS_TYPE)) + +typedef struct _GtkGps GtkGps; +typedef struct _GtkGpsClass GtkGpsClass; + +typedef struct _GtkGpsSatelliteData GtkGpsSatelliteData; +struct _GtkGpsSatelliteData { + guint prn; + guint elevation; + guint azimuth; + guint snr; +}; + +struct _GtkGps { + GtkWidget parent; + GtkWidget widget; + GdkGC *gc1; + GdkGC *gc2; + GdkGC *gc3; + gint width, height; + + PangoContext *sat_details_context; + PangoLayout *sat_details_layout; + PangoFontDescription *sat_details_fontdesc; + PangoContext *sat_details_expose_context; + PangoLayout *sat_details_expose_layout; + PangoFontDescription *sat_details_expose_fontdesc; + + GtkGpsSatelliteData gps_sat[12]; + guint satinview; + guint satinuse; + guint satforfix[12]; +}; + +struct _GtkGpsClass { + GtkWidgetClass parent_class; +}; + +GType gtk_gps_get_type(void); +GtkWidget* gtk_gps_new(void); +void gtk_gps_set_satellite_data(GtkWidget *widget, guint sat, gboolean fix, guint prn, guint elevation, guint azimuth, guint snr); +void gtk_gps_set_satellite_in_view(GtkWidget *widget, guint sat); + +G_END_DECLS + +#endif /* __GTK_GPS_H__ */