/* Copyright (C) 1999 Red Hat, Inc. */
/* Original work by Michael Fulbright <[email protected]> */

#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;
}