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)
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 ***********************************************************************/
15 #include <fc_config.h>
36 #include "government.h" /* government_graphic() */
41 #include "client_main.h"
45 #include "control.h" /* get_unit_in_focus() */
48 #include "overview_common.h"
52 /* client/gui-gtk-2.0 */
53 #include "citydlg.h" /* For reset_city_dialogs() */
57 #include "gui_stuff.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
73 **************************************************************************/
74 void update_turn_done_button(bool do_restore
)
76 static bool flip
= FALSE
;
78 if (!get_turn_done_button_state()) {
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
);
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 "
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 /**************************************************************************
117 **************************************************************************/
118 void update_info_label(void)
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
) {
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
];
137 len
= g_unichar_to_utf8(g_unichar_toupper(c
), nation
);
139 next
= g_utf8_find_next_char(name
, NULL
);
141 sz_strlcat(nation
, next
);
143 gtk_label_set_text(GTK_LABEL(label
), nation
);
145 gtk_label_set_text(GTK_LABEL(label
), name
);
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
) {
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
) {
208 if (cursor_frame
== NUM_CURSOR_FRAMES
) {
212 if (cursor_type
== CURSOR_DEFAULT
) {
213 gdk_window_set_cursor(root_window
, NULL
);
218 gdk_window_set_cursor(root_window
,
219 fc_cursors
[cursor_type
][cursor_frame
]);
220 control_mouse_cursor(NULL
);
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
244 **************************************************************************/
245 void update_unit_info_label(struct unit_list
*punits
)
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
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
;
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
);
336 refresh_overview_from_canvas();
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
--;
356 fc_assert(0 < mapview_frozen_level
);
357 mapview_frozen_level
= 0;
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
,
376 map_canvas_resized(ev
->width
, ev
->height
);
380 /**************************************************************************
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
);
398 /**************************************************************************
399 Flush the given part of the canvas buffer (if there is one) to the
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
)
424 is_flush_queued
= 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
445 **************************************************************************/
446 void dirty_rect(int canvas_x
, int canvas_y
,
447 int pixel_width
, int pixel_height
)
449 if (mapview_is_frozen()) {
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
;
462 /**************************************************************************
463 Mark the entire screen area as "dirty" so that we can flush it later.
464 **************************************************************************/
467 if (mapview_is_frozen()) {
470 num_dirty_rects
= MAX_DIRTY_RECTS
;
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()) {
484 if (num_dirty_rects
== MAX_DIRTY_RECTS
) {
485 flush_mapcanvas(0, 0, map_canvas
->allocation
.width
,
486 map_canvas
->allocation
.height
);
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
);
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 ****************************************************************************/
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);
535 /**************************************************************************
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
)
546 store
.type
= CANVAS_PIXCOMM
;
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
);
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
)
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
,
576 ssprite
->width
, ssprite
->height
);
577 gdk_gc_set_clip_mask(civ_gc
, NULL
);
579 gdk_draw_pixbuf(pixmap
, civ_gc
, ssprite
->pixbuf
,
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
)
597 static int sprites
= 0, pixbufs
= 0;
600 if (ssprite
->pixmap
) {
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
,
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
);
614 gdk_draw_pixbuf(pixmap
, civ_gc
, ssprite
->pixbuf
,
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);
627 if (sprites
% 1000 == 0) {
628 log_debug("%5d / %5d pixbufs = %d%%",
629 pixbufs
, sprites
, 100 * pixbufs
/ sprites
);
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
)
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
);
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
,
670 g_object_unref(fogged
);
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
,
688 if (fog
&& gui_options
.gui_gtk2_better_fog
689 && ((ssprite
->pixmap
&& !ssprite
->pixmap_fogged
)
690 || (!ssprite
->pixmap
&& !ssprite
->pixbuf_fogged
))) {
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
) {
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
,
709 ssprite
->width
, ssprite
->height
);
710 gdk_gc_set_clip_mask(civ_gc
, NULL
);
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);
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. */
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
,
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 /**************************************************************************
817 **************************************************************************/
818 void scrollbar_jump_callback(GtkAdjustment
*adj
, gpointer hscrollbar
)
820 int scroll_x
, scroll_y
;
822 if (!can_client_change_view()) {
826 get_mapview_scroll_pos(&scroll_x
, &scroll_y
);
829 scroll_x
= adj
->value
;
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
)
849 struct color
*pcolor
;
851 if (w
== 0 || h
== 0) {
855 pcolor
= get_color(tileset
, COLOR_MAPVIEW_SELECTION
);
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();
888 blank_max_unit_size();
889 editgui_tileset_changed();
891 /* keep the icon of the executable on Windows (see PR#36491) */
893 gtk_window_set_icon(GTK_WINDOW(toplevel
),
894 sprite_get_pixbuf(get_icon_sprite(tileset
, ICON_FREECIV
)));
897 science_report_dialog_redraw();