]> git.cworth.org Git - dvonn/commitdiff
Add simplistic button-press handling
authorCarl Worth <cworth@cworth.org>
Thu, 5 Mar 2009 08:33:54 +0000 (00:33 -0800)
committerCarl Worth <cworth@cworth.org>
Thu, 5 Mar 2009 08:33:54 +0000 (00:33 -0800)
Right now this is just toggling a white ring on and off at
each location. The significant bit here is that the calculations
between board-index positions and screen coordinates are now
correct. Thanks to Keith Packard for helping me think through
some of the math here.

dvonn.c

diff --git a/dvonn.c b/dvonn.c
index 43de664e9e362d9aa56d57ef9847d470a7f9e963..616ebf35e7ee6f69a3dabb5c4a5fc421481a78a7 100644 (file)
--- a/dvonn.c
+++ b/dvonn.c
@@ -80,6 +80,63 @@ loa_game_update_windows (loa_game_t *game)
        gtk_widget_queue_draw (game->views[i]->window);
 }
 
+/* Convert from a board index to a device-pixel coordinate pair, (at
+ * the center of the ring). */
+static void
+layout_board_to_device (layout_t *layout, double *x_ret, double *y_ret)
+{
+    double x = *x_ret, y = *y_ret;
+
+    *x_ret = layout->x_offset + layout->cell_size *
+       (x + (y - DVONN_BOARD_Y_SIZE/2)/2.0 + 0.5);
+    *y_ret = layout->y_offset + layout->cell_size * (M_SQRT1_2 * y + 0.5);
+}
+
+/* Convert from a device-pixel coordinate pair to a board index. */
+static void
+layout_device_to_board (layout_t *layout, int *x_ret, int *y_ret)
+{
+    int x = *x_ret, y = *y_ret;
+    int x1, y1, x2, y2;
+    double x1_dev, y1_dev, x2_dev, y2_dev;
+    double dx, dy, d1, d2;
+
+    /* Because the vertical spacing between adjacent rows is less than
+     * layout->cell_size, the simple calculations here give us two
+     * candidate (x,y) pairs. We then choose the correct one based on
+     * a distance calculation.
+     */
+    y1 = (y - layout->y_offset) / (layout->cell_size * M_SQRT1_2);
+    x1 = (double) (x - layout->x_offset) / layout->cell_size - (y1 - DVONN_BOARD_Y_SIZE/2)/2.0;
+
+    y2 = y1 - 1;
+    x2 = (double) (x - layout->x_offset) / layout->cell_size - (y2 - DVONN_BOARD_Y_SIZE/2)/2.0;
+
+    x1_dev = x1;
+    y1_dev = y1;
+    layout_board_to_device (layout, &x1_dev, &y1_dev);
+
+    x2_dev = x2;
+    y2_dev = y2;
+    layout_board_to_device (layout, &x2_dev, &y2_dev);
+
+    dx = x - x1_dev;
+    dy = y - y1_dev;
+    d1 = sqrt (dx*dx + dy*dy);
+
+    dx = x - x2_dev;
+    dy = y - y2_dev;
+    d2 = sqrt (dx*dx + dy*dy);
+
+    if (d1 < d2) {
+       *x_ret = x1;
+       *y_ret = y1;
+    } else {
+       *x_ret = x2;
+       *y_ret = y2;
+    }
+}
+
 static gboolean
 on_button_press_event (GtkWidget       *widget,
                       GdkEventButton   *event,
@@ -91,8 +148,29 @@ on_button_press_event (GtkWidget    *widget,
     int x, y;
     char *error;
 
-    x = (event->x - layout->x_offset) / layout->cell_size;
-    y = (event->y - layout->y_offset) / layout->cell_size;
+    x = event->x;
+    y = event->y;
+    layout_device_to_board (layout, &x, &y);
+
+    /* Do nothing for out-of-bounds clicks */
+    if (x < 0 || x >= DVONN_BOARD_X_SIZE ||
+       y < 0 || y >= DVONN_BOARD_Y_SIZE)
+    {
+       return TRUE;
+    }
+
+    /* Nor for cells which have array entries that are invalid. */
+    if (game->board.cells[x][y].type == DVONN_CELL_INVALID)
+       return TRUE;
+
+    if (game->board.cells[x][y].type == DVONN_CELL_EMPTY)
+       game->board.cells[x][y].type = DVONN_CELL_WHITE;
+    else if (game->board.cells[x][y].type == DVONN_CELL_WHITE)
+       game->board.cells[x][y].type = DVONN_CELL_EMPTY;
+
+    loa_game_update_windows (game);
+
+    return TRUE;
 
     if (! game->has_selected) {
        if (game->board.cells[x][y].type == game->board.player) {
@@ -104,13 +182,6 @@ on_button_press_event (GtkWidget   *widget,
        return TRUE;
     }
 
-    /* Do nothing for out-of-bounds clicks */
-    if (x < 0 || x >= DVONN_BOARD_X_SIZE ||
-       y < 0 || y >= DVONN_BOARD_Y_SIZE)
-    {
-       return TRUE;
-    }
-
     if (x == game->selected_x &&
        y == game->selected_y)
     {
@@ -199,7 +270,10 @@ on_expose_event_draw (GtkWidget            *widget,
                            x + (y - DVONN_BOARD_Y_SIZE/2) / 2.0,
                            M_SQRT1_2 * y);
            ring_path (cr);
-           cairo_set_source_rgba (cr, 0.0, 0.0, 0.2, 0.1);
+           if (cell.type == DVONN_CELL_WHITE)
+               cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+           else
+               cairo_set_source_rgba (cr, 0.0, 0.0, 0.2, 0.1);
            cairo_fill (cr);
 
            cairo_restore (cr);