]> git.cworth.org Git - loa/blob - loa.c
Fix compilation by putting dependent libraries at the end
[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     /* Do nothing for out-of-bounds clicks */
84     if (x < 0 || x >= LOA_BOARD_SIZE ||
85         y < 0 || y >= LOA_BOARD_SIZE)
86     {
87         return TRUE;
88     }
89
90     if (x == game->selected_x &&
91         y == game->selected_y)
92     {
93         game->has_selected = FALSE;
94         gtk_widget_queue_draw (widget);
95         return TRUE;
96     }
97         
98     if (loa_board_move (&game->board,
99                         game->selected_x, game->selected_y,
100                         x, y, &error))
101     {
102         game->has_selected = FALSE;
103         gtk_widget_queue_draw (widget);
104         return TRUE;
105     } else {
106         printf ("Illegal move %c%d%c%d: %s\n",
107                 'a' + game->selected_x,
108                 LOA_BOARD_SIZE - game->selected_y,
109                 'a' + x,
110                 LOA_BOARD_SIZE - y,
111                 error);
112     }
113
114     return TRUE;
115 }
116
117 static gboolean
118 on_expose_event_draw (GtkWidget         *widget,
119                       GdkEventExpose    *event,
120                       gpointer           user_data)
121 {
122     loa_game_t *game = user_data;
123     layout_t *layout = &game->layout;
124     cairo_t *cr;
125     int x, y;
126
127     if (layout->width != widget->allocation.width ||
128         layout->height != widget->allocation.height)
129     {
130         int size;
131
132         layout->width = widget->allocation.width;
133         layout->height = widget->allocation.height;
134
135         size = MIN (layout->width, layout->height);
136         /* Size must be a multiple of the integer cell_size */
137         layout->cell_size = size / BOARD_SIZE;
138         size = layout->cell_size * BOARD_SIZE;
139
140         layout->x_offset = (layout->width - size) / 2;
141         layout->y_offset = (layout->height - size) / 2;
142     }
143
144     cr = gdk_cairo_create (widget->window);
145
146     cairo_translate (cr, layout->x_offset, layout->y_offset);
147
148     for (y = 0; y < BOARD_SIZE; y++) {
149         for (x = 0; x < BOARD_SIZE; x++) {
150             loa_cell_t cell;
151             cairo_save (cr);
152             cairo_translate(cr, x * layout->cell_size, y * layout->cell_size);
153             if ((x + y) % 2 == 0)
154                 cairo_set_source_rgb (cr, LIGHT_SQUARE_COLOR);
155             else
156                 cairo_set_source_rgb (cr, DARK_SQUARE_COLOR);
157             cairo_rectangle (cr, 0, 0, layout->cell_size, layout->cell_size);
158             cairo_fill (cr);
159             cell = game->board.cells[x][y];
160             if (cell != LOA_CELL_EMPTY) {
161                 cairo_arc (cr,
162                            layout->cell_size / 2.0, layout->cell_size / 2.0,
163                            layout->cell_size / 2.5,
164                            0, 2 * M_PI);
165                 if (cell == LOA_CELL_BLACK)
166                     cairo_set_source_rgb (cr, 0, 0, 0); /* black */
167                 else
168                     cairo_set_source_rgb (cr, 1, 1, 1); /* white */
169                 cairo_fill_preserve (cr);
170                 cairo_set_line_width (cr, 2.0);
171                 if (cell == LOA_CELL_BLACK)
172                     cairo_set_source_rgb (cr, LIGHT_SQUARE_COLOR);
173                 else
174                     cairo_set_source_rgb (cr, DARK_SQUARE_COLOR);
175                 cairo_stroke (cr);
176             }
177             if (game->has_selected &&
178                 x == game->selected_x &&
179                 y == game->selected_y)
180             {
181                 cairo_arc (cr,
182                            layout->cell_size / 2.0, layout->cell_size / 2.0,
183                            layout->cell_size / 2.5,
184                            0, 2 * M_PI);
185                 cairo_set_source_rgba (cr, 0.2, 0.2, 1.0, 0.4);
186                 cairo_fill (cr);
187             }
188             cairo_restore (cr);
189         }
190     }
191
192     cairo_destroy (cr);
193
194     return TRUE;
195 }
196
197 static void
198 loa_game_init (loa_game_t *game)
199 {
200     game->layout.width = 0;
201     game->layout.height = 0;
202
203     game->has_selected = FALSE;
204
205     loa_board_init (&game->board);
206 }
207
208 int
209 main (int argc, char *argv[])
210 {
211     GtkWidget *window;
212     GtkWidget *drawing_area;
213     loa_game_t game;
214
215     loa_game_init (&game);
216
217     gtk_init (&argc, &argv);
218
219     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
220
221     gtk_window_set_default_size (GTK_WINDOW (window), 256, 256);
222
223     g_signal_connect (window, "delete-event",
224                       G_CALLBACK (on_delete_event_quit), NULL);
225
226     drawing_area = gtk_drawing_area_new ();
227
228     gtk_container_add (GTK_CONTAINER (window), drawing_area);
229
230     g_signal_connect (drawing_area, "expose-event",  
231                       G_CALLBACK (on_expose_event_draw), &game);
232
233     gtk_widget_add_events (drawing_area, GDK_BUTTON_PRESS_MASK);
234     g_signal_connect (drawing_area, "button-press-event",
235                       G_CALLBACK (on_button_press_event), &game);
236
237     gtk_widget_show_all (window);
238     
239     gtk_main ();
240
241     return 0;
242 }