chiark / gitweb /
Keyboard control patch for Pattern, from James H.
authorSimon Tatham <anakin@pobox.com>
Tue, 27 Jan 2009 18:30:46 +0000 (18:30 +0000)
committerSimon Tatham <anakin@pobox.com>
Tue, 27 Jan 2009 18:30:46 +0000 (18:30 +0000)
[originally from svn r8435]

pattern.c
puzzles.but

index a1d2424b518d80a3a3de0b675318516ad479d274..787e591a8037225440c93d4ad0f3e37df0faf094 100644 (file)
--- a/pattern.c
+++ b/pattern.c
@@ -18,6 +18,7 @@ enum {
     COL_TEXT,
     COL_UNKNOWN,
     COL_GRID,
+    COL_CURSOR,
     NCOLOURS
 };
 
@@ -745,6 +746,7 @@ struct game_ui {
     int drag_end_x;
     int drag_end_y;
     int drag, release, state;
+    int cur_x, cur_y, cur_visible;
 };
 
 static game_ui *new_ui(game_state *state)
@@ -753,6 +755,7 @@ static game_ui *new_ui(game_state *state)
 
     ret = snew(game_ui);
     ret->dragging = FALSE;
+    ret->cur_x = ret->cur_y = ret->cur_visible = 0;
 
     return ret;
 }
@@ -781,6 +784,7 @@ struct game_drawstate {
     int w, h;
     int tilesize;
     unsigned char *visible;
+    int cur_x, cur_y;
 };
 
 static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
@@ -824,6 +828,7 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
 
         ui->drag_start_x = ui->drag_end_x = x;
         ui->drag_start_y = ui->drag_end_y = y;
+        ui->cur_visible = 0;
 
         return "";                    /* UI activity occurred */
     }
@@ -884,6 +889,35 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
             return "";                /* UI activity occurred */
     }
 
+    if (IS_CURSOR_MOVE(button)) {
+        move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h, 0);
+        ui->cur_visible = 1;
+        return "";
+    }
+    if (IS_CURSOR_SELECT(button)) {
+        int currstate = state->grid[ui->cur_y * state->w + ui->cur_x];
+        int newstate;
+        char buf[80];
+
+        if (!ui->cur_visible) {
+            ui->cur_visible = 1;
+            return "";
+        }
+
+        if (button == CURSOR_SELECT2)
+            newstate = currstate == GRID_UNKNOWN ? GRID_EMPTY :
+                currstate == GRID_EMPTY ? GRID_FULL : GRID_UNKNOWN;
+        else
+            newstate = currstate == GRID_UNKNOWN ? GRID_FULL :
+                currstate == GRID_FULL ? GRID_EMPTY : GRID_UNKNOWN;
+
+        sprintf(buf, "%c%d,%d,%d,%d",
+                (char)(newstate == GRID_FULL ? 'F' :
+                      newstate == GRID_EMPTY ? 'E' : 'U'),
+                ui->cur_x, ui->cur_y, 1, 1);
+        return dupstr(buf);
+    }
+
     return NULL;
 }
 
