From d27505add68f9df169f2135a416bdf52ce9af8c3 Mon Sep 17 00:00:00 2001 From: Harishankar Date: Mon, 4 May 2020 14:53:30 +0530 Subject: [PATCH] Work on puzzle grid in player The puzzle grid in the player now responds to user input for moving currently selected row/col for up, down, left and right keys --- wordblox.c | 2 + wordblox.h | 35 ++++--- wordblox_player.c | 239 ++++++++++++++++++++++++++++++++++++++++-- wordblox_player.glade | 75 +++++++++++-- 4 files changed, 320 insertions(+), 31 deletions(-) diff --git a/wordblox.c b/wordblox.c index 8ab9891..0cbb804 100644 --- a/wordblox.c +++ b/wordblox.c @@ -107,6 +107,8 @@ void do_set_clue_word (Puzzle *p, enum ORIENTATION orient) index = get_num (); printf (INPUT_CLUE); fgets (clue, MAX_CLUE_LENGTH, stdin); + if (strlen (clue) == 1) + return; char* cl = strtok (clue, "\n"); bool res; diff --git a/wordblox.h b/wordblox.h index 9a5c27c..8886fab 100644 --- a/wordblox.h +++ b/wordblox.h @@ -11,8 +11,9 @@ #include #include "constantstrings.h" -#define MAX_PUZZLE_SIZE 20 +#define MAX_PUZZLE_SIZE 25 #define MAX_CLUE_LENGTH 150 +#define GRID_PIXELS 37 /* Enum to define terminal colours */ enum COLOR { @@ -36,6 +37,12 @@ enum ORIENTATION { DOWN=2 }; +/* for use with the player */ +enum DIRECTION { + DIR_FORWARD = 1, + DIR_BACK = -1 +}; + typedef char String[MAX_CLUE_LENGTH]; /* The main puzzle struct type */ @@ -133,7 +140,7 @@ void export_clues (Puzzle *p, const char *filename) /* Output the grid to image - if answerkey is true export filled grid */ void export_grid_image (Puzzle *p, const char *filename, bool answerkey) { - int img_size = p->grid_size * 40; + int img_size = p->grid_size * GRID_PIXELS; FILE * outfile = fopen (filename, "wb"); if (outfile == NULL) { @@ -154,13 +161,15 @@ void export_grid_image (Puzzle *p, const char *filename, bool answerkey) { /* if it is a block, draw the black square */ if (p->chars[i][j] == '#') - gdImageFilledRectangle (img, j*40, i*40, j*40+40, - i*40+40,black); + gdImageFilledRectangle (img, j*GRID_PIXELS, i*GRID_PIXELS, + j*GRID_PIXELS+GRID_PIXELS, + i*GRID_PIXELS+GRID_PIXELS,black); else { /* draw a regular square */ - gdImageRectangle (img, j*40, i*40, j*40+40, - i*40+40, black); + gdImageRectangle (img, j*GRID_PIXELS, i*GRID_PIXELS, + j*GRID_PIXELS+GRID_PIXELS, + i*GRID_PIXELS+GRID_PIXELS, black); /* print the numers, if it is either start across word or a down word */ @@ -171,22 +180,24 @@ void export_grid_image (Puzzle *p, const char *filename, bool answerkey) { char str[5]; sprintf (str, "%d", p->start_across_word[i][j]); - gdImageString (img, sm_fnt, j*40+2, i*40+2, - (unsigned char *)str, blue); + gdImageString (img, sm_fnt, j*GRID_PIXELS+2, + i*GRID_PIXELS+2, + (unsigned char *)str, blue); } else { char str[5]; sprintf (str, "%d", p->start_down_word[i][j]); - gdImageString (img, sm_fnt, j*40+2, i*40+2, - (unsigned char *)str, blue); + gdImageString (img, sm_fnt, j*GRID_PIXELS+2, + i*GRID_PIXELS+2, + (unsigned char *)str, blue); } } /* if answerkey is true, draw the character in the cell */ if (answerkey) { - gdImageChar (img, lg_fnt, j*40+15, i*40+15, - p->chars[i][j], black); + gdImageChar (img, lg_fnt, j*GRID_PIXELS+15, + i*GRID_PIXELS+10, p->chars[i][j], black); } } } diff --git a/wordblox_player.c b/wordblox_player.c index 2904929..a3105d6 100644 --- a/wordblox_player.c +++ b/wordblox_player.c @@ -5,35 +5,205 @@ #include "wordblox.h" GtkWidget *window; +GtkListStore *across_store; +GtkListStore *down_store; struct MainAppData { Puzzle puzzle; char filename[65535]; bool is_loaded; + int cur_row; + int cur_col; } app_data; +/* update the clue items */ +void update_clue_items () +{ + gtk_list_store_clear (across_store); + gtk_list_store_clear (down_store); + + /* if the puzzle is loaded */ + if (app_data.is_loaded == true) + { + /* iterate through the puzzle grid and gte the clues */ + for (int i = 0; i < app_data.puzzle.grid_size; i ++) + { + for (int j = 0; j < app_data.puzzle.grid_size; j ++) + { + /* if it is the start of an across word */ + if (app_data.puzzle.start_across_word[i][j] != -1) + { + GtkTreeIter iter; + + gtk_list_store_append (across_store, &iter); + gtk_list_store_set (across_store, &iter, 0, + app_data.puzzle.start_across_word[i][j], + 1, app_data.puzzle.clue_across[i][j], + -1); + } + /* if it is the start of a down word */ + if (app_data.puzzle.start_down_word[i][j] != -1) + { + GtkTreeIter iter; + gtk_list_store_append (down_store, &iter); + gtk_list_store_set (down_store, &iter, 0, + app_data.puzzle.start_down_word[i][j], + 1, app_data.puzzle.clue_down[i][j], + -1); + } + } + } + } +} + +/* move the current selection index left or right */ +void move_current_col (enum DIRECTION dir) +{ + int r = app_data.cur_row; + int c = app_data.cur_col; + if (dir == DIR_FORWARD) + { + c ++; + while (c < app_data.puzzle.grid_size) + { + if (app_data.puzzle.chars[r][c] == '#') + c ++; + else + break; + } + if (c < app_data.puzzle.grid_size) + app_data.cur_col = c; + } + else + { + c --; + while (c >= 0) + { + if (app_data.puzzle.chars[r][c] == '#') + c --; + else + break; + } + if (c >= 0) + app_data.cur_col = c; + } +} + +/* move the current selection index up or down */ +void move_current_row (enum DIRECTION dir) +{ + int r = app_data.cur_row; + int c = app_data.cur_col; + if (dir == DIR_FORWARD) + { + r ++; + while (r < app_data.puzzle.grid_size) + { + if (app_data.puzzle.chars[r][c] == '#') + r ++; + else + break; + } + if (r < app_data.puzzle.grid_size) + app_data.cur_row = r; + } + else + { + r --; + while (r >= 0) + { + if (app_data.puzzle.chars[r][c] == '#') + r --; + else + break; + } + if (r >= 0) + app_data.cur_row = r; + } +} + + +/* slot for handling key press event for puzzle drawing area */ +gboolean on_puzzle_area_key_press_event (GtkWidget *widget, + GdkEventKey *event, gpointer data) +{ + /* respond to key events only if the puzzle is loaded */ + if (app_data.is_loaded == true) + { + switch (event->keyval) + { + case GDK_KEY_Down : move_current_row (DIR_FORWARD); + gtk_widget_queue_draw_area (widget, + 0, 0, + app_data.puzzle.grid_size*GRID_PIXELS+10, + app_data.puzzle.grid_size*GRID_PIXELS+10); + break; + case GDK_KEY_Up : move_current_row (DIR_BACK); + gtk_widget_queue_draw_area (widget, + 0, 0, + app_data.puzzle.grid_size*GRID_PIXELS+10, + app_data.puzzle.grid_size*GRID_PIXELS+10); + break; + case GDK_KEY_Right: move_current_col (DIR_FORWARD); + gtk_widget_queue_draw_area (widget, + 0, 0, + app_data.puzzle.grid_size*GRID_PIXELS+10, + app_data.puzzle.grid_size*GRID_PIXELS+10); + break; + case GDK_KEY_Left : move_current_col (DIR_BACK); + gtk_widget_queue_draw_area (widget, + 0, 0, + app_data.puzzle.grid_size*GRID_PIXELS+10, + app_data.puzzle.grid_size*GRID_PIXELS+10); + } + } + + return FALSE; +} + /* slot for drawing the puzzle */ gboolean on_puzzle_area_draw (GtkWidget *widget, cairo_t *cr, gpointer data) { /* if a puzzle is loaded */ if (app_data.is_loaded == true) { - GdkRGBA colorfore, colorback; + GdkRGBA colorfore, colorback, colorblue, colorbacksel; gdk_rgba_parse (&colorfore, "#000000"); gdk_rgba_parse (&colorback, "#ffffff"); + gdk_rgba_parse (&colorblue, "#0000dd"); + gdk_rgba_parse (&colorbacksel, "#ffffaa"); cairo_set_line_width (cr, 3); /* set the size of the drawing area */ - gtk_widget_set_size_request (widget, app_data.puzzle.grid_size*30+5, - app_data.puzzle.grid_size*30+5); + gtk_widget_set_size_request (widget, + app_data.puzzle.grid_size*GRID_PIXELS+10, + app_data.puzzle.grid_size*GRID_PIXELS+10); /* Draw the grid */ for (int i = 0; i < app_data.puzzle.grid_size; i ++) { for (int j = 0; j < app_data.puzzle.grid_size; j ++) { - cairo_rectangle (cr, j*30+5, i*30+5, 30, 30); + /* if it is the current selection or if -1 is the current + selection then let the current selection be the first word */ + if (app_data.cur_col == -1 && app_data.cur_row == -1) + { + if (app_data.puzzle.start_across_word[i][j] == 1) + { + app_data.cur_row = i; + app_data.cur_col = j; + } + else if (app_data.puzzle.start_down_word[i][j] == 1) + { + app_data.cur_row = i; + app_data.cur_col = j; + } + } + gdk_cairo_set_source_rgba (cr, &colorfore); + cairo_rectangle (cr, j*GRID_PIXELS+5, i*GRID_PIXELS+5, + GRID_PIXELS, GRID_PIXELS); + cairo_stroke (cr); /* if it is not a blank grid then set the background color @@ -41,9 +211,37 @@ gboolean on_puzzle_area_draw (GtkWidget *widget, cairo_t *cr, gpointer data) if (app_data.puzzle.chars[i][j] != '#') gdk_cairo_set_source_rgba (cr, &colorback); - cairo_rectangle (cr, j*30+5, i*30+5, 30, 30); - + /* if it is a current selection then set the background + to yellow */ + if (app_data.cur_row == i && app_data.cur_col == j) + gdk_cairo_set_source_rgba (cr, &colorbacksel); + + cairo_rectangle (cr, j*GRID_PIXELS+5, i*GRID_PIXELS+5, + GRID_PIXELS, GRID_PIXELS); cairo_fill (cr); + + /* draw the word number if it is the start of a word */ + if (app_data.puzzle.start_across_word[i][j] != -1 || + app_data.puzzle.start_down_word[i][j] != -1) + { + int num; + if (app_data.puzzle.start_across_word[i][j] != -1) + num = app_data.puzzle.start_across_word[i][j]; + else + num = app_data.puzzle.start_down_word[i][j]; + + gdk_cairo_set_source_rgba (cr, &colorblue); + cairo_select_font_face (cr, "sans serif", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, 11); + cairo_move_to (cr, j*GRID_PIXELS+7, i*GRID_PIXELS+15); + char cnum[3]; + sprintf (cnum, "%d", num); + cairo_show_text (cr, (const char*)cnum); + } + + } } } @@ -52,6 +250,18 @@ gboolean on_puzzle_area_draw (GtkWidget *widget, cairo_t *cr, gpointer data) } +/* slot for reveal solution menu */ +void on_menu_reveal_solution_activate (GtkMenuItem *item, gpointer *data) +{ + /* TODO */ +} + +/* slot for save grid state menu */ +void on_menu_save_grid_state_activate (GtkMenuItem *item, gpointer *data) +{ + /* TODO */ +} + /* slot for exit menu */ void on_menu_exit_activate (GtkMenuItem *item, gpointer data) { @@ -90,10 +300,16 @@ void on_menu_open_activate (GtkMenuItem *item, GtkDrawingArea* area) gtk_dialog_run (GTK_DIALOG(errordlg)); gtk_widget_destroy (errordlg); app_data.is_loaded = false; + app_data.cur_col = -1; + app_data.cur_row = -1; + } + else + { + gtk_widget_queue_draw_area (GTK_WIDGET (area), 0, 0, + app_data.puzzle.grid_size*30+10, + app_data.puzzle.grid_size*30+10); + update_clue_items (); } - - gtk_widget_queue_draw_area (GTK_WIDGET (area), 0, 0, 305, 305); - g_free (filename); } @@ -140,6 +356,11 @@ int main (int argc, char *argv []) else { window = GTK_WIDGET (gtk_builder_get_object (builder, "main_window") ); + across_store = GTK_LIST_STORE (gtk_builder_get_object + (builder, "store_across_clues")); + down_store = GTK_LIST_STORE (gtk_builder_get_object + (builder, "store_down_clues")); + if (window != NULL) { gtk_window_set_default_icon (icon); diff --git a/wordblox_player.glade b/wordblox_player.glade index 428cb8a..bc9f27a 100644 --- a/wordblox_player.glade +++ b/wordblox_player.glade @@ -56,12 +56,12 @@ - + True False _Save Grid State... True - + @@ -94,12 +94,12 @@ True False - + True False _Reveal Solution... True - + @@ -156,8 +156,12 @@ True - False + True + True + True + True + @@ -171,17 +175,17 @@ True - True + False vertical True - True + False in True - True + False store_across_clues False 0 @@ -189,6 +193,31 @@ + + + True + Id + + + + 0 + + + + + + + True + Clues Across + + + + 1 + 1 + + + + @@ -200,17 +229,43 @@ True - True + False in True - True + False store_down_clues + False 0 + False + + + True + Id + + + + 0 + + + + + + + True + Clues Down + + + + 1 + + + + -- 2.20.1