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