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. */
16 /* globals static to this file go here */
19 GnomeCanvasImage *map[(ROWNO + 1) * COLNO];
20 GnomeCanvasImage *overlay[(ROWNO + 1) * COLNO];
25 static GdkImlibImage *background;
26 static GdkImlibImage *petmark;
27 static GnomeCanvasGroup *myCanvasGroup;
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);
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.
44 * More information about NetHackQt can be had from:
45 * http://www.troll.no/~warwick/nethack/
49 static char *pet_mark_xpm[] = {
50 /* width height ncolors chars_per_pixel */
67 * ghack_init_map_window( )
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
83 ghack_init_map_window ( )
90 GtkWidget *hSeparator;
93 double width, height, x, y;
96 width = COLNO * ghack_glyph_width();
97 height = ROWNO * ghack_glyph_height();
99 vbox = gtk_vbox_new (FALSE, 4);
100 gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
101 gtk_widget_show (vbox);
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);
108 hbox = gtk_hbox_new (FALSE, 4);
109 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
110 gtk_widget_show (hbox);
112 /* Create the Zoom spinbutton.
114 ghack_map.zoom = 1.0;
115 w = gtk_label_new ("Zoom:");
116 gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
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);
124 /* Canvas and scrollbars
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());
133 gtk_widget_pop_colormap();
134 gtk_widget_pop_visual();
135 gtk_widget_show (GTK_WIDGET(ghack_map.canvas));
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);
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,
148 GTK_EXPAND | GTK_FILL | GTK_SHRINK,
149 GTK_EXPAND | GTK_FILL | GTK_SHRINK,
151 gtk_widget_show (frame);
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());
157 gnome_canvas_set_pixels_per_unit (GNOME_CANVAS(ghack_map.canvas), 1.0);
159 w = gtk_hscrollbar_new (GTK_LAYOUT (ghack_map.canvas)->hadjustment);
160 gtk_table_attach (GTK_TABLE (table), w,
162 GTK_EXPAND | GTK_FILL | GTK_SHRINK,
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,
174 myCanvasGroup = GNOME_CANVAS_GROUP ( gnome_canvas_item_new (
175 gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)),
176 gnome_canvas_group_get_type (),
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)!");
187 gdk_imlib_render(background, background->rgb_width,
188 background->rgb_height);
190 /* Tile the map background */
191 for (y = 0; y < height+background->rgb_height; y+=background->rgb_height)
193 for (x = 0; x < width+background->rgb_width; x+=background->rgb_width)
195 bg = GNOME_CANVAS_IMAGE( gnome_canvas_item_new (
196 myCanvasGroup, gnome_canvas_image_get_type (),
199 "width", (double) background->rgb_width,
200 "height", (double) background->rgb_height,
202 "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER,
204 gnome_canvas_item_lower_to_bottom (GNOME_CANVAS_ITEM( bg));
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
214 for (i=0, y = 0; y < height; y+=ghack_glyph_height())
216 for (x = 0; x < width; x+=ghack_glyph_width())
218 ghack_map.map[i++] = GNOME_CANVAS_IMAGE(
219 gnome_canvas_item_new (
221 gnome_canvas_image_get_type (),
224 "width", (double) ghack_glyph_width(),
225 "height", (double) ghack_glyph_height(),
226 "anchor", GTK_ANCHOR_NORTH_WEST,
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!");
237 gdk_imlib_render(petmark, petmark->rgb_width, petmark->rgb_height);
239 /* ghack_map.overlay is an array of canvas images used to
240 * overlay tile images...
242 for (i=0, y = 0; y < height; y+=ghack_glyph_height())
244 for (x = 0; x < width; x+=ghack_glyph_width())
246 ghack_map.overlay[i] = GNOME_CANVAS_IMAGE(
247 gnome_canvas_item_new (
249 gnome_canvas_image_get_type (),
252 "width", (double) petmark->rgb_width,
253 "height", (double) petmark->rgb_height,
255 "anchor", GTK_ANCHOR_NORTH_WEST,
257 gnome_canvas_item_lower_to_bottom (
258 GNOME_CANVAS_ITEM( ghack_map.overlay[i++]));
263 /* Resize the canvas when the spinbutton changes
265 gtk_signal_connect (GTK_OBJECT (adj),
267 (GtkSignalFunc) ghack_map_window_zoom,
272 gtk_signal_connect (GTK_OBJECT (vbox),
274 GTK_SIGNAL_FUNC (ghack_map_cursor_to),
276 gtk_signal_connect (GTK_OBJECT (vbox),
278 GTK_SIGNAL_FUNC (ghack_map_putstr),
280 gtk_signal_connect (GTK_OBJECT (vbox),
282 GTK_SIGNAL_FUNC (ghack_map_print_glyph),
284 gtk_signal_connect (GTK_OBJECT (vbox),
286 GTK_SIGNAL_FUNC (ghack_map_clear),
288 gtk_signal_connect (GTK_OBJECT (vbox),
290 GTK_SIGNAL_FUNC (ghack_map_display),
292 gtk_signal_connect (GTK_OBJECT (vbox),
294 GTK_SIGNAL_FUNC (ghack_map_cliparound),
296 gtk_signal_connect (GTK_OBJECT (ghack_map.canvas),
297 "button_press_event",
298 GTK_SIGNAL_FUNC (ghack_handle_button_press),
300 gtk_signal_connect(GTK_OBJECT (ghack_map.canvas),
301 "gnome_delay_output",
302 GTK_SIGNAL_FUNC(ghack_delay),
305 return GTK_WIDGET(vbox);
310 * ghack_map_window_zoom
313 * double zoom -- The zoom factor
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.
325 ghack_map_window_zoom( GtkAdjustment *adj, gpointer data)
327 if ( adj->value > 3.0 )
329 if ( adj->value < 0.5 )
331 ghack_map.zoom = adj->value;
332 gnome_canvas_set_pixels_per_unit (data, adj->value);
338 ghack_map_cursor_to( GtkWidget *win, int x, int y, gpointer data)
340 GnomeCanvasGroup *group;
341 static GnomeCanvasRE *cursor = NULL;
343 double x1, y1, x2, y2;
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;
352 ? (u.mhmax ? (float)u.mh/u.mhmax : 1)
353 : (u.uhpmax ? (float)u.uhp/u.uhpmax : 1);
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));
359 group = gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas));
362 cursor = GNOME_CANVAS_RE (gnome_canvas_item_new (group,
363 gnome_canvas_rect_get_type (),
364 "width_units", 1.0, NULL));
366 gnome_canvas_item_set (GNOME_CANVAS_ITEM (cursor),
367 "outline_color_rgba", GNOME_CANVAS_COLOR(r, g, b),
374 gnome_canvas_item_raise_to_top( GNOME_CANVAS_ITEM( cursor));
375 gnome_canvas_item_show( GNOME_CANVAS_ITEM(cursor));
380 ghack_map_putstr( GtkWidget *win, int attr, const char* text, gpointer data)
382 g_warning("Fixme!!! ghack_map_putstr is not implemented");
386 * ghack_map_print_glyph( )
389 * XCHAR_P x, y -- The coordinates where which to print the glyph
390 * GdkImlibImage* glyph -- The glyph image to print
396 * Draw the glyph-tile at the specified coordinates.
400 ghack_map_print_glyph( GtkObject *win,
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]);
411 group = gnome_canvas_root (GNOME_CANVAS (ghack_map.canvas));
413 gnome_canvas_item_set (GNOME_CANVAS_ITEM ( canvas_image),
415 gnome_canvas_item_show( GNOME_CANVAS_ITEM( canvas_image));
417 canvas_image = GNOME_CANVAS_IMAGE( ghack_map.overlay[i]);
419 if (x==u.ux && y==u.uy)
420 ghack_map_cliparound(NULL, x, y, NULL);
422 if (glyph_is_pet(glyph)
427 gnome_canvas_item_raise_to_top( GNOME_CANVAS_ITEM( canvas_image));
428 gnome_canvas_item_show( GNOME_CANVAS_ITEM( canvas_image));
431 gnome_canvas_item_hide( GNOME_CANVAS_ITEM( canvas_image));
446 * Clear the map by hiding all the map tiles.
450 ghack_map_clear( GtkWidget *win, gpointer data)
454 for (i = 0; i < ROWNO * COLNO; i++)
456 if (GNOME_IS_CANVAS_IMAGE(ghack_map.map[i]))
458 gnome_canvas_item_hide( GNOME_CANVAS_ITEM (ghack_map.map[i]));
460 if (GNOME_IS_CANVAS_IMAGE(ghack_map.overlay[i]))
462 gnome_canvas_item_hide( GNOME_CANVAS_ITEM (ghack_map.overlay[i]));
465 gnome_canvas_update_now ( GNOME_CANVAS(ghack_map.canvas));
470 ghack_map_display( GtkWidget *win, boolean block, gpointer data)
472 gtk_widget_show_all( GTK_WIDGET(win));
477 ghack_map_cliparound( GtkWidget *win,
482 int map_width, map_height;
485 int width, height, half_width, half_height;
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;
492 gdk_window_get_size( GTK_LAYOUT (ghack_map.canvas)->bin_window,
494 gnome_canvas_get_scroll_offsets( ghack_map.canvas, &cur_x, &cur_y);
496 half_width = width * 0.5;
497 half_height = height * 0.5;
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;
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;
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);
524 ghack_reinit_map_window ( )
526 GnomeCanvasImage *bg;
527 double width, height, x, y;
530 /* ghack_map_clear(NULL, NULL); */
532 width = COLNO * ghack_glyph_width();
533 height = ROWNO * ghack_glyph_height();
535 gnome_canvas_set_scroll_region (GNOME_CANVAS(ghack_map.canvas), 0, 0,
536 width+2*ghack_glyph_width(), height+2*ghack_glyph_height());
538 /* remove everything currently in the canvas map */
539 gtk_object_destroy( GTK_OBJECT (myCanvasGroup));
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 (),
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)
554 for (x = 0; x < width+background->rgb_width; x+=background->rgb_width)
556 bg = GNOME_CANVAS_IMAGE( gnome_canvas_item_new (
557 myCanvasGroup, gnome_canvas_image_get_type (),
560 "width", (double) background->rgb_width,
561 "height", (double) background->rgb_height,
563 "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER,
565 gnome_canvas_item_lower_to_bottom (GNOME_CANVAS_ITEM( bg));
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
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 (
580 gnome_canvas_image_get_type (),
583 "width", (double) ghack_glyph_width(),
584 "height", (double) ghack_glyph_height(),
585 "anchor", GTK_ANCHOR_NORTH_WEST,
590 if (petmark != NULL) {
591 /* ghack_map.overlay is an array of canvas images used to
592 * overlay tile images...
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 (
599 gnome_canvas_image_get_type (),
602 "width", (double) petmark->rgb_width,
603 "height", (double) petmark->rgb_height,
605 "anchor", GTK_ANCHOR_NORTH_WEST,
607 gnome_canvas_item_lower_to_bottom (
608 GNOME_CANVAS_ITEM( ghack_map.overlay[i++]));
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);