]> err.no Git - mapper/blob - src/gtkgps.c
Start to make proper gtk widgets of the gps info displays.
[mapper] / src / gtkgps.c
1 /*
2  *
3  * GtkGps: Display GPS information
4  * Copyright (C) 2007 Kaj-Michael Lang
5  * Originanl non-widget version Copyright Cezary Jackiewicz
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the Free
19  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include <math.h>
23
24 #include <glib/gstdio.h>
25 #include <glib-object.h>
26 #include "gtkgps.h"
27
28 static void gtk_gps_finalize (GObject *object);
29 static void gtk_gps_size_request (GtkWidget *widget, GtkRequisition *requisition);
30 static void gtk_gps_size_allocate (GtkWidget *widget, GtkAllocation *allocate);
31 static gint gtk_gps_expose (GtkWidget *widget, GdkEventExpose *event);
32 static void gtk_gps_realize (GtkWidget *widget);
33 static void gtk_gps_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
34 static void gtk_gps_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
35 static gint gtk_gps_paint(GtkGps *gps);
36
37 G_DEFINE_TYPE(GtkGps, gtk_gps, GTK_TYPE_WIDGET);
38
39 #define PADDING (15)
40
41 #define BOUND(x, a, b) { \
42     if((x) < (a)) \
43         (x) = (a); \
44     else if((x) > (b)) \
45         (x) = (b); \
46 }
47
48 static void
49 gtk_gps_class_init (GtkGpsClass *class)
50 {
51 GObjectClass *object_class;
52 GtkWidgetClass *widget_class;
53         
54 object_class = (GObjectClass*) class;
55 widget_class = (GtkWidgetClass*) class;
56         
57 object_class->finalize = gtk_gps_finalize;
58 object_class->set_property = gtk_gps_set_property;
59 object_class->get_property = gtk_gps_get_property;
60         
61 widget_class->size_request = gtk_gps_size_request;
62 widget_class->expose_event = gtk_gps_expose;
63 widget_class->realize = gtk_gps_realize;
64 widget_class->size_allocate = gtk_gps_size_allocate;
65 }
66
67 static void
68 gtk_gps_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
69 {
70 GtkGps *gps;
71 g_return_if_fail(GTK_IS_GPS(object));
72 gps=GTK_GPS(object);
73 switch (prop_id) {
74         default:
75                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
76         break;
77 }
78 }
79
80 static void
81 gtk_gps_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec   *pspec)
82 {
83 GtkGps *gps;
84 g_return_if_fail(GTK_IS_GPS(object));
85 gps=GTK_GPS(object);
86 switch (prop_id) {
87         default:
88                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
89         break;
90 }
91 }
92
93 static void
94 gtk_gps_init (GtkGps *gps)
95 {
96 g_printf("%s()\n", __PRETTY_FUNCTION__);
97
98 gps->satinview=0;
99 gps->satinuse=0;
100 gps->gc1=NULL;
101 gps->gc2=NULL;
102 gps->gc3=NULL;
103 gps->width=400;
104 gps->height=300;
105 }
106
107 GtkWidget*
108 gtk_gps_new(void)
109 {
110 GtkGps *gps;
111 gps = gtk_type_new(gtk_gps_get_type ());
112 return GTK_WIDGET(gps);
113 }
114
115 static void
116 gtk_gps_finalize(GObject *object)
117 {
118 GtkGps *gps;
119
120 g_printf("%s()\n", __PRETTY_FUNCTION__);
121         
122 g_return_if_fail(GTK_IS_GPS(object));
123 gps=GTK_GPS(object);
124
125 if (GTK_WIDGET(object)->parent && GTK_WIDGET_MAPPED(object)) {
126         gtk_widget_unmap(GTK_WIDGET(object));
127 }
128
129 G_OBJECT_CLASS(gtk_gps_parent_class)->finalize(object);
130 }
131
132 static void
133 gtk_gps_size_request(GtkWidget  *widget, GtkRequisition *requisition)
134 {
135 GtkGps *gps;
136
137 g_printf("%s()\n", __PRETTY_FUNCTION__);
138         
139 g_return_if_fail(GTK_IS_GPS(widget));
140 g_return_if_fail(requisition != NULL);
141         
142 gps = GTK_GPS (widget);
143         
144 requisition->width=400;
145 requisition->height=300;
146 gps->width=400 - 10;
147 gps->height=300 - 10;
148 }
149
150 static void
151 gtk_gps_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
152 {
153 GtkGps *gps;
154
155 g_printf("%s()\n", __PRETTY_FUNCTION__);
156
157 g_return_if_fail(GTK_IS_GPS(widget));
158 g_return_if_fail(allocation!=NULL);
159
160 gps=GTK_GPS (widget);
161
162 widget->allocation = *allocation;
163
164 if (GTK_WIDGET_REALIZED (widget)) {
165         gdk_window_move_resize (widget->window,
166                 allocation->x, allocation->y,
167                 allocation->width, allocation->height);
168 }
169
170 gps->width=allocation->width-PADDING;
171 gps->height=allocation->height-PADDING;
172 }
173
174 static void 
175 gtk_gps_realize (GtkWidget *widget)
176 {
177 GtkGps *gps;
178 GdkColor color;
179 GdkWindowAttr attributes;
180 gint attributes_mask;
181
182 g_printf("%s()\n", __PRETTY_FUNCTION__);
183
184 g_return_if_fail (GTK_IS_GPS(widget));
185 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
186 gps=GTK_GPS(widget);
187
188 attributes.x=widget->allocation.x;
189 attributes.y=widget->allocation.y;
190 attributes.width=widget->allocation.width;
191 attributes.height=widget->allocation.height;
192 attributes.wclass=GDK_INPUT_OUTPUT;
193 attributes.window_type=GDK_WINDOW_CHILD;
194 attributes.event_mask=gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK ;
195 attributes.visual=gtk_widget_get_visual(widget);
196 attributes.colormap=gtk_widget_get_colormap(widget);
197
198 attributes_mask=GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
199
200 widget->window=gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributes_mask);
201 widget->style=gtk_style_attach(widget->style, widget->window);
202
203 gdk_window_set_user_data(widget->window, widget);
204 gtk_style_set_background(widget->style, widget->window, GTK_STATE_ACTIVE);
205
206 gps->sat_details_context=gtk_widget_get_pango_context(widget);
207 gps->sat_details_layout=pango_layout_new(gps->sat_details_context);
208 gps->sat_details_fontdesc=pango_font_description_new();
209 pango_font_description_set_family(gps->sat_details_fontdesc, "Sans Serif");
210 pango_font_description_set_size(gps->sat_details_fontdesc, 12*PANGO_SCALE);
211 pango_layout_set_font_description(gps->sat_details_layout, gps->sat_details_fontdesc);
212 pango_layout_set_alignment(gps->sat_details_layout, PANGO_ALIGN_CENTER);
213
214 if (!gps->gc1) {
215         color.red=0;
216         color.green=0;
217         color.blue=0;
218         gps->gc1=gdk_gc_new(widget->window);
219         gdk_gc_set_rgb_fg_color(gps->gc1, &color);
220 }
221
222 if (!gps->gc2) {
223         color.red=0;
224         color.green=0;
225         color.blue=0xffff;
226         gps->gc2=gdk_gc_new(widget->window);
227         gdk_gc_set_rgb_fg_color(gps->gc2, &color);
228 }
229
230 if (!gps->gc3) {
231         color.red=0xffff;
232         color.green=0xffff;
233         color.blue=0xffff;
234         gps->gc3=gdk_gc_new(widget->window);
235         gdk_gc_set_rgb_fg_color(gps->gc3, &color);
236 }
237 }
238
239 static gint
240 gtk_gps_paint(GtkGps *gps)
241 {
242 GdkGC *gc;
243 GtkWidget *widget;
244 guint i, j, x, y, size, halfsize, xoffset, yoffset;
245 guint x1, y1, x0, y0;
246 gfloat tmp;
247 gchar buffer[16];
248 guint line[12]={0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330};
249
250 g_printf("%s()\n", __PRETTY_FUNCTION__);
251
252 widget=GTK_WIDGET(gps);
253
254 if (!GTK_WIDGET_MAPPED(widget))
255         return TRUE;
256
257 x0=0;
258 y0=0;
259
260 size=MIN(gps->width, gps->height);
261 halfsize=size/2;
262 if (gps->width>gps->height) {
263         xoffset=x0+(gps->width-gps->height-PADDING)/2;
264         yoffset=y0+5;
265 } else {
266         xoffset=x0+5;
267         yoffset=y0+(gps->height-gps->width-PADDING)/2;
268 }
269
270 /* 90 */
271 gdk_draw_arc(widget->window,
272              widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
273              FALSE,
274              xoffset + 2, yoffset + 2, size - 4, size - 4, 0, 64 * 360);
275
276 /* 60 */
277 gdk_draw_arc(widget->window,
278              widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
279              FALSE,
280              xoffset + size / 6, yoffset + size / 6,
281              size / 6 * 4, size / 6 * 4, 0, 64 * 360);
282
283 /* 30 */
284 gdk_draw_arc(widget->window,
285              widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
286              FALSE,
287              xoffset + size / 6 * 2, yoffset + size / 6 * 2,
288              size / 6 * 2, size / 6 * 2, 0, 64 * 360);
289
290 for (i = 0; i < 6; i++) {
291         /* line */
292         tmp = (line[i] * (1.f / 180.f)) * G_PI;
293         gdk_draw_line(widget->window,
294                       widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
295                       xoffset + halfsize + (halfsize - 2) * sinf(tmp),
296                       yoffset + halfsize - (halfsize - 2) * cosf(tmp),
297                       xoffset + halfsize - (halfsize - 2) * sinf(tmp),
298                       yoffset + halfsize + (halfsize - 2) * cosf(tmp));
299 }
300
301 for (i = 0; i < 12; i++) {
302         tmp = (line[i] * (1.f / 180.f)) * G_PI;
303         /* azimuth */
304         if (line[i] == 0)
305                 g_snprintf(buffer, 16, "N");
306         else
307                 g_snprintf(buffer, 16, "%d°", line[i]);
308         pango_layout_set_text(gps->sat_details_layout, buffer, -1);
309         pango_layout_get_pixel_size(gps->sat_details_layout, &x, &y);
310         gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
311                         (xoffset + halfsize + (halfsize - size / 12) * sinf(tmp)) - x / 2,
312                         (yoffset + halfsize - (halfsize - size / 12) * cosf(tmp)) - y / 2,
313                         gps->sat_details_layout);
314 }
315
316 /* elevation 30 */
317 tmp = (30 * (1.f / 180.f)) * G_PI;
318 g_snprintf(buffer, 16, "30°");
319 pango_layout_set_text(gps->sat_details_layout, buffer, -1);
320 pango_layout_get_pixel_size(gps->sat_details_layout, &x, &y);
321 gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
322                 (xoffset + halfsize + size / 6 * 2 * sinf(tmp)) - x / 2,
323                 (yoffset + halfsize - size / 6 * 2 * cosf(tmp)) - y / 2,
324                 gps->sat_details_layout);
325
326 /* elevation 60 */
327 tmp = (30 * (1.f / 180.f)) * G_PI;
328 g_snprintf(buffer, 16, "60°");
329 pango_layout_set_text(gps->sat_details_layout, buffer, -1);
330 pango_layout_get_pixel_size(gps->sat_details_layout, &x, &y);
331 gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
332                 (xoffset + halfsize + size / 6 * sinf(tmp)) - x / 2,
333                 (yoffset + halfsize - size / 6 * cosf(tmp)) - y / 2, 
334                 gps->sat_details_layout);
335
336 for (i=0;i<gps->satinview;i++) {
337         /* Sat used or not */
338         gc=gps->gc1;
339         for (j=0;j<gps->satinuse;j++) {
340                 if (gps->satforfix[j]==gps->gps_sat[i].prn) {
341                         gc=gps->gc2;
342                         break;
343                 }
344         }
345
346         tmp = (gps->gps_sat[i].azimuth * (1.f / 180.f)) * G_PI;
347         x = xoffset + halfsize + (90 - gps->gps_sat[i].elevation) * halfsize / 90 * sinf(tmp);
348         y = yoffset + halfsize - (90 - gps->gps_sat[i].elevation) * halfsize / 90 * cosf(tmp);
349
350         gdk_draw_arc(widget->window, gc, TRUE, x - 10, y - 10, 20, 20, 0, 64 * 360);
351
352         g_snprintf(buffer, 6, "%02d", gps->gps_sat[i].prn);
353         pango_layout_set_text(gps->sat_details_layout, buffer, -1);
354         pango_layout_get_pixel_size(gps->sat_details_layout, &x1, &y1);
355         gdk_draw_layout(widget->window, gps->gc3, x - x1 / 2, y - y1 / 2, gps->sat_details_layout);
356 }
357
358 g_printf("%s(): return\n", __PRETTY_FUNCTION__);
359 return TRUE;
360 }
361
362 static gint
363 gtk_gps_expose(GtkWidget *widget, GdkEventExpose *event)
364 {
365 g_return_val_if_fail(GTK_IS_GPS(widget), FALSE);
366 g_return_val_if_fail(event != NULL, FALSE);
367
368 gtk_gps_paint(GTK_GPS(widget));
369 return TRUE;
370 }
371
372 void 
373 gtk_gps_set_satellite_data(GtkWidget *widget, guint sat, gboolean fix, guint prn, guint elevation, guint azimuth, guint snr)
374 {
375 GtkGps *gps;
376
377 g_printf("%s()\n", __PRETTY_FUNCTION__);
378 g_return_if_fail(GTK_IS_GPS (widget));
379
380 gps=GTK_GPS(widget);
381
382 if (sat>12)
383         sat=12;
384
385 BOUND(elevation, 0, 90);
386 BOUND(azimuth, 0, 360);
387 BOUND(snr, 0, 99);
388 gps->gps_sat[sat].prn=prn;
389 gps->gps_sat[sat].elevation=elevation;
390 gps->gps_sat[sat].azimuth=azimuth;
391 gps->gps_sat[sat].snr=snr;
392 if (fix)
393         gps->satforfix[sat]=prn;
394 else
395         gps->satforfix[sat]=-1;
396 g_printf("%s(): return\n", __PRETTY_FUNCTION__);
397 }
398
399 void
400 gtk_gps_set_satellite_in_view(GtkWidget *widget, guint sat)
401 {
402 GtkGps *gps;
403
404 g_printf("%s()\n", __PRETTY_FUNCTION__);
405 g_return_if_fail(GTK_IS_GPS(widget));
406
407 gps=GTK_GPS(widget);
408
409 if (sat>12)
410         sat=12;
411
412 gps->satinview=sat;
413 gtk_gps_paint(gps);
414
415 g_printf("%s(): return\n", __PRETTY_FUNCTION__);
416 }