diff options
-rw-r--r-- | gnome-map/Makefile | 11 | ||||
-rw-r--r-- | gnome-map/gglobe-canvas.c | 786 | ||||
-rw-r--r-- | gnome-map/gnome-canvas-dot.c | 434 | ||||
-rw-r--r-- | gnome-map/gnome-canvas-dot.h | 60 | ||||
-rw-r--r-- | gnome-map/gnome-map.c | 327 | ||||
-rw-r--r-- | gnome-map/gnome-map.h | 59 | ||||
-rw-r--r-- | gnome-map/map480.png | bin | 0 -> 134252 bytes | |||
-rw-r--r-- | gnome-map/pygtk.h | 334 | ||||
-rwxr-xr-x | gnome-map/pytimezone | 40 | ||||
-rw-r--r-- | gnome-map/testtz.c | 11 | ||||
-rw-r--r-- | gnome-map/timezonemapmodule.c | 824 | ||||
-rw-r--r-- | gnome-map/timezones.c | 178 | ||||
-rw-r--r-- | gnome-map/timezones.h | 40 |
13 files changed, 3104 insertions, 0 deletions
diff --git a/gnome-map/Makefile b/gnome-map/Makefile new file mode 100644 index 000000000..7c21a0794 --- /dev/null +++ b/gnome-map/Makefile @@ -0,0 +1,11 @@ +all: gglobe-canvas timezonemapmodule.so + +CFLAGS=-g -Wall -fPIC `gnome-config --cflags gnomeui` -I/usr/include/python1.5 +LDFLAGS=`gnome-config --libs gnomeui` + +gglobe-canvas: gglobe-canvas.c gnome-map.o gnome-canvas-dot.o gglobe-canvas.o gnome-map.h timezones.o timezones.h + gcc -O2 -g -o gglobe-canvas gnome-map.o timezones.o gnome-canvas-dot.o gglobe-canvas.o $(LDFLAGS) + + +timezonemapmodule.so: gnome-map.o gnome-canvas-dot.o timezonemapmodule.o gnome-map.h timezones.o timezones.h + gcc -o timezonemapmodule.so -shared gnome-map.o gnome-canvas-dot.o timezonemapmodule.o timezones.o $(LDFLAGS) diff --git a/gnome-map/gglobe-canvas.c b/gnome-map/gglobe-canvas.c new file mode 100644 index 000000000..68f92682f --- /dev/null +++ b/gnome-map/gglobe-canvas.c @@ -0,0 +1,786 @@ +/* Copyright (C) 1999 Red Hat, Inc. */ +/* Original work by Michael Fulbright <drmike@redhat.com> */ + +#include <gnome.h> +#include <stdlib.h> +#include <unistd.h> +#include <math.h> + +#include "gnome-map.h" +#include "gnome-canvas-dot.h" +#include "timezones.h" + + +/* Command line options */ +/* image - filename of file to use for map (must be PNG for antialias) */ +/* mapwidth - width to scale image to (also size of canvas widget) */ +/* mapheight - height to scale image to (also size of canvas widget) */ +/* aa - if TRUE use antialiased canvas instead of normal */ +static gchar *image = NULL; +static int mapwidth = -1; +static int mapheight = -1; +static int aa=FALSE; + +static const struct poptOption options[] = { + {"image", '\0', POPT_ARG_STRING, &image, 0, N_("Map Image to display"), NULL}, + {"width", '\0', POPT_ARG_INT, &mapwidth, 0, N_("Width of map (in pixels)"), NULL}, + {"antialias", '\0', POPT_ARG_INT, &aa, 0, N_("Enable antialias"), NULL}, + { NULL, '\0', 0, NULL, 0} +}; + + +/* time zone data */ +/* This is an array of TimeZoneLocations (see timezone.h). Created */ +/* by a call to loadTZDB */ +GPtrArray *Locations=NULL; + +/* index in all Locations GPtrArray of currently selected city */ +gint curselection=-1; + +/* toplevel app window */ +GtkWidget *mainwindow; + +/* other widgets for the top-level GUI */ +GtkWidget *statusbar; + +/* locationlist is the clist on the right side of the GUI showing all the */ +/* currently viewable locations. */ +/* It is created and updated by the create_location_list () function */ +GtkWidget *locationlist; + +/* if TRUE we do not want to act on the select_row events to locationlist */ +/* used when we are manually manipulating rows in locationlist and we */ +/* want to ignore the events going to the callback. */ +gboolean ignore_locationlist_selectevents=FALSE; + +/* Canvas item circle for selected location */ +GnomeCanvasItem *selmarker=NULL; +double oldselx, oldsely; /* old location of selection */ +#define SELECTED_COLOR "red" + +/* Canvas item circle for hilited location and optionally rubberband */ +/* line pointing from cursor to hilited location */ +GnomeCanvasItem *hilitemarker=NULL; +GnomeCanvasItem *hiliterubberband=NULL; +gint hiliteindex=-1; /* index in markers array of */ + /* currently hilted location */ +double oldhilitex, oldhilitey; /* old location of hilite circle */ +#define HILITED_COLOR "limegreen" + +/* set to appropriate value to enable/disable the rubberband */ +#define USE_HILITE_RUBBERBAND TRUE + +/* color for normal (non-hilited or -selected locations */ +#define CITY_COLOR "yellow" + +/* map and city structures */ +/* See gnome-map.h for more info on the GnomeMap structure */ +/* markers is an array of pointers to GnomeCanvasItems which are the */ +/* indicators for the locations in the Locations array */ +GnomeMap *WorldMap; +GnomeCanvasItem **markers=NULL; + +/* view data */ +/* Views are defined by a range of either longitude or latitude */ +/* as well as the central value for the other axis. */ +typedef enum +{ + LONGITUDE_CONSTRAINT, + LATITUDE_CONSTRAINT +} ViewContraintType; + +struct _VIEW_DEF { + gchar *name; + ViewContraintType type; + double constraint1, constraint2, constraint3; +}; + +typedef struct _VIEW_DEF ViewDefinition; + +ViewDefinition Views[] = { + { "World", LONGITUDE_CONSTRAINT, -180.0, 180.0, 0.0 }, + { "North America", LONGITUDE_CONSTRAINT, -171.0, -21.0, 40.0 }, + { "South America", LATITUDE_CONSTRAINT, 15.0, -70.0, -70.0 }, + { "Pacific Rim", LATITUDE_CONSTRAINT, -47.0, 47.0, 155.0}, + { "Europe", LONGITUDE_CONSTRAINT, -25.0, 70.0, 45.0 }, + { "Africa", LATITUDE_CONSTRAINT, 40.0, -40.0, 15.0}, + { "Asia", LONGITUDE_CONSTRAINT, 20.0, 165.0, 40.0} +}; + +gint numviews = sizeof(Views)/sizeof(ViewDefinition); + + +static gint item_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data); +static GtkWidget *create_location_list ( GtkWidget **returnlist ); + +/* give a location name search for match in Locations db */ +/* returns index if found, -1 if not */ +static int +find_location (gchar *locname) +{ + TimeZoneLocation *loc; + gint i; + + for (i=0; i < Locations->len; i++) { + loc = g_ptr_array_index (Locations, i); + + if (!strcmp (loc->zone, locname)) + return i; + } + + return -1; +} + + +/* find nearest location to specified map coords - clips to current view */ +/* if no match return -1 */ +static int +find_nearest ( double longitude, double latitude ) +{ + double mindist; + double dist; + double dx, dy; + int i, mini; + gboolean first=TRUE; + TimeZoneLocation *loc; + + mini = -1; + for (i=0; i < Locations->len; i++) { + loc = g_ptr_array_index (Locations, i); + + if (!gnome_map_is_loc_in_view (WorldMap, + loc->longitude, loc->latitude)) + continue; + + dx = (loc->longitude-longitude); + dy = (loc->latitude-latitude); + dist = dx*dx + dy*dy; + + if (dist < mindist || first) { + mindist = dist; + mini = i; + first = FALSE; + } + } + + return mini; +} + +/* attach to signal for canvas items so we can track motion and mouse */ +/* events */ +static void +setup_item (GnomeCanvasItem *item) +{ + gtk_signal_connect (GTK_OBJECT (item), "event", + (GtkSignalFunc) item_event, + NULL); +} + +/* Moves marker (a circle currently) to the specified location */ +/* and sets it to the specified color. The oldx and oldy */ +/* variables are required because the canvas only allows one */ +/* to do relative moves for items. These are automatically */ +/* set to x and y by this function before it returns. */ +/* */ +/* The first time this function is called for a given marker */ +/* *curmarker should equal NULL. The marker will be created */ +/* automatically. */ + +static void +set_flag_marker (GnomeCanvasItem **curmarker, gchar *color, + double x, double y, double *oldx, double *oldy) +{ + GnomeCanvasGroup *canvas_root; + GnomeCanvasItem *group; + + g_return_if_fail ( color != NULL ); + + canvas_root = gnome_canvas_root (GNOME_CANVAS(WorldMap->canvas)); + if (!*curmarker) { + + group = gnome_canvas_item_new ( canvas_root, + gnome_canvas_group_get_type(), + "x", x, + "y", y, + NULL); + +#define MARKER_RADIUS 3.5 +#define MARKER_WIDTH_PIX 1 + + setup_item (gnome_canvas_item_new (GNOME_CANVAS_GROUP (group), + gnome_canvas_text_get_type (), + "font", "-adobe-helvetica-bold-r-normal--12-*-72-72-p-*-iso8859-1", + "anchor", GTK_ANCHOR_CENTER, + "fill_color", "red", + "text", "X", + NULL)); + + *curmarker = GNOME_CANVAS_ITEM (group); + } else { + gnome_canvas_item_move ( *curmarker, x - *oldx, y - *oldy ); + } + + *oldx = x; + *oldy = y; +} + +/* Given a pointer to a GnomeMap and an index into the Locations db */ +/* mark it as the selected location on the canvas */ +static void +map_mark_location_selected (GnomeMap *map, gint index) +{ + TimeZoneLocation *loc; + double selx, sely; + + g_return_if_fail ( map != NULL ); + g_return_if_fail ( index >= 0 ); + + loc = g_ptr_array_index (Locations, index); + + gnome_map_xlat_map2screen ( map, + loc->longitude, loc->latitude, + &selx, &sely ); + set_flag_marker (&selmarker, SELECTED_COLOR, + selx, sely, &oldselx, &oldsely); + + if (curselection >= 0) { + gnome_canvas_item_set (markers[curselection], + "fill_color", CITY_COLOR, NULL); + gnome_canvas_item_show (markers[curselection]); + } +/* gnome_canvas_item_set (markers[index], "fill_color", */ +/* SELECTED_COLOR, NULL); */ + gnome_canvas_item_hide (markers[index]); + gnome_canvas_item_raise_to_top (selmarker); +} + +/* Given a pointer to a GnomeMap and an index into the Locations db */ +/* mark it as the selected location in the clist of locations */ +/* The jumpto gboolean is used to specify if the clist should be */ +/* forced to scroll to the new location. Used because when the */ +/* clist is autoscrolling we do not want to force selection to be */ +/* constantly recentered. */ +static void +list_mark_location_selected (GnomeMap *map, gint index, gboolean jumpto) +{ + gint newrow; + + /* We're messing with list manually, so let callback know to */ + /* ignore any events till we're done */ + ignore_locationlist_selectevents = TRUE; + + /* if current selection is visible then select it again, otherwise */ + /* change clist to not have a current selection */ + if (index >= 0) { + TimeZoneLocation *loc = g_ptr_array_index (Locations, index); + + if (gnome_map_is_loc_in_view (map,loc->longitude,loc->latitude)) { + gtk_clist_set_selection_mode (GTK_CLIST (locationlist), + GTK_SELECTION_BROWSE); + } else { + gtk_clist_set_selection_mode (GTK_CLIST (locationlist), + GTK_SELECTION_SINGLE); + } + } + + /* find in list of locations and set as current */ + newrow = gtk_clist_find_row_from_data( GTK_CLIST (locationlist), + GINT_TO_POINTER (index)); + + if (newrow >= 0 ) { + gtk_clist_select_row (GTK_CLIST(locationlist), newrow, 0); + if (jumpto && gtk_clist_row_is_visible (GTK_CLIST (locationlist), newrow) != GTK_VISIBILITY_FULL) { + gtk_clist_moveto (GTK_CLIST (locationlist), newrow , 0, 0.5, 0.5 ); + } + } + + /* We're done mucking with clist, ok to listen to events again */ + ignore_locationlist_selectevents = FALSE; + +} +/* handles all canvas drawing for making the selected location # index */ +/* in the sorted list in the Locations variable */ +static void +set_selection (gint index, gboolean jumpto) +{ + g_return_if_fail ( index >= 0 ); + + map_mark_location_selected (WorldMap, index); + + list_mark_location_selected (WorldMap, index, jumpto); + + /* NOTE: curselection is global variable. Only place it gets set */ + curselection = index; +} + +/* Given an index into the Locations db and a position, draw the hilite */ +/* marker around it to indicate it is city cursor is pointing at */ +static void +set_hilited (gint index, double item_x, double item_y) +{ + TimeZoneLocation *loc; + GnomeCanvasPoints *points; + + g_return_if_fail ( index >= 0 ); + + loc = g_ptr_array_index (Locations, index); + + points = gnome_canvas_points_new (2); + points->coords[0] = item_x; + points->coords[1] = item_y; + gnome_map_xlat_map2screen ( WorldMap, + loc->longitude, loc->latitude, + &points->coords[2], &points->coords[3] ); + if (hiliterubberband) { + gnome_canvas_item_set (hiliterubberband, "points", points, NULL); + gnome_canvas_item_show (hiliterubberband); + } else { + GnomeCanvasGroup *canvas_root = gnome_canvas_root (GNOME_CANVAS (WorldMap->canvas)); + + hiliterubberband = gnome_canvas_item_new (canvas_root, + gnome_canvas_line_get_type (), + "points", points, + "fill_color", HILITED_COLOR, + "width_pixels", 2, + "first_arrowhead", FALSE, + "last_arrowhead", TRUE, + "arrow_shape_a", 4.0, + "arrow_shape_b", 8.0, + "arrow_shape_c", 4.0, + NULL); + setup_item (hiliterubberband); + } + + /* Set USE_HILITE_RUBBER band define at top of file for desired */ + /* behavior */ + if (!USE_HILITE_RUBBERBAND) + gnome_canvas_item_hide (hiliterubberband); + + /* if hilited city isn't also currently selected city, draw the */ + /* hilite marker as well */ + if (index != curselection) { + /* + set_flag_marker ( &hilitemarker, HILITED_COLOR, + points->coords[2], points->coords[3], + &oldhilitex, &oldhilitey ); + */ + +/* gnome_canvas_item_set ( markers[index], */ +/* "fill_color", HILITED_COLOR, */ +/* NULL); */ + + if (hiliteindex >= 0 && hiliteindex != index) { + if (hiliteindex != curselection) + gnome_canvas_item_set ( markers[hiliteindex], + "fill_color", CITY_COLOR, + NULL); + else + gnome_canvas_item_set ( markers[hiliteindex], + "fill_color", SELECTED_COLOR, + NULL); + } + hiliteindex = index; + +/* gnome_canvas_item_show (hilitemarker); */ + } else { +/* gnome_canvas_item_hide (hilitemarker); */ + } + + gnome_canvas_points_free (points); + + gtk_statusbar_pop ( GTK_STATUSBAR (statusbar), 1); + gtk_statusbar_push ( GTK_STATUSBAR (statusbar), 1, loc->zone ); +} + +/* Handles case where cursor leaves the map */ +static int +canvas_event (GtkWidget *canvas, GdkEvent *event, gpointer data) +{ + /* if pointer just left canvas, hide hilite marker(s) */ + if (event->type == GDK_LEAVE_NOTIFY) { +/* if (hilitemarker) */ +/* gnome_canvas_item_hide (hilitemarker); */ + if (hiliterubberband) + gnome_canvas_item_hide (hiliterubberband); + if (hiliteindex >= 0 && hiliteindex != curselection) + gnome_canvas_item_set ( markers[hiliteindex], + "fill_color", CITY_COLOR, + NULL); + + } + return FALSE; +} + +/* Handles as motion and mouse button events in the map */ +static gint +item_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data) +{ + double longitude, latitude; + double item_x, item_y; + int nearest; + + item_x = event->button.x; + item_y = event->button.y; + gnome_canvas_item_w2i (WorldMap->image_item, &item_x, &item_y); + + switch (event->type) { + + /* User selected a new location with a left mouse button press */ + case GDK_BUTTON_PRESS: + switch (event->button.button) { + case 1: + + gnome_map_xlat_screen2map ( WorldMap, item_x, item_y, + &longitude, &latitude ); + + nearest = find_nearest( longitude, latitude ); + + set_selection (nearest, TRUE); + + break; + + default: + break; + } + + break; + + /* highlight city which a button press will select */ + case GDK_MOTION_NOTIFY: + + gnome_map_xlat_screen2map ( WorldMap, item_x, item_y, + &longitude, &latitude); + + nearest = find_nearest( longitude, latitude ); + set_hilited (nearest, item_x, item_y); + break; + + default: + break; + } + + return FALSE; +} + +/* Handles events for the clist of locations */ +static void +list_select_event ( GtkWidget *clist, gint row, gint column, + GdkEventButton *event, gpointer data) +{ + + gchar *text; + gint index; + + /* should we do anything? */ + if (ignore_locationlist_selectevents) + return; + + /* msf - always read zero because sometimes col == -1 if they select */ + /* without a mouse click (ie. keyboard navigation ) */ + gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text); + + /* Just prints some information about the selected row */ + g_print("You selected row %d. More specifically you clicked in column %d, and the text in this cell is %s\n\n", row, column, text); + + index = find_location (text); + if (index < 0) + return; + + set_selection (index, FALSE); + return; +} + + +static GnomeCanvasItem * +draw_city_marker ( GnomeMap *map, double longitude, double latitude) +{ + double x, y; + GnomeCanvasItem *item; + GnomeCanvasGroup *canvas_root; + + canvas_root = gnome_canvas_root (GNOME_CANVAS (map->canvas)); + + gnome_map_xlat_map2screen (map, longitude, latitude, &x, &y); + +#define RAD 1 +#ifdef ELLIPSE + item = gnome_canvas_item_new (canvas_root, + gnome_canvas_ellipse_get_type (), + "x1", x-RAD, + "y1", y-RAD, + "x2", x+RAD, + "y2", y+RAD, + "fill_color", CITY_COLOR, + NULL); +#else + item = gnome_canvas_item_new (canvas_root, + gnome_canvas_dot_get_type (), + "x", x, + "y", y, + "diameter_pixels", RAD, + "fill_color", CITY_COLOR, + NULL); +#endif + + setup_item ( item ); + return item; +} + +static void +draw_cities (GnomeMap *map) +{ + gint i; + + if (markers) + g_free(markers); + + markers = g_new( GnomeCanvasItem *, Locations->len); + for (i=0; i < Locations->len; i++) { + TimeZoneLocation *loc = g_ptr_array_index (Locations, i); + + markers[i] = draw_city_marker (map, loc->longitude, loc->latitude); + } +} + +static void +view_menu_activate (GtkWidget *widget, void *data) +{ + static gint curitem = -1; + gint item = GPOINTER_TO_INT (data); + + double lat1, long1, lat2, long2; + double dlat, dlong; + + if ( item == curitem ) + return; + + curitem = item; + + /* compute aspect correct view and set canvas to it */ + /* we may have to shift view if it extends outside of map */ + if (Views[item].type == LONGITUDE_CONSTRAINT) { + long1 = Views[item].constraint1; + long2 = Views[item].constraint2; + dlong = fabs(long2 - long1); + dlat = dlong/2.0; + lat1 = Views[item].constraint3 - dlat/2.0; + lat2 = Views[item].constraint3 + dlat/2.0; + + if (lat1 < -90.0) { + lat2 -= (lat1-90.0); + lat1 = -90.0; + } else if (lat2 > 90.0) { + lat1 -= (lat2-90.0); + lat2 = 90.0; + } + } else if (Views[item].type == LATITUDE_CONSTRAINT) { + lat1 = Views[item].constraint1; + lat2 = Views[item].constraint2; + dlat = fabs(lat2 - lat1); + dlong = 2.0*dlat; + long1 = Views[item].constraint3 - dlong/2.0; + long2 = Views[item].constraint3 + dlong/2.0; + + if (long1 < -180.0) { + long2 -= (long1-180.0); + long1 = -180.0; + } else if (long2 > 180.0) { + long1 -= (long2-180.0); + long2 = 180.0; + } + } else { + g_warning ("Bad contraint type %d in Views structure item # %d.\n", + item, Views[item].type); + return; + } + + gnome_map_set_view (WorldMap, long1, lat1, long2, lat2); + + /* make locationlist clist entries reflect those visible*/ + create_location_list (&locationlist); + +} + +GtkWidget * +create_view_menu ( void ) +{ + GtkWidget *omenu; + GtkWidget *menu; + GtkWidget *menu_item; + gint i; + + omenu = gtk_option_menu_new (); + + menu = gtk_menu_new (); + + for (i=0; i < numviews; i++) { + menu_item = gtk_menu_item_new_with_label (Views[i].name); + gtk_menu_append (GTK_MENU (menu), menu_item); + + gtk_signal_connect (GTK_OBJECT (menu_item), "activate", + (GtkSignalFunc) view_menu_activate, + GINT_TO_POINTER (i)); + + gtk_widget_show (menu_item); + } + gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu); + gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), 0); + + gtk_widget_show (omenu); + return omenu; +} + +/* returns pointer to the scrolled window containing the clist */ +/* pointer to clist is returned via the passed argument if it doesnt */ +/* already exist. The list is clipped to the current world view */ +static GtkWidget * +create_location_list ( GtkWidget **returnlist ) +{ + TimeZoneLocation *loc; + GtkWidget *scrolledwin; + gchar *titles[] = { "Location", NULL }; + gchar *row[1]; + gint i; + + ignore_locationlist_selectevents = TRUE; + + if ( !*returnlist) { + scrolledwin = gtk_scrolled_window_new (NULL, NULL); + + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + + gtk_widget_show (scrolledwin); + + *returnlist = gtk_clist_new_with_titles (1, titles); + gtk_clist_set_selection_mode (GTK_CLIST(*returnlist), + GTK_SELECTION_BROWSE); + gtk_clist_column_title_passive (GTK_CLIST(*returnlist), 0); + gtk_signal_connect(GTK_OBJECT(*returnlist), "select_row", + GTK_SIGNAL_FUNC(list_select_event), + NULL); + + + gtk_container_add (GTK_CONTAINER (scrolledwin), *returnlist); + } else { + gtk_clist_clear (GTK_CLIST (*returnlist)); + scrolledwin = NULL; + } + + for (i=0; i < Locations->len; i++) { + gint newrow; + + loc = g_ptr_array_index (Locations, i); + if (!gnome_map_is_loc_in_view (WorldMap,loc->longitude,loc->latitude)) + continue; + + row[0] = loc->zone; + newrow = gtk_clist_append (GTK_CLIST (*returnlist), row); + gtk_clist_set_row_data (GTK_CLIST (*returnlist), newrow, + GINT_TO_POINTER (i)); + } + + /* restore selection of location in list now we've recreated it */ + list_mark_location_selected(WorldMap, curselection, TRUE); + + gtk_widget_show (locationlist); + + ignore_locationlist_selectevents = FALSE; + return scrolledwin; +} + + +int +main (int argc, char **argv) +{ + GtkWidget *frame; + GtkWidget *hbox1, *hbox2; + GtkWidget *vbox1, *vbox2; + + GtkWidget *viewcombo; + +/* + tzset (); + printf ("tzname[0]=|%s| tzname[1]=|%s|\n",tzname[0], tzname[1]); +*/ + gnome_init_with_popt_table("gglobe", "0.1", argc, argv, + options, 0, NULL); + + /* load timezone data */ + Locations = loadTZDB (); + if (!Locations) { + g_warning (_("Cannot load timezone data")); + exit (1); + } + + mainwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_position (GTK_WINDOW (mainwindow), GTK_WIN_POS_CENTER); + gtk_window_set_title (GTK_WINDOW (mainwindow), _("gglobe-canvas")); + + gtk_signal_connect (GTK_OBJECT (mainwindow), "destroy", + GTK_SIGNAL_FUNC (gtk_main_quit), NULL); + + /* top-level hbox for packing map/statusbar and view combo/tz list box */ + hbox1 = gtk_hbox_new (FALSE, 2); + gtk_container_add (GTK_CONTAINER (mainwindow), hbox1); + + /* create frame and world map first */ + vbox1 = gtk_vbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (hbox1), vbox1, FALSE, FALSE, 0); + + frame = gtk_frame_new (NULL); + gtk_box_pack_start (GTK_BOX (vbox1), frame, FALSE, FALSE, 0); + + WorldMap = gnome_map_new ( image, mapwidth, mapheight, aa ); + if (!WorldMap) { + g_warning ("Could not create map view."); + exit (1); + } + + setup_item(WorldMap->image_item); + gtk_signal_connect (GTK_OBJECT (WorldMap->canvas), "event", + (GtkSignalFunc) canvas_event, + NULL); + + gtk_container_add (GTK_CONTAINER (frame), WorldMap->canvas); + + statusbar = gtk_statusbar_new (); + gtk_box_pack_start (GTK_BOX (vbox1), statusbar, FALSE, FALSE, 0); + gtk_statusbar_push (GTK_STATUSBAR (statusbar), 1, "Unselected"); + gtk_widget_show (statusbar); + + /* add View combo box */ + frame = gtk_frame_new (NULL); + gtk_box_pack_start (GTK_BOX (hbox1), frame, FALSE, FALSE, 2); + + vbox2 = gtk_vbox_new (FALSE, 2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + + hbox2 = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 2); + + viewcombo = create_view_menu (); + gtk_box_pack_start (GTK_BOX (hbox2), gtk_label_new ("View: "), + FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox2), viewcombo, FALSE, FALSE, 2); + + /* put cities on the world map */ + draw_cities (WorldMap); + + /* add list of all timezones */ + frame = gtk_frame_new (NULL); + gtk_box_pack_start (GTK_BOX (vbox2), + create_location_list (&locationlist), + TRUE, TRUE, 2); + + /* display and wait */ + gtk_widget_show_all (mainwindow); + + /* pick New York City as default */ + set_selection (find_location ("America/New_York"), TRUE); + + gtk_main (); + + return 0; +} + diff --git a/gnome-map/gnome-canvas-dot.c b/gnome-map/gnome-canvas-dot.c new file mode 100644 index 000000000..c69fe030e --- /dev/null +++ b/gnome-map/gnome-canvas-dot.c @@ -0,0 +1,434 @@ +/* Dot item for the GNOME canvas + * + * Copyright (C) 1999 Red Hat, Inc. + * + * Author: Federico Mena <federico@redhat.com> + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <math.h> +#include <gtk/gtkgc.h> +#include "gnome-canvas-dot.h" + + +/* Object argument IDs */ +enum { + ARG_0, + ARG_X, + ARG_Y, + ARG_DIAMETER_PIXELS, + ARG_FILL_COLOR +}; + + +static void gnome_canvas_dot_class_init (GnomeCanvasDotClass *class); +static void gnome_canvas_dot_init (GnomeCanvasDot *dot); +static void gnome_canvas_dot_destroy (GtkObject *object); +static void gnome_canvas_dot_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static void gnome_canvas_dot_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); + +static void gnome_canvas_dot_update (GnomeCanvasItem *item, double *affine, + ArtSVP *clip_svp, int flags); +static void gnome_canvas_dot_unrealize (GnomeCanvasItem *item); +static void gnome_canvas_dot_draw (GnomeCanvasItem *item, GdkDrawable *drawable, + int x, int y, int width, int height); +static double gnome_canvas_dot_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, + GnomeCanvasItem **actual_item); +static void gnome_canvas_dot_bounds (GnomeCanvasItem *item, + double *x1, double *y1, double *x2, double *y2); + + +static GnomeCanvasItemClass *parent_class; + + +/* Private data of the GnomeCanvasDot structure */ +typedef struct { + double x, y; + guint diameter; + + guint fill_color; + + GdkGC *gc; + + guint need_shape_update : 1; + guint need_color_update : 1; +} DotPrivate; + + +/** + * gnome_canvas_dot_get_type: + * @void: + * + * Registers the &GnomeCanvasDot class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GnomeCanvasDot class. + **/ +GtkType +gnome_canvas_dot_get_type (void) +{ + static GtkType dot_type = 0; + + if (!dot_type) { + static const GtkTypeInfo dot_info = { + "GnomeCanvasDot", + sizeof (GnomeCanvasDot), + sizeof (GnomeCanvasDotClass), + (GtkClassInitFunc) gnome_canvas_dot_class_init, + (GtkObjectInitFunc) gnome_canvas_dot_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + dot_type = gtk_type_unique (gnome_canvas_item_get_type (), &dot_info); + } + + return dot_type; +} + + +/* Class initialization function for the dot item */ +static void +gnome_canvas_dot_class_init (GnomeCanvasDotClass *class) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass *) class; + item_class = (GnomeCanvasItemClass *) class; + + parent_class = gtk_type_class (gnome_canvas_item_get_type ()); + + gtk_object_add_arg_type ("GnomeCanvasDot::x", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X); + gtk_object_add_arg_type ("GnomeCanvasDot::y", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y); + gtk_object_add_arg_type ("GnomeCanvasDot::diameter_pixels", + GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_DIAMETER_PIXELS); + gtk_object_add_arg_type ("GnomeCanvasDot::fill_color", + GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_FILL_COLOR); + + object_class->destroy = gnome_canvas_dot_destroy; + object_class->set_arg = gnome_canvas_dot_set_arg; + object_class->get_arg = gnome_canvas_dot_get_arg; + + item_class->update = gnome_canvas_dot_update; + item_class->unrealize = gnome_canvas_dot_unrealize; + item_class->draw = gnome_canvas_dot_draw; + item_class->point = gnome_canvas_dot_point; + item_class->bounds = gnome_canvas_dot_bounds; +} + +/* Object initialization function for the dot item */ +static void +gnome_canvas_dot_init (GnomeCanvasDot *dot) +{ + DotPrivate *priv; + + priv = g_new0 (DotPrivate, 1); + dot->priv = priv; + + priv->x = 0.0; + priv->y = 0.0; + priv->fill_color = 0x000000ff; +} + +/* Destroy handler for the dot item */ +static void +gnome_canvas_dot_destroy (GtkObject *object) +{ + GnomeCanvasDot *dot; + GnomeCanvasItem *item; + DotPrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (GNOME_IS_CANVAS_DOT (object)); + + dot = GNOME_CANVAS_DOT (object); + item = GNOME_CANVAS_ITEM (object); + priv = dot->priv; + + gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); + g_free (priv); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +/* Set_arg handler for the dot item */ +static void +gnome_canvas_dot_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + GnomeCanvasItem *item; + GnomeCanvasDot *dot; + DotPrivate *priv; + char *str; + GdkColor color; + + item = GNOME_CANVAS_ITEM (object); + dot = GNOME_CANVAS_DOT (object); + priv = dot->priv; + + switch (arg_id) { + case ARG_X: + priv->x = GTK_VALUE_DOUBLE (*arg); + priv->need_shape_update = TRUE; + gnome_canvas_item_request_update (item); + break; + + case ARG_Y: + priv->y = GTK_VALUE_DOUBLE (*arg); + priv->need_shape_update = TRUE; + gnome_canvas_item_request_update (item); + break; + + case ARG_DIAMETER_PIXELS: + priv->diameter = GTK_VALUE_UINT (*arg); + priv->need_shape_update = TRUE; + gnome_canvas_item_request_update (item); + break; + + case ARG_FILL_COLOR: + str = GTK_VALUE_STRING (*arg); + g_return_if_fail (str != NULL); + + if (gdk_color_parse (str, &color)) { + priv->fill_color = ((color.red & 0xff00) << 16 | + (color.green & 0xff00) << 8 | + (color.blue & 0xff00) | + 0xff); + priv->need_color_update = TRUE; + gnome_canvas_item_request_update (item); + } + + break; + + default: + break; + } +} + +/* Get_arg handler for the dot item */ +static void +gnome_canvas_dot_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + GnomeCanvasDot *dot; + DotPrivate *priv; + + dot = GNOME_CANVAS_DOT (object); + priv = dot->priv; + + switch (arg_id) { + case ARG_X: + GTK_VALUE_DOUBLE (*arg) = priv->x; + break; + + case ARG_Y: + GTK_VALUE_DOUBLE (*arg) = priv->y; + break; + + case ARG_DIAMETER_PIXELS: + GTK_VALUE_UINT (*arg) = priv->diameter; + break; + + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +/* Update handler for the dot item */ +static void +gnome_canvas_dot_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_svp, int flags) +{ + GnomeCanvasDot *dot; + DotPrivate *priv; + + dot = GNOME_CANVAS_DOT (item); + priv = dot->priv; + + if (parent_class->update) + (* parent_class->update) (item, affine, clip_svp, flags); + + /* Redraw old area if necessary */ + + if (((flags & GNOME_CANVAS_UPDATE_VISIBILITY) + && !(GTK_OBJECT_FLAGS (item) & GNOME_CANVAS_ITEM_VISIBLE)) + || (flags & GNOME_CANVAS_UPDATE_AFFINE) + || priv->need_shape_update) + gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); + + /* Update color if needed */ + if (priv->need_color_update) { + GdkGCValues values; + int mask; + + if (priv->gc) + gtk_gc_release (priv->gc); + + values.foreground.pixel = gnome_canvas_get_color_pixel (item->canvas, + priv->fill_color); + mask = GDK_GC_FOREGROUND; + + priv->gc = gtk_gc_get (gtk_widget_get_visual (GTK_WIDGET (item->canvas))->depth, + gtk_widget_get_colormap (GTK_WIDGET (item->canvas)), + &values, + mask); + + priv->need_color_update = FALSE; + } + + /* If we need a shape update, or if the item changed visibility + * to shown, recompute the bounding box. + */ + if (priv->need_shape_update + || ((flags & GNOME_CANVAS_UPDATE_VISIBILITY) + && (GTK_OBJECT_FLAGS (item) & GNOME_CANVAS_ITEM_VISIBLE)) + || (flags & GNOME_CANVAS_UPDATE_AFFINE)) { + ArtPoint i1, i2, c1, c2; + double d; + double i2c[6]; + + d = priv->diameter / item->canvas->pixels_per_unit; + + i1.x = priv->x - d / 2; + i1.y = priv->y - d / 2; + i2.x = priv->x + d / 2; + i2.y = priv->y + d / 2; + + gnome_canvas_item_i2c_affine (item, i2c); + art_affine_point (&c1, &i1, i2c); + art_affine_point (&c2, &i2, i2c); + + item->x1 = c1.x; + item->y1 = c1.y; + item->x2 = c2.x + 1; + item->y2 = c2.y + 1; + + priv->need_shape_update = FALSE; + } + + /* If the fill our outline changed, we need to redraw, anyways */ + gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); +} + +/* Unrealize handler for the dot item */ +static void +gnome_canvas_dot_unrealize (GnomeCanvasItem *item) +{ + GnomeCanvasDot *dot; + DotPrivate *priv; + + dot = GNOME_CANVAS_DOT (item); + priv = dot->priv; + + if (priv->gc) { + gtk_gc_release (priv->gc); + priv->gc = NULL; + } + + if (parent_class->unrealize) + (* parent_class->unrealize) (item); +} + +/* Draw handler for the dot item */ +static void +gnome_canvas_dot_draw (GnomeCanvasItem *item, GdkDrawable *drawable, + int x, int y, int width, int height) +{ + GnomeCanvasDot *dot; + DotPrivate *priv; + double i2c[6]; + ArtPoint i, c; + int x1, y1; + + dot = GNOME_CANVAS_DOT (item); + priv = dot->priv; + + i.x = priv->x; + i.y = priv->y; + + gnome_canvas_item_i2c_affine (item, i2c); + art_affine_point (&c, &i, i2c); + + x1 = floor (c.x - priv->diameter / 2.0 + 0.5) - x; + y1 = floor (c.y - priv->diameter / 2.0 + 0.5) - y; + + gdk_draw_arc (drawable, + priv->gc, + TRUE, + x1, y1, + priv->diameter, + priv->diameter, + 0 * 64, + 360 * 64); + + gdk_draw_arc (drawable, + priv->gc, + FALSE, + x1, y1, + priv->diameter, + priv->diameter, + 0 * 64, + 360 * 64); +} + +/* Point handler for the dot item */ +static double +gnome_canvas_dot_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, + GnomeCanvasItem **actual_item) +{ + GnomeCanvasDot *dot; + DotPrivate *priv; + double d; + double dx, dy, dist; + + dot = GNOME_CANVAS_DOT (item); + priv = dot->priv; + + *actual_item = item; + + d = priv->diameter / item->canvas->pixels_per_unit; + + dx = x - priv->x; + dy = y - priv->y; + dist = sqrt (dx * dx + dy * dy); + + if (dist <= d / 2.0) + return 0.0; + else + return dist - d / 2.0; +} + +/* Bounds handler for the dot item */ +static void +gnome_canvas_dot_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) +{ + GnomeCanvasDot *dot; + DotPrivate *priv; + double d; + + dot = GNOME_CANVAS_DOT (item); + priv = dot->priv; + + d = priv->diameter / item->canvas->pixels_per_unit; + + *x1 = priv->x - d / 2.0; + *y1 = priv->y - d / 2.0; + *x2 = priv->x + d / 2.0; + *y2 = priv->y + d / 2.0; +} diff --git a/gnome-map/gnome-canvas-dot.h b/gnome-map/gnome-canvas-dot.h new file mode 100644 index 000000000..fc748a562 --- /dev/null +++ b/gnome-map/gnome-canvas-dot.h @@ -0,0 +1,60 @@ +/* Dot item for the GNOME canvas + * + * Copyright (C) 1999 Red Hat, Inc. + * + * Author: Federico Mena <federico@redhat.com> + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef GNOME_CANVAS_DOT_H +#define GNOME_CANVAS_DOT_H + +#include <libgnome/gnome-defs.h> +#include <libgnomeui/gnome-canvas.h> + + +BEGIN_GNOME_DECLS + + +#define GNOME_TYPE_CANVAS_DOT (gnome_canvas_dot_get_type ()) +#define GNOME_CANVAS_DOT(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_DOT, \ + GnomeCanvasDot)) +#define GNOME_CANVAS_DOT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_DOT, \ + GnomeCanvasDotClass)) +#define GNOME_IS_CANVAS_DOT(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_DOT)) +#define GNOME_IS_CANVAS_DOT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_DOT)) + + +typedef struct _GnomeCanvasDot GnomeCanvasDot; +typedef struct _GnomeCanvasDotClass GnomeCanvasDotClass; + +struct _GnomeCanvasDot { + GnomeCanvasItem item; + + gpointer priv; +}; + +struct _GnomeCanvasDotClass { + GnomeCanvasItemClass parent_class; +}; + + +GtkType gnome_canvas_dot_get_type (void); + + +END_GNOME_DECLS + +#endif diff --git a/gnome-map/gnome-map.c b/gnome-map/gnome-map.c new file mode 100644 index 000000000..31aa0239d --- /dev/null +++ b/gnome-map/gnome-map.c @@ -0,0 +1,327 @@ +/* GNOME canvas based interface to a map using a simple cylindrical proj */ +/* */ +/* Copyright (C) 1999 Red Hat, Incorportated */ +/* Original work by Michael Fulbright <drmike@redhat.com> */ + +#include <gnome.h> +#include <math.h> +#include "gnome-map.h" + +/* look in <gdk/gdkcursors.h> for valid values */ +#define MAP_CURSOR GDK_LEFT_PTR + +/** + * gnome_map_set_image: + * @map: Map to apply image to. + * @imagefile: Filename of image for map. + * + * This function sets the image used for the map to @imagefile. It is + * assumed that this image is a simple cylindrical projection. + * + * Return value: 0 on success, -1 if image could not be loaded + **/ +static gint +gnome_map_set_image ( GnomeMap *map, gchar *imagefile ) +{ + + g_return_val_if_fail ( map != NULL, -1 ); + g_return_val_if_fail ( map->image == NULL, -1 ); + + /* load map image */ + if (map->aa) + map->image = gnome_canvas_load_alpha (imagefile); + else + map->image = gdk_imlib_load_image (imagefile); + + if (!map->image) + return -1; + + return 0; +} + + +static void +canvas_realize_event (GtkWidget *canvas, gpointer *data) +{ + + GdkCursor *ptrcursor; + + ptrcursor = gdk_cursor_new (MAP_CURSOR); + if (!ptrcursor) { + g_warning ("Unable to load new cursor %d for map\n", MAP_CURSOR); + return; + } + + gdk_window_set_cursor (canvas->window, ptrcursor); + + gdk_cursor_destroy (ptrcursor); +} + +/** + * gnome_map_new: + * @imagefile: File to be used map image. + * @width: Width of map view in pixels. + * @height: Height of map view in pixels. + * @antialias: Boolean used to set map to use antialias canvas or not. + * + * Creates a new map, using anti-aliased or normal canvas based on the + * value of @antialias. Of anti-aliased maps the image file must be + * in PNG format (this is a gnome-canvas limitation as of gnome-libs 1.0.10). + * If @width and @height are both <= 0, then the map image size is used. + * If only one of @width or @height is > 0, then the unspecified + * dimension is scaled (perserving the aspect of the original image). + * + * Return value: The newly-created map structure or NULL if image couldn't + * be loaded. + **/ +GnomeMap * +gnome_map_new ( gchar *imagefile, gint width, gint height, gboolean aa ) +{ + GnomeCanvasGroup *canvas_root; + GnomeMap *map; + gint h, w; + + map = g_new0 ( GnomeMap, 1 ); + map->aa = aa; + + if ( gnome_map_set_image ( map, imagefile ) < 0 ) { + g_free (map); + return NULL; + } + + /* create a canvas */ + if (aa) { + gtk_widget_push_visual (gdk_rgb_get_visual ()); + gtk_widget_push_colormap (gdk_rgb_get_cmap ()); + map->canvas = gnome_canvas_new_aa (); + } else { + gtk_widget_push_visual (gdk_imlib_get_visual ()); + gtk_widget_push_colormap (gdk_imlib_get_colormap ()); + map->canvas = gnome_canvas_new (); + } + + /* set map size and scaling */ + if ( width <= 0 && height <= 0 ) { + w = map->image->rgb_width; + h = map->image->rgb_height; + } else if ( width > 0 && height <= 0 ) { + w = width; + h = (int)(((float)w/(float)map->image->rgb_width)*map->image->rgb_height); + } else if ( width <= 0 && height > 0 ) { + h = height; + w = (int)(((float)h/(float)map->image->rgb_height)*map->image->rgb_width); + } else { + w = width; + h = height; + } + + map->width = w; + map->height = h; + map->long1 = -180.0; + map->lat1 = -90.0; + map->long2 = 180.0; + map->lat2 = 90.0; + + gtk_widget_set_usize (map->canvas, w, h); + gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (map->canvas), 1.0); + gnome_canvas_set_scroll_region (GNOME_CANVAS (map->canvas), + 0.0, 0.0, + (double)w, (double)h); + + gtk_widget_show(map->canvas); + + /* Setup canvas items */ + canvas_root = gnome_canvas_root (GNOME_CANVAS (map->canvas)); + map->image_item = gnome_canvas_item_new (canvas_root, + gnome_canvas_image_get_type (), + "image", map->image, + "x", 0.0, + "y", 0.0, + "width", (double) w, + "height", (double) h, + "anchor", GTK_ANCHOR_NW, + NULL); + + /* grap realize signal so we can set cursor for map */ + gtk_signal_connect (GTK_OBJECT (map->canvas), "realize", + (GtkSignalFunc) canvas_realize_event, + NULL); + + /* restore to original */ + gtk_widget_pop_colormap (); + gtk_widget_pop_visual (); + + return map; +} + + +/** + * gnome_map_get_image_size: Get the unscaled image size of map image. + * @map: The map which image size is desired for. + * @width: Width of map in pixels. + * @height: Height of map in pixels. + * + * Given the GnomeMap @map, this function returns the dimensions of the + * original unscaled map image. + * + * Return value: None. + **/ +void +gnome_map_get_image_size ( GnomeMap *map, gint *width, gint *height ) +{ + g_return_if_fail ( map != NULL || map->image != NULL); + g_return_if_fail ( width != NULL || height != NULL ); + + *width = map->image->rgb_width; + *height = map->image->rgb_width; +} + +/** + * gnome_map_set_size: Set screen dimensions (in pixels) of map view. + * @map: Map to apply dimensions to. + * @width: Desired width of map view. + * @height: Desired height of map view. + * + * Given a map which has an image associated with it via the + * gnome_map_set_image() call, set the onscreen size of the map view widget. + * + * Return value: None. + **/ +void +gnome_map_set_size ( GnomeMap *map, gint width, gint height ) +{ + g_return_if_fail ( map != NULL ); + g_return_if_fail ( map->canvas != NULL ); + g_return_if_fail ( map->image != NULL ); + g_return_if_fail ( width > 0 ); + g_return_if_fail ( height > 0 ); +} + + + +/** + * gnome_map_xlat_map2screen: Convert from map coordinates to screen coordinates. + * @map: Map to apply dimensions to. + * @longitude: Longitude coordinate to convert (in degrees). + * @latitude: Latitude coordinate to convert (in degrees). + * @sx: Converted screen coordinate. + * @sy: Converted screen coordinate. + * + * A (longitude, latitude) pair is converted to a (x, y) canvas coordinate. + * (An obvious improvement to the gnome-map would be to just let the + * canvas do the mapping internally. If this change is made this function + * will still work but will be a small stub). + * + * Return value: None. + **/ +void +gnome_map_xlat_map2screen ( GnomeMap *map, + double longitude, double latitude, + double *sx, double *sy ) +{ + g_return_if_fail ( map != NULL ); + + *sx = (map->width/2.0 + (map->width/2.0)*longitude/180.0); + *sy = (map->height/2.0 - (map->height/2.0)*latitude/90.0); +} + + +/** + * gnome_map_xlat_screen2map: Convert from screen coordinates to map coordinates. + * @map: Map to apply dimensions to. + * @sx: Screen coordinate to convert. + * @sy: Screen coordinate to convert. + * @longitude: Converted longitude coordinate (in degrees). + * @latitude: Converted latitude coordinate (in degrees). + * + * A (x, y) canvas coordinate is converted to a (longitude, latitude) pair. + * (An obvious improvement to the gnome-map would be to just let the + * canvas do the mapping internally. If this change is made this function + * will still work but will be a small stub). + * + * Return value: None. + **/ +void +gnome_map_xlat_screen2map ( GnomeMap *map, + double sx, double sy, + double *longitude, double *latitude) +{ + g_return_if_fail ( map != NULL ); + + *longitude = ( sx - (double)map->width/2.0)/((double)map->width/2.0)*180.0; + *latitude = ((double)map->height/2.0-sy)/((double)map->height/2.0)*90.0; +} + +/** + * gnome_map_set_view: Set view of map in map coordinates. + * @map: Map to apply dimensions to. + * @longitude1: Longitude of corner 1. + * @latitude1: Latitude of corner 1. + * @longitude2: Longitude of corner 2. + * @latitude2: Latitude of corner 2. + * + * Sets view of map to a box defined by the two corners given in map + * coordinates. + * + * Return value: None. + **/ +void +gnome_map_set_view ( GnomeMap *map, + double longitude1, double latitude1, + double longitude2, double latitude2) +{ + double x1, y1, x2, y2; + double scale; + + g_return_if_fail ( map != NULL ); + g_return_if_fail ( longitude1 >= -180.0 && longitude1 <= 180.0 ); + g_return_if_fail ( longitude2 >= -180.0 && longitude2 <= 180.0 ); + g_return_if_fail ( latitude1 >= -90.0 && latitude1 <= 90.0 ); + g_return_if_fail ( latitude2 >= -90.0 && latitude2 <= 90.0 ); + + + gnome_map_xlat_map2screen (map, longitude1, latitude1, &x1, &y1); + gnome_map_xlat_map2screen (map, longitude2, latitude2, &x2, &y2); + + gnome_canvas_set_scroll_region (GNOME_CANVAS(map->canvas), + x1, y1, x2, y2); + + if (longitude1 < longitude2) { + map->long1 = longitude1; + map->long2 = longitude2; + } else { + map->long1 = longitude2; + map->long2 = longitude1; + } + + if (latitude1 < latitude2) { + map->lat1 = latitude1; + map->lat2 = latitude2; + } else { + map->lat1 = latitude2; + map->lat2 = latitude1; + } + + scale = ((double)map->width)/fabs(x1-x2); + gnome_canvas_set_pixels_per_unit (GNOME_CANVAS(map->canvas), scale); + +} + +/** + * gnome_map_is_loc_in_view: Test to see if location is on current view + * @map: Map to apply dimensions to. + * @longitude: Longitude of location to test. + * @latitude: Latitude of location to test. + * + * Tests whether (longitude, latitude) is within current map view. + * + * Return value: TRUE is visible, FALSE if not. + **/ +gboolean +gnome_map_is_loc_in_view (GnomeMap *map, double longitude, double latitude) +{ + + return !(longitude < map->long1 || longitude > map->long2 || + latitude < map->lat1 || latitude > map->lat2); +} + diff --git a/gnome-map/gnome-map.h b/gnome-map/gnome-map.h new file mode 100644 index 000000000..a0c2e77ce --- /dev/null +++ b/gnome-map/gnome-map.h @@ -0,0 +1,59 @@ +/* GNOME canvas based interface to a map using a simple cylindrical proj */ +/* */ +/* Copyright (C) 1999 Red Hat, Incorportated */ +/* Original work by Michael Fulbright <drmike@redhat.com> */ + +#ifndef _GNOME_MAP_H_ +#define _GNOME_MAP_H_ + +struct _GnomeMapStruct { + GtkWidget *canvas; /* canvas object used to display map */ + + gboolean aa; /* true if antialiased */ + + gint width; /* width of canvas in pixels */ + gint height; /* height of canvas in pixels */ + double long1; /* long1, lat1 is lower left corner of view */ + double lat1; + double long2; /* long2, lat2 is upper right corner of view */ + double lat2; + + GdkImlibImage *image; /* actual image data */ + GnomeCanvasItem *image_item; /* background image canvas object */ + void *data; /* extra stuff */ +}; + +typedef struct _GnomeMapStruct GnomeMap; + + +/* create new map */ +GnomeMap *gnome_map_new ( gchar *imagefile, + gint width, gint height, + gboolean antialias ); + +/* set background map image used by map */ +/*gint gnome_map_set_image ( GnomeMap *map, gchar *imagefile ); */ + +/* get original size of map image */ +/*void gnome_map_get_image_size ( GnomeMap *map, gint *width, gint *height ); */ + +/* set/get size of view in pixels */ +/*void gnome_map_set_size ( GnomeMap *map, gint width, gint height );*/ +void gnome_map_get_size ( GnomeMap *map, gint *width, gint *height ); + +/* utility functions to go from screen coords to map coords */ +void gnome_map_xlat_map2screen ( GnomeMap *map, + double longitude, double latitude, + double *sx, double *sy ); +void gnome_map_xlat_screen2map ( GnomeMap *map, + double sx, double sy, + double *longitude, double *latitude ); +void gnome_map_set_view (GnomeMap *map, + double longitude1, double latitude1, + double longitude2, double latitude2); + +gboolean gnome_map_is_loc_in_view (GnomeMap *map, + double longitude, double latitude); +#endif + + diff --git a/gnome-map/map480.png b/gnome-map/map480.png Binary files differnew file mode 100644 index 000000000..e41835b77 --- /dev/null +++ b/gnome-map/map480.png diff --git a/gnome-map/pygtk.h b/gnome-map/pygtk.h new file mode 100644 index 000000000..f43c30131 --- /dev/null +++ b/gnome-map/pygtk.h @@ -0,0 +1,334 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- */ +#ifndef _PYGTK_H_ +#define _PYGTK_H_ + +#include <Python.h> +#include <gtk/gtk.h> + +struct _PyGtk_FunctionStruct { + char *pygtkVersion; + gboolean fatalExceptions; + + void (* blockThreads)(void); + void (* unblockThreads)(void); + + GtkDestroyNotify destroyNotify; + GtkCallbackMarshal callbackMarshal; + PyObject *(* argsAsTuple)(int nparams, GtkArg *args); + int (* argsFromSequence)(GtkArg *args, int nparams, PyObject *seq); + int (* argFromPyObject)(GtkArg *arg, PyObject *obj); + PyObject *(* argAsPyObject)(GtkArg *arg); + void (* retFromPyObject)(GtkArg *ret, PyObject *obj); + PyObject *(* retAsPyObject)(GtkArg *ret); + GtkArg *(* dictAsGtkArgs)(PyObject *dict, GtkType type, gint *nargs); + void (* registerBoxed)(GtkType boxed_type, + PyObject *(*from_func)(gpointer boxed), + int (*to_func)(gpointer *boxed, PyObject *obj)); + + gint (* enum_get_value)(GtkType enum_type, PyObject *obj, int *val); + gint (* flag_get_value)(GtkType enum_type, PyObject *obj, int *val); + + PyTypeObject *gtk_type; + PyObject *(* gtk_new)(GtkObject *obj); + + PyTypeObject *gtkAccelGroup_type; + PyObject *(*gtkAccelGroup_new)(GtkAccelGroup *ag); + + PyTypeObject *gtkStyle_type; + PyObject *(* gtkStyle_new)(GtkStyle *style); + + PyTypeObject *gdkFont_type; + PyObject *(* gdkFont_new)(GdkFont *font); + + PyTypeObject *gdkColor_type; + PyObject *(* gdkColor_new)(GdkColor *colour); + + PyTypeObject *gdkEvent_type; + PyObject *(* gdkEvent_new)(GdkEvent *event); + + PyTypeObject *gdkWindow_type; + PyObject *(* gdkWindow_new)(GdkWindow *win); + + PyTypeObject *gdkGC_type; + PyObject *(* gdkGC_new)(GdkGC *gc); + + PyTypeObject *gdkColormap_type; + PyObject *(* gdkColormap_new)(GdkColormap *colourmap); + + PyTypeObject *gdkDragContext_type; + PyObject *(* gdkDragContext_new)(GdkDragContext *ctx); + + PyTypeObject *gtkSelectionData_type; + PyObject *(* gtkSelectionData_new)(GtkSelectionData *data); + + PyTypeObject *gdkAtom_type; + PyObject *(* gdkAtom_new)(GdkAtom atom); + + PyTypeObject *gdkCursor_type; + PyObject *(* gdkCursor_new)(GdkCursor *cursor); + + PyTypeObject *gtkCTreeNode_type; + PyObject *(* gtkCTreeNode_new)(GtkCTreeNode *node); +}; + +/* structure definitions for the various object types in PyGTK */ +typedef struct { + PyObject_HEAD + GtkObject *obj; +} PyGtk_Object; + +typedef struct { + PyObject_HEAD + GtkAccelGroup *obj; +} PyGtkAccelGroup_Object; + +typedef struct { + PyObject_HEAD + GtkStyle *obj; +} PyGtkStyle_Object; + +typedef struct { + PyObject_HEAD + GdkFont *obj; +} PyGdkFont_Object; + +typedef struct { + PyObject_HEAD + GdkColor obj; +} PyGdkColor_Object; + +typedef struct { + PyObject_HEAD + GdkEvent *obj; + PyObject *attrs; +} PyGdkEvent_Object; + +typedef struct { + PyObject_HEAD + GdkWindow *obj; +} PyGdkWindow_Object; + +typedef struct { + PyObject_HEAD + GdkGC *obj; +} PyGdkGC_Object; + +typedef struct { + PyObject_HEAD + GdkColormap *obj; +} PyGdkColormap_Object; + +typedef struct { + PyObject_HEAD + GdkDragContext *obj; +} PyGdkDragContext_Object; + +typedef struct { + PyObject_HEAD + GtkSelectionData *obj; +} PyGtkSelectionData_Object; + +typedef struct { + PyObject_HEAD + gchar *name; + GdkAtom atom; +} PyGdkAtom_Object; + +typedef struct { + PyObject_HEAD + GdkCursor *obj; +} PyGdkCursor_Object; + +typedef struct { + PyObject_HEAD + GtkCTreeNode *node; +} PyGtkCTreeNode_Object; + +/* routines to get the C object value out of the PyObject wrapper */ +#define PyGtk_Get(v) (((PyGtk_Object *)(v))->obj) +#define PyGtkAccelGroup_Get(v) (((PyGtkAccelGroup_Object *)(v))->obj) +#define PyGtkStyle_Get(v) (((PyGtkStyle_Object *)(v))->obj) +#define PyGdkFont_Get(v) (((PyGdkFont_Object *)(v))->obj) +#define PyGdkColor_Get(v) (&((PyGdkColor_Object *)(v))->obj) +#define PyGdkEvent_Get(v) (((PyGdkEvent_Object *)(v))->obj) +#define PyGdkWindow_Get(v) (((PyGdkWindow_Object *)(v))->obj) +#define PyGdkGC_Get(v) (((PyGdkGC_Object *)(v))->obj) +#define PyGdkColormap_Get(v) (((PyGdkColormap_Object *)(v))->obj) +#define PyGdkDragContext_Get(v) (((PyGdkDragContext_Object *)(v))->obj) +#define PyGtkSelectionData_Get(v) (((PyGtkSelectionData_Object *)(v))->obj) +#define PyGdkAtom_Get(v) (((PyGdkAtom_Object *)(v))->atom) +#define PyGdkCursor_Get(v) (((PyGdkCursor_Object *)(v))->obj) +#define PyGtkCTreeNode_Get(v) (((PyGtkCTreeNode_Object *)(v))->node) + +/* this section is dependent on whether we are being included from gtkmodule.c + * or not. A similar source level interface should be provided in both + * instances. */ +#ifdef _INSIDE_PYGTK_ +staticforward PyTypeObject PyGtk_Type; +staticforward PyTypeObject PyGtkAccelGroup_Type; +staticforward PyTypeObject PyGtkStyle_Type; +staticforward PyTypeObject PyGdkFont_Type; +staticforward PyTypeObject PyGdkColor_Type; +staticforward PyTypeObject PyGdkEvent_Type; +staticforward PyTypeObject PyGdkWindow_Type; +staticforward PyTypeObject PyGdkGC_Type; +staticforward PyTypeObject PyGdkColormap_Type; +staticforward PyTypeObject PyGdkDragContext_Type; +staticforward PyTypeObject PyGtkSelectionData_Type; +staticforward PyTypeObject PyGdkAtom_Type; +staticforward PyTypeObject PyGdkCursor_Type; +staticforward PyTypeObject PyGtkCTreeNode_Type; + +/* check the type of a PyObject */ +#define PyGtk_Check(v) ((v)->ob_type == &PyGtk_Type) +#define PyGtkAccelGroup_Check(v) ((v)->ob_type == &PyGtkAccelGroup_Type) +#define PyGtkStyle_Check(v) ((v)->ob_type == &PyGtkStyle_Type) +#define PyGdkFont_Check(v) ((v)->ob_type == &PyGdkFont_Type) +#define PyGdkColor_Check(v) ((v)->ob_type == &PyGdkColor_Type) +#define PyGdkEvent_Check(v) ((v)->ob_type == &PyGdkEvent_Type) +#define PyGdkWindow_Check(v) ((v)->ob_type == &PyGdkWindow_Type) +#define PyGdkGC_Check(v) ((v)->ob_type == &PyGdkGC_Type) +#define PyGdkColormap_Check(v) ((v)->ob_type == &PyGdkColormap_Type) +#define PyGdkDragContext_Check(v) ((v)->ob_type == &PyGdkDragContext_Type) +#define PyGtkSelectionData_Check(v) ((v)->ob_type == &PyGtkSelectionData_Type) +#define PyGdkAtom_Check(v) ((v)->ob_type == &PyGdkAtom_Type) +#define PyGdkCursor_Check(v) ((v)->ob_type == &PyGdkCursor_Type) +#define PyGtkCTreeNode_Check(v) ((v)->ob_type == &PyGtkCTreeNode_Type) + +/* constructors for PyObject wrappers ... */ +static PyObject *PyGtk_New(GtkObject *obj); +static PyObject *PyGtkAccelGroup_New(GtkAccelGroup *obj); +static PyObject *PyGtkStyle_New(GtkStyle *style); +static PyObject *PyGdkFont_New(GdkFont *font); +static PyObject *PyGdkColor_New(GdkColor *colour); +static PyObject *PyGdkEvent_New(GdkEvent *event); +static PyObject *PyGdkWindow_New(GdkWindow *window); +static PyObject *PyGdkGC_New(GdkGC *gc); +static PyObject *PyGdkColormap_New(GdkColormap *colourmap); +static PyObject *PyGdkDragContext_New(GdkDragContext *ctx); +static PyObject *PyGtkSelectionData_New(GtkSelectionData *data); +static PyObject *PyGdkAtom_New(GdkAtom atom); +static PyObject *PyGdkCursor_New(GdkCursor *cursor); +static PyObject *PyGtkCTreeNode_New(GtkCTreeNode *node); + +/* miscelaneous functions */ +static void PyGtk_BlockThreads(void); +static void PyGtk_UnblockThreads(void); +static void PyGtk_DestroyNotify(gpointer data); +static void PyGtk_CallbackMarshal(GtkObject *o, gpointer d, guint nargs, + GtkArg *args); +static PyObject *GtkArgs_AsTuple(int nparams, GtkArg *args); +static int GtkArgs_FromSequence(GtkArg *args, int nparams, PyObject *seq); +static int GtkArg_FromPyObject(GtkArg *arg, PyObject *obj); +static PyObject *GtkArg_AsPyObject(GtkArg *arg); +static void GtkRet_FromPyObject(GtkArg *ret, PyObject *py_ret); +static PyObject *GtkRet_AsPyObject(GtkArg *arg); +static GtkArg *PyDict_AsGtkArgs(PyObject *dict, GtkType type, gint *nargs); + +static void PyGtk_RegisterBoxed(GtkType boxed_type, + PyObject *(*fromarg)(gpointer boxed), + int (*toarg)(gpointer *boxed, PyObject *obj)); +gint PyGtkEnum_get_value(GtkType enum_type, PyObject *obj, int *val); +gint PyGtkFlag_get_value(GtkType enum_type, PyObject *obj, int *val); + +static gboolean PyGtk_FatalExceptions = FALSE; + +#else + +/* for multi file extensions, define one of these in all but the main file + * of the module */ +#if defined(NO_IMPORT) || defined(NO_IMPORT_PYGTK) +extern struct _PyGtk_FunctionStruct *_PyGtk_API; +#else +struct _PyGtk_FunctionStruct *_PyGtk_API; +#endif + +/* type objects */ +#define PyGtk_Type *(_PyGtk_API->gtk_type) +#define PyGtkAccelGroup_Type *(_PyGtk_API->gtkAccelGroup_type) +#define PyGtkStyle_Type *(_PyGtk_API->gtkStyle_type) +#define PyGdkFont_Type *(_PyGtk_API->gdkFont_type) +#define PyGdkColor_Type *(_PyGtk_API->gdkColor_type) +#define PyGdkEvent_Type *(_PyGtk_API->gdkEvent_type) +#define PyGdkWindow_Type *(_PyGtk_API->gdkWindow_type) +#define PyGdkGC_Type *(_PyGtk_API->gdkGC_type) +#define PyGdkColormap_Type *(_PyGtk_API->gdkColormap_type) +#define PyGdkDragContext_Type *(_PyGtk_API->gdkDragContext_type) +#define PyGtkSelectionData_Type *(_PyGtk_API->gtkSelectionData_type) +#define PyGdkAtom_Type *(_PyGtk_API->gdkAtom_type) +#define PyGdkCursor_Type *(_PyGtk_API->gdkCursor_type) +#define PyGtkCTreeNode_Type *(_PyGtk_API->gtkCTreeNode_type) + +/* type checking routines */ +#define PyGtk_Check(v) ((v)->ob_type == _PyGtk_API->gtk_type) +#define PyGtkAccelGroup_Check(v) ((v)->ob_type == _PyGtk_API->gtkAccelGroup_type) +#define PyGtkStyle_Check(v) ((v)->ob_type == _PyGtk_API->gtkStyle_type) +#define PyGdkFont_Check(v) ((v)->ob_type == _PyGtk_API->gdkFont_type) +#define PyGdkColor_Check(v) ((v)->ob_type == _PyGtk_API->gdkColor_type) +#define PyGdkEvent_Check(v) ((v)->ob_type == _PyGtk_API->gdkEvent_type) +#define PyGdkWindow_Check(v) ((v)->ob_type == _PyGtk_API->gdkWindow_type) +#define PyGdkGC_Check(v) ((v)->ob_type == _PyGtk_API->gdkGC_type) +#define PyGdkColormap_Check(v) ((v)->ob_type == _PyGtk_API->gdkColormap_type) +#define PyGdkDragContext_Check(v) ((v)->ob_type == _PyGtk_API->gdkDragContext_type) +#define PyGtkSelectionData_Check(v) ((v)->ob_type == _PyGtk_API->gtkSelectionData_type) +#define PyGdkAtom_Check(v) ((v)->ob_type == _PyGtk_API->gdkAtom_type) +#define PyGdkCursor_Check(v) ((v)->ob_type == _PyGtk_API->gdkCursor_type) +#define PyGtkCTreeNode_Check(v) ((v)->ob_type == _PyGtk_API->GtkCTreeNode_type) + +/* type objects */ +#define PyGtk_New (_PyGtk_API->gtk_new) +#define PyGtkAccelGroup_New (_PyGtk_API->gtkAccelGroup_new) +#define PyGtkStyle_New (_PyGtk_API->gtkStyle_new) +#define PyGdkFont_New (_PyGtk_API->gdkFont_new) +#define PyGdkColor_New (_PyGtk_API->gdkColor_new) +#define PyGdkEvent_New (_PyGtk_API->gdkEvent_new) +#define PyGdkWindow_New (_PyGtk_API->gdkWindow_new) +#define PyGdkGC_New (_PyGtk_API->gdkGC_new) +#define PyGdkColormap_New (_PyGtk_API->gdkColormap_new) +#define PyGdkDragContext_New (_PyGtk_API->gdkDragContext_new) +#define PyGtkSelectionData_New (_PyGtk_API->gtkSelectionData_new) +#define PyGdkAtom_New (_PyGtk_API->gdkAtom_new) +#define PyGdkCursor_New (_PyGtk_API->gdkCursor_new) +#define PyGtkCTreeNode_New (_PyGtk_API->gtkCTreeNode_new) + +/* miscelaneous other functions */ +#define PyGtk_BlockThreads (_PyGtk_API->blockThreads) +#define PyGtk_UnblockThreads (_PyGtk_API->unblockThreads) +#define PyGtk_DestroyNotify (_PyGtk_API->destroyNotify) +#define PyGtk_CallbackMarshal (_PyGtk_API->callbackMarshal) +#define GtkArgs_AsTuple (_PyGtk_API->argsAsTuple) +#define GtkArgs_FromSequence (_PyGtk_API->argsFromSequence) +#define GtkArg_FromPyObject (_PyGtk_API->argFromPyObject) +#define GtkArg_AsPyObject (_PyGtk_API->argAsPyObject) +#define GtkRet_FromPyObject (_PyGtk_API->retFromPyObject) +#define GtkRet_AsPyObject (_PyGtk_API->retAsPyObject) +#define PyDict_AsGtkArgs (_PyGtk_API->dictAsGtkArgs) +#define PyGtk_RegisterBoxed (_PyGtk_API->registerBoxed) +#define PyGtkEnum_get_value (_PyGtk_API->enum_get_value) +#define PyGtkFlag_get_value (_PyGtk_API->flag_get_value) + +/* some variables */ +#define PyGtk_FatalExceptions (_PyGtk_API->fatalExceptions) +#define PYGTK_VERSION (_PyGtk_API->pygtkVersion) + +/* a function to initialise the pygtk functions */ +#define init_pygtk() { \ + PyObject *pygtk = PyImport_ImportModule("_gtk"); \ + if (pygtk != NULL) { \ + PyObject *module_dict = PyModule_GetDict(pygtk); \ + PyObject *cobject = PyDict_GetItemString(module_dict, "_PyGtk_API"); \ + if (PyCObject_Check(cobject)) \ + _PyGtk_API = PyCObject_AsVoidPtr(cobject); \ + else { \ + Py_FatalError("could not find _PyGtk_API object"); \ + return; \ + } \ + } else { \ + Py_FatalError("could not import _gtk"); \ + return; \ + } \ +} + +#endif + +#endif /* !_PYGTK_H_ */ diff --git a/gnome-map/pytimezone b/gnome-map/pytimezone new file mode 100755 index 000000000..dc05e7938 --- /dev/null +++ b/gnome-map/pytimezone @@ -0,0 +1,40 @@ +#!/usr/bin/python + +import timezonemap +from gtk import * +import GdkImlib +from gnome.ui import * + +class Map (GnomeCanvas): + def __init__ (self, map): + self._o = map + +class List (GtkScrolledWindow): + def __init__ (self, list): + self._o = list + +class Status (GtkStatusbar): + def __init__ (self, bar): + self._o = bar + +class Option (GtkOptionMenu): + def __init__ (self, option): + self._o = option + +win = GtkWindow() +vbox = GtkVBox (FALSE, 10) + +tz = timezonemap.new () +map = Map (tz.map) +list = List (tz.citylist) +option = Option (tz.views) +status = Status (tz.statusbar) +vbox.pack_start (option, FALSE) +vbox.pack_start (map, FALSE) +vbox.pack_start (status, FALSE) +vbox.pack_start (list) +win.add (vbox) +win.show_all () + +mainloop () + diff --git a/gnome-map/testtz.c b/gnome-map/testtz.c new file mode 100644 index 000000000..e70cbc193 --- /dev/null +++ b/gnome-map/testtz.c @@ -0,0 +1,11 @@ +#include <stdio.h> +#include <unistd.h> +#include <time.h> + + +int main() +{ + + tzset (); + printf ("%s %s %ld %d\n",tzname[0],tzname[1], timezone, daylight); +} diff --git a/gnome-map/timezonemapmodule.c b/gnome-map/timezonemapmodule.c new file mode 100644 index 000000000..33027c177 --- /dev/null +++ b/gnome-map/timezonemapmodule.c @@ -0,0 +1,824 @@ +/* Copyright (C) 1999 Red Hat, Inc. */ +/* Original work by Michael Fulbright <drmike@redhat.com> */ + +#include <gnome.h> +#include <stdlib.h> +#include <unistd.h> +#include <math.h> + +#include <Python.h> + +#include "pygtk.h" +#include "gnome-map.h" +#include "gnome-canvas-dot.h" +#include "timezones.h" + + +/* Command line options */ +/* image - filename of file to use for map (must be PNG for antialias) */ +/* mapwidth - width to scale image to (also size of canvas widget) */ +/* mapheight - height to scale image to (also size of canvas widget) */ +/* aa - if TRUE use antialiased canvas instead of normal */ + +typedef struct MapData_t { + GnomeMap *map; + GtkWidget * locationlist; + GtkWidget * citylist; + GtkWidget * statusbar; + GtkWidget * views; + gint curselection; + GnomeCanvasItem *selmarker; + GnomeCanvasItem *curmarker; + GnomeCanvasItem **markers; + GPtrArray *Locations; + GnomeCanvasItem *hiliterubberband; + gint hiliteindex; +} MapData; + +/* if TRUE we do not want to act on the select_row events to locationlist */ +/* used when we are manually manipulating rows in locationlist and we */ +/* want to ignore the events going to the callback. */ +gboolean ignore_locationlist_selectevents=FALSE; + +/* Canvas item circle for selected location */ +double oldselx, oldsely; /* old location of selection */ +#define SELECTED_COLOR "red" +#define HILITED_COLOR "limegreen" +#define CITY_COLOR "yellow" + +GnomeMap *WorldMap; + +/* view data */ +/* Views are defined by a range of either longitude or latitude */ +/* as well as the central value for the other axis. */ +typedef enum +{ + LONGITUDE_CONSTRAINT, + LATITUDE_CONSTRAINT +} ViewContraintType; + +struct _VIEW_DEF { + gchar *name; + ViewContraintType type; + double constraint1, constraint2, constraint3; +}; + +typedef struct _VIEW_DEF ViewDefinition; + +ViewDefinition Views[] = { + { "World", LONGITUDE_CONSTRAINT, -180.0, 180.0, 0.0 }, + { "North America", LONGITUDE_CONSTRAINT, -171.0, -21.0, 40.0 }, + { "South America", LATITUDE_CONSTRAINT, 15.0, -70.0, -70.0 }, + { "Pacific Rim", LATITUDE_CONSTRAINT, -47.0, 47.0, 155.0}, + { "Europe", LONGITUDE_CONSTRAINT, -25.0, 70.0, 45.0 }, + { "Africa", LATITUDE_CONSTRAINT, 40.0, -40.0, 15.0}, + { "Asia", LONGITUDE_CONSTRAINT, 20.0, 165.0, 40.0} +}; + +static gint numviews = sizeof(Views)/sizeof(ViewDefinition); + +static gint item_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data); +static GtkWidget * create_location_list (MapData *mapdata); + +/* give a location name search for match in Locations db */ +/* returns index if found, -1 if not */ +static int +find_location (GPtrArray *Locations, gchar *locname) +{ + TimeZoneLocation *loc; + gint i; + + for (i=0; i < Locations->len; i++) { + loc = g_ptr_array_index (Locations, i); + + if (!strcmp (loc->zone, locname)) + return i; + } + + return -1; +} + + +/* find nearest location to specified map coords - clips to current view */ +/* if no match return -1 */ +static int +find_nearest (GPtrArray * Locations, double longitude, double latitude ) +{ + double mindist; + double dist; + double dx, dy; + int i, mini; + gboolean first=TRUE; + TimeZoneLocation *loc; + + mini = -1; + for (i=0; i < Locations->len; i++) { + loc = g_ptr_array_index (Locations, i); + + if (!gnome_map_is_loc_in_view (WorldMap, + loc->longitude, loc->latitude)) + continue; + + dx = (loc->longitude-longitude); + dy = (loc->latitude-latitude); + dist = dx*dx + dy*dy; + + if (dist < mindist || first) { + mindist = dist; + mini = i; + first = FALSE; + } + } + + return mini; +} + +/* attach to signal for canvas items so we can track motion and mouse */ +/* events */ +static void +setup_item (GnomeCanvasItem *item, MapData *mapdata) +{ + gtk_signal_connect (GTK_OBJECT (item), "event", + (GtkSignalFunc) item_event, + mapdata); +} + +/* Moves marker (a 'x' currently) to the specified location */ +/* and sets it to the specified color. The oldx and oldy */ +/* variables are required because the canvas only allows one */ +/* to do relative moves for items. These are automatically */ +/* set to x and y by this function before it returns. */ +/* */ +/* The first time this function is called for a given marker */ +/* *curmarker should equal NULL. The marker will be created */ +/* automatically. */ + +static void +set_flag_marker (MapData *mapdata, gchar *color, + double x, double y, double *oldx, double *oldy) +{ + GnomeCanvasGroup *canvas_root; + GnomeCanvasItem *group; + + g_return_if_fail ( color != NULL ); + + canvas_root = gnome_canvas_root (GNOME_CANVAS(WorldMap->canvas)); + if (!mapdata->curmarker) { + group = gnome_canvas_item_new ( canvas_root, + gnome_canvas_group_get_type(), + "x", x, + "y", y, + NULL); + +#define MARKER_RADIUS 3.5 +#define MARKER_WIDTH_PIX 1 + + setup_item (gnome_canvas_item_new (GNOME_CANVAS_GROUP (group), + gnome_canvas_text_get_type (), + "font", "-adobe-helvetica-bold-r-normal--12-*-72-72-p-*-iso8859-1", + "anchor", GTK_ANCHOR_CENTER, + "fill_color", "red", + "text", "x", + NULL), mapdata); + + mapdata->curmarker = GNOME_CANVAS_ITEM (group); + } else { + gnome_canvas_item_move (mapdata->curmarker, x - *oldx, y - *oldy); + } + + *oldx = x; + *oldy = y; +} + +/* Given a pointer to a GnomeMap and an index into the Locations db */ +/* mark it as the selected location on the canvas */ +static void +map_mark_location_selected (GnomeMap *map, gint index) +{ + TimeZoneLocation *loc; + double selx, sely; + MapData *mapdata = (MapData *) map->data; + + g_return_if_fail ( map != NULL ); + g_return_if_fail ( index >= 0 ); + + loc = g_ptr_array_index (mapdata->Locations, index); + + gnome_map_xlat_map2screen ( map, + loc->longitude, loc->latitude, + &selx, &sely ); + set_flag_marker (mapdata, SELECTED_COLOR, selx, sely, &oldselx, &oldsely); + + if (mapdata->curselection >= 0) { + gnome_canvas_item_set (mapdata->markers[mapdata->curselection], + "fill_color", CITY_COLOR, NULL); + gnome_canvas_item_show (mapdata->markers[mapdata->curselection]); + } + + gnome_canvas_item_hide (mapdata->markers[index]); +} + +/* Given a pointer to a GnomeMap and an index into the Locations db */ +/* mark it as the selected location in the clist of locations */ +/* The jumpto gboolean is used to specify if the clist should be */ +/* forced to scroll to the new location. Used because when the */ +/* clist is autoscrolling we do not want to force selection to be */ +/* constantly recentered. */ +static void +list_mark_location_selected (GnomeMap *map, gint index, gboolean jumpto) +{ + gint newrow; + MapData * mapdata; + + mapdata = (MapData *) map->data; + + /* We're messing with list manually, so let callback know to */ + /* ignore any events till we're done */ + ignore_locationlist_selectevents = TRUE; + + /* if current selection is visible then select it again, otherwise */ + /* change clist to not have a current selection */ + if (index >= 0) { + TimeZoneLocation *loc = g_ptr_array_index (mapdata->Locations, index); + + if (gnome_map_is_loc_in_view (map,loc->longitude,loc->latitude)) { + gtk_clist_set_selection_mode (GTK_CLIST (mapdata->locationlist), + GTK_SELECTION_BROWSE); + } else { + gtk_clist_set_selection_mode (GTK_CLIST (mapdata->locationlist), + GTK_SELECTION_SINGLE); + } + } + + /* find in list of locations and set as current */ + newrow = gtk_clist_find_row_from_data (GTK_CLIST (mapdata->locationlist), + GINT_TO_POINTER (index)); + + if (newrow >= 0 ) { + gtk_clist_select_row (GTK_CLIST(mapdata->locationlist), newrow, 0); + if (jumpto && gtk_clist_row_is_visible (GTK_CLIST (mapdata->locationlist), newrow) != GTK_VISIBILITY_FULL) { + gtk_clist_moveto (GTK_CLIST (mapdata->locationlist), newrow , 0, 0.5, 0.5 ); + } + } + + /* We're done mucking with clist, ok to listen to events again */ + ignore_locationlist_selectevents = FALSE; + +} +/* handles all canvas drawing for making the selected location # index */ +/* in the sorted list in the Locations variable */ +static void +set_selection (MapData *mapdata, gint index, gboolean jumpto) +{ + g_return_if_fail ( index >= 0 ); + + map_mark_location_selected (WorldMap, index); + + list_mark_location_selected (WorldMap, index, jumpto); + + /* NOTE: curselection is global variable. Only place it gets set */ + mapdata->curselection = index; +} + +/* Given an index into the Locations db and a position, draw the hilite */ +/* marker around it to indicate it is city cursor is pointing at */ +static void +set_hilited (MapData *mapdata, gint index, double item_x, double item_y) +{ + TimeZoneLocation *loc; + GnomeCanvasPoints *points; + + g_return_if_fail ( index >= 0 ); + + loc = g_ptr_array_index (mapdata->Locations, index); + + points = gnome_canvas_points_new (2); + points->coords[0] = item_x; + points->coords[1] = item_y; + gnome_map_xlat_map2screen ( WorldMap, + loc->longitude, loc->latitude, + &points->coords[2], &points->coords[3] ); + if (mapdata->hiliterubberband) { + gnome_canvas_item_set (mapdata->hiliterubberband, "points", points, NULL); + gnome_canvas_item_show (mapdata->hiliterubberband); + } else { + GnomeCanvasGroup *canvas_root = gnome_canvas_root (GNOME_CANVAS (WorldMap->canvas)); + + mapdata->hiliterubberband = + gnome_canvas_item_new (canvas_root, + gnome_canvas_line_get_type (), + "points", points, + "fill_color", HILITED_COLOR, + "width_pixels", 2, + "first_arrowhead", FALSE, + "last_arrowhead", TRUE, + "arrow_shape_a", 4.0, + "arrow_shape_b", 8.0, + "arrow_shape_c", 4.0, + NULL); + setup_item (mapdata->hiliterubberband, mapdata); + } + + /* if hilited city isn't also currently selected city, draw the */ + /* hilite marker as well */ + if (index != mapdata->curselection) { + + if (mapdata->hiliteindex >= 0 && mapdata->hiliteindex != index) { + if (mapdata->hiliteindex != mapdata->curselection) + gnome_canvas_item_set (mapdata->markers[mapdata->hiliteindex], + "fill_color", CITY_COLOR, + NULL); + else + gnome_canvas_item_set (mapdata->markers[mapdata->hiliteindex], + "fill_color", SELECTED_COLOR, + NULL); + } + mapdata->hiliteindex = index; + gtk_statusbar_pop (GTK_STATUSBAR (mapdata->statusbar), 1); + gtk_statusbar_push (GTK_STATUSBAR (mapdata->statusbar), 1, loc->zone ); + } + + gnome_canvas_points_free (points); +} + +/* Handles case where cursor leaves the map */ +static int +canvas_event (GtkWidget *canvas, GdkEvent *event, gpointer data) +{ + MapData *mapdata = (MapData *) data; + + /* if pointer just left canvas, hide hilite marker(s) */ + if (event->type == GDK_LEAVE_NOTIFY) { + if (mapdata->hiliterubberband) + gnome_canvas_item_hide (mapdata->hiliterubberband); + if (mapdata->hiliteindex >= 0 && + mapdata->hiliteindex != mapdata->curselection) + gnome_canvas_item_set (mapdata->markers[mapdata->hiliteindex], + "fill_color", CITY_COLOR, + NULL); + + } + return FALSE; +} + +/* Handles as motion and mouse button events in the map */ +static gint +item_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data) +{ + double longitude, latitude; + double item_x, item_y; + int nearest; + MapData *mapdata = (MapData *) data; + + item_x = event->button.x; + item_y = event->button.y; + gnome_canvas_item_w2i (WorldMap->image_item, &item_x, &item_y); + + switch (event->type) { + + /* User selected a new location with a left mouse button press */ + case GDK_BUTTON_PRESS: + switch (event->button.button) { + case 1: + + gnome_map_xlat_screen2map (WorldMap, item_x, item_y, + &longitude, &latitude); + + nearest = find_nearest(mapdata->Locations, longitude, latitude); + + set_selection (mapdata, nearest, TRUE); + + break; + + default: + break; + } + + break; + + /* highlight city which a button press will select */ + case GDK_MOTION_NOTIFY: + + gnome_map_xlat_screen2map ( WorldMap, item_x, item_y, + &longitude, &latitude); + + nearest = find_nearest(mapdata->Locations, longitude, latitude); + set_hilited (mapdata, nearest, item_x, item_y); + break; + + default: + break; + } + + return FALSE; +} + +/* Handles events for the clist of locations */ +static void +list_select_event ( GtkWidget *clist, gint row, gint column, + GdkEventButton *event, gpointer data) +{ + gchar *text; + gint index; + MapData * mapdata = (MapData *) data; + + /* should we do anything? */ + if (ignore_locationlist_selectevents) + return; + + /* msf - always read zero because sometimes col == -1 if they select */ + /* without a mouse click (ie. keyboard navigation ) */ + gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text); + + /* Just prints some information about the selected row */ + g_print("You selected row %d. More specifically you clicked in column %d, and the text in this cell is %s\n\n", row, column, text); + + index = find_location (mapdata->Locations, text); + if (index < 0) + return; + + set_selection (mapdata, index, FALSE); + return; +} + + +static GnomeCanvasItem * +draw_city_marker ( GnomeMap *map, double longitude, double latitude) +{ + double x, y; + GnomeCanvasItem *item; + GnomeCanvasGroup *canvas_root; + MapData *mapdata = (MapData *) map->data; + + canvas_root = gnome_canvas_root (GNOME_CANVAS (map->canvas)); + + gnome_map_xlat_map2screen (map, longitude, latitude, &x, &y); + +#define RAD 1 +#ifdef ELLIPSE + item = gnome_canvas_item_new (canvas_root, + gnome_canvas_ellipse_get_type (), + "x1", x-RAD, + "y1", y-RAD, + "x2", x+RAD, + "y2", y+RAD, + "fill_color", CITY_COLOR, + NULL); +#else + item = gnome_canvas_item_new (canvas_root, + gnome_canvas_dot_get_type (), + "x", x, + "y", y, + "diameter_pixels", RAD, + "fill_color", CITY_COLOR, + NULL); +#endif + + setup_item (item, mapdata); + return item; +} + +static void +draw_cities (GnomeMap *map) +{ + gint i; + MapData * mapdata = (MapData *) map->data; + + if (mapdata->markers) + g_free(mapdata->markers); + + mapdata->markers = g_new( GnomeCanvasItem *, mapdata->Locations->len); + for (i=0; i < mapdata->Locations->len; i++) { + TimeZoneLocation *loc = g_ptr_array_index (mapdata->Locations, i); + + mapdata->markers[i] = draw_city_marker (map, loc->longitude, loc->latitude); + } +} + +static void +view_menu_activate (GtkWidget *widget, void *data) +{ + static gint curitem = -1; + gint item = GPOINTER_TO_INT (data); + MapData *mapdata = gtk_object_get_data (GTK_OBJECT (widget), "mapdata"); + + double lat1, long1, lat2, long2; + double dlat, dlong; + + if ( item == curitem ) + return; + + curitem = item; + + /* compute aspect correct view and set canvas to it */ + /* we may have to shift view if it extends outside of map */ + if (Views[item].type == LONGITUDE_CONSTRAINT) { + long1 = Views[item].constraint1; + long2 = Views[item].constraint2; + dlong = fabs(long2 - long1); + dlat = dlong/2.0; + lat1 = Views[item].constraint3 - dlat/2.0; + lat2 = Views[item].constraint3 + dlat/2.0; + + if (lat1 < -90.0) { + lat2 -= (lat1-90.0); + lat1 = -90.0; + } else if (lat2 > 90.0) { + lat1 -= (lat2-90.0); + lat2 = 90.0; + } + } else if (Views[item].type == LATITUDE_CONSTRAINT) { + lat1 = Views[item].constraint1; + lat2 = Views[item].constraint2; + dlat = fabs(lat2 - lat1); + dlong = 2.0*dlat; + long1 = Views[item].constraint3 - dlong/2.0; + long2 = Views[item].constraint3 + dlong/2.0; + + if (long1 < -180.0) { + long2 -= (long1-180.0); + long1 = -180.0; + } else if (long2 > 180.0) { + long1 -= (long2-180.0); + long2 = 180.0; + } + } else { + g_warning ("Bad contraint type %d in Views structure item # %d.\n", + item, Views[item].type); + return; + } + + gnome_map_set_view (WorldMap, long1, lat1, long2, lat2); + + /* make locationlist clist entries reflect those visible*/ + create_location_list (mapdata); +} + +GtkWidget * +create_view_menu (MapData *mapdata) +{ + GtkWidget *omenu; + GtkWidget *menu; + GtkWidget *menu_item; + gint i; + + omenu = gtk_option_menu_new (); + + menu = gtk_menu_new (); + + for (i=0; i < numviews; i++) { + menu_item = gtk_menu_item_new_with_label (Views[i].name); + gtk_menu_append (GTK_MENU (menu), menu_item); + + gtk_signal_connect (GTK_OBJECT (menu_item), "activate", + (GtkSignalFunc) view_menu_activate, + GINT_TO_POINTER (i)); + + gtk_object_set_data (GTK_OBJECT (menu_item), "mapdata", mapdata); + + gtk_widget_show (menu_item); + } + gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu); + gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), 0); + + gtk_widget_show (omenu); + + return omenu; +} + +/* returns pointer to the scrolled window containing the clist */ +/* pointer to clist is returned via the passed argument if it doesnt */ +/* already exist. The list is clipped to the current world view */ +static GtkWidget * +create_location_list (MapData *mapdata) +{ + TimeZoneLocation *loc; + GtkWidget *scrolledwin; + gchar *titles[] = { "Location", NULL }; + gchar *row[1]; + gint i; + + ignore_locationlist_selectevents = TRUE; + + if (! mapdata->locationlist) { + scrolledwin = gtk_scrolled_window_new (NULL, NULL); + + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + + gtk_widget_show (scrolledwin); + + mapdata->locationlist = gtk_clist_new_with_titles (1, titles); + + gtk_clist_set_selection_mode (GTK_CLIST(mapdata->locationlist), + GTK_SELECTION_BROWSE); + gtk_clist_column_title_passive (GTK_CLIST(mapdata->locationlist), 0); + gtk_signal_connect(GTK_OBJECT(mapdata->locationlist), "select_row", + GTK_SIGNAL_FUNC(list_select_event), + mapdata); + + gtk_container_add (GTK_CONTAINER (scrolledwin), mapdata->locationlist); + } else { + gtk_clist_clear (GTK_CLIST (mapdata->locationlist)); + scrolledwin = NULL; + } + + for (i=0; i < mapdata->Locations->len; i++) { + gint newrow; + + loc = g_ptr_array_index (mapdata->Locations, i); + if (!gnome_map_is_loc_in_view (WorldMap, loc->longitude, loc->latitude)) + continue; + + row[0] = loc->zone; + newrow = gtk_clist_append (GTK_CLIST (mapdata->locationlist), row); + gtk_clist_set_row_data (GTK_CLIST (mapdata->locationlist), newrow, + GINT_TO_POINTER (i)); + } + + /* restore selection of location in list now we've recreated it */ + list_mark_location_selected(WorldMap, mapdata->curselection, TRUE); + + ignore_locationlist_selectevents = FALSE; + return scrolledwin; +} + +MapData * new_mapdata (void) +{ + MapData * mapdata; + mapdata = g_new0 (MapData, 1); + + /* make a new map view */ + WorldMap = gnome_map_new ("map480.png", 390, 180, FALSE); + if (!WorldMap) { + g_warning ("Could not create map view."); + exit (1); + } + WorldMap->data = mapdata; + mapdata->map = WorldMap; + + setup_item (WorldMap->image_item, mapdata); + gtk_signal_connect (GTK_OBJECT (WorldMap->canvas), "event", + (GtkSignalFunc) canvas_event, + mapdata); + + /* load timezone data */ + mapdata->Locations = loadTZDB (); + if (!mapdata->Locations) { + g_warning (_("Cannot load timezone data")); + exit (1); + } + + mapdata->citylist = create_location_list (mapdata); + draw_cities (WorldMap); + + mapdata->statusbar = gtk_statusbar_new (); + mapdata->views = create_view_menu (mapdata); + + return mapdata; +} + +#if 0 +int +main (int argc, char **argv) +{ + GtkWidget *frame; + GtkWidget *hbox1, *hbox2; + GtkWidget *vbox1, *vbox2; + GtkWidget *viewcombo; + GtkWidget *statusbar; + GtkWidget *aframe; + GtkWidget *mainwindow; + MapData *mapdata; + + gnome_init ("gglobe", "0.1", argc, argv); + + mapdata = new_mapdata (); + + mainwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_position (GTK_WINDOW (mainwindow), GTK_WIN_POS_CENTER); + gtk_window_set_title (GTK_WINDOW (mainwindow), _("gglobe-canvas")); + + gtk_container_add (GTK_CONTAINER (mainwindow), WorldMap->canvas); + + gtk_widget_show (statusbar); + + /* add View combo box */ + aframe = gtk_frame_new (NULL); + gtk_box_pack_start (GTK_BOX (hbox1), frame, FALSE, FALSE, 2); + + vbox2 = gtk_vbox_new (FALSE, 2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + + hbox2 = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 2); + + viewcombo = create_view_menu (mapdata); + gtk_box_pack_start (GTK_BOX (hbox2), gtk_label_new ("View: "), + FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox2), viewcombo, FALSE, FALSE, 2); + + /* put cities on the world map */ + + /* add list of all timezones */ + frame = gtk_frame_new (NULL); + gtk_box_pack_start (GTK_BOX (vbox2), + create_location_list (mapdata), + TRUE, TRUE, 2); + + /* display and wait */ + gtk_widget_show_all (mainwindow); + + /* pick New York City as default */ + set_selection (mapdata, + find_location (mapdata->Locations, "America/New_York"), + TRUE); + + gtk_main (); + + return 0; +} + +#endif + +static PyMethodDef tzObjectMethods[] = { + { NULL }, +}; + +typedef struct tzObject_t { + PyObject_HEAD; + MapData * mapdata; +} tzObject; + +/* typedef struct tzObject_t tzObject; */ + +static PyObject * tzGetAttr(tzObject * o, char * name); +static void tzDealloc (tzObject * o); + +static PyTypeObject tzType = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "timezonemap", /* tp_name */ + sizeof(tzObject), /* tp_size */ + 0, /* tp_itemsize */ + (destructor) tzDealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc) tzGetAttr, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ +}; + +static PyObject * tzGetAttr(tzObject * o, char * name) { + if (!strncmp (name, "map", 3)) { + return PyGtk_New((GtkObject *) o->mapdata->map->canvas); + } + if (!strncmp (name, "citylist", 8)) { + return PyGtk_New((GtkObject *) o->mapdata->citylist); + } + if (!strncmp (name, "statusbar", 9)) { + return PyGtk_New((GtkObject *) o->mapdata->statusbar); + } + if (!strncmp (name, "views", 5)) { + return PyGtk_New((GtkObject *) o->mapdata->views); + } + return Py_FindMethod(tzObjectMethods, (PyObject *) o, name); +}; + +static void tzDealloc (tzObject * o) +{ + return; +} + +static tzObject * doNewTZ (PyObject * s, PyObject * args); + +static PyMethodDef timezoneMethods[] = { + { "new", (PyCFunction) doNewTZ, METH_VARARGS, NULL }, + { NULL }, +}; + +static tzObject * doNewTZ (PyObject * s, PyObject * args) { + tzObject *o; + + o = (tzObject *) PyObject_NEW(tzObject, &tzType); + + o->mapdata = new_mapdata (); + + if (!WorldMap) { + PyErr_SetString(PyExc_TypeError, "Could not create map view."); + return NULL; + } + + return o; +} + +#include <gdk_imlib.h> + +void inittimezonemap (void) { + init_pygtk(); + + Py_InitModule("timezonemap", timezoneMethods); +} diff --git a/gnome-map/timezones.c b/gnome-map/timezones.c new file mode 100644 index 000000000..28830af5f --- /dev/null +++ b/gnome-map/timezones.c @@ -0,0 +1,178 @@ +/* GNOME canvas based interface to a map using a simple cylindrical proj */ +/* */ +/* Copyright (C) 1999 Red Hat, Incorportated */ +/* Original work by Michael Fulbright <drmike@redhat.com> */ + +#include <glib.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include <math.h> + +#include "timezones.h" + + +TZZoneInfo * +tzinfo_get_for_location (TimeZoneLocation *loc) +{ + TZZoneInfo *tzinfo; + gchar *str; + + g_return_val_if_fail (loc != NULL, NULL); + g_return_val_if_fail (loc->zone != NULL, NULL); + + str = g_strdup_printf ("TZ=%s", loc->zone); + g_print ("%s %s\n",loc->zone, str); + putenv (str); + tzset (); + g_free (str); + tzinfo = g_new0 (TZZoneInfo, 1); + + g_print ("%s %s %ld %d\n",tzname[0], tzname[1], timezone, daylight); + + /* Currently this solution doesnt seem to work - I get that */ + /* America/Phoenix uses daylight savings, which is wrong */ + tzinfo->tzname_normal = (tzname[0]) ? g_strdup (tzname[0]) : NULL; + tzinfo->tzname_daylight = (tzname[1]) ? g_strdup (tzname[1]) : NULL; + tzinfo->utc_offset = timezone; + tzinfo->daylight = daylight; + + return tzinfo; +} + +void +tzinfo_free (TZZoneInfo *tzinfo) +{ + g_return_if_fail (tzinfo != NULL); + + if (tzinfo->tzname_normal) + g_free (tzinfo->tzname_normal); + if (tzinfo->tzname_daylight) + g_free (tzinfo->tzname_daylight); + g_free (tzinfo); +} + +static float +convertPos( gchar *pos, int digits ) +{ + gchar whole[10]; + gchar *fraction; + gint i; + float t1, t2; + + if (!pos || strlen(pos) < 4 || digits > 9) + return 0.0; + + for (i=0; i < digits+1; i++) + whole[i] = pos[i]; + whole[i] = '\0'; + fraction = pos+digits+1; + + t1 = g_strtod (whole, NULL); + t2 = g_strtod (fraction, NULL); + + /* how do I get sign of a float in a portable fashion? */ + if (t1 >= 0.0 ) + return t1 + t2/pow (10.0, strlen(fraction)); + else + return t1 - t2/pow (10.0, strlen(fraction)); + +} + +#if 0 + +/* Currently not working */ +static void +free_tzdata( TimeZoneLocation *tz) +{ + + if (tz->country) + g_free(tz->country); + if (tz->zone) + g_free(tz->zone); + if (tz->comment) + g_free(tz->comment); + + g_free(tz); +} +#endif + +static int +compare_country_names (const void * a, const void * b) +{ + const TimeZoneLocation *tza = * (TimeZoneLocation **) a; + const TimeZoneLocation *tzb = * (TimeZoneLocation **) b; + + return strcmp (tza->zone, tzb->zone); +} + +static void +sort_locations_by_country (GPtrArray *locations) +{ + qsort (locations->pdata, locations->len, sizeof (gpointer), + compare_country_names); +} + + +GPtrArray * +loadTZDB( void ) +{ + GPtrArray *tzdb; + FILE *tzfile; + char buf[4096]; + + tzfile = fopen (TZ_DATAFILE, "r"); + if (!tzfile) + return NULL; + + tzdb = g_ptr_array_new (); + + while (fgets (buf, sizeof(buf), tzfile)) { + gchar **tmpstrarr; + gchar *latstr, *lngstr, *p; + TimeZoneLocation *loc; + + if (*buf == '#') + continue; + + g_strchomp(buf); + tmpstrarr = g_strsplit(buf,"\t", 4); + +#ifdef DEBUG_ZONEREAD + printf ("country code: %s\nlocaton:%s\ntimezone:%s\ncomment:\%s\n", + tmpstrarr[0], tmpstrarr[1], tmpstrarr[2], tmpstrarr[3]); +#endif + latstr = g_strdup (tmpstrarr[1]); + p = latstr+1; + while (*p != '-' && *p != '+') + p++; + lngstr = g_strdup (p); + *p = '\0'; + +#ifdef DEBUG_ZONEREAD + printf ("lat: %s\nlong: %s\n",latstr, lngstr); + printf ("lat: %f\nlong: %f\n\n", convertPos (latstr,2), convertPos (lngstr,3)); +#endif + loc = g_new( TimeZoneLocation, 1); + loc->country = g_strdup(tmpstrarr[0]); + loc->zone = g_strdup(tmpstrarr[2]); + loc->comment = (tmpstrarr[3]) ? g_strdup(tmpstrarr[3]) : NULL; + loc->latitude = convertPos(latstr,2); + loc->longitude = convertPos(lngstr,3); + + g_ptr_array_add (tzdb, (gpointer) loc); + + g_free (latstr); + g_free (lngstr); + g_strfreev (tmpstrarr); + } + + fclose (tzfile); + + /* now sort by country */ + sort_locations_by_country (tzdb); + + return tzdb; +} + diff --git a/gnome-map/timezones.h b/gnome-map/timezones.h new file mode 100644 index 000000000..d29cc440e --- /dev/null +++ b/gnome-map/timezones.h @@ -0,0 +1,40 @@ +/* GNOME canvas based interface to a map using a simple cylindrical proj */ +/* */ +/* Copyright (C) 1999 Red Hat, Incorportated */ +/* Original work by Michael Fulbright <drmike@redhat.com> */ + +#ifndef _GNOME_MAP_TIMEZONES_H +#define _GNOME_MAP_TIMEZONES_H + + +#define TZ_DATAFILE "/usr/share/zoneinfo/zone.tab" + + +struct _TZ_DATA_LOCATION { + char *country; + float latitude; + float longitude; + char *zone; + char *comment; +}; + +typedef struct _TZ_DATA_LOCATION TimeZoneLocation; + +/* see the glibc info page information on time zone information */ +/* tzname_normal is the default name for the timezone */ +/* tzname_daylight is the name of the zone when in daylight savings */ +/* utc_offset is offset in seconds from utc */ +/* daylight if non-zero then location obeys daylight savings */ +struct _TZ_ZONE_INFO { + char *tzname_normal; + char *tzname_daylight; + long int utc_offset; + int daylight; +}; + +typedef struct _TZ_ZONE_INFO TZZoneInfo; + +GPtrArray *loadTZDB ( void ); +TZZoneInfo *tzinfo_get_for_location (TimeZoneLocation *loc); +void tzinfo_free (TZZoneInfo *tzinfo); +#endif |