OSDN Git Service

Initial Import
[nethackexpress/trunk.git] / win / gnome / gnmap.c
1 /*      SCCS Id: @(#)gnmap.c    3.4     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*
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   if (background == NULL) {
184       g_warning("Bummer! Failed to load the map background image (mapbg.xpm)!");
185   }
186   else {
187     gdk_imlib_render(background, background->rgb_width,
188           background->rgb_height);
189
190     /* Tile the map background */
191     for (y = 0; y < height+background->rgb_height; y+=background->rgb_height)
192     {
193       for (x = 0; x < width+background->rgb_width; x+=background->rgb_width)
194         {
195           bg = GNOME_CANVAS_IMAGE( gnome_canvas_item_new (
196                       myCanvasGroup, gnome_canvas_image_get_type (),
197                       "x",      (double) x,
198                       "y",      (double) y,
199                       "width",  (double) background->rgb_width,
200                       "height", (double) background->rgb_height,
201                       "image",  background,
202                       "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER,
203                       NULL) );
204           gnome_canvas_item_lower_to_bottom (GNOME_CANVAS_ITEM( bg));
205         }
206     }
207   }
208
209   /* ghack_map.map is an array of canvas images.  Each cell of
210    * the array will contain one tile.  Here, we create the
211    * space for the cells and then create the cells for easy
212    * access later.
213   */
214   for (i=0, y = 0; y < height; y+=ghack_glyph_height())
215     {
216       for (x = 0; x < width; x+=ghack_glyph_width())
217         {
218           ghack_map.map[i++] = GNOME_CANVAS_IMAGE( 
219                   gnome_canvas_item_new (
220                       myCanvasGroup,
221                       gnome_canvas_image_get_type (),
222                       "x",      (double) x,
223                       "y",      (double) y,
224                       "width",  (double) ghack_glyph_width(),
225                       "height", (double) ghack_glyph_height(),
226                       "anchor", GTK_ANCHOR_NORTH_WEST,
227                       NULL) );
228         }
229     }
230
231    /* Set up the pet mark image */
232   petmark = gdk_imlib_create_image_from_xpm_data( pet_mark_xpm);
233   if (petmark == NULL) {
234     g_warning("Bummer! Failed to load the pet_mark image!");
235   }
236   else {
237       gdk_imlib_render(petmark, petmark->rgb_width, petmark->rgb_height);
238
239       /* ghack_map.overlay is an array of canvas images used to
240        * overlay tile images...
241        */
242       for (i=0, y = 0; y < height; y+=ghack_glyph_height())
243         {
244           for (x = 0; x < width; x+=ghack_glyph_width())
245             {
246               ghack_map.overlay[i] = GNOME_CANVAS_IMAGE( 
247                       gnome_canvas_item_new (
248                           myCanvasGroup,
249                           gnome_canvas_image_get_type (),
250                           "x",      (double) x,
251                           "y",      (double) y,
252                           "width",  (double) petmark->rgb_width,
253                           "height", (double) petmark->rgb_height,
254                           "image",  petmark,
255                           "anchor", GTK_ANCHOR_NORTH_WEST,
256                           NULL) );
257               gnome_canvas_item_lower_to_bottom (
258                       GNOME_CANVAS_ITEM( ghack_map.overlay[i++]));
259             }
260         }
261   }
262
263   /* Resize the canvas when the spinbutton changes
264   */
265   gtk_signal_connect (GTK_OBJECT (adj),
266                       "value_changed",
267                       (GtkSignalFunc) ghack_map_window_zoom,
268                       ghack_map.canvas);
269
270   /* Game signals
271   */
272   gtk_signal_connect (GTK_OBJECT (vbox),
273                       "ghack_curs",
274                       GTK_SIGNAL_FUNC (ghack_map_cursor_to),
275                       NULL);
276   gtk_signal_connect (GTK_OBJECT (vbox),
277                       "ghack_putstr",
278                       GTK_SIGNAL_FUNC (ghack_map_putstr),
279                       NULL);
280   gtk_signal_connect (GTK_OBJECT (vbox),
281                       "ghack_print_glyph",
282                       GTK_SIGNAL_FUNC (ghack_map_print_glyph),
283                       NULL);
284   gtk_signal_connect (GTK_OBJECT (vbox),
285                       "ghack_clear",
286                       GTK_SIGNAL_FUNC (ghack_map_clear),
287                       NULL);
288   gtk_signal_connect (GTK_OBJECT (vbox),
289                       "ghack_display",
290                       GTK_SIGNAL_FUNC (ghack_map_display),
291                       NULL);
292   gtk_signal_connect (GTK_OBJECT (vbox),
293                       "ghack_cliparound",
294                       GTK_SIGNAL_FUNC (ghack_map_cliparound),
295                       NULL);
296   gtk_signal_connect (GTK_OBJECT (ghack_map.canvas),
297                       "button_press_event",
298                       GTK_SIGNAL_FUNC (ghack_handle_button_press),
299                       NULL);
300   gtk_signal_connect(GTK_OBJECT (ghack_map.canvas), 
301                       "gnome_delay_output",
302                       GTK_SIGNAL_FUNC(ghack_delay), 
303                       NULL);
304   
305   return GTK_WIDGET(vbox);
306 }
307
308
309 /* NAME: 
310  *     ghack_map_window_zoom
311  *
312  * ARGUMENTS:
313  *     double     zoom -- The zoom factor
314  *
315  * RETURNS:
316  *     Nothing.
317  *
318  * PURPOSE:
319  *     Zoom the map image in and out.  This should allow the user to
320  *     dynamically scale the map.  Ideally, the background should
321  *     *NOT* scale, but this may be impractical.
322 */
323
324 static void
325 ghack_map_window_zoom( GtkAdjustment *adj, gpointer data)
326 {
327   if ( adj->value > 3.0 ) 
328       adj->value = 3.0;
329   if ( adj->value < 0.5 )
330       adj->value = 0.5;
331   ghack_map.zoom = adj->value;
332   gnome_canvas_set_pixels_per_unit (data, adj->value);
333 }
334
335
336
337 void
338 ghack_map_cursor_to( GtkWidget *win, int x, int y, gpointer data)
339 {
340   GnomeCanvasGroup *group;
341   static GnomeCanvasRE *cursor = NULL;
342
343   double x1, y1, x2, y2;
344   float hp;
345   guint r, g, b;
346
347   x1 = x * ghack_glyph_width() - 1;
348   y1 = y * ghack_glyph_height() - 1;
349   x2 = x1 + ghack_glyph_width() + 2;
350   y2 = y1 + ghack_glyph_height() + 2;
351   hp = u.mtimedone
352           ? (u.mhmax  ? (float)u.mh/u.mhmax   : 1)
353           : (u.uhpmax ? (float)u.uhp/u.uhpmax : 1);
354
355   r = 255;
356   g = (hp >= 0.75) ? 255             : (hp >= 0.25 ? 255*2*(hp-0.25) : 0);
357   b = (hp >= 0.75) ? 255*4*(hp-0.75) : (hp >= 0.25 ? 0 : 255*4*(0.25-hp));
358
359   group = gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas));
360
361   if (!cursor) {
362     cursor = GNOME_CANVAS_RE (gnome_canvas_item_new (group, 
363                 gnome_canvas_rect_get_type (), 
364                 "width_units", 1.0, NULL));
365   }
366   gnome_canvas_item_set (GNOME_CANVAS_ITEM (cursor),
367                         "outline_color_rgba", GNOME_CANVAS_COLOR(r, g, b),
368                          "x1", x1,
369                          "y1", y1,
370                          "x2", x2,
371                          "y2", y2,
372                          NULL);
373
374   gnome_canvas_item_raise_to_top( GNOME_CANVAS_ITEM( cursor));
375   gnome_canvas_item_show( GNOME_CANVAS_ITEM(cursor));
376 }
377
378
379 void
380 ghack_map_putstr( GtkWidget *win, int attr, const char* text, gpointer data)
381 {
382     g_warning("Fixme!!! ghack_map_putstr is not implemented");
383 }
384
385 /* NAME: 
386  *     ghack_map_print_glyph( )
387  *
388  * ARGUMENTS:
389  *     XCHAR_P x, y  -- The coordinates where which to print the glyph
390  *     GdkImlibImage*   glyph -- The glyph image to print
391  *
392  * RETURNS:
393  *     Nothing.
394  *
395  * PURPOSE:
396  *     Draw the glyph-tile at the specified coordinates.
397 */
398
399 void
400 ghack_map_print_glyph( GtkObject *win, 
401                        guint x, 
402                        guint y, 
403                        GdkImlibImage *im,
404                        gpointer data)
405 {
406   GnomeCanvasGroup *group;
407   int i = y * COLNO + x;
408   int glyph = glyph_at(x,y);
409   GnomeCanvasImage *canvas_image = GNOME_CANVAS_IMAGE( ghack_map.map[i]);
410
411   group = gnome_canvas_root (GNOME_CANVAS (ghack_map.canvas));
412   
413   gnome_canvas_item_set (GNOME_CANVAS_ITEM ( canvas_image),
414                          "image",  im, NULL);
415   gnome_canvas_item_show( GNOME_CANVAS_ITEM( canvas_image));
416
417   canvas_image = GNOME_CANVAS_IMAGE( ghack_map.overlay[i]);
418
419   if (x==u.ux && y==u.uy)
420       ghack_map_cliparound(NULL, x, y, NULL);
421
422   if (glyph_is_pet(glyph)
423 #ifdef TEXTCOLOR
424                   && iflags.hilite_pet
425 #endif
426                 ) {
427       gnome_canvas_item_raise_to_top( GNOME_CANVAS_ITEM( canvas_image));
428       gnome_canvas_item_show( GNOME_CANVAS_ITEM( canvas_image));
429   }
430   else {
431       gnome_canvas_item_hide( GNOME_CANVAS_ITEM( canvas_image));
432   }
433 }
434
435
436 /* NAME: 
437  *     ghack_map_clear( )
438  *
439  * ARGUMENTS:
440  *     NONE
441  *
442  * RETURNS:
443  *     Nothing.
444  *
445  * PURPOSE:
446  *     Clear the map by hiding all the map tiles.
447 */
448
449 void
450 ghack_map_clear( GtkWidget *win, gpointer data)
451 {
452   int i;
453
454   for (i = 0; i < ROWNO * COLNO; i++)
455     {
456       if (GNOME_IS_CANVAS_IMAGE(ghack_map.map[i]))
457         {
458           gnome_canvas_item_hide( GNOME_CANVAS_ITEM (ghack_map.map[i]));
459         }
460       if (GNOME_IS_CANVAS_IMAGE(ghack_map.overlay[i]))
461         {
462           gnome_canvas_item_hide( GNOME_CANVAS_ITEM (ghack_map.overlay[i]));
463         }
464     }
465   gnome_canvas_update_now ( GNOME_CANVAS(ghack_map.canvas));
466 }
467
468
469 void
470 ghack_map_display( GtkWidget *win, boolean block, gpointer data)
471 {
472   gtk_widget_show_all( GTK_WIDGET(win));
473 }
474
475
476 void
477 ghack_map_cliparound( GtkWidget *win,
478                       int x,
479                       int y,
480                       gpointer data)
481 {
482   int  map_width, map_height;
483   int  to_x, to_y;
484   int  cur_x, cur_y;
485   int  width, height, half_width, half_height;
486
487   x *= ghack_glyph_width() * ghack_map.zoom;
488   y *= ghack_glyph_height() * ghack_map.zoom;
489   map_width = COLNO * ghack_glyph_width() * ghack_map.zoom;
490   map_height = ROWNO * ghack_glyph_height() * ghack_map.zoom;
491
492   gdk_window_get_size( GTK_LAYOUT (ghack_map.canvas)->bin_window, 
493           &width, &height);
494   gnome_canvas_get_scroll_offsets( ghack_map.canvas, &cur_x, &cur_y);
495
496   half_width  = width * 0.5;
497   half_height = height * 0.5;
498
499   if ( ((x - cur_x) < (width * 0.25) ) || ( (x - cur_x) > (width * 0.75) ) ) {
500     to_x = ((x-half_width) > 0)? x - half_width : 0;
501     to_x = ((x+half_width) > map_width)? map_width - 2 * half_width : to_x;
502   }                                                                             
503   else {
504     to_x = cur_x;
505   }                                                                             
506
507   if ( ((y - cur_y) < (height * 0.25) ) || ( (y - cur_y) > (height * 0.75) ) ) {
508     to_y = ((y-half_height) > 0)? y - half_height : 0;
509     to_y = ((y+half_height) > map_height)? map_height - 2 * half_height : to_y;
510   }                                                                             
511   else {
512     to_y = cur_y;
513   }                                                                             
514
515   if (to_x != cur_x || to_y != cur_y)
516     gnome_canvas_scroll_to( ghack_map.canvas, to_x, to_y);
517   //gnome_canvas_update_now ( ghack_map.canvas);
518   
519 }
520
521
522
523 void
524 ghack_reinit_map_window ( )
525 {
526   GnomeCanvasImage  *bg;
527   double width, height, x, y;
528   int i;
529
530   /* ghack_map_clear(NULL, NULL); */
531
532   width = COLNO * ghack_glyph_width();
533   height = ROWNO * ghack_glyph_height();
534
535   gnome_canvas_set_scroll_region (GNOME_CANVAS(ghack_map.canvas), 0, 0, 
536                     width+2*ghack_glyph_width(), height+2*ghack_glyph_height());
537
538   /* remove everything currently in the canvas map */
539   gtk_object_destroy( GTK_OBJECT (myCanvasGroup));
540
541   /* Put some groups back */
542   myCanvasGroup = GNOME_CANVAS_GROUP ( gnome_canvas_item_new ( 
543                     gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)), 
544                     gnome_canvas_group_get_type (), 
545                     "x", 0.0, 
546                     "y", 0.0, 
547                     NULL) );
548
549   /* Tile the map background with a pretty image */ 
550   if (background != NULL) {
551     /* Tile the map background */
552     for (y = 0; y < height+background->rgb_height; y+=background->rgb_height)
553     {
554       for (x = 0; x < width+background->rgb_width; x+=background->rgb_width)
555         {
556           bg = GNOME_CANVAS_IMAGE( gnome_canvas_item_new (
557                       myCanvasGroup, gnome_canvas_image_get_type (),
558                       "x",      (double) x,
559                       "y",      (double) y,
560                       "width",  (double) background->rgb_width,
561                       "height", (double) background->rgb_height,
562                       "image",  background,
563                       "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER,
564                       NULL) );
565           gnome_canvas_item_lower_to_bottom (GNOME_CANVAS_ITEM( bg));
566         }
567     }
568   }
569
570   /* ghack_map.map is an array of canvas images.  Each cell of
571    * the array will contain one tile.  Here, we create the
572    * space for the cells and then create the cells for easy
573    * access later.
574   */
575   for (i=0, y = 0; y < height; y+=ghack_glyph_height()) {
576       for (x = 0; x < width; x+=ghack_glyph_width()) {
577           ghack_map.map[i++] = GNOME_CANVAS_IMAGE( 
578                   gnome_canvas_item_new (
579                       myCanvasGroup,
580                       gnome_canvas_image_get_type (),
581                       "x",      (double) x,
582                       "y",      (double) y,
583                       "width",  (double) ghack_glyph_width(),
584                       "height", (double) ghack_glyph_height(),
585                       "anchor", GTK_ANCHOR_NORTH_WEST,
586                       NULL) );
587       }
588   }
589   
590   if (petmark != NULL) {
591       /* ghack_map.overlay is an array of canvas images used to
592        * overlay tile images...
593       */
594       for (i=0, y = 0; y < height; y+=ghack_glyph_height()) {
595           for (x = 0; x < width; x+=ghack_glyph_width()) {
596               ghack_map.overlay[i] = GNOME_CANVAS_IMAGE( 
597                       gnome_canvas_item_new (
598                           myCanvasGroup,
599                           gnome_canvas_image_get_type (),
600                           "x",      (double) x,
601                           "y",      (double) y,
602                           "width",  (double) petmark->rgb_width,
603                           "height", (double) petmark->rgb_height,
604                           "image",  petmark,
605                           "anchor", GTK_ANCHOR_NORTH_WEST,
606                           NULL) );
607               gnome_canvas_item_lower_to_bottom (
608                       GNOME_CANVAS_ITEM( ghack_map.overlay[i++]));
609             }
610         }
611   }
612
613   ghack_map_cliparound(NULL, u.ux, u.uy, NULL);
614   ghack_map_cursor_to(NULL, u.ux, u.uy, NULL);
615   gnome_canvas_update_now ( ghack_map.canvas);
616   doredraw();
617 }
618
619