Work on puzzle grid in player
[wordblah.git] / wordblox_player.c
1 #include <gtk/gtk.h>
2
3 #include "constantstrings.h"
4 #include "wordblox_resource.c"
5 #include "wordblox.h"
6
7 GtkWidget *window;
8 GtkListStore *across_store;
9 GtkListStore *down_store;
10
11 struct MainAppData {
12 Puzzle puzzle;
13 char filename[65535];
14 bool is_loaded;
15 int cur_row;
16 int cur_col;
17 } app_data;
18
19 /* update the clue items */
20 void update_clue_items ()
21 {
22 gtk_list_store_clear (across_store);
23 gtk_list_store_clear (down_store);
24
25 /* if the puzzle is loaded */
26 if (app_data.is_loaded == true)
27 {
28 /* iterate through the puzzle grid and gte the clues */
29 for (int i = 0; i < app_data.puzzle.grid_size; i ++)
30 {
31 for (int j = 0; j < app_data.puzzle.grid_size; j ++)
32 {
33 /* if it is the start of an across word */
34 if (app_data.puzzle.start_across_word[i][j] != -1)
35 {
36 GtkTreeIter iter;
37
38 gtk_list_store_append (across_store, &iter);
39 gtk_list_store_set (across_store, &iter, 0,
40 app_data.puzzle.start_across_word[i][j],
41 1, app_data.puzzle.clue_across[i][j],
42 -1);
43 }
44 /* if it is the start of a down word */
45 if (app_data.puzzle.start_down_word[i][j] != -1)
46 {
47 GtkTreeIter iter;
48 gtk_list_store_append (down_store, &iter);
49 gtk_list_store_set (down_store, &iter, 0,
50 app_data.puzzle.start_down_word[i][j],
51 1, app_data.puzzle.clue_down[i][j],
52 -1);
53 }
54 }
55 }
56 }
57 }
58
59 /* move the current selection index left or right */
60 void move_current_col (enum DIRECTION dir)
61 {
62 int r = app_data.cur_row;
63 int c = app_data.cur_col;
64 if (dir == DIR_FORWARD)
65 {
66 c ++;
67 while (c < app_data.puzzle.grid_size)
68 {
69 if (app_data.puzzle.chars[r][c] == '#')
70 c ++;
71 else
72 break;
73 }
74 if (c < app_data.puzzle.grid_size)
75 app_data.cur_col = c;
76 }
77 else
78 {
79 c --;
80 while (c >= 0)
81 {
82 if (app_data.puzzle.chars[r][c] == '#')
83 c --;
84 else
85 break;
86 }
87 if (c >= 0)
88 app_data.cur_col = c;
89 }
90 }
91
92 /* move the current selection index up or down */
93 void move_current_row (enum DIRECTION dir)
94 {
95 int r = app_data.cur_row;
96 int c = app_data.cur_col;
97 if (dir == DIR_FORWARD)
98 {
99 r ++;
100 while (r < app_data.puzzle.grid_size)
101 {
102 if (app_data.puzzle.chars[r][c] == '#')
103 r ++;
104 else
105 break;
106 }
107 if (r < app_data.puzzle.grid_size)
108 app_data.cur_row = r;
109 }
110 else
111 {
112 r --;
113 while (r >= 0)
114 {
115 if (app_data.puzzle.chars[r][c] == '#')
116 r --;
117 else
118 break;
119 }
120 if (r >= 0)
121 app_data.cur_row = r;
122 }
123 }
124
125
126 /* slot for handling key press event for puzzle drawing area */
127 gboolean on_puzzle_area_key_press_event (GtkWidget *widget,
128 GdkEventKey *event, gpointer data)
129 {
130 /* respond to key events only if the puzzle is loaded */
131 if (app_data.is_loaded == true)
132 {
133 switch (event->keyval)
134 {
135 case GDK_KEY_Down : move_current_row (DIR_FORWARD);
136 gtk_widget_queue_draw_area (widget,
137 0, 0,
138 app_data.puzzle.grid_size*GRID_PIXELS+10,
139 app_data.puzzle.grid_size*GRID_PIXELS+10);
140 break;
141 case GDK_KEY_Up : move_current_row (DIR_BACK);
142 gtk_widget_queue_draw_area (widget,
143 0, 0,
144 app_data.puzzle.grid_size*GRID_PIXELS+10,
145 app_data.puzzle.grid_size*GRID_PIXELS+10);
146 break;
147 case GDK_KEY_Right: move_current_col (DIR_FORWARD);
148 gtk_widget_queue_draw_area (widget,
149 0, 0,
150 app_data.puzzle.grid_size*GRID_PIXELS+10,
151 app_data.puzzle.grid_size*GRID_PIXELS+10);
152 break;
153 case GDK_KEY_Left : move_current_col (DIR_BACK);
154 gtk_widget_queue_draw_area (widget,
155 0, 0,
156 app_data.puzzle.grid_size*GRID_PIXELS+10,
157 app_data.puzzle.grid_size*GRID_PIXELS+10);
158 }
159 }
160
161 return FALSE;
162 }
163
164 /* slot for drawing the puzzle */
165 gboolean on_puzzle_area_draw (GtkWidget *widget, cairo_t *cr, gpointer data)
166 {
167 /* if a puzzle is loaded */
168 if (app_data.is_loaded == true)
169 {
170 GdkRGBA colorfore, colorback, colorblue, colorbacksel;
171 gdk_rgba_parse (&colorfore, "#000000");
172 gdk_rgba_parse (&colorback, "#ffffff");
173 gdk_rgba_parse (&colorblue, "#0000dd");
174 gdk_rgba_parse (&colorbacksel, "#ffffaa");
175 cairo_set_line_width (cr, 3);
176
177 /* set the size of the drawing area */
178 gtk_widget_set_size_request (widget,
179 app_data.puzzle.grid_size*GRID_PIXELS+10,
180 app_data.puzzle.grid_size*GRID_PIXELS+10);
181
182 /* Draw the grid */
183 for (int i = 0; i < app_data.puzzle.grid_size; i ++)
184 {
185 for (int j = 0; j < app_data.puzzle.grid_size; j ++)
186 {
187 /* if it is the current selection or if -1 is the current
188 selection then let the current selection be the first word */
189 if (app_data.cur_col == -1 && app_data.cur_row == -1)
190 {
191 if (app_data.puzzle.start_across_word[i][j] == 1)
192 {
193 app_data.cur_row = i;
194 app_data.cur_col = j;
195 }
196 else if (app_data.puzzle.start_down_word[i][j] == 1)
197 {
198 app_data.cur_row = i;
199 app_data.cur_col = j;
200 }
201 }
202
203 gdk_cairo_set_source_rgba (cr, &colorfore);
204 cairo_rectangle (cr, j*GRID_PIXELS+5, i*GRID_PIXELS+5,
205 GRID_PIXELS, GRID_PIXELS);
206
207 cairo_stroke (cr);
208
209 /* if it is not a blank grid then set the background color
210 to black */
211 if (app_data.puzzle.chars[i][j] != '#')
212 gdk_cairo_set_source_rgba (cr, &colorback);
213
214 /* if it is a current selection then set the background
215 to yellow */
216 if (app_data.cur_row == i && app_data.cur_col == j)
217 gdk_cairo_set_source_rgba (cr, &colorbacksel);
218
219 cairo_rectangle (cr, j*GRID_PIXELS+5, i*GRID_PIXELS+5,
220 GRID_PIXELS, GRID_PIXELS);
221 cairo_fill (cr);
222
223 /* draw the word number if it is the start of a word */
224 if (app_data.puzzle.start_across_word[i][j] != -1 ||
225 app_data.puzzle.start_down_word[i][j] != -1)
226 {
227 int num;
228 if (app_data.puzzle.start_across_word[i][j] != -1)
229 num = app_data.puzzle.start_across_word[i][j];
230 else
231 num = app_data.puzzle.start_down_word[i][j];
232
233 gdk_cairo_set_source_rgba (cr, &colorblue);
234 cairo_select_font_face (cr, "sans serif",
235 CAIRO_FONT_SLANT_NORMAL,
236 CAIRO_FONT_WEIGHT_NORMAL);
237 cairo_set_font_size (cr, 11);
238 cairo_move_to (cr, j*GRID_PIXELS+7, i*GRID_PIXELS+15);
239 char cnum[3];
240 sprintf (cnum, "%d", num);
241 cairo_show_text (cr, (const char*)cnum);
242 }
243
244
245 }
246 }
247 }
248
249 return FALSE;
250
251 }
252
253 /* slot for reveal solution menu */
254 void on_menu_reveal_solution_activate (GtkMenuItem *item, gpointer *data)
255 {
256 /* TODO */
257 }
258
259 /* slot for save grid state menu */
260 void on_menu_save_grid_state_activate (GtkMenuItem *item, gpointer *data)
261 {
262 /* TODO */
263 }
264
265 /* slot for exit menu */
266 void on_menu_exit_activate (GtkMenuItem *item, gpointer data)
267 {
268 gtk_main_quit ();
269 }
270
271 /* slot for open menu */
272 void on_menu_open_activate (GtkMenuItem *item, GtkDrawingArea* area)
273 {
274 GtkWidget *dialog;
275 GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
276 gint res;
277 dialog = gtk_file_chooser_dialog_new (OPEN_FILE, GTK_WINDOW(window), action,
278 "_Cancel",
279 GTK_RESPONSE_CANCEL,
280 "_Open",
281 GTK_RESPONSE_ACCEPT,
282 NULL);
283 res = gtk_dialog_run (GTK_DIALOG (dialog));
284 if (res == GTK_RESPONSE_ACCEPT)
285 {
286 char *filename;
287 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog));
288 app_data.puzzle = load_puzzle (filename);
289 app_data.is_loaded = true;
290 strcpy (app_data.filename, filename);
291 /* if the grid is not frozen then the game cannot be played */
292 if (app_data.puzzle.grid_frozen == false)
293 {
294 GtkWidget *errordlg ;
295 errordlg = gtk_message_dialog_new (GTK_WINDOW(window),
296 GTK_DIALOG_DESTROY_WITH_PARENT,
297 GTK_MESSAGE_ERROR,
298 GTK_BUTTONS_CLOSE,
299 UNFROZEN_GRID_PLAYER);
300 gtk_dialog_run (GTK_DIALOG(errordlg));
301 gtk_widget_destroy (errordlg);
302 app_data.is_loaded = false;
303 app_data.cur_col = -1;
304 app_data.cur_row = -1;
305 }
306 else
307 {
308 gtk_widget_queue_draw_area (GTK_WIDGET (area), 0, 0,
309 app_data.puzzle.grid_size*30+10,
310 app_data.puzzle.grid_size*30+10);
311 update_clue_items ();
312 }
313 g_free (filename);
314 }
315
316 gtk_widget_destroy (dialog);
317 }
318
319 /* slot for about menu */
320 void on_menu_about_activate (GtkMenuItem *item, gpointer data)
321 {
322 const char *AUTHOR[] = {"V.Harishankar", NULL};
323 gtk_show_about_dialog (GTK_WINDOW(window), "authors",AUTHOR,
324 "program-name", PROGRAM_NAME,
325 "copyright", COPYRIGHT,
326 "comments", COMMENTS,
327 "website", WEBSITE,
328 "website-label", WEBSITE_LABEL,
329 "license-type", GTK_LICENSE_GPL_2_0,
330 "version", VERSION,
331 (char*)NULL);
332 }
333
334 int main (int argc, char *argv [])
335 {
336 gtk_init (&argc, &argv);
337 GdkPixbuf *icon;
338 icon = gdk_pixbuf_new_from_resource
339 ("/org/harishankar/wordblox/wordblox.svg", NULL);
340 if (icon == NULL)
341 fprintf (stderr, ERROR_ICON);
342
343 GtkBuilder *builder;
344 builder = gtk_builder_new ();
345 guint ret = gtk_builder_add_from_resource (builder,
346 "/org/harishankar/wordblox/wordblox_player.glade", NULL);
347
348 app_data.is_loaded = false;
349
350 if (ret == 0)
351 {
352 fprintf (stderr, ERROR_WINDOW);
353 g_object_unref (builder);
354 return 1;
355 }
356 else
357 {
358 window = GTK_WIDGET (gtk_builder_get_object (builder, "main_window") );
359 across_store = GTK_LIST_STORE (gtk_builder_get_object
360 (builder, "store_across_clues"));
361 down_store = GTK_LIST_STORE (gtk_builder_get_object
362 (builder, "store_down_clues"));
363
364 if (window != NULL)
365 {
366 gtk_window_set_default_icon (icon);
367
368 gtk_builder_connect_signals (builder, NULL);
369 g_object_unref (builder);
370 gtk_widget_show (window);
371 gtk_main ();
372 return 0;
373 }
374 else
375 {
376 g_object_unref (builder);
377 fprintf (stderr, ERROR_WINDOW);
378 return 1;
379 }
380 }
381 }