Enhanced word entry and grid movement in puzzle player
authorHarishankar <v.harishankar@gmail.com>
Wed, 6 May 2020 09:54:10 +0000 (15:24 +0530)
committerHarishankar <v.harishankar@gmail.com>
Wed, 6 May 2020 09:54:10 +0000 (15:24 +0530)
Enhanced the word entry to have up/down and across movement on
entry of letters and also to handle space, backspace and delete
characters. Also made clicking a clue in the list of clues to
point to the correct word and orientation

wordblox.h
wordblox_player.c
wordblox_player.glade

index f7a3ce4..e27d37c 100644 (file)
@@ -69,6 +69,7 @@ typedef struct {
        char char_ans[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
        int cur_row;
        int cur_col;
+       enum ORIENTATION current_movement;
 } MainPlayerData;
 
 /* compute the hash of a password */
@@ -290,6 +291,46 @@ void reset_color () {
        printf ("\x1B[0m");
 }
 
+/* check if the prev row has a block or not */
+bool prev_row_block (Puzzle *p, int r, int c)
+{
+       if (r == 0)
+               return true;
+       if (p->chars[r-1][c] == '#')
+               return true;
+       return false;
+}
+
+/* check if the next row has a block or not */
+bool next_row_block (Puzzle *p, int r, int c)
+{
+       if (r == p->grid_size-1)
+               return true;
+       if (p->chars[r+1][c] == '#')
+               return true;
+       return false;
+}
+
+/* check if the prev col has a block or not */
+bool prev_col_block (Puzzle *p, int r, int c)
+{
+       if (c == 0)
+               return true;
+       if (p->chars[r][c-1] == '#')
+               return true;
+       return false;
+}
+
+/* check if the next col has a block or not */
+bool next_col_block (Puzzle *p, int r, int c)
+{
+       if (c == p->grid_size - 1)
+               return true;
+       if (p->chars[r][c+1] == '#')
+               return true;
+       return false;
+}
+
 /* check if previous row is blank or not */
 bool prev_row_blank (Puzzle *p, int r, int c) 
 {
@@ -319,6 +360,34 @@ bool next_col_blank (Puzzle *p, int r, int c)
        return false;
 }
 
+/* set the current row/col to the beginning of word index (across or down) */
+void set_selection_to_word_start (MainPlayerData *app_data,
+                                                                enum ORIENTATION orient, int word_index)
+{
+       for (int i = 0; i < app_data->puzzle.grid_size; i ++)
+       {
+               for (int j = 0; j < app_data->puzzle.grid_size; j ++)
+               {
+                       if (orient == ACROSS && 
+                               app_data->puzzle.start_across_word[i][j] == word_index)
+                       {
+                               app_data->current_movement = ACROSS;
+                               app_data->cur_row = i;
+                               app_data->cur_col = j;
+                               break;
+                       }
+                       else if (orient == DOWN && 
+                               app_data->puzzle.start_down_word[i][j] == word_index)
+                       {
+                               app_data->current_movement = DOWN;
+                               app_data->cur_row = i;
+                               app_data->cur_col = j;
+                               break;
+                       }
+               }
+       }
+}
+
 /* unfreeze the grid - make editing possible to change words */
 void unfreeze_puzzle (Puzzle *p)
 {
index 46a41fd..8e7299b 100644 (file)
@@ -50,6 +50,49 @@ void update_clue_items ()
        } 
 }
 
+/* slot for handling list down selection changed */
+gboolean on_down_list_selection_changed (GtkTreeSelection *sel, 
+                                                                                       GtkDrawingArea *area)
+{
+       GtkTreeIter iter;
+       GtkTreeModel* mod;
+       
+       if (gtk_tree_selection_get_selected (sel, &mod, &iter))
+       {
+               guint sel_word_index;
+               gtk_tree_model_get (mod, &iter, 0, &sel_word_index, -1);
+               set_selection_to_word_start (&app_data, DOWN, sel_word_index);
+       }
+       
+       gtk_widget_queue_draw_area (GTK_WIDGET(area), 0, 0,  
+               app_data.puzzle.grid_size*GRID_PIXELS+10, 
+               app_data.puzzle.grid_size*GRID_PIXELS+10);
+       
+       return FALSE;
+
+}
+/* slot for handling list across selection changed */
+gboolean on_across_list_selection_changed (GtkTreeSelection *sel, 
+                                                                                       GtkDrawingArea *area)
+{
+       GtkTreeIter iter;
+       GtkTreeModel* mod;
+       
+       if (gtk_tree_selection_get_selected (sel, &mod, &iter))
+       {
+               guint sel_word_index;
+               gtk_tree_model_get (mod, &iter, 0, &sel_word_index, -1);
+               set_selection_to_word_start (&app_data, ACROSS, sel_word_index);
+       }
+       
+       gtk_widget_queue_draw_area (GTK_WIDGET(area), 0, 0,  
+               app_data.puzzle.grid_size*GRID_PIXELS+10, 
+               app_data.puzzle.grid_size*GRID_PIXELS+10);
+       
+       return FALSE;
+
+}
+
 /* slot for handling mouse button event for puzzle drawing area */
 gboolean on_puzzle_area_button_press_event (GtkWidget *widget, 
                                                                        GdkEventButton *event, gpointer data)
