2 * Copyright (C) 2006, 2007 John Costigan.
4 * POI and GPS-Info code originally written by Cezary Jackiewicz.
6 * Default map data provided by http://www.openstreetmap.org/
8 * This file is part of Maemo Mapper.
10 * Maemo Mapper is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
15 * Maemo Mapper is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with Maemo Mapper. If not, see <http://www.gnu.org/licenses/>.
35 # include <hildon/hildon-help.h>
36 # include <hildon/hildon-note.h>
37 # include <hildon/hildon-file-chooser-dialog.h>
38 # include <hildon/hildon-banner.h>
39 # include <hildon/hildon-sound.h>
41 # include <osso-helplib.h>
42 # include <hildon-widgets/hildon-note.h>
43 # include <hildon-widgets/hildon-file-chooser-dialog.h>
44 # include <hildon-widgets/hildon-banner.h>
45 # include <hildon-widgets/hildon-system-sound.h>
54 #include "gdk-pixbuf-rotate.h"
62 #define VELVEC_SIZE_FACTOR (4)
64 static GtkWidget *_sat_details_panel = NULL;
65 static GtkWidget *_sdi_lat = NULL;
66 static GtkWidget *_sdi_lon = NULL;
67 static GtkWidget *_sdi_spd = NULL;
68 static GtkWidget *_sdi_alt = NULL;
69 static GtkWidget *_sdi_hea = NULL;
70 static GtkWidget *_sdi_tim = NULL;
71 static GtkWidget *_sdi_vie = NULL;
72 static GtkWidget *_sdi_use = NULL;
73 static GtkWidget *_sdi_fix = NULL;
74 static GtkWidget *_sdi_fqu = NULL;
75 static GtkWidget *_sdi_msp = NULL;
76 static gint _redraw_count = 0;
78 static gint _mark_bufx1 = -1;
79 static gint _mark_bufx2 = -1;
80 static gint _mark_bufy1 = -1;
81 static gint _mark_bufy2 = -1;
82 static gint _mark_minx = -1;
83 static gint _mark_miny = -1;
84 static gint _mark_width = -1;
85 static gint _mark_height = -1;
86 static GdkRectangle _scale_rect = { 0, 0, 0, 0};
87 static GdkRectangle _zoom_rect = { 0, 0, 0, 0};
88 static gint _dl_errors = 0;
90 static volatile gint _pending_replaces = 0;
93 GdkRectangle _comprose_rect = { 0, 0, 0, 0};
94 PangoLayout *_scale_layout = NULL;
95 PangoLayout *_zoom_layout = NULL;
96 PangoLayout *_comprose_layout = NULL;
97 GdkGC *_speed_limit_gc1 = NULL;
98 GdkGC *_speed_limit_gc2 = NULL;
99 PangoLayout *_speed_limit_layout = NULL;
100 PangoLayout *_sat_panel_layout = NULL;
101 PangoLayout *_heading_panel_layout = NULL;
102 PangoFontDescription *_heading_panel_fontdesc = NULL;
103 GdkGC *_sat_info_gc1 = NULL;
104 GdkGC *_sat_info_gc2 = NULL;
105 PangoLayout *_sat_info_layout = NULL;
106 PangoLayout *_sat_details_layout = NULL;
107 PangoLayout *_sat_details_expose_layout = NULL;
109 #define SCALE_WIDTH (100)
114 printf("%s()\n", __PRETTY_FUNCTION__);
118 hildon_play_system_sound(
119 "/usr/share/sounds/ui-information_note.wav");
121 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
131 static gint x = 0, y = 0, width = 0, height = 0;
132 printf("%s()\n", __PRETTY_FUNCTION__);
134 cur_speed = _gps.speed * UNITS_CONVERT[_units];
136 if(cur_speed > _speed_limit)
138 gc = _speed_limit_gc1;
141 _speed_excess = TRUE;
142 g_timeout_add_full(G_PRIORITY_HIGH_IDLE,
143 5000, (GSourceFunc)speed_excess, NULL, NULL);
148 gc = _speed_limit_gc2;
149 _speed_excess = FALSE;
152 /* remove previous number */
153 if (width != 0 && height != 0) {
154 gtk_widget_queue_draw_area (_map_widget,
159 gdk_window_process_all_updates();
162 buffer = g_strdup_printf("%0.0f", cur_speed);
163 pango_layout_set_text(_speed_limit_layout, buffer, -1);
166 pango_layout_get_pixel_size(_speed_limit_layout, &width, &height);
168 switch (_speed_location)
170 case SPEED_LOCATION_TOP_RIGHT:
171 x = _map_widget->allocation.width - 10 - width;
174 case SPEED_LOCATION_BOTTOM_RIGHT:
175 x = _map_widget->allocation.width - 10 - width;
176 y = _map_widget->allocation.height - 10 - height;
178 case SPEED_LOCATION_BOTTOM_LEFT:
180 y = _map_widget->allocation.height - 10 - height;
188 gdk_draw_layout(_map_widget->window,
191 _speed_limit_layout);
194 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
198 gps_display_details(void)
200 gchar *buffer, litbuf[16];
201 printf("%s()\n", __PRETTY_FUNCTION__);
206 gtk_label_set_label(GTK_LABEL(_sdi_lat), " --- ");
207 gtk_label_set_label(GTK_LABEL(_sdi_lon), " --- ");
208 gtk_label_set_label(GTK_LABEL(_sdi_spd), " --- ");
209 gtk_label_set_label(GTK_LABEL(_sdi_alt), " --- ");
210 gtk_label_set_label(GTK_LABEL(_sdi_hea), " --- ");
211 gtk_label_set_label(GTK_LABEL(_sdi_tim), " --:--:-- ");
215 gfloat speed = _gps.speed * UNITS_CONVERT[_units];
218 lat_format(_gps.lat, litbuf);
219 gtk_label_set_label(GTK_LABEL(_sdi_lat), litbuf);
222 lon_format(_gps.lon, litbuf);
223 gtk_label_set_label(GTK_LABEL(_sdi_lon), litbuf);
229 buffer = g_strdup_printf("%.1f mph", speed);
232 buffer = g_strdup_printf("%.1f kn", speed);
235 buffer = g_strdup_printf("%.1f km/h", speed);
238 gtk_label_set_label(GTK_LABEL(_sdi_spd), buffer);
246 buffer = g_strdup_printf("%d ft",
247 (gint)(_pos.altitude * 3.2808399f));
250 buffer = g_strdup_printf("%d m", _pos.altitude);
253 gtk_label_set_label(GTK_LABEL(_sdi_alt), buffer);
257 buffer = g_strdup_printf("%0.0f°", _gps.heading);
258 gtk_label_set_label(GTK_LABEL(_sdi_hea), buffer);
262 strftime(litbuf, 15, "%X", localtime(&_pos.time));
263 gtk_label_set_label(GTK_LABEL(_sdi_tim), litbuf);
267 buffer = g_strdup_printf("%d", _gps.satinview);
268 gtk_label_set_label(GTK_LABEL(_sdi_vie), buffer);
272 buffer = g_strdup_printf("%d", _gps.satinuse);
273 gtk_label_set_label(GTK_LABEL(_sdi_use), buffer);
280 case 3: buffer = g_strdup_printf("%dD fix", _gps.fix); break;
281 default: buffer = g_strdup_printf("nofix"); break;
283 gtk_label_set_label(GTK_LABEL(_sdi_fix), buffer);
287 buffer = g_strdup("none");
290 switch (_gps.fixquality)
292 case 1 : buffer = g_strdup_printf(_("SPS")); break;
293 case 2 : buffer = g_strdup_printf(_("DGPS")); break;
294 case 3 : buffer = g_strdup_printf(_("PPS")); break;
295 case 4 : buffer = g_strdup_printf(_("Real Time Kinematic")); break;
296 case 5 : buffer = g_strdup_printf(_("Float RTK")); break;
297 case 6 : buffer = g_strdup_printf(_("Estimated")); break;
298 case 7 : buffer = g_strdup_printf(_("Manual")); break;
299 case 8 : buffer = g_strdup_printf(_("Simulation")); break;
300 default : buffer = g_strdup_printf(_("none")); break;
303 gtk_label_set_label(GTK_LABEL(_sdi_fqu), buffer);
308 gfloat maxspeed = _gps.maxspeed * UNITS_CONVERT[_units];
314 buffer = g_strdup_printf("%.1f mph", maxspeed);
317 buffer = g_strdup_printf("%.1f kn", maxspeed);
320 buffer = g_strdup_printf("%.1f km/h", maxspeed);
323 gtk_label_set_label(GTK_LABEL(_sdi_msp), buffer);
327 /* refresh sat panel */
328 gtk_widget_queue_draw_area(GTK_WIDGET(_sat_details_panel),
330 _sat_details_panel->allocation.width,
331 _sat_details_panel->allocation.height);
333 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
338 gps_display_data(void)
340 gchar *buffer, litbuf[LL_FMT_LEN];
341 printf("%s()\n", __PRETTY_FUNCTION__);
346 gtk_label_set_label(GTK_LABEL(_text_lat), " --- ");
347 gtk_label_set_label(GTK_LABEL(_text_lon), " --- ");
348 gtk_label_set_label(GTK_LABEL(_text_speed), " --- ");
349 gtk_label_set_label(GTK_LABEL(_text_alt), " --- ");
350 gtk_label_set_label(GTK_LABEL(_text_time), " --:--:-- ");
354 gfloat speed = _gps.speed * UNITS_CONVERT[_units];
357 lat_format(_gps.lat, litbuf);
358 gtk_label_set_label(GTK_LABEL(_text_lat), litbuf);
361 lon_format(_gps.lon, litbuf);
362 gtk_label_set_label(GTK_LABEL(_text_lon), litbuf);
368 buffer = g_strdup_printf("Spd: %.1f mph", speed);
371 buffer = g_strdup_printf("Spd: %.1f kn", speed);
374 buffer = g_strdup_printf("Spd: %.1f km/h", speed);
377 gtk_label_set_label(GTK_LABEL(_text_speed), buffer);
385 buffer = g_strdup_printf("Alt: %d ft",
386 (gint)(_pos.altitude * 3.2808399f));
389 buffer = g_strdup_printf("Alt: %d m", _pos.altitude);
391 gtk_label_set_label(GTK_LABEL(_text_alt), buffer);
395 strftime(litbuf, 15, "%X", localtime(&_pos.time));
396 gtk_label_set_label(GTK_LABEL(_text_time), litbuf);
399 /* refresh sat panel */
400 gtk_widget_queue_draw_area(GTK_WIDGET(_sat_panel),
402 _sat_panel->allocation.width,
403 _sat_panel->allocation.height);
405 /* refresh heading panel*/
406 gtk_widget_queue_draw_area(GTK_WIDGET(_heading_panel),
408 _heading_panel->allocation.width,
409 _heading_panel->allocation.height);
411 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
418 printf("%s()\n", __PRETTY_FUNCTION__);
428 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
434 printf("%s()\n", __PRETTY_FUNCTION__);
436 if(_gps_info && _enable_gps)
437 gtk_widget_show_all(GTK_WIDGET(_gps_widget));
441 gtk_widget_hide(GTK_WIDGET(_gps_widget));
444 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
448 draw_sat_info(GtkWidget *widget, gint x0, gint y0,
449 gint width, gint height, gboolean showsnr)
452 gint step, i, j, snr_height, bymargin, xoffset, yoffset;
455 printf("%s()\n", __PRETTY_FUNCTION__);
459 /* Bootom margin - 12% */
460 bymargin = height * 0.88f;
463 gdk_draw_line(widget->window,
464 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
465 xoffset + 5, yoffset + bymargin,
466 xoffset + width - 10 - 2, yoffset + bymargin);
467 gdk_draw_line(widget->window,
468 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
469 xoffset + 5, yoffset + bymargin - 1,
470 xoffset + width - 10 - 2, yoffset + bymargin - 1);
472 if(_gps.satinview > 0 )
474 /* Left margin - 5pix, Right margin - 5pix */
475 step = (width - 10) / _gps.satinview;
477 for(i = 0; i < _gps.satinview; i++)
479 /* Sat used or not */
481 for(j = 0; j < _gps.satinuse ; j++)
483 if(_gps.satforfix[j] == _gps_sat[i].prn)
491 snr_height = _gps_sat[i].snr * height * 0.78f / 100;
492 y = height * 0.1f + (height * 0.78f - snr_height);
494 /* draw sat rectangle... */
495 gdk_draw_rectangle(widget->window,
503 if(showsnr && _gps_sat[i].snr > 0)
506 tmp = g_strdup_printf("%02d", _gps_sat[i].snr);
507 pango_layout_set_text(_sat_info_layout, tmp, 2);
508 pango_layout_get_pixel_size(_sat_info_layout, &x1, &y1);
509 gdk_draw_layout(widget->window,
510 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
511 xoffset + x + ((step - 2) - x1)/2,
517 /* ...and sat number */
518 tmp = g_strdup_printf("%02d", _gps_sat[i].prn);
519 pango_layout_set_text(_sat_info_layout, tmp, 2);
520 pango_layout_get_pixel_size(_sat_info_layout, &x1, &y1);
521 gdk_draw_layout(widget->window,
522 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
523 xoffset + x + ((step - 2) - x1)/2 ,
524 yoffset + bymargin + 1,
530 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
535 draw_sat_details(GtkWidget *widget, gint x0, gint y0,
536 gint width, gint height)
538 gint i, j, x, y, size, halfsize, xoffset, yoffset;
542 GdkGC *gc1, *gc2, *gc3, *gc;
543 gchar *buffer = NULL;
544 printf("%s()\n", __PRETTY_FUNCTION__);
546 size = MIN(width, height);
550 xoffset = x0 + (width - height - 10) / 2;
556 yoffset = y0 + (height - width - 10) / 2;
560 gdk_draw_arc(widget->window,
561 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
563 xoffset + 2, yoffset + 2, size - 4, size - 4,
567 gdk_draw_arc(widget->window,
568 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
570 xoffset + size/6, yoffset + size/6,
575 gdk_draw_arc(widget->window,
576 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
578 xoffset + size/6*2, yoffset + size/6*2,
582 gint line[12] = {0,30,60,90,120,150,180,210,240,270,300,330};
584 for(i = 0; i < 6; i++)
587 tmp = deg2rad(line[i]);
588 gdk_draw_line(widget->window,
589 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
590 xoffset + halfsize + (halfsize -2) * sinf(tmp),
591 yoffset + halfsize - (halfsize -2) * cosf(tmp),
592 xoffset + halfsize - (halfsize -2) * sinf(tmp),
593 yoffset + halfsize + (halfsize -2) * cosf(tmp));
596 for(i = 0; i < 12; i++)
598 tmp = deg2rad(line[i]);
601 buffer = g_strdup_printf("N");
603 buffer = g_strdup_printf("%d°", line[i]);
604 pango_layout_set_text(_sat_details_layout, buffer, -1);
605 pango_layout_get_pixel_size(_sat_details_layout, &x, &y);
606 gdk_draw_layout(widget->window,
607 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
608 (xoffset + halfsize + (halfsize - size/12) * sinf(tmp)) - x/2,
609 (yoffset + halfsize - (halfsize - size/12) * cosf(tmp)) - y/2,
610 _sat_details_layout);
616 buffer = g_strdup_printf("30°");
617 pango_layout_set_text(_sat_details_layout, buffer, -1);
618 pango_layout_get_pixel_size(_sat_details_layout, &x, &y);
619 gdk_draw_layout(widget->window,
620 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
621 (xoffset + halfsize + size/6*2 * sinf(tmp)) - x/2,
622 (yoffset + halfsize - size/6*2 * cosf(tmp)) - y/2,
623 _sat_details_layout);
628 buffer = g_strdup_printf("60°");
629 pango_layout_set_text(_sat_details_layout, buffer, -1);
630 pango_layout_get_pixel_size(_sat_details_layout, &x, &y);
631 gdk_draw_layout(widget->window,
632 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
633 (xoffset + halfsize + size/6 * sinf(tmp)) - x/2,
634 (yoffset + halfsize - size/6 * cosf(tmp)) - y/2,
635 _sat_details_layout);
641 gc1 = gdk_gc_new (widget->window);
642 gdk_gc_set_rgb_fg_color (gc1, &color);
647 gc2 = gdk_gc_new (widget->window);
648 gdk_gc_set_rgb_fg_color (gc2, &color);
651 color.green = 0xffff;
653 gc3 = gdk_gc_new (widget->window);
654 gdk_gc_set_rgb_fg_color (gc3, &color);
656 for(i = 0; i < _gps.satinview; i++)
658 /* Sat used or not */
660 for(j = 0; j < _gps.satinuse ; j++)
662 if(_gps.satforfix[j] == _gps_sat[i].prn)
669 tmp = deg2rad(_gps_sat[i].azimuth);
670 x = xoffset + halfsize
671 + (90 - _gps_sat[i].elevation)*halfsize/90 * sinf(tmp);
672 y = yoffset + halfsize
673 - (90 - _gps_sat[i].elevation)*halfsize/90 * cosf(tmp);
675 gdk_draw_arc (widget->window,
677 x - 10, y - 10, 20, 20,
680 buffer = g_strdup_printf("%02d", _gps_sat[i].prn);
681 pango_layout_set_text(_sat_details_layout, buffer, -1);
682 pango_layout_get_pixel_size(_sat_details_layout, &x1, &y1);
683 gdk_draw_layout(widget->window,
687 _sat_details_layout);
690 g_object_unref (gc1);
691 g_object_unref (gc2);
692 g_object_unref (gc3);
694 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
700 sat_details_panel_expose(GtkWidget *widget, GdkEventExpose *event)
702 gint width, height, x, y;
703 gchar *buffer = NULL;
704 printf("%s()\n", __PRETTY_FUNCTION__);
706 width = widget->allocation.width;
707 height = widget->allocation.height * 0.9;
709 draw_sat_info(widget, 0, 0, width/2, height, TRUE);
710 draw_sat_details(widget, width/2, 0, width/2, height);
712 buffer = g_strdup_printf(
714 _("Satellites in view"), _gps.satinview,
715 _("in use"), _gps.satinuse);
716 pango_layout_set_text(_sat_details_expose_layout, buffer, -1);
717 pango_layout_get_pixel_size(_sat_details_expose_layout, &x, &y);
718 gdk_draw_layout(widget->window,
719 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
722 _sat_details_expose_layout);
725 buffer = g_strdup_printf("HDOP: %.01f", _gps.hdop);
726 pango_layout_set_text(_sat_details_expose_layout, buffer, -1);
727 pango_layout_get_pixel_size(_sat_details_expose_layout, &x, &y);
728 gdk_draw_layout(widget->window,
729 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
732 _sat_details_expose_layout);
734 buffer = g_strdup_printf("PDOP: %.01f", _gps.pdop);
735 pango_layout_set_text(_sat_details_expose_layout, buffer, -1);
736 pango_layout_get_pixel_size(_sat_details_expose_layout, &x, &y);
737 gdk_draw_layout(widget->window,
738 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
740 (height/6) - y/2 + 20,
741 _sat_details_expose_layout);
743 buffer = g_strdup_printf("VDOP: %.01f", _gps.vdop);
744 pango_layout_set_text(_sat_details_expose_layout, buffer, -1);
745 pango_layout_get_pixel_size(_sat_details_expose_layout, &x, &y);
746 gdk_draw_layout(widget->window,
747 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
749 (height/6) - y/2 + 40,
750 _sat_details_expose_layout);
753 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
760 static GtkWidget *dialog = NULL;
761 static GtkWidget *table = NULL;
762 static GtkWidget *label = NULL;
763 static GtkWidget *notebook = NULL;
764 printf("%s()\n", __PRETTY_FUNCTION__);
768 dialog = gtk_dialog_new_with_buttons(_("GPS Details"),
769 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
770 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
773 gtk_window_set_default_size(GTK_WINDOW(dialog), 600, 300);
775 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
776 notebook = gtk_notebook_new(), TRUE, TRUE, 0);
779 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
780 table = gtk_table_new(4, 6, FALSE),
781 label = gtk_label_new(_("GPS Information")));
783 _sat_details_panel = gtk_drawing_area_new ();
784 gtk_widget_set_size_request (_sat_details_panel, 300, 300);
785 /* sat details info */
786 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
788 label = gtk_label_new(_("Satellites details")));
789 g_signal_connect (G_OBJECT (_sat_details_panel), "expose_event",
790 G_CALLBACK (sat_details_panel_expose), NULL);
792 gtk_table_attach(GTK_TABLE(table),
793 label = gtk_label_new(_("Latitude")),
794 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, 0, 20, 4);
795 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
796 gtk_table_attach(GTK_TABLE(table),
797 _sdi_lat = gtk_label_new(" --- "),
798 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
799 gtk_misc_set_alignment(GTK_MISC(_sdi_lat), 0.f, 0.5f);
801 gtk_table_attach(GTK_TABLE(table),
802 label = gtk_label_new(_("Longitude")),
803 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, 0, 20, 4);
804 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
805 gtk_table_attach(GTK_TABLE(table),
806 _sdi_lon = gtk_label_new(" --- "),
807 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
808 gtk_misc_set_alignment(GTK_MISC(_sdi_lon), 0.f, 0.5f);
810 gtk_table_attach(GTK_TABLE(table),
811 label = gtk_label_new(_("Speed")),
812 0, 1, 2, 3, GTK_EXPAND | GTK_FILL, 0, 20, 4);
813 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
814 gtk_table_attach(GTK_TABLE(table),
815 _sdi_spd = gtk_label_new(" --- "),
816 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
817 gtk_misc_set_alignment(GTK_MISC(_sdi_spd), 0.f, 0.5f);
819 gtk_table_attach(GTK_TABLE(table),
820 label = gtk_label_new(_("Altitude")),
821 0, 1, 3, 4, GTK_EXPAND | GTK_FILL, 0, 20, 4);
822 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
823 gtk_table_attach(GTK_TABLE(table),
824 _sdi_alt = gtk_label_new(" --- "),
825 1, 2, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4);
826 gtk_misc_set_alignment(GTK_MISC(_sdi_alt), 0.f, 0.5f);
828 gtk_table_attach(GTK_TABLE(table),
829 label = gtk_label_new(_("Heading")),
830 0, 1, 4, 5, GTK_EXPAND | GTK_FILL, 0, 20, 4);
831 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
832 gtk_table_attach(GTK_TABLE(table),
833 _sdi_hea = gtk_label_new(" --- "),
834 1, 2, 4, 5, GTK_EXPAND | GTK_FILL, 0, 2, 4);
835 gtk_misc_set_alignment(GTK_MISC(_sdi_hea), 0.f, 0.5f);
837 gtk_table_attach(GTK_TABLE(table),
838 label = gtk_label_new(_("Local time")),
839 0, 1, 5, 6, GTK_EXPAND | GTK_FILL, 0, 20, 4);
840 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
841 gtk_table_attach(GTK_TABLE(table),
842 _sdi_tim = gtk_label_new(" --:--:-- "),
843 1, 2, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 4);
844 gtk_misc_set_alignment(GTK_MISC(_sdi_tim), 0.f, 0.5f);
846 gtk_table_attach(GTK_TABLE(table),
847 label = gtk_label_new(_("Sat in view")),
848 2, 3, 0, 1, GTK_EXPAND | GTK_FILL, 0, 20, 4);
849 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
850 gtk_table_attach(GTK_TABLE(table),
851 _sdi_vie = gtk_label_new("0"),
852 3, 4, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
853 gtk_misc_set_alignment(GTK_MISC(_sdi_vie), 0.f, 0.5f);
855 gtk_table_attach(GTK_TABLE(table),
856 label = gtk_label_new(_("Sat in use")),
857 2, 3, 1, 2, GTK_EXPAND | GTK_FILL, 0, 20, 4);
858 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
859 gtk_table_attach(GTK_TABLE(table),
860 _sdi_use = gtk_label_new("0"),
861 3, 4, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
862 gtk_misc_set_alignment(GTK_MISC(_sdi_use), 0.f, 0.5f);
864 gtk_table_attach(GTK_TABLE(table),
865 label = gtk_label_new(_("Fix")),
866 2, 3, 2, 3, GTK_EXPAND | GTK_FILL, 0, 20, 4);
867 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
868 gtk_table_attach(GTK_TABLE(table),
869 _sdi_fix = gtk_label_new(_("nofix")),
870 3, 4, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
871 gtk_misc_set_alignment(GTK_MISC(_sdi_fix), 0.f, 0.5f);
873 gtk_table_attach(GTK_TABLE(table),
874 label = gtk_label_new(_("Fix Quality")),
875 2, 3, 3, 4, GTK_EXPAND | GTK_FILL, 0, 20, 4);
876 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
877 gtk_table_attach(GTK_TABLE(table),
878 _sdi_fqu = gtk_label_new(_("none")),
879 3, 4, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4);
880 gtk_misc_set_alignment(GTK_MISC(_sdi_fqu), 0.f, 0.5f);
882 gtk_table_attach(GTK_TABLE(table),
883 label = gtk_label_new(_("Max speed")),
884 2, 3, 5, 6, GTK_EXPAND | GTK_FILL, 0, 20, 4);
885 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
886 gtk_table_attach(GTK_TABLE(table),
887 _sdi_msp = gtk_label_new(" --- "),
888 3, 4, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 4);
889 gtk_misc_set_alignment(GTK_MISC(_sdi_msp), 0.f, 0.5f);
892 gtk_widget_show_all(dialog);
893 _satdetails_on = TRUE;
894 gps_display_details();
895 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
897 _satdetails_on = FALSE;
900 gtk_widget_hide(dialog);
902 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
907 * Render a single track line to _map_pixmap. If either point on the line
908 * is a break (defined as unity == 0), a circle is drawn at the other point.
909 * IT IS AN ERROR FOR BOTH POINTS TO INDICATE A BREAK.
912 map_render_segment(GdkGC *gc_norm, GdkGC *gc_alt,
913 gint unitx1, gint unity1, gint unitx2, gint unity2)
915 /* vprintf("%s(%d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
916 unitx1, unity1, unitx2, unity2); */
921 unit2buf(unitx2, unity2, x2, y2);
922 if(((unsigned)(x2+_draw_width) <= _view_width_pixels+2*_draw_width)
923 &&((unsigned)(y2+_draw_width) <= _view_height_pixels+2*_draw_width))
925 gdk_draw_arc(_map_pixmap, gc_alt,
926 FALSE, /* FALSE: not filled. */
931 0, /* start at 0 degrees. */
938 unit2buf(unitx1, unity1, x1, y1);
939 if(((unsigned)(x1+_draw_width) <= _view_width_pixels+2*_draw_width)
940 &&((unsigned)(y1+_draw_width) <= _view_height_pixels+2*_draw_width))
942 gdk_draw_arc(_map_pixmap, gc_alt,
943 FALSE, /* FALSE: not filled. */
948 0, /* start at 0 degrees. */
955 unit2buf(unitx1, unity1, x1, y1);
956 unit2buf(unitx2, unity2, x2, y2);
957 /* Make sure this line could possibly be visible. */
958 if(!((x1 > _view_width_pixels && x2 > _view_width_pixels)
959 || (x1 < 0 && x2 < 0)
960 || (y1 > _view_height_pixels && y2 > _view_height_pixels)
961 || (y1 < 0 && y2 < 0)))
962 gdk_draw_line(_map_pixmap, gc_norm, x1, y1, x2, y2);
965 /* vprintf("%s(): return\n", __PRETTY_FUNCTION__); */
969 * Render all track data onto the _map_pixmap. Note that this does not
970 * clear the pixmap of previous track data (use map_force_redraw() for
971 * that), and also note that this method does not queue any redraws, so it
972 * is up to the caller to decide which part of the track really needs to be
976 map_render_path(Path *path, GdkGC **gc)
980 printf("%s()\n", __PRETTY_FUNCTION__);
982 /* gc is a pointer to the first GC to use (for plain points). (gc + 1)
983 * is a pointer to the GC to use for waypoints, and (gc + 2) is a pointer
984 * to the GC to use for breaks. */
986 /* else there is a route to draw. */
987 for(curr = path->head, wcurr = path->whead; curr++ != path->tail; )
989 /* Draw the line from (curr - 1) to (curr). */
990 map_render_segment(gc[0], gc[2],
991 curr[-1].unitx, curr[-1].unity, curr->unitx, curr->unity);
993 /* Now, check if curr is a waypoint. */
994 if(wcurr <= path->wtail && wcurr->point == curr)
997 unit2buf(wcurr->point->unitx, wcurr->point->unity, x1, y1);
998 gdk_draw_arc(_map_pixmap,
1000 FALSE, /* FALSE: not filled. */
1005 0, /* start at 0 degrees. */
1011 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1017 printf("%s()\n", __PRETTY_FUNCTION__);
1019 if((_show_paths & ROUTES_MASK) && _route.head != _route.tail)
1022 map_render_path(&_route, _gc + COLORABLE_ROUTE);
1024 next_way = path_get_next_way();
1026 /* Now, draw the next waypoint on top of all other waypoints. */
1030 unit2buf(next_way->point->unitx, next_way->point->unity, x1, y1);
1031 /* Draw the next waypoint as a break. */
1032 gdk_draw_arc(_map_pixmap,
1033 _gc[COLORABLE_ROUTE_BREAK],
1034 FALSE, /* FALSE: not filled. */
1039 0, /* start at 0 degrees. */
1043 if(_show_paths & TRACKS_MASK)
1044 map_render_path(&_track, _gc + COLORABLE_TRACK);
1046 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1050 * Update all GdkGC objects to reflect the current _draw_width.
1052 #define UPDATE_GC(gc) \
1053 gdk_gc_set_line_attributes(gc, \
1054 _draw_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
1059 printf("%s()\n", __PRETTY_FUNCTION__);
1061 for(i = 0; i < COLORABLE_ENUM_COUNT; i++)
1063 gdk_color_alloc(gtk_widget_get_colormap(_map_widget), &_color[i]);
1065 g_object_unref(_gc[i]);
1066 _gc[i] = gdk_gc_new(_map_pixmap);
1067 gdk_gc_set_foreground(_gc[i], &_color[i]);
1068 gdk_gc_set_line_attributes(_gc[i],
1069 _draw_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
1072 /* Update the _map_widget's gc's. */
1073 gdk_gc_set_line_attributes(
1074 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
1075 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
1076 gdk_gc_set_line_attributes(
1077 _map_widget->style->bg_gc[GTK_STATE_ACTIVE],
1078 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
1080 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1084 * Call gtk_window_present() on Maemo Mapper. This also checks the
1085 * configuration and brings up the Settings dialog if the GPS Receiver is
1086 * not set up, the first time it is called.
1091 static gint been_here = 0;
1092 static gint done_here = 0;
1093 printf("%s()\n", __PRETTY_FUNCTION__);
1097 /* Set connection state first, to avoid going into this if twice. */
1102 gtk_window_present(GTK_WINDOW(_window));
1104 confirm = hildon_note_new_confirmation(GTK_WINDOW(_window),
1105 _("It looks like this is your first time running"
1106 " Maemo Mapper. Press OK to view the the help pages."
1107 " Otherwise, press Cancel to continue."));
1109 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1112 hildon_help_show(_osso, HELP_ID_INTRO, 0);
1114 ossohelp_show(_osso, HELP_ID_INTRO, 0);
1117 gtk_widget_destroy(confirm);
1119 /* Present the settings dialog. */
1121 popup_error(_window,
1122 _("OpenStreetMap.org provides public, free-to-use maps. "
1123 "You can also download a sample set of repositories from "
1124 " the internet by using the \"Download...\" button."));
1126 /* Present the repository dialog. */
1128 confirm = hildon_note_new_confirmation(GTK_WINDOW(_window),
1129 _("You will now see a blank screen. You can download"
1130 " maps using the \"Manage Maps\" menu item in the"
1131 " \"Maps\" menu. Or, press OK now to enable"
1132 " Auto-Download."));
1133 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1135 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(
1136 _menu_maps_auto_download_item), TRUE);
1138 gtk_widget_destroy(confirm);
1141 /* Connect to receiver. */
1145 ++done_here; /* Don't ask... */
1149 gtk_window_present(GTK_WINDOW(_window));
1150 g_timeout_add_full(G_PRIORITY_HIGH_IDLE,
1151 250, (GSourceFunc)banner_reset, NULL, NULL);
1154 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1159 * "Set" the mark, which translates the current GPS position into on-screen
1160 * units in preparation for drawing the mark with map_draw_mark().
1165 gfloat sqrt_speed, tmp, vel_offset_devx, vel_offset_devy;
1166 printf("%s()\n", __PRETTY_FUNCTION__);
1168 tmp = deg2rad(_gps.heading);
1169 sqrt_speed = VELVEC_SIZE_FACTOR * sqrtf(10 + _gps.speed);
1170 gdk_pixbuf_rotate_vector(&vel_offset_devx, &vel_offset_devy,
1172 sqrt_speed * sinf(tmp), -sqrt_speed * cosf(tmp));
1174 unit2buf(_pos.unitx, _pos.unity, _mark_bufx1, _mark_bufy1);
1176 _mark_bufx2 = _mark_bufx1 + (_show_velvec ? (vel_offset_devx + 0.5f) : 0);
1177 _mark_bufy2 = _mark_bufy1 + (_show_velvec ? (vel_offset_devy + 0.5f) : 0);
1179 _mark_minx = MIN(_mark_bufx1, _mark_bufx2) - (2 * _draw_width);
1180 _mark_miny = MIN(_mark_bufy1, _mark_bufy2) - (2 * _draw_width);
1181 _mark_width = abs(_mark_bufx1 - _mark_bufx2) + (4 * _draw_width);
1182 _mark_height = abs(_mark_bufy1 - _mark_bufy2) + (4 * _draw_width);
1184 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1189 * Force a redraw of the entire _map_pixmap, including fetching the
1190 * background maps from disk and redrawing the tracks on top of them.
1195 printf("%s()\n", __PRETTY_FUNCTION__);
1199 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
1203 _view_width_pixels, _view_height_pixels,
1204 GDK_RGB_DITHER_NONE, 0, 0);
1206 MACRO_MAP_RENDER_DATA();
1207 MACRO_QUEUE_DRAW_AREA();
1209 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1213 map_calc_new_center(gint zoom)
1216 printf("%s()\n", __PRETTY_FUNCTION__);
1218 switch(_center_mode)
1222 gfloat tmp = deg2rad(_gps.heading);
1223 gfloat screen_pixels = _view_width_pixels
1224 + (((gint)_view_height_pixels
1225 - (gint)_view_width_pixels)
1226 * fabsf(cosf(deg2rad(
1227 ROTATE_DIR_ENUM_DEGREES[_rotate_dir] -
1229 : (_next_map_rotate_angle
1230 - (gint)(_gps.heading)))))));
1231 gfloat lead_pixels = 0.0025f
1232 * pixel2zunit((gint)screen_pixels, zoom)
1234 * VELVEC_SIZE_FACTOR
1235 * (_lead_is_fixed ? 7 : sqrtf(_gps.speed));
1237 new_center.unitx = _pos.unitx + (gint)(lead_pixels * sinf(tmp));
1238 new_center.unity = _pos.unity - (gint)(lead_pixels * cosf(tmp));
1242 new_center.unitx = _pos.unitx;
1243 new_center.unity = _pos.unity;
1246 new_center.unitx = _next_center.unitx;
1247 new_center.unity = _next_center.unity;
1250 vprintf("%s(): return (%d, %d)\n", __PRETTY_FUNCTION__,
1251 new_center.unitx, new_center.unity);
1256 * Center the view on the given unitx/unity.
1259 map_center_unit_full(Point new_center,
1260 gint zoom, gint rotate_angle)
1263 printf("%s(%d, %d)\n", __PRETTY_FUNCTION__,
1264 new_center.unitx, new_center.unity);
1268 /* Assure that _center.unitx/y are bounded. */
1269 BOUND(new_center.unitx, 0, WORLD_SIZE_UNITS);
1270 BOUND(new_center.unity, 0, WORLD_SIZE_UNITS);
1272 mrt = g_slice_new(MapRenderTask);
1273 mrt->repo = _curr_repo;
1274 mrt->old_offsetx = _map_offset_devx;
1275 mrt->old_offsety = _map_offset_devy;
1276 mrt->new_center = _next_center = new_center;
1277 mrt->screen_width_pixels = _view_width_pixels;
1278 mrt->screen_height_pixels = _view_height_pixels;
1279 mrt->zoom = _next_zoom = zoom;
1280 mrt->rotate_angle = _next_map_rotate_angle = rotate_angle;
1283 gtk_widget_queue_draw_area(
1285 _redraw_wait_bounds.x,
1286 _redraw_wait_bounds.y,
1287 _redraw_wait_bounds.width
1288 + (_redraw_count * HOURGLASS_SEPARATION),
1289 _redraw_wait_bounds.height);
1293 g_thread_pool_push(_mrt_thread_pool, mrt, NULL);
1296 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1300 map_center_unit(Point new_center)
1302 map_center_unit_full(new_center, _next_zoom,
1303 _center_mode > 0 && _center_rotate
1304 ? _gps.heading : _next_map_rotate_angle);
1308 map_rotate(gint rotate_angle)
1310 if(_center_mode > 0 && gtk_check_menu_item_get_active(
1311 GTK_CHECK_MENU_ITEM(_menu_view_rotate_auto_item)))
1312 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(
1313 _menu_view_rotate_auto_item), FALSE);
1315 map_center_unit_full(map_calc_new_center(_next_zoom), _next_zoom,
1316 (_next_map_rotate_angle + rotate_angle) % 360);
1320 map_center_zoom(gint zoom)
1322 map_center_unit_full(map_calc_new_center(zoom), zoom,
1323 _center_mode > 0 && _center_rotate
1324 ? _gps.heading : _next_map_rotate_angle);
1328 * Pan the view by the given number of units in the X and Y directions.
1331 map_pan(gint delta_unitx, gint delta_unity)
1334 printf("%s(%d, %d)\n", __PRETTY_FUNCTION__, delta_unitx, delta_unity);
1336 if(_center_mode > 0)
1337 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(
1338 _menu_view_ac_none_item), TRUE);
1339 new_center.unitx = _center.unitx + delta_unitx;
1340 new_center.unity = _center.unity + delta_unity;
1341 map_center_unit_full(new_center, _next_zoom,
1342 _center_mode > 0 && _center_rotate
1343 ? _gps.heading : _next_map_rotate_angle);
1345 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1349 * Initiate a move of the mark from the old location to the current
1350 * location. This function queues the draw area of the old mark (to force
1351 * drawing of the background map), then updates the mark, then queus the
1352 * draw area of the new mark.
1357 printf("%s()\n", __PRETTY_FUNCTION__);
1359 /* Just queue the old and new draw areas. */
1360 gtk_widget_queue_draw_area(_map_widget,
1361 _mark_minx + _map_offset_devx,
1362 _mark_miny + _map_offset_devy,
1366 gtk_widget_queue_draw_area(_map_widget,
1367 _mark_minx + _map_offset_devx,
1368 _mark_miny + _map_offset_devy,
1372 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1376 * Make sure the mark is up-to-date. This function triggers a panning of
1377 * the view if the mark is appropriately close to the edge of the view.
1380 map_refresh_mark(gboolean force_redraw)
1382 printf("%s()\n", __PRETTY_FUNCTION__);
1384 gint new_center_devx, new_center_devy;
1386 Point new_center = map_calc_new_center(_next_zoom);
1388 unit2buf(new_center.unitx, new_center.unity,
1389 new_center_devx, new_center_devy);
1390 if(force_redraw || (_center_mode > 0
1391 && (UNITS_CONVERT[_units] * _gps.speed) >= _ac_min_speed &&
1392 (((unsigned)(new_center_devx - (_view_width_pixels * _center_ratio / 20))
1393 > ((10 - _center_ratio) * _view_width_pixels / 10))
1394 || ((unsigned)(new_center_devy - (_view_height_pixels * _center_ratio / 20))
1395 > ((10 - _center_ratio) * _view_height_pixels / 10))
1396 || (_center_rotate &&
1397 abs(_next_map_rotate_angle - _gps.heading)
1398 > (4*(10-_rotate_sens))))))
1401 map_center_unit(new_center);
1405 /* We're not changing the view - just move the mark. */
1409 /* Draw speed info */
1413 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1417 map_download_refresh_idle(MapUpdateTask *mut)
1419 vprintf("%s(%p, %d, %d, %d)\n", __PRETTY_FUNCTION__, mut,
1420 mut->zoom, mut->tilex, mut->tiley);
1422 /* Test if download succeeded (only if retries != 0). */
1423 if(mut->pixbuf && mut->repo == _curr_repo)
1425 gint zoff = mut->zoom - _zoom;
1426 /* Update the UI to reflect the updated map database. */
1427 /* Only refresh at same or "lower" (more detailed) zoom level. */
1428 if(mut->update_type == MAP_UPDATE_AUTO && (unsigned)zoff <= 4)
1430 gfloat destx, desty;
1431 gint boundx, boundy, width, height;
1434 tile2pixel(mut->tilex << zoff)
1435 + ((TILE_SIZE_PIXELS << zoff) >> 1),
1436 tile2pixel(mut->tiley << zoff)
1437 + ((TILE_SIZE_PIXELS << zoff) >> 1),
1440 /* Multiply the matrix to cause blitting. */
1442 gdk_pixbuf_rotate_matrix_mult_number(
1443 _map_rotate_matrix, 1 << zoff);
1444 gdk_pixbuf_rotate(_map_pixbuf,
1445 /* Apply Map Correction. */
1446 destx - unit2pixel(_map_correction_unitx),
1447 desty - unit2pixel(_map_correction_unity),
1450 TILE_SIZE_PIXELS / 2,
1451 TILE_SIZE_PIXELS / 2,
1454 &boundx, &boundy, &width, &height);
1455 /* Un-multiply the matrix that we used for blitting. Good thing
1456 * we're multiplying by powers of two, or this wouldn't work
1457 * consistently... */
1459 gdk_pixbuf_rotate_matrix_mult_number(
1460 _map_rotate_matrix, 1.f / (1 << zoff));
1466 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
1471 GDK_RGB_DITHER_NONE, 0, 0);
1472 MACRO_MAP_RENDER_DATA();
1473 gtk_widget_queue_draw_area(
1474 _map_widget, boundx, boundy, width, height);
1477 g_object_unref(mut->pixbuf);
1479 else if(mut->vfs_result != GNOME_VFS_OK)
1484 if(++_curr_download == _num_downloads)
1486 if(_download_banner)
1488 gtk_widget_destroy(_download_banner);
1489 _download_banner = NULL;
1491 _num_downloads = _curr_download = 0;
1492 g_thread_pool_stop_unused_threads();
1493 #ifndef MAPDB_SQLITE
1495 gdbm_sync(_curr_repo->db);
1499 gchar buffer[BUFFER_SIZE];
1500 snprintf(buffer, sizeof(buffer), "%d %s", _dl_errors,
1501 _("maps failed to download."));
1502 MACRO_BANNER_SHOW_INFO(_window, buffer);
1505 else if(mut->update_type != MAP_UPDATE_AUTO)
1507 /* Update the map. */
1508 map_refresh_mark(TRUE);
1511 else if(_download_banner)
1513 hildon_banner_set_fraction(HILDON_BANNER(_download_banner),
1514 _curr_download / (double)_num_downloads);
1517 g_mutex_lock(_mut_priority_mutex);
1518 g_hash_table_remove(_mut_exists_table, mut);
1519 g_mutex_unlock(_mut_priority_mutex);
1521 g_slice_free(MapUpdateTask, mut);
1523 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1528 * Set the current zoom level. If the given zoom level is the same as the
1529 * current zoom level, or if the new zoom is invalid
1530 * (not MIN_ZOOM <= new_zoom < MAX_ZOOM), then this method does nothing.
1533 map_set_zoom(gint new_zoom)
1535 printf("%s(%d)\n", __PRETTY_FUNCTION__, _zoom);
1537 /* This if condition also checks for new_zoom >= 0. */
1538 if((unsigned)new_zoom > MAX_ZOOM)
1541 map_center_zoom(new_zoom / _curr_repo->view_zoom_steps
1542 * _curr_repo->view_zoom_steps);
1544 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1548 map_replace_pixbuf_idle(MapRenderTask *mrt)
1550 printf("%s()\n", __PRETTY_FUNCTION__);
1552 if(!--_pending_replaces && !_mouse_is_down
1553 && mrt->screen_width_pixels == _view_width_pixels
1554 && mrt->screen_height_pixels == _view_height_pixels)
1556 g_object_unref(_map_pixbuf);
1557 _map_pixbuf = mrt->pixbuf;
1559 if(_center.unitx != mrt->new_center.unitx
1560 || _center.unity != mrt->new_center.unity
1561 || _zoom != mrt->zoom
1562 || _map_rotate_angle != mrt->rotate_angle)
1564 dbus_ifc_fire_view_position_changed(
1565 mrt->new_center, mrt->zoom, mrt->rotate_angle);
1568 _center = mrt->new_center;
1570 _map_rotate_angle = mrt->rotate_angle;
1572 gdk_pixbuf_rotate_matrix_fill_for_rotation(
1574 deg2rad(ROTATE_DIR_ENUM_DEGREES[_rotate_dir]
1575 - _map_rotate_angle));
1576 gdk_pixbuf_rotate_matrix_fill_for_rotation(
1577 _map_reverse_matrix,
1578 deg2rad(_map_rotate_angle
1579 - ROTATE_DIR_ENUM_DEGREES[_rotate_dir]));
1583 _map_offset_devx = 0;
1584 _map_offset_devy = 0;
1591 /* Ignore this new pixbuf. We have newer ones coming. */
1592 g_object_unref(mrt->pixbuf);
1596 g_slice_free(MapRenderTask, mrt);
1598 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1603 thread_render_map(MapRenderTask *mrt)
1606 gint start_tilex, start_tiley, stop_tilex, stop_tiley;
1607 gint x = 0, y, num_tilex, num_tiley;
1608 gint diag_halflength_units;
1610 gint tile_rothalf_pixels;
1611 gint curr_tile_to_draw, num_tiles_to_draw;
1613 ThreadLatch *refresh_latch = NULL;
1615 static gint8 auto_download_batch_id = INT8_MIN;
1616 printf("%s(%d, %d, %d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1617 mrt->screen_width_pixels, mrt->screen_height_pixels,
1618 mrt->new_center.unitx, mrt->new_center.unity, mrt->zoom,
1621 /* If there are more render tasks in the queue, skip this one. */
1622 if(g_thread_pool_unprocessed(_mrt_thread_pool))
1624 g_slice_free(MapRenderTask, mrt);
1626 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1630 angle_rad = deg2rad(ROTATE_DIR_ENUM_DEGREES[_rotate_dir]
1631 - mrt->rotate_angle);
1633 gdk_pixbuf_rotate_matrix_fill_for_rotation(matrix, angle_rad);
1635 /* Determine (roughly) the tiles we might have to process.
1636 * Basically, we take the center unit and subtract the maximum dimension
1637 * of the screen plus the maximum additional pixels of a rotated tile.
1639 tile_rothalf_pixels = MAX(
1640 fabsf(TILE_HALFDIAG_PIXELS * sinf((PI / 4) - angle_rad)),
1641 fabsf(TILE_HALFDIAG_PIXELS * cosf((PI / 4) - angle_rad)));
1643 mrt->zoom = _next_zoom;
1645 if(mrt->repo->type != REPOTYPE_NONE && mrt->repo->db)
1646 cache_amount = _auto_download_precache;
1648 cache_amount = 1; /* No cache. */
1650 diag_halflength_units = pixel2zunit(TILE_HALFDIAG_PIXELS
1651 + MAX(mrt->screen_width_pixels, mrt->screen_height_pixels) / 2,
1653 start_tilex = unit2ztile(
1654 mrt->new_center.unitx - diag_halflength_units
1655 + _map_correction_unitx, mrt->zoom);
1656 start_tilex = MAX(start_tilex - (cache_amount - 1), 0);
1657 start_tiley = unit2ztile(
1658 mrt->new_center.unity - diag_halflength_units
1659 + _map_correction_unity, mrt->zoom);
1660 start_tiley = MAX(start_tiley - (cache_amount - 1), 0);
1661 stop_tilex = unit2ztile(mrt->new_center.unitx + diag_halflength_units
1662 + _map_correction_unitx, mrt->zoom);
1663 stop_tilex = MIN(stop_tilex + (cache_amount - 1),
1664 unit2ztile(WORLD_SIZE_UNITS, mrt->zoom));
1665 stop_tiley = unit2ztile(mrt->new_center.unity + diag_halflength_units
1666 + _map_correction_unity, mrt->zoom);
1667 stop_tiley = MIN(stop_tiley + (cache_amount - 1),
1668 unit2ztile(WORLD_SIZE_UNITS, mrt->zoom));
1670 num_tilex = (stop_tilex - start_tilex + 1);
1671 num_tiley = (stop_tiley - start_tiley + 1);
1672 tile_dev = g_new0(gfloat, num_tilex * num_tiley * 2);
1674 ++auto_download_batch_id;
1676 /* Iterate through the tiles and mark which ones need retrieval. */
1677 num_tiles_to_draw = 0;
1678 for(y = 0; y < num_tiley; ++y)
1680 for(x = 0; x < num_tilex; ++x)
1684 /* Find the device location of this tile's center. */
1686 tile2pixel(x + start_tilex) + (TILE_SIZE_PIXELS >> 1),
1687 tile2pixel(y + start_tiley) + (TILE_SIZE_PIXELS >> 1),
1689 mrt->new_center, mrt->zoom, matrix);
1691 /* Apply Map Correction. */
1692 devx -= unit2zpixel(_map_correction_unitx, mrt->zoom);
1693 devy -= unit2zpixel(_map_correction_unity, mrt->zoom);
1695 /* Skip this tile under the following conditions:
1696 * devx < -tile_rothalf_pixels
1697 * devx > _view_width_pixels + tile_rothalf_pixels
1698 * devy < -tile_rothalf_pixels
1699 * devy > _view_height_pixels + tile_rothalf_pixels
1701 if(((unsigned)(devx + tile_rothalf_pixels))
1702 < (_view_width_pixels + (2 * tile_rothalf_pixels))
1703 && ((unsigned)(devy + tile_rothalf_pixels))
1704 < (_view_height_pixels + (2 * tile_rothalf_pixels)))
1706 tile_dev[2 * (y * num_tilex + x)] = devx;
1707 tile_dev[2 * (y * num_tilex + x) + 1] = devy;
1708 ++num_tiles_to_draw;
1712 tile_dev[2 * (y * num_tilex + x)] = FLT_MAX;
1717 mrt->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
1718 mrt->screen_width_pixels, mrt->screen_height_pixels);
1720 /* Iterate through the tiles, get them (or queue a download if they're
1721 * not in the cache), and rotate them into the pixbuf. */
1722 for(y = curr_tile_to_draw = 0; y < num_tiley; ++y)
1724 gint tiley = y + start_tiley;
1725 for(x = 0; x < num_tilex; ++x)
1727 GdkPixbuf *tile_pixbuf = NULL;
1728 gboolean started_download = FALSE;
1732 tilex = x + start_tilex;
1734 zoff = mrt->repo->double_size ? 1 : 0;
1736 /* Iteratively try to retrieve a map to draw the tile. */
1737 while((mrt->zoom + zoff) <= MAX_ZOOM && zoff < TILE_SIZE_P2)
1739 /* Check if we're actually going to draw this map. */
1740 if(tile_dev[2 * (y*num_tilex + x)] != FLT_MAX)
1742 if(NULL != (tile_pixbuf = mapdb_get(
1743 mrt->repo, mrt->zoom + zoff,
1751 /* Else we're not going to be drawing this map, so just check
1752 * if it's in the database. */
1753 else if(mapdb_exists(
1754 mrt->repo, mrt->zoom + zoff,
1761 /* No map; download, if we should. */
1762 if(!started_download && _auto_download
1763 && mrt->repo->type != REPOTYPE_NONE
1764 /* Make sure this map is within dl zoom limits. */
1765 && ((unsigned)(mrt->zoom + zoff - mrt->repo->min_zoom)
1766 <= (mrt->repo->max_zoom - mrt->repo->min_zoom))
1767 /* Make sure this map matches the dl_zoom_steps,
1768 * or that there currently is no cache. */
1769 && (!mrt->repo->db || !((mrt->zoom + zoff
1770 - (mrt->repo->double_size ? 1 : 0))
1771 % mrt->repo->dl_zoom_steps))
1772 /* Make sure this tile is even possible. */
1773 && ((unsigned)(tilex >> zoff)
1774 < unit2ztile(WORLD_SIZE_UNITS, mrt->zoom + zoff)
1775 && (unsigned)(tiley >> zoff)
1776 < unit2ztile(WORLD_SIZE_UNITS, mrt->zoom + zoff)))
1778 started_download = TRUE;
1782 refresh_latch = g_slice_new(ThreadLatch);
1783 refresh_latch->is_open = FALSE;
1784 refresh_latch->is_done_adding_tasks = FALSE;
1785 refresh_latch->num_tasks = 1;
1786 refresh_latch->num_done = 0;
1787 refresh_latch->mutex = g_mutex_new();
1788 refresh_latch->cond = g_cond_new();
1791 ++refresh_latch->num_tasks;
1793 mapdb_initiate_update(
1799 auto_download_batch_id,
1800 (abs((tilex >> zoff) - unit2ztile(
1801 mrt->new_center.unitx, mrt->zoom + zoff))
1802 + abs((tiley >> zoff) - unit2ztile(
1803 mrt->new_center.unity, mrt->zoom + zoff))),
1807 /* Try again at a coarser resolution. */
1813 gint boundx, boundy, width, height;
1815 gdk_pixbuf_rotate_matrix_mult_number(matrix, 1 << zoff);
1816 gdk_pixbuf_rotate(mrt->pixbuf,
1817 tile_dev[2 * (y * num_tilex + x)],
1818 tile_dev[2 * (y * num_tilex + x) + 1],
1821 ((tilex - ((tilex >> zoff) << zoff))
1822 << (TILE_SIZE_P2 - zoff))
1823 + (TILE_SIZE_PIXELS >> (1 + zoff)),
1824 ((tiley - ((tiley>>zoff) << zoff))
1825 << (TILE_SIZE_P2 - zoff))
1826 + (TILE_SIZE_PIXELS >> (1 + zoff)),
1827 TILE_SIZE_PIXELS >> zoff,
1828 TILE_SIZE_PIXELS >> zoff,
1829 &boundx, &boundy, &width, &height);
1830 g_object_unref(tile_pixbuf);
1831 /* Un-multiply the matrix that we used for blitting. Good
1832 * thing we're multiplying by powers of two, or this wouldn't
1833 * work consistently... */
1835 gdk_pixbuf_rotate_matrix_mult_number(
1836 matrix, 1.f / (1 << zoff));
1838 /* usleep(10000); DEBUG */
1842 /* Don't replace the pixbuf unless/until the mouse is released. */
1843 g_mutex_lock(_mouse_mutex);
1844 ++_pending_replaces;
1845 g_idle_add_full(G_PRIORITY_HIGH_IDLE + 20,
1846 (GSourceFunc)map_replace_pixbuf_idle, mrt, NULL);
1847 g_mutex_unlock(_mouse_mutex);
1849 /* Release the view-change lock. */
1852 g_mutex_lock(refresh_latch->mutex);
1853 if(refresh_latch->num_tasks == refresh_latch->num_done)
1855 /* Fast little workers, aren't they? */
1856 g_mutex_unlock(refresh_latch->mutex);
1857 g_cond_free(refresh_latch->cond);
1858 g_mutex_free(refresh_latch->mutex);
1859 g_slice_free(ThreadLatch, refresh_latch);
1863 refresh_latch->is_done_adding_tasks = TRUE;
1864 refresh_latch->is_open = TRUE;
1865 g_cond_signal(refresh_latch->cond);
1866 g_mutex_unlock(refresh_latch->mutex);
1872 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1877 map_cb_configure(GtkWidget *widget, GdkEventConfigure *event)
1879 gint old_view_width_pixels, old_view_height_pixels;
1880 GdkPixbuf *old_map_pixbuf;
1881 printf("%s(%d, %d)\n", __PRETTY_FUNCTION__,
1882 _map_widget->allocation.width, _map_widget->allocation.height);
1884 if(_map_widget->allocation.width == 1
1885 && _map_widget->allocation.height == 1)
1886 /* Special case - first allocation - not persistent. */
1889 old_view_width_pixels = _view_width_pixels;
1890 old_view_height_pixels = _view_height_pixels;
1891 _view_width_pixels = _map_widget->allocation.width;
1892 _view_height_pixels = _map_widget->allocation.height;
1893 _view_halfwidth_pixels = _view_width_pixels / 2;
1894 _view_halfheight_pixels = _view_height_pixels / 2;
1896 g_object_unref(_map_pixmap);
1897 _map_pixmap = gdk_pixmap_new(
1898 _map_widget->window,
1899 _view_width_pixels, _view_height_pixels,
1900 -1); /* -1: use bit depth of widget->window. */
1902 old_map_pixbuf = _map_pixbuf;
1903 _map_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
1904 _view_width_pixels, _view_height_pixels);
1907 gint oldnew_diffx = (gint)(_view_width_pixels
1908 - old_view_width_pixels) / 2;
1909 gint oldnew_diffy = (gint)(_view_height_pixels
1910 - old_view_height_pixels) / 2;
1911 gdk_pixbuf_copy_area(old_map_pixbuf,
1912 MAX(0, -oldnew_diffx), MAX(0, -oldnew_diffy),
1913 MIN(_view_width_pixels, old_view_width_pixels),
1914 MIN(_view_height_pixels, old_view_height_pixels),
1916 MAX(0, oldnew_diffx), MAX(0, oldnew_diffy));
1919 g_object_unref(old_map_pixbuf);
1921 /* Set _scale_rect. */
1922 _scale_rect.x = (_view_width_pixels - SCALE_WIDTH) / 2;
1923 _scale_rect.width = SCALE_WIDTH;
1924 pango_layout_set_text(_scale_layout, "0", -1);
1925 pango_layout_get_pixel_size(_scale_layout, NULL, &_scale_rect.height);
1926 _scale_rect.y = _view_height_pixels - _scale_rect.height - 1;
1928 /* Set _zoom rect. */
1929 pango_layout_set_text(_zoom_layout, "00", -1);
1930 pango_layout_get_pixel_size(_zoom_layout, &_zoom_rect.width,
1931 &_zoom_rect.height);
1932 _zoom_rect.width *= 1.25;
1933 pango_layout_set_width(_zoom_layout, _zoom_rect.width);
1934 pango_layout_context_changed(_zoom_layout);
1935 _zoom_rect.x = _scale_rect.x - _zoom_rect.width;
1936 _zoom_rect.y = _view_height_pixels - _zoom_rect.height - 1;
1938 /* Set _comprose_rect. */
1939 _comprose_rect.x = _view_width_pixels - 25 - _comprose_rect.width;
1940 _comprose_rect.y = _view_height_pixels - 25 - _comprose_rect.height;
1945 /* Fire the screen_dimensions_changed DBUS signal. */
1946 dbus_ifc_fire_view_dimensions_changed(
1947 _view_width_pixels, _view_height_pixels);
1949 /* If Auto-Center is set to Lead, then recalc center. */
1950 if(_center_mode == CENTER_LEAD)
1951 map_center_unit(map_calc_new_center(_next_zoom));
1953 map_center_unit(_next_center);
1955 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1960 sat_panel_expose(GtkWidget *widget, GdkEventExpose *event)
1964 printf("%s()\n", __PRETTY_FUNCTION__);
1966 draw_sat_info(widget,
1968 widget->allocation.width,
1969 widget->allocation.height,
1972 /* Sat View/In Use */
1973 tmp = g_strdup_printf("%d/%d", _gps.satinuse, _gps.satinview);
1974 pango_layout_set_text(_sat_panel_layout, tmp, -1);
1975 pango_layout_set_alignment(_sat_panel_layout, PANGO_ALIGN_LEFT);
1976 gdk_draw_layout(widget->window,
1977 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1985 case 3: tmp = g_strdup_printf("%dD fix", _gps.fix); break;
1986 default: tmp = g_strdup_printf("nofix"); break;
1988 pango_layout_set_text(_sat_panel_layout, tmp, -1);
1989 pango_layout_set_alignment(_sat_panel_layout, PANGO_ALIGN_RIGHT);
1990 pango_layout_get_pixel_size(_sat_panel_layout, &x, &y);
1991 gdk_draw_layout(widget->window,
1992 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1993 widget->allocation.width - 20 - x, 2,
1997 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2002 heading_panel_expose(GtkWidget *widget, GdkEventExpose *event)
2004 gint size, xoffset, yoffset, i, x, y;
2008 printf("%s()\n", __PRETTY_FUNCTION__);
2010 size = MIN(widget->allocation.width, widget->allocation.height);
2011 if(widget->allocation.width > widget->allocation.height)
2013 xoffset = (widget->allocation.width - widget->allocation.height) / 2;
2019 yoffset = (widget->allocation.height - widget->allocation.width) / 2;
2021 pango_font_description_set_size(_heading_panel_fontdesc,12*PANGO_SCALE);
2022 pango_layout_set_font_description(_heading_panel_layout,
2023 _heading_panel_fontdesc);
2024 pango_layout_set_alignment(_heading_panel_layout, PANGO_ALIGN_CENTER);
2026 text = g_strdup_printf("%3.0f°", _gps.heading);
2027 pango_layout_set_text(_heading_panel_layout, text, -1);
2028 pango_layout_get_pixel_size(_heading_panel_layout, &x, &y);
2030 gdk_draw_layout(widget->window,
2031 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2032 xoffset + size/2 - x/2,
2033 yoffset + size - y - 2, _heading_panel_layout);
2036 gdk_draw_arc (widget->window,
2037 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2039 xoffset, yoffset + size/2,
2043 /* Simple arrow for heading*/
2044 gdk_draw_line(widget->window,
2045 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2046 xoffset + size/2 + 3,
2047 yoffset + size - y - 5,
2049 yoffset + size/2 + 5);
2051 gdk_draw_line(widget->window,
2052 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2053 xoffset + size/2 - 3,
2054 yoffset + size - y - 5,
2056 yoffset + size/2 + 5);
2058 gdk_draw_line(widget->window,
2059 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2060 xoffset + size/2 - 3,
2061 yoffset + size - y - 5,
2063 yoffset + size - y - 8);
2065 gdk_draw_line(widget->window,
2066 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2067 xoffset + size/2 + 3,
2068 yoffset + size - y - 5,
2070 yoffset + size - y - 8);
2072 gint angle[5] = {-90,-45,0,45,90};
2073 gint fsize[5] = {0,4,10,4,0};
2074 for(i = 0; i < 5; i++)
2076 dir = (gint)(_gps.heading/45)*45 + angle[i];
2081 case 360: text = g_strdup("N"); break;
2084 text = g_strdup("NE"); break;
2086 text = g_strdup("E"); break;
2088 text = g_strdup("SE"); break;
2090 text = g_strdup("S"); break;
2092 text = g_strdup("SW"); break;
2095 text = g_strdup("W"); break;
2098 text = g_strdup("NW"); break;
2100 text = g_strdup("??");
2104 tmp = deg2rad(dir - _gps.heading);
2105 gdk_draw_line(widget->window,
2106 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2107 xoffset + size/2 + ((size/2 - 5) * sinf(tmp)),
2108 yoffset + size - ((size/2 - 5) * cosf(tmp)),
2109 xoffset + size/2 + ((size/2 + 5) * sinf(tmp)),
2110 yoffset + size - ((size/2 + 5) * cosf(tmp)));
2113 if(abs((gint)(_gps.heading/45)*45 - _gps.heading)
2114 > abs((gint)(_gps.heading/45)*45 + 45 - _gps.heading)
2118 pango_font_description_set_size(_heading_panel_fontdesc,
2119 (10 + x)*PANGO_SCALE);
2120 pango_layout_set_font_description(_heading_panel_layout,
2121 _heading_panel_fontdesc);
2122 pango_layout_set_text(_heading_panel_layout, text, -1);
2123 pango_layout_get_pixel_size(_heading_panel_layout, &x, &y);
2124 x = xoffset + size/2 + ((size/2 + 15) * sinf(tmp)) - x/2,
2125 y = yoffset + size - ((size/2 + 15) * cosf(tmp)) - y/2,
2127 gdk_draw_layout(widget->window,
2128 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2129 x, y, _heading_panel_layout);
2133 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2138 map_cb_expose(GtkWidget *widget, GdkEventExpose *event)
2141 printf("%s(%d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
2142 event->area.x, event->area.y,
2143 event->area.width, event->area.height);
2146 _map_widget->window,
2147 _gc[COLORABLE_MARK],
2149 event->area.x - _map_offset_devx, event->area.y - _map_offset_devy,
2150 event->area.x, event->area.y,
2151 event->area.width, event->area.height);
2153 /* Draw the mark. */
2154 if((((unsigned)(_mark_bufx1 + _draw_width)
2155 <= _view_width_pixels+2*_draw_width)
2156 &&((unsigned)(_mark_bufy1 + _draw_width)
2157 <= _view_height_pixels+2*_draw_width))
2158 || (((unsigned)(_mark_bufx2 + _draw_width)
2159 <= _view_width_pixels+2*_draw_width)
2160 &&((unsigned)(_mark_bufy2 + _draw_width)
2161 <= _view_height_pixels+2*_draw_width)))
2164 _map_widget->window,
2165 _gps_state == RCVR_FIXED
2166 ? _gc[COLORABLE_MARK] : _gc[COLORABLE_MARK_OLD],
2167 FALSE, /* not filled. */
2168 _mark_bufx1 - _draw_width + _map_offset_devx,
2169 _mark_bufy1 - _draw_width + _map_offset_devy,
2170 2 * _draw_width, 2 * _draw_width,
2173 _map_widget->window,
2174 _gps_state == RCVR_FIXED
2176 ? _gc[COLORABLE_MARK_VELOCITY] : _gc[COLORABLE_MARK])
2177 : _gc[COLORABLE_MARK_OLD],
2178 _mark_bufx1 + _map_offset_devx,
2179 _mark_bufy1 + _map_offset_devy,
2180 _mark_bufx2 + _map_offset_devx,
2181 _mark_bufy2 + _map_offset_devy);
2184 /* draw zoom box if so wanted */
2185 if(_show_zoomlevel) {
2186 gchar *buffer = g_strdup_printf("%d", _zoom);
2187 gdk_draw_rectangle(_map_widget->window,
2188 _map_widget->style->bg_gc[GTK_STATE_ACTIVE],
2190 _zoom_rect.x, _zoom_rect.y,
2191 _zoom_rect.width, _zoom_rect.height);
2192 gdk_draw_rectangle(_map_widget->window,
2193 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2195 _zoom_rect.x, _zoom_rect.y,
2196 _zoom_rect.width, _zoom_rect.height);
2197 pango_layout_set_text(_zoom_layout, buffer, -1);
2198 gdk_draw_layout(_map_widget->window,
2199 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2200 _zoom_rect.x + _zoom_rect.width / 2,
2201 _zoom_rect.y, _zoom_layout);
2204 /* Draw scale, if necessary. */
2207 gdk_rectangle_intersect(&event->area, &_scale_rect, &event->area);
2208 if(event->area.width && event->area.height)
2210 gdk_draw_rectangle(_map_widget->window,
2211 _map_widget->style->bg_gc[GTK_STATE_ACTIVE],
2213 _scale_rect.x, _scale_rect.y,
2214 _scale_rect.width, _scale_rect.height);
2215 gdk_draw_rectangle(_map_widget->window,
2216 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2218 _scale_rect.x, _scale_rect.y,
2219 _scale_rect.width, _scale_rect.height);
2221 /* Now calculate and draw the distance. */
2225 gdouble lat1, lon1, lat2, lon2;
2228 unit2latlon(_center.unitx - pixel2unit(SCALE_WIDTH / 2 - 4),
2229 _center.unity, lat1, lon1);
2230 unit2latlon(_center.unitx + pixel2unit(SCALE_WIDTH / 2 - 4),
2231 _center.unity, lat2, lon2);
2232 distance = calculate_distance(lat1, lon1, lat2, lon2)
2233 * UNITS_CONVERT[_units];
2236 snprintf(buffer, sizeof(buffer), "%0.2f %s", distance,
2237 UNITS_ENUM_TEXT[_units]);
2238 else if(distance < 10.f)
2239 snprintf(buffer, sizeof(buffer), "%0.1f %s", distance,
2240 UNITS_ENUM_TEXT[_units]);
2242 snprintf(buffer, sizeof(buffer), "%0.f %s", distance,
2243 UNITS_ENUM_TEXT[_units]);
2244 pango_layout_set_text(_scale_layout, buffer, -1);
2246 pango_layout_get_pixel_size(_scale_layout, &width, NULL);
2248 /* Draw the layout itself. */
2249 gdk_draw_layout(_map_widget->window,
2250 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2251 _scale_rect.x + (_scale_rect.width - width) / 2,
2252 _scale_rect.y, _scale_layout);
2254 /* Draw little hashes on the ends. */
2255 gdk_draw_line(_map_widget->window,
2256 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2258 _scale_rect.y + _scale_rect.height / 2 - 4,
2260 _scale_rect.y + _scale_rect.height / 2 + 4);
2261 gdk_draw_line(_map_widget->window,
2262 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2264 _scale_rect.y + _scale_rect.height / 2,
2265 _scale_rect.x + (_scale_rect.width - width) / 2 - 4,
2266 _scale_rect.y + _scale_rect.height / 2);
2267 gdk_draw_line(_map_widget->window,
2268 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2269 _scale_rect.x + _scale_rect.width - 4,
2270 _scale_rect.y + _scale_rect.height / 2 - 4,
2271 _scale_rect.x + _scale_rect.width - 4,
2272 _scale_rect.y + _scale_rect.height / 2 + 4);
2273 gdk_draw_line(_map_widget->window,
2274 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2275 _scale_rect.x + _scale_rect.width - 4,
2276 _scale_rect.y + _scale_rect.height / 2,
2277 _scale_rect.x + (_scale_rect.width + width) / 2 + 4,
2278 _scale_rect.y + _scale_rect.height / 2);
2283 /* Draw the compass rose, if necessary. */
2287 gint offsetx, offsety;
2290 offsetx = _comprose_rect.x;
2291 offsety = _comprose_rect.y;
2293 gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, 0, 12);
2294 points[0].x = offsetx + x + 0.5f; points[0].y = offsety + y + 0.5f;
2295 gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, 20, 30);
2296 points[1].x = offsetx + x + 0.5f; points[1].y = offsety + y + 0.5f;
2297 gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, 0, -45);
2298 points[2].x = offsetx + x + 0.5f; points[2].y = offsety + y + 0.5f;
2299 gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, -20, 30);
2300 points[3].x = offsetx + x + 0.5f; points[3].y = offsety + y + 0.5f;
2302 gdk_draw_polygon(_map_widget->window,
2303 _map_widget->style->bg_gc[GTK_STATE_ACTIVE],
2306 gdk_draw_polygon(_map_widget->window,
2307 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2308 FALSE, /* NOT FILLED */
2311 gdk_draw_layout(_map_widget->window,
2312 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2313 _comprose_rect.x - _comprose_rect.width / 2 + 1,
2314 _comprose_rect.y - _comprose_rect.height / 2 - 4,
2318 /* Draw a stopwatch if we're redrawing the map. */
2319 for(i = _redraw_count - 1; i >= 0; i--)
2322 _map_widget->window,
2323 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2326 _redraw_wait_bounds.x + i
2327 * HOURGLASS_SEPARATION,
2328 _redraw_wait_bounds.y,
2329 _redraw_wait_bounds.width,
2330 _redraw_wait_bounds.height,
2331 GDK_RGB_DITHER_NONE, 0, 0);
2334 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2339 latlon_cb_copy_clicked(GtkWidget *widget, LatlonDialog *lld) {
2342 snprintf(buffer, sizeof(buffer),
2344 gtk_label_get_text(GTK_LABEL(lld->lat)),
2345 gtk_label_get_text(GTK_LABEL(lld->lon)));
2347 gtk_clipboard_set_text(
2348 gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), buffer, -1);
2352 latlon_cb_fmt_changed(GtkWidget *widget, LatlonDialog *lld) {
2355 fmt = gtk_combo_box_get_active(GTK_COMBO_BOX(lld->fmt_combo));
2358 gint old = _degformat; /* augh... */
2359 gchar buffer[LL_FMT_LEN];
2362 lat_format(lld->glat, buffer);
2363 gtk_label_set_label(GTK_LABEL(lld->lat), buffer);
2364 lon_format(lld->glon, buffer);
2365 gtk_label_set_label(GTK_LABEL(lld->lon), buffer);
2371 latlon_dialog(gdouble lat, gdouble lon)
2379 GtkWidget *cmb_format;
2380 GtkWidget *btn_copy = NULL;
2381 printf("%s()\n", __PRETTY_FUNCTION__);
2383 dialog = gtk_dialog_new_with_buttons(_("Show Position"),
2384 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2385 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2388 /* Set the lat/lon strings. */
2389 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2390 table = gtk_table_new(5, 2, FALSE), TRUE, TRUE, 0);
2392 gtk_table_attach(GTK_TABLE(table),
2393 label = gtk_label_new(_("Lat")),
2394 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
2395 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2396 gtk_table_attach(GTK_TABLE(table),
2397 txt_lat = gtk_label_new(""),
2398 1, 2, 0, 1, GTK_FILL, 0, 2, 4);
2399 gtk_misc_set_alignment(GTK_MISC(txt_lat), 1.f, 0.5f);
2401 gtk_table_attach(GTK_TABLE(table),
2402 label = gtk_label_new(_("Lon")),
2403 0, 1, 1, 2, GTK_FILL, 0, 2, 4);
2404 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2405 gtk_table_attach(GTK_TABLE(table),
2406 txt_lon = gtk_label_new(""),
2407 1, 2, 1, 2, GTK_FILL, 0, 2, 4);
2408 gtk_misc_set_alignment(GTK_MISC(txt_lon), 1.f, 0.5f);
2410 gtk_table_attach(GTK_TABLE(table),
2411 label = gtk_label_new(_("Format")),
2412 0, 1, 2, 3, GTK_FILL, 0, 2, 4);
2413 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2414 gtk_table_attach(GTK_TABLE(table),
2415 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2416 1, 2, 2, 3, GTK_FILL, 0, 2, 4);
2417 gtk_container_add(GTK_CONTAINER(label),
2418 cmb_format = gtk_combo_box_new_text());
2419 gtk_table_attach(GTK_TABLE(table),
2420 btn_copy = gtk_button_new_with_label(_("Copy")),
2421 0, 2, 3, 4, GTK_FILL, 0, 2, 4);
2425 gchar buffer[LL_FMT_LEN];
2427 lat_format(lat, buffer);
2428 gtk_label_set_label(GTK_LABEL(txt_lat), buffer);
2429 lat_format(lon, buffer);
2430 gtk_label_set_label(GTK_LABEL(txt_lon), buffer);
2433 /* Fill in formats */
2437 for(i = 0; i < DEG_FORMAT_ENUM_COUNT; i++) {
2438 gtk_combo_box_append_text(GTK_COMBO_BOX(cmb_format),
2439 DEG_FORMAT_ENUM_TEXT[i]);
2441 gtk_combo_box_set_active(GTK_COMBO_BOX(cmb_format), _degformat);
2445 /* setup cb context */
2446 lld.fmt_combo = cmb_format;
2452 /* Connect Signals */
2453 g_signal_connect(G_OBJECT(cmb_format), "changed",
2454 G_CALLBACK(latlon_cb_fmt_changed), &lld);
2455 g_signal_connect(G_OBJECT(btn_copy), "clicked",
2456 G_CALLBACK(latlon_cb_copy_clicked), &lld);
2458 gtk_widget_show_all(dialog);
2460 gtk_dialog_run(GTK_DIALOG(dialog));
2461 gtk_widget_hide(dialog);
2463 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2469 * This is a multi-purpose function for allowing the user to select a file
2470 * for either reading or writing. If chooser_action is
2471 * GTK_FILE_CHOOSER_ACTION_OPEN, then bytes_out and size_out must be
2472 * non-NULL. If chooser_action is GTK_FILE_CHOOSER_ACTION_SAVE, then
2473 * handle_out must be non-NULL. Either dir or file (or both) can be NULL.
2474 * This function returns TRUE if a file was successfully opened.
2477 display_open_file(GtkWidget *parent, gchar **bytes_out,
2478 GnomeVFSHandle **handle_out, gint *size_out,
2479 gchar **dir, gchar **file, GtkFileChooserAction chooser_action)
2482 gboolean success = FALSE;
2483 printf("%s()\n", __PRETTY_FUNCTION__);
2485 dialog = hildon_file_chooser_dialog_new(parent, chooser_action);
2488 gtk_file_chooser_set_current_folder_uri(
2489 GTK_FILE_CHOOSER(dialog), *dir);
2492 gtk_file_chooser_set_uri(
2493 GTK_FILE_CHOOSER(dialog), *file);
2494 if(chooser_action == GTK_FILE_CHOOSER_ACTION_SAVE)
2496 /* Work around a bug in HildonFileChooserDialog. */
2497 gchar *basename = g_path_get_basename(*file);
2498 g_object_set(G_OBJECT(dialog), "autonaming", FALSE, NULL);
2499 gtk_file_chooser_set_current_name(
2500 GTK_FILE_CHOOSER(dialog), basename);
2505 gtk_widget_show_all(dialog);
2507 while(!success && gtk_dialog_run(GTK_DIALOG(dialog))==GTK_RESPONSE_OK)
2509 gchar *file_uri_str;
2510 GnomeVFSResult vfs_result;
2512 /* Get the selected filename. */
2513 file_uri_str = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog));
2515 if((chooser_action == GTK_FILE_CHOOSER_ACTION_OPEN
2516 && (GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
2517 file_uri_str, size_out, bytes_out))))
2518 || (chooser_action == GTK_FILE_CHOOSER_ACTION_SAVE
2519 && GNOME_VFS_OK != (vfs_result = gnome_vfs_create(
2520 handle_out, file_uri_str,
2521 GNOME_VFS_OPEN_WRITE, FALSE, 0664))))
2523 gchar buffer[BUFFER_SIZE];
2524 snprintf(buffer, sizeof(buffer),
2525 "%s:\n%s", chooser_action == GTK_FILE_CHOOSER_ACTION_OPEN
2526 ? _("Failed to open file for reading")
2527 : _("Failed to open file for writing"),
2528 gnome_vfs_result_to_string(vfs_result));
2529 popup_error(dialog, buffer);
2534 g_free(file_uri_str);
2543 *dir = gtk_file_chooser_get_current_folder_uri(
2544 GTK_FILE_CHOOSER(dialog));
2547 /* If desired, save the file for later. */
2551 *file = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog));
2555 gtk_widget_destroy(dialog);
2557 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
2564 PangoContext *pango_context;
2565 PangoFontDescription *pango_font;
2567 printf("%s()\n", __PRETTY_FUNCTION__);
2569 /* Cache some pango and GCs for drawing. */
2570 pango_context = gtk_widget_get_pango_context(_map_widget);
2571 _scale_layout = pango_layout_new(pango_context);
2572 pango_font = pango_font_description_new();
2573 pango_font_description_set_size(pango_font, 12 * PANGO_SCALE);
2574 pango_layout_set_font_description(_scale_layout, pango_font);
2577 pango_context = gtk_widget_get_pango_context(_map_widget);
2578 _zoom_layout = pango_layout_new(pango_context);
2579 pango_font = pango_font_description_new();
2580 pango_font_description_set_size(pango_font, 12 * PANGO_SCALE);
2581 pango_layout_set_font_description(_zoom_layout, pango_font);
2582 pango_layout_set_alignment(_zoom_layout, PANGO_ALIGN_CENTER);
2585 pango_context = gtk_widget_get_pango_context(_map_widget);
2586 _comprose_layout = pango_layout_new(pango_context);
2587 pango_font = pango_font_description_new();
2588 pango_font_description_set_size(pango_font, 16 * PANGO_SCALE);
2589 pango_font_description_set_weight(pango_font, PANGO_WEIGHT_BOLD);
2590 pango_layout_set_font_description(_comprose_layout, pango_font);
2591 pango_layout_set_alignment(_comprose_layout, PANGO_ALIGN_CENTER);
2592 pango_layout_set_text(_comprose_layout, "N", -1);
2594 PangoRectangle rect;
2595 pango_layout_get_pixel_extents(_comprose_layout, &rect, NULL);
2596 _comprose_rect.width = rect.width + 3;
2597 _comprose_rect.height = rect.height + 3;
2601 _speed_limit_gc1 = gdk_gc_new (_map_widget->window);
2605 gdk_gc_set_rgb_fg_color(_speed_limit_gc1, &color);
2609 _speed_limit_gc2 = gdk_gc_new(_map_widget->window);
2610 gdk_gc_set_rgb_fg_color(_speed_limit_gc2, &color);
2611 pango_context = gtk_widget_get_pango_context(_map_widget);
2612 _speed_limit_layout = pango_layout_new(pango_context);
2613 pango_font = pango_font_description_new();
2614 pango_font_description_set_size(pango_font, 64 * PANGO_SCALE);
2615 pango_layout_set_font_description(_speed_limit_layout,
2617 pango_layout_set_alignment(_speed_limit_layout, PANGO_ALIGN_CENTER);
2619 /* draw_sat_info() */
2620 _sat_info_gc1 = gdk_gc_new(_map_widget->window);
2624 gdk_gc_set_rgb_fg_color(_sat_info_gc1, &color);
2627 color.blue = 0xffff;
2628 _sat_info_gc2 = gdk_gc_new(_map_widget->window);
2629 gdk_gc_set_rgb_fg_color(_sat_info_gc2, &color);
2630 pango_context = gtk_widget_get_pango_context(_map_widget);
2631 _sat_info_layout = pango_layout_new(pango_context);
2632 pango_font = pango_font_description_new();
2633 pango_font_description_set_family(pango_font,"Sans Serif");
2634 pango_font_description_set_size(pango_font, 8*PANGO_SCALE);
2635 pango_layout_set_font_description(_sat_info_layout, pango_font);
2636 pango_layout_set_alignment(_sat_info_layout, PANGO_ALIGN_CENTER);
2638 /* sat_panel_expose() */
2639 pango_context = gtk_widget_get_pango_context(_map_widget);
2640 _sat_panel_layout = pango_layout_new(pango_context);
2641 pango_font = pango_font_description_new();
2642 pango_font_description_set_family(pango_font,"Sans Serif");
2643 pango_font_description_set_size(pango_font, 14*PANGO_SCALE);
2644 pango_layout_set_font_description (_sat_panel_layout, pango_font);
2646 /* heading_panel_expose() */
2647 pango_context = gtk_widget_get_pango_context(_map_widget);
2648 _heading_panel_layout = pango_layout_new(pango_context);
2649 _heading_panel_fontdesc = pango_font_description_new();
2650 pango_font_description_set_family(_heading_panel_fontdesc, "Sans Serif");
2652 /* draw_sat_details() */
2653 pango_context = gtk_widget_get_pango_context(_map_widget);
2654 _sat_details_layout = pango_layout_new(pango_context);
2655 pango_font = pango_font_description_new();
2656 pango_font_description_set_family(pango_font,"Sans Serif");
2657 pango_font_description_set_size(pango_font, 10*PANGO_SCALE);
2658 pango_layout_set_font_description(_sat_details_layout,
2660 pango_layout_set_alignment(_sat_details_layout, PANGO_ALIGN_CENTER);
2662 /* sat_details_panel_expose() */
2663 pango_context = gtk_widget_get_pango_context(_map_widget);
2664 _sat_details_expose_layout = pango_layout_new(pango_context);
2665 pango_font = pango_font_description_new();
2666 pango_font_description_set_family(
2667 pango_font,"Sans Serif");
2668 pango_layout_set_alignment(_sat_details_expose_layout,
2669 PANGO_ALIGN_CENTER);
2670 pango_font_description_set_size(pango_font,
2672 pango_layout_set_font_description(_sat_details_expose_layout,
2675 /* Load the _redraw_wait_icon. */
2677 GError *error = NULL;
2678 gchar *icon_path = "/usr/share/icons/hicolor/scalable/hildon"
2679 "/maemo-mapper-wait.png";
2680 _redraw_wait_bounds.x = 0;
2681 _redraw_wait_bounds.y = 0;
2682 _redraw_wait_icon = gdk_pixbuf_new_from_file(icon_path, &error);
2683 if(!_redraw_wait_icon || error)
2685 g_printerr("Error parsing pixbuf: %s\n",
2686 error ? error->message : icon_path);
2687 _redraw_wait_bounds.width = 0;
2688 _redraw_wait_bounds.height = 0;
2689 _redraw_wait_icon = NULL;
2693 _redraw_wait_bounds.width
2694 = gdk_pixbuf_get_width(_redraw_wait_icon);
2695 _redraw_wait_bounds.height
2696 = gdk_pixbuf_get_height(_redraw_wait_icon);
2700 g_signal_connect(G_OBJECT(_map_widget), "configure_event",
2701 G_CALLBACK(map_cb_configure), NULL);
2703 g_signal_connect(G_OBJECT(_map_widget), "expose_event",
2704 G_CALLBACK(map_cb_expose), NULL);
2705 g_signal_connect(G_OBJECT(_sat_panel), "expose_event",
2706 G_CALLBACK(sat_panel_expose), NULL);
2707 g_signal_connect(G_OBJECT(_heading_panel), "expose_event",
2708 G_CALLBACK(heading_panel_expose), NULL);
2710 vprintf("%s(): return\n", __PRETTY_FUNCTION__);