mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 16:05:44 -07:00
Revamp of the control mechanism to permit drag- as well as
click-based control. Only used for right-dragging to clear a large area to NONTENT. [originally from svn r6400]
This commit is contained in:
@ -1836,6 +1836,11 @@ Right-clicking in a blank square will colour it green, indicating
|
|||||||
that you are sure it \e{isn't} a tent. Clicking either button in an
|
that you are sure it \e{isn't} a tent. Clicking either button in an
|
||||||
occupied square will clear it.
|
occupied square will clear it.
|
||||||
|
|
||||||
|
If you \e{drag} with the right button along a row or column, every
|
||||||
|
blank square in the region you cover will be turned green, and no
|
||||||
|
other squares will be affected. (This is useful for clearing the
|
||||||
|
remainder of a row once you have placed all its tents.)
|
||||||
|
|
||||||
(All the actions described in \k{common-actions} are also available.)
|
(All the actions described in \k{common-actions} are also available.)
|
||||||
|
|
||||||
\H{tents-parameters} \I{parameters, for Tents}Tents parameters
|
\H{tents-parameters} \I{parameters, for Tents}Tents parameters
|
||||||
|
165
tents.c
165
tents.c
@ -1400,13 +1400,26 @@ static char *game_text_format(game_state *state)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct game_ui {
|
||||||
|
int dsx, dsy; /* coords of drag start */
|
||||||
|
int dex, dey; /* coords of drag end */
|
||||||
|
int drag_button; /* -1 for none, or a button code */
|
||||||
|
int drag_ok; /* dragged off the window, to cancel */
|
||||||
|
};
|
||||||
|
|
||||||
static game_ui *new_ui(game_state *state)
|
static game_ui *new_ui(game_state *state)
|
||||||
{
|
{
|
||||||
return NULL;
|
game_ui *ui = snew(game_ui);
|
||||||
|
ui->dsx = ui->dsy = -1;
|
||||||
|
ui->dex = ui->dey = -1;
|
||||||
|
ui->drag_button = -1;
|
||||||
|
ui->drag_ok = FALSE;
|
||||||
|
return ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_ui(game_ui *ui)
|
static void free_ui(game_ui *ui)
|
||||||
{
|
{
|
||||||
|
sfree(ui);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *encode_ui(game_ui *ui)
|
static char *encode_ui(game_ui *ui)
|
||||||
@ -1439,32 +1452,151 @@ struct game_drawstate {
|
|||||||
|
|
||||||
#define FLASH_TIME 0.30F
|
#define FLASH_TIME 0.30F
|
||||||
|
|
||||||
|
static int drag_xform(game_ui *ui, int x, int y, int v)
|
||||||
|
{
|
||||||
|
int xmin, ymin, xmax, ymax;
|
||||||
|
|
||||||
|
xmin = min(ui->dsx, ui->dex);
|
||||||
|
xmax = max(ui->dsx, ui->dex);
|
||||||
|
ymin = min(ui->dsy, ui->dey);
|
||||||
|
ymax = max(ui->dsy, ui->dey);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Left-dragging has no effect, so we treat a left-drag as a
|
||||||
|
* single click on dsx,dsy.
|
||||||
|
*/
|
||||||
|
if (ui->drag_button == LEFT_BUTTON) {
|
||||||
|
xmin = xmax = ui->dsx;
|
||||||
|
ymin = ymax = ui->dsy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x < xmin || x > xmax || y < ymin || y > ymax)
|
||||||
|
return v; /* no change outside drag area */
|
||||||
|
|
||||||
|
if (v == TREE)
|
||||||
|
return v; /* trees are inviolate always */
|
||||||
|
|
||||||
|
if (xmin == xmax && ymin == ymax) {
|
||||||
|
/*
|
||||||
|
* Results of a simple click. Left button sets blanks to
|
||||||
|
* tents; right button sets blanks to non-tents; either
|
||||||
|
* button clears a non-blank square.
|
||||||
|
*/
|
||||||
|
if (ui->drag_button == LEFT_BUTTON)
|
||||||
|
v = (v == BLANK ? TENT : BLANK);
|
||||||
|
else
|
||||||
|
v = (v == BLANK ? NONTENT : BLANK);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Results of a drag. Left-dragging has no effect.
|
||||||
|
* Right-dragging sets all blank squares to non-tents and
|
||||||
|
* has no effect on anything else.
|
||||||
|
*/
|
||||||
|
if (ui->drag_button == RIGHT_BUTTON)
|
||||||
|
v = (v == BLANK ? NONTENT : v);
|
||||||
|
else
|
||||||
|
/* do nothing */;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
|
static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
|
||||||
int x, int y, int button)
|
int x, int y, int button)
|
||||||
{
|
{
|
||||||
int w = state->p.w, h = state->p.h;
|
int w = state->p.w, h = state->p.h;
|
||||||
|
|
||||||
if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
|
if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
|
||||||
int v;
|
|
||||||
char buf[80];
|
|
||||||
|
|
||||||
x = FROMCOORD(x);
|
x = FROMCOORD(x);
|
||||||
y = FROMCOORD(y);
|
y = FROMCOORD(y);
|
||||||
if (x < 0 || y < 0 || x >= w || y >= h)
|
if (x < 0 || y < 0 || x >= w || y >= h)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (state->grid[y*w+x] == TREE)
|
ui->drag_button = button;
|
||||||
return NULL;
|
ui->dsx = ui->dex = x;
|
||||||
|
ui->dsy = ui->dey = y;
|
||||||
|
ui->drag_ok = TRUE;
|
||||||
|
return ""; /* ui updated */
|
||||||
|
}
|
||||||
|
|
||||||
if (button == LEFT_BUTTON) {
|
if ((IS_MOUSE_DRAG(button) || IS_MOUSE_RELEASE(button)) &&
|
||||||
v = (state->grid[y*w+x] == BLANK ? TENT : BLANK);
|
ui->drag_button > 0) {
|
||||||
|
int xmin, ymin, xmax, ymax;
|
||||||
|
char *buf, *sep, tmpbuf[80];
|
||||||
|
int buflen, bufsize, tmplen;
|
||||||
|
|
||||||
|
x = FROMCOORD(x);
|
||||||
|
y = FROMCOORD(y);
|
||||||
|
if (x < 0 || y < 0 || x >= w || y >= h) {
|
||||||
|
ui->drag_ok = FALSE;
|
||||||
} else {
|
} else {
|
||||||
v = (state->grid[y*w+x] == BLANK ? NONTENT : BLANK);
|
/*
|
||||||
|
* Drags are limited to one row or column. Hence, we
|
||||||
|
* work out which coordinate is closer to the drag
|
||||||
|
* start, and move it _to_ the drag start.
|
||||||
|
*/
|
||||||
|
if (abs(x - ui->dsx) < abs(y - ui->dsy))
|
||||||
|
x = ui->dsx;
|
||||||
|
else
|
||||||
|
y = ui->dsy;
|
||||||
|
|
||||||
|
ui->dex = x;
|
||||||
|
ui->dey = y;
|
||||||
|
|
||||||
|
ui->drag_ok = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(buf, "%c%d,%d", (int)(v==BLANK ? 'B' :
|
if (IS_MOUSE_DRAG(button))
|
||||||
v==TENT ? 'T' : 'N'), x, y);
|
return ""; /* ui updated */
|
||||||
return dupstr(buf);
|
|
||||||
|
/*
|
||||||
|
* The drag has been released. Enact it.
|
||||||
|
*/
|
||||||
|
if (!ui->drag_ok) {
|
||||||
|
ui->drag_button = -1;
|
||||||
|
return ""; /* drag was just cancelled */
|
||||||
|
}
|
||||||
|
|
||||||
|
xmin = min(ui->dsx, ui->dex);
|
||||||
|
xmax = max(ui->dsx, ui->dex);
|
||||||
|
ymin = min(ui->dsy, ui->dey);
|
||||||
|
ymax = max(ui->dsy, ui->dey);
|
||||||
|
assert(0 <= xmin && xmin <= xmax && xmax < w);
|
||||||
|
assert(0 <= ymin && ymin <= ymax && ymax < w);
|
||||||
|
|
||||||
|
buflen = 0;
|
||||||
|
bufsize = 256;
|
||||||
|
buf = snewn(bufsize, char);
|
||||||
|
sep = "";
|
||||||
|
for (y = ymin; y <= ymax; y++)
|
||||||
|
for (x = xmin; x <= xmax; x++) {
|
||||||
|
int v = drag_xform(ui, x, y, state->grid[y*w+x]);
|
||||||
|
if (state->grid[y*w+x] != v) {
|
||||||
|
tmplen = sprintf(tmpbuf, "%s%c%d,%d", sep,
|
||||||
|
(v == BLANK ? 'B' :
|
||||||
|
v == TENT ? 'T' : 'N'),
|
||||||
|
x, y);
|
||||||
|
sep = ";";
|
||||||
|
|
||||||
|
if (buflen + tmplen >= bufsize) {
|
||||||
|
bufsize = buflen + tmplen + 256;
|
||||||
|
buf = sresize(buf, bufsize, char);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(buf+buflen, tmpbuf);
|
||||||
|
buflen += tmplen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->drag_button = -1; /* drag is terminated */
|
||||||
|
|
||||||
|
if (buflen == 0) {
|
||||||
|
sfree(buf);
|
||||||
|
return ""; /* ui updated (drag was terminated) */
|
||||||
|
} else {
|
||||||
|
buf[buflen] = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1834,6 +1966,15 @@ static void int_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
|
|||||||
for (x = 0; x < w; x++) {
|
for (x = 0; x < w; x++) {
|
||||||
int v = state->grid[y*w+x];
|
int v = state->grid[y*w+x];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We deliberately do not take drag_ok into account
|
||||||
|
* here, because user feedback suggests that it's
|
||||||
|
* marginally nicer not to have the drag effects
|
||||||
|
* flickering on and off disconcertingly.
|
||||||
|
*/
|
||||||
|
if (ui->drag_button >= 0)
|
||||||
|
v = drag_xform(ui, x, y, v);
|
||||||
|
|
||||||
if (flashing && (v == TREE || v == TENT))
|
if (flashing && (v == TREE || v == TENT))
|
||||||
v = NONTENT;
|
v = NONTENT;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user