@@ -982,28 +1016,20 @@ static void game_set_size(drawing *dr, game_drawstate *ds,
 static float *game_colours(frontend *fe, int *ncolours)
 {
     float *ret = snewn(3 * NCOLOURS, float);
+    int i;
 
     frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
 
-    ret[COL_GRID * 3 + 0] = 0.3F;
-    ret[COL_GRID * 3 + 1] = 0.3F;
-    ret[COL_GRID * 3 + 2] = 0.3F;
-
-    ret[COL_UNKNOWN * 3 + 0] = 0.5F;
-    ret[COL_UNKNOWN * 3 + 1] = 0.5F;
-    ret[COL_UNKNOWN * 3 + 2] = 0.5F;
-
-    ret[COL_TEXT * 3 + 0] = 0.0F;
-    ret[COL_TEXT * 3 + 1] = 0.0F;
-    ret[COL_TEXT * 3 + 2] = 0.0F;
-
-    ret[COL_FULL * 3 + 0] = 0.0F;
-    ret[COL_FULL * 3 + 1] = 0.0F;
-    ret[COL_FULL * 3 + 2] = 0.0F;
-
-    ret[COL_EMPTY * 3 + 0] = 1.0F;
-    ret[COL_EMPTY * 3 + 1] = 1.0F;
-    ret[COL_EMPTY * 3 + 2] = 1.0F;
+    for (i = 0; i < 3; i++) {
+        ret[COL_GRID    * 3 + i] = 0.3F;
+        ret[COL_UNKNOWN * 3 + i] = 0.5F;
+        ret[COL_TEXT    * 3 + i] = 0.0F;
+        ret[COL_FULL    * 3 + i] = 0.0F;
+        ret[COL_EMPTY   * 3 + i] = 1.0F;
+    }
+    ret[COL_CURSOR * 3 + 0] = 1.0F;
+    ret[COL_CURSOR * 3 + 1] = 0.25F;
+    ret[COL_CURSOR * 3 + 2] = 0.25F;
 
     *ncolours = NCOLOURS;
     return ret;
@@ -1030,9 +1056,9 @@ static void game_free_drawstate(drawing *dr, game_drawstate *ds)
 }
 
 static void grid_square(drawing *dr, game_drawstate *ds,
-                        int y, int x, int state)
+                        int y, int x, int state, int cur)
 {
-    int xl, xr, yt, yb;
+    int xl, xr, yt, yb, dx, dy, dw, dh;
 
     draw_rect(dr, TOCOORD(ds->w, x), TOCOORD(ds->h, y),
               TILE_SIZE, TILE_SIZE, COL_GRID);
@@ -1042,10 +1068,18 @@ static void grid_square(drawing *dr, game_drawstate *ds,
     xr = (x % 5 == 4 || x == ds->w-1 ? 1 : 0);
     yb = (y % 5 == 4 || y == ds->h-1 ? 1 : 0);
 
-    draw_rect(dr, TOCOORD(ds->w, x) + 1 + xl, TOCOORD(ds->h, y) + 1 + yt,
-              TILE_SIZE - xl - xr - 1, TILE_SIZE - yt - yb - 1,
+    dx = TOCOORD(ds->w, x) + 1 + xl;
+    dy = TOCOORD(ds->h, y) + 1 + yt;
+    dw = TILE_SIZE - xl - xr - 1;
+    dh = TILE_SIZE - yt - yb - 1;
+
+    draw_rect(dr, dx, dy, dw, dh,
               (state == GRID_FULL ? COL_FULL :
                state == GRID_EMPTY ? COL_EMPTY : COL_UNKNOWN));
+    if (cur) {
+        draw_rect_outline(dr, dx, dy, dw, dh, COL_CURSOR);
+        draw_rect_outline(dr, dx+1, dy+1, dw-2, dh-2, COL_CURSOR);
+    }
 
     draw_update(dr, TOCOORD(ds->w, x), TOCOORD(ds->h, y),
                 TILE_SIZE, TILE_SIZE);
@@ -1100,6 +1134,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
 {
     int i, j;
     int x1, x2, y1, y2;
+    int cx, cy, cmoved;
 
     if (!ds->started) {
         /*
@@ -1136,13 +1171,20 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
         x1 = x2 = y1 = y2 = -1;        /* placate gcc warnings */
     }
 
+    if (ui->cur_visible) {
+        cx = ui->cur_x; cy = ui->cur_y;
+    } else {
+        cx = cy = -1;
+    }
+    cmoved = (cx != ds->cur_x || cy != ds->cur_y);
+
     /*
      * Now draw any grid squares which have changed since last
      * redraw.
      */
     for (i = 0; i < ds->h; i++) {
         for (j = 0; j < ds->w; j++) {
-            int val;
+            int val, cc = 0;
 
             /*
              * Work out what state this square should be drawn in,
@@ -1153,6 +1195,13 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
             else
                 val = state->grid[i * state->w + j];
 
+            if (cmoved) {
+                /* the cursor has moved; if we were the old or
+                 * the new cursor position we need to redraw. */
+                if (j == cx && i == cy) cc = 1;
+                if (j == ds->cur_x && i == ds->cur_y) cc = 1;
+            }
+
             /*
              * Briefly invert everything twice during a completion
              * flash.
@@ -1162,12 +1211,14 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
                 val != GRID_UNKNOWN)
                 val = (GRID_FULL ^ GRID_EMPTY) ^ val;
 
-            if (ds->visible[i * ds->w + j] != val) {
-                grid_square(dr, ds, i, j, val);
+            if (ds->visible[i * ds->w + j] != val || cc) {
+                grid_square(dr, ds, i, j, val,
+                            (j == cx && i == cy));
                 ds->visible[i * ds->w + j] = val;
             }
         }
     }
+    ds->cur_x = cx; ds->cur_y = cy;
 }
 
 static float game_anim_length(game_state *oldstate,
@@ -1198,8 +1249,8 @@ static void game_print_size(game_params *params, float *x, float *y)
      * I'll use 5mm squares by default.
      */
     game_compute_size(params, 500, &pw, &ph);
-    *x = pw / 100.0;
-    *y = ph / 100.0;
+    *x = pw / 100.0F;
+    *y = ph / 100.0F;
 }
 
 static void game_print(drawing *dr, game_state *state, int tilesize)
@@ -1379,3 +1430,5 @@ int main(int argc, char **argv)
 }
 
 #endif
+
+/* vim: set shiftwidth=4 tabstop=8: */
index bd2e592a3d579c9910ebe3f008d22a4bce6050d5..32f331a8db83d682ebf45f46975bd72fccca3b8e 100644 (file)
@@ -884,6 +884,10 @@ a vertical or horizontal line of squares black or white at a time
 with Shift held down, you can colour a whole rectangle of squares
 grey.
 
+You can also move around the grid with the cursor keys. Pressing the
+return key will cycle the current cell through empty --> black -->
+white --> empty, and the space bar does the same cycle in reverse.
+
 (All the actions described in \k{common-actions} are also available.)
 
 \H{pattern-parameters} \I{parameters, for Pattern}Pattern parameters