Map: stop storing pixel coordinates in game_ui.

The fields (ui->dragx,ui->dragy) stored the pixel coordinates of the
visible cursor (if any), no matter whether that cursor was being
displayed in response to a mouse dragging action or arrow-key
activity. But this meant that resizing the window while the keyboard
cursor was visible would cause the cursor to be drawn in totally the
wrong place in the newly resized window: you get a new drawstate with
a fresh blitter (so at least no part of the old-size window is
accidentally 'restored' on to the new-size one), but the ui fields
saying where _next_ to draw the cursor would still have bogus values
left over from the previous window size.

To fix this, I've arranged that we simply don't use ui->dragx and
ui->dragy any more in keyboard cursor mode: instead, we leave it to
game_redraw to spot that the keyboard cursor is visible and compute
its pixel coordinates for display.

A knock-on effect is that when we need to know which region is under
the cursor during interpret_move, we can't use the previous strategy
of just calling region_from_coords(ui->dragx, ui->dragy) regardless of
which kind of cursor is active. So I've split that function up into an
inner section taking a tile and a displacement from the tile's centre
and an outer part which derives those from real pixel coordinates in
the case where the cursor is originating from a mouse drag; then
there's a new alternative outer part which derives the same (tile,
displacement) pair purely from the game_ui keyboard cursor data
without having to explicitly translate into pixels and back in the
middle. Probably a less fragile strategy anyway.
This commit is contained in:
Simon Tatham
2017-10-28 08:55:33 +01:00
parent efcc00ffef
commit 6da8dc91a2

67
map.c
View File

