Qt client - remove right click menu from end turn sidebar
[freeciv.git] / client / gui-gtk-2.0 / mapview.c
blob9c815f655da67d333911e7e0299d659fdd1f86cc
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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <stdio.h>
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h>
22 #endif
24 #include <gtk/gtk.h>
26 /* utility */
27 #include "fcintl.h"
28 #include "log.h"
29 #include "mem.h"
30 #include "rand.h"
31 #include "support.h"
32 #include "timing.h"
34 /* common */
35 #include "game.h"
36 #include "government.h" /* government_graphic() */
37 #include "map.h"
38 #include "player.h"
40 /* client */
41 #include "client_main.h"
42 #include "climap.h"
43 #include "climisc.h"
44 #include "colors.h"
45 #include "control.h" /* get_unit_in_focus() */
46 #include "editor.h"
47 #include "options.h"
48 #include "overview_common.h"
49 #include "tilespec.h"
50 #include "text.h"
52 /* client/gui-gtk-2.0 */
53 #include "citydlg.h" /* For reset_city_dialogs() */
54 #include "editgui.h"
55 #include "graphics.h"
56 #include "gui_main.h"
57 #include "gui_stuff.h"
58 #include "mapctrl.h"
59 #include "repodlgs.h"
60 #include "wldlg.h"
62 #include "mapview.h"
64 static GtkObject *map_hadj, *map_vadj;
65 static int cursor_timer_id = 0, cursor_type = -1, cursor_frame = 0;
66 static int mapview_frozen_level = 0;
68 /**************************************************************************
69 If do_restore is FALSE it will invert the turn done button style. If
70 called regularly from a timer this will give a blinking turn done
71 button. If do_restore is TRUE this will reset the turn done button
72 to the default style.
73 **************************************************************************/
74 void update_turn_done_button(bool do_restore)
76 static bool flip = FALSE;
78 if (!get_turn_done_button_state()) {
79 return;
82 if ((do_restore && flip) || !do_restore) {
83 GdkGC *fore = turn_done_button->style->bg_gc[GTK_STATE_NORMAL];
84 GdkGC *back = turn_done_button->style->light_gc[GTK_STATE_NORMAL];
86 turn_done_button->style->bg_gc[GTK_STATE_NORMAL] = back;
87 turn_done_button->style->light_gc[GTK_STATE_NORMAL] = fore;
89 gtk_expose_now(turn_done_button);
91 flip = !flip;
95 /**************************************************************************
96 Timeout label requires refreshing
97 **************************************************************************/
98 void update_timeout_label(void)
100 gtk_label_set_text(GTK_LABEL(timeout_label), get_timeout_label_text());
102 if (current_turn_timeout() > 0) {
103 gtk_widget_set_tooltip_text(timeout_label,
104 _("Time to forced turn change,\n"
105 "or estimated time to finish turn change "
106 "processing."));
107 } else {
108 gtk_widget_set_tooltip_text(timeout_label,
109 _("Turn timeout disabled.\n"
110 "Between turns this shows estimated time "
111 "to finish turn change processing."));
115 /**************************************************************************
116 Refresh info label
117 **************************************************************************/
118 void update_info_label(void)
120 GtkWidget *label;
121 const struct player *pplayer = client.conn.playing;
123 label = gtk_frame_get_label_widget(GTK_FRAME(main_frame_civ_name));
124 if (pplayer != NULL) {
125 const gchar *name;
126 gunichar c;
128 /* Capitalize the first character of the translated nation
129 * plural name so that the frame label looks good. */
130 name = nation_plural_for_player(pplayer);
131 c = g_utf8_get_char_validated(name, -1);
132 if ((gunichar) -1 != c && (gunichar) -2 != c) {
133 gchar nation[MAX_LEN_NAME];
134 gchar *next;
135 gint len;
137 len = g_unichar_to_utf8(g_unichar_toupper(c), nation);
138 nation[len] = '\0';
139 next = g_utf8_find_next_char(name, NULL);
140 if (NULL != next) {
141 sz_strlcat(nation, next);
143 gtk_label_set_text(GTK_LABEL(label), nation);
144 } else {
145 gtk_label_set_text(GTK_LABEL(label), name);
147 } else {
148 gtk_label_set_text(GTK_LABEL(label), "-");
151 gtk_label_set_text(GTK_LABEL(main_label_info),
152 get_info_label_text(!gui_options.gui_gtk2_small_display_layout));
154 set_indicator_icons(client_research_sprite(),
155 client_warming_sprite(),
156 client_cooling_sprite(),
157 client_government_sprite());
159 if (NULL != client.conn.playing) {
160 int d = 0;
162 for (; d < client.conn.playing->economic.luxury /10; d++) {
163 struct sprite *sprite = get_tax_sprite(tileset, O_LUXURY);
165 gtk_image_set_from_pixbuf(GTK_IMAGE(econ_label[d]),
166 sprite_get_pixbuf(sprite));
169 for (; d < (client.conn.playing->economic.science
170 + client.conn.playing->economic.luxury) / 10; d++) {
171 struct sprite *sprite = get_tax_sprite(tileset, O_SCIENCE);
173 gtk_image_set_from_pixbuf(GTK_IMAGE(econ_label[d]),
174 sprite_get_pixbuf(sprite));
177 for (; d < 10; d++) {
178 struct sprite *sprite = get_tax_sprite(tileset, O_GOLD);
180 gtk_image_set_from_pixbuf(GTK_IMAGE(econ_label[d]),
181 sprite_get_pixbuf(sprite));
185 update_timeout_label();
187 /* update tooltips. */
188 gtk_widget_set_tooltip_text(econ_ebox,
189 _("Shows your current luxury/science/tax rates; "
190 "click to toggle them."));
192 gtk_widget_set_tooltip_text(bulb_ebox, get_bulb_tooltip());
193 gtk_widget_set_tooltip_text(sun_ebox, get_global_warming_tooltip());
194 gtk_widget_set_tooltip_text(flake_ebox, get_nuclear_winter_tooltip());
195 gtk_widget_set_tooltip_text(government_ebox, get_government_tooltip());
198 /**************************************************************************
199 This function is used to animate the mouse cursor.
200 **************************************************************************/
201 static gboolean anim_cursor_cb(gpointer data)
203 if (!cursor_timer_id) {
204 return FALSE;
207 cursor_frame++;
208 if (cursor_frame == NUM_CURSOR_FRAMES) {
209 cursor_frame = 0;
212 if (cursor_type == CURSOR_DEFAULT) {
213 gdk_window_set_cursor(root_window, NULL);
214 cursor_timer_id = 0;
215 return FALSE;
218 gdk_window_set_cursor(root_window,
219 fc_cursors[cursor_type][cursor_frame]);
220 control_mouse_cursor(NULL);
221 return TRUE;
224 /**************************************************************************
225 This function will change the current mouse cursor.
226 **************************************************************************/
227 void update_mouse_cursor(enum cursor_type new_cursor_type)
229 cursor_type = new_cursor_type;
230 if (!cursor_timer_id) {
231 cursor_timer_id = g_timeout_add(CURSOR_INTERVAL, anim_cursor_cb, NULL);
235 /**************************************************************************
236 Update the information label which gives info on the current unit and the
237 square under the current unit, for specified unit. Note that in practice
238 punit is always the focus unit.
239 Clears label if punit is NULL.
240 Also updates the cursor for the map_canvas (this is related because the
241 info label includes a "select destination" prompt etc).
242 Also calls update_unit_pix_label() to update the icons for units on this
243 square.
244 **************************************************************************/
245 void update_unit_info_label(struct unit_list *punits)
247 GtkWidget *label;
249 label = gtk_frame_get_label_widget(GTK_FRAME(unit_info_frame));
250 gtk_label_set_text(GTK_LABEL(label),
251 get_unit_info_label_text1(punits));
253 gtk_label_set_text(GTK_LABEL(unit_info_label),
254 get_unit_info_label_text2(punits, 0));
256 update_unit_pix_label(punits);
260 /**************************************************************************
261 Get sprite for treaty acceptance or rejection.
262 **************************************************************************/
263 GdkPixbuf *get_thumb_pixbuf(int onoff)
265 return sprite_get_pixbuf(get_treaty_thumb_sprite(tileset, BOOL_VAL(onoff)));
268 /****************************************************************************
269 Set information for the indicator icons typically shown in the main
270 client window. The parameters tell which sprite to use for the
271 indicator.
272 ****************************************************************************/
273 void set_indicator_icons(struct sprite *bulb, struct sprite *sol,
274 struct sprite *flake, struct sprite *gov)
276 gtk_image_set_from_pixbuf(GTK_IMAGE(bulb_label),
277 sprite_get_pixbuf(bulb));
278 gtk_image_set_from_pixbuf(GTK_IMAGE(sun_label),
279 sprite_get_pixbuf(sol));
280 gtk_image_set_from_pixbuf(GTK_IMAGE(flake_label),
281 sprite_get_pixbuf(flake));
282 gtk_image_set_from_pixbuf(GTK_IMAGE(government_label),
283 sprite_get_pixbuf(gov));
286 /****************************************************************************
287 Return the maximum dimensions of the area (container widget) for the
288 overview. Due to the fact that the scaling factor is at least 1, the real
289 size could be larger. The calculation in calculate_overview_dimensions()
290 limit it to the smallest possible size.
291 ****************************************************************************/
292 void get_overview_area_dimensions(int *width, int *height)
294 *width = GUI_GTK_OVERVIEW_MIN_XSIZE;
295 *height = GUI_GTK_OVERVIEW_MIN_YSIZE;
298 /**************************************************************************
299 Size of overview changed
300 **************************************************************************/
301 void overview_size_changed(void)
303 gtk_widget_set_size_request(overview_canvas,
304 gui_options.overview.width,
305 gui_options.overview.height);
306 update_map_canvas_scrollbars_size();
309 /****************************************************************************
310 Return a canvas that is the overview window.
311 ****************************************************************************/
312 struct canvas *get_overview_window(void)
314 static struct canvas store;
316 store.type = CANVAS_PIXMAP;
317 store.v.pixmap = overview_canvas->window;
318 return &store;
321 /**************************************************************************
322 Overview canvas exposed
323 **************************************************************************/
324 gboolean overview_canvas_expose(GtkWidget *w, GdkEventExpose *ev, gpointer data)
326 if (!can_client_change_view()) {
327 if (radar_gfx_sprite) {
328 gdk_draw_drawable(overview_canvas->window, civ_gc,
329 radar_gfx_sprite->pixmap, ev->area.x, ev->area.y,
330 ev->area.x, ev->area.y,
331 ev->area.width, ev->area.height);
333 return TRUE;
336 refresh_overview_from_canvas();
337 return TRUE;
340 /****************************************************************************
341 Freeze the drawing of the map.
342 ****************************************************************************/
343 void mapview_freeze(void)
345 mapview_frozen_level++;
348 /****************************************************************************
349 Thaw the drawing of the map.
350 ****************************************************************************/
351 void mapview_thaw(void)
353 if (1 < mapview_frozen_level) {
354 mapview_frozen_level--;
355 } else {
356 fc_assert(0 < mapview_frozen_level);
357 mapview_frozen_level = 0;
358 dirty_all();
362 /****************************************************************************
363 Return whether the map should be drawn or not.
364 ****************************************************************************/
365 bool mapview_is_frozen(void)
367 return (0 < mapview_frozen_level);
370 /**************************************************************************
371 Update on canvas widget size change
372 **************************************************************************/
373 gboolean map_canvas_configure(GtkWidget *w, GdkEventConfigure *ev,
374 gpointer data)
376 map_canvas_resized(ev->width, ev->height);
377 return TRUE;
380 /**************************************************************************
381 Map canvas exposed
382 **************************************************************************/
383 gboolean map_canvas_expose(GtkWidget *w, GdkEventExpose *ev, gpointer data)
385 if (can_client_change_view() && map_exists() && !mapview_is_frozen()) {
386 /* First we mark the area to be updated as dirty. Then we unqueue
387 * any pending updates, to make sure only the most up-to-date data
388 * is written (otherwise drawing bugs happen when old data is copied
389 * to screen). Then we draw all changed areas to the screen. */
390 unqueue_mapview_updates(FALSE);
391 gdk_draw_drawable(map_canvas->window, civ_gc, mapview.store->v.pixmap,
392 ev->area.x, ev->area.y, ev->area.x, ev->area.y,
393 ev->area.width, ev->area.height);
395 return TRUE;
398 /**************************************************************************
399 Flush the given part of the canvas buffer (if there is one) to the
400 screen.
401 **************************************************************************/
402 void flush_mapcanvas(int canvas_x, int canvas_y,
403 int pixel_width, int pixel_height)
405 if (NULL != map_canvas->window && !mapview_is_frozen()) {
406 gdk_draw_drawable(map_canvas->window, civ_gc, mapview.store->v.pixmap,
407 canvas_x, canvas_y, canvas_x, canvas_y,
408 pixel_width, pixel_height);
412 #define MAX_DIRTY_RECTS 20
413 static int num_dirty_rects = 0;
414 static GdkRectangle dirty_rects[MAX_DIRTY_RECTS];
415 static bool is_flush_queued = FALSE;
417 /**************************************************************************
418 A callback invoked as a result of g_idle_add, this function simply
419 flushes the mapview canvas.
420 **************************************************************************/
421 static gboolean unqueue_flush(gpointer data)
423 flush_dirty();
424 is_flush_queued = FALSE;
426 return FALSE;
429 /**************************************************************************
430 Called when a region is marked dirty, this function queues a flush event
431 to be handled later by GTK. The flush may end up being done
432 by freeciv before then, in which case it will be a wasted call.
433 **************************************************************************/
434 static void queue_flush(void)
436 if (!is_flush_queued) {
437 g_idle_add(unqueue_flush, NULL);
438 is_flush_queued = TRUE;
442 /**************************************************************************
443 Mark the rectangular region as "dirty" so that we know to flush it
444 later.
445 **************************************************************************/
446 void dirty_rect(int canvas_x, int canvas_y,
447 int pixel_width, int pixel_height)
449 if (mapview_is_frozen()) {
450 return;
452 if (num_dirty_rects < MAX_DIRTY_RECTS) {
453 dirty_rects[num_dirty_rects].x = canvas_x;
454 dirty_rects[num_dirty_rects].y = canvas_y;
455 dirty_rects[num_dirty_rects].width = pixel_width;
456 dirty_rects[num_dirty_rects].height = pixel_height;
457 num_dirty_rects++;
458 queue_flush();
462 /**************************************************************************
463 Mark the entire screen area as "dirty" so that we can flush it later.
464 **************************************************************************/
465 void dirty_all(void)
467 if (mapview_is_frozen()) {
468 return;
470 num_dirty_rects = MAX_DIRTY_RECTS;
471 queue_flush();
474 /**************************************************************************
475 Flush all regions that have been previously marked as dirty. See
476 dirty_rect and dirty_all. This function is generally called after we've
477 processed a batch of drawing operations.
478 **************************************************************************/
479 void flush_dirty(void)
481 if (mapview_is_frozen()) {
482 return;
484 if (num_dirty_rects == MAX_DIRTY_RECTS) {
485 flush_mapcanvas(0, 0, map_canvas->allocation.width,
486 map_canvas->allocation.height);
487 } else {
488 int i;
490 for (i = 0; i < num_dirty_rects; i++) {
491 flush_mapcanvas(dirty_rects[i].x, dirty_rects[i].y,
492 dirty_rects[i].width, dirty_rects[i].height);
495 num_dirty_rects = 0;
498 /****************************************************************************
499 Do any necessary synchronization to make sure the screen is up-to-date.
500 The canvas should have already been flushed to screen via flush_dirty -
501 all this function does is make sure the hardware has caught up.
502 ****************************************************************************/
503 void gui_flush(void)
505 gdk_flush();
508 /**************************************************************************
509 Update display of descriptions associated with cities on the main map.
510 **************************************************************************/
511 void update_city_descriptions(void)
513 update_map_canvas_visible();
516 /**************************************************************************
517 Fill pixcomm with unit gfx
518 **************************************************************************/
519 void put_unit_gpixmap(struct unit *punit, GtkPixcomm *p)
521 struct canvas canvas_store;
523 canvas_store.type = CANVAS_PIXCOMM;
524 canvas_store.v.pixcomm = p;
526 gtk_pixcomm_freeze(p);
527 gtk_pixcomm_clear(p);
529 put_unit(punit, &canvas_store, 1.0, 0, 0);
531 gtk_pixcomm_thaw(p);
535 /**************************************************************************
536 FIXME:
537 For now only two food, two gold one shield and two masks can be drawn per
538 unit, the proper way to do this is probably something like what Civ II does.
539 (One food/shield/mask drawn N times, possibly one top of itself. -- SKi
540 **************************************************************************/
541 void put_unit_gpixmap_city_overlays(struct unit *punit, GtkPixcomm *p,
542 int *upkeep_cost, int happy_cost)
544 struct canvas store;
546 store.type = CANVAS_PIXCOMM;
547 store.v.pixcomm = p;
549 gtk_pixcomm_freeze(p);
551 put_unit_city_overlays(punit, &store, 0,
552 tileset_unit_layout_offset_y(tileset),
553 upkeep_cost, happy_cost);
555 gtk_pixcomm_thaw(p);
558 /**************************************************************************
559 Put overlay tile to pixmap
560 **************************************************************************/
561 void pixmap_put_overlay_tile(GdkDrawable *pixmap,
562 int canvas_x, int canvas_y,
563 struct sprite *ssprite)
565 if (!ssprite) {
566 return;
569 if (ssprite->pixmap) {
570 gdk_gc_set_clip_origin(civ_gc, canvas_x, canvas_y);
571 gdk_gc_set_clip_mask(civ_gc, ssprite->mask);
573 gdk_draw_drawable(pixmap, civ_gc, ssprite->pixmap,
574 0, 0,
575 canvas_x, canvas_y,
576 ssprite->width, ssprite->height);
577 gdk_gc_set_clip_mask(civ_gc, NULL);
578 } else {
579 gdk_draw_pixbuf(pixmap, civ_gc, ssprite->pixbuf,
580 0, 0,
581 canvas_x, canvas_y,
582 ssprite->width, ssprite->height,
583 GDK_RGB_DITHER_NONE, 0, 0);
587 /**************************************************************************
588 Place part of a (possibly masked) sprite on a pixmap.
589 **************************************************************************/
590 static void pixmap_put_sprite(GdkDrawable *pixmap,
591 int pixmap_x, int pixmap_y,
592 struct sprite *ssprite,
593 int offset_x, int offset_y,
594 int width, int height)
596 #ifdef DEBUG
597 static int sprites = 0, pixbufs = 0;
598 #endif
600 if (ssprite->pixmap) {
601 if (ssprite->mask) {
602 gdk_gc_set_clip_origin(civ_gc, pixmap_x, pixmap_y);
603 gdk_gc_set_clip_mask(civ_gc, ssprite->mask);
606 gdk_draw_drawable(pixmap, civ_gc, ssprite->pixmap,
607 offset_x, offset_y,
608 pixmap_x + offset_x, pixmap_y + offset_y,
609 MIN(width, MAX(0, ssprite->width - offset_x)),
610 MIN(height, MAX(0, ssprite->height - offset_y)));
612 gdk_gc_set_clip_mask(civ_gc, NULL);
613 } else {
614 gdk_draw_pixbuf(pixmap, civ_gc, ssprite->pixbuf,
615 offset_x, offset_y,
616 pixmap_x + offset_x, pixmap_y + offset_y,
617 MIN(width, MAX(0, ssprite->width - offset_x)),
618 MIN(height, MAX(0, ssprite->height - offset_y)),
619 GDK_RGB_DITHER_NONE, 0, 0);
620 #ifdef DEBUG
621 pixbufs++;
622 #endif
625 #ifdef DEBUG
626 sprites++;
627 if (sprites % 1000 == 0) {
628 log_debug("%5d / %5d pixbufs = %d%%",
629 pixbufs, sprites, 100 * pixbufs / sprites);
631 #endif /* DEBUG */
634 /**************************************************************************
635 Created a fogged version of the sprite. This can fail on older systems
636 in which case the callers needs a fallback.
637 **************************************************************************/
638 static void fog_sprite(struct sprite *sprite)
640 int x, y;
641 GdkPixbuf *fogged;
642 guchar *pixel;
643 const int bright = 65; /* Brightness percentage */
645 if (sprite->pixmap) {
646 fogged = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
647 sprite->width, sprite->height);
648 gdk_pixbuf_get_from_drawable(fogged, sprite->pixmap, NULL,
649 0, 0, 0, 0, sprite->width, sprite->height);
650 } else {
651 fogged = gdk_pixbuf_copy(sprite->pixbuf);
654 /* Iterate over all pixels, reducing brightness by 50%. */
655 for (x = 0; x < sprite->width; x++) {
656 for (y = 0; y < sprite->height; y++) {
657 pixel = gdk_pixbuf_get_pixels(fogged)
658 + y * gdk_pixbuf_get_rowstride(fogged)
659 + x * gdk_pixbuf_get_n_channels(fogged);
661 pixel[0] = pixel[0] * bright / 100;
662 pixel[1] = pixel[1] * bright / 100;
663 pixel[2] = pixel[2] * bright / 100;
667 if (sprite->pixmap) {
668 gdk_pixbuf_render_pixmap_and_mask(fogged, &sprite->pixmap_fogged,
669 NULL, 0);
670 g_object_unref(fogged);
671 } else {
672 sprite->pixbuf_fogged = fogged;
676 /**************************************************************************
677 Only used for isometric view.
678 **************************************************************************/
679 void pixmap_put_overlay_tile_draw(GdkDrawable *pixmap,
680 int canvas_x, int canvas_y,
681 struct sprite *ssprite,
682 bool fog)
684 if (!ssprite) {
685 return;
688 if (fog && gui_options.gui_gtk2_better_fog
689 && ((ssprite->pixmap && !ssprite->pixmap_fogged)
690 || (!ssprite->pixmap && !ssprite->pixbuf_fogged))) {
691 fog_sprite(ssprite);
692 if ((ssprite->pixmap && !ssprite->pixmap_fogged)
693 || (!ssprite->pixmap && !ssprite->pixbuf_fogged)) {
694 log_normal(_("Better fog will only work in truecolor. Disabling it"));
695 gui_options.gui_gtk2_better_fog = FALSE;
699 if (fog && gui_options.gui_gtk2_better_fog) {
700 if (ssprite->pixmap) {
701 if (ssprite->mask) {
702 gdk_gc_set_clip_origin(civ_gc, canvas_x, canvas_y);
703 gdk_gc_set_clip_mask(civ_gc, ssprite->mask);
705 gdk_draw_drawable(pixmap, civ_gc,
706 ssprite->pixmap_fogged,
707 0, 0,
708 canvas_x, canvas_y,
709 ssprite->width, ssprite->height);
710 gdk_gc_set_clip_mask(civ_gc, NULL);
711 } else {
712 gdk_draw_pixbuf(pixmap, civ_gc, ssprite->pixbuf_fogged,
713 0, 0, canvas_x, canvas_y,
714 ssprite->width, ssprite->height,
715 GDK_RGB_DITHER_NONE, 0, 0);
717 return;
720 pixmap_put_sprite(pixmap, canvas_x, canvas_y, ssprite,
721 0, 0, ssprite->width, ssprite->height);
723 /* I imagine this could be done more efficiently. Some pixels We first
724 draw from the sprite, and then draw black afterwards. It would be much
725 faster to just draw every second pixel black in the first place. */
726 if (fog) {
727 gdk_gc_set_clip_origin(fill_tile_gc, canvas_x, canvas_y);
728 gdk_gc_set_clip_mask(fill_tile_gc, sprite_get_mask(ssprite));
729 gdk_gc_set_foreground(fill_tile_gc,
730 &get_color(tileset, COLOR_MAPVIEW_UNKNOWN)->color);
731 gdk_gc_set_ts_origin(fill_tile_gc, canvas_x, canvas_y);
732 gdk_gc_set_stipple(fill_tile_gc, black50);
734 gdk_draw_rectangle(pixmap, fill_tile_gc, TRUE,
735 canvas_x, canvas_y, ssprite->width, ssprite->height);
736 gdk_gc_set_clip_mask(fill_tile_gc, NULL);
740 /**************************************************************************
741 Draws a cross-hair overlay on a tile
742 **************************************************************************/
743 void put_cross_overlay_tile(struct tile *ptile)
745 float canvas_x, canvas_y;
747 if (tile_to_canvas_pos(&canvas_x, &canvas_y, ptile)) {
748 pixmap_put_overlay_tile(map_canvas->window,
749 canvas_x, canvas_y,
750 get_attention_crosshair_sprite(tileset));
754 /*****************************************************************************
755 Sets the position of the overview scroll window based on mapview position.
756 *****************************************************************************/
757 void update_overview_scroll_window_pos(int x, int y)
759 gdouble ov_scroll_x, ov_scroll_y;
760 GtkAdjustment *ov_hadj, *ov_vadj;
762 ov_hadj = gtk_scrolled_window_get_hadjustment(
763 GTK_SCROLLED_WINDOW(overview_scrolled_window));
764 ov_vadj = gtk_scrolled_window_get_vadjustment(
765 GTK_SCROLLED_WINDOW(overview_scrolled_window));
767 ov_scroll_x = MIN(x - (overview_canvas_store_width / 2),
768 ov_hadj->upper -ov_hadj->page_size);
769 ov_scroll_y = MIN(y - (overview_canvas_store_height / 2),
770 ov_vadj->upper -ov_vadj->page_size);
772 gtk_adjustment_set_value(GTK_ADJUSTMENT(ov_hadj), ov_scroll_x);
773 gtk_adjustment_set_value(GTK_ADJUSTMENT(ov_vadj), ov_scroll_y);
776 /**************************************************************************
777 Refresh map canvas scrollbars
778 **************************************************************************/
779 void update_map_canvas_scrollbars(void)
781 int scroll_x, scroll_y;
783 get_mapview_scroll_pos(&scroll_x, &scroll_y);
784 gtk_adjustment_set_value(GTK_ADJUSTMENT(map_hadj), scroll_x);
785 gtk_adjustment_set_value(GTK_ADJUSTMENT(map_vadj), scroll_y);
788 /**************************************************************************
789 Refresh map canvas scrollbar as canvas size changes
790 **************************************************************************/
791 void update_map_canvas_scrollbars_size(void)
793 float xmin, ymin, xmax, ymax;
794 int xsize, ysize, xstep, ystep;
796 get_mapview_scroll_window(&xmin, &ymin, &xmax, &ymax, &xsize, &ysize);
797 get_mapview_scroll_step(&xstep, &ystep);
799 map_hadj = gtk_adjustment_new(-1, xmin, xmax, xstep, xsize, xsize);
800 map_vadj = gtk_adjustment_new(-1, ymin, ymax, ystep, ysize, ysize);
802 gtk_range_set_adjustment(GTK_RANGE(map_horizontal_scrollbar),
803 GTK_ADJUSTMENT(map_hadj));
804 gtk_range_set_adjustment(GTK_RANGE(map_vertical_scrollbar),
805 GTK_ADJUSTMENT(map_vadj));
807 g_signal_connect(map_hadj, "value_changed",
808 G_CALLBACK(scrollbar_jump_callback),
809 GINT_TO_POINTER(TRUE));
810 g_signal_connect(map_vadj, "value_changed",
811 G_CALLBACK(scrollbar_jump_callback),
812 GINT_TO_POINTER(FALSE));
815 /**************************************************************************
816 Scrollbar has moved
817 **************************************************************************/
818 void scrollbar_jump_callback(GtkAdjustment *adj, gpointer hscrollbar)
820 int scroll_x, scroll_y;
822 if (!can_client_change_view()) {
823 return;
826 get_mapview_scroll_pos(&scroll_x, &scroll_y);
828 if (hscrollbar) {
829 scroll_x = adj->value;
830 } else {
831 scroll_y = adj->value;
834 set_mapview_scroll_pos(scroll_x, scroll_y);
837 /**************************************************************************
838 Draws a rectangle with top left corner at (canvas_x, canvas_y), and
839 width 'w' and height 'h'. It is drawn using the 'selection_gc' context,
840 so the pixel combining function is XOR. This means that drawing twice
841 in the same place will restore the image to its original state.
843 NB: A side effect of this function is to set the 'selection_gc' color
844 to COLOR_MAPVIEW_SELECTION.
845 **************************************************************************/
846 void draw_selection_rectangle(int canvas_x, int canvas_y, int w, int h)
848 GdkPoint points[5];
849 struct color *pcolor;
851 if (w == 0 || h == 0) {
852 return;
855 pcolor = get_color(tileset, COLOR_MAPVIEW_SELECTION);
856 if (!pcolor) {
857 return;
860 /* gdk_draw_rectangle() must start top-left.. */
861 points[0].x = canvas_x;
862 points[0].y = canvas_y;
864 points[1].x = canvas_x + w;
865 points[1].y = canvas_y;
867 points[2].x = canvas_x + w;
868 points[2].y = canvas_y + h;
870 points[3].x = canvas_x;
871 points[3].y = canvas_y + h;
873 points[4].x = canvas_x;
874 points[4].y = canvas_y;
876 gdk_gc_set_foreground(selection_gc, &pcolor->color);
877 gdk_draw_lines(map_canvas->window, selection_gc,
878 points, ARRAY_SIZE(points));
881 /**************************************************************************
882 This function is called when the tileset is changed.
883 **************************************************************************/
884 void tileset_changed(void)
886 reset_city_dialogs();
887 reset_unit_table();
888 blank_max_unit_size();
889 editgui_tileset_changed();
891 /* keep the icon of the executable on Windows (see PR#36491) */
892 #ifndef WIN32_NATIVE
893 gtk_window_set_icon(GTK_WINDOW(toplevel),
894 sprite_get_pixbuf(get_icon_sprite(tileset, ICON_FREECIV)));
895 #endif
897 science_report_dialog_redraw();