Made left panel unit icon area big enough
[freeciv.git] / client / gui-gtk-3.22 / mapview.c
blob1d283b65d52087c0a93156c83afaa4b438f2e26a
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"
51 #include "zoom.h"
53 /* client/gui-gtk-3.22 */
54 #include "citydlg.h" /* For reset_city_dialogs() */
55 #include "editgui.h"
56 #include "graphics.h"
57 #include "gui_main.h"
58 #include "gui_stuff.h"
59 #include "mapctrl.h"
60 #include "repodlgs.h"
61 #include "wldlg.h"
63 #include "mapview.h"
65 static GtkAdjustment *map_hadj, *map_vadj;
66 static int cursor_timer_id = 0, cursor_type = -1, cursor_frame = 0;
67 static int mapview_frozen_level = 0;
69 /**************************************************************************
70 If do_restore is FALSE it will invert the turn done button style. If
71 called regularly from a timer this will give a blinking turn done
72 button. If do_restore is TRUE this will reset the turn done button
73 to the default style.
74 **************************************************************************/
75 void update_turn_done_button(bool do_restore)
77 static bool flip = FALSE;
79 if (!get_turn_done_button_state()) {
80 return;
83 if ((do_restore && flip) || !do_restore) {
84 static GtkCssProvider *tdb_provider = NULL;
85 GtkStyleContext *scontext = gtk_widget_get_style_context(turn_done_button);
87 if (tdb_provider == NULL) {
88 tdb_provider = gtk_css_provider_new();
90 gtk_css_provider_load_from_data(tdb_provider,
91 ".lighted {\n"
92 "color: rgba(235, 127, 235, 255);\n"
93 "background-color: rgba(127, 127, 127, 255);\n"
94 "}\n",
95 -1, NULL);
97 gtk_style_context_add_provider(scontext,
98 GTK_STYLE_PROVIDER(tdb_provider),
99 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
102 if (flip) {
103 gtk_style_context_add_class(scontext, "lighted");
104 } else {
105 gtk_style_context_remove_class(scontext, "lighted");
108 flip = !flip;
112 /**************************************************************************
113 Timeout label requires refreshing
114 **************************************************************************/
115 void update_timeout_label(void)
117 gtk_label_set_text(GTK_LABEL(timeout_label), get_timeout_label_text());
119 if (current_turn_timeout() > 0) {
120 gtk_widget_set_tooltip_text(timeout_label,
121 _("Time to forced turn change,\n"
122 "or estimated time to finish turn change "
123 "processing."));
124 } else {
125 gtk_widget_set_tooltip_text(timeout_label,
126 _("Turn timeout disabled.\n"
127 "Between turns this shows estimated time "
128 "to finish turn change processing."));
132 /**************************************************************************
133 Refresh info label
134 **************************************************************************/
135 void update_info_label(void)
137 GtkWidget *label;
138 const struct player *pplayer = client.conn.playing;
140 label = gtk_frame_get_label_widget(GTK_FRAME(main_frame_civ_name));
141 if (pplayer != NULL) {
142 const gchar *name;
143 gunichar c;
145 /* Capitalize the first character of the translated nation
146 * plural name so that the frame label looks good. */
147 name = nation_plural_for_player(pplayer);
148 c = g_utf8_get_char_validated(name, -1);
149 if ((gunichar) -1 != c && (gunichar) -2 != c) {
150 gchar nation[MAX_LEN_NAME];
151 gchar *next;
152 gint len;
154 len = g_unichar_to_utf8(g_unichar_toupper(c), nation);
155 nation[len] = '\0';
156 next = g_utf8_find_next_char(name, NULL);
157 if (NULL != next) {
158 sz_strlcat(nation, next);
160 gtk_label_set_text(GTK_LABEL(label), nation);
161 } else {
162 gtk_label_set_text(GTK_LABEL(label), name);
164 } else {
165 gtk_label_set_text(GTK_LABEL(label), "-");
168 gtk_label_set_text(GTK_LABEL(main_label_info),
169 get_info_label_text(!GUI_GTK_OPTION(small_display_layout)));
171 set_indicator_icons(client_research_sprite(),
172 client_warming_sprite(),
173 client_cooling_sprite(),
174 client_government_sprite());
176 if (NULL != client.conn.playing) {
177 int d = 0;
179 for (; d < client.conn.playing->economic.luxury /10; d++) {
180 struct sprite *spr = get_tax_sprite(tileset, O_LUXURY);
181 GdkPixbuf *pb;
183 pb = sprite_get_pixbuf(spr);
184 gtk_image_set_from_pixbuf(GTK_IMAGE(econ_label[d]), pb);
185 g_object_unref(pb);
188 for (; d < (client.conn.playing->economic.science
189 + client.conn.playing->economic.luxury) / 10; d++) {
190 struct sprite *spr = get_tax_sprite(tileset, O_SCIENCE);
191 GdkPixbuf *pb;
193 pb = sprite_get_pixbuf(spr);
194 gtk_image_set_from_pixbuf(GTK_IMAGE(econ_label[d]), pb);
195 g_object_unref(pb);
198 for (; d < 10; d++) {
199 struct sprite *spr = get_tax_sprite(tileset, O_GOLD);
200 GdkPixbuf *pb;
202 pb = sprite_get_pixbuf(spr);
203 gtk_image_set_from_pixbuf(GTK_IMAGE(econ_label[d]), pb);
204 g_object_unref(pb);
208 update_timeout_label();
210 /* update tooltips. */
211 gtk_widget_set_tooltip_text(econ_ebox,
212 _("Shows your current luxury/science/tax rates; "
213 "click to toggle them."));
215 gtk_widget_set_tooltip_text(bulb_ebox, get_bulb_tooltip());
216 gtk_widget_set_tooltip_text(sun_ebox, get_global_warming_tooltip());
217 gtk_widget_set_tooltip_text(flake_ebox, get_nuclear_winter_tooltip());
218 gtk_widget_set_tooltip_text(government_ebox, get_government_tooltip());
221 /**************************************************************************
222 This function is used to animate the mouse cursor.
223 **************************************************************************/
224 static gboolean anim_cursor_cb(gpointer data)
226 if (!cursor_timer_id) {
227 return FALSE;
230 cursor_frame++;
231 if (cursor_frame == NUM_CURSOR_FRAMES) {
232 cursor_frame = 0;
235 if (cursor_type == CURSOR_DEFAULT) {
236 gdk_window_set_cursor(root_window, NULL);
237 cursor_timer_id = 0;
238 return FALSE;
241 gdk_window_set_cursor(root_window,
242 fc_cursors[cursor_type][cursor_frame]);
243 control_mouse_cursor(NULL);
244 return TRUE;
247 /**************************************************************************
248 This function will change the current mouse cursor.
249 **************************************************************************/
250 void update_mouse_cursor(enum cursor_type new_cursor_type)
252 cursor_type = new_cursor_type;
253 if (!cursor_timer_id) {
254 cursor_timer_id = g_timeout_add(CURSOR_INTERVAL, anim_cursor_cb, NULL);
258 /**************************************************************************
259 Update the information label which gives info on the current unit and the
260 square under the current unit, for specified unit. Note that in practice
261 punit is always the focus unit.
262 Clears label if punit is NULL.
263 Also updates the cursor for the map_canvas (this is related because the
264 info label includes a "select destination" prompt etc).
265 Also calls update_unit_pix_label() to update the icons for units on this
266 square.
267 **************************************************************************/
268 void update_unit_info_label(struct unit_list *punits)
270 GtkWidget *label;
272 label = gtk_frame_get_label_widget(GTK_FRAME(unit_info_frame));
273 gtk_label_set_text(GTK_LABEL(label),
274 get_unit_info_label_text1(punits));
276 gtk_label_set_text(GTK_LABEL(unit_info_label),
277 get_unit_info_label_text2(punits, 0));
279 update_unit_pix_label(punits);
282 /**************************************************************************
283 Get sprite for treaty acceptance or rejection.
284 **************************************************************************/
285 GdkPixbuf *get_thumb_pixbuf(int onoff)
287 return sprite_get_pixbuf(get_treaty_thumb_sprite(tileset, BOOL_VAL(onoff)));
290 /****************************************************************************
291 Set information for the indicator icons typically shown in the main
292 client window. The parameters tell which sprite to use for the
293 indicator.
294 ****************************************************************************/
295 void set_indicator_icons(struct sprite *bulb, struct sprite *sol,
296 struct sprite *flake, struct sprite *gov)
298 GdkPixbuf *pb;
300 pb = sprite_get_pixbuf(bulb);
301 gtk_image_set_from_pixbuf(GTK_IMAGE(bulb_label), pb);
302 g_object_unref(pb);
303 pb = sprite_get_pixbuf(sol);
304 gtk_image_set_from_pixbuf(GTK_IMAGE(sun_label), pb);
305 g_object_unref(pb);
306 pb = sprite_get_pixbuf(flake);
307 gtk_image_set_from_pixbuf(GTK_IMAGE(flake_label), pb);
308 g_object_unref(pb);
309 pb = sprite_get_pixbuf(gov);
310 gtk_image_set_from_pixbuf(GTK_IMAGE(government_label), pb);
311 g_object_unref(pb);
314 /****************************************************************************
315 Return the maximum dimensions of the area (container widget) for the
316 overview. Due to the fact that the scaling factor is at least 1, the real
317 size could be larger. The calculation in calculate_overview_dimensions()
318 limit it to the smallest possible size.
319 ****************************************************************************/
320 void get_overview_area_dimensions(int *width, int *height)
322 *width = GUI_GTK_OVERVIEW_MIN_XSIZE;
323 *height = GUI_GTK_OVERVIEW_MIN_YSIZE;
326 /**************************************************************************
327 Size of overview changed
328 **************************************************************************/
329 void overview_size_changed(void)
331 gtk_widget_set_size_request(overview_canvas,
332 gui_options.overview.width,
333 gui_options.overview.height);
334 update_map_canvas_scrollbars_size();
337 /****************************************************************************
338 Return a canvas that is the overview window.
339 ****************************************************************************/
340 struct canvas *get_overview_window(void)
342 #if 0
343 static struct canvas store;
345 store.surface = NULL;
346 store.drawable = gdk_cairo_create(gtk_widget_get_window(overview_canvas));
348 return &store;
349 #endif /* 0 */
351 return NULL;
354 /**************************************************************************
355 Redraw overview canvas
356 **************************************************************************/
357 gboolean overview_canvas_draw(GtkWidget *w, cairo_t *cr, gpointer data)
359 gpointer source = (can_client_change_view()) ?
360 (gpointer)gui_options.overview.window : (gpointer)radar_gfx_sprite;
362 if (source) {
363 cairo_surface_t *surface = (can_client_change_view()) ?
364 gui_options.overview.window->surface :
365 radar_gfx_sprite->surface;
367 cairo_set_source_surface(cr, surface, 0, 0);
368 cairo_paint(cr);
370 return TRUE;
373 /****************************************************************************
374 Freeze the drawing of the map.
375 ****************************************************************************/
376 void mapview_freeze(void)
378 mapview_frozen_level++;
381 /****************************************************************************
382 Thaw the drawing of the map.
383 ****************************************************************************/
384 void mapview_thaw(void)
386 if (1 < mapview_frozen_level) {
387 mapview_frozen_level--;
388 } else {
389 fc_assert(0 < mapview_frozen_level);
390 mapview_frozen_level = 0;
391 dirty_all();
395 /****************************************************************************
396 Return whether the map should be drawn or not.
397 ****************************************************************************/
398 bool mapview_is_frozen(void)
400 return (0 < mapview_frozen_level);
403 /**************************************************************************
404 Update on canvas widget size change
405 **************************************************************************/
406 gboolean map_canvas_configure(GtkWidget *w, GdkEventConfigure *ev,
407 gpointer data)
409 map_canvas_resized(ev->width, ev->height);
411 return TRUE;
414 /**************************************************************************
415 Redraw map canvas.
416 **************************************************************************/
417 gboolean map_canvas_draw(GtkWidget *w, cairo_t *cr, gpointer data)
419 if (can_client_change_view() && map_exists() && !mapview_is_frozen()) {
420 /* First we mark the area to be updated as dirty. Then we unqueue
421 * any pending updates, to make sure only the most up-to-date data
422 * is written (otherwise drawing bugs happen when old data is copied
423 * to screen). Then we draw all changed areas to the screen. */
424 unqueue_mapview_updates(FALSE);
425 cairo_set_source_surface(cr, mapview.store->surface, 0, 0);
426 cairo_paint(cr);
428 return TRUE;
431 /**************************************************************************
432 Flush the given part of the canvas buffer (if there is one) to the
433 screen.
434 **************************************************************************/
435 void flush_mapcanvas(int canvas_x, int canvas_y,
436 int pixel_width, int pixel_height)
438 GdkRectangle rectangle = {canvas_x, canvas_y, pixel_width, pixel_height};
439 if (gtk_widget_get_realized(map_canvas) && !mapview_is_frozen()) {
440 gdk_window_invalidate_rect(gtk_widget_get_window(map_canvas), &rectangle, FALSE);
444 /**************************************************************************
445 Mark the rectangular region as "dirty" so that we know to flush it
446 later.
447 **************************************************************************/
448 void dirty_rect(int canvas_x, int canvas_y,
449 int pixel_width, int pixel_height)
451 GdkRectangle rectangle = {canvas_x, canvas_y, pixel_width, pixel_height};
452 if (gtk_widget_get_realized(map_canvas)) {
453 gdk_window_invalidate_rect(gtk_widget_get_window(map_canvas), &rectangle, FALSE);
457 /**************************************************************************
458 Mark the entire screen area as "dirty" so that we can flush it later.
459 **************************************************************************/
460 void dirty_all(void)
462 if (gtk_widget_get_realized(map_canvas)) {
463 gdk_window_invalidate_rect(gtk_widget_get_window(map_canvas), NULL, FALSE);
467 /**************************************************************************
468 Flush all regions that have been previously marked as dirty. See
469 dirty_rect and dirty_all. This function is generally called after we've
470 processed a batch of drawing operations.
471 **************************************************************************/
472 void flush_dirty(void)
474 if (map_canvas != NULL && gtk_widget_get_realized(map_canvas)) {
475 gdk_window_process_updates(gtk_widget_get_window(map_canvas), FALSE);
479 /****************************************************************************
480 Do any necessary synchronization to make sure the screen is up-to-date.
481 The canvas should have already been flushed to screen via flush_dirty -
482 all this function does is make sure the hardware has caught up.
483 ****************************************************************************/
484 void gui_flush(void)
486 cairo_surface_flush(mapview.store->surface);
489 /**************************************************************************
490 Update display of descriptions associated with cities on the main map.
491 **************************************************************************/
492 void update_city_descriptions(void)
494 update_map_canvas_visible();
497 /**************************************************************************
498 Fill image with unit gfx
499 **************************************************************************/
500 void put_unit_image(struct unit *punit, GtkImage *p, int height)
502 struct canvas store = FC_STATIC_CANVAS_INIT;
503 int width;
505 if (height <= 0) {
506 height = tileset_full_tile_height(tileset);
508 width = tileset_full_tile_width(tileset);
510 store.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
511 width, height);
513 put_unit(punit, &store, 1.0, 0, 0);
515 gtk_image_set_from_surface(p, store.surface);
516 cairo_surface_destroy(store.surface);
519 /**************************************************************************
520 FIXME:
521 For now only two food, two gold one shield and two masks can be drawn per
522 unit, the proper way to do this is probably something like what Civ II does.
523 (One food/shield/mask drawn N times, possibly one top of itself. -- SKi
524 **************************************************************************/
525 void put_unit_image_city_overlays(struct unit *punit, GtkImage *p,
526 int height,
527 int *upkeep_cost, int happy_cost)
529 struct canvas store = FC_STATIC_CANVAS_INIT;
530 GdkPixbuf *pb;
531 int width = tileset_full_tile_width(tileset);
533 store.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
534 width, height);
536 put_unit(punit, &store, 1.0, 0, 0);
538 put_unit_city_overlays(punit, &store, 0, tileset_unit_layout_offset_y(tileset),
539 upkeep_cost, happy_cost);
541 pb = surface_get_pixbuf(store.surface, width, height);
542 gtk_image_set_from_pixbuf(p, pb);
543 g_object_unref(pb);
544 cairo_surface_destroy(store.surface);
547 /**************************************************************************
548 Put overlay tile to pixmap
549 **************************************************************************/
550 void pixmap_put_overlay_tile(GdkWindow *pixmap, float zoom,
551 int canvas_x, int canvas_y,
552 struct sprite *ssprite)
554 cairo_t *cr;
556 if (!ssprite) {
557 return;
560 cr = gdk_cairo_create(pixmap);
561 cairo_scale(cr, zoom, zoom);
562 cairo_set_source_surface(cr, ssprite->surface, canvas_x, canvas_y);
563 cairo_paint(cr);
564 cairo_destroy(cr);
567 /**************************************************************************
568 Only used for isometric view.
569 **************************************************************************/
570 void pixmap_put_overlay_tile_draw(struct canvas *pcanvas,
571 int canvas_x, int canvas_y,
572 struct sprite *ssprite,
573 bool fog)
575 cairo_t *cr;
576 int sswidth, ssheight;
578 if (!ssprite) {
579 return;
582 get_sprite_dimensions(ssprite, &sswidth, &ssheight);
584 if (fog) {
585 struct color *fogcol = color_alloc(0.0, 0.0, 0.0);
586 cairo_surface_t *fog_surface;
587 struct sprite *fogged;
588 unsigned char *mask_in;
589 unsigned char *mask_out;
590 int i, j;
592 /* Create sprites fully transparent */
593 fogcol->color.alpha = 0.0;
594 fogged = create_sprite(sswidth, ssheight, fogcol);
595 fog_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sswidth, ssheight);
597 /* Calculate black fog mask from the original sprite,
598 * we don't want to blacken transparent parts of the sprite */
599 mask_in = cairo_image_surface_get_data(ssprite->surface);
600 mask_out = cairo_image_surface_get_data(fog_surface);
602 for (i = 0; i < sswidth; i++) {
603 for (j = 0; j < ssheight; j++) {
604 #ifndef WORDS_BIGENDIAN
605 mask_out[(j * sswidth + i) * 4 + 3] = 0.65 * mask_in[(j * sswidth + i) * 4 + 3];
606 #else /* WORDS_BIGENDIAN */
607 mask_out[(j * sswidth + i) * 4 + 0] = 0.65 * mask_in[(j * sswidth + i) * 4 + 0];
608 #endif /* WORDS_BIGENDIAN */
612 cairo_surface_mark_dirty(fog_surface);
614 /* First copy original sprite canvas to intermediate sprite canvas */
615 cr = cairo_create(fogged->surface);
616 cairo_set_source_surface(cr, ssprite->surface, 0, 0);
617 cairo_paint(cr);
619 /* Then apply created fog to the intermediate sprite */
620 cairo_set_source_surface(cr, fog_surface, 0, 0);
621 cairo_paint(cr);
622 cairo_destroy(cr);
624 /* Put intermediate sprite to the target canvas */
625 canvas_put_sprite(pcanvas, canvas_x, canvas_y,
626 fogged, 0, 0, sswidth, ssheight);
628 /* Free intermediate stuff */
629 cairo_surface_destroy(fog_surface);
630 free_sprite(fogged);
631 color_free(fogcol);
632 } else {
633 canvas_put_sprite(pcanvas, canvas_x, canvas_y,
634 ssprite, 0, 0, sswidth, ssheight);
638 /**************************************************************************
639 Draws a cross-hair overlay on a tile
640 **************************************************************************/
641 void put_cross_overlay_tile(struct tile *ptile)
643 float canvas_x, canvas_y;
645 if (tile_to_canvas_pos(&canvas_x, &canvas_y, ptile)) {
646 pixmap_put_overlay_tile(gtk_widget_get_window(map_canvas), map_zoom,
647 canvas_x / map_zoom, canvas_y / map_zoom,
648 get_attention_crosshair_sprite(tileset));
652 /*****************************************************************************
653 Sets the position of the overview scroll window based on mapview position.
654 *****************************************************************************/
655 void update_overview_scroll_window_pos(int x, int y)
657 gdouble ov_scroll_x, ov_scroll_y;
658 GtkAdjustment *ov_hadj, *ov_vadj;
660 ov_hadj = gtk_scrolled_window_get_hadjustment(
661 GTK_SCROLLED_WINDOW(overview_scrolled_window));
662 ov_vadj = gtk_scrolled_window_get_vadjustment(
663 GTK_SCROLLED_WINDOW(overview_scrolled_window));
665 ov_scroll_x = MIN(x - (overview_canvas_store_width / 2),
666 gtk_adjustment_get_upper(ov_hadj)
667 - gtk_adjustment_get_page_size(ov_hadj));
668 ov_scroll_y = MIN(y - (overview_canvas_store_height / 2),
669 gtk_adjustment_get_upper(ov_vadj)
670 - gtk_adjustment_get_page_size(ov_vadj));
672 gtk_adjustment_set_value(ov_hadj, ov_scroll_x);
673 gtk_adjustment_set_value(ov_vadj, ov_scroll_y);
676 /**************************************************************************
677 Refresh map canvas scrollbars
678 **************************************************************************/
679 void update_map_canvas_scrollbars(void)
681 int scroll_x, scroll_y;
683 get_mapview_scroll_pos(&scroll_x, &scroll_y);
684 gtk_adjustment_set_value(map_hadj, scroll_x);
685 gtk_adjustment_set_value(map_vadj, scroll_y);
686 if (can_client_change_view()) {
687 gtk_widget_queue_draw(overview_canvas);
691 /**************************************************************************
692 Refresh map canvas scrollbar as canvas size changes
693 **************************************************************************/
694 void update_map_canvas_scrollbars_size(void)
696 float xmin, ymin, xmax, ymax;
697 int xsize, ysize, xstep, ystep;
699 get_mapview_scroll_window(&xmin, &ymin, &xmax, &ymax, &xsize, &ysize);
700 get_mapview_scroll_step(&xstep, &ystep);
702 map_hadj = gtk_adjustment_new(-1, xmin, xmax, xstep, xsize, xsize);
703 map_vadj = gtk_adjustment_new(-1, ymin, ymax, ystep, ysize, ysize);
705 gtk_range_set_adjustment(GTK_RANGE(map_horizontal_scrollbar), map_hadj);
706 gtk_range_set_adjustment(GTK_RANGE(map_vertical_scrollbar), map_vadj);
708 g_signal_connect(map_hadj, "value_changed",
709 G_CALLBACK(scrollbar_jump_callback),
710 GINT_TO_POINTER(TRUE));
711 g_signal_connect(map_vadj, "value_changed",
712 G_CALLBACK(scrollbar_jump_callback),
713 GINT_TO_POINTER(FALSE));
716 /**************************************************************************
717 Scrollbar has moved
718 **************************************************************************/
719 void scrollbar_jump_callback(GtkAdjustment *adj, gpointer hscrollbar)
721 int scroll_x, scroll_y;
723 if (!can_client_change_view()) {
724 return;
727 get_mapview_scroll_pos(&scroll_x, &scroll_y);
729 if (hscrollbar) {
730 scroll_x = gtk_adjustment_get_value(adj);
731 } else {
732 scroll_y = gtk_adjustment_get_value(adj);
735 set_mapview_scroll_pos(scroll_x, scroll_y);
738 /**************************************************************************
739 Draws a rectangle with top left corner at (canvas_x, canvas_y), and
740 width 'w' and height 'h'. It is drawn using the 'selection_gc' context,
741 so the pixel combining function is XOR. This means that drawing twice
742 in the same place will restore the image to its original state.
744 NB: A side effect of this function is to set the 'selection_gc' color
745 to COLOR_MAPVIEW_SELECTION.
746 **************************************************************************/
747 void draw_selection_rectangle(int canvas_x, int canvas_y, int w, int h)
749 double dashes[2] = {4.0, 4.0};
750 struct color *pcolor;
751 cairo_t *cr;
753 if (w == 0 || h == 0) {
754 return;
757 pcolor = get_color(tileset, COLOR_MAPVIEW_SELECTION);
758 if (!pcolor) {
759 return;
762 cr = gdk_cairo_create(gtk_widget_get_window(map_canvas));
763 gdk_cairo_set_source_rgba(cr, &pcolor->color);
764 cairo_set_line_width(cr, 2.0);
765 cairo_set_dash(cr, dashes, 2, 0);
766 cairo_set_operator(cr, CAIRO_OPERATOR_DIFFERENCE);
767 cairo_rectangle(cr, canvas_x, canvas_y, w, h);
768 cairo_stroke(cr);
769 cairo_destroy(cr);
772 /**************************************************************************
773 This function is called when the tileset is changed.
774 **************************************************************************/
775 void tileset_changed(void)
777 science_report_dialog_redraw();
778 reset_city_dialogs();
779 reset_unit_table();
780 blank_max_unit_size();
781 editgui_tileset_changed();
783 /* keep the icon of the executable on Windows (see PR#36491) */
784 #ifndef WIN32_NATIVE
786 GdkPixbuf *pixbuf = sprite_get_pixbuf(get_icon_sprite(tileset, ICON_FREECIV));
788 /* Only call this after tileset_load_tiles is called. */
789 gtk_window_set_icon(GTK_WINDOW(toplevel), pixbuf);
790 g_object_unref(pixbuf);
792 #endif /* WIN32_NATIVE */