[Freeciv-Dev] Re: (PR#7445) mapview scrolling
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://rt.freeciv.org/Ticket/Display.html?id=7445 >
Gregory Berkolaiko wrote:
> <URL: http://rt.freeciv.org/Ticket/Display.html?id=7445 >
>
>><URL: http://rt.freeciv.org/Ticket/Display.html?id=7445 >
>>
>>Fed up with our attempts at hacking around the problem, I just
>>implemented it the way it should be (tm).
>
>
> The patch looks ok. But you are right about off-by-one problems.
>
> A couple of glitches
> topo 5, xs 40, ys 40, isotrident
>
> 1. Middle click will give you tiles to the right of the one you click on
> unless you click near the left corner. I guess canvas_to_map is broken.
Yes, it's an off-by-one-half error. Fixed.
> 2. Centering (other than caused by the above):
> scroll right as far as possible. Click on the right tile (better be
> something you remeber, like a unit or a whale). After centering the
> "center" tile is actually near the left edge.
A clipping problem. Fixed. (I think.)
This happens because the gtk scrollbar code imposes the clipping
restrictions any time the mapview is recentered. So it is physically
impossible to center on an area that is outside of the clipping boundaries.
> 3. In the overview window the white rectangle zigzags or jumps (depends on
> topo and scroll direction) when you scroll.
This could be fixed by adding a gui_to_overview_pos function that
preserves granularity. But I haven't done this yet. It could be done
for this patch, but we'd get more patch bloat.
> 4. Cannot scroll past "date change line". This could be regarded a
> feature I guess.
Well, it's not a feature, but I don't think it's a bug either. The
problem is there's no normalization step during scrolling.
> 5. Question: if gui coordinates extend indefinitely in both directions,
> isn't there a danger of overflow?
No. The canvas is moved in one of two ways:
- center_tile_mapcanvas. Here the center tile is guaranteed to be
normal, so we shouldn't go outside of the clipping boundaries.
- scolling. Here we are directly limited by the clipping boundaries (as
determined in get_mapview_scroll_window).
jason
Index: client/mapctrl_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapctrl_common.c,v
retrieving revision 1.28
diff -u -r1.28 mapctrl_common.c
--- client/mapctrl_common.c 2004/02/20 06:42:28 1.28
+++ client/mapctrl_common.c 2004/02/23 01:12:52
@@ -87,8 +87,8 @@
map_to_canvas_pos(&rec_anchor_x, &rec_anchor_y, tile_x, tile_y);
rec_anchor_x += NORMAL_TILE_WIDTH / 2;
rec_anchor_y += NORMAL_TILE_HEIGHT / 2;
- rec_canvas_map_x0 = mapview_canvas.map_x0;
- rec_canvas_map_y0 = mapview_canvas.map_y0;
+ /* FIXME: This may be off-by-one. */
+ canvas_to_map_pos(&rec_canvas_map_x0, &rec_canvas_map_y0, 0, 0);
rec_w = rec_h = 0;
}
@@ -165,6 +165,7 @@
const int H = NORMAL_TILE_HEIGHT, half_H = H / 2;
static int rec_tile_x = 9999, rec_tile_y = 9999;
int tile_x, tile_y, diff_x, diff_y;
+ int map_x0, map_y0;
canvas_to_map_pos(&tile_x, &tile_y, canvas_x, canvas_y);
@@ -190,8 +191,10 @@
rec_w = rec_anchor_x - canvas_x; /* width */
rec_h = rec_anchor_y - canvas_y; /* height */
- diff_x = rec_canvas_map_x0 - mapview_canvas.map_x0;
- diff_y = rec_canvas_map_y0 - mapview_canvas.map_y0;
+ /* FIXME: This may be off-by-one. */
+ canvas_to_map_pos(&map_x0, &map_y0, 0, 0);
+ diff_x = rec_canvas_map_x0 - map_x0;
+ diff_y = rec_canvas_map_y0 - map_y0;
/* Adjust width, height if mapview has recentered.
*/
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.79
diff -u -r1.79 mapview_common.c
--- client/mapview_common.c 2004/02/21 22:15:03 1.79
+++ client/mapview_common.c 2004/02/23 01:12:52
@@ -160,6 +160,87 @@
}
}
+/****************************************************************************
+ Translate from map to gui coordinate systems.
+
+ GUI coordinates are comparable to canvas coordinates but extend in all
+ directions. gui(0,0) == map(0,0).
+****************************************************************************/
+static void map_to_gui_pos(int *gui_x, int *gui_y, int map_x, int map_y)
+{
+ if (is_isometric) {
+ /*
+ * Convert the map coordinates to isometric GUI
+ * coordinates. We'll make tile map(0,0) be the origin, and
+ * transform like this:
+ *
+ * 3
+ * 123 2 6
+ * 456 -> becomes -> 1 5 9
+ * 789 4 8
+ * 7
+ */
+ *gui_x = (map_x - map_y) * NORMAL_TILE_WIDTH / 2;
+ *gui_y = (map_x + map_y) * NORMAL_TILE_HEIGHT / 2;
+ } else {
+ *gui_x = map_x * NORMAL_TILE_HEIGHT;
+ *gui_y = map_y * NORMAL_TILE_WIDTH;
+ }
+}
+
+/****************************************************************************
+ Translate from gui to map coordinate systems. See map_to_gui_pos().
+
+ Note that you lose some information in this conversion. If you convert
+ from a gui position to a map position and back, you will probably not get
+ the same value you started with.
+****************************************************************************/
+static void gui_to_map_pos(int *map_x, int *map_y, int gui_x, int gui_y)
+{
+ const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
+
+ if (is_isometric) {
+ /* The basic operation here is a simple pi/4 rotation; however, we
+ * have to first scale because the tiles have different width and
+ * height. Mathematically, this looks like
+ * | 1/W 1/H | |x| |x`|
+ * | | | | -> | |
+ * |-1/W 1/H | |y| |y`|
+ *
+ * Where W is the tile width and H the height.
+ *
+ * In simple terms, this is
+ * map_x = [ x / W + y / H ]
+ * map_y = [ - x / W + y / H ]
+ * where [q] stands for integer part of q.
+ *
+ * Here the division is proper mathematical floating point division.
+ *
+ * A picture demonstrating this can be seen at
+ * http://rt.freeciv.org/Ticket/Attachment/16782/9982/grid1.png.
+ *
+ * We have to subtract off a half-tile in the X direction before doing
+ * the transformation. This is because, although the origin of the tile
+ * is the top-left corner of the bounding box, after the transformation
+ * the top corner of the diamond-shaped tile moves into this position.
+ *
+ * The calculation is complicated somewhat because of two things: we
+ * only use integer math, and C integer division rounds toward zero
+ * instead of rounding down.
+ *
+ * For another example of this math, see canvas_to_city_pos().
+ */
+ gui_x -= W / 2;
+ *map_x = DIVIDE(gui_x * H + gui_y * W, W * H);
+ *map_y = DIVIDE(gui_y * W - gui_x * H, W * H);
+ } else { /* is_isometric */
+ /* We use DIVIDE so that we will get the correct result even
+ * for negative coordinates. */
+ *map_x = DIVIDE(gui_x, W);
+ *map_y = DIVIDE(gui_y, H);
+ }
+}
+
/**************************************************************************
Finds the canvas coordinates for a map position. Beside setting the results
in canvas_x, canvas_y it returns whether the tile is inside the
@@ -198,53 +279,21 @@
map_distance_vector(&dx, &dy, center_map_x, center_map_y, map_x, map_y);
map_x = center_map_x + dx;
map_y = center_map_y + dy;
-
- if (is_isometric) {
- /* For a simpler example of this math, see city_to_canvas_pos(). */
- int iso_x, iso_y;
- /*
- * Next we convert the flat GUI coordinates to isometric GUI
- * coordinates. We'll make tile (x0, y0) be the origin, and
- * transform like this:
- *
- * 3
- * 123 2 6
- * 456 -> becomes -> 1 5 9
- * 789 4 8
- * 7
- */
- iso_x = (map_x - map_y)
- - (mapview_canvas.map_x0 - mapview_canvas.map_y0);
- iso_y = (map_x + map_y)
- - (mapview_canvas.map_x0 + mapview_canvas.map_y0);
+ map_to_gui_pos(canvas_x, canvas_y, map_x, map_y);
+ *canvas_x -= mapview_canvas.gui_x0;
+ *canvas_y -= mapview_canvas.gui_y0;
- /*
- * As the above picture shows, each isometric-coordinate unit
- * corresponds to a half-tile on the canvas. Since the (x0, y0)
- * tile actually has its top corner (of the diamond-shaped tile)
- * located right at the corner of the canvas, to find the top-left
- * corner of the surrounding rectangle we must subtract off an
- * additional half-tile in the X direction.
- */
- *canvas_x = (iso_x - 1) * NORMAL_TILE_WIDTH / 2;
- *canvas_y = iso_y * NORMAL_TILE_HEIGHT / 2;
- } else { /* is_isometric */
- *canvas_x = map_x - mapview_canvas.map_x0;
- *canvas_y = map_y - mapview_canvas.map_y0;
-
- *canvas_x *= NORMAL_TILE_WIDTH;
- *canvas_y *= NORMAL_TILE_HEIGHT;
- }
-
/*
* Finally we clip; checking to see if _any part_ of the tile is
- * visible on the canvas.
+ * present on the backing store. (Even if it's not visible on the canvas,
+ * if it's present on the backing store we need to draw it in case the
+ * canvas is resized.)
*/
return (*canvas_x > -NORMAL_TILE_WIDTH
- && *canvas_x < mapview_canvas.width
+ && *canvas_x < mapview_canvas.store_width
&& *canvas_y > -NORMAL_TILE_HEIGHT
- && *canvas_y < mapview_canvas.height);
+ && *canvas_y < mapview_canvas.store_height);
}
/****************************************************************************
@@ -254,45 +303,9 @@
static void base_canvas_to_map_pos(int *map_x, int *map_y,
int canvas_x, int canvas_y)
{
- const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
-
- if (is_isometric) {
- /* The basic operation here is a simple pi/4 rotation; however, we
- * have to first scale because the tiles have different width and
- * height. Mathematically, this looks like
- * | 1/W 1/H | |x| |x`|
- * | | | | -> | |
- * |-1/W 1/H | |y| |y`|
- *
- * Where W is the tile width and H the height.
- *
- * In simple terms, this is
- * map_x = [ x / W + y / H ]
- * map_y = [ - x / W + y / H ]
- * where [q] stands for integer part of q.
- *
- * Here the division is proper mathematical floating point division.
- *
- * A picture demonstrating this can be seen at
- * http://rt.freeciv.org/Ticket/Attachment/16782/9982/grid1.png.
- *
- * The calculation is complicated somewhat because of two things: we
- * only use integer math, and C integer division rounds toward zero
- * instead of rounding down.
- *
- * For another example of this math, see canvas_to_city_pos().
- */
- *map_x = DIVIDE(canvas_x * H + canvas_y * W, W * H);
- *map_y = DIVIDE(canvas_y * W - canvas_x * H, W * H);
- } else { /* is_isometric */
- /* We use DIVIDE so that we will get the correct result even
- * for negative (off-canvas) coordinates. */
- *map_x = DIVIDE(canvas_x, W);
- *map_y = DIVIDE(canvas_y, H);
- }
-
- *map_x += mapview_canvas.map_x0;
- *map_y += mapview_canvas.map_y0;
+ gui_to_map_pos(map_x, map_y,
+ canvas_x + mapview_canvas.gui_x0,
+ canvas_y + mapview_canvas.gui_y0);
}
@@ -311,35 +324,28 @@
/****************************************************************************
Change the mapview origin, clip it, and update everything.
****************************************************************************/
-static void set_mapview_origin(int map_x0, int map_y0)
+static void set_mapview_origin(int gui_x0, int gui_y0)
{
- int nat_x0, nat_y0, xmin, xmax, ymin, ymax, xsize, ysize;
+ int xmin, xmax, ymin, ymax, xsize, ysize;
/* First wrap/clip the position. Wrapping is done in native positions
* while clipping is done in scroll (native) positions. */
- map_to_native_pos(&nat_x0, &nat_y0, map_x0, map_y0);
get_mapview_scroll_window(&xmin, &ymin, &xmax, &ymax, &xsize, &ysize);
- if (topo_has_flag(TF_WRAPX)) {
- nat_x0 = FC_WRAP(nat_x0, map.xsize);
- } else {
- nat_x0 = CLIP(xmin, nat_x0, xmax - xsize);
+ if (!topo_has_flag(TF_WRAPX)) {
+ gui_x0 = CLIP(xmin, gui_x0, xmax - xsize);
}
- if (topo_has_flag(TF_WRAPY)) {
- nat_y0 = FC_WRAP(nat_y0, map.ysize);
- } else {
- nat_y0 = CLIP(ymin, nat_y0, ymax - ysize);
+ if (!topo_has_flag(TF_WRAPY)) {
+ gui_y0 = CLIP(ymin, gui_y0, ymax - ysize);
}
- native_to_map_pos(&map_x0, &map_y0, nat_x0, nat_y0);
-
/* Then update everything. */
- if (mapview_canvas.map_x0 != map_x0 || mapview_canvas.map_y0 != map_y0) {
+ if (mapview_canvas.gui_x0 != gui_x0 || mapview_canvas.gui_y0 != gui_y0) {
int map_center_x, map_center_y;
- mapview_canvas.map_x0 = map_x0;
- mapview_canvas.map_y0 = map_y0;
+ mapview_canvas.gui_x0 = gui_x0;
+ mapview_canvas.gui_y0 = gui_y0;
get_center_tile_mapcanvas(&map_center_x, &map_center_y);
center_tile_overviewcanvas(map_center_x, map_center_y);
@@ -382,103 +388,50 @@
void get_mapview_scroll_window(int *xmin, int *ymin, int *xmax, int *ymax,
int *xsize, int *ysize)
{
- /* There are a number of factors that must be taken into account in
- * calculating these values:
- *
- * 1. Basic constraints: X should generally range from 0 to map.xsize;
- * Y from 0 to map.ysize.
- *
- * 2. Non-aligned borders: if the borders don't line up (an iso-view client
- * with a standard map, for instance) the minimum and maximum must be
- * extended if the map doesn't wrap in that direction. They are extended
- * by an amount proportional to the size of the screen.
- *
- * 3. Compression: on an iso-map native coordinates are compressed 2x in
- * the X direction.
- *
- * 4. Translation: the min and max values give a range for the origin.
- * Since the base constraint is on the minimal value contained in the
- * mapview, we have to translate the minimum and maximum to account for
- * this.
- *
- * 5. Wrapping: if the map wraps in a given direction, no border adjustment
- * or translation is needed. Instead we have to make sure the range is
- * large enough to get the full wrap.
- */
- *xmin = 0;
- *ymin = 0;
- *xmax = map.xsize;
- *ymax = map.ysize;
-
- if (topo_has_flag(TF_ISO) != is_isometric) {
- /* The mapview window is aligned differently than the map. In this
- * case we need to give looser constraints because (if the map doesn't
- * wrap) the edges will not line up well. */
-
- /* These are the dimensions of the bounding box. */
- *xsize = *ysize =
- mapview_canvas.tile_width + mapview_canvas.tile_height;
-
- if (is_isometric) {
- /* Step 2: Calculate extra border distance. */
- *xmin = *ymin = -(MAX(mapview_canvas.tile_width,
- mapview_canvas.tile_height) + 1) / 2;
- *xmax -= *xmin;
- *ymax -= *ymin;
-
- /* Step 4: Translate the Y coordinate. The mapview origin is at the
- * top-left corner of the window, which is offset at +tile_width from
- * the minimum Y value (at the top-right corner). */
- *ymin += mapview_canvas.tile_width;
- *ymax += mapview_canvas.tile_width;
- } else {
- /* Compression. */
- *xsize = (*xsize + 1) / 2;
+ *xsize = mapview_canvas.width;
+ *ysize = mapview_canvas.height;
- /* Step 2: calculate border adjustment. */
- *ymin = -(MAX(mapview_canvas.tile_width,
- mapview_canvas.tile_height) + 1) / 2;
- *xmin = (*ymin + 1) / 2; /* again compressed */
- *xmax -= *xmin;
- *ymax -= *ymin;
-
- /* Step 4: translate the X coordinate. The mapview origin is at the
- * top-left corner of the window, which is offset at +tile_height/2
- * from the minimum X value (at the bottom-left corner). */
- *xmin += mapview_canvas.tile_height / 2;
- *xmax += (mapview_canvas.tile_height + 1) / 2;
+ if (topo_has_flag(TF_ISO) == is_isometric) {
+ /* If the map and view line up, it's easy. */
+ native_to_map_pos(xmin, ymin, 0, 0);
+ map_to_gui_pos(xmin, ymin, *xmin, *ymin);
+
+ native_to_map_pos(xmax, ymax, map.xsize - 1, map.ysize - 1);
+ map_to_gui_pos(xmax, ymax, *xmax, *ymax);
+ *xmax += NORMAL_TILE_WIDTH;
+ *ymax += NORMAL_TILE_HEIGHT;
+
+ /* To be able to center on positions near the edges, we have to be
+ * allowed to scroll past those edges. */
+ if (topo_has_flag(TF_WRAPX)) {
+ *xmax += *xsize;
}
+ if (topo_has_flag(TF_WRAPY)) {
+ *ymax += *ysize;
+ }
} else {
- *xsize = mapview_canvas.tile_width;
- *ysize = mapview_canvas.tile_height;
+ /* Otherwise it's hard. Very hard. Impossible, in fact. This is just
+ * an approximation - a huge bounding box. */
+ int gui_x1, gui_y1, gui_x2, gui_y2, gui_x3, gui_y3, gui_x4, gui_y4;
+ int map_x, map_y;
- if (is_isometric) {
- /* Compression: Each vertical half-tile corresponds to one native
- * unit (a full horizontal tile corresponds to a native unit). */
- *ysize = (mapview_canvas.height - 1) / (NORMAL_TILE_HEIGHT / 2) + 1;
-
- /* Isometric fixes: the above calculations are in half-tiles; since we
- * need to see full tiles we have to extend the range a bit. This also
- * corrects for the off-by-one error caused by the X compression of
- * native coordinates. */
- (*xmin)--;
- (*xmax)++;
- (*ymax) += 2;
- } else {
- (*ymax)++;
- }
- }
+ native_to_map_pos(&map_x, &map_y, 0, 0);
+ map_to_gui_pos(&gui_x1, &gui_y1, map_x, map_y);
- /* Now override the above to satisfy wrapping constraints. We allow the
- * scrolling to cover the full range of the map, plus one unit in each
- * direction (to allow scrolling with the scroll bars, for instance). */
- if (topo_has_flag(TF_WRAPX)) {
- *xmin = -1;
- *xmax = map.xsize + *xsize;
- }
- if (topo_has_flag(TF_WRAPY)) {
- *ymin = -1;
- *ymax = map.ysize + *ysize;
+ native_to_map_pos(&map_x, &map_y, map.xsize - 1, 0);
+ map_to_gui_pos(&gui_x2, &gui_y2, map_x, map_y);
+
+ native_to_map_pos(&map_x, &map_y, 0, map.ysize - 1);
+ map_to_gui_pos(&gui_x3, &gui_y3, map_x, map_y);
+
+ native_to_map_pos(&map_x, &map_y, map.xsize - 1, map.ysize - 1);
+ map_to_gui_pos(&gui_x4, &gui_y4, map_x, map_y);
+
+ *xmin = MIN(gui_x1, MIN(gui_x2, gui_x3)) - mapview_canvas.width / 2;
+ *ymin = MIN(gui_y1, MIN(gui_y2, gui_y3)) - mapview_canvas.height / 2;
+
+ *xmax = MAX(gui_x4, MAX(gui_x2, gui_x3)) + mapview_canvas.width / 2;
+ *ymax = MAX(gui_y4, MAX(gui_y2, gui_y3)) + mapview_canvas.height / 2;
}
freelog(LOG_DEBUG, "x: %d<-%d->%d; y: %d<-%d->%d",
@@ -491,8 +444,13 @@
****************************************************************************/
void get_mapview_scroll_step(int *xstep, int *ystep)
{
- *xstep = 1;
- *ystep = (topo_has_flag(TF_ISO) ? 2 : 1);
+ *xstep = NORMAL_TILE_WIDTH;
+ *ystep = NORMAL_TILE_HEIGHT;
+
+ if (is_isometric) {
+ *xstep /= 2;
+ *ystep /= 2;
+ }
}
/****************************************************************************
@@ -500,8 +458,8 @@
****************************************************************************/
void get_mapview_scroll_pos(int *scroll_x, int *scroll_y)
{
- map_to_native_pos(scroll_x, scroll_y,
- mapview_canvas.map_x0, mapview_canvas.map_y0);
+ *scroll_x = mapview_canvas.gui_x0;
+ *scroll_y = mapview_canvas.gui_y0;
}
/****************************************************************************
@@ -509,10 +467,9 @@
****************************************************************************/
void set_mapview_scroll_pos(int scroll_x, int scroll_y)
{
- int map_x0, map_y0;
+ int gui_x0 = scroll_x, gui_y0 = scroll_y;
- native_to_map_pos(&map_x0, &map_y0, scroll_x, scroll_y);
- set_mapview_origin(map_x0, map_y0);
+ set_mapview_origin(gui_x0, gui_y0);
}
/**************************************************************************
@@ -532,8 +489,10 @@
**************************************************************************/
void center_tile_mapcanvas(int map_center_x, int map_center_y)
{
- int map_x = map_center_x, map_y = map_center_y;
+ int map_x = map_center_x, map_y = map_center_y, gui_x, gui_y;
+ CHECK_MAP_POS(map_center_x, map_center_y);
+
/* Find top-left corner. */
if (is_isometric) {
map_x -= mapview_canvas.tile_width / 2;
@@ -545,7 +504,8 @@
map_y -= mapview_canvas.tile_height / 2;
}
- set_mapview_origin(map_x, map_y);
+ map_to_gui_pos(&gui_x, &gui_y, map_x, map_y);
+ set_mapview_origin(gui_x, gui_y);
}
/**************************************************************************
@@ -1168,6 +1128,8 @@
**************************************************************************/
void update_map_canvas_visible(void)
{
+ int map_x0, map_y0;
+
dirty_all();
/* Clear the entire mapview. This is necessary since if the mapview is
@@ -1179,18 +1141,20 @@
gui_put_rectangle(mapview_canvas.store, COLOR_STD_BLACK,
0, 0, mapview_canvas.width, mapview_canvas.height);
+ canvas_to_map_pos(&map_x0, &map_y0, 0, 0);
if (is_isometric) {
/* just find a big rectangle that includes the whole visible area. The
invisible tiles will not be drawn. */
int width, height;
- width = height = mapview_canvas.tile_width + mapview_canvas.tile_height;
- update_map_canvas(mapview_canvas.map_x0,
- mapview_canvas.map_y0 - mapview_canvas.tile_width,
+ width = mapview_canvas.tile_width + mapview_canvas.tile_height + 2;
+ height = width;
+ update_map_canvas(map_x0 - 1, map_y0 - mapview_canvas.tile_width - 1,
width, height, FALSE);
} else {
- update_map_canvas(mapview_canvas.map_x0, mapview_canvas.map_y0,
- mapview_canvas.tile_width, mapview_canvas.tile_height,
+ update_map_canvas(map_x0, map_y0,
+ mapview_canvas.tile_width + 1,
+ mapview_canvas.tile_height + 1,
FALSE);
}
@@ -1203,6 +1167,7 @@
void show_city_descriptions(void)
{
int canvas_x, canvas_y;
+ int map_x0, map_y0;
if (!draw_city_names && !draw_city_productions) {
return;
@@ -1210,12 +1175,13 @@
prepare_show_city_descriptions();
+ canvas_to_map_pos(&map_x0, &map_y0, 0, 0);
if (is_isometric) {
int w, h;
for (h = -1; h < mapview_canvas.tile_height * 2; h++) {
- int x_base = mapview_canvas.map_x0 + h / 2 + (h != -1 ? h % 2 : 0);
- int y_base = mapview_canvas.map_y0 + h / 2 + (h == -1 ? -1 : 0);
+ int x_base = map_x0 + h / 2 + (h != -1 ? h % 2 : 0);
+ int y_base = map_y0 + h / 2 + (h == -1 ? -1 : 0);
for (w = 0; w <= mapview_canvas.tile_width; w++) {
int x = x_base + w;
@@ -1232,10 +1198,10 @@
} else { /* is_isometric */
int x1, y1;
- for (x1 = 0; x1 < mapview_canvas.tile_width; x1++) {
- for (y1 = 0; y1 < mapview_canvas.tile_height; y1++) {
- int x = mapview_canvas.map_x0 + x1;
- int y = mapview_canvas.map_y0 + y1;
+ for (x1 = 0; x1 <= mapview_canvas.tile_width; x1++) {
+ for (y1 = 0; y1 <= mapview_canvas.tile_height; y1++) {
+ int x = map_x0 + x1;
+ int y = map_y0 + y1;
struct city *pcity;
if (normalize_map_pos(&x, &y)
@@ -1743,8 +1709,10 @@
**************************************************************************/
static void get_mapview_corners(int x[4], int y[4])
{
- map_to_overview_pos(&x[0], &y[0],
- mapview_canvas.map_x0, mapview_canvas.map_y0);
+ int map_x0, map_y0;
+
+ canvas_to_map_pos(&map_x0, &map_y0, 0, 0);
+ map_to_overview_pos(&x[0], &y[0], map_x0, map_y0);
/* Note: these calculations operate on overview coordinates as if they
* are native. */
@@ -1853,40 +1821,50 @@
**************************************************************************/
bool map_canvas_resized(int width, int height)
{
+ int old_tile_width = mapview_canvas.tile_width;
+ int old_tile_height = mapview_canvas.tile_height;
+ int old_width = mapview_canvas.width, old_height = mapview_canvas.height;
int tile_width = (width + NORMAL_TILE_WIDTH - 1) / NORMAL_TILE_WIDTH;
int tile_height = (height + NORMAL_TILE_HEIGHT - 1) / NORMAL_TILE_HEIGHT;
+ int full_width = tile_width * NORMAL_TILE_WIDTH;
+ int full_height = tile_height * NORMAL_TILE_HEIGHT;
+ bool tile_size_changed, size_changed;
- if (mapview_canvas.tile_width == tile_width
- && mapview_canvas.tile_height == tile_height) {
- return FALSE;
- }
-
/* Resized */
-
- /* Since a resize is only triggered when the tile_*** changes, the canvas
- * width and height must include the entire backing store - otherwise
- * small resizings may lead to undrawn tiles. */
mapview_canvas.tile_width = tile_width;
mapview_canvas.tile_height = tile_height;
-
- mapview_canvas.width = mapview_canvas.tile_width * NORMAL_TILE_WIDTH;
- mapview_canvas.height = mapview_canvas.tile_height * NORMAL_TILE_HEIGHT;
-
- if (mapview_canvas.store) {
- canvas_store_free(mapview_canvas.store);
+ mapview_canvas.width = width;
+ mapview_canvas.height = height;
+ mapview_canvas.store_width = full_width;
+ mapview_canvas.store_height = full_height;
+
+ /* Check for what's changed. */
+ tile_size_changed = (tile_width != old_tile_width
+ || tile_height != old_tile_height);
+ size_changed = (width != old_width || height != old_height);
+
+ /* If the tile size has changed, resize the canvas. */
+ if (tile_size_changed) {
+ if (mapview_canvas.store) {
+ canvas_store_free(mapview_canvas.store);
+ }
+ mapview_canvas.store = canvas_store_create(full_width, full_height);
+ gui_put_rectangle(mapview_canvas.store, COLOR_STD_BLACK, 0, 0,
+ full_width, full_height);
}
-
- mapview_canvas.store =
- canvas_store_create(mapview_canvas.width, mapview_canvas.height);
- gui_put_rectangle(mapview_canvas.store, COLOR_STD_BLACK, 0, 0,
- mapview_canvas.width, mapview_canvas.height);
if (map_exists() && can_client_change_view()) {
- update_map_canvas_visible();
+ if (tile_size_changed) {
+ update_map_canvas_visible();
+ refresh_overview_canvas();
+ }
- update_map_canvas_scrollbars_size();
- update_map_canvas_scrollbars();
- refresh_overview_canvas();
+ /* If the width/height has changed, update the scrollbars even if
+ * the backing store is not resized. */
+ if (size_changed) {
+ update_map_canvas_scrollbars_size();
+ update_map_canvas_scrollbars();
+ }
}
return TRUE;
Index: client/mapview_common.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.h,v
retrieving revision 1.44
diff -u -r1.44 mapview_common.h
--- client/mapview_common.h 2004/02/21 22:15:03 1.44
+++ client/mapview_common.h 2004/02/23 01:12:52
@@ -23,9 +23,10 @@
struct canvas_store; /* opaque type, real type is gui-dep */
struct canvas {
- int map_x0, map_y0;
+ int gui_x0, gui_y0;
int width, height; /* Size in pixels. */
int tile_width, tile_height; /* Size in tiles. Rounded up. */
+ int store_width, store_height;
struct canvas_store *store;
};
|
|