@@ -66,6 +109,24 @@ gboolean on_puzzle_area_button_press_event (GtkWidget *widget,
                        {
                                app_data.cur_row = row;
                                app_data.cur_col = col;
+                               
+                               /* if it is a start of both across and down word, then 
+                                  toggle the movement on clicking it */
+                               if (app_data.puzzle.start_across_word[row][col] != -1 &&
+                                       app_data.puzzle.start_down_word[row][col] != -1)
+                               {
+                                       if (app_data.current_movement == ACROSS)
+                                               app_data.current_movement = DOWN;
+                                       else
+                                               app_data.current_movement = ACROSS;                             
+                               }
+                               /* if it is only start of across word, make the current
+                                  movement across */
+                               else if (app_data.puzzle.start_across_word[row][col] != -1)
+                                       app_data.current_movement = ACROSS;
+                               /* else down movement */
+                               else if (app_data.puzzle.start_down_word[row][col] != -1)
+                                       app_data.current_movement = DOWN; 
                        }
                }
        }
@@ -73,9 +134,7 @@ gboolean on_puzzle_area_button_press_event (GtkWidget *widget,
        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;   
 }
 
@@ -89,13 +148,18 @@ gboolean on_puzzle_area_key_press_event (GtkWidget *widget,
                switch (event->keyval)
                {
                        case GDK_KEY_Down : move_current_row (&app_data, DIR_FORWARD);
+                                                               app_data.current_movement = DOWN;
                                                                break;
                        case GDK_KEY_Up   : move_current_row (&app_data, DIR_BACK);
+                                                               app_data.current_movement = DOWN;
                                                                break;
                        case GDK_KEY_Right: move_current_col (&app_data, DIR_FORWARD);
+                                                               app_data.current_movement = ACROSS;
                                                                break;
                        case GDK_KEY_Left : move_current_col (&app_data, DIR_BACK);
+                                                               app_data.current_movement = ACROSS;
                                                                break;
+                       case GDK_KEY_BackSpace:
                        case GDK_KEY_Delete:
                        case GDK_KEY_space: 
                                        app_data.char_ans[app_data.cur_row][app_data.cur_col] = ' ';
@@ -209,6 +273,40 @@ gboolean on_puzzle_area_key_press_event (GtkWidget *widget,
                }
        }
        
+       /* move the selection pointer to next row/col as per the current 
+       movement orientation if it is not a key left right up or down */
+       if (event->keyval != GDK_KEY_Down && event->keyval != GDK_KEY_Up &&
+                       event->keyval != GDK_KEY_Left && event->keyval != GDK_KEY_Right
+                               && event->keyval != GDK_KEY_Delete)
+       {
+               /* if the current movement is an across movement */
+               if (app_data.current_movement == ACROSS)
+               {
+                       /* if the next column is not blocking move the col */
+                       if (event->keyval != GDK_KEY_BackSpace && 
+                               next_col_block (&app_data.puzzle, app_data.cur_row,
+                                                       app_data.cur_col) == false)
+                               move_current_col (&app_data, DIR_FORWARD);
+                       else if (event->keyval == GDK_KEY_BackSpace &&
+                                                prev_col_block (&app_data.puzzle, app_data.cur_row,
+                                                       app_data.cur_col) == false)
+                               move_current_col (&app_data, DIR_BACK);
+               }
+               /* current movement is a up/down movement */
+               else
+               {
+                       if (event->keyval != GDK_KEY_BackSpace && 
+                                               next_row_block (&app_data.puzzle, 
+                                                               app_data.cur_row, app_data.cur_col) == false)
+                               move_current_row (&app_data, DIR_FORWARD);
+                       else if (event->keyval == GDK_KEY_BackSpace &&
+                                               prev_row_block (&app_data.puzzle,
+                                                               app_data.cur_row, app_data.cur_col) == false)
+                               move_current_row (&app_data, 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);      
@@ -222,11 +320,12 @@ 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, colorblue, colorbacksel;
+               GdkRGBA colorfore, colorback, colorblue, colorbacksel1, colorbacksel2;
                gdk_rgba_parse (&colorfore, "#000000"); 
                gdk_rgba_parse (&colorback, "#ffffff");
                gdk_rgba_parse (&colorblue, "#0000dd");
-               gdk_rgba_parse (&colorbacksel, "#ffffaa");
+               gdk_rgba_parse (&colorbacksel1, "#ffffaa");
+               gdk_rgba_parse (&colorbacksel2, "#aaffff");
                cairo_set_line_width (cr, 3);
                
                /* set the size of the drawing area */
@@ -269,7 +368,12 @@ gboolean on_puzzle_area_draw (GtkWidget *widget, cairo_t *cr, gpointer data)
                                /* 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);
+                               {
+                                       if (app_data.current_movement == ACROSS)
+                                               gdk_cairo_set_source_rgba (cr, &colorbacksel1);
+                                       else
+                                               gdk_cairo_set_source_rgba (cr, &colorbacksel2);
+                               }
                                
                                cairo_rectangle (cr, j*GRID_PIXELS+5, i*GRID_PIXELS+5, 
                                                                        GRID_PIXELS, GRID_PIXELS);
index 7c1bc92..3f30d95 100644 (file)
                         <property name="search_column">0</property>
                         <property name="show_expanders">False</property>
                         <child internal-child="selection">
-                          <object class="GtkTreeSelection"/>
+                          <object class="GtkTreeSelection">
+                            <signal name="changed" handler="on_across_list_selection_changed" object="puzzle_area" swapped="no"/>
+                          </object>
                         </child>
                         <child>
                           <object class="GtkTreeViewColumn" id="id">
                         <property name="search_column">0</property>
                         <property name="show_expanders">False</property>
                         <child internal-child="selection">
-                          <object class="GtkTreeSelection"/>
+                          <object class="GtkTreeSelection">
+                            <signal name="changed" handler="on_down_list_selection_changed" object="puzzle_area" swapped="no"/>
+                          </object>
                         </child>
                         <child>
                           <object class="GtkTreeViewColumn" id="ID">