Complete.Org: Mailing Lists: Archives: freeciv-dev: February 2004:
[Freeciv-Dev] Re: (PR#7445) mapview scrolling
Home

[Freeciv-Dev] Re: (PR#7445) mapview scrolling

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] Re: (PR#7445) mapview scrolling
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 20 Feb 2004 09:41:34 -0800
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=7445 >

Jason Short wrote:

> This patch gets rid of mapview_canvas.map_x0/map_y0.  Instead we track 
> the mapview origin in gui coordinates.  Gui coordinates are just like 
> canvas coordinates but they extend indefinitely in all directions (for 
> scroll purposes we limit them to a bounding box).  Scrolling is done in 
> gui coordinates.  In fact just about everything is done in gui coordinates.

This patch makes a few changes:

- Some improved comments.

- Fix for resizing canvas.  We have to track the canvas width/height 
because the scrollbar size depends on them (this isn't just a cosmetic 
issue - without it some parts of the map may not be visible at all).  We 
also have to track the canvas _store_ width/height because 
map_to_canvas_pos needs it.  We need to do updates to all tiles visible 
anywhere on the store because if the canvas is resized, these tiles may 
_become_ visible without a resize.  This means two new values in the 
mapview_canvas struct.  Finally, we have to update the scrollbars if the 
canvas width/height changes even if the canvas store remains the same size.

With this patch almost everything should work.  The only thing that may 
not work perfectly is the updating of a selection rectangle when the 
canvas is recentered (very rare).

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/20 17:40:28
@@ -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.78
diff -u -r1.78 mapview_common.c
--- client/mapview_common.c     2004/02/18 02:20:51     1.78
+++ client/mapview_common.c     2004/02/20 17:40:29
@@ -160,6 +160,81 @@
   }
 }
 
+/****************************************************************************
+  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.
+     *
+     * 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(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
@@ -199,52 +274,20 @@
   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;
+  map_to_gui_pos(canvas_x, canvas_y, map_x, map_y);
+  *canvas_x -= mapview_canvas.gui_x0;
+  *canvas_y -= mapview_canvas.gui_y0;
 
-    /*
-     * 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);
-
-    /*
-     * 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 +297,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 +318,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 +382,41 @@
 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;
   } 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 +429,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 +443,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 +452,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,7 +474,7 @@
 **************************************************************************/
 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;
 
   /* Find top-left corner. */
   if (is_isometric) {
@@ -545,7 +487,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);
 }
 
 /**************************************************************************
@@ -1134,6 +1077,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
@@ -1145,18 +1090,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);
   }
 
@@ -1169,6 +1116,7 @@
 void show_city_descriptions(void)
 {
   int canvas_x, canvas_y;
+  int map_x0, map_y0;
 
   if (!draw_city_names && !draw_city_productions) {
     return;
@@ -1176,12 +1124,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;
@@ -1198,10 +1147,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)
@@ -1709,8 +1658,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. */
@@ -1819,40 +1770,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.43
diff -u -r1.43 mapview_common.h
--- client/mapview_common.h     2004/02/18 02:20:51     1.43
+++ client/mapview_common.h     2004/02/20 17:40:29
@@ -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;
 };
 

[Prev in Thread] Current Thread [Next in Thread]