From 52fe7cdf6d86687cca4662a937b8e212cba94f6f Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Thu, 5 Mar 2009 00:33:54 -0800 Subject: [PATCH] Add simplistic button-press handling 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 | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 10 deletions(-) diff --git a/dvonn.c b/dvonn.c index 43de664..616ebf3 100644 --- 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); -- 2.43.0