Fixed URL in license
[wordblah.git] / wordblah_player.c
1 #include <gtk/gtk.h>
2
3 #include "constantstrings.h"
4 #include "wordblah_resource.c"
5 #include "wordblah.h"
6
7 GtkWidget *main_window;
8 GtkListStore *across_store;
9 GtkListStore *down_store;
10
11 MainPlayerData app_data;
12
13 /* update the clue items store */
14 void update_clue_items ()
15 {
16 gtk_list_store_clear (across_store);
17 gtk_list_store_clear (down_store);
18
19 /* if the puzzle is loaded */
20 if (app_data.is_loaded == true)
21 {
22 /* iterate through the puzzle grid and gte the clues */
23 for (int i = 0; i < app_data.puzzle.grid_size; i ++)
24 {
25 for (int j = 0; j < app_data.puzzle.grid_size; j ++)
26 {
27 /* if it is the start of an across word */
28 if (app_data.puzzle.start_across_word[i][j] != -1)
29 {
30 GtkTreeIter iter;
31
32 gtk_list_store_append (across_store, &iter);
33 gtk_list_store_set (across_store, &iter, 0,
34 app_data.puzzle.start_across_word[i][j],
35 1, app_data.puzzle.clue_across[i][j],
36 -1);
37 }
38 /* if it is the start of a down word */
39 if (app_data.puzzle.start_down_word[i][j] != -1)
40 {
41 GtkTreeIter iter;
42 gtk_list_store_append (down_store, &iter);
43 gtk_list_store_set (down_store, &iter, 0,
44 app_data.puzzle.start_down_word[i][j],
45 1, app_data.puzzle.clue_down[i][j],
46 -1);
47 }
48 }
49 }
50 }
51 }
52
53 /* slot for handling list down selection changed */
54 gboolean on_down_list_selection_changed (GtkTreeSelection *sel,
55 GtkDrawingArea *area)
56 {
57 GtkTreeIter iter;
58 GtkTreeModel* mod;
59
60 if (gtk_tree_selection_get_selected (sel, &mod, &iter))
61 {
62 guint sel_word_index;
63 gtk_tree_model_get (mod, &iter, 0, &sel_word_index, -1);
64 set_selection_to_word_start (&app_data, DOWN, sel_word_index);
65 }
66
67 gtk_widget_queue_draw_area (GTK_WIDGET(area), 0, 0,
68 app_data.puzzle.grid_size*GRID_PIXELS+10,
69 app_data.puzzle.grid_size*GRID_PIXELS+10);
70
71 return FALSE;
72
73 }
74 /* slot for handling list across selection changed */
75 gboolean on_across_list_selection_changed (GtkTreeSelection *sel,
76 GtkDrawingArea *area)
77 {
78 GtkTreeIter iter;
79 GtkTreeModel* mod;
80
81 if (gtk_tree_selection_get_selected (sel, &mod, &iter))
82 {
83 guint sel_word_index;
84 gtk_tree_model_get (mod, &iter, 0, &sel_word_index, -1);
85 set_selection_to_word_start (&app_data, ACROSS, sel_word_index);
86 }
87
88 gtk_widget_queue_draw_area (GTK_WIDGET(area), 0, 0,
89 app_data.puzzle.grid_size*GRID_PIXELS+10,
90 app_data.puzzle.grid_size*GRID_PIXELS+10);
91
92 return FALSE;
93
94 }
95
96 /* slot for handling mouse button event for puzzle drawing area */
97 gboolean on_puzzle_area_button_press_event (GtkWidget *widget,
98 GdkEventButton *event, gpointer data)
99 {
100 /* if it is solution mode, then don't do anything but reset it to
101 non solution mode */
102 if (app_data.solution_revealed == true)
103 {
104 app_data.solution_revealed = false;
105 gtk_widget_queue_draw_area (widget, 0, 0,
106 app_data.puzzle.grid_size*GRID_PIXELS+10,
107 app_data.puzzle.grid_size*GRID_PIXELS+10);
108 return FALSE;
109 }
110
111 /* Depending on the type of button handle the movement */
112 if (event->type == GDK_BUTTON_PRESS && event->button == 1)
113 {
114 int col = (event->x - 5) / GRID_PIXELS;
115 int row = (event->y - 5) / GRID_PIXELS;
116
117 if (app_data.puzzle.chars[row][col] != '#')
118 {
119 if (row < app_data.puzzle.grid_size &&
120 col < app_data.puzzle.grid_size)
121 {
122 app_data.cur_row = row;
123 app_data.cur_col = col;
124
125 /* if it is a start of both across and down word, then
126 toggle the movement on clicking it */
127 if (app_data.puzzle.start_across_word[row][col] != -1 &&
128 app_data.puzzle.start_down_word[row][col] != -1)
129 {
130 if (app_data.current_movement == ACROSS)
131 app_data.current_movement = DOWN;
132 else
133 app_data.current_movement = ACROSS;
134 }
135 /* if it is only start of across word, make the current
136 movement across */
137 else if (app_data.puzzle.start_across_word[row][col] != -1)
138 app_data.current_movement = ACROSS;
139 /* else down movement */
140 else if (app_data.puzzle.start_down_word[row][col] != -1)
141 app_data.current_movement = DOWN;
142 }
143 }
144 }
145
146 gtk_widget_queue_draw_area (widget, 0, 0,
147 app_data.puzzle.grid_size*GRID_PIXELS+10,
148 app_data.puzzle.grid_size*GRID_PIXELS+10);
149
150 return FALSE;
151 }
152
153 /* slot for handling key press event for puzzle drawing area */
154 gboolean on_puzzle_area_key_press_event (GtkWidget *widget,
155 GdkEventKey *event, gpointer data)
156 {
157 /* respond to key events only if the puzzle is loaded */
158 if (app_data.is_loaded == true)
159 {
160 /* if the solution is revealed, don't respond to key events except
161 to return to the non-solution mode */
162 if (app_data.solution_revealed == true)
163 {
164 app_data.solution_revealed = false;
165 gtk_widget_queue_draw_area (widget, 0, 0,
166 app_data.puzzle.grid_size*GRID_PIXELS+10,
167 app_data.puzzle.grid_size*GRID_PIXELS+10);
168 return FALSE;
169 }
170
171 switch (event->keyval)
172 {
173 case GDK_KEY_Down : move_current_row (&app_data, DIR_FORWARD);
174 app_data.current_movement = DOWN;
175 break;
176 case GDK_KEY_Up : move_current_row (&app_data, DIR_BACK);
177 app_data.current_movement = DOWN;
178 break;
179 case GDK_KEY_Right: move_current_col (&app_data, DIR_FORWARD);
180 app_data.current_movement = ACROSS;
181 break;
182 case GDK_KEY_Left : move_current_col (&app_data, DIR_BACK);
183 app_data.current_movement = ACROSS;
184 break;
185 case GDK_KEY_BackSpace:
186 case GDK_KEY_Delete:
187 case GDK_KEY_space:
188 app_data.char_ans[app_data.cur_row][app_data.cur_col] = ' ';
189 break;
190 case GDK_KEY_a :
191 case GDK_KEY_A :
192 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'A';
193 break;
194 case GDK_KEY_b :
195 case GDK_KEY_B :
196 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'B';
197 break;
198 case GDK_KEY_c :
199 case GDK_KEY_C :
200 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'C';
201 break;
202 case GDK_KEY_d :
203 case GDK_KEY_D :
204 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'D';
205 break;
206 case GDK_KEY_e :
207 case GDK_KEY_E :
208 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'E';
209 break;
210 case GDK_KEY_f :
211 case GDK_KEY_F :
212 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'F';
213 break;
214 case GDK_KEY_g :
215 case GDK_KEY_G :
216 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'G';
217 break;
218 case GDK_KEY_h :
219 case GDK_KEY_H :
220 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'H';
221 break;
222 case GDK_KEY_i :
223 case GDK_KEY_I :
224 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'I';
225 break;
226 case GDK_KEY_j :
227 case GDK_KEY_J :
228 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'J';
229 break;
230 case GDK_KEY_k :
231 case GDK_KEY_K :
232 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'K';
233 break;
234 case GDK_KEY_l :
235 case GDK_KEY_L :
236 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'L';
237 break;
238 case GDK_KEY_m :
239 case GDK_KEY_M :
240 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'M';
241 break;
242 case GDK_KEY_n :
243 case GDK_KEY_N :
244 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'N';
245 break;
246 case GDK_KEY_o :
247 case GDK_KEY_O :
248 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'O';
249 break;
250 case GDK_KEY_p :
251 case GDK_KEY_P :
252 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'P';
253 break;
254 case GDK_KEY_q :
255 case GDK_KEY_Q :
256 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'Q';
257 break;
258 case GDK_KEY_r :
259 case GDK_KEY_R :
260 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'R';
261 break;
262 case GDK_KEY_s :
263 case GDK_KEY_S :
264 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'S';
265 break;
266 case GDK_KEY_t :
267 case GDK_KEY_T :
268 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'T';
269 break;
270 case GDK_KEY_u :
271 case GDK_KEY_U :
272 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'U';
273 break;
274 case GDK_KEY_v :
275 case GDK_KEY_V :
276 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'V';
277 break;
278 case GDK_KEY_w :
279 case GDK_KEY_W :
280 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'W';
281 break;
282 case GDK_KEY_x :
283 case GDK_KEY_X :
284 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'X';
285 break;
286 case GDK_KEY_y :
287 case GDK_KEY_Y :
288 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'Y';
289 break;
290 case GDK_KEY_z :
291 case GDK_KEY_Z :
292 app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'Z';
293 break;
294 default : return FALSE;
295
296 }
297 }
298
299 /* move the selection pointer to next row/col as per the current
300 movement orientation if it is not a key left right up or down */
301 if (event->keyval != GDK_KEY_Down && event->keyval != GDK_KEY_Up &&
302 event->keyval != GDK_KEY_Left && event->keyval != GDK_KEY_Right
303 && event->keyval != GDK_KEY_Delete)
304 {
305 /* if the current movement is an across movement */
306 if (app_data.current_movement == ACROSS)
307 {
308 /* if the next column is not blocking move the col */
309 if (event->keyval != GDK_KEY_BackSpace &&
310 next_col_block (&app_data.puzzle, app_data.cur_row,
311 app_data.cur_col) == false)
312 move_current_col (&app_data, DIR_FORWARD);
313 else if (event->keyval == GDK_KEY_BackSpace &&
314 prev_col_block (&app_data.puzzle, app_data.cur_row,
315 app_data.cur_col) == false)
316 move_current_col (&app_data, DIR_BACK);
317 }
318 /* current movement is a up/down movement */
319 else
320 {
321 if (event->keyval != GDK_KEY_BackSpace &&
322 next_row_block (&app_data.puzzle,
323 app_data.cur_row, app_data.cur_col) == false)
324 move_current_row (&app_data, DIR_FORWARD);
325 else if (event->keyval == GDK_KEY_BackSpace &&
326 prev_row_block (&app_data.puzzle,
327 app_data.cur_row, app_data.cur_col) == false)
328 move_current_row (&app_data, DIR_BACK);
329 }
330 }
331
332
333 gtk_widget_queue_draw_area (widget, 0, 0,
334 app_data.puzzle.grid_size*GRID_PIXELS+10,
335 app_data.puzzle.grid_size*GRID_PIXELS+10);
336
337 return FALSE;
338 }
339
340 /* slot for drawing the puzzle */
341 gboolean on_puzzle_area_draw (GtkWidget *widget, cairo_t *cr, gpointer data)
342 {
343 /* if a puzzle is loaded */
344 if (app_data.is_loaded == true)
345 {
346 GdkRGBA colorfore, colorback, colorblue, colorbacksel1,
347 colorbacksel2, colorsolution;
348 gdk_rgba_parse (&colorfore, "#000000");
349 gdk_rgba_parse (&colorback, "#ffffff");
350 gdk_rgba_parse (&colorblue, "#0000dd");
351 gdk_rgba_parse (&colorbacksel1, "#ffffaa");
352 gdk_rgba_parse (&colorbacksel2, "#aaffff");
353 gdk_rgba_parse (&colorsolution, "#990099");
354 cairo_set_line_width (cr, 3);
355
356 /* set the size of the drawing area */
357 gtk_widget_set_size_request (widget,
358 app_data.puzzle.grid_size*GRID_PIXELS+10,
359 app_data.puzzle.grid_size*GRID_PIXELS+10);
360
361 /* Draw the grid */
362 for (int i = 0; i < app_data.puzzle.grid_size; i ++)
363 {
364 for (int j = 0; j < app_data.puzzle.grid_size; j ++)
365 {
366 /* if it is the current selection or if -1 is the current
367 selection then let the current selection be the first word */
368 if (app_data.cur_col == -1 && app_data.cur_row == -1)
369 {
370 if (app_data.puzzle.start_across_word[i][j] == 1)
371 {
372 app_data.cur_row = i;
373 app_data.cur_col = j;
374 app_data.current_movement = ACROSS;
375 }
376 else if (app_data.puzzle.start_down_word[i][j] == 1)
377 {
378 app_data.cur_row = i;
379 app_data.cur_col = j;
380 app_data.current_movement = DOWN;
381 }
382 }
383
384 gdk_cairo_set_source_rgba (cr, &colorfore);
385 cairo_rectangle (cr, j*GRID_PIXELS+5, i*GRID_PIXELS+5,
386 GRID_PIXELS, GRID_PIXELS);
387
388 cairo_stroke (cr);
389
390 /* if it is not a blank grid then set the background color
391 to black */
392 if (app_data.puzzle.chars[i][j] != '#')
393 gdk_cairo_set_source_rgba (cr, &colorback);
394
395 /* if it is a current selection and solution reveal mode is not
396 set then then set the background depending on whether across
397 or down movement mode is current */
398 if (app_data.solution_revealed == false &&
399 app_data.cur_row == i && app_data.cur_col == j)
400 {
401 if (app_data.current_movement == ACROSS)
402 gdk_cairo_set_source_rgba (cr, &colorbacksel1);
403 else
404 gdk_cairo_set_source_rgba (cr, &colorbacksel2);
405 }
406
407 cairo_rectangle (cr, j*GRID_PIXELS+5, i*GRID_PIXELS+5,
408 GRID_PIXELS, GRID_PIXELS);
409 cairo_fill (cr);
410
411 /* draw the word number if it is the start of a word */
412 if (app_data.puzzle.start_across_word[i][j] != -1 ||
413 app_data.puzzle.start_down_word[i][j] != -1)
414 {
415 int num;
416 if (app_data.puzzle.start_across_word[i][j] != -1)
417 num = app_data.puzzle.start_across_word[i][j];
418 else
419 num = app_data.puzzle.start_down_word[i][j];
420
421 gdk_cairo_set_source_rgba (cr, &colorblue);
422 cairo_select_font_face (cr, "sans serif",
423 CAIRO_FONT_SLANT_NORMAL,
424 CAIRO_FONT_WEIGHT_NORMAL);
425 cairo_set_font_size (cr, 11);
426 cairo_move_to (cr, j*GRID_PIXELS+7, i*GRID_PIXELS+15);
427 char cnum[3];
428 sprintf (cnum, "%d", num);
429 cairo_show_text (cr, (const char*)cnum);
430 }
431
432 /* if solution is not revealed set the color to normal
433 or set it to solution color */
434 if (app_data.solution_revealed == false)
435 gdk_cairo_set_source_rgba (cr, &colorfore);
436 else
437 gdk_cairo_set_source_rgba (cr, &colorsolution);
438
439 cairo_select_font_face (cr, "sans serif",
440 CAIRO_FONT_SLANT_NORMAL,
441 CAIRO_FONT_WEIGHT_BOLD);
442
443 cairo_set_font_size (cr, 16);
444 cairo_move_to (cr, j*GRID_PIXELS+GRID_PIXELS/2,
445 i*GRID_PIXELS+GRID_PIXELS-10);
446 char ctxt[3];
447 /* if it is solution mode reveal the answer or else the
448 user input */
449 if (app_data.solution_revealed == false)
450 sprintf (ctxt, "%c", app_data.char_ans[i][j]);
451 else
452 if (app_data.puzzle.chars[i][j] != '#')
453 sprintf (ctxt, "%c", app_data.puzzle.chars[i][j]);
454 else
455 sprintf (ctxt, "%c", ' ');
456 cairo_show_text (cr, (const char*) ctxt);
457
458 }
459 }
460 }
461
462 return FALSE;
463
464 }
465
466 /* slot for reveal solution menu */
467 void on_menu_reveal_solution_activate (GtkMenuItem *item, GtkDrawingArea *area)
468 {
469 /* if puzzle solution is password protected ask for the password */
470 if (strlen (app_data.puzzle.hashed_solution_password) > 0)
471 {
472 GtkBuilder *builder;
473 builder = gtk_builder_new ();
474
475 guint ret = gtk_builder_add_from_resource
476 (builder,
477 "/org/harishankar/wordblah/wordblah_player.glade",
478 NULL);
479 if (ret == 0)
480 {
481 fprintf (stderr, ERROR_WINDOW);
482 g_object_unref (builder);
483 return;
484 }
485
486 GtkWidget *password_dialog = GTK_WIDGET (gtk_builder_get_object
487 (builder, "password_dialog"));
488 GtkWidget *password_text = GTK_WIDGET (gtk_builder_get_object
489 (builder, "password_text"));
490
491 if (password_dialog == NULL)
492 {
493 fprintf (stderr, ERROR_WINDOW);
494 g_object_unref (builder);
495 return;
496 }
497 gtk_window_set_transient_for (GTK_WINDOW(password_dialog),
498 GTK_WINDOW(main_window));
499 gtk_dialog_set_default_response (GTK_DIALOG(password_dialog),
500 GTK_RESPONSE_ACCEPT);
501 gint res = gtk_dialog_run (GTK_DIALOG (password_dialog));
502 if (res == GTK_RESPONSE_ACCEPT)
503 {
504 const gchar *user_pwd = gtk_entry_get_text
505 (GTK_ENTRY(password_text));
506 /* if password is correct */
507 if (verify_solution_password (&app_data.puzzle, user_pwd) == true)
508 app_data.solution_revealed = true;
509 /* password is incorrect */
510 else
511 {
512 app_data.solution_revealed = false;
513 GtkWidget *errordlg ;
514 errordlg = gtk_message_dialog_new (GTK_WINDOW(main_window),
515 GTK_DIALOG_DESTROY_WITH_PARENT,
516 GTK_MESSAGE_ERROR,
517 GTK_BUTTONS_CLOSE,
518 WRONG_PASSWORD);
519 gtk_dialog_run (GTK_DIALOG(errordlg));
520 gtk_widget_destroy (errordlg);
521 }
522 }
523
524 gtk_widget_destroy (password_text);
525 gtk_widget_destroy (password_dialog);
526 g_object_unref (builder);
527 }
528 else
529 app_data.solution_revealed = true;
530
531 gtk_widget_queue_draw_area (GTK_WIDGET(area), 0, 0,
532 app_data.puzzle.grid_size*GRID_PIXELS+10,
533 app_data.puzzle.grid_size*GRID_PIXELS+10);
534
535 }
536
537 /* slot for load grid state menu */
538 void on_menu_load_grid_state_activate (GtkMenuItem *item, GtkDrawingArea *area)
539 {
540 GtkWidget *dialog;
541 GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
542 gint res;
543 dialog = gtk_file_chooser_dialog_new (OPEN_FILE, GTK_WINDOW (main_window),
544 action,
545 "_Cancel",
546 GTK_RESPONSE_CANCEL,
547 "_Open",
548 GTK_RESPONSE_ACCEPT,
549 NULL
550 );
551
552 res = gtk_dialog_run (GTK_DIALOG (dialog));
553 if (res == GTK_RESPONSE_ACCEPT)
554 {
555 char *filename;
556 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
557 MainPlayerData temp;
558 load_user_data (&temp, filename);
559 /* if the puzzle file is invalid or the grid is frozen */
560 if (temp.puzzle.grid_size == 0 ||
561 temp.puzzle.grid_frozen == false)
562 {
563 GtkWidget *errordlg;
564 char message[256];
565 if (temp.puzzle.grid_size == 0)
566 strcpy (message, INVALID_PUZZLE);
567 else
568 strcpy (message, UNFROZEN_GRID_PLAYER);
569
570 errordlg = gtk_message_dialog_new (GTK_WINDOW(main_window),
571 GTK_DIALOG_DESTROY_WITH_PARENT,
572 GTK_MESSAGE_ERROR,
573 GTK_BUTTONS_CLOSE,
574 "%s",message);
575 gtk_dialog_run (GTK_DIALOG(errordlg));
576 gtk_widget_destroy (errordlg);
577
578 }
579 else
580 app_data = temp;
581 g_free (filename);
582 }
583
584 gtk_widget_destroy (dialog);
585
586 gtk_widget_queue_draw_area (GTK_WIDGET(area), 0, 0,
587 app_data.puzzle.grid_size*GRID_PIXELS+10,
588 app_data.puzzle.grid_size*GRID_PIXELS+10);
589
590 update_clue_items ();
591 }
592
593 /* slot for save grid state menu */
594 void on_menu_save_grid_state_activate (GtkMenuItem *item, gpointer *data)
595 {
596 if (app_data.is_loaded == false)
597 return;
598
599 GtkWidget *dialog;
600 GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
601 gint res;
602 dialog = gtk_file_chooser_dialog_new (SAVE_FILE, GTK_WINDOW(main_window),
603 action,
604 "_Cancel",
605 GTK_RESPONSE_CANCEL,
606 "_Save",
607 GTK_RESPONSE_ACCEPT,
608 NULL);
609 res = gtk_dialog_run (GTK_DIALOG (dialog));
610 if (res == GTK_RESPONSE_ACCEPT)
611 {
612 char *filename;
613 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
614 save_user_data (&app_data, filename);
615 g_free (filename);
616 }
617
618 gtk_widget_destroy (dialog);
619 }
620
621 /* slot for exit menu */
622 void on_menu_exit_activate (GtkMenuItem *item, gpointer data)
623 {
624 gtk_main_quit ();
625 }
626
627 /* slot for open menu */
628 void on_menu_open_activate (GtkMenuItem *item, GtkDrawingArea* area)
629 {
630 GtkWidget *dialog;
631 GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
632 gint res;
633 dialog = gtk_file_chooser_dialog_new (OPEN_FILE, GTK_WINDOW(main_window),
634 action,
635 "_Cancel",
636 GTK_RESPONSE_CANCEL,
637 "_Open",
638 GTK_RESPONSE_ACCEPT,
639 NULL);
640 res = gtk_dialog_run (GTK_DIALOG (dialog));
641 if (res == GTK_RESPONSE_ACCEPT)
642 {
643 char *filename;
644 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog));
645 MainPlayerData temp;
646 reset_player_data (&temp, filename);
647
648 /* if the puzzle is either an invalid puzzle file or grid is not frozen
649 then the game cannot be played */
650 if (temp.puzzle.grid_size == 0 || temp.is_loaded == false)
651 {
652 GtkWidget *errordlg ;
653 char message[256];
654 if (temp.puzzle.grid_size == 0)
655 strcpy (message, INVALID_PUZZLE);
656 else
657 strcpy (message, UNFROZEN_GRID_PLAYER);
658
659 errordlg = gtk_message_dialog_new (GTK_WINDOW(main_window),
660 GTK_DIALOG_DESTROY_WITH_PARENT,
661 GTK_MESSAGE_ERROR,
662 GTK_BUTTONS_CLOSE,
663 "%s",message);
664 gtk_dialog_run (GTK_DIALOG(errordlg));
665 gtk_widget_destroy (errordlg);
666 }
667 else
668 {
669 app_data = temp;
670 gtk_widget_queue_draw_area (GTK_WIDGET (area), 0, 0,
671 app_data.puzzle.grid_size*30+10,
672 app_data.puzzle.grid_size*30+10);
673
674 }
675 update_clue_items ();
676 g_free (filename);
677 }
678
679 gtk_widget_destroy (dialog);
680 }
681
682 /* slot for about menu */
683 void on_menu_about_activate (GtkMenuItem *item, gpointer data)
684 {
685 const char *AUTHOR[] = {"V.Harishankar", NULL};
686 gtk_show_about_dialog (GTK_WINDOW(main_window), "authors",AUTHOR,
687 "program-name", PROGRAM_NAME,
688 "copyright", COPYRIGHT,
689 "comments", COMMENTS,
690 "website", WEBSITE,
691 "website-label", WEBSITE_LABEL,
692 "license-type", GTK_LICENSE_CUSTOM,
693 "license", LICENSE_BSD,
694 "version", VERSION,
695 (char*)NULL);
696 }
697
698 int main (int argc, char *argv [])
699 {
700 gtk_init (&argc, &argv);
701 GdkPixbuf *icon;
702 icon = gdk_pixbuf_new_from_resource
703 ("/org/harishankar/wordblah/wordblah.svg", NULL);
704 if (icon == NULL)
705 fprintf (stderr, ERROR_ICON);
706
707 GtkBuilder *builder;
708 builder = gtk_builder_new ();
709 guint ret = gtk_builder_add_from_resource (builder,
710 "/org/harishankar/wordblah/wordblah_player.glade", NULL);
711
712 app_data.is_loaded = false;
713
714 if (ret == 0)
715 {
716 fprintf (stderr, ERROR_WINDOW);
717 g_object_unref (builder);
718 return 1;
719 }
720 else
721 {
722 main_window = GTK_WIDGET (gtk_builder_get_object (builder,
723 "main_window"));
724
725 across_store = GTK_LIST_STORE (gtk_builder_get_object
726 (builder, "store_across_clues"));
727 down_store = GTK_LIST_STORE (gtk_builder_get_object
728 (builder, "store_down_clues"));
729
730 if (main_window != NULL)
731 {
732 gtk_window_set_default_icon (icon);
733
734 GtkWidget *draw_area = GTK_WIDGET (
735 gtk_builder_get_object(builder, "puzzle_area"));
736
737 /* make drawing area respond to mouse event */
738 gtk_widget_set_events(draw_area,
739 gtk_widget_get_events(draw_area)
740 | GDK_BUTTON_PRESS_MASK);
741
742 gtk_builder_connect_signals (builder, NULL);
743 g_object_unref (builder);
744 gtk_widget_show (main_window);
745 gtk_main ();
746 return 0;
747 }
748 else
749 {
750 g_object_unref (builder);
751 fprintf (stderr, ERROR_WINDOW);
752 return 1;
753 }
754 }
755 }