1 /***********************************************************************
2  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 
21 #include <X11/Intrinsic.h>
22 #include <X11/StringDefs.h>
23 #include <X11/Xaw/Scrollbar.h>
24 
25 #include "canvas.h"
26 #include "pixcomm.h"
27 
28 /* utility */
29 #include "fcintl.h"
30 #include "mem.h"
31 #include "rand.h"
32 #include "support.h"
33 #include "timing.h"
34 
35 /* common */
36 #include "government.h"		/* government_graphic() */
37 #include "map.h"
38 #include "player.h"
39 #include "unit.h"
40 #include "unitlist.h"
41 
42 /* client */
43 #include "client_main.h"
44 #include "climap.h"
45 #include "climisc.h"
46 #include "colors.h"
47 #include "control.h" /* get_unit_in_focus() */
48 #include "goto.h"
49 #include "graphics.h"
50 #include "gui_main.h"
51 #include "gui_stuff.h"
52 #include "mapctrl.h"
53 #include "options.h"
54 #include "overview_common.h"
55 #include "text.h"
56 #include "tilespec.h"
57 
58 #include "mapview.h"
59 
60 static void pixmap_put_overlay_tile(Pixmap pixmap, int x, int y,
61  				    struct sprite *ssprite);
62 static void canvas_fog_sprite_area(struct canvas *pcanvas, struct sprite *psprite,
63                                    int canvas_x, int canvas_y);
64 
65 /* the intro picture is held in this pixmap, which is scaled to
66    the screen size */
67 Pixmap scaled_intro_pixmap;
68 int scaled_intro_pixmap_width, scaled_intro_pixmap_height;
69 
70 
71 /****************************************************************************
72   Return the dimensions of the area (container widget; maximum size) for
73   the overview.
74 ****************************************************************************/
get_overview_area_dimensions(int * width,int * height)75 void get_overview_area_dimensions(int *width, int *height)
76 {
77   XtVaGetValues(left_column_form, XtNheight, &height, NULL);
78   XtVaGetValues(below_menu_form, XtNwidth, &width, NULL);
79 }
80 
81 /**************************************************************************
82 ...
83 **************************************************************************/
overview_size_changed(void)84 void overview_size_changed(void)
85 {
86   Dimension h, w;
87 
88   XtVaSetValues(overview_canvas, XtNwidth, gui_options.overview.width,
89                 XtNheight, gui_options.overview.height, NULL);
90 
91   XtVaGetValues(left_column_form, XtNheight, &h, NULL);
92   XtVaSetValues(map_form, XtNheight, h, NULL);
93 
94   XtVaGetValues(below_menu_form, XtNwidth, &w, NULL);
95   XtVaSetValues(menu_form, XtNwidth, w, NULL);
96   XtVaSetValues(bottom_form, XtNwidth, w, NULL);
97 }
98 
99 /**************************************************************************
100   Create a canvas of the given size.
101 **************************************************************************/
canvas_create(int width,int height)102 struct canvas *canvas_create(int width, int height)
103 {
104   struct canvas *result = fc_malloc(sizeof(*result));
105 
106   result->pixmap =
107       XCreatePixmap(display, root_window, width, height, display_depth);
108   return result;
109 }
110 
111 /**************************************************************************
112   Free any resources associated with this canvas and the canvas struct
113   itself.
114 **************************************************************************/
canvas_free(struct canvas * store)115 void canvas_free(struct canvas *store)
116 {
117   XFreePixmap(display, store->pixmap);
118   free(store);
119 }
120 
121 /****************************************************************************
122   Set canvas zoom for future drawing operations.
123 ****************************************************************************/
canvas_set_zoom(struct canvas * store,float zoom)124 void canvas_set_zoom(struct canvas *store, float zoom)
125 {
126   /* xaw-client has no zoom support */
127 }
128 
129 /****************************************************************************
130   This gui has zoom support.
131 ****************************************************************************/
has_zoom_support(void)132 bool has_zoom_support(void)
133 {
134   return FALSE;
135 }
136 
137 /****************************************************************************
138   Initialize canvas as mapview.
139 ****************************************************************************/
canvas_mapview_init(struct canvas * store)140 void canvas_mapview_init(struct canvas *store)
141 {
142 }
143 
144 /****************************************************************************
145   Return a canvas that is the overview window.
146 ****************************************************************************/
get_overview_window(void)147 struct canvas *get_overview_window(void)
148 {
149   static struct canvas store;
150 
151   store.pixmap = XtWindow(overview_canvas);
152 
153   return &store;
154 }
155 
156 /**************************************************************************
157 ...
158 **************************************************************************/
update_turn_done_button(bool do_restore)159 void update_turn_done_button(bool do_restore)
160 {
161   static bool flip = FALSE;
162 
163   if (!get_turn_done_button_state()) {
164     return;
165   }
166 
167   if ((do_restore && flip) || !do_restore) {
168     Pixel fore, back;
169 
170     XtVaGetValues(turn_done_button, XtNforeground, &fore,
171 		  XtNbackground, &back, NULL);
172 
173     XtVaSetValues(turn_done_button, XtNforeground, back,
174 		  XtNbackground, fore, NULL);
175 
176     flip = !flip;
177   }
178 }
179 
180 
181 /**************************************************************************
182 ...
183 **************************************************************************/
update_timeout_label(void)184 void update_timeout_label(void)
185 {
186   xaw_set_label(timeout_label, get_timeout_label_text());
187 }
188 
189 
190 /**************************************************************************
191 ...
192 **************************************************************************/
update_info_label(void)193 void update_info_label(void)
194 {
195   int d = 0;
196 
197   xaw_set_label(info_command, get_info_label_text(TRUE));
198 
199   set_indicator_icons(client_research_sprite(),
200 		      client_warming_sprite(),
201 		      client_cooling_sprite(),
202 		      client_government_sprite());
203 
204   if (NULL == client.conn.playing) {
205     return;
206   }
207 
208   for (; d < (client.conn.playing->economic.luxury) / 10; d++) {
209     xaw_set_bitmap(econ_label[d], get_tax_sprite(tileset, O_LUXURY)->pixmap);
210   }
211 
212   for (; d < (client.conn.playing->economic.science + client.conn.playing->economic.luxury) / 10; d++) {
213     xaw_set_bitmap(econ_label[d], get_tax_sprite(tileset, O_SCIENCE)->pixmap);
214   }
215 
216   for(; d < 10; d++) {
217     xaw_set_bitmap(econ_label[d], get_tax_sprite(tileset, O_GOLD)->pixmap);
218   }
219 
220   update_timeout_label();
221 }
222 
223 
224 /**************************************************************************
225   Update the information label which gives info on the current unit and the
226   square under the current unit, for specified unit.  Note that in practice
227   punit is almost always (or maybe strictly always?) the focus unit.
228   Clears label if punit is NULL.
229   Also updates the cursor for the map_canvas (this is related because the
230   info label includes a "select destination" prompt etc).
231   Also calls update_unit_pix_label() to update the icons for units on this
232   square.
233 **************************************************************************/
update_unit_info_label(struct unit_list * punitlist)234 void update_unit_info_label(struct unit_list *punitlist)
235 {
236   char buffer[512];
237 
238   fc_snprintf(buffer, sizeof(buffer), "%s\n%s",
239               get_unit_info_label_text1(punitlist),
240               get_unit_info_label_text2(punitlist, 0));
241   xaw_set_label(unit_info_label, buffer);
242 
243   if (punitlist && unit_list_size(punitlist) > 0) {
244     switch (hover_state) {
245     case HOVER_NONE:
246       XUndefineCursor(display, XtWindow(map_canvas));
247       break;
248     case HOVER_PATROL:
249       XDefineCursor(display, XtWindow(map_canvas), cursors[CURSOR_PATROL]);
250       break;
251     case HOVER_GOTO:
252     case HOVER_CONNECT:
253       XDefineCursor(display, XtWindow(map_canvas), cursors[CURSOR_GOTO]);
254       break;
255     case HOVER_NUKE:
256       XDefineCursor(display, XtWindow(map_canvas), cursors[CURSOR_NUKE]);
257       break;
258     case HOVER_PARADROP:
259       XDefineCursor(display, XtWindow(map_canvas), cursors[CURSOR_PARADROP]);
260       break;
261     case HOVER_ACT_SEL_TGT:
262       XDefineCursor(display, XtWindow(map_canvas), cursors[CURSOR_SELECT]);
263       break;
264     }
265   } else {
266     xaw_set_label(unit_info_label, "");
267     XUndefineCursor(display, XtWindow(map_canvas));
268   }
269 
270   update_unit_pix_label(punitlist);
271 }
272 
273 /**************************************************************************
274   This function will change the current mouse cursor.
275 **************************************************************************/
update_mouse_cursor(enum cursor_type new_cursor_type)276 void update_mouse_cursor(enum cursor_type new_cursor_type)
277 {
278   /* PORT ME */
279 }
280 
281 /**************************************************************************
282 ...
283 **************************************************************************/
get_thumb_pixmap(int onoff)284 Pixmap get_thumb_pixmap(int onoff)
285 {
286   /* FIXME: what about the mask? */
287   return get_treaty_thumb_sprite(tileset, BOOL_VAL(onoff))->pixmap;
288 }
289 
290 /**************************************************************************
291 ...
292 **************************************************************************/
get_citizen_pixmap(enum citizen_category type,int cnum,struct city * pcity)293 Pixmap get_citizen_pixmap(enum citizen_category type, int cnum,
294 			  struct city *pcity)
295 {
296   return get_citizen_sprite(tileset, type, cnum, pcity)->pixmap;
297 }
298 
299 
300 /**************************************************************************
301 ...
302 **************************************************************************/
set_indicator_icons(struct sprite * bulb,struct sprite * sol,struct sprite * flake,struct sprite * gov)303 void set_indicator_icons(struct sprite *bulb, struct sprite *sol,
304 			 struct sprite *flake, struct sprite *gov)
305 {
306   xaw_set_bitmap(bulb_label, bulb->pixmap);
307   xaw_set_bitmap(sun_label, sol->pixmap);
308   xaw_set_bitmap(flake_label, flake->pixmap);
309   xaw_set_bitmap(government_label, gov->pixmap);
310 }
311 
312 /**************************************************************************
313 ...
314 **************************************************************************/
overview_canvas_expose(Widget w,XEvent * event,Region exposed,void * client_data)315 void overview_canvas_expose(Widget w, XEvent *event, Region exposed,
316 			    void *client_data)
317 {
318   Dimension height, width;
319 
320   if (!can_client_change_view()) {
321     if (radar_gfx_sprite) {
322       XCopyArea(display, radar_gfx_sprite->pixmap, XtWindow(overview_canvas),
323                  civ_gc,
324                  event->xexpose.x, event->xexpose.y,
325                  event->xexpose.width, event->xexpose.height,
326                  event->xexpose.x, event->xexpose.y);
327     }
328     return;
329   }
330 
331   XtVaGetValues(w, XtNheight, &height, XtNwidth, &width, NULL);
332 
333   refresh_overview_from_canvas();
334 }
335 
336 /**************************************************************************
337 ...
338 **************************************************************************/
canvas_copy(struct canvas * dest,struct canvas * src,int src_x,int src_y,int dest_x,int dest_y,int width,int height)339 void canvas_copy(struct canvas *dest, struct canvas *src,
340 		 int src_x, int src_y, int dest_x, int dest_y,
341 		 int width, int height)
342 {
343   XCopyArea(display, src->pixmap, dest->pixmap, civ_gc, src_x, src_y, width,
344 	    height, dest_x, dest_y);
345 }
346 
347 /**************************************************************************
348 ...
349 **************************************************************************/
map_canvas_expose(Widget w,XEvent * event,Region exposed,void * client_data)350 void map_canvas_expose(Widget w, XEvent *event, Region exposed,
351 		       void *client_data)
352 {
353   Dimension width, height;
354   bool map_resized;
355 
356   XtVaGetValues(w, XtNwidth, &width, XtNheight, &height, NULL);
357 
358   map_resized = map_canvas_resized(width, height);
359 
360   if (!can_client_change_view()) {
361     if (!intro_gfx_sprite) {
362       load_intro_gfx();
363     }
364     if (height != scaled_intro_pixmap_height
365         || width != scaled_intro_pixmap_width) {
366       if (scaled_intro_pixmap) {
367 	XFreePixmap(display, scaled_intro_pixmap);
368       }
369 
370       scaled_intro_pixmap=x_scale_pixmap(intro_gfx_sprite->pixmap,
371 					 intro_gfx_sprite->width,
372 					 intro_gfx_sprite->height,
373 					 width, height, root_window);
374       scaled_intro_pixmap_width=width;
375       scaled_intro_pixmap_height=height;
376     }
377 
378     if(scaled_intro_pixmap)
379        XCopyArea(display, scaled_intro_pixmap, XtWindow(map_canvas),
380 		 civ_gc,
381 		 event->xexpose.x, event->xexpose.y,
382 		 event->xexpose.width, event->xexpose.height,
383 		 event->xexpose.x, event->xexpose.y);
384     return;
385   }
386   if(scaled_intro_pixmap) {
387     XFreePixmap(display, scaled_intro_pixmap);
388     scaled_intro_pixmap=0; scaled_intro_pixmap_height=0;
389   }
390 
391   if (map_exists() && !map_resized) {
392     /* First we mark the area to be updated as dirty.  Then we unqueue
393      * any pending updates, to make sure only the most up-to-date data
394      * is written (otherwise drawing bugs happen when old data is copied
395      * to screen).  Then we draw all changed areas to the screen. */
396     unqueue_mapview_updates(FALSE);
397     XCopyArea(display, mapview.store->pixmap, XtWindow(map_canvas),
398 	      civ_gc,
399 	      event->xexpose.x, event->xexpose.y,
400 	      event->xexpose.width, event->xexpose.height,
401 	      event->xexpose.x, event->xexpose.y);
402   }
403   refresh_overview_canvas();
404 }
405 
406 /**************************************************************************
407   Draw a single masked sprite to the pixmap.
408 **************************************************************************/
pixmap_put_sprite(Pixmap pixmap,int canvas_x,int canvas_y,struct sprite * sprite,int offset_x,int offset_y,int width,int height)409 static void pixmap_put_sprite(Pixmap pixmap,
410 			      int canvas_x, int canvas_y,
411 			      struct sprite *sprite,
412 			      int offset_x, int offset_y,
413 			      int width, int height)
414 {
415   if (sprite->has_mask) {
416     XSetClipOrigin(display, civ_gc, canvas_x, canvas_y);
417     XSetClipMask(display, civ_gc, sprite->mask);
418   }
419 
420   XCopyArea(display, sprite->pixmap, pixmap,
421 	    civ_gc,
422 	    offset_x, offset_y,
423 	    width, height,
424 	    canvas_x, canvas_y);
425 
426   if (sprite->has_mask) {
427     XSetClipMask(display, civ_gc, None);
428   }
429 }
430 
431 /**************************************************************************
432   Draw some or all of a sprite onto the mapview or citydialog canvas.
433 **************************************************************************/
canvas_put_sprite(struct canvas * pcanvas,int canvas_x,int canvas_y,struct sprite * sprite,int offset_x,int offset_y,int width,int height)434 void canvas_put_sprite(struct canvas *pcanvas,
435 		       int canvas_x, int canvas_y,
436 		       struct sprite *sprite,
437 		       int offset_x, int offset_y, int width, int height)
438 {
439   pixmap_put_sprite(pcanvas->pixmap, canvas_x, canvas_y,
440 		    sprite, offset_x, offset_y, width, height);
441 }
442 
443 /**************************************************************************
444   Draw a full sprite onto the mapview or citydialog canvas.
445 **************************************************************************/
canvas_put_sprite_full(struct canvas * pcanvas,int canvas_x,int canvas_y,struct sprite * sprite)446 void canvas_put_sprite_full(struct canvas *pcanvas,
447 			    int canvas_x, int canvas_y,
448 			    struct sprite *sprite)
449 {
450   canvas_put_sprite(pcanvas, canvas_x, canvas_y,
451 		    sprite, 0, 0, sprite->width, sprite->height);
452 }
453 
454 /****************************************************************************
455   Draw a full sprite onto the canvas.  If "fog" is specified draw it with
456   fog.
457 ****************************************************************************/
canvas_put_sprite_fogged(struct canvas * pcanvas,int canvas_x,int canvas_y,struct sprite * psprite,bool fog,int fog_x,int fog_y)458 void canvas_put_sprite_fogged(struct canvas *pcanvas,
459 			      int canvas_x, int canvas_y,
460 			      struct sprite *psprite,
461 			      bool fog, int fog_x, int fog_y)
462 {
463   canvas_put_sprite_full(pcanvas, canvas_x, canvas_y, psprite);
464 
465   if (fog) {
466     canvas_fog_sprite_area(pcanvas, psprite, canvas_x, canvas_y);
467   }
468 }
469 
470 /**************************************************************************
471   Draw a filled-in colored rectangle onto the mapview or citydialog canvas.
472 **************************************************************************/
canvas_put_rectangle(struct canvas * pcanvas,struct color * pcolor,int canvas_x,int canvas_y,int width,int height)473 void canvas_put_rectangle(struct canvas *pcanvas,
474 			  struct color *pcolor,
475 			  int canvas_x, int canvas_y, int width, int height)
476 {
477   XSetForeground(display, fill_bg_gc, pcolor->color.pixel);
478   XFillRectangle(display, pcanvas->pixmap, fill_bg_gc,
479 		 canvas_x, canvas_y, width, height);
480 }
481 
482 /****************************************************************************
483   Fill the area covered by the sprite with the given color.
484 ****************************************************************************/
canvas_fill_sprite_area(struct canvas * pcanvas,struct sprite * psprite,struct color * pcolor,int canvas_x,int canvas_y)485 void canvas_fill_sprite_area(struct canvas *pcanvas,
486 			     struct sprite *psprite,
487 			     struct color *pcolor,
488 			     int canvas_x, int canvas_y)
489 {
490   if (psprite->has_mask) {
491     XSetClipOrigin(display, fill_tile_gc, canvas_x, canvas_y);
492     XSetClipMask(display, fill_tile_gc, psprite->mask);
493   }
494   XSetForeground(display, fill_tile_gc, pcolor->color.pixel);
495 
496   XFillRectangle(display, pcanvas->pixmap, fill_tile_gc,
497 		 canvas_x, canvas_y, psprite->width, psprite->height);
498 
499   if (psprite->has_mask) {
500     XSetClipMask(display, fill_tile_gc, None);
501   }
502 }
503 
504 /****************************************************************************
505   Fill the area covered by the sprite with the given color.
506 ****************************************************************************/
canvas_fog_sprite_area(struct canvas * pcanvas,struct sprite * psprite,int canvas_x,int canvas_y)507 static void canvas_fog_sprite_area(struct canvas *pcanvas, struct sprite *psprite,
508                                    int canvas_x, int canvas_y)
509 {
510   if (psprite->has_mask) {
511     XSetClipOrigin(display, fill_tile_gc, canvas_x, canvas_y);
512     XSetClipMask(display, fill_tile_gc, psprite->mask);
513   }
514   XSetStipple(display, fill_tile_gc, gray50);
515   XSetTSOrigin(display, fill_tile_gc, canvas_x, canvas_y);
516   XSetForeground(display, fill_tile_gc,
517 		 get_color(tileset, COLOR_MAPVIEW_UNKNOWN)->color.pixel);
518 
519   XFillRectangle(display, pcanvas->pixmap, fill_tile_gc,
520 		 canvas_x, canvas_y, psprite->width, psprite->height);
521 
522   if (psprite->has_mask) {
523     XSetClipMask(display, fill_tile_gc, None);
524   }
525 }
526 
527 /**************************************************************************
528   Draw a 1-pixel-width colored line onto the mapview or citydialog canvas.
529 **************************************************************************/
canvas_put_line(struct canvas * pcanvas,struct color * pcolor,enum line_type ltype,int start_x,int start_y,int dx,int dy)530 void canvas_put_line(struct canvas *pcanvas, struct color *pcolor,
531 		     enum line_type ltype, int start_x, int start_y,
532 		     int dx, int dy)
533 {
534   GC gc = NULL;
535 
536   switch (ltype) {
537   case LINE_NORMAL:
538     gc = civ_gc;
539     break;
540   case LINE_BORDER:
541     gc = border_line_gc;
542     break;
543   case LINE_TILE_FRAME:
544   case LINE_GOTO:
545     /* TODO: differentiate these. */
546     gc = civ_gc;
547     break;
548   }
549 
550   XSetForeground(display, gc, pcolor->color.pixel);
551   XDrawLine(display, pcanvas->pixmap, gc,
552 	    start_x, start_y, start_x + dx, start_y + dy);
553 }
554 
555 /**************************************************************************
556   Draw a 1-pixel-width curved colored line onto the mapview or
557   citydialog canvas.
558 **************************************************************************/
canvas_put_curved_line(struct canvas * pcanvas,struct color * pcolor,enum line_type ltype,int start_x,int start_y,int dx,int dy)559 void canvas_put_curved_line(struct canvas *pcanvas, struct color *pcolor,
560                             enum line_type ltype, int start_x, int start_y,
561                             int dx, int dy)
562 {
563   /* FIXME: Implement curved line drawing. */
564   canvas_put_line(pcanvas, pcolor, ltype, start_x, start_y, dx, dy);
565 }
566 
567 /**************************************************************************
568   Flush the given part of the canvas buffer (if there is one) to the
569   screen.
570 **************************************************************************/
flush_mapcanvas(int canvas_x,int canvas_y,int pixel_width,int pixel_height)571 void flush_mapcanvas(int canvas_x, int canvas_y,
572 		     int pixel_width, int pixel_height)
573 {
574   XCopyArea(display, mapview.store->pixmap, XtWindow(map_canvas),
575 	    civ_gc,
576 	    canvas_x, canvas_y, pixel_width, pixel_height,
577 	    canvas_x, canvas_y);
578 }
579 
580 #define MAX_DIRTY_RECTS 20
581 static int num_dirty_rects = 0;
582 static XRectangle dirty_rects[MAX_DIRTY_RECTS];
583 bool is_flush_queued = FALSE;
584 
585 /**************************************************************************
586   A callback invoked as a result of a 0-length timer, this function simply
587   flushes the mapview canvas.
588 **************************************************************************/
unqueue_flush(XtPointer client_data,XtIntervalId * id)589 static void unqueue_flush(XtPointer client_data, XtIntervalId * id)
590 {
591   flush_dirty();
592   redraw_selection_rectangle();
593   is_flush_queued = FALSE;
594 }
595 
596 /**************************************************************************
597   Called when a region is marked dirty, this function queues a flush event
598   to be handled later by Xaw.  The flush may end up being done
599   by freeciv before then, in which case it will be a wasted call.
600 **************************************************************************/
queue_flush(void)601 static void queue_flush(void)
602 {
603   if (!is_flush_queued) {
604     (void) XtAppAddTimeOut(app_context, 0, unqueue_flush, NULL);
605     is_flush_queued = TRUE;
606   }
607 }
608 
609 /**************************************************************************
610   Mark the rectangular region as 'dirty' so that we know to flush it
611   later.
612 **************************************************************************/
dirty_rect(int canvas_x,int canvas_y,int pixel_width,int pixel_height)613 void dirty_rect(int canvas_x, int canvas_y,
614 		int pixel_width, int pixel_height)
615 {
616   if (num_dirty_rects < MAX_DIRTY_RECTS) {
617     dirty_rects[num_dirty_rects].x = canvas_x;
618     dirty_rects[num_dirty_rects].y = canvas_y;
619     dirty_rects[num_dirty_rects].width = pixel_width;
620     dirty_rects[num_dirty_rects].height = pixel_height;
621     num_dirty_rects++;
622     queue_flush();
623   }
624 }
625 
626 /**************************************************************************
627   Mark the entire screen area as "dirty" so that we can flush it later.
628 **************************************************************************/
dirty_all(void)629 void dirty_all(void)
630 {
631   num_dirty_rects = MAX_DIRTY_RECTS;
632   queue_flush();
633 }
634 
635 /**************************************************************************
636   Flush all regions that have been previously marked as dirty.  See
637   dirty_rect and dirty_all.  This function is generally called after we've
638   processed a batch of drawing operations.
639 **************************************************************************/
flush_dirty(void)640 void flush_dirty(void)
641 {
642   if (num_dirty_rects == MAX_DIRTY_RECTS) {
643     Dimension width, height;
644 
645     XtVaGetValues(map_canvas, XtNwidth, &width, XtNheight, &height, NULL);
646     flush_mapcanvas(0, 0, width, height);
647   } else {
648     int i;
649 
650     for (i = 0; i < num_dirty_rects; i++) {
651       flush_mapcanvas(dirty_rects[i].x, dirty_rects[i].y,
652 		      dirty_rects[i].width, dirty_rects[i].height);
653     }
654   }
655   num_dirty_rects = 0;
656 }
657 
658 /****************************************************************************
659   Do any necessary synchronization to make sure the screen is up-to-date.
660   The canvas should have already been flushed to screen via flush_dirty -
661   all this function does is make sure the hardware has caught up.
662 ****************************************************************************/
gui_flush(void)663 void gui_flush(void)
664 {
665   XSync(display, 0);
666 }
667 
668 /**************************************************************************
669 ...
670 **************************************************************************/
update_map_canvas_scrollbars(void)671 void update_map_canvas_scrollbars(void)
672 {
673   float shown_h, top_h, shown_v, top_v;
674   float xmin, ymin, xmax, ymax;
675   int xsize, ysize;
676   int scroll_x, scroll_y;
677 
678   get_mapview_scroll_window(&xmin, &ymin, &xmax, &ymax, &xsize, &ysize);
679   get_mapview_scroll_pos(&scroll_x, &scroll_y);
680 
681   top_h = (float)(scroll_x - xmin) / (float)(xmax - xmin);
682   top_v = (float)(scroll_y - ymin) / (float)(ymax - ymin);
683 
684   shown_h = (float)xsize / (float)(xmax - xmin);
685   shown_v = (float)ysize / (float)(ymax - ymin);
686 
687   XawScrollbarSetThumb(map_horizontal_scrollbar, top_h, shown_h);
688   XawScrollbarSetThumb(map_vertical_scrollbar, top_v, shown_v);
689 }
690 
691 /**************************************************************************
692 ...
693 **************************************************************************/
update_map_canvas_scrollbars_size(void)694 void update_map_canvas_scrollbars_size(void)
695 {
696   /* Nothing */
697 }
698 
699 /**************************************************************************
700 Update display of descriptions associated with cities on the main map.
701 **************************************************************************/
update_city_descriptions(void)702 void update_city_descriptions(void)
703 {
704   update_map_canvas_visible();
705 }
706 
707 /**************************************************************************
708 Draw at x = left of string, y = top of string.
709 **************************************************************************/
draw_shadowed_string(struct canvas * pcanvas,XFontSet fontset,GC fgc,struct color * foreground,struct color * shadow,int x,int y,const char * string)710 static void draw_shadowed_string(struct canvas *pcanvas,
711                                  XFontSet fontset, GC fgc,
712                                  struct color *foreground,
713                                  struct color *shadow,
714                                  int x, int y, const char *string)
715 {
716   size_t len = strlen(string);
717 
718   y -= XExtentsOfFontSet(fontset)->max_logical_extent.y;
719 
720   if (foreground->color.pixel != shadow->color.pixel) {
721     XSetForeground(display, fgc, shadow->color.pixel);
722     XmbDrawString(display, pcanvas->pixmap, fontset, fgc,
723                   x + 1, y + 1, string, len);
724   }
725 
726   XSetForeground(display, fgc, foreground->color.pixel);
727   XmbDrawString(display, pcanvas->pixmap, fontset, fgc,
728                 x, y, string, len);
729 }
730 
731 static XFontSet *fonts[FONT_COUNT] = {&main_font_set, &prod_font_set};
732 static GC *font_gcs[FONT_COUNT] = {&font_gc, &prod_font_gc};
733 
734 /****************************************************************************
735   Return the size of the given text in the given font.  This size should
736   include the ascent and descent of the text.  Either of width or height
737   may be NULL in which case those values simply shouldn't be filled out.
738 ****************************************************************************/
get_text_size(int * width,int * height,enum client_font font,const char * text)739 void get_text_size(int *width, int *height,
740 		   enum client_font font, const char *text)
741 {
742   if (width) {
743     *width = XmbTextEscapement(*fonts[font], text, strlen(text));
744   }
745   if (height) {
746     /* ??? */
747     *height = XExtentsOfFontSet(*fonts[font])->max_logical_extent.height;
748   }
749 }
750 
751 /****************************************************************************
752   Draw the text onto the canvas in the given color and font.  The canvas
753   position does not account for the ascent of the text; this function must
754   take care of this manually.  The text will not be NULL but may be empty.
755 ****************************************************************************/
canvas_put_text(struct canvas * pcanvas,int canvas_x,int canvas_y,enum client_font font,struct color * pcolor,const char * text)756 void canvas_put_text(struct canvas *pcanvas, int canvas_x, int canvas_y,
757 		     enum client_font font, struct color *pcolor,
758 		     const char *text)
759 {
760   draw_shadowed_string(pcanvas, *fonts[font], *font_gcs[font],
761 		       pcolor, get_color(tileset, COLOR_MAPVIEW_UNKNOWN),
762 		       canvas_x, canvas_y, text);
763 }
764 
765 /**************************************************************************
766   FIXME:
767   For now only two food, one shield and two masks can be drawn per unit,
768   the proper way to do this is probably something like what Civ II does.
769   (One food/shield/mask drawn N times, possibly one top of itself. -- SKi
770 **************************************************************************/
put_unit_pixmap_city_overlays(struct unit * punit,Pixmap pm,int * upkeep_cost,int happy_cost)771 void put_unit_pixmap_city_overlays(struct unit *punit, Pixmap pm,
772                                    int *upkeep_cost, int happy_cost)
773 {
774   struct canvas store = {pm};
775 
776   /* wipe the slate clean */
777   XSetForeground(display, fill_bg_gc,
778 		 get_color(tileset, COLOR_MAPVIEW_CITYTEXT)->color.pixel);
779   XFillRectangle(display, pm, fill_bg_gc, 0, tileset_tile_width(tileset),
780 		 tileset_tile_height(tileset),
781 		 tileset_tile_height(tileset)
782 		 + tileset_small_sprite_height(tileset));
783 
784   put_unit_city_overlays(punit, &store, 0, tileset_tile_height(tileset),
785                          upkeep_cost, happy_cost);
786 }
787 
788 /**************************************************************************
789 ...
790 **************************************************************************/
pixmap_put_overlay_tile(Pixmap pixmap,int canvas_x,int canvas_y,struct sprite * ssprite)791 static void pixmap_put_overlay_tile(Pixmap pixmap, int canvas_x, int canvas_y,
792  				    struct sprite *ssprite)
793 {
794   if (!ssprite) return;
795 
796   pixmap_put_sprite(pixmap, canvas_x, canvas_y,
797 		    ssprite, 0, 0, ssprite->width, ssprite->height);
798 }
799 
800 /**************************************************************************
801  Draws a cross-hair overlay on a tile
802 **************************************************************************/
put_cross_overlay_tile(struct tile * ptile)803 void put_cross_overlay_tile(struct tile *ptile)
804 {
805   float canvas_x, canvas_y;
806 
807   if (tile_to_canvas_pos(&canvas_x, &canvas_y, ptile)) {
808     pixmap_put_overlay_tile(XtWindow(map_canvas), canvas_x, canvas_y,
809 			    get_attention_crosshair_sprite(tileset));
810   }
811 }
812 
813 /**************************************************************************
814 ...
815 **************************************************************************/
scrollbar_jump_callback(Widget w,XtPointer client_data,XtPointer percent_ptr)816 void scrollbar_jump_callback(Widget w, XtPointer client_data,
817 			     XtPointer percent_ptr)
818 {
819   float percent=*(float*)percent_ptr;
820   float xmin, ymin, xmax, ymax;
821   int xsize, ysize;
822   int scroll_x, scroll_y;
823 
824   if (!can_client_change_view()) {
825     return;
826   }
827 
828   get_mapview_scroll_window(&xmin, &ymin, &xmax, &ymax, &xsize, &ysize);
829   get_mapview_scroll_pos(&scroll_x, &scroll_y);
830 
831   if(w==map_horizontal_scrollbar) {
832     scroll_x = xmin + (percent * (xmax - xmin));
833   } else {
834     scroll_y = ymin + (percent * (ymax - ymin));
835   }
836 
837   set_mapview_scroll_pos(scroll_x, scroll_y);
838 }
839 
840 
841 /**************************************************************************
842 ...
843 **************************************************************************/
scrollbar_scroll_callback(Widget w,XtPointer client_data,XtPointer position_val)844 void scrollbar_scroll_callback(Widget w, XtPointer client_data,
845 			     XtPointer position_val)
846 {
847   int position = XTPOINTER_TO_INT(position_val);
848   int scroll_x, scroll_y, xstep, ystep;
849 
850   get_mapview_scroll_pos(&scroll_x, &scroll_y);
851   get_mapview_scroll_step(&xstep, &ystep);
852 
853   if (!can_client_change_view()) {
854     return;
855   }
856 
857   if(w==map_horizontal_scrollbar) {
858     if (position > 0) {
859       scroll_x += xstep;
860     } else {
861       scroll_x -= xstep;
862     }
863   }
864   else {
865     if (position > 0) {
866       scroll_y += ystep;
867     } else {
868       scroll_y -= ystep;
869     }
870   }
871 
872   set_mapview_scroll_pos(scroll_x, scroll_y);
873   update_map_canvas_scrollbars();
874 }
875 
876 /**************************************************************************
877  Area Selection
878 **************************************************************************/
draw_selection_rectangle(int canvas_x,int canvas_y,int w,int h)879 void draw_selection_rectangle(int canvas_x, int canvas_y, int w, int h)
880 {
881   /* PORTME */
882 }
883 
884 /**************************************************************************
885   This function is called when the tileset is changed.
886 **************************************************************************/
tileset_changed(void)887 void tileset_changed(void)
888 {
889   /* PORTME */
890   /* Here you should do any necessary redraws (for instance, the city
891    * dialogs usually need to be resized).
892    */
893   reset_econ_label_pixmaps();
894   update_info_label();
895   reset_unit_below_pixmaps();
896 }
897 
898 /**************************************************************************
899  Sets the position of the overview scroll window based on mapview position.
900 **************************************************************************/
update_overview_scroll_window_pos(int x,int y)901 void update_overview_scroll_window_pos(int x, int y)
902 {
903   /* TODO: PORTME. */
904 }
905 
906 /**************************************************************************
907   New turn callback
908 **************************************************************************/
start_turn(void)909 void start_turn(void)
910 {}
911