3 #include "constantstrings.h"
4 #include "wordblox_resource.c"
8 GtkListStore
*across_store
;
9 GtkListStore
*down_store
;
11 MainPlayerData app_data
;
13 /* update the clue items store */
14 void update_clue_items ()
16 gtk_list_store_clear (across_store
);
17 gtk_list_store_clear (down_store
);
19 /* if the puzzle is loaded */
20 if (app_data
.is_loaded
== true)
22 /* iterate through the puzzle grid and gte the clues */
23 for (int i
= 0; i
< app_data
.puzzle
.grid_size
; i
++)
25 for (int j
= 0; j
< app_data
.puzzle
.grid_size
; j
++)
27 /* if it is the start of an across word */
28 if (app_data
.puzzle
.start_across_word
[i
][j
] != -1)
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
],
38 /* if it is the start of a down word */
39 if (app_data
.puzzle
.start_down_word
[i
][j
] != -1)
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
],
53 /* slot for handling list down selection changed */
54 gboolean
on_down_list_selection_changed (GtkTreeSelection
*sel
,
60 if (gtk_tree_selection_get_selected (sel
, &mod
, &iter
))
63 gtk_tree_model_get (mod
, &iter
, 0, &sel_word_index
, -1);
64 set_selection_to_word_start (&app_data
, DOWN
, sel_word_index
);
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);
74 /* slot for handling list across selection changed */
75 gboolean
on_across_list_selection_changed (GtkTreeSelection
*sel
,
81 if (gtk_tree_selection_get_selected (sel
, &mod
, &iter
))
84 gtk_tree_model_get (mod
, &iter
, 0, &sel_word_index
, -1);
85 set_selection_to_word_start (&app_data
, ACROSS
, sel_word_index
);
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);
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
)
100 if (event
->type
== GDK_BUTTON_PRESS
&& event
->button
== 1)
102 int col
= (event
->x
- 5) / GRID_PIXELS
;
103 int row
= (event
->y
- 5) / GRID_PIXELS
;
105 if (app_data
.puzzle
.chars
[row
][col
] != '#')
107 if (row
< app_data
.puzzle
.grid_size
&&
108 col
< app_data
.puzzle
.grid_size
)
110 app_data
.cur_row
= row
;
111 app_data
.cur_col
= col
;
113 /* if it is a start of both across and down word, then
114 toggle the movement on clicking it */
115 if (app_data
.puzzle
.start_across_word
[row
][col
] != -1 &&
116 app_data
.puzzle
.start_down_word
[row
][col
] != -1)
118 if (app_data
.current_movement
== ACROSS
)
119 app_data
.current_movement
= DOWN
;
121 app_data
.current_movement
= ACROSS
;
123 /* if it is only start of across word, make the current
125 else if (app_data
.puzzle
.start_across_word
[row
][col
] != -1)
126 app_data
.current_movement
= ACROSS
;
127 /* else down movement */
128 else if (app_data
.puzzle
.start_down_word
[row
][col
] != -1)
129 app_data
.current_movement
= DOWN
;
134 gtk_widget_queue_draw_area (widget
, 0, 0,
135 app_data
.puzzle
.grid_size
*GRID_PIXELS
+10,
136 app_data
.puzzle
.grid_size
*GRID_PIXELS
+10);
141 /* slot for handling key press event for puzzle drawing area */
142 gboolean
on_puzzle_area_key_press_event (GtkWidget
*widget
,
143 GdkEventKey
*event
, gpointer data
)
145 /* respond to key events only if the puzzle is loaded */
146 if (app_data
.is_loaded
== true)
148 switch (event
->keyval
)
150 case GDK_KEY_Down
: move_current_row (&app_data
, DIR_FORWARD
);
151 app_data
.current_movement
= DOWN
;
153 case GDK_KEY_Up
: move_current_row (&app_data
, DIR_BACK
);
154 app_data
.current_movement
= DOWN
;
156 case GDK_KEY_Right
: move_current_col (&app_data
, DIR_FORWARD
);
157 app_data
.current_movement
= ACROSS
;
159 case GDK_KEY_Left
: move_current_col (&app_data
, DIR_BACK
);
160 app_data
.current_movement
= ACROSS
;
162 case GDK_KEY_BackSpace
:
165 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = ' ';
169 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'A';
173 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'B';
177 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'C';
181 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'D';
185 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'E';
189 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'F';
193 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'G';
197 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'H';
201 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'I';
205 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'J';
209 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'K';
213 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'L';
217 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'M';
221 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'N';
225 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'O';
229 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'P';
233 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'Q';
237 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'R';
241 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'S';
245 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'T';
249 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'U';
253 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'V';
257 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'W';
261 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'X';
265 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'Y';
269 app_data
.char_ans
[app_data
.cur_row
][app_data
.cur_col
] = 'Z';
271 default : return FALSE
;
276 /* move the selection pointer to next row/col as per the current
277 movement orientation if it is not a key left right up or down */
278 if (event
->keyval
!= GDK_KEY_Down
&& event
->keyval
!= GDK_KEY_Up
&&
279 event
->keyval
!= GDK_KEY_Left
&& event
->keyval
!= GDK_KEY_Right
280 && event
->keyval
!= GDK_KEY_Delete
)
282 /* if the current movement is an across movement */
283 if (app_data
.current_movement
== ACROSS
)
285 /* if the next column is not blocking move the col */
286 if (event
->keyval
!= GDK_KEY_BackSpace
&&
287 next_col_block (&app_data
.puzzle
, app_data
.cur_row
,
288 app_data
.cur_col
) == false)
289 move_current_col (&app_data
, DIR_FORWARD
);
290 else if (event
->keyval
== GDK_KEY_BackSpace
&&
291 prev_col_block (&app_data
.puzzle
, app_data
.cur_row
,
292 app_data
.cur_col
) == false)
293 move_current_col (&app_data
, DIR_BACK
);
295 /* current movement is a up/down movement */
298 if (event
->keyval
!= GDK_KEY_BackSpace
&&
299 next_row_block (&app_data
.puzzle
,
300 app_data
.cur_row
, app_data
.cur_col
) == false)
301 move_current_row (&app_data
, DIR_FORWARD
);
302 else if (event
->keyval
== GDK_KEY_BackSpace
&&
303 prev_row_block (&app_data
.puzzle
,
304 app_data
.cur_row
, app_data
.cur_col
) == false)
305 move_current_row (&app_data
, DIR_BACK
);
310 gtk_widget_queue_draw_area (widget
, 0, 0,
311 app_data
.puzzle
.grid_size
*GRID_PIXELS
+10,
312 app_data
.puzzle
.grid_size
*GRID_PIXELS
+10);
317 /* slot for drawing the puzzle */
318 gboolean
on_puzzle_area_draw (GtkWidget
*widget
, cairo_t
*cr
, gpointer data
)
320 /* if a puzzle is loaded */
321 if (app_data
.is_loaded
== true)
323 GdkRGBA colorfore
, colorback
, colorblue
, colorbacksel1
, colorbacksel2
;
324 gdk_rgba_parse (&colorfore
, "#000000");
325 gdk_rgba_parse (&colorback
, "#ffffff");
326 gdk_rgba_parse (&colorblue
, "#0000dd");
327 gdk_rgba_parse (&colorbacksel1
, "#ffffaa");
328 gdk_rgba_parse (&colorbacksel2
, "#aaffff");
329 cairo_set_line_width (cr
, 3);
331 /* set the size of the drawing area */
332 gtk_widget_set_size_request (widget
,
333 app_data
.puzzle
.grid_size
*GRID_PIXELS
+10,
334 app_data
.puzzle
.grid_size
*GRID_PIXELS
+10);
337 for (int i
= 0; i
< app_data
.puzzle
.grid_size
; i
++)
339 for (int j
= 0; j
< app_data
.puzzle
.grid_size
; j
++)
341 /* if it is the current selection or if -1 is the current
342 selection then let the current selection be the first word */
343 if (app_data
.cur_col
== -1 && app_data
.cur_row
== -1)
345 if (app_data
.puzzle
.start_across_word
[i
][j
] == 1)
347 app_data
.cur_row
= i
;
348 app_data
.cur_col
= j
;
350 else if (app_data
.puzzle
.start_down_word
[i
][j
] == 1)
352 app_data
.cur_row
= i
;
353 app_data
.cur_col
= j
;
357 gdk_cairo_set_source_rgba (cr
, &colorfore
);
358 cairo_rectangle (cr
, j
*GRID_PIXELS
+5, i
*GRID_PIXELS
+5,
359 GRID_PIXELS
, GRID_PIXELS
);
363 /* if it is not a blank grid then set the background color
365 if (app_data
.puzzle
.chars
[i
][j
] != '#')
366 gdk_cairo_set_source_rgba (cr
, &colorback
);
368 /* if it is a current selection then set the background
370 if (app_data
.cur_row
== i
&& app_data
.cur_col
== j
)
372 if (app_data
.current_movement
== ACROSS
)
373 gdk_cairo_set_source_rgba (cr
, &colorbacksel1
);
375 gdk_cairo_set_source_rgba (cr
, &colorbacksel2
);
378 cairo_rectangle (cr
, j
*GRID_PIXELS
+5, i
*GRID_PIXELS
+5,
379 GRID_PIXELS
, GRID_PIXELS
);
382 /* draw the word number if it is the start of a word */
383 if (app_data
.puzzle
.start_across_word
[i
][j
] != -1 ||
384 app_data
.puzzle
.start_down_word
[i
][j
] != -1)
387 if (app_data
.puzzle
.start_across_word
[i
][j
] != -1)
388 num
= app_data
.puzzle
.start_across_word
[i
][j
];
390 num
= app_data
.puzzle
.start_down_word
[i
][j
];
392 gdk_cairo_set_source_rgba (cr
, &colorblue
);
393 cairo_select_font_face (cr
, "sans serif",
394 CAIRO_FONT_SLANT_NORMAL
,
395 CAIRO_FONT_WEIGHT_NORMAL
);
396 cairo_set_font_size (cr
, 11);
397 cairo_move_to (cr
, j
*GRID_PIXELS
+7, i
*GRID_PIXELS
+15);
399 sprintf (cnum
, "%d", num
);
400 cairo_show_text (cr
, (const char*)cnum
);
403 /* draw the answer if it is there */
404 gdk_cairo_set_source_rgba (cr
, &colorfore
);
405 cairo_select_font_face (cr
, "sans serif",
406 CAIRO_FONT_SLANT_NORMAL
,
407 CAIRO_FONT_WEIGHT_BOLD
);
409 cairo_set_font_size (cr
, 16);
410 cairo_move_to (cr
, j
*GRID_PIXELS
+GRID_PIXELS
/2,
411 i
*GRID_PIXELS
+GRID_PIXELS
-10);
413 sprintf (ctxt
, "%c", app_data
.char_ans
[i
][j
]);
414 cairo_show_text (cr
, (const char*) ctxt
);
424 /* slot for reveal solution menu */
425 void on_menu_reveal_solution_activate (GtkMenuItem
*item
, gpointer
*data
)
430 /* slot for save grid state menu */
431 void on_menu_save_grid_state_activate (GtkMenuItem
*item
, gpointer
*data
)
436 /* slot for exit menu */
437 void on_menu_exit_activate (GtkMenuItem
*item
, gpointer data
)
442 /* slot for open menu */
443 void on_menu_open_activate (GtkMenuItem
*item
, GtkDrawingArea
* area
)
446 GtkFileChooserAction action
= GTK_FILE_CHOOSER_ACTION_OPEN
;
448 dialog
= gtk_file_chooser_dialog_new (OPEN_FILE
, GTK_WINDOW(window
), action
,
454 res
= gtk_dialog_run (GTK_DIALOG (dialog
));
455 if (res
== GTK_RESPONSE_ACCEPT
)
458 filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog
));
460 reset_player_data (&temp
, filename
);
462 /* if the grid is not frozen then the game cannot be played */
463 if (temp
.is_loaded
== false)
465 GtkWidget
*errordlg
;
466 errordlg
= gtk_message_dialog_new (GTK_WINDOW(window
),
467 GTK_DIALOG_DESTROY_WITH_PARENT
,
470 UNFROZEN_GRID_PLAYER
);
471 gtk_dialog_run (GTK_DIALOG(errordlg
));
472 gtk_widget_destroy (errordlg
);
477 gtk_widget_queue_draw_area (GTK_WIDGET (area
), 0, 0,
478 app_data
.puzzle
.grid_size
*30+10,
479 app_data
.puzzle
.grid_size
*30+10);
482 update_clue_items ();
486 gtk_widget_destroy (dialog
);
489 /* slot for about menu */
490 void on_menu_about_activate (GtkMenuItem
*item
, gpointer data
)
492 const char *AUTHOR
[] = {"V.Harishankar", NULL
};
493 gtk_show_about_dialog (GTK_WINDOW(window
), "authors",AUTHOR
,
494 "program-name", PROGRAM_NAME
,
495 "copyright", COPYRIGHT
,
496 "comments", COMMENTS
,
498 "website-label", WEBSITE_LABEL
,
499 "license-type", GTK_LICENSE_GPL_2_0
,
504 int main (int argc
, char *argv
[])
506 gtk_init (&argc
, &argv
);
508 icon
= gdk_pixbuf_new_from_resource
509 ("/org/harishankar/wordblox/wordblox.svg", NULL
);
511 fprintf (stderr
, ERROR_ICON
);
514 builder
= gtk_builder_new ();
515 guint ret
= gtk_builder_add_from_resource (builder
,
516 "/org/harishankar/wordblox/wordblox_player.glade", NULL
);
518 app_data
.is_loaded
= false;
522 fprintf (stderr
, ERROR_WINDOW
);
523 g_object_unref (builder
);
528 window
= GTK_WIDGET (gtk_builder_get_object (builder
, "main_window") );
529 across_store
= GTK_LIST_STORE (gtk_builder_get_object
530 (builder
, "store_across_clues"));
531 down_store
= GTK_LIST_STORE (gtk_builder_get_object
532 (builder
, "store_down_clues"));
536 gtk_window_set_default_icon (icon
);
538 GtkWidget
*draw_area
= GTK_WIDGET (
539 gtk_builder_get_object(builder
, "puzzle_area"));
541 /* make drawing area respond to mouse event */
542 gtk_widget_set_events(draw_area
,
543 gtk_widget_get_events(draw_area
)
544 | GDK_BUTTON_PRESS_MASK
);
546 gtk_builder_connect_signals (builder
, NULL
);
547 g_object_unref (builder
);
548 gtk_widget_show (window
);
554 g_object_unref (builder
);
555 fprintf (stderr
, ERROR_WINDOW
);