1 /*	SCCS Id: @(#)gnmap.c	3.3	2000/07/16	*/
2 /* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
3 /* Copyright (C) 1998 by Anthony Taylor <tonyt@ptialaska.net> */
4 /* NetHack may be freely redistributed.  See license for details. */
5 
6 #include "gnmap.h"
7 #include "gnglyph.h"
8 #include "gnsignal.h"
9 #include "hack.h"
10 
11 #ifndef ROWNO
12 #define ROWNO 21
13 #define COLNO 80
14 #endif
15 
16 /* globals static to this file go here */
17 struct {
18   GnomeCanvas       *canvas;
19   GnomeCanvasImage  *map[(ROWNO + 1) * COLNO];
20   GnomeCanvasImage  *overlay[(ROWNO + 1) * COLNO];
21   double            zoom;
22   GtkWidget         *frame;
23 } ghack_map;
24 
25 static GdkImlibImage *background;
26 static GdkImlibImage *petmark;
27 static GnomeCanvasGroup *myCanvasGroup;
28 
29 /* static function declarations -- local to this file go here */
30 void ghack_map_cursor_to( GtkWidget *win, int x, int y, gpointer data);
31 void ghack_map_putstr( GtkWidget *win, int attr, const char* text, gpointer data);
32 void ghack_map_print_glyph( GtkObject *win, guint x, guint y, GdkImlibImage *im, gpointer data);
33 void ghack_map_clear( GtkWidget *win, gpointer data);
34 static void ghack_map_display( GtkWidget *win, boolean block, gpointer data);
35 static void ghack_map_cliparound( GtkWidget *win, int x, int y, gpointer data);
36 static void ghack_map_window_zoom( GtkAdjustment *adj, gpointer data);
37 
38 
39 /* The following XPM is the artwork of Warwick Allison
40  * <warwick@troll.no>.  It has been borrowed from
41  * the most excellent NetHackQt, until such time as
42  * we can come up with something better.
43  *
44  * More information about NetHackQt can be had from:
45  * http://www.troll.no/~warwick/nethack/
46  */
47 
48 /* XPM */
49 static char *pet_mark_xpm[] = {
50 /* width height ncolors chars_per_pixel */
51 "8 7 2 1",
52 /* colors */
53 ". c None",
54 "  c #FF0000",
55 /* pixels */
56 "........",
57 "..  .  .",
58 ".       ",
59 ".       ",
60 "..     .",
61 "...   ..",
62 ".... ..."
63 };
64 
65 
66 /* NAME:
67  *     ghack_init_map_window( )
68  *
69  * ARGUMENTS:
70  *     NONE
71  *
72  * RETURNS:
73  *     GtkWidget*
74  *
75  * PURPOSE:
76  *     Create the basic map necessities.  Create a canvas;
77  *     give it a background.  Attach all the right signals
78  *     to all the right places.  Generally prepare the map
79  *     to behave properly.
80 */
81 
82 GtkWidget*
ghack_init_map_window()83 ghack_init_map_window ( )
84 {
85   GtkWidget        *vbox;
86   GtkWidget        *hbox;
87   GtkWidget        *table;
88   GtkWidget        *frame;
89   GtkWidget        *w;
90   GtkWidget	   *hSeparator;
91   GtkAdjustment    *adj;
92   GnomeCanvasImage  *bg;
93   double width, height, x, y;
94   int i;
95 
96   width = COLNO * ghack_glyph_width();
97   height = ROWNO * ghack_glyph_height();
98 
99   vbox = gtk_vbox_new (FALSE, 4);
100   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
101   gtk_widget_show (vbox);
102 
103   /* Add in a horiz seperator */
104   hSeparator = gtk_hseparator_new ();
105   gtk_box_pack_start (GTK_BOX (vbox), hSeparator, FALSE, FALSE, 2);
106   gtk_widget_show ( hSeparator);
107 
108   hbox = gtk_hbox_new (FALSE, 4);
109   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
110   gtk_widget_show (hbox);
111 
112   /* Create the Zoom spinbutton.
113   */
114   ghack_map.zoom = 1.0;
115   w = gtk_label_new ("Zoom:");
116   gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
117   gtk_widget_show (w);
118   adj = GTK_ADJUSTMENT (gtk_adjustment_new (1.00, 0.5, 3.00, 0.05, 0.50, 0.50));
119   w = gtk_spin_button_new (adj, 0.5, 2);
120   gtk_widget_set_usize (w, 50, 0);
121   gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
122   gtk_widget_show (w);
123 
124   /* Canvas and scrollbars
125   */
126   gtk_widget_push_visual (gdk_imlib_get_visual ());
127   gtk_widget_push_colormap (gdk_imlib_get_colormap ());
128   ghack_map.canvas = GNOME_CANVAS (gnome_canvas_new());
129   //gtk_widget_push_visual(gdk_rgb_get_visual());
130   //gtk_widget_push_colormap(gdk_rgb_get_cmap());
131   //ghack_map.canvas = GNOME_CANVAS (gnome_canvas_new_aa());
132 
133   gtk_widget_pop_colormap();
134   gtk_widget_pop_visual();
135   gtk_widget_show (GTK_WIDGET(ghack_map.canvas));
136 
137   table = gtk_table_new (2, 2, FALSE);
138   gtk_table_set_row_spacings (GTK_TABLE (table), 4);
139   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
140   gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
141   gtk_widget_show (table);
142 
143   frame = gtk_frame_new (NULL);
144   ghack_map.frame = frame;
145   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
146   gtk_table_attach (GTK_TABLE (table), frame,
147 		    0, 1, 0, 1,
148 		    GTK_EXPAND | GTK_FILL | GTK_SHRINK,
149 		    GTK_EXPAND | GTK_FILL | GTK_SHRINK,
150 		    0, 0);
151   gtk_widget_show (frame);
152 
153   gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET(ghack_map.canvas));
154   gnome_canvas_set_scroll_region (GNOME_CANVAS(ghack_map.canvas), 0, 0,
155 		    width+2*ghack_glyph_width(), height+2*ghack_glyph_height());
156 
157   gnome_canvas_set_pixels_per_unit (GNOME_CANVAS(ghack_map.canvas), 1.0);
158 
159   w = gtk_hscrollbar_new (GTK_LAYOUT (ghack_map.canvas)->hadjustment);
160   gtk_table_attach (GTK_TABLE (table), w,
161 		    0, 1, 1, 2,
162 		    GTK_EXPAND | GTK_FILL | GTK_SHRINK,
163 		    GTK_FILL,
164 		    0, 0);
165   gtk_widget_show (w);
166 
167   w = gtk_vscrollbar_new (GTK_LAYOUT (ghack_map.canvas)->vadjustment);
168   gtk_table_attach (GTK_TABLE (table), w,
169 		    1, 2, 0, 1, GTK_FILL,
170 		    GTK_EXPAND | GTK_FILL | GTK_SHRINK,
171 		    0, 0);
172   gtk_widget_show (w);
173 
174   myCanvasGroup = GNOME_CANVAS_GROUP ( gnome_canvas_item_new (
175 		    gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)),
176 		    gnome_canvas_group_get_type (),
177 		    "x", 0.0,
178 		    "y", 0.0,
179 		    NULL) );
180 
181   /* Tile the map background with a pretty image */
182   background = gdk_imlib_load_image((char *) "mapbg.xpm");
183   gdk_imlib_render( background, background->rgb_width,
184 	  background->rgb_height);
185   if (background == NULL) {
186       g_warning("Bummer! Failed to load the map background image (mapbg.xpm)!");
187   }
188   else {
189     /* Tile the map background */
190     for (y = 0; y < height+background->rgb_height; y+=background->rgb_height)
191     {
192       for (x = 0; x < width+background->rgb_width; x+=background->rgb_width)
193 	{
194 	  bg = GNOME_CANVAS_IMAGE( gnome_canvas_item_new (
195 		      myCanvasGroup, gnome_canvas_image_get_type (),
196 		      "x",      (double) x,
197 		      "y",      (double) y,
198 		      "width",  (double) background->rgb_width,
199 		      "height", (double) background->rgb_height,
200 		      "image",  background,
201 		      "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER,
202 		      NULL) );
203 	  gnome_canvas_item_lower_to_bottom (GNOME_CANVAS_ITEM( bg));
204 	}
205     }
206   }
207 
208   /* ghack_map.map is an array of canvas images.  Each cell of
209    * the array will contain one tile.  Here, we create the
210    * space for the cells and then create the cells for easy
211    * access later.
212   */
213   for (i=0, y = 0; y < height; y+=ghack_glyph_height())
214     {
215       for (x = 0; x < width; x+=ghack_glyph_width())
216 	{
217 	  ghack_map.map[i++] = GNOME_CANVAS_IMAGE(
218 		  gnome_canvas_item_new (
219 		      myCanvasGroup,
220 		      gnome_canvas_image_get_type (),
221 		      "x",      (double) x,
222 		      "y",      (double) y,
223 		      "width",  (double) ghack_glyph_height(),
224 		      "height", (double) ghack_glyph_width(),
225 		      "anchor", GTK_ANCHOR_NORTH_WEST,
226 		      NULL) );
227 	}
228     }
229 
230    /* Set up the pet mark image */
231   petmark = gdk_imlib_create_image_from_xpm_data( pet_mark_xpm);
232   gdk_imlib_render( petmark, petmark->rgb_width,
233 	  petmark->rgb_height);
234   if (petmark == NULL) {
235     g_warning("Bummer! Failed to load the pet_mark image!");
236   }
237   else {
238       /* ghack_map.overlay is an array of canvas images used to
239        * overlay tile images...
240       */
241       for (i=0, y = 0; y < height; y+=ghack_glyph_height())
242 	{
243 	  for (x = 0; x < width; x+=ghack_glyph_width())
244 	    {
245 	      ghack_map.overlay[i] = GNOME_CANVAS_IMAGE(
246 		      gnome_canvas_item_new (
247 			  myCanvasGroup,
248 			  gnome_canvas_image_get_type (),
249 			  "x",      (double) x,
250 			  "y",      (double) y,
251 			  "width",  (double) petmark->rgb_width,
252 			  "height", (double) petmark->rgb_height,
253 			  "image",  petmark,
254 			  "anchor", GTK_ANCHOR_NORTH_WEST,
255 			  NULL) );
256 	      gnome_canvas_item_lower_to_bottom (
257 		      GNOME_CANVAS_ITEM( ghack_map.overlay[i++]));
258 	    }
259 	}
260   }
261 
262   /* Resize the canvas when the spinbutton changes
263   */
264   gtk_signal_connect (GTK_OBJECT (adj),
265 		      "value_changed",
266 		      (GtkSignalFunc) ghack_map_window_zoom,
267 		      ghack_map.canvas);
268 
269   /* Game signals
270   */
271   gtk_signal_connect (GTK_OBJECT (vbox),
272 		      "ghack_curs",
273 		      GTK_SIGNAL_FUNC (ghack_map_cursor_to),
274 		      NULL);
275   gtk_signal_connect (GTK_OBJECT (vbox),
276 		      "ghack_putstr",
277 		      GTK_SIGNAL_FUNC (ghack_map_putstr),
278 		      NULL);
279   gtk_signal_connect (GTK_OBJECT (vbox),
280 		      "ghack_print_glyph",
281 		      GTK_SIGNAL_FUNC (ghack_map_print_glyph),
282 		      NULL);
283   gtk_signal_connect (GTK_OBJECT (vbox),
284 		      "ghack_clear",
285 		      GTK_SIGNAL_FUNC (ghack_map_clear),
286 		      NULL);
287   gtk_signal_connect (GTK_OBJECT (vbox),
288 		      "ghack_display",
289 		      GTK_SIGNAL_FUNC (ghack_map_display),
290 		      NULL);
291   gtk_signal_connect (GTK_OBJECT (vbox),
292 		      "ghack_cliparound",
293 		      GTK_SIGNAL_FUNC (ghack_map_cliparound),
294 		      NULL);
295   gtk_signal_connect (GTK_OBJECT (ghack_map.canvas),
296 		      "button_press_event",
297 		      GTK_SIGNAL_FUNC (ghack_handle_button_press),
298 		      NULL);
299   gtk_signal_connect(GTK_OBJECT (ghack_map.canvas),
300 	              "gnome_delay_output",
301                       GTK_SIGNAL_FUNC(ghack_delay),
302 		      NULL);
303 
304   return GTK_WIDGET(vbox);
305 }
306 
307 
308 /* NAME:
309  *     ghack_map_window_zoom
310  *
311  * ARGUMENTS:
312  *     double     zoom -- The zoom factor
313  *
314  * RETURNS:
315  *     Nothing.
316  *
317  * PURPOSE:
318  *     Zoom the map image in and out.  This should allow the user to
319  *     dynamically scale the map.  Ideally, the background should
320  *     *NOT* scale, but this may be impractical.
321 */
322 
323 static void
ghack_map_window_zoom(GtkAdjustment * adj,gpointer data)324 ghack_map_window_zoom( GtkAdjustment *adj, gpointer data)
325 {
326   if ( adj->value > 3.0 )
327       adj->value = 3.0;
328   if ( adj->value < 0.5 )
329       adj->value = 0.5;
330   ghack_map.zoom = adj->value;
331   gnome_canvas_set_pixels_per_unit (data, adj->value);
332 }
333 
334 
335 
336 void
ghack_map_cursor_to(GtkWidget * win,int x,int y,gpointer data)337 ghack_map_cursor_to( GtkWidget *win, int x, int y, gpointer data)
338 {
339   GnomeCanvasGroup *group;
340   static GnomeCanvasRE *cursor = NULL;
341 
342   double x1, y1, x2, y2;
343 
344   x1 = x * ghack_glyph_width() - 1;
345   y1 = y * ghack_glyph_height() - 1;
346   x2 = x1 + ghack_glyph_width() + 2;
347   y2 = y1 + ghack_glyph_height() + 2;
348 
349 
350   group = gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas));
351 
352   if (!cursor) {
353     cursor = GNOME_CANVAS_RE (gnome_canvas_item_new (group,
354 		gnome_canvas_rect_get_type (),
355 		"outline_color", "antiquewhite2",
356 		"width_units", 1.0, NULL));
357   }
358   gnome_canvas_item_set (GNOME_CANVAS_ITEM (cursor),
359 			 "x1", x1,
360 			 "y1", y1,
361 			 "x2", x2,
362 			 "y2", y2,
363 			 NULL);
364 
365   gnome_canvas_item_raise_to_top( GNOME_CANVAS_ITEM( cursor));
366   gnome_canvas_item_show( GNOME_CANVAS_ITEM(cursor));
367 }
368 
369 
370 void
ghack_map_putstr(GtkWidget * win,int attr,const char * text,gpointer data)371 ghack_map_putstr( GtkWidget *win, int attr, const char* text, gpointer data)
372 {
373     g_warning("Fixme!!! ghack_map_putstr is not implemented");
374 }
375 
376 /* NAME:
377  *     ghack_map_print_glyph( )
378  *
379  * ARGUMENTS:
380  *     XCHAR_P x, y  -- The coordinates where which to print the glyph
381  *     GdkImlibImage*   glyph -- The glyph image to print
382  *
383  * RETURNS:
384  *     Nothing.
385  *
386  * PURPOSE:
387  *     Draw the glyph-tile at the specified coordinates.
388 */
389 
390 void
ghack_map_print_glyph(GtkObject * win,guint x,guint y,GdkImlibImage * im,gpointer data)391 ghack_map_print_glyph( GtkObject *win,
392 		       guint x,
393 		       guint y,
394 		       GdkImlibImage *im,
395 		       gpointer data)
396 {
397   GnomeCanvasGroup *group;
398   int i = y * COLNO + x;
399   int glyph = glyph_at(x,y);
400   GnomeCanvasImage *canvas_image = GNOME_CANVAS_IMAGE( ghack_map.map[i]);
401 
402   group = gnome_canvas_root (GNOME_CANVAS (ghack_map.canvas));
403 
404   gnome_canvas_item_set (GNOME_CANVAS_ITEM ( canvas_image),
405 			 "image",  im, NULL);
406   gnome_canvas_item_show( GNOME_CANVAS_ITEM( canvas_image));
407 
408   canvas_image = GNOME_CANVAS_IMAGE( ghack_map.overlay[i]);
409 
410   if (x==u.ux && y==u.uy)
411       ghack_map_cliparound(NULL, x, y, NULL);
412 
413   if (glyph_is_pet(glyph)
414 #ifdef TEXTCOLOR
415 		  && iflags.hilite_pet
416 #endif
417 		) {
418       gnome_canvas_item_raise_to_top( GNOME_CANVAS_ITEM( canvas_image));
419       gnome_canvas_item_show( GNOME_CANVAS_ITEM( canvas_image));
420   }
421   else {
422       gnome_canvas_item_hide( GNOME_CANVAS_ITEM( canvas_image));
423   }
424 }
425 
426 
427 /* NAME:
428  *     ghack_map_clear( )
429  *
430  * ARGUMENTS:
431  *     NONE
432  *
433  * RETURNS:
434  *     Nothing.
435  *
436  * PURPOSE:
437  *     Clear the map by hiding all the map tiles.
438 */
439 
440 void
ghack_map_clear(GtkWidget * win,gpointer data)441 ghack_map_clear( GtkWidget *win, gpointer data)
442 {
443   int i;
444 
445   for (i = 0; i < ROWNO * COLNO; i++)
446     {
447       if (GNOME_IS_CANVAS_IMAGE(ghack_map.map[i]))
448 	{
449 	  gnome_canvas_item_hide( GNOME_CANVAS_ITEM (ghack_map.map[i]));
450 	}
451       if (GNOME_IS_CANVAS_IMAGE(ghack_map.overlay[i]))
452 	{
453 	  gnome_canvas_item_hide( GNOME_CANVAS_ITEM (ghack_map.overlay[i]));
454 	}
455     }
456   gnome_canvas_update_now ( GNOME_CANVAS(ghack_map.canvas));
457 }
458 
459 
460 void
ghack_map_display(GtkWidget * win,boolean block,gpointer data)461 ghack_map_display( GtkWidget *win, boolean block, gpointer data)
462 {
463   gtk_widget_show_all( GTK_WIDGET(win));
464 }
465 
466 
467 void
ghack_map_cliparound(GtkWidget * win,int x,int y,gpointer data)468 ghack_map_cliparound( GtkWidget *win,
469 		      int x,
470 		      int y,
471 		      gpointer data)
472 {
473   int  map_width, map_height;
474   int  to_x, to_y;
475   int  cur_x, cur_y;
476   int  width, height, half_width, half_height;
477 
478   x *= ghack_glyph_width() * ghack_map.zoom;
479   y *= ghack_glyph_height() * ghack_map.zoom;
480   map_width = COLNO * ghack_glyph_width() * ghack_map.zoom;
481   map_height = ROWNO * ghack_glyph_height() * ghack_map.zoom;
482 
483   gdk_window_get_size( GTK_LAYOUT (ghack_map.canvas)->bin_window,
484 	  &width, &height);
485   gnome_canvas_get_scroll_offsets( ghack_map.canvas, &cur_x, &cur_y);
486 
487   half_width  = width * 0.5;
488   half_height = height * 0.5;
489 
490   if ( ((x - cur_x) < (width * 0.25) ) || ( (x - cur_x) > (width * 0.75) ) ) {
491     to_x = ((x-half_width) > 0)? x - half_width : 0;
492     to_x = ((x+half_width) > map_width)? map_width - 2 * half_width : to_x;
493   }
494   else {
495     to_x = cur_x;
496   }
497 
498   if ( ((y - cur_y) < (height * 0.25) ) || ( (y - cur_y) > (height * 0.75) ) ) {
499     to_y = ((y-half_height) > 0)? y - half_height : 0;
500     to_y = ((y+half_height) > map_height)? map_height - 2 * half_height : to_y;
501   }
502   else {
503     to_y = cur_y;
504   }
505 
506   if (to_x != cur_x || to_y != cur_y)
507     gnome_canvas_scroll_to( ghack_map.canvas, to_x, to_y);
508   //gnome_canvas_update_now ( ghack_map.canvas);
509 
510 }
511 
512 
513 
514 void
ghack_reinit_map_window()515 ghack_reinit_map_window ( )
516 {
517   GnomeCanvasImage  *bg;
518   double width, height, x, y;
519   int i;
520 
521   /* ghack_map_clear(NULL, NULL); */
522 
523   width = COLNO * ghack_glyph_width();
524   height = ROWNO * ghack_glyph_height();
525 
526   gnome_canvas_set_scroll_region (GNOME_CANVAS(ghack_map.canvas), 0, 0,
527 		    width+2*ghack_glyph_width(), height+2*ghack_glyph_height());
528 
529   /* remove everything currently in the canvas map */
530   gtk_object_destroy( GTK_OBJECT (myCanvasGroup));
531 
532   /* Put some groups back */
533   myCanvasGroup = GNOME_CANVAS_GROUP ( gnome_canvas_item_new (
534 		    gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)),
535 		    gnome_canvas_group_get_type (),
536 		    "x", 0.0,
537 		    "y", 0.0,
538 		    NULL) );
539 
540   /* Tile the map background with a pretty image */
541   if (background != NULL) {
542     /* Tile the map background */
543     for (y = 0; y < height+background->rgb_height; y+=background->rgb_height)
544     {
545       for (x = 0; x < width+background->rgb_width; x+=background->rgb_width)
546 	{
547 	  bg = GNOME_CANVAS_IMAGE( gnome_canvas_item_new (
548 		      myCanvasGroup, gnome_canvas_image_get_type (),
549 		      "x",      (double) x,
550 		      "y",      (double) y,
551 		      "width",  (double) background->rgb_width,
552 		      "height", (double) background->rgb_height,
553 		      "image",  background,
554 		      "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER,
555 		      NULL) );
556 	  gnome_canvas_item_lower_to_bottom (GNOME_CANVAS_ITEM( bg));
557 	}
558     }
559   }
560 
561   /* ghack_map.map is an array of canvas images.  Each cell of
562    * the array will contain one tile.  Here, we create the
563    * space for the cells and then create the cells for easy
564    * access later.
565   */
566   for (i=0, y = 0; y < height; y+=ghack_glyph_height()) {
567       for (x = 0; x < width; x+=ghack_glyph_width()) {
568 	  ghack_map.map[i++] = GNOME_CANVAS_IMAGE(
569 		  gnome_canvas_item_new (
570 		      myCanvasGroup,
571 		      gnome_canvas_image_get_type (),
572 		      "x",      (double) x,
573 		      "y",      (double) y,
574 		      "width",  (double) ghack_glyph_height(),
575 		      "height", (double) ghack_glyph_width(),
576 		      "anchor", GTK_ANCHOR_NORTH_WEST,
577 		      NULL) );
578       }
579   }
580 
581   if (petmark != NULL) {
582       /* ghack_map.overlay is an array of canvas images used to
583        * overlay tile images...
584       */
585       for (i=0, y = 0; y < height; y+=ghack_glyph_height()) {
586 	  for (x = 0; x < width; x+=ghack_glyph_width()) {
587 	      ghack_map.overlay[i] = GNOME_CANVAS_IMAGE(
588 		      gnome_canvas_item_new (
589 			  myCanvasGroup,
590 			  gnome_canvas_image_get_type (),
591 			  "x",      (double) x,
592 			  "y",      (double) y,
593 			  "width",  (double) petmark->rgb_width,
594 			  "height", (double) petmark->rgb_height,
595 			  "image",  petmark,
596 			  "anchor", GTK_ANCHOR_NORTH_WEST,
597 			  NULL) );
598 	      gnome_canvas_item_lower_to_bottom (
599 		      GNOME_CANVAS_ITEM( ghack_map.overlay[i++]));
600 	    }
601 	}
602   }
603 
604   ghack_map_cliparound(NULL, u.ux, u.uy, NULL);
605   ghack_map_cursor_to(NULL, u.ux, u.uy, NULL);
606   gnome_canvas_update_now ( ghack_map.canvas);
607   doredraw();
608 }
609 
610 
611