+ } else if (IS_CURSOR_MOVE(button)) {
+ ui->cur_visible = 1;
+ if (control || shift) {
+ ui->dragx_src = ui->cur_x;
+ ui->dragy_src = ui->cur_y;
+ ui->dragging = TRUE;
+ ui->drag_is_noline = !control;
+ }
+ if (ui->dragging) {
+ int nx = ui->cur_x, ny = ui->cur_y;
+
+ move_cursor(button, &nx, &ny, state->w, state->h, 0);
+ if (nx == ui->cur_x && ny == ui->cur_y)
+ return NULL;
+ update_drag_dst(state, ui, ds,
+ COORD(nx)+TILE_SIZE/2,
+ COORD(ny)+TILE_SIZE/2);
+ return finish_drag(state, ui);
+ } else {
+ int dx = (button == CURSOR_RIGHT) ? +1 : (button == CURSOR_LEFT) ? -1 : 0;
+ int dy = (button == CURSOR_DOWN) ? +1 : (button == CURSOR_UP) ? -1 : 0;
+ int dorthx = 1 - abs(dx), dorthy = 1 - abs(dy);
+ int dir, orth, nx = x, ny = y;
+
+ /* 'orthorder' is a tweak to ensure that if you press RIGHT and
+ * happen to move upwards, when you press LEFT you then tend
+ * downwards (rather than upwards again). */
+ int orthorder = (button == CURSOR_LEFT || button == CURSOR_UP) ? 1 : -1;
+
+ /* This attempts to find an island in the direction you're
+ * asking for, broadly speaking. If you ask to go right, for
+ * example, it'll look for islands to the right and slightly
+ * above or below your current horiz. position, allowing
+ * further above/below the further away it searches. */
+
+ assert(GRID(state, ui->cur_x, ui->cur_y) & G_ISLAND);
+ /* currently this is depth-first (so orthogonally-adjacent
+ * islands across the other side of the grid will be moved to
+ * before closer islands slightly offset). Swap the order of
+ * these two loops to change to breadth-first search. */
+ for (orth = 0; ; orth++) {
+ int oingrid = 0;
+ for (dir = 1; ; dir++) {
+ int dingrid = 0;
+
+ if (orth > dir) continue; /* only search in cone outwards. */
+
+ nx = ui->cur_x + dir*dx + orth*dorthx*orthorder;
+ ny = ui->cur_y + dir*dy + orth*dorthy*orthorder;
+ if (INGRID(state, nx, ny)) {
+ dingrid = oingrid = 1;
+ if (GRID(state, nx, ny) & G_ISLAND) goto found;
+ }
+
+ nx = ui->cur_x + dir*dx - orth*dorthx*orthorder;
+ ny = ui->cur_y + dir*dy - orth*dorthy*orthorder;
+ if (INGRID(state, nx, ny)) {
+ dingrid = oingrid = 1;
+ if (GRID(state, nx, ny) & G_ISLAND) goto found;
+ }
+
+ if (!dingrid) break;
+ }
+ if (!oingrid) return "";
+ }
+ /* not reached */
+
+found:
+ ui->cur_x = nx;
+ ui->cur_y = ny;
+ return "";
+ }
+ } else if (IS_CURSOR_SELECT(button)) {
+ if (!ui->cur_visible) {
+ ui->cur_visible = 1;
+ return "";
+ }
+ if (ui->dragging || button == CURSOR_SELECT2) {
+ ui_cancel_drag(ui);
+ if (ui->dragx_dst == -1 && ui->dragy_dst == -1) {
+ sprintf(buf, "M%d,%d", ui->cur_x, ui->cur_y);
+ return dupstr(buf);
+ } else
+ return "";
+ } else {
+ grid_type v = GRID(state, ui->cur_x, ui->cur_y);
+ if (v & G_ISLAND) {
+ ui->dragging = 1;
+ ui->dragx_src = ui->cur_x;
+ ui->dragy_src = ui->cur_y;
+ ui->dragx_dst = ui->dragy_dst = -1;
+ ui->drag_is_noline = (button == CURSOR_SELECT2) ? 1 : 0;
+ return "";
+ }
+ }
+ } else if ((button >= '0' && button <= '9') ||
+ (button >= 'a' && button <= 'f') ||
+ (button >= 'A' && button <= 'F')) {
+ /* jump to island with .count == number closest to cur_{x,y} */
+ int best_x = -1, best_y = -1, best_sqdist = -1, number = -1, i;
+
+ if (button >= '0' && button <= '9')
+ number = (button == '0' ? 16 : button - '0');
+ else if (button >= 'a' && button <= 'f')
+ number = 10 + button - 'a';
+ else if (button >= 'A' && button <= 'F')
+ number = 10 + button - 'A';
+
+ if (!ui->cur_visible) {
+ ui->cur_visible = 1;
+ return "";
+ }
+
+ for (i = 0; i < state->n_islands; ++i) {
+ int x = state->islands[i].x, y = state->islands[i].y;
+ int dx = x - ui->cur_x, dy = y - ui->cur_y;
+ int sqdist = dx*dx + dy*dy;
+
+ if (state->islands[i].count != number)
+ continue;
+ if (x == ui->cur_x && y == ui->cur_y)
+ continue;
+
+ /* new_game() reads the islands in row-major order, so by
+ * breaking ties in favor of `first in state->islands' we
+ * also break ties by `lexicographically smallest (y, x)'.
+ * Thus, there's a stable pattern to how ties are broken
+ * which the user can learn and use to navigate faster. */
+ if (best_sqdist == -1 || sqdist < best_sqdist) {
+ best_x = x;
+ best_y = y;
+ best_sqdist = sqdist;
+ }
+ }
+ if (best_x != -1 && best_y != -1) {
+ ui->cur_x = best_x;
+ ui->cur_y = best_y;
+ return "";
+ } else
+ return NULL;
+ } else if (button == 'g' || button == 'G') {
+ ui->show_hints = 1 - ui->show_hints;
+ return "";