/* * Copyright (C) 2006, 2007 John Costigan. * * POI and GPS-Info code originally written by Cezary Jackiewicz. * * Default map data provided by http://www.openstreetmap.org/ * * This file is part of Maemo Mapper. * * Maemo Mapper is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Maemo Mapper 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Maemo Mapper. If not, see . */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #define _GNU_SOURCE #include #include #include #include "aprs.h" #include "aprs_decode.h" #include "types.h" #ifndef LEGACY # include # include # include # include # include #else # include # include # include # include # include #endif #include "types.h" #include "data.h" #include "defines.h" #include "dbus-ifc.h" #include "display.h" #include "gdk-pixbuf-rotate.h" #include "gps.h" #include "maps.h" #include "path.h" #include "poi.h" #include "settings.h" #include "util.h" #define VELVEC_SIZE_FACTOR (4) static GtkWidget *_sat_details_panel = NULL; static GtkWidget *_sdi_lat = NULL; static GtkWidget *_sdi_lon = NULL; static GtkWidget *_sdi_spd = NULL; static GtkWidget *_sdi_alt = NULL; static GtkWidget *_sdi_hea = NULL; static GtkWidget *_sdi_tim = NULL; static GtkWidget *_sdi_vie = NULL; static GtkWidget *_sdi_use = NULL; static GtkWidget *_sdi_fix = NULL; static GtkWidget *_sdi_fqu = NULL; static GtkWidget *_sdi_msp = NULL; static gint _redraw_count = 0; static gint _mark_bufx1 = -1; static gint _mark_bufx2 = -1; static gint _mark_bufy1 = -1; static gint _mark_bufy2 = -1; static gint _mark_minx = -1; static gint _mark_miny = -1; static gint _mark_width = -1; static gint _mark_height = -1; static GdkRectangle _scale_rect = { 0, 0, 0, 0}; static GdkRectangle _zoom_rect = { 0, 0, 0, 0}; static gint _dl_errors = 0; static volatile gint _pending_replaces = 0; /** Pango stuff. */ GdkRectangle _comprose_rect = { 0, 0, 0, 0}; PangoLayout *_scale_layout = NULL; PangoLayout *_zoom_layout = NULL; PangoLayout *_comprose_layout = NULL; GdkGC *_speed_limit_gc1 = NULL; GdkGC *_speed_limit_gc2 = NULL; PangoLayout *_speed_limit_layout = NULL; PangoLayout *_sat_panel_layout = NULL; PangoLayout *_heading_panel_layout = NULL; PangoFontDescription *_heading_panel_fontdesc = NULL; GdkGC *_sat_info_gc1 = NULL; GdkGC *_sat_info_gc2 = NULL; PangoLayout *_sat_info_layout = NULL; PangoLayout *_sat_details_layout = NULL; PangoLayout *_sat_details_expose_layout = NULL; #ifdef INCLUDE_APRS PangoLayout *_aprs_label_layout = NULL; #endif // INCLUDE_APRS #define SCALE_WIDTH (100) static gboolean speed_excess(void) { printf("%s()\n", __PRETTY_FUNCTION__); if(!_speed_excess) return FALSE; hildon_play_system_sound( "/usr/share/sounds/ui-information_note.wav"); vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__); return TRUE; } #ifdef INCLUDE_APRS //// START OF APRS CODE gint add_aprs_label(gchar *label, gint label_len, gint x, gint y) { gint height = 0; gint width = 0; pango_layout_set_text(_aprs_label_layout, label, label_len); pango_layout_get_pixel_size(_aprs_label_layout, &width, &height); /* Draw the layout itself. */ gdk_draw_layout( _map_pixmap, _gc[COLORABLE_APRS_STATION], x, y - (gint)((gfloat)height/2.0f), _aprs_label_layout); return width; } gboolean extract_aprs_symbol(const gchar symbol, const char primary, GdkPixbuf **pixbuf, gint *symbol_size, gint *symbol_column, gint *symbol_row) { // GdkPixbuf *pixbuf = NULL; GError *error = NULL; gchar filename[100]; const gint startSymbol = ' '; const gint symbols_per_column = 16; const gint symbols_per_row = 6; /*const gint*/ *symbol_size = 96/symbols_per_row; gint symbol_number = (gint)symbol - startSymbol; if(symbol_number<0 || symbol_number > symbols_per_row * symbols_per_column) symbol_number = 0; if(primary == '/') snprintf(filename, sizeof(filename), "/usr/share/icons/hicolor/scalable/hildon/allicons.png"); else snprintf(filename, sizeof(filename), "/usr/share/icons/hicolor/scalable/hildon/allicon2.png"); *symbol_column = (gint)(symbol_number/symbols_per_column); *symbol_row = symbol_number - ((*symbol_column)*symbols_per_column); *pixbuf = gdk_pixbuf_new_from_file(filename, &error); if(error) { return FALSE; } if( (*symbol_size)*(*symbol_column) < 0 || (*symbol_size)*(*symbol_row) < 0 ) { return FALSE; } return TRUE; } // gboolean draw_aprs_symbol(const gchar symbol, const gchar primary, const gint poix, const gint poiy, gint* imageSize) { GdkPixbuf *pixbuf = NULL; gint symbol_column = 0; gint symbol_row = 0; gint symbol_size = 0; if(!extract_aprs_symbol(symbol, primary, &pixbuf, &symbol_size, &symbol_column, &symbol_row)) return FALSE; /* We found an icon to draw. */ gdk_draw_pixbuf( _map_pixmap, _gc[COLORABLE_POI], pixbuf, symbol_size*symbol_column, symbol_size*symbol_row, poix - symbol_size / 2, poiy - symbol_size / 2, symbol_size, symbol_size, GDK_RGB_DITHER_NONE, 0, 0); g_object_unref(pixbuf); *imageSize = symbol_size; return TRUE; } void plot_aprs_station(AprsDataRow *p_station, gboolean single ) { if(_poi_zoom <= _zoom) return ; gint image_size = 0; gdouble lat1 = 0; gdouble lon1 = 0; gint poix, poiy; gint unitx, unity; // TODO - if this station has been ploted before, then redraw the map at that position /* if(p_station->newest_trackpoint != NULL) { AprsTrackRow *pPreviousPoint = p_station->newest_trackpoint; lat1 = convert_lat_l2d(pPreviousPoint->trail_lat_pos); lon1 = convert_lon_l2d(pPreviousPoint->trail_long_pos); latlon2unit(lat1, lon1, unitx, unity); unit2buf(unitx, unity, poix, poiy); fprintf(stderr, "Removing old pos.\n"); poix = poix - 40; poiy = poiy - 25; if(poix<0) poix = 0; if(poiy<0) poiy = 0; if(poix+100 > _view_width_pixels) poix = _view_width_pixels; if(poiy+50 > _view_height_pixels) poiy = _view_height_pixels; gdk_draw_pixbuf( _map_pixmap, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], _map_pixbuf, poix, poiy, poix, poiy, 100, 50, GDK_RGB_DITHER_NONE, 0, 0); // TODO - this will only redraw the background, not any POI´s or other items } */ lat1 = convert_lat_l2d(p_station->coord_lat); lon1 = convert_lon_l2d(p_station->coord_lon); latlon2unit(lat1, lon1, unitx, unity); unit2buf(unitx, unity, poix, poiy); // Ignore this station if it's position is not on the screen if(poix < 0 || poix > _view_width_pixels || poiy < 0 || poiy > _view_height_pixels) return ; gchar label[MAX_CALLSIGN+1]; snprintf(label, sizeof(label), "%s", p_station->call_sign); if(!draw_aprs_symbol(p_station->aprs_symbol.aprs_symbol, p_station->aprs_symbol.aprs_type, poix, poiy, &image_size)) { /* No icon for POI or for category or default POI icon file. Draw default purple square. */ gdk_draw_rectangle(_map_pixmap, _gc[COLORABLE_APRS_STATION], TRUE, poix - (gint)(1.5f * _draw_width), poiy - (gint)(1.5f * _draw_width), 3 * _draw_width, 3 * _draw_width); image_size = 3 * _draw_width; } gint label_width = 0; gint _aprs_label_zoom = _poi_zoom - 1; if(_aprs_label_zoom > _zoom) { label_width = add_aprs_label(label, strlen(label), poix + image_size, poiy); } if(single) { gint offset = (gint)((gfloat)image_size/2.0f); gtk_widget_queue_draw_area( _map_widget, poix - offset, poiy - offset, (2*image_size) + label_width, image_size ); } } #endif // INCLUDE_APRS //// END OF APRS CODE static void speed_limit(void) { GdkGC *gc; gfloat cur_speed; gchar *buffer; static gint x = 0, y = 0, width = 0, height = 0; printf("%s()\n", __PRETTY_FUNCTION__); cur_speed = _gps.speed * UNITS_CONVERT[_units]; if(cur_speed > _speed_limit) { gc = _speed_limit_gc1; if(!_speed_excess) { _speed_excess = TRUE; g_timeout_add_full(G_PRIORITY_HIGH_IDLE, 5000, (GSourceFunc)speed_excess, NULL, NULL); } } else { gc = _speed_limit_gc2; _speed_excess = FALSE; } /* remove previous number */ if (width != 0 && height != 0) { gtk_widget_queue_draw_area (_map_widget, x - 5, y - 5, width + 10, height + 10); gdk_window_process_all_updates(); } buffer = g_strdup_printf("%0.0f", cur_speed); pango_layout_set_text(_speed_limit_layout, buffer, -1); pango_layout_get_pixel_size(_speed_limit_layout, &width, &height); switch (_speed_location) { case SPEED_LOCATION_TOP_RIGHT: x = _map_widget->allocation.width - 10 - width; y = 5; break; case SPEED_LOCATION_BOTTOM_RIGHT: x = _map_widget->allocation.width - 10 - width; y = _map_widget->allocation.height - 10 - height; break; case SPEED_LOCATION_BOTTOM_LEFT: x = 10; y = _map_widget->allocation.height - 10 - height; break; default: x = 10; y = 10; break; } gdk_draw_layout(_map_widget->window, gc, x, y, _speed_limit_layout); g_free(buffer); vprintf("%s(): return\n", __PRETTY_FUNCTION__); } gboolean gps_display_details(void) { gchar *buffer, litbuf[LL_FMT_LEN], buffer2[LL_FMT_LEN]; printf("%s()\n", __PRETTY_FUNCTION__); if(_gps.fix < 2) { /* no fix no fun */ gtk_label_set_label(GTK_LABEL(_sdi_lat), " --- "); gtk_label_set_label(GTK_LABEL(_sdi_lon), " --- "); gtk_label_set_label(GTK_LABEL(_sdi_spd), " --- "); gtk_label_set_label(GTK_LABEL(_sdi_alt), " --- "); gtk_label_set_label(GTK_LABEL(_sdi_hea), " --- "); gtk_label_set_label(GTK_LABEL(_sdi_tim), " --:--:-- "); } else { gfloat speed = _gps.speed * UNITS_CONVERT[_units]; format_lat_lon(_gps.lat, _gps.lon, litbuf, buffer2); /* latitude */ //lat_format(_gps.lat, litbuf); gtk_label_set_label(GTK_LABEL(_sdi_lat), litbuf); /* longitude */ //lon_format(_gps.lon, litbuf); //gtk_label_set_label(GTK_LABEL(_sdi_lon), litbuf); if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use) gtk_label_set_label(GTK_LABEL(_sdi_lon), buffer2); /* speed */ switch(_units) { case UNITS_MI: buffer = g_strdup_printf("%.1f mph", speed); break; case UNITS_NM: buffer = g_strdup_printf("%.1f kn", speed); break; default: buffer = g_strdup_printf("%.1f km/h", speed); break; } gtk_label_set_label(GTK_LABEL(_sdi_spd), buffer); g_free(buffer); /* altitude */ switch(_units) { case UNITS_MI: case UNITS_NM: buffer = g_strdup_printf("%d ft", (gint)(_pos.altitude * 3.2808399f)); break; default: buffer = g_strdup_printf("%d m", _pos.altitude); break; } gtk_label_set_label(GTK_LABEL(_sdi_alt), buffer); g_free(buffer); /* heading */ buffer = g_strdup_printf("%0.0f°", _gps.heading); gtk_label_set_label(GTK_LABEL(_sdi_hea), buffer); g_free(buffer); /* local time */ strftime(litbuf, 15, "%X", localtime(&_pos.time)); gtk_label_set_label(GTK_LABEL(_sdi_tim), litbuf); } /* Sat in view */ buffer = g_strdup_printf("%d", _gps.satinview); gtk_label_set_label(GTK_LABEL(_sdi_vie), buffer); g_free(buffer); /* Sat in use */ buffer = g_strdup_printf("%d", _gps.satinuse); gtk_label_set_label(GTK_LABEL(_sdi_use), buffer); g_free(buffer); /* fix */ switch(_gps.fix) { case 2: case 3: buffer = g_strdup_printf("%dD fix", _gps.fix); break; default: buffer = g_strdup_printf("nofix"); break; } gtk_label_set_label(GTK_LABEL(_sdi_fix), buffer); g_free(buffer); if(_gps.fix == 1) buffer = g_strdup("none"); else { switch (_gps.fixquality) { case 1 : buffer = g_strdup_printf(_("SPS")); break; case 2 : buffer = g_strdup_printf(_("DGPS")); break; case 3 : buffer = g_strdup_printf(_("PPS")); break; case 4 : buffer = g_strdup_printf(_("Real Time Kinematic")); break; case 5 : buffer = g_strdup_printf(_("Float RTK")); break; case 6 : buffer = g_strdup_printf(_("Estimated")); break; case 7 : buffer = g_strdup_printf(_("Manual")); break; case 8 : buffer = g_strdup_printf(_("Simulation")); break; default : buffer = g_strdup_printf(_("none")); break; } } gtk_label_set_label(GTK_LABEL(_sdi_fqu), buffer); g_free(buffer); /* max speed */ { gfloat maxspeed = _gps.maxspeed * UNITS_CONVERT[_units]; /* speed */ switch(_units) { case UNITS_MI: buffer = g_strdup_printf("%.1f mph", maxspeed); break; case UNITS_NM: buffer = g_strdup_printf("%.1f kn", maxspeed); break; default: buffer = g_strdup_printf("%.1f km/h", maxspeed); break; } gtk_label_set_label(GTK_LABEL(_sdi_msp), buffer); g_free(buffer); } /* refresh sat panel */ gtk_widget_queue_draw_area(GTK_WIDGET(_sat_details_panel), 0, 0, _sat_details_panel->allocation.width, _sat_details_panel->allocation.height); vprintf("%s(): return\n", __PRETTY_FUNCTION__); return TRUE; } void gps_display_data(void) { gchar *buffer, litbuf[LL_FMT_LEN], buffer2[LL_FMT_LEN]; printf("%s()\n", __PRETTY_FUNCTION__); if(_gps.fix < 2) { /* no fix no fun */ gtk_label_set_label(GTK_LABEL(_text_lat), " --- "); gtk_label_set_label(GTK_LABEL(_text_lon), " --- "); gtk_label_set_label(GTK_LABEL(_text_speed), " --- "); gtk_label_set_label(GTK_LABEL(_text_alt), " --- "); gtk_label_set_label(GTK_LABEL(_text_time), " --:--:-- "); } else { gfloat speed = _gps.speed * UNITS_CONVERT[_units]; format_lat_lon(_gps.lat, _gps.lon, litbuf, buffer2); /* latitude */ //lat_format(_gps.lat, litbuf); gtk_label_set_label(GTK_LABEL(_text_lat), litbuf); /* longitude */ //lon_format(_gps.lon, litbuf); if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use) gtk_label_set_label(GTK_LABEL(_text_lon), buffer2); /* speed */ switch(_units) { case UNITS_MI: buffer = g_strdup_printf("Spd: %.1f mph", speed); break; case UNITS_NM: buffer = g_strdup_printf("Spd: %.1f kn", speed); break; default: buffer = g_strdup_printf("Spd: %.1f km/h", speed); break; } gtk_label_set_label(GTK_LABEL(_text_speed), buffer); g_free(buffer); /* altitude */ switch(_units) { case UNITS_MI: case UNITS_NM: buffer = g_strdup_printf("Alt: %d ft", (gint)(_pos.altitude * 3.2808399f)); break; default: buffer = g_strdup_printf("Alt: %d m", _pos.altitude); } gtk_label_set_label(GTK_LABEL(_text_alt), buffer); g_free(buffer); /* local time */ strftime(litbuf, 15, "%X", localtime(&_pos.time)); gtk_label_set_label(GTK_LABEL(_text_time), litbuf); } /* refresh sat panel */ gtk_widget_queue_draw_area(GTK_WIDGET(_sat_panel), 0, 0, _sat_panel->allocation.width, _sat_panel->allocation.height); /* refresh heading panel*/ gtk_widget_queue_draw_area(GTK_WIDGET(_heading_panel), 0, 0, _heading_panel->allocation.width, _heading_panel->allocation.height); vprintf("%s(): return\n", __PRETTY_FUNCTION__); return; } void gps_hide_text(void) { printf("%s()\n", __PRETTY_FUNCTION__); /* Clear gps data */ _gps.fix = 1; _gps.satinuse = 0; _gps.satinview = 0; if(_gps_info) gps_display_data(); vprintf("%s(): return\n", __PRETTY_FUNCTION__); } void gps_show_info(void) { printf("%s()\n", __PRETTY_FUNCTION__); if(_gps_info && _enable_gps) gtk_widget_show_all(GTK_WIDGET(_gps_widget)); else { gps_hide_text(); gtk_widget_hide(GTK_WIDGET(_gps_widget)); } vprintf("%s(): return\n", __PRETTY_FUNCTION__); } static void draw_sat_info(GtkWidget *widget, gint x0, gint y0, gint width, gint height, gboolean showsnr) { GdkGC *gc; gint step, i, j, snr_height, bymargin, xoffset, yoffset; gint x, y, x1, y1; gchar *tmp = NULL; printf("%s()\n", __PRETTY_FUNCTION__); xoffset = x0; yoffset = y0; /* Bootom margin - 12% */ bymargin = height * 0.88f; /* Bottom line */ gdk_draw_line(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], xoffset + 5, yoffset + bymargin, xoffset + width - 10 - 2, yoffset + bymargin); gdk_draw_line(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], xoffset + 5, yoffset + bymargin - 1, xoffset + width - 10 - 2, yoffset + bymargin - 1); if(_gps.satinview > 0 ) { /* Left margin - 5pix, Right margin - 5pix */ step = (width - 10) / _gps.satinview; for(i = 0; i < _gps.satinview; i++) { /* Sat used or not */ gc = _sat_info_gc1; for(j = 0; j < _gps.satinuse ; j++) { if(_gps.satforfix[j] == _gps_sat[i].prn) { gc = _sat_info_gc2; break; } } x = 5 + i * step; snr_height = _gps_sat[i].snr * height * 0.78f / 100; y = height * 0.1f + (height * 0.78f - snr_height); /* draw sat rectangle... */ gdk_draw_rectangle(widget->window, gc, TRUE, xoffset + x, yoffset + y, step - 2, snr_height); if(showsnr && _gps_sat[i].snr > 0) { /* ...snr.. */ tmp = g_strdup_printf("%02d", _gps_sat[i].snr); pango_layout_set_text(_sat_info_layout, tmp, 2); pango_layout_get_pixel_size(_sat_info_layout, &x1, &y1); gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], xoffset + x + ((step - 2) - x1)/2, yoffset + y - 15, _sat_info_layout); g_free(tmp); } /* ...and sat number */ tmp = g_strdup_printf("%02d", _gps_sat[i].prn); pango_layout_set_text(_sat_info_layout, tmp, 2); pango_layout_get_pixel_size(_sat_info_layout, &x1, &y1); gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], xoffset + x + ((step - 2) - x1)/2 , yoffset + bymargin + 1, _sat_info_layout); g_free(tmp); } } vprintf("%s(): return\n", __PRETTY_FUNCTION__); return; } static void draw_sat_details(GtkWidget *widget, gint x0, gint y0, gint width, gint height) { gint i, j, x, y, size, halfsize, xoffset, yoffset; gint x1, y1; gfloat tmp; GdkColor color; GdkGC *gc1, *gc2, *gc3, *gc; gchar *buffer = NULL; printf("%s()\n", __PRETTY_FUNCTION__); size = MIN(width, height); halfsize = size/2; if(width > height) { xoffset = x0 + (width - height - 10) / 2; yoffset = y0 + 5; } else { xoffset = x0 + 5; yoffset = y0 + (height - width - 10) / 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); gint line[12] = {0,30,60,90,120,150,180,210,240,270,300,330}; for(i = 0; i < 6; i++) { /* line */ tmp = deg2rad(line[i]); 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 = deg2rad(line[i]); /* azimuth */ if(line[i] == 0) buffer = g_strdup_printf("N"); else buffer = g_strdup_printf("%d°", line[i]); pango_layout_set_text(_sat_details_layout, buffer, -1); pango_layout_get_pixel_size(_sat_details_layout, &x, &y); gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], (xoffset + halfsize + (halfsize - size/12) * sinf(tmp)) - x/2, (yoffset + halfsize - (halfsize - size/12) * cosf(tmp)) - y/2, _sat_details_layout); g_free(buffer); } /* elevation 30 */ tmp = deg2rad(30); buffer = g_strdup_printf("30°"); pango_layout_set_text(_sat_details_layout, buffer, -1); pango_layout_get_pixel_size(_sat_details_layout, &x, &y); gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], (xoffset + halfsize + size/6*2 * sinf(tmp)) - x/2, (yoffset + halfsize - size/6*2 * cosf(tmp)) - y/2, _sat_details_layout); g_free(buffer); /* elevation 60 */ tmp = deg2rad(30); buffer = g_strdup_printf("60°"); pango_layout_set_text(_sat_details_layout, buffer, -1); pango_layout_get_pixel_size(_sat_details_layout, &x, &y); gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], (xoffset + halfsize + size/6 * sinf(tmp)) - x/2, (yoffset + halfsize - size/6 * cosf(tmp)) - y/2, _sat_details_layout); g_free(buffer); color.red = 0; color.green = 0; color.blue = 0; gc1 = gdk_gc_new (widget->window); gdk_gc_set_rgb_fg_color (gc1, &color); color.red = 0; color.green = 0; color.blue = 0xffff; gc2 = gdk_gc_new (widget->window); gdk_gc_set_rgb_fg_color (gc2, &color); color.red = 0xffff; color.green = 0xffff; color.blue = 0xffff; gc3 = gdk_gc_new (widget->window); gdk_gc_set_rgb_fg_color (gc3, &color); for(i = 0; i < _gps.satinview; i++) { /* Sat used or not */ gc = gc1; for(j = 0; j < _gps.satinuse ; j++) { if(_gps.satforfix[j] == _gps_sat[i].prn) { gc = gc2; break; } } tmp = deg2rad(_gps_sat[i].azimuth); x = xoffset + halfsize + (90 - _gps_sat[i].elevation)*halfsize/90 * sinf(tmp); y = yoffset + halfsize - (90 - _gps_sat[i].elevation)*halfsize/90 * cosf(tmp); gdk_draw_arc (widget->window, gc, TRUE, x - 10, y - 10, 20, 20, 0, 64 * 360); buffer = g_strdup_printf("%02d", _gps_sat[i].prn); pango_layout_set_text(_sat_details_layout, buffer, -1); pango_layout_get_pixel_size(_sat_details_layout, &x1, &y1); gdk_draw_layout(widget->window, gc3, x - x1/2, y - y1/2, _sat_details_layout); g_free(buffer); } g_object_unref (gc1); g_object_unref (gc2); g_object_unref (gc3); vprintf("%s(): return\n", __PRETTY_FUNCTION__); return; } static gboolean sat_details_panel_expose(GtkWidget *widget, GdkEventExpose *event) { gint width, height, x, y; gchar *buffer = NULL; printf("%s()\n", __PRETTY_FUNCTION__); width = widget->allocation.width; height = widget->allocation.height * 0.9; draw_sat_info(widget, 0, 0, width/2, height, TRUE); draw_sat_details(widget, width/2, 0, width/2, height); buffer = g_strdup_printf( "%s: %d; %s: %d", _("Satellites in view"), _gps.satinview, _("in use"), _gps.satinuse); pango_layout_set_text(_sat_details_expose_layout, buffer, -1); pango_layout_get_pixel_size(_sat_details_expose_layout, &x, &y); gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], 10, height*0.9 + 10, _sat_details_expose_layout); g_free(buffer); buffer = g_strdup_printf("HDOP: %.01f", _gps.hdop); pango_layout_set_text(_sat_details_expose_layout, buffer, -1); pango_layout_get_pixel_size(_sat_details_expose_layout, &x, &y); gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], (width/8) - x/2, (height/6) - y/2, _sat_details_expose_layout); g_free(buffer); buffer = g_strdup_printf("PDOP: %.01f", _gps.pdop); pango_layout_set_text(_sat_details_expose_layout, buffer, -1); pango_layout_get_pixel_size(_sat_details_expose_layout, &x, &y); gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], (width/8) - x/2, (height/6) - y/2 + 20, _sat_details_expose_layout); g_free(buffer); buffer = g_strdup_printf("VDOP: %.01f", _gps.vdop); pango_layout_set_text(_sat_details_expose_layout, buffer, -1); pango_layout_get_pixel_size(_sat_details_expose_layout, &x, &y); gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], (width/8) - x/2, (height/6) - y/2 + 40, _sat_details_expose_layout); g_free(buffer); vprintf("%s(): return\n", __PRETTY_FUNCTION__); return TRUE; } void gps_details(void) { static GtkWidget *dialog = NULL; static GtkWidget *table = NULL; static GtkWidget *label = NULL; static GtkWidget *notebook = NULL; printf("%s()\n", __PRETTY_FUNCTION__); if(dialog == NULL) { dialog = gtk_dialog_new_with_buttons(_("GPS Details"), GTK_WINDOW(_window), GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); gtk_window_set_default_size(GTK_WINDOW(dialog), 600, 300); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), notebook = gtk_notebook_new(), TRUE, TRUE, 0); /* textual info */ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), table = gtk_table_new(4, 6, FALSE), label = gtk_label_new(_("GPS Information"))); _sat_details_panel = gtk_drawing_area_new (); gtk_widget_set_size_request (_sat_details_panel, 300, 300); /* sat details info */ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), _sat_details_panel, label = gtk_label_new(_("Satellites details"))); g_signal_connect (G_OBJECT (_sat_details_panel), "expose_event", G_CALLBACK (sat_details_panel_expose), NULL); gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Latitude")), 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, 0, 20, 4); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), _sdi_lat = gtk_label_new(" --- "), 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(_sdi_lat), 0.f, 0.5f); gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Longitude")), 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, 0, 20, 4); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), _sdi_lon = gtk_label_new(" --- "), 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(_sdi_lon), 0.f, 0.5f); gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Speed")), 0, 1, 2, 3, GTK_EXPAND | GTK_FILL, 0, 20, 4); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), _sdi_spd = gtk_label_new(" --- "), 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(_sdi_spd), 0.f, 0.5f); gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Altitude")), 0, 1, 3, 4, GTK_EXPAND | GTK_FILL, 0, 20, 4); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), _sdi_alt = gtk_label_new(" --- "), 1, 2, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(_sdi_alt), 0.f, 0.5f); gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Heading")), 0, 1, 4, 5, GTK_EXPAND | GTK_FILL, 0, 20, 4); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), _sdi_hea = gtk_label_new(" --- "), 1, 2, 4, 5, GTK_EXPAND | GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(_sdi_hea), 0.f, 0.5f); gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Local time")), 0, 1, 5, 6, GTK_EXPAND | GTK_FILL, 0, 20, 4); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), _sdi_tim = gtk_label_new(" --:--:-- "), 1, 2, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(_sdi_tim), 0.f, 0.5f); gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Sat in view")), 2, 3, 0, 1, GTK_EXPAND | GTK_FILL, 0, 20, 4); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), _sdi_vie = gtk_label_new("0"), 3, 4, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(_sdi_vie), 0.f, 0.5f); gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Sat in use")), 2, 3, 1, 2, GTK_EXPAND | GTK_FILL, 0, 20, 4); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), _sdi_use = gtk_label_new("0"), 3, 4, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(_sdi_use), 0.f, 0.5f); gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Fix")), 2, 3, 2, 3, GTK_EXPAND | GTK_FILL, 0, 20, 4); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), _sdi_fix = gtk_label_new(_("nofix")), 3, 4, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(_sdi_fix), 0.f, 0.5f); gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Fix Quality")), 2, 3, 3, 4, GTK_EXPAND | GTK_FILL, 0, 20, 4); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), _sdi_fqu = gtk_label_new(_("none")), 3, 4, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(_sdi_fqu), 0.f, 0.5f); gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Max speed")), 2, 3, 5, 6, GTK_EXPAND | GTK_FILL, 0, 20, 4); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), _sdi_msp = gtk_label_new(" --- "), 3, 4, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(_sdi_msp), 0.f, 0.5f); } gtk_widget_show_all(dialog); _satdetails_on = TRUE; gps_display_details(); while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) { _satdetails_on = FALSE; break; } gtk_widget_hide(dialog); vprintf("%s(): return\n", __PRETTY_FUNCTION__); } /** * Render a single track line to _map_pixmap. If either point on the line * is a break (defined as unity == 0), a circle is drawn at the other point. * IT IS AN ERROR FOR BOTH POINTS TO INDICATE A BREAK. */ void map_render_segment(GdkGC *gc_norm, GdkGC *gc_alt, gint unitx1, gint unity1, gint unitx2, gint unity2) { /* vprintf("%s(%d, %d, %d, %d)\n", __PRETTY_FUNCTION__, unitx1, unity1, unitx2, unity2); */ if(!unity1) { gint x2, y2; unit2buf(unitx2, unity2, x2, y2); if(((unsigned)(x2+_draw_width) <= _view_width_pixels+2*_draw_width) &&((unsigned)(y2+_draw_width) <= _view_height_pixels+2*_draw_width)) { gdk_draw_arc(_map_pixmap, gc_alt, FALSE, /* FALSE: not filled. */ x2 - _draw_width, y2 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, /* start at 0 degrees. */ 360 * 64); } } else if(!unity2) { gint x1, y1; unit2buf(unitx1, unity1, x1, y1); if(((unsigned)(x1+_draw_width) <= _view_width_pixels+2*_draw_width) &&((unsigned)(y1+_draw_width) <= _view_height_pixels+2*_draw_width)) { gdk_draw_arc(_map_pixmap, gc_alt, FALSE, /* FALSE: not filled. */ x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, /* start at 0 degrees. */ 360 * 64); } } else { gint x1, y1, x2, y2; unit2buf(unitx1, unity1, x1, y1); unit2buf(unitx2, unity2, x2, y2); /* Make sure this line could possibly be visible. */ if(!((x1 > _view_width_pixels && x2 > _view_width_pixels) || (x1 < 0 && x2 < 0) || (y1 > _view_height_pixels && y2 > _view_height_pixels) || (y1 < 0 && y2 < 0))) gdk_draw_line(_map_pixmap, gc_norm, x1, y1, x2, y2); } /* vprintf("%s(): return\n", __PRETTY_FUNCTION__); */ } /** * Render all track data onto the _map_pixmap. Note that this does not * clear the pixmap of previous track data (use map_force_redraw() for * that), and also note that this method does not queue any redraws, so it * is up to the caller to decide which part of the track really needs to be * redrawn. */ static void map_render_path(Path *path, GdkGC **gc) { Point *curr; WayPoint *wcurr; printf("%s()\n", __PRETTY_FUNCTION__); /* gc is a pointer to the first GC to use (for plain points). (gc + 1) * is a pointer to the GC to use for waypoints, and (gc + 2) is a pointer * to the GC to use for breaks. */ /* else there is a route to draw. */ for(curr = path->head, wcurr = path->whead; curr++ != path->tail; ) { /* Draw the line from (curr - 1) to (curr). */ map_render_segment(gc[0], gc[2], curr[-1].unitx, curr[-1].unity, curr->unitx, curr->unity); /* Now, check if curr is a waypoint. */ if(wcurr <= path->wtail && wcurr->point == curr) { gint x1, y1; unit2buf(wcurr->point->unitx, wcurr->point->unity, x1, y1); gdk_draw_arc(_map_pixmap, gc[1], FALSE, /* FALSE: not filled. */ x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, /* start at 0 degrees. */ 360 * 64); wcurr++; } } vprintf("%s(): return\n", __PRETTY_FUNCTION__); } void map_render_paths() { printf("%s()\n", __PRETTY_FUNCTION__); if((_show_paths & ROUTES_MASK) && _route.head != _route.tail) { WayPoint *next_way; map_render_path(&_route, _gc + COLORABLE_ROUTE); next_way = path_get_next_way(); /* Now, draw the next waypoint on top of all other waypoints. */ if(next_way) { gint x1, y1; unit2buf(next_way->point->unitx, next_way->point->unity, x1, y1); /* Draw the next waypoint as a break. */ gdk_draw_arc(_map_pixmap, _gc[COLORABLE_ROUTE_BREAK], FALSE, /* FALSE: not filled. */ x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, /* start at 0 degrees. */ 360 * 64); } } if(_show_paths & TRACKS_MASK) map_render_path(&_track, _gc + COLORABLE_TRACK); vprintf("%s(): return\n", __PRETTY_FUNCTION__); } /** * Update all GdkGC objects to reflect the current _draw_width. */ #define UPDATE_GC(gc) \ gdk_gc_set_line_attributes(gc, \ _draw_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND); void update_gcs() { gint i; printf("%s()\n", __PRETTY_FUNCTION__); for(i = 0; i < COLORABLE_ENUM_COUNT; i++) { gdk_color_alloc(gtk_widget_get_colormap(_map_widget), &_color[i]); if(_gc[i]) g_object_unref(_gc[i]); _gc[i] = gdk_gc_new(_map_pixmap); gdk_gc_set_foreground(_gc[i], &_color[i]); gdk_gc_set_line_attributes(_gc[i], _draw_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND); } /* Update the _map_widget's gc's. */ gdk_gc_set_line_attributes( _map_widget->style->fg_gc[GTK_STATE_ACTIVE], 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER); gdk_gc_set_line_attributes( _map_widget->style->bg_gc[GTK_STATE_ACTIVE], 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER); vprintf("%s(): return\n", __PRETTY_FUNCTION__); } /** * Call gtk_window_present() on Maemo Mapper. This also checks the * configuration and brings up the Settings dialog if the GPS Receiver is * not set up, the first time it is called. */ gboolean window_present() { static gint been_here = 0; static gint done_here = 0; printf("%s()\n", __PRETTY_FUNCTION__); if(!been_here++) { /* Set connection state first, to avoid going into this if twice. */ if(_is_first_time) { GtkWidget *confirm; gtk_window_present(GTK_WINDOW(_window)); confirm = hildon_note_new_confirmation(GTK_WINDOW(_window), _("It looks like this is your first time running" " Maemo Mapper. Press OK to view the the help pages." " Otherwise, press Cancel to continue.")); if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm))) { #ifndef LEGACY hildon_help_show(_osso, HELP_ID_INTRO, 0); #else ossohelp_show(_osso, HELP_ID_INTRO, 0); #endif } gtk_widget_destroy(confirm); /* Present the settings dialog. */ settings_dialog(); popup_error(_window, _("OpenStreetMap.org provides public, free-to-use maps. " "You can also download a sample set of repositories from " " the internet by using the \"Download...\" button.")); /* Present the repository dialog. */ repoman_dialog(); confirm = hildon_note_new_confirmation(GTK_WINDOW(_window), _("You will now see a blank screen. You can download" " maps using the \"Manage Maps\" menu item in the" " \"Maps\" menu. Or, press OK now to enable" " Auto-Download.")); if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm))) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM( _menu_maps_auto_download_item), TRUE); } gtk_widget_destroy(confirm); } /* Connect to receiver. */ if(_enable_gps) rcvr_connect(); ++done_here; /* Don't ask... */ } if(done_here) { gtk_window_present(GTK_WINDOW(_window)); g_timeout_add_full(G_PRIORITY_HIGH_IDLE, 250, (GSourceFunc)banner_reset, NULL, NULL); } vprintf("%s(): return\n", __PRETTY_FUNCTION__); return FALSE; } /** * "Set" the mark, which translates the current GPS position into on-screen * units in preparation for drawing the mark with map_draw_mark(). */ static void map_set_mark() { gfloat sqrt_speed, tmp, vel_offset_devx, vel_offset_devy; printf("%s()\n", __PRETTY_FUNCTION__); tmp = deg2rad(_gps.heading); sqrt_speed = VELVEC_SIZE_FACTOR * sqrtf(10 + _gps.speed); gdk_pixbuf_rotate_vector(&vel_offset_devx, &vel_offset_devy, _map_rotate_matrix, sqrt_speed * sinf(tmp), -sqrt_speed * cosf(tmp)); unit2buf(_pos.unitx, _pos.unity, _mark_bufx1, _mark_bufy1); _mark_bufx2 = _mark_bufx1 + (_show_velvec ? (vel_offset_devx + 0.5f) : 0); _mark_bufy2 = _mark_bufy1 + (_show_velvec ? (vel_offset_devy + 0.5f) : 0); _mark_minx = MIN(_mark_bufx1, _mark_bufx2) - (2 * _draw_width); _mark_miny = MIN(_mark_bufy1, _mark_bufy2) - (2 * _draw_width); _mark_width = abs(_mark_bufx1 - _mark_bufx2) + (4 * _draw_width); _mark_height = abs(_mark_bufy1 - _mark_bufy2) + (4 * _draw_width); vprintf("%s(): return\n", __PRETTY_FUNCTION__); } /** * Force a redraw of the entire _map_pixmap, including fetching the * background maps from disk and redrawing the tracks on top of them. */ void map_force_redraw() { printf("%s()\n", __PRETTY_FUNCTION__); gdk_draw_pixbuf( _map_pixmap, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], _map_pixbuf, 0, 0, 0, 0, _view_width_pixels, _view_height_pixels, GDK_RGB_DITHER_NONE, 0, 0); MACRO_MAP_RENDER_DATA(); MACRO_QUEUE_DRAW_AREA(); vprintf("%s(): return\n", __PRETTY_FUNCTION__); } Point map_calc_new_center(gint zoom) { Point new_center; printf("%s()\n", __PRETTY_FUNCTION__); switch(_center_mode) { case CENTER_LEAD: { gfloat tmp = deg2rad(_gps.heading); gfloat screen_pixels = _view_width_pixels + (((gint)_view_height_pixels - (gint)_view_width_pixels) * fabsf(cosf(deg2rad( ROTATE_DIR_ENUM_DEGREES[_rotate_dir] - (_center_rotate ? 0 : (_next_map_rotate_angle - (gint)(_gps.heading))))))); gfloat lead_pixels = 0.0025f * pixel2zunit((gint)screen_pixels, zoom) * _lead_ratio * VELVEC_SIZE_FACTOR * (_lead_is_fixed ? 7 : sqrtf(_gps.speed)); new_center.unitx = _pos.unitx + (gint)(lead_pixels * sinf(tmp)); new_center.unity = _pos.unity - (gint)(lead_pixels * cosf(tmp)); break; } case CENTER_LATLON: new_center.unitx = _pos.unitx; new_center.unity = _pos.unity; break; default: new_center.unitx = _next_center.unitx; new_center.unity = _next_center.unity; } vprintf("%s(): return (%d, %d)\n", __PRETTY_FUNCTION__, new_center.unitx, new_center.unity); return new_center; } /** * Center the view on the given unitx/unity. */ void map_center_unit_full(Point new_center, gint zoom, gint rotate_angle) { MapRenderTask *mrt; printf("%s(%d, %d)\n", __PRETTY_FUNCTION__, new_center.unitx, new_center.unity); if(!_mouse_is_down) { /* Assure that _center.unitx/y are bounded. */ BOUND(new_center.unitx, 0, WORLD_SIZE_UNITS); BOUND(new_center.unity, 0, WORLD_SIZE_UNITS); mrt = g_slice_new(MapRenderTask); mrt->repo = _curr_repo; mrt->old_offsetx = _map_offset_devx; mrt->old_offsety = _map_offset_devy; mrt->new_center = _next_center = new_center; mrt->screen_width_pixels = _view_width_pixels; mrt->screen_height_pixels = _view_height_pixels; mrt->zoom = _next_zoom = zoom; mrt->rotate_angle = _next_map_rotate_angle = rotate_angle; gtk_widget_queue_draw_area( _map_widget, _redraw_wait_bounds.x, _redraw_wait_bounds.y, _redraw_wait_bounds.width + (_redraw_count * HOURGLASS_SEPARATION), _redraw_wait_bounds.height); ++_redraw_count; g_thread_pool_push(_mrt_thread_pool, mrt, NULL); } vprintf("%s(): return\n", __PRETTY_FUNCTION__); } void map_center_unit(Point new_center) { map_center_unit_full(new_center, _next_zoom, _center_mode > 0 && _center_rotate ? _gps.heading : _next_map_rotate_angle); } void map_rotate(gint rotate_angle) { if(_center_mode > 0 && gtk_check_menu_item_get_active( GTK_CHECK_MENU_ITEM(_menu_view_rotate_auto_item))) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM( _menu_view_rotate_auto_item), FALSE); map_center_unit_full(map_calc_new_center(_next_zoom), _next_zoom, (_next_map_rotate_angle + rotate_angle) % 360); } void map_center_zoom(gint zoom) { map_center_unit_full(map_calc_new_center(zoom), zoom, _center_mode > 0 && _center_rotate ? _gps.heading : _next_map_rotate_angle); } /** * Pan the view by the given number of units in the X and Y directions. */ void map_pan(gint delta_unitx, gint delta_unity) { Point new_center; printf("%s(%d, %d)\n", __PRETTY_FUNCTION__, delta_unitx, delta_unity); if(_center_mode > 0) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM( _menu_view_ac_none_item), TRUE); new_center.unitx = _center.unitx + delta_unitx; new_center.unity = _center.unity + delta_unity; map_center_unit_full(new_center, _next_zoom, _center_mode > 0 && _center_rotate ? _gps.heading : _next_map_rotate_angle); vprintf("%s(): return\n", __PRETTY_FUNCTION__); } /** * Initiate a move of the mark from the old location to the current * location. This function queues the draw area of the old mark (to force * drawing of the background map), then updates the mark, then queus the * draw area of the new mark. */ void map_move_mark() { printf("%s()\n", __PRETTY_FUNCTION__); /* Just queue the old and new draw areas. */ gtk_widget_queue_draw_area(_map_widget, _mark_minx + _map_offset_devx, _mark_miny + _map_offset_devy, _mark_width, _mark_height); map_set_mark(); gtk_widget_queue_draw_area(_map_widget, _mark_minx + _map_offset_devx, _mark_miny + _map_offset_devy, _mark_width, _mark_height); vprintf("%s(): return\n", __PRETTY_FUNCTION__); } /** * Make sure the mark is up-to-date. This function triggers a panning of * the view if the mark is appropriately close to the edge of the view. */ void map_refresh_mark(gboolean force_redraw) { printf("%s()\n", __PRETTY_FUNCTION__); gint new_center_devx, new_center_devy; Point new_center = map_calc_new_center(_next_zoom); unit2buf(new_center.unitx, new_center.unity, new_center_devx, new_center_devy); if(force_redraw || (_center_mode > 0 && (UNITS_CONVERT[_units] * _gps.speed) >= _ac_min_speed && (((unsigned)(new_center_devx - (_view_width_pixels * _center_ratio / 20)) > ((10 - _center_ratio) * _view_width_pixels / 10)) || ((unsigned)(new_center_devy - (_view_height_pixels * _center_ratio / 20)) > ((10 - _center_ratio) * _view_height_pixels / 10)) || (_center_rotate && abs(_next_map_rotate_angle - _gps.heading) > (4*(10-_rotate_sens)))))) { map_move_mark(); map_center_unit(new_center); } else { /* We're not changing the view - just move the mark. */ map_move_mark(); } /* Draw speed info */ if(_speed_limit_on) speed_limit(); vprintf("%s(): return\n", __PRETTY_FUNCTION__); } gboolean map_download_refresh_idle(MapUpdateTask *mut) { vprintf("%s(%p, %d, %d, %d)\n", __PRETTY_FUNCTION__, mut, mut->zoom, mut->tilex, mut->tiley); /* Test if download succeeded (only if retries != 0). */ if(mut->pixbuf) { gint zoff = mut->zoom - _zoom; /* Update the UI to reflect the updated map database. */ /* Only refresh at same or "lower" (more detailed) zoom level. */ if(mut->update_type == MAP_UPDATE_AUTO && (unsigned)zoff <= 4) { gfloat destx, desty; gint boundx, boundy, width, height; pixel2buf( tile2pixel(mut->tilex << zoff) + ((TILE_SIZE_PIXELS << zoff) >> 1), tile2pixel(mut->tiley << zoff) + ((TILE_SIZE_PIXELS << zoff) >> 1), destx, desty); /* Multiply the matrix to cause blitting. */ if(zoff) gdk_pixbuf_rotate_matrix_mult_number( _map_rotate_matrix, 1 << zoff); gdk_pixbuf_rotate(_map_pixbuf, /* Apply Map Correction. */ destx - unit2pixel(_map_correction_unitx), desty - unit2pixel(_map_correction_unity), _map_rotate_matrix, mut->pixbuf, TILE_SIZE_PIXELS / 2, TILE_SIZE_PIXELS / 2, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS, &boundx, &boundy, &width, &height); /* Un-multiply the matrix that we used for blitting. Good thing * we're multiplying by powers of two, or this wouldn't work * consistently... */ if(zoff) gdk_pixbuf_rotate_matrix_mult_number( _map_rotate_matrix, 1.f / (1 << zoff)); if(width * height) { gdk_draw_pixbuf( _map_pixmap, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], _map_pixbuf, boundx, boundy, boundx, boundy, width, height, GDK_RGB_DITHER_NONE, 0, 0); MACRO_MAP_RENDER_DATA(); gtk_widget_queue_draw_area( _map_widget, boundx, boundy, width, height); } } g_object_unref(mut->pixbuf); } else if(mut->vfs_result != GNOME_VFS_OK) { _dl_errors++; } if(++_curr_download == _num_downloads) { if(_download_banner) { gtk_widget_destroy(_download_banner); _download_banner = NULL; } _num_downloads = _curr_download = 0; g_thread_pool_stop_unused_threads(); if(_curr_repo->gdbm_db && !_curr_repo->is_sqlite) gdbm_sync(_curr_repo->gdbm_db); if(_dl_errors) { if (mut->repo->layer_level == 0) { gchar buffer[BUFFER_SIZE]; snprintf(buffer, sizeof(buffer), "%d %s", _dl_errors, _("maps failed to download.")); MACRO_BANNER_SHOW_INFO(_window, buffer); } _dl_errors = 0; } if(mut->update_type != MAP_UPDATE_AUTO || _refresh_map_after_download) { /* Update the map. */ map_refresh_mark(TRUE); } } else if(_download_banner) { hildon_banner_set_fraction(HILDON_BANNER(_download_banner), _curr_download / (double)_num_downloads); } g_mutex_lock(_mut_priority_mutex); g_hash_table_remove(_mut_exists_table, mut); g_mutex_unlock(_mut_priority_mutex); g_slice_free(MapUpdateTask, mut); vprintf("%s(): return\n", __PRETTY_FUNCTION__); return FALSE; } /** * Set the current zoom level. If the given zoom level is the same as the * current zoom level, or if the new zoom is invalid * (not MIN_ZOOM <= new_zoom < MAX_ZOOM), then this method does nothing. */ void map_set_zoom(gint new_zoom) { printf("%s(%d)\n", __PRETTY_FUNCTION__, _zoom); /* This if condition also checks for new_zoom >= 0. */ if((unsigned)new_zoom > MAX_ZOOM) return; map_center_zoom(new_zoom / _curr_repo->view_zoom_steps * _curr_repo->view_zoom_steps); vprintf("%s(): return\n", __PRETTY_FUNCTION__); } static gboolean map_replace_pixbuf_idle(MapRenderTask *mrt) { printf("%s()\n", __PRETTY_FUNCTION__); if(!--_pending_replaces && !_mouse_is_down && mrt->screen_width_pixels == _view_width_pixels && mrt->screen_height_pixels == _view_height_pixels) { g_object_unref(_map_pixbuf); _map_pixbuf = mrt->pixbuf; if(_center.unitx != mrt->new_center.unitx || _center.unity != mrt->new_center.unity || _zoom != mrt->zoom || _map_rotate_angle != mrt->rotate_angle) { dbus_ifc_fire_view_position_changed( mrt->new_center, mrt->zoom, mrt->rotate_angle); } _center = mrt->new_center; _zoom = mrt->zoom; _map_rotate_angle = mrt->rotate_angle; gdk_pixbuf_rotate_matrix_fill_for_rotation( _map_rotate_matrix, deg2rad(ROTATE_DIR_ENUM_DEGREES[_rotate_dir] - _map_rotate_angle)); gdk_pixbuf_rotate_matrix_fill_for_rotation( _map_reverse_matrix, deg2rad(_map_rotate_angle - ROTATE_DIR_ENUM_DEGREES[_rotate_dir])); --_redraw_count; _map_offset_devx = 0; _map_offset_devy = 0; map_set_mark(); map_force_redraw(); } else { /* Ignore this new pixbuf. We have newer ones coming. */ g_object_unref(mrt->pixbuf); --_redraw_count; } g_slice_free(MapRenderTask, mrt); vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__); return FALSE; } /* Routine draws one partly-transparent pixbuf on top of the another (base map). For efficiency, we assume that base map's tile have no transparent pixels (because it should not have them). We also assume that pixbufs are have the same size. */ static void combine_tiles (GdkPixbuf *dst_pixbuf, GdkPixbuf *src_pixbuf) { gint s_n_channels = gdk_pixbuf_get_n_channels (src_pixbuf); gint d_n_channels = gdk_pixbuf_get_n_channels (dst_pixbuf); gint bps = gdk_pixbuf_get_bits_per_sample (dst_pixbuf); gint width, height, x, y, d_delta, s_delta; guchar *d_p, *s_p; printf("combine_tiles()\n"); if (gdk_pixbuf_get_colorspace (dst_pixbuf) != gdk_pixbuf_get_colorspace (src_pixbuf)) { printf ("combine return (1)\n"); return; } if (gdk_pixbuf_get_colorspace (dst_pixbuf) != GDK_COLORSPACE_RGB) { printf ("combine return (2)\n"); return; } if (bps != gdk_pixbuf_get_bits_per_sample (src_pixbuf)) { printf ("combine return (5)\n"); return; } width = gdk_pixbuf_get_width (dst_pixbuf); height = gdk_pixbuf_get_height (dst_pixbuf); if (width != gdk_pixbuf_get_width (src_pixbuf)) { printf ("combine return (6)\n"); return; } if (height != gdk_pixbuf_get_height (src_pixbuf)) { printf ("combine return (7)\n"); return; } s_delta = (bps >> 3) * s_n_channels; d_delta = (bps >> 3) * d_n_channels; d_p = gdk_pixbuf_get_pixels (dst_pixbuf); s_p = gdk_pixbuf_get_pixels (src_pixbuf); /* ok, we're ready to combine */ for (y = 0; y < height; y++) { for (x = 0; x < width; x++, d_p += d_delta, s_p += s_delta) { /* TODO: alpha blending? */ if (s_n_channels == 3 || s_p[3]) { d_p[0] = s_p[0]; d_p[1] = s_p[1]; d_p[2] = s_p[2]; } } } } gboolean thread_render_map(MapRenderTask *mrt) { gfloat matrix[4]; gint start_tilex, start_tiley, stop_tilex, stop_tiley; gint x = 0, y, num_tilex, num_tiley; gint diag_halflength_units; gfloat angle_rad; gint tile_rothalf_pixels; gint curr_tile_to_draw, num_tiles_to_draw; gfloat *tile_dev; ThreadLatch *refresh_latch = NULL; gint cache_amount; static gint8 auto_download_batch_id = INT8_MIN; printf("%s(%d, %d, %d, %d, %d, %d)\n", __PRETTY_FUNCTION__, mrt->screen_width_pixels, mrt->screen_height_pixels, mrt->new_center.unitx, mrt->new_center.unity, mrt->zoom, mrt->rotate_angle); /* If there are more render tasks in the queue, skip this one. */ if(g_thread_pool_unprocessed(_mrt_thread_pool)) { g_slice_free(MapRenderTask, mrt); --_redraw_count; vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__); return FALSE; } angle_rad = deg2rad(ROTATE_DIR_ENUM_DEGREES[_rotate_dir] - mrt->rotate_angle); gdk_pixbuf_rotate_matrix_fill_for_rotation(matrix, angle_rad); /* Determine (roughly) the tiles we might have to process. * Basically, we take the center unit and subtract the maximum dimension * of the screen plus the maximum additional pixels of a rotated tile. */ tile_rothalf_pixels = MAX( fabsf(TILE_HALFDIAG_PIXELS * sinf((PI / 4) - angle_rad)), fabsf(TILE_HALFDIAG_PIXELS * cosf((PI / 4) - angle_rad))); mrt->zoom = _next_zoom; if(mrt->repo->type != REPOTYPE_NONE && MAPDB_EXISTS(mrt->repo)) cache_amount = _auto_download_precache; else cache_amount = 1; /* No cache. */ diag_halflength_units = pixel2zunit(TILE_HALFDIAG_PIXELS + MAX(mrt->screen_width_pixels, mrt->screen_height_pixels) / 2, mrt->zoom); start_tilex = unit2ztile( mrt->new_center.unitx - diag_halflength_units + _map_correction_unitx, mrt->zoom); start_tilex = MAX(start_tilex - (cache_amount - 1), 0); start_tiley = unit2ztile( mrt->new_center.unity - diag_halflength_units + _map_correction_unity, mrt->zoom); start_tiley = MAX(start_tiley - (cache_amount - 1), 0); stop_tilex = unit2ztile(mrt->new_center.unitx + diag_halflength_units + _map_correction_unitx, mrt->zoom); stop_tilex = MIN(stop_tilex + (cache_amount - 1), unit2ztile(WORLD_SIZE_UNITS, mrt->zoom)); stop_tiley = unit2ztile(mrt->new_center.unity + diag_halflength_units + _map_correction_unity, mrt->zoom); stop_tiley = MIN(stop_tiley + (cache_amount - 1), unit2ztile(WORLD_SIZE_UNITS, mrt->zoom)); num_tilex = (stop_tilex - start_tilex + 1); num_tiley = (stop_tiley - start_tiley + 1); tile_dev = g_new0(gfloat, num_tilex * num_tiley * 2); ++auto_download_batch_id; /* Iterate through the tiles and mark which ones need retrieval. */ num_tiles_to_draw = 0; for(y = 0; y < num_tiley; ++y) { for(x = 0; x < num_tilex; ++x) { gfloat devx, devy; /* Find the device location of this tile's center. */ pixel2buf_full( tile2pixel(x + start_tilex) + (TILE_SIZE_PIXELS >> 1), tile2pixel(y + start_tiley) + (TILE_SIZE_PIXELS >> 1), devx, devy, mrt->new_center, mrt->zoom, matrix); /* Apply Map Correction. */ devx -= unit2zpixel(_map_correction_unitx, mrt->zoom); devy -= unit2zpixel(_map_correction_unity, mrt->zoom); /* Skip this tile under the following conditions: * devx < -tile_rothalf_pixels * devx > _view_width_pixels + tile_rothalf_pixels * devy < -tile_rothalf_pixels * devy > _view_height_pixels + tile_rothalf_pixels */ if(((unsigned)(devx + tile_rothalf_pixels)) < (_view_width_pixels + (2 * tile_rothalf_pixels)) && ((unsigned)(devy + tile_rothalf_pixels)) < (_view_height_pixels + (2 * tile_rothalf_pixels))) { tile_dev[2 * (y * num_tilex + x)] = devx; tile_dev[2 * (y * num_tilex + x) + 1] = devy; ++num_tiles_to_draw; } else { tile_dev[2 * (y * num_tilex + x)] = FLT_MAX; } } } mrt->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, mrt->screen_width_pixels, mrt->screen_height_pixels); _refresh_map_after_download = FALSE; /* Iterate through the tiles, get them (or queue a download if they're * not in the cache), and rotate them into the pixbuf. */ for(y = curr_tile_to_draw = 0; y < num_tiley; ++y) { gint tiley = y + start_tiley; for(x = 0; x < num_tilex; ++x) { GdkPixbuf *tile_pixbuf = NULL, *layer_pixbuf = NULL; gboolean started_download = FALSE; gint zoff, zoff_base; gint tilex; RepoData* repo_p = mrt->repo; tilex = x + start_tilex; zoff_base = mrt->repo->double_size ? 1 : 0; /* iterating over tile and all it's layers */ while (repo_p) { started_download = FALSE; /* for layers we must use resolution of underlying map */ zoff = zoff_base; /* if this is not a bottom layer and layer not enabled, skip it */ if (repo_p != mrt->repo && !repo_p->layer_enabled) { repo_p = repo_p->layers; continue; } /* Iteratively try to retrieve a map to draw the tile. */ while((mrt->zoom + zoff) <= MAX_ZOOM && zoff < 4) { /* Check if we're actually going to draw this map. */ if(tile_dev[2 * (y*num_tilex + x)] != FLT_MAX) { if(NULL != (layer_pixbuf = mapdb_get( repo_p, mrt->zoom + zoff, tilex >> zoff, tiley >> zoff))) { /* if this is a layer's tile, join with main tile */ if (repo_p != mrt->repo) { /* but only if main layer is exists */ if (tile_pixbuf) combine_tiles (tile_pixbuf, layer_pixbuf); g_object_unref (layer_pixbuf); } else { tile_pixbuf = layer_pixbuf; zoff_base = zoff; } break; } else if (repo_p->layers) _refresh_map_after_download = TRUE; } /* Else we're not going to be drawing this map, so just check * if it's in the database. */ else if(mapdb_exists( repo_p, mrt->zoom + zoff, tilex >> zoff, tiley >> zoff)) { zoff_base = zoff; break; } /* No map; download, if we should. */ if(!started_download && _auto_download && mrt->repo->type != REPOTYPE_NONE /* Make sure this map is within dl zoom limits. */ && ((unsigned)(mrt->zoom + zoff - mrt->repo->min_zoom) <= (mrt->repo->max_zoom - mrt->repo->min_zoom)) /* Make sure this map matches the dl_zoom_steps, * or that there currently is no cache. */ && (!MAPDB_EXISTS(repo_p) || !((mrt->zoom + zoff - (mrt->repo->double_size ? 1 : 0)) % mrt->repo->dl_zoom_steps)) /* Make sure this tile is even possible. */ && ((unsigned)(tilex >> zoff) < unit2ztile(WORLD_SIZE_UNITS, mrt->zoom + zoff) && (unsigned)(tiley >> zoff) < unit2ztile(WORLD_SIZE_UNITS, mrt->zoom + zoff))) { started_download = TRUE; if(!refresh_latch) { refresh_latch = g_slice_new(ThreadLatch); refresh_latch->is_open = FALSE; refresh_latch->is_done_adding_tasks = FALSE; refresh_latch->num_tasks = 1; refresh_latch->num_done = 0; refresh_latch->mutex = g_mutex_new(); refresh_latch->cond = g_cond_new(); } else ++refresh_latch->num_tasks; mapdb_initiate_update( repo_p, mrt->zoom + zoff, tilex >> zoff, tiley >> zoff, MAP_UPDATE_AUTO, auto_download_batch_id, (abs((tilex >> zoff) - unit2ztile( mrt->new_center.unitx, mrt->zoom + zoff)) + abs((tiley >> zoff) - unit2ztile( mrt->new_center.unity, mrt->zoom + zoff))), refresh_latch); } /* Try again at a coarser resolution. Only for underlying map.*/ if (repo_p == mrt->repo && MAPDB_EXISTS(repo_p)) ++zoff; else break; } repo_p = repo_p->layers; } /* use zoom of the base map */ zoff = zoff_base; if(tile_pixbuf) { gint boundx, boundy, width, height; if(zoff) gdk_pixbuf_rotate_matrix_mult_number(matrix, 1 << zoff); gdk_pixbuf_rotate(mrt->pixbuf, tile_dev[2 * (y * num_tilex + x)], tile_dev[2 * (y * num_tilex + x) + 1], matrix, tile_pixbuf, ((tilex - ((tilex >> zoff) << zoff)) << (TILE_SIZE_P2 - zoff)) + (TILE_SIZE_PIXELS >> (1 + zoff)), ((tiley - ((tiley>>zoff) << zoff)) << (TILE_SIZE_P2 - zoff)) + (TILE_SIZE_PIXELS >> (1 + zoff)), TILE_SIZE_PIXELS >> zoff, TILE_SIZE_PIXELS >> zoff, &boundx, &boundy, &width, &height); g_object_unref(tile_pixbuf); /* Un-multiply the matrix that we used for blitting. Good * thing we're multiplying by powers of two, or this wouldn't * work consistently... */ if(zoff) gdk_pixbuf_rotate_matrix_mult_number( matrix, 1.f / (1 << zoff)); } /* usleep(10000); DEBUG */ } } /* Don't replace the pixbuf unless/until the mouse is released. */ g_mutex_lock(_mouse_mutex); ++_pending_replaces; g_idle_add_full(G_PRIORITY_HIGH_IDLE + 20, (GSourceFunc)map_replace_pixbuf_idle, mrt, NULL); g_mutex_unlock(_mouse_mutex); /* Release the view-change lock. */ if(refresh_latch) { g_mutex_lock(refresh_latch->mutex); if(refresh_latch->num_tasks == refresh_latch->num_done) { /* Fast little workers, aren't they? */ g_mutex_unlock(refresh_latch->mutex); g_cond_free(refresh_latch->cond); g_mutex_free(refresh_latch->mutex); g_slice_free(ThreadLatch, refresh_latch); } else { refresh_latch->is_done_adding_tasks = TRUE; refresh_latch->is_open = TRUE; g_cond_signal(refresh_latch->cond); g_mutex_unlock(refresh_latch->mutex); } } g_free(tile_dev); vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__); return FALSE; } gboolean map_cb_configure(GtkWidget *widget, GdkEventConfigure *event) { gint old_view_width_pixels, old_view_height_pixels; GdkPixbuf *old_map_pixbuf; printf("%s(%d, %d)\n", __PRETTY_FUNCTION__, _map_widget->allocation.width, _map_widget->allocation.height); if(_map_widget->allocation.width == 1 && _map_widget->allocation.height == 1) /* Special case - first allocation - not persistent. */ return TRUE; old_view_width_pixels = _view_width_pixels; old_view_height_pixels = _view_height_pixels; _view_width_pixels = _map_widget->allocation.width; _view_height_pixels = _map_widget->allocation.height; _view_halfwidth_pixels = _view_width_pixels / 2; _view_halfheight_pixels = _view_height_pixels / 2; g_object_unref(_map_pixmap); _map_pixmap = gdk_pixmap_new( _map_widget->window, _view_width_pixels, _view_height_pixels, -1); /* -1: use bit depth of widget->window. */ old_map_pixbuf = _map_pixbuf; _map_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, _view_width_pixels, _view_height_pixels); { gint oldnew_diffx = (gint)(_view_width_pixels - old_view_width_pixels) / 2; gint oldnew_diffy = (gint)(_view_height_pixels - old_view_height_pixels) / 2; gdk_pixbuf_copy_area(old_map_pixbuf, MAX(0, -oldnew_diffx), MAX(0, -oldnew_diffy), MIN(_view_width_pixels, old_view_width_pixels), MIN(_view_height_pixels, old_view_height_pixels), _map_pixbuf, MAX(0, oldnew_diffx), MAX(0, oldnew_diffy)); } g_object_unref(old_map_pixbuf); /* Set _scale_rect. */ _scale_rect.x = (_view_width_pixels - SCALE_WIDTH) / 2; _scale_rect.width = SCALE_WIDTH; pango_layout_set_text(_scale_layout, "0", -1); pango_layout_get_pixel_size(_scale_layout, NULL, &_scale_rect.height); _scale_rect.y = _view_height_pixels - _scale_rect.height - 1; /* Set _zoom rect. */ pango_layout_set_text(_zoom_layout, "00", -1); pango_layout_get_pixel_size(_zoom_layout, &_zoom_rect.width, &_zoom_rect.height); _zoom_rect.width *= 1.25; pango_layout_set_width(_zoom_layout, _zoom_rect.width); pango_layout_context_changed(_zoom_layout); _zoom_rect.x = _scale_rect.x - _zoom_rect.width; _zoom_rect.y = _view_height_pixels - _zoom_rect.height - 1; /* Set _comprose_rect. */ _comprose_rect.x = _view_width_pixels - 25 - _comprose_rect.width; _comprose_rect.y = _view_height_pixels - 25 - _comprose_rect.height; map_set_mark(); map_force_redraw(); /* Fire the screen_dimensions_changed DBUS signal. */ dbus_ifc_fire_view_dimensions_changed( _view_width_pixels, _view_height_pixels); /* If Auto-Center is set to Lead, then recalc center. */ if(_center_mode == CENTER_LEAD) map_center_unit(map_calc_new_center(_next_zoom)); else map_center_unit(_next_center); vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__); return TRUE; } gboolean sat_panel_expose(GtkWidget *widget, GdkEventExpose *event) { gchar *tmp = NULL; gint x, y; printf("%s()\n", __PRETTY_FUNCTION__); draw_sat_info(widget, 0, 0, widget->allocation.width, widget->allocation.height, FALSE); /* Sat View/In Use */ tmp = g_strdup_printf("%d/%d", _gps.satinuse, _gps.satinview); pango_layout_set_text(_sat_panel_layout, tmp, -1); pango_layout_set_alignment(_sat_panel_layout, PANGO_ALIGN_LEFT); gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], 20, 2, _sat_panel_layout); g_free(tmp); switch(_gps.fix) { case 2: case 3: tmp = g_strdup_printf("%dD fix", _gps.fix); break; default: tmp = g_strdup_printf("nofix"); break; } pango_layout_set_text(_sat_panel_layout, tmp, -1); pango_layout_set_alignment(_sat_panel_layout, PANGO_ALIGN_RIGHT); pango_layout_get_pixel_size(_sat_panel_layout, &x, &y); gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], widget->allocation.width - 20 - x, 2, _sat_panel_layout); g_free(tmp); vprintf("%s(): return\n", __PRETTY_FUNCTION__); return TRUE; } gboolean heading_panel_expose(GtkWidget *widget, GdkEventExpose *event) { gint size, xoffset, yoffset, i, x, y; gint dir; gfloat tmp; gchar *text; printf("%s()\n", __PRETTY_FUNCTION__); size = MIN(widget->allocation.width, widget->allocation.height); if(widget->allocation.width > widget->allocation.height) { xoffset = (widget->allocation.width - widget->allocation.height) / 2; yoffset = 0; } else { xoffset = 0; yoffset = (widget->allocation.height - widget->allocation.width) / 2; } pango_font_description_set_size(_heading_panel_fontdesc,12*PANGO_SCALE); pango_layout_set_font_description(_heading_panel_layout, _heading_panel_fontdesc); pango_layout_set_alignment(_heading_panel_layout, PANGO_ALIGN_CENTER); text = g_strdup_printf("%3.0f°", _gps.heading); pango_layout_set_text(_heading_panel_layout, text, -1); pango_layout_get_pixel_size(_heading_panel_layout, &x, &y); gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], xoffset + size/2 - x/2, yoffset + size - y - 2, _heading_panel_layout); g_free(text); gdk_draw_arc (widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], FALSE, xoffset, yoffset + size/2, size, size, 0, 64 * 180); /* Simple arrow for heading*/ gdk_draw_line(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], xoffset + size/2 + 3, yoffset + size - y - 5, xoffset + size/2, yoffset + size/2 + 5); gdk_draw_line(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], xoffset + size/2 - 3, yoffset + size - y - 5, xoffset + size/2, yoffset + size/2 + 5); gdk_draw_line(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], xoffset + size/2 - 3, yoffset + size - y - 5, xoffset + size/2, yoffset + size - y - 8); gdk_draw_line(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], xoffset + size/2 + 3, yoffset + size - y - 5, xoffset + size/2, yoffset + size - y - 8); gint angle[5] = {-90,-45,0,45,90}; gint fsize[5] = {0,4,10,4,0}; for(i = 0; i < 5; i++) { dir = (gint)(_gps.heading/45)*45 + angle[i]; switch(dir) { case 0: case 360: text = g_strdup("N"); break; case 45: case 405: text = g_strdup("NE"); break; case 90: text = g_strdup("E"); break; case 135: text = g_strdup("SE"); break; case 180: text = g_strdup("S"); break; case 225: text = g_strdup("SW"); break; case 270: case -90: text = g_strdup("W"); break; case 315: case -45: text = g_strdup("NW"); break; default : text = g_strdup("??"); break; } tmp = deg2rad(dir - _gps.heading); gdk_draw_line(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], xoffset + size/2 + ((size/2 - 5) * sinf(tmp)), yoffset + size - ((size/2 - 5) * cosf(tmp)), xoffset + size/2 + ((size/2 + 5) * sinf(tmp)), yoffset + size - ((size/2 + 5) * cosf(tmp))); x = fsize[i]; if(abs((gint)(_gps.heading/45)*45 - _gps.heading) > abs((gint)(_gps.heading/45)*45 + 45 - _gps.heading) && (i > 0)) x = fsize[i - 1]; pango_font_description_set_size(_heading_panel_fontdesc, (10 + x)*PANGO_SCALE); pango_layout_set_font_description(_heading_panel_layout, _heading_panel_fontdesc); pango_layout_set_text(_heading_panel_layout, text, -1); pango_layout_get_pixel_size(_heading_panel_layout, &x, &y); x = xoffset + size/2 + ((size/2 + 15) * sinf(tmp)) - x/2, y = yoffset + size - ((size/2 + 15) * cosf(tmp)) - y/2, gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], x, y, _heading_panel_layout); g_free(text); } vprintf("%s(): return\n", __PRETTY_FUNCTION__); return TRUE; } gboolean map_cb_expose(GtkWidget *widget, GdkEventExpose *event) { gint i; printf("%s(%d, %d, %d, %d)\n", __PRETTY_FUNCTION__, event->area.x, event->area.y, event->area.width, event->area.height); gdk_draw_drawable( _map_widget->window, _gc[COLORABLE_MARK], _map_pixmap, event->area.x - _map_offset_devx, event->area.y - _map_offset_devy, event->area.x, event->area.y, event->area.width, event->area.height); /* Draw the mark. */ if((((unsigned)(_mark_bufx1 + _draw_width) <= _view_width_pixels+2*_draw_width) &&((unsigned)(_mark_bufy1 + _draw_width) <= _view_height_pixels+2*_draw_width)) || (((unsigned)(_mark_bufx2 + _draw_width) <= _view_width_pixels+2*_draw_width) &&((unsigned)(_mark_bufy2 + _draw_width) <= _view_height_pixels+2*_draw_width))) { gdk_draw_arc( _map_widget->window, _gps_state == RCVR_FIXED ? _gc[COLORABLE_MARK] : _gc[COLORABLE_MARK_OLD], FALSE, /* not filled. */ _mark_bufx1 - _draw_width + _map_offset_devx, _mark_bufy1 - _draw_width + _map_offset_devy, 2 * _draw_width, 2 * _draw_width, 0, 360 * 64); gdk_draw_line( _map_widget->window, _gps_state == RCVR_FIXED ? (_show_velvec ? _gc[COLORABLE_MARK_VELOCITY] : _gc[COLORABLE_MARK]) : _gc[COLORABLE_MARK_OLD], _mark_bufx1 + _map_offset_devx, _mark_bufy1 + _map_offset_devy, _mark_bufx2 + _map_offset_devx, _mark_bufy2 + _map_offset_devy); } /* draw zoom box if so wanted */ if(_show_zoomlevel) { gchar *buffer = g_strdup_printf("%d", _zoom); gdk_draw_rectangle(_map_widget->window, _map_widget->style->bg_gc[GTK_STATE_ACTIVE], TRUE, _zoom_rect.x, _zoom_rect.y, _zoom_rect.width, _zoom_rect.height); gdk_draw_rectangle(_map_widget->window, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], FALSE, _zoom_rect.x, _zoom_rect.y, _zoom_rect.width, _zoom_rect.height); pango_layout_set_text(_zoom_layout, buffer, -1); gdk_draw_layout(_map_widget->window, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], _zoom_rect.x + _zoom_rect.width / 2, _zoom_rect.y, _zoom_layout); } /* Draw scale, if necessary. */ if(_show_scale) { gdk_rectangle_intersect(&event->area, &_scale_rect, &event->area); if(event->area.width && event->area.height) { gdk_draw_rectangle(_map_widget->window, _map_widget->style->bg_gc[GTK_STATE_ACTIVE], TRUE, _scale_rect.x, _scale_rect.y, _scale_rect.width, _scale_rect.height); gdk_draw_rectangle(_map_widget->window, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], FALSE, _scale_rect.x, _scale_rect.y, _scale_rect.width, _scale_rect.height); /* Now calculate and draw the distance. */ { gchar buffer[16]; gfloat distance; gdouble lat1, lon1, lat2, lon2; gint width; unit2latlon(_center.unitx - pixel2unit(SCALE_WIDTH / 2 - 4), _center.unity, lat1, lon1); unit2latlon(_center.unitx + pixel2unit(SCALE_WIDTH / 2 - 4), _center.unity, lat2, lon2); distance = calculate_distance(lat1, lon1, lat2, lon2) * UNITS_CONVERT[_units]; if(distance < 1.f) snprintf(buffer, sizeof(buffer), "%0.2f %s", distance, UNITS_ENUM_TEXT[_units]); else if(distance < 10.f) snprintf(buffer, sizeof(buffer), "%0.1f %s", distance, UNITS_ENUM_TEXT[_units]); else snprintf(buffer, sizeof(buffer), "%0.f %s", distance, UNITS_ENUM_TEXT[_units]); pango_layout_set_text(_scale_layout, buffer, -1); pango_layout_get_pixel_size(_scale_layout, &width, NULL); /* Draw the layout itself. */ gdk_draw_layout(_map_widget->window, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], _scale_rect.x + (_scale_rect.width - width) / 2, _scale_rect.y, _scale_layout); /* Draw little hashes on the ends. */ gdk_draw_line(_map_widget->window, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], _scale_rect.x + 4, _scale_rect.y + _scale_rect.height / 2 - 4, _scale_rect.x + 4, _scale_rect.y + _scale_rect.height / 2 + 4); gdk_draw_line(_map_widget->window, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], _scale_rect.x + 4, _scale_rect.y + _scale_rect.height / 2, _scale_rect.x + (_scale_rect.width - width) / 2 - 4, _scale_rect.y + _scale_rect.height / 2); gdk_draw_line(_map_widget->window, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], _scale_rect.x + _scale_rect.width - 4, _scale_rect.y + _scale_rect.height / 2 - 4, _scale_rect.x + _scale_rect.width - 4, _scale_rect.y + _scale_rect.height / 2 + 4); gdk_draw_line(_map_widget->window, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], _scale_rect.x + _scale_rect.width - 4, _scale_rect.y + _scale_rect.height / 2, _scale_rect.x + (_scale_rect.width + width) / 2 + 4, _scale_rect.y + _scale_rect.height / 2); } } } /* Draw the compass rose, if necessary. */ if(_show_comprose) { GdkPoint points[3]; gint offsetx, offsety; gfloat x, y; offsetx = _comprose_rect.x; offsety = _comprose_rect.y; gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, 0, 12); points[0].x = offsetx + x + 0.5f; points[0].y = offsety + y + 0.5f; gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, 20, 30); points[1].x = offsetx + x + 0.5f; points[1].y = offsety + y + 0.5f; gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, 0, -45); points[2].x = offsetx + x + 0.5f; points[2].y = offsety + y + 0.5f; gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, -20, 30); points[3].x = offsetx + x + 0.5f; points[3].y = offsety + y + 0.5f; gdk_draw_polygon(_map_widget->window, _map_widget->style->bg_gc[GTK_STATE_ACTIVE], TRUE, /* FILLED */ points, 4); gdk_draw_polygon(_map_widget->window, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], FALSE, /* NOT FILLED */ points, 4); gdk_draw_layout(_map_widget->window, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], _comprose_rect.x - _comprose_rect.width / 2 + 1, _comprose_rect.y - _comprose_rect.height / 2 - 4, _comprose_layout); } /* Draw a stopwatch if we're redrawing the map. */ for(i = _redraw_count - 1; i >= 0; i--) { gdk_draw_pixbuf( _map_widget->window, _map_widget->style->fg_gc[GTK_STATE_ACTIVE], _redraw_wait_icon, 0, 0, _redraw_wait_bounds.x + i * HOURGLASS_SEPARATION, _redraw_wait_bounds.y, _redraw_wait_bounds.width, _redraw_wait_bounds.height, GDK_RGB_DITHER_NONE, 0, 0); } vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__); return TRUE; } static void latlon_cb_copy_clicked(GtkWidget *widget, LatlonDialog *lld) { gchar buffer[42]; snprintf(buffer, sizeof(buffer), "%s %s", gtk_label_get_text(GTK_LABEL(lld->lat)), gtk_label_get_text(GTK_LABEL(lld->lon))); gtk_clipboard_set_text( gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), buffer, -1); } static void latlon_cb_fmt_changed(GtkWidget *widget, LatlonDialog *lld) { DegFormat fmt; fmt = gtk_combo_box_get_active(GTK_COMBO_BOX(lld->fmt_combo)); { gint old = _degformat; /* augh... */ gchar buffer[LL_FMT_LEN]; gchar buffer2[LL_FMT_LEN]; _degformat = fmt; format_lat_lon(lld->glat, lld->glon, buffer, buffer2); //lat_format(lld->glat, buffer); gtk_label_set_label(GTK_LABEL(lld->lat), buffer); //lon_format(lld->glon, buffer); if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use) gtk_label_set_label(GTK_LABEL(lld->lon), buffer2); else gtk_label_set_label(GTK_LABEL(lld->lon), g_strdup("")); // And set the titles gtk_label_set_label(GTK_LABEL(lld->lat_title), DEG_FORMAT_ENUM_TEXT[_degformat].short_field_1 ); if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use) gtk_label_set_label(GTK_LABEL(lld->lon_title), DEG_FORMAT_ENUM_TEXT[_degformat].short_field_2 ); else gtk_label_set_label(GTK_LABEL(lld->lon_title), g_strdup("")); _degformat = old; } } gboolean latlon_dialog(gdouble lat, gdouble lon) { LatlonDialog lld; GtkWidget *dialog; GtkWidget *table; GtkWidget *label; GtkWidget *lbl_lon_title; GtkWidget *lbl_lat_title; GtkWidget *txt_lat; GtkWidget *txt_lon; GtkWidget *cmb_format; GtkWidget *btn_copy = NULL; gint prev_degformat = _degformat; gint fallback_deg_format = _degformat; printf("%s()\n", __PRETTY_FUNCTION__); // Check that the current coord system supports the select position if(!coord_system_check_lat_lon (lat, lon, &fallback_deg_format)) { _degformat = fallback_deg_format; } dialog = gtk_dialog_new_with_buttons(_("Show Position"), GTK_WINDOW(_window), GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); /* Set the lat/lon strings. */ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), table = gtk_table_new(5, 2, FALSE), TRUE, TRUE, 0); gtk_table_attach(GTK_TABLE(table), lbl_lat_title = gtk_label_new(/*_("Lat")*/ DEG_FORMAT_ENUM_TEXT[_degformat].short_field_1 ), 0, 1, 0, 1, GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(lbl_lat_title), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), txt_lat = gtk_label_new(""), 1, 2, 0, 1, GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(txt_lat), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), lbl_lon_title = gtk_label_new(/*_("Lon")*/ DEG_FORMAT_ENUM_TEXT[_degformat].short_field_2 ), 0, 1, 1, 2, GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(lbl_lon_title), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), txt_lon = gtk_label_new(""), 1, 2, 1, 2, GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(txt_lon), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Format")), 0, 1, 2, 3, GTK_FILL, 0, 2, 4); gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); gtk_table_attach(GTK_TABLE(table), label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f), 1, 2, 2, 3, GTK_FILL, 0, 2, 4); gtk_container_add(GTK_CONTAINER(label), cmb_format = gtk_combo_box_new_text()); gtk_table_attach(GTK_TABLE(table), btn_copy = gtk_button_new_with_label(_("Copy")), 0, 2, 3, 4, GTK_FILL, 0, 2, 4); /* Lat/Lon */ { gchar buffer[LL_FMT_LEN]; gchar buffer2[LL_FMT_LEN]; format_lat_lon(lat, lon, buffer, buffer2); //lat_format(lat, buffer); gtk_label_set_label(GTK_LABEL(txt_lat), buffer); //lat_format(lon, buffer); if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use) gtk_label_set_label(GTK_LABEL(txt_lon), buffer2); else gtk_label_set_label(GTK_LABEL(txt_lon), g_strdup("")); } /* Fill in formats */ { int i; for(i = 0; i < DEG_FORMAT_ENUM_COUNT; i++) { gtk_combo_box_append_text(GTK_COMBO_BOX(cmb_format), DEG_FORMAT_ENUM_TEXT[i].name); } gtk_combo_box_set_active(GTK_COMBO_BOX(cmb_format), _degformat); } /* setup cb context */ lld.fmt_combo = cmb_format; lld.glat = lat; lld.glon = lon; lld.lat = txt_lat; lld.lon = txt_lon; lld.lat_title = lbl_lat_title; lld.lon_title = lbl_lon_title; /* Connect Signals */ g_signal_connect(G_OBJECT(cmb_format), "changed", G_CALLBACK(latlon_cb_fmt_changed), &lld); g_signal_connect(G_OBJECT(btn_copy), "clicked", G_CALLBACK(latlon_cb_copy_clicked), &lld); gtk_widget_show_all(dialog); gtk_dialog_run(GTK_DIALOG(dialog)); _degformat = prev_degformat; // Put back incase it had to be auto changed gtk_widget_hide(dialog); vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__); return TRUE; } /** * This is a multi-purpose function for allowing the user to select a file * for either reading or writing. If chooser_action is * GTK_FILE_CHOOSER_ACTION_OPEN, then bytes_out and size_out must be * non-NULL. If chooser_action is GTK_FILE_CHOOSER_ACTION_SAVE, then * handle_out must be non-NULL. Either dir or file (or both) can be NULL. * This function returns TRUE if a file was successfully opened. */ gboolean display_open_file(GtkWindow *parent, gchar **bytes_out, GnomeVFSHandle **handle_out, gint *size_out, gchar **dir, gchar **file, GtkFileChooserAction chooser_action) { GtkWidget *dialog; gboolean success = FALSE; printf("%s()\n", __PRETTY_FUNCTION__); dialog = hildon_file_chooser_dialog_new(parent, chooser_action); if(dir && *dir) gtk_file_chooser_set_current_folder_uri( GTK_FILE_CHOOSER(dialog), *dir); if(file && *file) { gtk_file_chooser_set_uri( GTK_FILE_CHOOSER(dialog), *file); if(chooser_action == GTK_FILE_CHOOSER_ACTION_SAVE) { /* Work around a bug in HildonFileChooserDialog. */ gchar *basename = g_path_get_basename(*file); g_object_set(G_OBJECT(dialog), "autonaming", FALSE, NULL); gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER(dialog), basename); g_free(basename); } } gtk_widget_show_all(dialog); while(!success && gtk_dialog_run(GTK_DIALOG(dialog))==GTK_RESPONSE_OK) { gchar *file_uri_str; GnomeVFSResult vfs_result; /* Get the selected filename. */ file_uri_str = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); if((chooser_action == GTK_FILE_CHOOSER_ACTION_OPEN && (GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file( file_uri_str, size_out, bytes_out)))) || (chooser_action == GTK_FILE_CHOOSER_ACTION_SAVE && GNOME_VFS_OK != (vfs_result = gnome_vfs_create( handle_out, file_uri_str, GNOME_VFS_OPEN_WRITE, FALSE, 0664)))) { gchar buffer[BUFFER_SIZE]; snprintf(buffer, sizeof(buffer), "%s:\n%s", chooser_action == GTK_FILE_CHOOSER_ACTION_OPEN ? _("Failed to open file for reading") : _("Failed to open file for writing"), gnome_vfs_result_to_string(vfs_result)); popup_error(dialog, buffer); } else success = TRUE; g_free(file_uri_str); } if(success) { /* Success!. */ if(dir) { g_free(*dir); *dir = gtk_file_chooser_get_current_folder_uri( GTK_FILE_CHOOSER(dialog)); } /* If desired, save the file for later. */ if(file) { g_free(*file); *file = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); } } gtk_widget_destroy(dialog); vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success); return success; } void display_init() { PangoContext *pango_context; PangoFontDescription *pango_font; GdkColor color; printf("%s()\n", __PRETTY_FUNCTION__); /* Cache some pango and GCs for drawing. */ pango_context = gtk_widget_get_pango_context(_map_widget); _scale_layout = pango_layout_new(pango_context); pango_font = pango_font_description_new(); pango_font_description_set_size(pango_font, 12 * PANGO_SCALE); pango_layout_set_font_description(_scale_layout, pango_font); #ifdef INCLUDE_APRS /* APRS Labels */ pango_context = gtk_widget_get_pango_context(_map_widget); _aprs_label_layout = pango_layout_new(pango_context); pango_font = pango_font_description_new(); pango_font_description_set_size(pango_font, 10 * PANGO_SCALE); pango_font_description_set_family(pango_font,"Sans Serif"); pango_layout_set_font_description(_aprs_label_layout, pango_font); #endif // INCLUDE_APRS /* zoom box */ pango_context = gtk_widget_get_pango_context(_map_widget); _zoom_layout = pango_layout_new(pango_context); pango_font = pango_font_description_new(); pango_font_description_set_size(pango_font, 12 * PANGO_SCALE); pango_layout_set_font_description(_zoom_layout, pango_font); pango_layout_set_alignment(_zoom_layout, PANGO_ALIGN_CENTER); /* compose rose */ pango_context = gtk_widget_get_pango_context(_map_widget); _comprose_layout = pango_layout_new(pango_context); pango_font = pango_font_description_new(); pango_font_description_set_size(pango_font, 16 * PANGO_SCALE); pango_font_description_set_weight(pango_font, PANGO_WEIGHT_BOLD); pango_layout_set_font_description(_comprose_layout, pango_font); pango_layout_set_alignment(_comprose_layout, PANGO_ALIGN_CENTER); pango_layout_set_text(_comprose_layout, "N", -1); { PangoRectangle rect; pango_layout_get_pixel_extents(_comprose_layout, &rect, NULL); _comprose_rect.width = rect.width + 3; _comprose_rect.height = rect.height + 3; } /* speed limit */ _speed_limit_gc1 = gdk_gc_new (_map_widget->window); color.red = 0xffff; color.green = 0; color.blue = 0; gdk_gc_set_rgb_fg_color(_speed_limit_gc1, &color); color.red = 0; color.green = 0; color.blue = 0; _speed_limit_gc2 = gdk_gc_new(_map_widget->window); gdk_gc_set_rgb_fg_color(_speed_limit_gc2, &color); pango_context = gtk_widget_get_pango_context(_map_widget); _speed_limit_layout = pango_layout_new(pango_context); pango_font = pango_font_description_new(); pango_font_description_set_size(pango_font, 64 * PANGO_SCALE); pango_layout_set_font_description(_speed_limit_layout, pango_font); pango_layout_set_alignment(_speed_limit_layout, PANGO_ALIGN_CENTER); /* draw_sat_info() */ _sat_info_gc1 = gdk_gc_new(_map_widget->window); color.red = 0; color.green = 0; color.blue = 0; gdk_gc_set_rgb_fg_color(_sat_info_gc1, &color); color.red = 0; color.green = 0; color.blue = 0xffff; _sat_info_gc2 = gdk_gc_new(_map_widget->window); gdk_gc_set_rgb_fg_color(_sat_info_gc2, &color); pango_context = gtk_widget_get_pango_context(_map_widget); _sat_info_layout = pango_layout_new(pango_context); pango_font = pango_font_description_new(); pango_font_description_set_family(pango_font,"Sans Serif"); pango_font_description_set_size(pango_font, 8*PANGO_SCALE); pango_layout_set_font_description(_sat_info_layout, pango_font); pango_layout_set_alignment(_sat_info_layout, PANGO_ALIGN_CENTER); /* sat_panel_expose() */ pango_context = gtk_widget_get_pango_context(_map_widget); _sat_panel_layout = pango_layout_new(pango_context); pango_font = pango_font_description_new(); pango_font_description_set_family(pango_font,"Sans Serif"); pango_font_description_set_size(pango_font, 14*PANGO_SCALE); pango_layout_set_font_description (_sat_panel_layout, pango_font); /* heading_panel_expose() */ pango_context = gtk_widget_get_pango_context(_map_widget); _heading_panel_layout = pango_layout_new(pango_context); _heading_panel_fontdesc = pango_font_description_new(); pango_font_description_set_family(_heading_panel_fontdesc, "Sans Serif"); /* draw_sat_details() */ pango_context = gtk_widget_get_pango_context(_map_widget); _sat_details_layout = pango_layout_new(pango_context); pango_font = pango_font_description_new(); pango_font_description_set_family(pango_font,"Sans Serif"); pango_font_description_set_size(pango_font, 10*PANGO_SCALE); pango_layout_set_font_description(_sat_details_layout, pango_font); pango_layout_set_alignment(_sat_details_layout, PANGO_ALIGN_CENTER); /* sat_details_panel_expose() */ pango_context = gtk_widget_get_pango_context(_map_widget); _sat_details_expose_layout = pango_layout_new(pango_context); pango_font = pango_font_description_new(); pango_font_description_set_family( pango_font,"Sans Serif"); pango_layout_set_alignment(_sat_details_expose_layout, PANGO_ALIGN_CENTER); pango_font_description_set_size(pango_font, 14*PANGO_SCALE); pango_layout_set_font_description(_sat_details_expose_layout, pango_font); /* Load the _redraw_wait_icon. */ { GError *error = NULL; gchar *icon_path = "/usr/share/icons/hicolor/scalable/hildon" "/maemo-mapper-wait.png"; _redraw_wait_bounds.x = 0; _redraw_wait_bounds.y = 0; _redraw_wait_icon = gdk_pixbuf_new_from_file(icon_path, &error); if(!_redraw_wait_icon || error) { g_printerr("Error parsing pixbuf: %s\n", error ? error->message : icon_path); _redraw_wait_bounds.width = 0; _redraw_wait_bounds.height = 0; _redraw_wait_icon = NULL; } else { _redraw_wait_bounds.width = gdk_pixbuf_get_width(_redraw_wait_icon); _redraw_wait_bounds.height = gdk_pixbuf_get_height(_redraw_wait_icon); } } g_signal_connect(G_OBJECT(_map_widget), "configure_event", G_CALLBACK(map_cb_configure), NULL); g_signal_connect(G_OBJECT(_map_widget), "expose_event", G_CALLBACK(map_cb_expose), NULL); g_signal_connect(G_OBJECT(_sat_panel), "expose_event", G_CALLBACK(sat_panel_expose), NULL); g_signal_connect(G_OBJECT(_heading_panel), "expose_event", G_CALLBACK(heading_panel_expose), NULL); vprintf("%s(): return\n", __PRETTY_FUNCTION__); }