OSDN Git Service

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