@ -2340,18 +2340,21 @@ struct game_drawstate {
((button) == CURSOR_UP) ? -1 : 0) ((button) == CURSOR_UP) ? -1 : 0)
static int region_from_coords(const game_state *state, /*
const game_drawstate *ds, int x, int y) * Return the map region containing a point in tile (tx,ty), offset by
* (x_eps,y_eps) from the centre of the tile.
*/
static int region_from_logical_coords(const game_state *state, int tx, int ty,
int x_eps, int y_eps)
{ {
int w = state->p.w, h = state->p.h, wh = w*h /*, n = state->p.n */; int w = state->p.w, h = state->p.h, wh = w*h /*, n = state->p.n */;
int tx = FROMCOORD(x), ty = FROMCOORD(y);
int dx = x - COORD(tx), dy = y - COORD(ty);
int quadrant; int quadrant;
if (tx < 0 || tx >= w || ty < 0 || ty >= h) if (tx < 0 || tx >= w || ty < 0 || ty >= h)
return -1; /* border */ return -1; /* border */
quadrant = 2 * (dx > dy) + (TILESIZE - dx > dy); quadrant = 2 * (x_eps > y_eps) + (-x_eps > y_eps);
quadrant = (quadrant == 0 ? BE : quadrant = (quadrant == 0 ? BE :
quadrant == 1 ? LE : quadrant == 1 ? LE :
quadrant == 2 ? RE : TE); quadrant == 2 ? RE : TE);
@ -2359,12 +2362,28 @@ static int region_from_coords(const game_state *state,
return state->map->map[quadrant * wh + ty*w+tx]; return state->map->map[quadrant * wh + ty*w+tx];
} }
static int region_from_coords(const game_state *state,
const game_drawstate *ds, int x, int y)
{
int tx = FROMCOORD(x), ty = FROMCOORD(y);
return region_from_logical_coords(
state, tx, ty, x - COORD(tx) - TILESIZE/2, y - COORD(ty) - TILESIZE/2);
}
static int region_from_ui_cursor(const game_state *state, const game_ui *ui)
{
assert(ui->cur_visible);
return region_from_logical_coords(state, ui->cur_x, ui->cur_y,
EPSILON_X(ui->cur_lastmove),
EPSILON_Y(ui->cur_lastmove));
}
static char *interpret_move(const game_state *state, game_ui *ui, static char *interpret_move(const game_state *state, game_ui *ui,
const game_drawstate *ds, const game_drawstate *ds,
int x, int y, int button) int x, int y, int button)
{ {
char *bufp, buf[256]; char *bufp, buf[256];
int alt_button; int alt_button, drop_region;
/* /*
* Enable or disable numeric labels on regions. * Enable or disable numeric labels on regions.
@ -2379,19 +2398,15 @@ static char *interpret_move(const game_state *state, game_ui *ui,
ui->cur_visible = 1; ui->cur_visible = 1;
ui->cur_moved = 1; ui->cur_moved = 1;
ui->cur_lastmove = button; ui->cur_lastmove = button;
ui->dragx = COORD(ui->cur_x) + TILESIZE/2 + EPSILON_X(button);
ui->dragy = COORD(ui->cur_y) + TILESIZE/2 + EPSILON_Y(button);
return UI_UPDATE; return UI_UPDATE;
} }
if (IS_CURSOR_SELECT(button)) { if (IS_CURSOR_SELECT(button)) {
if (!ui->cur_visible) { if (!ui->cur_visible) {
ui->dragx = COORD(ui->cur_x) + TILESIZE/2 + EPSILON_X(ui->cur_lastmove);
ui->dragy = COORD(ui->cur_y) + TILESIZE/2 + EPSILON_Y(ui->cur_lastmove);
ui->cur_visible = 1; ui->cur_visible = 1;
return UI_UPDATE; return UI_UPDATE;
} }
if (ui->drag_colour == -2) { /* not currently cursor-dragging, start. */ if (ui->drag_colour == -2) { /* not currently cursor-dragging, start. */
int r = region_from_coords(state, ds, ui->dragx, ui->dragy); int r = region_from_ui_cursor(state, ui);
if (r >= 0) { if (r >= 0) {
ui->drag_colour = state->colouring[r]; ui->drag_colour = state->colouring[r];
ui->drag_pencil = (ui->drag_colour >= 0) ? 0 : state->pencil[r]; ui->drag_pencil = (ui->drag_colour >= 0) ? 0 : state->pencil[r];
@ -2402,11 +2417,10 @@ static char *interpret_move(const game_state *state, game_ui *ui,
ui->cur_moved = 0; ui->cur_moved = 0;
return UI_UPDATE; return UI_UPDATE;
} else { /* currently cursor-dragging; drop the colour in the new region. */ } else { /* currently cursor-dragging; drop the colour in the new region. */
x = COORD(ui->cur_x) + TILESIZE/2 + EPSILON_X(ui->cur_lastmove);
y = COORD(ui->cur_y) + TILESIZE/2 + EPSILON_Y(ui->cur_lastmove);
alt_button = (button == CURSOR_SELECT2) ? 1 : 0; alt_button = (button == CURSOR_SELECT2) ? 1 : 0;
/* Double-select removes current colour. */ /* Double-select removes current colour. */
if (!ui->cur_moved) ui->drag_colour = -1; if (!ui->cur_moved) ui->drag_colour = -1;
drop_region = region_from_ui_cursor(state, ui);
goto drag_dropped; goto drag_dropped;
} }
} }
@ -2439,6 +2453,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
if ((button == LEFT_RELEASE || button == RIGHT_RELEASE) && if ((button == LEFT_RELEASE || button == RIGHT_RELEASE) &&
ui->drag_colour > -2) { ui->drag_colour > -2) {
alt_button = (button == RIGHT_RELEASE) ? 1 : 0; alt_button = (button == RIGHT_RELEASE) ? 1 : 0;
drop_region = region_from_coords(state, ds, x, y);
goto drag_dropped; goto drag_dropped;
} }
@ -2446,7 +2461,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
drag_dropped: drag_dropped:
{ {
int r = region_from_coords(state, ds, x, y); int r = drop_region;
int c = ui->drag_colour; int c = ui->drag_colour;
int p = ui->drag_pencil; int p = ui->drag_pencil;
int oldp; int oldp;
@ -2972,29 +2987,37 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
* Draw the dragged colour blob if any. * Draw the dragged colour blob if any.
*/ */
if ((ui->drag_colour > -2) || ui->cur_visible) { if ((ui->drag_colour > -2) || ui->cur_visible) {
int bg, iscur = 0; int bg, iscur = 0, cursor_x, cursor_y;
if (ui->drag_colour >= 0) if (ui->drag_colour >= 0)
bg = COL_0 + ui->drag_colour; bg = COL_0 + ui->drag_colour;
else if (ui->drag_colour == -1) { else if (ui->drag_colour == -1) {
bg = COL_BACKGROUND; bg = COL_BACKGROUND;
} else { } else {
int r = region_from_coords(state, ds, ui->dragx, ui->dragy); int r = region_from_ui_cursor(state, ui);
int c = (r < 0) ? -1 : state->colouring[r]; int c = (r < 0) ? -1 : state->colouring[r];
assert(ui->cur_visible);
/*bg = COL_GRID;*/ /*bg = COL_GRID;*/
bg = (c < 0) ? COL_BACKGROUND : COL_0 + c; bg = (c < 0) ? COL_BACKGROUND : COL_0 + c;
iscur = 1; iscur = 1;
} }
ds->dragx = ui->dragx - TILESIZE/2 - 2; if (ui->cur_visible) {
ds->dragy = ui->dragy - TILESIZE/2 - 2; cursor_x = COORD(ui->cur_x) + TILESIZE/2 +
EPSILON_X(ui->cur_lastmove);
cursor_y = COORD(ui->cur_y) + TILESIZE/2 +
EPSILON_Y(ui->cur_lastmove);
} else {
cursor_x = ui->dragx;
cursor_y = ui->dragy;
}
ds->dragx = cursor_x - TILESIZE/2 - 2;
ds->dragy = cursor_y - TILESIZE/2 - 2;
blitter_save(dr, ds->bl, ds->dragx, ds->dragy); blitter_save(dr, ds->bl, ds->dragx, ds->dragy);
draw_circle(dr, ui->dragx, ui->dragy, draw_circle(dr, cursor_x, cursor_y,
iscur ? TILESIZE/4 : TILESIZE/2, bg, COL_GRID); iscur ? TILESIZE/4 : TILESIZE/2, bg, COL_GRID);
for (i = 0; i < FOUR; i++) for (i = 0; i < FOUR; i++)
if (ui->drag_pencil & (1 << i)) if (ui->drag_pencil & (1 << i))
draw_circle(dr, ui->dragx + ((i*4+2)%10-3) * TILESIZE/10, draw_circle(dr, cursor_x + ((i*4+2)%10-3) * TILESIZE/10,
ui->dragy + (i*2-3) * TILESIZE/10, cursor_y + (i*2-3) * TILESIZE/10,
TILESIZE/8, COL_0 + i, COL_0 + i); TILESIZE/8, COL_0 + i, COL_0 + i);
draw_update(dr, ds->dragx, ds->dragy, TILESIZE + 3, TILESIZE + 3); draw_update(dr, ds->dragx, ds->dragy, TILESIZE + 3, TILESIZE + 3);
ds->drag_visible = TRUE; ds->drag_visible = TRUE;