]> git.cworth.org Git - loa/blob - loa.c
Make the game playable by clicking
[loa] / loa.c
1 /*
2  * Copyright (C) 2008 Carl Worth
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see http://www.gnu.org/licenses/ .
16  *
17  * Author: Carl Worth <cworth@cworth.org>
18  */
19
20 #include <gtk/gtk.h>
21 #include <math.h>
22
23 #include "loa-board.h"
24
25 #define BOARD_SIZE 8
26
27 typedef struct {
28     int x_offset;
29     int y_offset;
30     int width;
31     int height;
32     int cell_size;
33 } layout_t;
34
35 typedef struct {
36     layout_t layout;
37     loa_board_t board;
38     loa_bool_t has_selected;
39     int selected_x;
40     int selected_y;
41 } loa_game_t;
42
43 static gboolean
44 on_delete_event_quit (GtkWidget  *widget,
45                       GdkEvent   *event,
46                       gpointer    user_data)
47 {
48     gtk_main_quit ();
49
50     /* Returning FALSE allows the default handler for delete-event
51      * to proceed to cleanup the widget. */
52     return FALSE;
53 }
54
55 /* Something like buff */
56 #define LIGHT_SQUARE_COLOR 0.89, 0.70, 0.40
57 /* Something like mahogany */
58 #define DARK_SQUARE_COLOR  0.26, 0.02, 0.01
59
60 static gboolean
61 on_button_press_event (GtkWidget        *widget,
62                        GdkEventButton   *event,
63                        gpointer          user_data)
64 {
65     loa_game_t *game = user_data;
66     layout_t *layout = &game->layout;
67     int x, y;
68     char *error;
69
70     x = (event->x - layout->x_offset) / layout->cell_size;
71     y = (event->y - layout->y_offset) / layout->cell_size;
72
73     if (! game->has_selected) {
74         if (game->board.cells[x][y] == game->board.player) {
75             game->has_selected = TRUE;
76             game->selected_x = x;
77             game->selected_y = y;
78             gtk_widget_queue_draw (widget);
79         }
80         return TRUE;
81     }
82
83     if (x == game->selected_x &&
84         y == game->selected_y)
85     {
86         game->has_selected = FALSE;
87         gtk_widget_queue_draw (widget);
88         return TRUE;
89     }
90         
91     if (loa_board_move (&game->board,
92                         game->selected_x, game->selected_y,
93                         x, y, &error))
94     {
95         game->has_selected = FALSE;
96         gtk_widget_queue_draw (widget);
97         return TRUE;
98     } else {
99         printf ("Illegal move %c%d%c%d: %s\n",
100                 'a' + game->selected_x,
101                 LOA_BOARD_SIZE - game->selected_y,
102                 'a' + x,
103                 LOA_BOARD_SIZE - y,
104                 error);
105     }
106
107     return TRUE;
108 }
109
110 static gboolean
111 on_expose_event_draw (GtkWidget         *widget,
112                       GdkEventExpose    *event,
113                       gpointer           user_data)
114 {
115     loa_game_t *game = user_data;
116     layout_t *layout = &game->layout;
117     cairo_t *cr;
118     int x, y;
119
120     if (layout->width != widget->allocation.width ||
121         layout->height != widget->allocation.height)
122     {
123         int size;
124
125         layout->width = widget->allocation.width;
126         layout->height = widget->allocation.height;
127
128         size = MIN (layout->width, layout->height);
129         /* Size must be a multiple of the integer cell_size */
130         layout->cell_size = size / BOARD_SIZE;
131         size = layout->cell_size * BOARD_SIZE;
132
133         layout->x_offset = (layout->width - size) / 2;
134         layout->y_offset = (layout->height - size) / 2;
135     }
136
137     cr = gdk_cairo_create (widget->window);
138
139     cairo_translate (cr, layout->x_offset, layout->y_offset);
140
141     for (y = 0; y < BOARD_SIZE; y++) {
142         for (x = 0; x < BOARD_SIZE; x++) {
143             loa_cell_t cell;
144             cairo_save (cr);
145             cairo_translate(cr, x * layout->cell_size, y * layout->cell_size);
146             if ((x + y) % 2 == 0)
147                 cairo_set_source_rgb (cr, LIGHT_SQUARE_COLOR);
148             else
149                 cairo_set_source_rgb (cr, DARK_SQUARE_COLOR);
150             cairo_rectangle (cr, 0, 0, layout->cell_size, layout->cell_size);
151             cairo_fill (cr);
152             cell = game->board.cells[x][y];
153             if (cell != LOA_CELL_EMPTY) {
154                 cairo_arc (cr,
155                            layout->cell_size / 2.0, layout->cell_size / 2.0,
156                            layout->cell_size / 2.5,
157                            0, 2 * M_PI);
158                 if (cell == LOA_CELL_BLACK)
159                     cairo_set_source_rgb (cr, 0, 0, 0); /* black */
160                 else
161                     cairo_set_source_rgb (cr, 1, 1, 1); /* white */
162                 cairo_fill_preserve (cr);
163                 cairo_set_line_width (cr, 2.0);
164                 if (cell == LOA_CELL_BLACK)
165                     cairo_set_source_rgb (cr, LIGHT_SQUARE_COLOR);
166                 else
167                     cairo_set_source_rgb (cr, DARK_SQUARE_COLOR);
168                 cairo_stroke (cr);
169             }
170             if (game->has_selected &&
171                 x == game->selected_x &&
172                 y == game->selected_y)
173             {
174                 cairo_arc (cr,
175                            layout->cell_size / 2.0, layout->cell_size / 2.0,
176                            layout->cell_size / 2.5,
177                            0, 2 * M_PI);
178                 cairo_set_source_rgba (cr, 0.2, 0.2, 1.0, 0.4);
179                 cairo_fill (cr);
180             }
181             cairo_restore (cr);
182         }
183     }
184
185     cairo_destroy (cr);
186
187     return TRUE;
188 }
189
190 static void
191 loa_game_init (loa_game_t *game)
192 {
193     game->layout.width = 0;
194     game->layout.height = 0;
195
196     game->has_selected = FALSE;
197
198     loa_board_init (&game->board);
199 }
200
201 int
202 main (int argc, char *argv[])
203 {
204     GtkWidget *window;
205     GtkWidget *drawing_area;
206     loa_game_t game;
207
208     loa_game_init (&game);
209
210     gtk_init (&argc, &argv);
211
212     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
213
214     gtk_window_set_default_size (GTK_WINDOW (window), 256, 256);
215
216     g_signal_connect (window, "delete-event",
217                       G_CALLBACK (on_delete_event_quit), NULL);
218
219     drawing_area = gtk_drawing_area_new ();
220
221     gtk_container_add (GTK_CONTAINER (window), drawing_area);
222
223     g_signal_connect (drawing_area, "expose-event",  
224                       G_CALLBACK (on_expose_event_draw), &game);
225
226     gtk_widget_add_events (drawing_area, GDK_BUTTON_PRESS_MASK);
227     g_signal_connect (drawing_area, "button-press-event",
228                       G_CALLBACK (on_button_press_event), &game);
229
230     gtk_widget_show_all (window);
231     
232     gtk_main ();
233
234     return 0;
235 }