Renamed the project to Wordblah from wordblox
authorHarishankar <v.harishankar@gmail.com>
Sat, 9 May 2020 15:06:31 +0000 (20:36 +0530)
committerHarishankar <v.harishankar@gmail.com>
Sat, 9 May 2020 15:15:31 +0000 (20:45 +0530)
Renamed the project from wordblox to wordblah

14 files changed:
Makefile
constantstrings.h
wordblah.c [new file with mode: 0644]
wordblah.gresource.xml [new file with mode: 0644]
wordblah.h [new file with mode: 0644]
wordblah.svg [new file with mode: 0644]
wordblah_player.c [new file with mode: 0644]
wordblah_player.glade [new file with mode: 0644]
wordblox.c [deleted file]
wordblox.gresource.xml [deleted file]
wordblox.h [deleted file]
wordblox.svg [deleted file]
wordblox_player.c [deleted file]
wordblox_player.glade [deleted file]

index 34a60ab..6bd7b90 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
-all:  wordblox wordblox_player
+all:  wordblah wordblah_player
 
-wordblox: wordblox.c wordblox.h constantstrings.h
-       clang wordblox.c -lgd -lz -lcrypto -o wordblox
+wordblah: wordblah.c wordblah.h constantstrings.h
+       clang wordblah.c -lgd -lz -lcrypto -o wordblah
 
-wordblox_player: wordblox_player.c wordblox.h wordblox_resource.c wordblox.gresource.xml wordblox_player.glade constantstrings.h
-               glib-compile-resources wordblox.gresource.xml --target wordblox_resource.c --generate-source
-               clang -rdynamic -lz -lgd -lcrypto -o wordblox_player wordblox_player.c -Wall `pkg-config --cflags --libs gtk+-3.0`
+wordblah_player: wordblah_player.c wordblah.h wordblah.gresource.xml wordblah_player.glade constantstrings.h
+               glib-compile-resources wordblah.gresource.xml --target wordblah_resource.c --generate-source
+               clang -rdynamic -lz -lgd -lcrypto -o wordblah_player wordblah_player.c -Wall `pkg-config --cflags --libs gtk+-3.0`
index b2a270a..e571501 100644 (file)
@@ -41,7 +41,7 @@ and is irreversible (y/N): "
 #define USAGE_LINE_3 "new <nn> - create new puzzle with <nn> grid \
 columns (warning: existing file name may be overwritten)\n"
 
-/* for wordblox_player */
+/* for wordblah_player */
 #define ERROR_ICON "Unable to load icon!"
 #define ERROR_WINDOW "Error loading Window Resource!"
 #define OPEN_FILE "Open File"
@@ -52,8 +52,8 @@ columns (warning: existing file name may be overwritten)\n"
 /* about box info */
 const char *AUTHOR[] = { "V. Harishankar", NULL};
 const char *COPYRIGHT = "Copyright 2020 V.Harishankar";
-const char *COMMENTS = "A player for wordblox (crossword puzzles)";
-const char *PROGRAM_NAME = "Wordblox Player";
+const char *COMMENTS = "A player for wordblah (crossword puzzles)";
+const char *PROGRAM_NAME = "Wordblah Player";
 const char *WEBSITE = "http://harishankar.org/";
 const char *WEBSITE_LABEL = "Author's HomePage";
 
diff --git a/wordblah.c b/wordblah.c
new file mode 100644 (file)
index 0000000..2dbc366
--- /dev/null
@@ -0,0 +1,438 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include "wordblah.h"
+#include "constantstrings.h"
+
+/* export the clues to a text file */
+void do_export_clues (Puzzle *p)
+{
+       if (p->grid_frozen == false)
+       {
+               printf (UNFROZEN_GRID);
+               char ch = getchar ();
+               return;
+       }
+       char fname[256];
+       printf (INPUT_FILE);
+       fgets (fname, 256, stdin);
+       if (strlen(fname) == 1)
+               return;
+       char *filename = strtok (fname, "\n");
+       
+       export_clues (p, filename);
+       printf (FILE_SAVED);
+       char ch = getchar ();
+}
+
+/* export the puzzle to a png file */
+void do_export_puzzle (Puzzle *p)
+{
+       if (p->grid_frozen == false)
+       {
+               printf (UNFROZEN_GRID);
+               char ch = getchar ();
+               return;
+       }
+       char fname[256];
+       printf (INPUT_FILE);
+       fgets (fname, 256, stdin);
+       if (strlen (fname) == 1)
+               return;
+       char* filename = strtok (fname, "\n");
+
+       printf (INPUT_EXPORT_ANSWERS);
+       char ans[3];
+       fgets (ans, 3, stdin);
+       bool solution;
+       solution = (toupper (ans[0]) == 'Y') ? true : false;
+               
+       export_grid_image (p, filename, solution);
+       printf (FILE_SAVED);
+       char ch = getchar ();
+}
+
+/* reset the grid */
+void do_reset_puzzle (Puzzle *p)
+{
+       int grid_size = p->grid_size;
+       printf (INPUT_CONFIRM_RESET);
+       char conf[3];
+       fgets (conf, 3, stdin);
+       if (toupper (conf[0]) == 'Y')
+               init_puzzle (p, grid_size);
+
+        print_puzzle (p);
+        char ch = getchar ();
+}
+
+/* set the solution password for the puzzle */
+void do_set_solution_password (Puzzle *p)
+{
+       char* password;
+       password = getpass (INPUT_PASSWORD);
+       /* if empty reset the password to nothing */
+       if (strlen(password) == 0)
+       {
+               set_solution_password (p, "\0");
+               printf (SOLUTION_PASSWORD_RESET);
+               char ch = getchar ();
+       }
+       /* set the password */
+       else 
+       {
+               set_solution_password (p, (const char* )password);
+               printf (PASSWORD_SET);
+               char ch = getchar ();
+       }
+}
+/* set the master (editing) password for the puzzle */
+void do_set_master_password (Puzzle *p)
+{
+       char* password;
+       password = getpass (INPUT_PASSWORD);
+       /* if empty reset the password to nothing */
+       if (strlen(password) == 0)
+       {
+               set_master_password (p, "\0");
+               printf (MASTER_PASSWORD_RESET);
+               char ch = getchar ();
+       }
+       /* set the password */
+       else 
+       {
+               set_master_password (p, (const char* )password);
+               printf (PASSWORD_SET);
+               char ch = getchar ();
+       }
+}
+
+/* set clue for a word - only for frozen grid */
+void do_set_clue_word (Puzzle *p, enum ORIENTATION orient)
+{
+       print_puzzle (p);
+       if (p->grid_frozen == false)
+       {
+               printf (UNFROZEN_GRID);
+               char ch = getchar ();
+               return;
+       }
+       int index;
+       String clue; 
+       printf (INPUT_INDEX);
+       index = get_num ();
+       printf (INPUT_CLUE);
+       fgets (clue, MAX_CLUE_LENGTH, stdin);
+       if (strlen (clue) == 1)
+               return;
+       char* cl = strtok (clue, "\n");
+       
+       bool res;
+       res = set_clue (p, cl, index, orient);
+
+       if (res == false)
+       {
+               printf (NO_WORD_INDEX);
+               char ch = getchar ();
+       }
+}
+
+/* clear a cell in the grid */
+void do_clear_cell (Puzzle *p)
+{
+       print_puzzle (p);
+       if (p->grid_frozen == true) 
+       {
+               printf (FROZEN_GRID);
+               char ch = getchar ();
+               return;
+       }
+       int row, col;
+       printf (INPUT_ROW);
+       row = get_num (); 
+       printf (INPUT_COL);
+       col = get_num ();
+       if (row >= p->grid_size || col >= p->grid_size)
+       {
+               printf (EXCEED_GRID_SIZE);
+               char ch = getchar ();
+               return;
+       }
+       p->chars[row][col] = ' ';
+       print_puzzle (p);
+       
+       char ch = getchar ();
+}
+
+/* add a down word to the grid */
+void do_add_down_word (Puzzle *p)
+{
+       print_puzzle (p);
+       if (p->grid_frozen == true) 
+       {
+               printf (FROZEN_GRID);
+               char ch = getchar ();
+               return;
+       }
+       char wd[MAX_PUZZLE_SIZE];
+       int row, col;
+       printf (INPUT_WORD);
+       fgets (wd, MAX_PUZZLE_SIZE, stdin);
+       char *word = is_valid_word (wd);
+       if (word == NULL)
+       {
+               printf (INVALID_WORD);
+               char ch = getchar ();
+               return;
+       }
+       printf (INPUT_ROW);
+       row = get_num ();
+       printf (INPUT_COL);
+       col = get_num ();
+       if (row >= p->grid_size || col >= p->grid_size) 
+       {
+               printf (EXCEED_GRID_SIZE);
+               char ch = getchar ();
+               return;
+       }
+       if (strlen (word) > (p->grid_size - row))
+       {
+               printf (WORD_TOO_LONG);
+               char ch = getchar ();
+               return;
+       }
+       
+       for (int i = row; i < row + strlen(word); i ++)
+               p->chars[i][col] = toupper(word[i - row]);
+       
+       print_puzzle (p);
+       char ch = getchar ();
+}
+
+/* add an across word to the grid */
+void do_add_across_word (Puzzle *p)
+{
+       print_puzzle (p);
+       if (p->grid_frozen == true) 
+       {
+               printf (FROZEN_GRID);
+               char ch = getchar ();
+               return;
+       }
+       char wd[MAX_PUZZLE_SIZE];
+       int row, col;   
+       printf (INPUT_WORD);
+       fgets (wd, MAX_PUZZLE_SIZE, stdin);
+       char *word = is_valid_word (wd);
+       if (word == NULL)
+       {
+               printf (INVALID_WORD);
+               char ch = getchar ();
+               return;
+       }
+       printf (INPUT_ROW);
+       row = get_num ();
+       printf (INPUT_COL);
+       col = get_num ();
+       if (row >= p->grid_size || col >= p->grid_size)
+       {
+               printf (EXCEED_GRID_SIZE);
+               char ch = getchar ();
+               return;
+       }
+       
+       if (strlen (word) > (p->grid_size - col))
+       {
+               printf (WORD_TOO_LONG);
+               char ch = getchar ();
+               return;
+       }
+       
+       for (int i = col; i < col+strlen (word); i ++)
+               p->chars[row][i] = toupper(word[i - col]);
+               
+       print_puzzle (p);
+       char ch = getchar ();
+}
+/* confirm exit */
+bool do_confirm_exit ()
+{
+       printf (INPUT_CONFIRM_EXIT);
+       char res[3];
+       fgets (res, 3, stdin);
+       if (toupper(res[0]) == 'Y')
+               return true;
+       else
+               return false;
+} 
+
+/* main loop for the puzzle editor */
+void puzzle_editor_loop (Puzzle *p, const char *filename) 
+{
+       bool loop = true;
+       while (loop) 
+       {
+               char puzzle_title[60];
+               sprintf (puzzle_title, "%s - %s", PUZZLE_MENU_TITLE, filename);
+               print_menu (WHITE, BLUE, puzzle_title, PUZZLE_EDIT_MENU, 15, 50);
+               printf (INPUT_CHOICE);
+               int ch = get_num ();
+               switch (ch)
+               {
+                       case 1: print_puzzle (p);
+                                       char ch = getchar ();
+                                       break;
+                       case 2: do_add_across_word (p);
+                                       break;
+                       case 3: do_add_down_word (p);
+                                       break;
+                       case 4: do_clear_cell (p);
+                                       break;
+                       case 5: freeze_puzzle (p);
+                                       print_puzzle (p);
+                                       ch = getchar ();
+                                       break;
+                       case 6: unfreeze_puzzle (p);
+                                       print_puzzle (p);
+                                       ch = getchar ();
+                                       break;
+                       case 7: do_set_clue_word (p, ACROSS);
+                                       break;
+                       case 8: do_set_clue_word (p, DOWN);
+                                       break;
+                       case 9: save_puzzle (p, filename);
+                                       printf ("%s\n",FILE_SAVED);
+                                       ch = getchar ();
+                                       break;
+                       case 10: do_set_master_password (p);
+                                        break;
+                       case 11: do_set_solution_password (p);
+                                        break;
+                       case 12: do_reset_puzzle (p);
+                                        break;
+                       case 13: do_export_puzzle (p);
+                                        break;
+                       case 14: do_export_clues (p);
+                                        break;
+                       case 15: loop = ! do_confirm_exit ();
+                                        break;
+               }
+       }
+}
+
+/* open an existing puzzle */
+void do_open_puzzle (const char *filename) 
+{
+       Puzzle p;
+       /* if no filename is provided, get it from command line */
+       if (filename == NULL) 
+       {
+               printf (INPUT_FILE);
+               char fname[256];
+               fgets(fname, 256, stdin);
+               if (strlen (fname) == 1)
+                       return;
+               filename = strtok (fname, "\n");
+       }
+
+       p = load_puzzle (filename);
+       
+       if (strcmp (p.hashed_master_password, "\0") != 0)
+       {
+               char *passwd;
+               passwd = getpass (INPUT_PASSWORD);
+               if (strlen (passwd) == 0)
+                       return;
+                                       
+               if (verify_master_password (&p, (const char*) passwd))
+                       puzzle_editor_loop (&p, filename);
+               else
+               {
+                       printf (WRONG_PASSWORD);
+                       char ch = getchar ();
+               } 
+       }
+       else
+               puzzle_editor_loop (&p, filename);
+}
+
+/* create a new blank puzzle */
+void do_new_puzzle (char *filename, int size) 
+{
+       Puzzle p; 
+       /* if filename is not provided get it from command line */
+       if (filename == NULL)
+       {
+               printf (INPUT_FILE);
+               char fname[256];
+               fgets (fname, 256, stdin);
+               if (strlen (fname) == 1)
+                       return;
+               filename = strtok (fname, "\n"); 
+       }
+       /* if no size is specified get it from command line */  
+       if (size == -1)
+       {
+               printf (INPUT_GRID_SIZE);
+               size = get_num ();
+       }
+       
+       if (size > MAX_PUZZLE_SIZE) 
+       { 
+               printf (EXCEED_MAX_GRID_SIZE);
+               char c = getchar (); 
+       }
+       else
+       {
+               init_puzzle (&p, size);
+               puzzle_editor_loop (&p, filename);
+       }
+}
+
+/* The main loop of the program */
+int main_loop () 
+{
+       /* Print the main menu */
+       while (1)
+       {
+               print_menu (WHITE, BLUE, MAIN_MENU_TITLE, MAIN_MENU, 3, 50);
+               printf (INPUT_CHOICE);
+               int ch = get_num ();
+               switch (ch)
+               {
+                       case 1: do_new_puzzle (NULL, -1);
+                                       break;
+                       case 2: do_open_puzzle (NULL);
+                                       break;
+                       case 3: exit (0);
+               }
+       }
+}
+
+int main (int argc, char* argv[]) 
+{
+       if (argc >= 2)
+       {
+               Puzzle p;
+               switch (argc)
+               {
+                       case 2 : do_open_puzzle (argv[1]);
+                                        break;
+                       case 4 : if (strcmp (argv[2], "new") == 0)
+                                        {
+                                               int grid_size = atoi (argv[3]);
+                                               do_new_puzzle (argv[1], grid_size);
+                                               break;
+                                        }
+                       default: fprintf (stderr, USAGE_LINE_1, argv[0]);
+                                        fprintf (stderr, USAGE_LINE_2);
+                                        fprintf (stderr, USAGE_LINE_3);
+                                        exit (3);
+               }
+       }
+       return (main_loop ());
+}
diff --git a/wordblah.gresource.xml b/wordblah.gresource.xml
new file mode 100644 (file)
index 0000000..b027cc0
--- /dev/null
@@ -0,0 +1,8 @@
+
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/harishankar/wordblah">
+    <file preprocess="xml-stripblanks">wordblah_player.glade</file>
+    <file>wordblah.svg</file>
+  </gresource>
+</gresources>
diff --git a/wordblah.h b/wordblah.h
new file mode 100644 (file)
index 0000000..328148d
--- /dev/null
@@ -0,0 +1,1032 @@
+#ifndef __WORDBLAH_H
+#define __WORDBLAH_H
+#define _XOPEN_SOURCE
+#include <unistd.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <gd.h>
+#include <gdfontmb.h>
+#include <gdfontg.h>
+#include <zlib.h>
+#include <openssl/conf.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include "constantstrings.h"
+
+#define MAX_PUZZLE_SIZE 25
+#define MAX_CLUE_LENGTH 150
+#define GRID_PIXELS 37
+
+/* Enum to define terminal colours */
+enum COLOR {
+       BLACK = 0,
+       RED= 1,
+       GREEN=2,
+       YELLOW=3,
+       BLUE=4,
+       MAGENTA=5,
+       CYAN=6,
+       WHITE=7
+};
+
+enum ATTR {
+       NORMAL = 23,
+       BOLD=1
+};
+
+enum ORIENTATION {
+       ACROSS=1,
+       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 */
+typedef struct {
+       char chars[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
+       int start_across_word[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
+       int start_down_word[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
+       String clue_across[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
+       String clue_down[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
+       int grid_size;
+       bool grid_frozen;
+       char hashed_master_password[256];
+       char hashed_solution_password[256];
+} Puzzle;
+
+/* The player data struct type - for the player app */
+typedef struct {
+       Puzzle puzzle;
+       char filename[65535];
+       bool is_loaded;
+       char char_ans[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
+       int cur_row;
+       int cur_col;
+       bool solution_revealed;
+       enum ORIENTATION current_movement;
+} MainPlayerData;
+
+/* compute the hash of a password */
+void digest_message(const unsigned char *message, 
+       size_t message_len, unsigned char **digest, unsigned int *digest_len)
+{
+       EVP_MD_CTX *mdctx;
+
+       if((mdctx = EVP_MD_CTX_new()) == NULL)
+               goto err;
+
+       if(1 != EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL))
+               goto err;
+
+       if(1 != EVP_DigestUpdate(mdctx, message, message_len))
+               goto err;
+
+       if((*digest = (unsigned char *)
+               OPENSSL_malloc(EVP_MD_size(EVP_sha256()))) == NULL)
+               goto err;
+
+       if(1 != EVP_DigestFinal_ex(mdctx, *digest, digest_len))
+               goto err;
+
+       EVP_MD_CTX_free(mdctx);
+       return;
+err:
+       EVP_MD_CTX_free(mdctx);
+       ERR_print_errors_fp(stderr);    
+       exit (2);
+}
+
+/* convert the hashed binary password to hexadecimal representation and
+   free the hashed binary password */
+void to_hexadecimal (char *hex, unsigned char *binary_pwd, unsigned int len)
+{
+       char buf[3];
+       /* keep reference to beginning of the hashed password */
+       unsigned char *binary_pw_begin = binary_pwd;
+       for (int i = 0; i < len; i ++)
+       {
+               sprintf (buf, "%02x", (*binary_pwd)&0xff);
+               strcat (hex, buf);
+               binary_pwd ++;
+       }
+       /* free the hashed password */
+       OPENSSL_free (binary_pw_begin); 
+}
+
+/* get a number from the user */
+int get_num ()
+{
+       char s[5];
+       fgets (s, 5, stdin);
+       int n = atoi (s);
+       return n;
+}
+
+/* verify solution password */
+bool verify_solution_password (Puzzle *p, const char* password)
+{
+       /* no password set */
+       if (strcmp (p->hashed_solution_password, "\0") == 0)
+               return true;
+               
+       /* hash the user input password and compare it with the stored password */
+       unsigned char* hashed_sol_password;
+       unsigned int len;
+       digest_message ((const unsigned char *)password, strlen(password),
+                                               &hashed_sol_password, &len);
+       char hashed_hex_pwd[256] = { (char) NULL };
+       to_hexadecimal (hashed_hex_pwd, hashed_sol_password, len);
+       
+       if (strcmp (p->hashed_solution_password, hashed_hex_pwd) == 0)
+               return true;
+       
+       return false;
+}
+
+
+/* verify master password */
+bool verify_master_password (Puzzle *p, const char* password)
+{
+       /* no password set */
+       if (strcmp (p->hashed_master_password, "\0") == 0)
+               return true;
+               
+       /* hash the user input password and compare it with the stored password */
+       unsigned char* hashed_mas_password;
+       unsigned int len;
+       digest_message ((const unsigned char *)password, strlen(password),
+                                               &hashed_mas_password, &len);
+       char hashed_hex_pwd[256] = { (char) NULL };
+       to_hexadecimal (hashed_hex_pwd, hashed_mas_password, len);
+       
+       if (strcmp (p->hashed_master_password, hashed_hex_pwd) == 0)
+               return true;
+       
+       return false;
+}
+
+/* Set or reset solution password for puzzle */
+void set_solution_password (Puzzle *p, const char *password)
+{
+       /* if it is a null string, reset the password */
+       if (strcmp (password, "\0") == 0)
+               strcpy (p->hashed_solution_password, "\0");
+       else 
+       {
+
+               unsigned char* hashedpwd;
+               unsigned int len;
+               digest_message ((const unsigned char *)password, strlen(password),
+                                               &hashedpwd, &len);
+               /* the hashedpwd contains binary data - we will convert it to 
+                  hexadecimal data and store in file */
+
+               to_hexadecimal (p->hashed_solution_password, hashedpwd, len);
+       }
+}
+
+/* Set or reset master password for puzzle */
+void set_master_password (Puzzle *p, const char *password)
+{
+       /* if it is a null string, reset the password */
+       if (strcmp (password, "\0") == 0)
+               strcpy (p->hashed_master_password, "\0");
+       else 
+       {
+
+               unsigned char* hashedpwd;
+               unsigned int len;
+               digest_message ((const unsigned char *)password, strlen(password),
+                                               &hashedpwd, &len);
+               /* the hashedpwd contains binary data - we will convert it to 
+                  hexadecimal data and store in file */
+
+               to_hexadecimal (p->hashed_master_password, hashedpwd, len);
+       }
+}
+
+/* Output the clues to text file */
+void export_clues (Puzzle *p, const char *filename)
+{
+       FILE *outfile = fopen (filename, "w");
+       if (outfile == NULL)
+       {
+               fprintf (stderr, "%s\n", ERROR_WRITING_FILE);
+               exit (1);
+       }
+       /* first the across clues */
+       fprintf (outfile, "ACROSS CLUES\n");
+       for (int i = 0; i < p->grid_size; i ++)
+       {
+               for (int j = 0; j < p->grid_size; j ++)
+               {
+                       if (p->start_across_word[i][j] != -1)
+                               fprintf (outfile, "%d - %s\n", p->start_across_word[i][j],
+                                                       p->clue_across[i][j]);
+               }
+       }
+       /* now the down clues */
+       fprintf (outfile, "DOWN CLUES\n");
+       for (int i = 0; i < p->grid_size; i ++)
+       {
+               for (int j = 0; j < p->grid_size; j ++)
+               {
+                       if (p->start_down_word[i][j] != -1)
+                               fprintf (outfile, "%d - %s\n", p->start_down_word[i][j],
+                                                       p->clue_down[i][j]);
+               }
+       }
+       fclose (outfile);
+}
+
+/* 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 * GRID_PIXELS;
+       FILE * outfile = fopen (filename, "wb");
+       if (outfile == NULL)
+       {
+               fprintf (stderr, "%s\n", ERROR_WRITING_FILE);
+               exit (1);
+       }
+       
+       gdImagePtr img = gdImageCreate (img_size, img_size);
+       gdImageColorAllocate (img, 255,255,255);
+       int black = gdImageColorAllocate (img, 0, 0, 0);
+       int blue = gdImageColorAllocate (img, 0, 0, 216);
+       gdFontPtr sm_fnt = gdFontGetMediumBold ();
+       gdFontPtr lg_fnt = gdFontGetGiant ();
+       
+       for (int i = 0; i < p->grid_size; i ++)
+       {
+               for (int j = 0; j < p->grid_size; j++)
+               {
+                       /* if it is a block, draw the black square */
+                       if (p->chars[i][j] == '#')
+                               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*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 */
+                               if (p->start_across_word[i][j] != -1 || 
+                                               p->start_down_word[i][j] != -1)
+                               {
+                                       if (p->start_across_word[i][j] != -1)
+                                       {
+                                               char str[5];
+                                               sprintf (str, "%d", p->start_across_word[i][j]);
+                                               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*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*GRID_PIXELS+15, 
+                                                                       i*GRID_PIXELS+10, p->chars[i][j], black);
+                               }
+                       }
+               }
+       }
+       
+       gdImagePng (img, outfile);
+       gdImageDestroy (img);
+       fclose (outfile);
+}
+
+/* Set the terminal colour */
+void set_color (enum COLOR fg, enum COLOR bg, enum ATTR at) {
+       printf ("\x1B[%d;%d;%dm", fg+30, bg+40, at);
+}
+
+/* Reset the terminal colour */
+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) 
+{
+       if (r == 0) return true;
+       if (p->chars[r-1][c] == ' ' || p->chars[r-1][c] == '#') return true;
+       return false;
+}
+/* check if next row is blank or not */
+bool next_row_blank (Puzzle *p, int r, int c)
+{
+       if (r == p->grid_size - 1) return true;
+       if (p->chars[r+1][c] == ' ' || p->chars[r+1][c] == '#') return true;
+       return false;
+}
+/* check if previous col is blank or not */
+bool prev_col_blank (Puzzle *p, int r, int c)
+{
+       if (c == 0) return true;
+       if (p->chars[r][c-1] == ' ' || p->chars[r][c-1] == '#') return true;
+       return false; 
+}
+/* check if the next col is blank or not */
+bool next_col_blank (Puzzle *p, int r, int c)
+{
+       if (c == p->grid_size -1) return true;
+       if (p->chars[r][c+1] == ' ' || p->chars[r][c+1] == '#') return true;
+       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)
+{
+       for (int i = 0; i < p->grid_size; i ++)
+       {
+               for (int j = 0; j < p->grid_size; j ++)
+               {
+                       if (p->chars[i][j] == '#')
+                               p->chars[i][j] = ' ';
+                       
+                       p->start_across_word[i][j] = -1;
+                       p->start_down_word[i][j] = -1;
+               }
+       }
+       p->grid_frozen = false;
+}
+
+/* freeze the grid - make editing impossible because it finalizes the
+   across and down words in the grid */
+void freeze_puzzle (Puzzle *p)
+{              
+       int word_num = 1;
+       bool across_word_start, down_word_start;
+       for (int i = 0; i < p->grid_size; i ++)
+       {
+               for (int j = 0; j < p->grid_size; j++)
+               {
+                       across_word_start = false; 
+                       down_word_start = false;
+                       /* if it is a blank cell - cover it with a block */
+                       if (p->chars[i][j] == ' ' || p->chars[i][j] == '#')
+                               p->chars[i][j] = '#';
+                       /* it is not a blank cell - check all possibilities */
+                       else 
+                       {
+                               bool prev_row = prev_row_blank (p, i, j);
+                               bool next_row = next_row_blank (p, i, j);
+                               bool prev_col = prev_col_blank (p, i, j);
+                               bool next_col = next_col_blank (p, i, j);
+                               if (prev_row && ! next_row)
+                                       down_word_start = true;
+                               if (prev_col && ! next_col)
+                                       across_word_start = true;
+                       }
+                       
+                       if (across_word_start == true)
+                               p->start_across_word[i][j] = word_num;
+                       else 
+                               p->start_across_word[i][j] = -1;
+                       if (down_word_start == true)
+                               p->start_down_word[i][j] = word_num;
+                       else
+                               p->start_down_word[i][j] = -1;
+                       if (across_word_start == true || down_word_start == true)
+                               word_num ++;
+               }
+       }
+       p->grid_frozen = true;
+}
+
+/* reset the entire grid */
+void init_puzzle (Puzzle *p, int grid_size) 
+{
+       p->grid_size = grid_size;
+       p->grid_frozen = false;
+       for (int i = 0; i < p->grid_size; i ++)
+       {
+               for (int j = 0; j < p->grid_size; j ++) 
+               {
+                       p->chars[i][j] = ' ';
+                       p->start_across_word[i][j] = -1;
+                       p->start_down_word[i][j] = -1;
+                       strcpy (p->clue_across[i][j], "");
+                       strcpy (p->clue_down[i][j], "");                        
+               }
+       }
+       strcpy (p->hashed_master_password, "\0");
+       strcpy (p->hashed_solution_password, "\0");
+       
+}
+
+/* save the puzzle to a file */
+void save_puzzle (Puzzle *puzzle, const char* file) 
+{
+       FILE *outfile;
+       /* First output the uncompressed contents to a temp file */
+       outfile = tmpfile ();
+       if (outfile == NULL)
+       {
+               fprintf (stderr, "%s\n", ERROR_WRITING_FILE);
+               exit (1);
+       }
+       /* grid size is the first field */
+       fprintf (outfile, "%d\n", puzzle->grid_size);
+       /* whether grid is frozen or not */
+       fprintf (outfile, "%d\n", puzzle->grid_frozen);
+       /* the hashed password */
+       fprintf (outfile, "%s\n", puzzle->hashed_master_password);
+       /* the hashed_solution_password */
+       fprintf (outfile, "%s\n", puzzle->hashed_solution_password);
+       
+       /* First output the grid characters columns/rows */
+       for (int i = 0; i < puzzle->grid_size; i ++)
+       {
+               for (int j = 0; j < puzzle->grid_size; j ++)
+                       fprintf (outfile, "%c", puzzle->chars[i][j]);
+               fprintf (outfile, "\n");
+       }
+       
+       /* Next output the start across/down numbers */
+       for (int i = 0; i < puzzle->grid_size; i ++)
+       {
+               for (int j = 0; j < puzzle->grid_size; j++)
+               {
+                       fprintf (outfile, "%d ", puzzle->start_across_word[i][j]);
+                       fprintf (outfile, "%d ", puzzle->start_down_word[i][j]);
+               }
+               fprintf (outfile, "\n");
+       }
+       
+       /* Output the across clues */
+       fprintf (outfile, "ACROSS\n");
+       /* Search the grid for across words */
+       for (int i = 0; i < puzzle->grid_size; i ++)
+       {
+               for (int j = 0; j < puzzle->grid_size; j++)
+               {
+                       /* if it is an across word, then put the word index followed by
+                       tab character (as separator) and the clue */
+                       if (puzzle->start_across_word[i][j] != -1)
+                               fprintf (outfile, "%d\t%s\n", puzzle->start_across_word[i][j], 
+                                       puzzle->clue_across[i][j]);
+               }
+       }
+       
+       /* Output the down clues */
+       fprintf (outfile, "DOWN\n");
+       /* Search the grid for down words */
+       for (int i = 0; i < puzzle->grid_size; i ++)
+       {
+               for (int j = 0; j < puzzle->grid_size; j++)
+               {
+                       /* same as across word, put the word index followed by the tab
+                       character and then the clue */
+                       if (puzzle->start_down_word[i][j] != -1)
+                               fprintf (outfile, "%d\t%s\n", puzzle->start_down_word[i][j], 
+                                       puzzle->clue_down[i][j]);
+               }
+       }
+       
+       /* Flush the buffer and rewind to beginning - to read and save into 
+       gzip compressed file */
+       fflush (outfile);
+       fseek (outfile, 0, 0);
+                       
+       /* now compress the file and save it to destination file */
+       gzFile outdestfile = gzopen (file, "wb");
+       if (outdestfile == NULL)
+       {
+               fprintf (stderr, "%s\n", ERROR_WRITING_FILE);
+               fclose (outfile);
+               exit (1);
+       }
+       char buf[128];
+       int num = fread (buf, sizeof(char), sizeof(char)*128, outfile);
+       while (num > 0)
+       {
+               int res = gzwrite (outdestfile, buf, num*sizeof(char) );
+               if (res == 0)
+               {
+                       fprintf (stderr, "%s %s\n", ERROR_WRITING_FILE, COMPRESSED);
+                       fclose (outfile);
+                       exit (1);
+               }
+               num = fread (buf, sizeof(char), sizeof(char)*128, outfile);
+       }
+       gzclose (outdestfile);
+       fclose (outfile);
+
+}
+
+/* read the puzzle from a file */
+Puzzle load_puzzle (const char* file) 
+{
+       /* First open the GZip file */
+       gzFile insourcefile = gzopen (file, "rb");
+       if (insourcefile == NULL)
+       {
+               fprintf (stderr, "%s %s\n", ERROR_READING_FILE, COMPRESSED);
+               exit (1);
+       }
+       /* Open a temporary file to uncompress the contents */
+       FILE *infile = tmpfile ();
+       if (infile == NULL)
+       {
+               fprintf (stderr, "%s\n", ERROR_READING_FILE);
+               exit (1);       
+       }
+       /* Put the uncompressed content to the temp file */
+       char buf[128];
+       int num = 0;
+       num = gzread (insourcefile, buf, 128);
+       while (num > 0)
+       {
+               int res = fwrite (buf, 1, num, infile);
+               if (res == 0)
+               {
+                       fprintf (stderr, "%s\n", ERROR_READING_FILE);
+                       fclose (infile);
+                       gzclose (insourcefile);
+                       exit (1);
+               }
+               num = gzread (insourcefile, buf, 128);
+       }
+       /* Close the gzip file */
+       gzclose (insourcefile);
+       /* Flush the temp file buffer and rewind to beginning */
+       fflush (infile);
+       fseek (infile, 0, 0);
+
+       /* Read the temporary file contents to the structure Puzzle */
+       Puzzle p;
+       char line[MAX_CLUE_LENGTH+10];
+       fgets (line, MAX_CLUE_LENGTH + 10, infile);
+       p.grid_size = atoi (line);
+       fgets (line, MAX_CLUE_LENGTH + 10, infile);
+       p.grid_frozen = atoi (line) == 0 ? false : true ;
+       fgets (line, MAX_CLUE_LENGTH + 10, infile);
+       if (strlen (line) != 1)
+               strcpy (p.hashed_master_password, strtok (line, "\n"));
+       else
+               strcpy (p.hashed_master_password, "\0");
+       fgets (line, MAX_CLUE_LENGTH + 10, infile);
+       if (strlen (line) != 1)
+               strcpy (p.hashed_solution_password, strtok (line, "\n"));
+       else
+               strcpy (p.hashed_solution_password, "\0");
+       
+       /* read each character of the grid */
+       for (int i = 0; i < p.grid_size; i ++ )
+       {
+               fgets (line, MAX_CLUE_LENGTH + 10, infile);
+               for (int j = 0; j < p.grid_size; j ++)
+                       p.chars[i][j] = line[j];
+       }
+       /* read the word numbers */
+       for (int i = 0; i < p.grid_size; i ++)
+       {
+               fgets (line, MAX_CLUE_LENGTH + 10, infile);
+               char *token = strtok (line, " ");
+               for (int j = 0; j < p.grid_size; j ++)
+               {
+                       if (token != NULL) 
+                               p.start_across_word[i][j] = atoi (token);
+                       token = strtok (NULL, " ");
+                       if (token != NULL)
+                               p.start_down_word[i][j] = atoi (token);
+                       token = strtok (NULL, " ");
+               }
+       }
+       /* read the clues */
+       fgets (line, MAX_CLUE_LENGTH + 10, infile);
+       
+       /* across clues */
+       char clues[100][MAX_CLUE_LENGTH];
+       int word_num[100];
+       int c = 0;
+       /* first read the across clues from file */
+       while (1)
+       {
+               fgets (line, MAX_CLUE_LENGTH + 10, infile);
+               /* if reached the end of across clues */
+               if (strcmp (line, "DOWN\n") == 0)
+                       break;
+               word_num[c] = atoi (strtok (line, "\t"));
+               char *cl = strtok (NULL, "\n");
+               if (cl != NULL)         
+                       strcpy (clues[c], cl);
+               else
+                       strcpy (clues[c], "\0");
+               c++;
+       }
+       /* set the clue to the correct cell in grid */
+       for (int i = 0; i < p.grid_size; i ++)
+       {
+               for (int j = 0; j < p.grid_size; j ++)
+               {
+                       for (int r = 0; r < c; r ++)
+                               if (p.start_across_word[i][j] == word_num[r])
+                                       strcpy (p.clue_across[i][j], clues[r]);
+               }
+       }
+
+       /* down clues */
+       c = 0;
+       while (fgets (line, MAX_CLUE_LENGTH + 10, infile))
+       {
+               word_num[c] = atoi (strtok (line, "\t"));
+               char* cl = strtok (NULL, "\n");
+               if (cl != NULL)
+                       strcpy (clues[c], cl);
+               else
+                       strcpy (clues[c], "\0");
+               c++;
+       }
+       for (int i = 0; i < p.grid_size; i ++)
+       {
+               for (int j = 0; j < p.grid_size; j ++)
+               {
+                       for (int r = 0; r < c; r ++)
+                               if (p.start_down_word[i][j] == word_num[r])
+                                       strcpy (p.clue_down[i][j], clues[r]);
+               }
+       }
+
+       fclose (infile);
+       return p;
+}
+
+/* display the puzzle */ 
+void print_puzzle (Puzzle *p) 
+{
+       printf ("\n");
+       set_color (WHITE, CYAN, NORMAL);
+       printf ("    ");
+       for (int i = 0; i < p->grid_size; i ++)
+               printf ("%3d", i);
+       reset_color ();
+       printf("\n");
+       for (int i = 0; i < p->grid_size; i ++)
+       {
+               set_color (WHITE, CYAN, NORMAL);
+               printf ("%3d ", i);
+               for (int j = 0; j < p->grid_size; j ++) 
+               {
+                       if (p->chars[i][j] == '#') {
+                               set_color (WHITE, BLACK, NORMAL);
+                               printf ("   ");
+                       }
+                       else 
+                       {
+                               if (p->start_across_word[i][j] != -1 || 
+                                       p->start_down_word[i][j] != -1) 
+                               {
+                                       set_color (BLUE, WHITE, NORMAL);
+                                       if (p->start_across_word[i][j] != -1)
+                                               printf ("%-2d", p->start_across_word[i][j]);
+                                       else 
+                                               printf ("%-2d", p->start_down_word[i][j]);
+                               }
+                               else
+                               {
+                                       set_color (BLACK, WHITE,NORMAL);
+                                       printf ("  ");
+                               }
+                                       
+                               set_color (BLACK, WHITE, BOLD);
+                               printf ("%c", p->chars[i][j]);
+                       }
+                       reset_color ();
+               }
+               printf ("\n");
+       }
+       /* print the clues if set */
+       if (p->grid_frozen == true) 
+       {
+               printf ("\x1B[1mACROSS - CLUES\x1B[0m\n");
+               for (int i = 0; i < p->grid_size; i ++)
+               {
+                       for (int j = 0; j < p->grid_size; j ++)
+                       {
+                               if (p->start_across_word[i][j] != -1)
+                               {
+                                       printf ("%d - %s; ", p->start_across_word[i][j], 
+                                                               p->clue_across[i][j]);
+                               }
+                       }
+               }
+               printf ("\n\x1B[1mDOWN - CLUES\x1B[0m\n");
+               for (int i = 0; i < p->grid_size; i ++)
+               {
+                       for (int j = 0; j < p->grid_size; j ++)
+                       {
+                               if (p->start_down_word[i][j] != -1)
+                               {
+                                       printf ("%d - %s; ", p->start_down_word[i][j], 
+                                                               p->clue_down[i][j]);
+                               }
+                       }
+               }
+               printf ("\n");  
+       }
+}
+
+/* function to check if a word is valid or not */
+char* is_valid_word (char *word) 
+{
+       if (word == NULL || strlen(word) == 0)
+               return NULL;
+       for (int i = 0; i < strlen (word) - 1; i ++)
+               if (! isalpha (word[i])) 
+                       return NULL;
+                       
+       return strtok (word, "\n");
+}
+
+
+/* function to set a clue for an across word */
+bool set_clue (Puzzle *p, String clue, int index, enum ORIENTATION order) 
+{
+       for (int i = 0; i < p->grid_size; i ++)
+       {
+               for (int j = 0; j < p->grid_size; j ++)
+               {
+                       if (order == ACROSS)
+                       {
+                               if (p->start_across_word[i][j] == index)
+                               {
+                                       strcpy (p->clue_across[i][j], clue);
+                                       return true;
+                               }
+                       }
+                       else if (order == DOWN)
+                       {
+                               if (p->start_down_word[i][j] == index)
+                               {
+                                       strcpy (p->clue_down[i][j], clue);
+                                       return true;
+                               }
+                       }               
+               }
+       }
+       return false;
+}
+
+/* function to print a menu */
+void print_menu (enum COLOR fg, enum COLOR bg, const char* title, 
+                                       char **items, int num_items, int padding)
+{
+               /* clear screen */
+               printf ("\e[1;1H\e[2J");
+               set_color (fg, bg, NORMAL);
+               printf ("\u2554");
+               for (int i = 0; i < padding; i ++)
+                       printf ("\u2550");
+               printf ("\u2557"); 
+               reset_color (); printf ("\n");
+               set_color (fg, bg, NORMAL);
+               printf ("\u2551");
+               set_color (fg, bg, BOLD);
+               printf ("%-*s", padding, title);
+               reset_color ();
+               set_color (fg, bg, NORMAL);
+               printf ("\u2551");
+               reset_color (); printf ("\n");
+               set_color (fg, bg, NORMAL);
+               printf ("\u2560");
+               for (int i = 0; i < padding; i ++)
+                       printf ("\u2550");
+               printf ("\u2563");
+               reset_color (); printf ("\n");
+               for (int i = 0; i < num_items; i ++) 
+               {
+                       set_color (fg, bg, NORMAL);
+                       printf ("\u2551%-*s\u2551", padding, items[i]);
+                       reset_color (); printf ("\n");
+               }
+               set_color (fg, bg, NORMAL);
+               printf ("\u255A");
+               for (int i = 0; i < padding; i ++)
+                       printf ("\u2550");
+               printf ("\u255D");
+               reset_color (); printf ("\n");
+}
+
+/* reset the player data, loading from the puzzle file */
+void reset_player_data (MainPlayerData *app_data, const char *filename)
+{
+       app_data->puzzle = load_puzzle (filename);
+
+       app_data->is_loaded = app_data->puzzle.grid_frozen;
+       app_data->cur_col = -1;
+       app_data->cur_row = -1;
+       app_data->solution_revealed = false;
+       strcpy (app_data->filename, filename);
+       /* reset the answer keys */
+       for (int i = 0; i < app_data->puzzle.grid_size; i ++)
+               for (int j = 0; j < app_data->puzzle.grid_size; j ++)
+                       app_data->char_ans[i][j] = ' ';
+       
+}
+
+/* save the user grid to a file */
+void save_user_data (MainPlayerData *app_data, const char *filename) 
+{
+       FILE *outfile;
+       outfile = fopen (filename, "wb");
+       if (outfile == NULL) 
+       {
+               fprintf (stderr, ERROR_WRITING_FILE);
+               return;
+       }
+       fprintf (outfile, "%s\n", app_data->filename);
+       for (int i = 0; i < app_data->puzzle.grid_size; i ++)
+       {
+               for (int j = 0; j < app_data->puzzle.grid_size; j ++)
+                       fprintf (outfile, "%c", app_data->char_ans[i][j]);
+               fprintf (outfile, "\n");
+       }
+       
+       fclose (outfile);
+}
+
+/* load the user grid from a file */
+void load_user_data (MainPlayerData *app_data, const char *filename)
+{
+       FILE *infile;
+       infile = fopen (filename, "rb");
+       if (infile == NULL)
+       {
+               fprintf (stderr, "%s\n", ERROR_READING_FILE);
+               return;
+       }
+
+       char puzzle_file_name[65535];
+       fgets (puzzle_file_name, 65535, infile);        
+       reset_player_data (app_data, strtok (puzzle_file_name, "\n"));
+
+       char line[MAX_PUZZLE_SIZE+10];
+       for (int i = 0; i < app_data->puzzle.grid_size; i ++)
+       {
+               fgets (line, MAX_PUZZLE_SIZE+10, infile);
+               for (int j = 0; j < app_data->puzzle.grid_size; j ++)
+                       app_data->char_ans[i][j] = line[j];
+
+       }
+       fclose (infile);
+}
+
+/* in the player app, move the current selection index left or right */
+void move_current_col (MainPlayerData *app_data, 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;
+       }
+}
+
+/* in the player app move the current selection index up or down */
+void move_current_row (MainPlayerData *app_data, 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;
+       }
+}
+
+#endif
diff --git a/wordblah.svg b/wordblah.svg
new file mode 100644 (file)
index 0000000..d7e6745
--- /dev/null
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg2985"
+   version="1.1"
+   inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
+   sodipodi:docname="wordblox.svg"
+   inkscape:export-filename="/home/hari/Projects/GetAClue/resources/getaclue.png"
+   inkscape:export-xdpi="96"
+   inkscape:export-ydpi="96">
+  <defs
+     id="defs2987" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.6875"
+     inkscape:cx="373.4413"
+     inkscape:cy="-67.966563"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1366"
+     inkscape:window-height="704"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata2990">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <rect
+       style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.50000000000000000;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="rect2993"
+       width="60.18182"
+       height="60.363636"
+       x="2.1818182"
+       y="2" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="m 22.727273,2.5454545 0,59.6363635"
+       id="path2995"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="M 42.545455,2.3636367 42.545455,62"
+       id="path2995-2"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="M 2.5454545,22.363636 62,22.363636"
+       id="path3022"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="m 3.2727273,42.545455 58.9840237,0"
+       id="path3024"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       d="M 42.909095,11.727272 V 2 h 9.727272 9.727273 v 9.727272 9.727273 h -9.727273 -9.727272 z"
+       id="path3032"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       d="M 3.2727282,11.818181 V 2.5454545 h 9.7272728 9.727272 v 9.2727265 9.272727 H 13.000001 3.2727282 Z"
+       id="path3032-3"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       d="M 3.2727273,51.818181 V 42.545455 H 13 22.727272 v 9.272726 9.272727 H 13 3.2727273 Z"
+       id="path3032-3-7"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       d="M 42.545455,52.727273 V 43.454547 H 52.272728 62 V 52.727273 62 h -9.727272 -9.727273 z"
+       id="path3032-3-5"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/wordblah_player.c b/wordblah_player.c
new file mode 100644 (file)
index 0000000..26dab29
--- /dev/null
@@ -0,0 +1,724 @@
+#include <gtk/gtk.h>
+
+#include "constantstrings.h"
+#include "wordblah_resource.c"
+#include "wordblah.h"
+
+GtkWidget *main_window; 
+GtkListStore *across_store;
+GtkListStore *down_store;
+
+MainPlayerData app_data;
+
+/* update the clue items store */
+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);
+                               }
+                       }
+               }
+       } 
+}
+
+/* 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)
+{
+       /* if it is solution mode, then don't do anything but reset it to 
+          non solution mode */
+       if (app_data.solution_revealed == true)
+       {
+               app_data.solution_revealed = false;
+               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;
+       }
+       
+       /* Depending on the type of button handle the movement */
+       if (event->type == GDK_BUTTON_PRESS && event->button == 1)
+       {
+               int col = (event->x - 5) / GRID_PIXELS;
+               int row = (event->y - 5) / GRID_PIXELS;
+       
+               if (app_data.puzzle.chars[row][col] != '#')
+               {
+                       if (row < app_data.puzzle.grid_size && 
+                               col < app_data.puzzle.grid_size)
+                       {
+                               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; 
+                       }
+               }
+       }
+       
+       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 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)
+       {
+               /* if the solution is revealed, don't respond to key events except
+                  to return to the non-solution mode */
+               if (app_data.solution_revealed == true)
+               {
+                       app_data.solution_revealed = false;
+                       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;
+               }
+               
+               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] = ' ';
+                                                               break;                  
+                       case GDK_KEY_a    :
+                       case GDK_KEY_A    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'A';
+                                                               break;
+                       case GDK_KEY_b    :
+                       case GDK_KEY_B    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'B';
+                                                               break;
+                       case GDK_KEY_c    :
+                       case GDK_KEY_C    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'C';
+                                                               break;
+                       case GDK_KEY_d    :
+                       case GDK_KEY_D    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'D';
+                                                               break;
+                       case GDK_KEY_e    :
+                       case GDK_KEY_E    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'E';
+                                                               break;
+                       case GDK_KEY_f    :
+                       case GDK_KEY_F    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'F';            
+                                                               break;
+                       case GDK_KEY_g    :
+                       case GDK_KEY_G    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'G';
+                                                               break;
+                       case GDK_KEY_h    :
+                       case GDK_KEY_H    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'H';
+                                                               break;
+                       case GDK_KEY_i    :
+                       case GDK_KEY_I    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'I';
+                                                               break;
+                       case GDK_KEY_j    :
+                       case GDK_KEY_J    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'J';
+                                                               break;
+                       case GDK_KEY_k    :
+                       case GDK_KEY_K    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'K';
+                                                               break;
+                       case GDK_KEY_l    :
+                       case GDK_KEY_L    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'L';
+                                                               break;
+                       case GDK_KEY_m    :
+                       case GDK_KEY_M    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'M';
+                                                               break;
+                       case GDK_KEY_n    :
+                       case GDK_KEY_N    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'N';
+                                                               break;
+                       case GDK_KEY_o    :
+                       case GDK_KEY_O    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'O';
+                                                               break;
+                       case GDK_KEY_p    :
+                       case GDK_KEY_P    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'P';
+                                                               break;
+                       case GDK_KEY_q    :
+                       case GDK_KEY_Q    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'Q';
+                                                               break;
+                       case GDK_KEY_r    :
+                       case GDK_KEY_R    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'R';
+                                                               break;
+                       case GDK_KEY_s    :
+                       case GDK_KEY_S    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'S';
+                                                               break;
+                       case GDK_KEY_t    :
+                       case GDK_KEY_T    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'T';
+                                                               break;
+                       case GDK_KEY_u    :
+                       case GDK_KEY_U    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'U';
+                                                               break;
+                       case GDK_KEY_v    :
+                       case GDK_KEY_V    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'V';
+                                                               break;
+                       case GDK_KEY_w    :
+                       case GDK_KEY_W    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'W';
+                                                               break;
+                       case GDK_KEY_x    :
+                       case GDK_KEY_X    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'X';
+                                                               break;
+                       case GDK_KEY_y    :
+                       case GDK_KEY_Y    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'Y';
+                                                               break;
+                       case GDK_KEY_z    :
+                       case GDK_KEY_Z    : 
+                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'Z';
+                                                               break;
+                       default                   : return FALSE;
+                                                                               
+               }
+       }
+       
+       /* 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);      
+       
+       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, colorblue, colorbacksel1, 
+                               colorbacksel2, colorsolution;
+               gdk_rgba_parse (&colorfore, "#000000"); 
+               gdk_rgba_parse (&colorback, "#ffffff");
+               gdk_rgba_parse (&colorblue, "#0000dd");
+               gdk_rgba_parse (&colorbacksel1, "#ffffaa");
+               gdk_rgba_parse (&colorbacksel2, "#aaffff");
+               gdk_rgba_parse (&colorsolution, "#990099");
+               cairo_set_line_width (cr, 3);
+               
+               /* set the size of the drawing area */
+               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 ++)
+                       {
+                               /* 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;
+                                               app_data.current_movement = ACROSS;
+                                       }
+                                       else if (app_data.puzzle.start_down_word[i][j] == 1)
+                                       {
+                                               app_data.cur_row = i; 
+                                               app_data.cur_col = j;
+                                               app_data.current_movement = DOWN;
+                                       }
+                               }
+                       
+                               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
+                                  to black */
+                               if (app_data.puzzle.chars[i][j] != '#')
+                                       gdk_cairo_set_source_rgba (cr, &colorback);
+                               
+                               /* if it is a current selection and solution reveal mode is not 
+                                  set then then set the background depending on whether across
+                                  or down movement mode is current */
+                               if (app_data.solution_revealed == false && 
+                                               app_data.cur_row == i && app_data.cur_col == j)
+                               {
+                                       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);
+                               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);
+                               }
+                               
+                               /* if solution is not revealed set the color to normal
+                                  or set it to solution color */
+                               if (app_data.solution_revealed == false)
+                                       gdk_cairo_set_source_rgba (cr, &colorfore);
+                               else
+                                       gdk_cairo_set_source_rgba (cr, &colorsolution);
+                                       
+                               cairo_select_font_face (cr, "sans serif", 
+                                                                               CAIRO_FONT_SLANT_NORMAL,
+                                                                               CAIRO_FONT_WEIGHT_BOLD);
+                               
+                               cairo_set_font_size (cr, 16);
+                               cairo_move_to (cr, j*GRID_PIXELS+GRID_PIXELS/2, 
+                                                               i*GRID_PIXELS+GRID_PIXELS-10);
+                               char ctxt[3];
+                               /* if it is solution mode reveal the answer or else the 
+                                  user input */
+                                 if (app_data.solution_revealed == false)
+                                       sprintf (ctxt, "%c", app_data.char_ans[i][j]);
+                                 else
+                                       if (app_data.puzzle.chars[i][j] != '#')
+                                               sprintf (ctxt, "%c", app_data.puzzle.chars[i][j]);
+                                       else
+                                               sprintf (ctxt, "%c", ' ');
+                               cairo_show_text (cr, (const char*) ctxt);
+
+                       }
+               }
+       }
+                       
+       return FALSE;
+
+}
+
+/* slot for reveal solution menu */
+void on_menu_reveal_solution_activate (GtkMenuItem *item, GtkDrawingArea *area)
+{
+       /* if puzzle solution is password protected ask for the password */
+       if (strlen (app_data.puzzle.hashed_solution_password) > 0)
+       {
+               GtkBuilder *builder;
+               builder = gtk_builder_new ();
+               
+               guint ret = gtk_builder_add_from_resource 
+                                               (builder, 
+                                                       "/org/harishankar/wordblah/wordblah_player.glade", 
+                                                       NULL);          
+               if (ret == 0)
+               {
+                       fprintf (stderr, ERROR_WINDOW);
+                       g_object_unref (builder);
+                       return;
+               }
+                                               
+               GtkWidget *password_dialog = GTK_WIDGET (gtk_builder_get_object 
+                                                                               (builder, "password_dialog"));
+               GtkWidget *password_text = GTK_WIDGET (gtk_builder_get_object 
+                                                                               (builder, "password_text"));
+                                                                               
+               if (password_dialog == NULL)
+               {
+                       fprintf (stderr, ERROR_WINDOW);
+                       g_object_unref (builder);
+                       return;
+               }
+               gtk_window_set_transient_for (GTK_WINDOW(password_dialog), 
+                                                                       GTK_WINDOW(main_window));
+               gtk_dialog_set_default_response (GTK_DIALOG(password_dialog), 
+               GTK_RESPONSE_ACCEPT);
+               gint res = gtk_dialog_run (GTK_DIALOG (password_dialog));
+               if (res == GTK_RESPONSE_ACCEPT)
+               {
+                       const gchar *user_pwd = gtk_entry_get_text 
+                                                                                       (GTK_ENTRY(password_text));
+                       /* if password is correct */
+                       if (verify_solution_password (&app_data.puzzle, user_pwd) == true)
+                               app_data.solution_revealed = true;
+                       /* password is incorrect */
+                       else
+                       {
+                               app_data.solution_revealed = false;
+                               GtkWidget *errordlg ;
+                               errordlg = gtk_message_dialog_new (GTK_WINDOW(main_window), 
+                                                                                               GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                                                               GTK_MESSAGE_ERROR,
+                                                                                               GTK_BUTTONS_CLOSE,
+                                                                                               WRONG_PASSWORD);
+                               gtk_dialog_run (GTK_DIALOG(errordlg));
+                               gtk_widget_destroy (errordlg);
+                       }
+               }
+               
+               gtk_widget_destroy (password_text);
+               gtk_widget_destroy (password_dialog);
+               g_object_unref (builder);
+                       }
+       else
+               app_data.solution_revealed = true;
+
+       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);
+
+}
+
+/* slot for load grid state menu */
+void on_menu_load_grid_state_activate (GtkMenuItem *item, GtkDrawingArea *area)
+{
+       GtkWidget *dialog;
+       GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
+       gint res;
+       dialog = gtk_file_chooser_dialog_new (OPEN_FILE, GTK_WINDOW (main_window),
+                                                                               action,
+                                                                               "_Cancel",
+                                                                               GTK_RESPONSE_CANCEL,
+                                                                               "_Open",
+                                                                               GTK_RESPONSE_ACCEPT,
+                                                                               NULL
+                                                                               );
+                                                                               
+       res = gtk_dialog_run (GTK_DIALOG (dialog));
+       if (res == GTK_RESPONSE_ACCEPT)
+       {
+               char *filename;
+               filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+               load_user_data (&app_data, filename);
+               g_free (filename);
+       }
+       
+       gtk_widget_destroy (dialog);
+       
+       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);
+                               
+       update_clue_items ();
+}
+
+/* slot for save grid state menu */
+void on_menu_save_grid_state_activate (GtkMenuItem *item, gpointer *data)
+{
+       if (app_data.is_loaded == false)
+               return;
+               
+       GtkWidget *dialog;
+       GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
+       gint res;
+       dialog = gtk_file_chooser_dialog_new (SAVE_FILE, GTK_WINDOW(main_window),
+                                                                               action,
+                                                                               "_Cancel",
+                                                                               GTK_RESPONSE_CANCEL,
+                                                                               "_Save",
+                                                                               GTK_RESPONSE_ACCEPT,
+                                                                               NULL);
+       res = gtk_dialog_run (GTK_DIALOG (dialog));
+       if (res == GTK_RESPONSE_ACCEPT)
+       {
+               char *filename;
+               filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+               save_user_data (&app_data, filename);
+               g_free (filename);
+       }
+       
+       gtk_widget_destroy (dialog);
+}
+
+/* slot for exit menu */
+void on_menu_exit_activate (GtkMenuItem *item, gpointer data)
+{
+       gtk_main_quit ();
+}
+
+/* slot for open menu */
+void on_menu_open_activate (GtkMenuItem *item, GtkDrawingArea* area)
+{
+       GtkWidget *dialog;
+       GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
+       gint res;
+       dialog = gtk_file_chooser_dialog_new (OPEN_FILE, GTK_WINDOW(main_window),
+                                                                                        action, 
+                                                                                       "_Cancel", 
+                                                                                       GTK_RESPONSE_CANCEL, 
+                                                                                       "_Open",
+                                                                                       GTK_RESPONSE_ACCEPT,
+                                                                                       NULL);
+       res = gtk_dialog_run (GTK_DIALOG (dialog));
+       if (res == GTK_RESPONSE_ACCEPT)
+       {
+               char *filename;
+               filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog));
+               MainPlayerData temp;
+               reset_player_data (&temp, filename);
+
+               /* if the grid is not frozen then the game cannot be played */
+               if (temp.is_loaded == false)
+               {
+                       GtkWidget *errordlg ;
+                       errordlg = gtk_message_dialog_new (GTK_WINDOW(main_window), 
+                                                                                               GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                                                               GTK_MESSAGE_ERROR,
+                                                                                               GTK_BUTTONS_CLOSE,
+                                                                                               UNFROZEN_GRID_PLAYER);
+                       gtk_dialog_run (GTK_DIALOG(errordlg));
+                       gtk_widget_destroy (errordlg);
+               }
+               else
+               {
+                       app_data = temp;
+                       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 ();           
+               g_free (filename);
+       }
+       
+       gtk_widget_destroy (dialog);
+}
+
+/* slot for about menu */
+void on_menu_about_activate (GtkMenuItem *item, gpointer data)
+{      
+       const char *AUTHOR[] =  {"V.Harishankar", NULL};
+       gtk_show_about_dialog (GTK_WINDOW(main_window), "authors",AUTHOR, 
+                                                       "program-name", PROGRAM_NAME,
+                                                       "copyright", COPYRIGHT,
+                                                       "comments", COMMENTS,
+                                                       "website", WEBSITE,
+                                                       "website-label", WEBSITE_LABEL,
+                                                       "license-type", GTK_LICENSE_GPL_2_0,
+                                                       "version", VERSION,
+                                                       (char*)NULL);
+}
+
+int main (int argc, char *argv [])
+{
+       gtk_init (&argc, &argv);
+       GdkPixbuf *icon;
+       icon = gdk_pixbuf_new_from_resource 
+                               ("/org/harishankar/wordblah/wordblah.svg", NULL);
+       if (icon == NULL)
+               fprintf (stderr, ERROR_ICON);
+       
+       GtkBuilder *builder;
+       builder = gtk_builder_new ();
+       guint ret = gtk_builder_add_from_resource (builder, 
+               "/org/harishankar/wordblah/wordblah_player.glade", NULL);
+       
+       app_data.is_loaded = false;
+       
+       if (ret == 0)
+       {
+               fprintf (stderr, ERROR_WINDOW);
+               g_object_unref (builder);
+               return 1;       
+       }
+       else 
+       {
+               main_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 (main_window != NULL)
+               {
+                       gtk_window_set_default_icon (icon);
+                       
+                       GtkWidget *draw_area = GTK_WIDGET (
+                                                       gtk_builder_get_object(builder, "puzzle_area"));
+                       
+                       /* make drawing area respond to mouse event */
+                       gtk_widget_set_events(draw_area,
+                                       gtk_widget_get_events(draw_area) 
+                                               | GDK_BUTTON_PRESS_MASK);
+               
+                       gtk_builder_connect_signals (builder, NULL);
+                       g_object_unref (builder);
+                       gtk_widget_show (main_window);
+                       gtk_main ();
+                       return 0;
+               }
+               else
+               {
+                       g_object_unref (builder);
+                       fprintf (stderr, ERROR_WINDOW);
+                       return 1;
+               }
+       } 
+}
diff --git a/wordblah_player.glade b/wordblah_player.glade
new file mode 100644 (file)
index 0000000..36c2054
--- /dev/null
@@ -0,0 +1,417 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkListStore" id="store_across_clues">
+    <columns>
+      <!-- column-name ID -->
+      <column type="gint"/>
+      <!-- column-name Clue -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="store_down_clues">
+    <columns>
+      <!-- column-name ID -->
+      <column type="gint"/>
+      <!-- column-name Clue -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkWindow" id="main_window">
+    <property name="can_focus">False</property>
+    <property name="title" translatable="yes">Wordblah Player</property>
+    <property name="default_width">540</property>
+    <property name="default_height">400</property>
+    <signal name="destroy" handler="on_menu_exit_activate" swapped="no"/>
+    <child type="titlebar">
+      <placeholder/>
+    </child>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkMenuBar" id="main_menu">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkMenuItem" id="menu_puzzle">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">_Puzzle</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkMenuItem" id="menu_open">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Open...</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="on_menu_open_activate" object="puzzle_area" swapped="no"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkSeparatorMenuItem">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkMenuItem" id="menu_exit">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">E_xit</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="on_menu_exit_activate" swapped="no"/>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkMenuItem" id="menu_grid">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">_Grid</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkMenuItem" id="menu_save_grid_state">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Save Grid State...</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="on_menu_save_grid_state_activate" swapped="no"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkMenuItem" id="menu_load_grid_state">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Load Grid State...</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="on_menu_load_grid_state_activate" object="puzzle_area" swapped="no"/>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkMenuItem" id="menu_view">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">_View</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkMenuItem" id="menu_reveal_solution">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Reveal Solution...</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="on_menu_reveal_solution_activate" object="puzzle_area" swapped="no"/>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkMenuItem" id="menu_help">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">_Help</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkMenuItem" id="menu_about">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_About...</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="on_menu_about_activate" swapped="no"/>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkPaned">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <child>
+              <object class="GtkScrolledWindow">
+                <property name="width_request">80</property>
+                <property name="height_request">80</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="shadow_type">in</property>
+                <child>
+                  <object class="GtkViewport">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hscroll_policy">natural</property>
+                    <property name="vscroll_policy">natural</property>
+                    <child>
+                      <object class="GtkDrawingArea" id="puzzle_area">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="has_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="has_default">True</property>
+                        <signal name="button-press-event" handler="on_puzzle_area_button_press_event" swapped="no"/>
+                        <signal name="draw" handler="on_puzzle_area_draw" swapped="no"/>
+                        <signal name="key-press-event" handler="on_puzzle_area_key_press_event" swapped="no"/>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="resize">True</property>
+                <property name="shrink">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkPaned">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkScrolledWindow">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkTreeView" id="list_across_clues">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="model">store_across_clues</property>
+                        <property name="enable_search">False</property>
+                        <property name="search_column">0</property>
+                        <property name="show_expanders">False</property>
+                        <child internal-child="selection">
+                          <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="resizable">True</property>
+                            <property name="title" translatable="yes">Id</property>
+                            <child>
+                              <object class="GtkCellRendererText"/>
+                              <attributes>
+                                <attribute name="text">0</attribute>
+                              </attributes>
+                            </child>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkTreeViewColumn" id="ClueAcross">
+                            <property name="resizable">True</property>
+                            <property name="title" translatable="yes">Clues Across</property>
+                            <child>
+                              <object class="GtkCellRendererText"/>
+                              <attributes>
+                                <attribute name="text">1</attribute>
+                                <attribute name="placeholder-text">1</attribute>
+                              </attributes>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="resize">True</property>
+                    <property name="shrink">True</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkTreeView" id="list_down_clues">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="model">store_down_clues</property>
+                        <property name="enable_search">False</property>
+                        <property name="search_column">0</property>
+                        <property name="show_expanders">False</property>
+                        <child internal-child="selection">
+                          <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">
+                            <property name="resizable">True</property>
+                            <property name="title" translatable="yes">Id</property>
+                            <child>
+                              <object class="GtkCellRendererText"/>
+                              <attributes>
+                                <attribute name="text">0</attribute>
+                              </attributes>
+                            </child>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkTreeViewColumn" id="ClueDown">
+                            <property name="resizable">True</property>
+                            <property name="title" translatable="yes">Clues Down</property>
+                            <child>
+                              <object class="GtkCellRendererText"/>
+                              <attributes>
+                                <attribute name="text">1</attribute>
+                              </attributes>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="resize">True</property>
+                    <property name="shrink">True</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="resize">True</property>
+                <property name="shrink">True</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkDialog" id="password_dialog">
+    <property name="can_focus">False</property>
+    <property name="title" translatable="yes">Password</property>
+    <property name="resizable">False</property>
+    <property name="hide_titlebar_when_maximized">True</property>
+    <property name="type_hint">dialog</property>
+    <property name="transient_for">main_window</property>
+    <child type="titlebar">
+      <placeholder/>
+    </child>
+    <child internal-child="vbox">
+      <object class="GtkBox">
+        <property name="can_focus">False</property>
+        <property name="margin_left">10</property>
+        <property name="margin_right">10</property>
+        <property name="margin_top">10</property>
+        <property name="margin_bottom">10</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_stock">True</property>
+                <property name="always_show_image">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button2">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_stock">True</property>
+                <property name="always_show_image">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Password for revealing solution</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="password_text">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="max_length">256</property>
+            <property name="visibility">False</property>
+            <property name="invisible_char">●</property>
+            <property name="activates_default">True</property>
+            <property name="input_purpose">password</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-6">button1</action-widget>
+      <action-widget response="-3">button2</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/wordblox.c b/wordblox.c
deleted file mode 100644 (file)
index f30c039..0000000
+++ /dev/null
@@ -1,438 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-
-#include "wordblox.h"
-#include "constantstrings.h"
-
-/* export the clues to a text file */
-void do_export_clues (Puzzle *p)
-{
-       if (p->grid_frozen == false)
-       {
-               printf (UNFROZEN_GRID);
-               char ch = getchar ();
-               return;
-       }
-       char fname[256];
-       printf (INPUT_FILE);
-       fgets (fname, 256, stdin);
-       if (strlen(fname) == 1)
-               return;
-       char *filename = strtok (fname, "\n");
-       
-       export_clues (p, filename);
-       printf (FILE_SAVED);
-       char ch = getchar ();
-}
-
-/* export the puzzle to a png file */
-void do_export_puzzle (Puzzle *p)
-{
-       if (p->grid_frozen == false)
-       {
-               printf (UNFROZEN_GRID);
-               char ch = getchar ();
-               return;
-       }
-       char fname[256];
-       printf (INPUT_FILE);
-       fgets (fname, 256, stdin);
-       if (strlen (fname) == 1)
-               return;
-       char* filename = strtok (fname, "\n");
-
-       printf (INPUT_EXPORT_ANSWERS);
-       char ans[3];
-       fgets (ans, 3, stdin);
-       bool solution;
-       solution = (toupper (ans[0]) == 'Y') ? true : false;
-               
-       export_grid_image (p, filename, solution);
-       printf (FILE_SAVED);
-       char ch = getchar ();
-}
-
-/* reset the grid */
-void do_reset_puzzle (Puzzle *p)
-{
-       int grid_size = p->grid_size;
-       printf (INPUT_CONFIRM_RESET);
-       char conf[3];
-       fgets (conf, 3, stdin);
-       if (toupper (conf[0]) == 'Y')
-               init_puzzle (p, grid_size);
-
-        print_puzzle (p);
-        char ch = getchar ();
-}
-
-/* set the solution password for the puzzle */
-void do_set_solution_password (Puzzle *p)
-{
-       char* password;
-       password = getpass (INPUT_PASSWORD);
-       /* if empty reset the password to nothing */
-       if (strlen(password) == 0)
-       {
-               set_solution_password (p, "\0");
-               printf (SOLUTION_PASSWORD_RESET);
-               char ch = getchar ();
-       }
-       /* set the password */
-       else 
-       {
-               set_solution_password (p, (const char* )password);
-               printf (PASSWORD_SET);
-               char ch = getchar ();
-       }
-}
-/* set the master (editing) password for the puzzle */
-void do_set_master_password (Puzzle *p)
-{
-       char* password;
-       password = getpass (INPUT_PASSWORD);
-       /* if empty reset the password to nothing */
-       if (strlen(password) == 0)
-       {
-               set_master_password (p, "\0");
-               printf (MASTER_PASSWORD_RESET);
-               char ch = getchar ();
-       }
-       /* set the password */
-       else 
-       {
-               set_master_password (p, (const char* )password);
-               printf (PASSWORD_SET);
-               char ch = getchar ();
-       }
-}
-
-/* set clue for a word - only for frozen grid */
-void do_set_clue_word (Puzzle *p, enum ORIENTATION orient)
-{
-       print_puzzle (p);
-       if (p->grid_frozen == false)
-       {
-               printf (UNFROZEN_GRID);
-               char ch = getchar ();
-               return;
-       }
-       int index;
-       String clue; 
-       printf (INPUT_INDEX);
-       index = get_num ();
-       printf (INPUT_CLUE);
-       fgets (clue, MAX_CLUE_LENGTH, stdin);
-       if (strlen (clue) == 1)
-               return;
-       char* cl = strtok (clue, "\n");
-       
-       bool res;
-       res = set_clue (p, cl, index, orient);
-
-       if (res == false)
-       {
-               printf (NO_WORD_INDEX);
-               char ch = getchar ();
-       }
-}
-
-/* clear a cell in the grid */
-void do_clear_cell (Puzzle *p)
-{
-       print_puzzle (p);
-       if (p->grid_frozen == true) 
-       {
-               printf (FROZEN_GRID);
-               char ch = getchar ();
-               return;
-       }
-       int row, col;
-       printf (INPUT_ROW);
-       row = get_num (); 
-       printf (INPUT_COL);
-       col = get_num ();
-       if (row >= p->grid_size || col >= p->grid_size)
-       {
-               printf (EXCEED_GRID_SIZE);
-               char ch = getchar ();
-               return;
-       }
-       p->chars[row][col] = ' ';
-       print_puzzle (p);
-       
-       char ch = getchar ();
-}
-
-/* add a down word to the grid */
-void do_add_down_word (Puzzle *p)
-{
-       print_puzzle (p);
-       if (p->grid_frozen == true) 
-       {
-               printf (FROZEN_GRID);
-               char ch = getchar ();
-               return;
-       }
-       char wd[MAX_PUZZLE_SIZE];
-       int row, col;
-       printf (INPUT_WORD);
-       fgets (wd, MAX_PUZZLE_SIZE, stdin);
-       char *word = is_valid_word (wd);
-       if (word == NULL)
-       {
-               printf (INVALID_WORD);
-               char ch = getchar ();
-               return;
-       }
-       printf (INPUT_ROW);
-       row = get_num ();
-       printf (INPUT_COL);
-       col = get_num ();
-       if (row >= p->grid_size || col >= p->grid_size) 
-       {
-               printf (EXCEED_GRID_SIZE);
-               char ch = getchar ();
-               return;
-       }
-       if (strlen (word) > (p->grid_size - row))
-       {
-               printf (WORD_TOO_LONG);
-               char ch = getchar ();
-               return;
-       }
-       
-       for (int i = row; i < row + strlen(word); i ++)
-               p->chars[i][col] = toupper(word[i - row]);
-       
-       print_puzzle (p);
-       char ch = getchar ();
-}
-
-/* add an across word to the grid */
-void do_add_across_word (Puzzle *p)
-{
-       print_puzzle (p);
-       if (p->grid_frozen == true) 
-       {
-               printf (FROZEN_GRID);
-               char ch = getchar ();
-               return;
-       }
-       char wd[MAX_PUZZLE_SIZE];
-       int row, col;   
-       printf (INPUT_WORD);
-       fgets (wd, MAX_PUZZLE_SIZE, stdin);
-       char *word = is_valid_word (wd);
-       if (word == NULL)
-       {
-               printf (INVALID_WORD);
-               char ch = getchar ();
-               return;
-       }
-       printf (INPUT_ROW);
-       row = get_num ();
-       printf (INPUT_COL);
-       col = get_num ();
-       if (row >= p->grid_size || col >= p->grid_size)
-       {
-               printf (EXCEED_GRID_SIZE);
-               char ch = getchar ();
-               return;
-       }
-       
-       if (strlen (word) > (p->grid_size - col))
-       {
-               printf (WORD_TOO_LONG);
-               char ch = getchar ();
-               return;
-       }
-       
-       for (int i = col; i < col+strlen (word); i ++)
-               p->chars[row][i] = toupper(word[i - col]);
-               
-       print_puzzle (p);
-       char ch = getchar ();
-}
-/* confirm exit */
-bool do_confirm_exit ()
-{
-       printf (INPUT_CONFIRM_EXIT);
-       char res[3];
-       fgets (res, 3, stdin);
-       if (toupper(res[0]) == 'Y')
-               return true;
-       else
-               return false;
-} 
-
-/* main loop for the puzzle editor */
-void puzzle_editor_loop (Puzzle *p, const char *filename) 
-{
-       bool loop = true;
-       while (loop) 
-       {
-               char puzzle_title[60];
-               sprintf (puzzle_title, "%s - %s", PUZZLE_MENU_TITLE, filename);
-               print_menu (WHITE, BLUE, puzzle_title, PUZZLE_EDIT_MENU, 15, 50);
-               printf (INPUT_CHOICE);
-               int ch = get_num ();
-               switch (ch)
-               {
-                       case 1: print_puzzle (p);
-                                       char ch = getchar ();
-                                       break;
-                       case 2: do_add_across_word (p);
-                                       break;
-                       case 3: do_add_down_word (p);
-                                       break;
-                       case 4: do_clear_cell (p);
-                                       break;
-                       case 5: freeze_puzzle (p);
-                                       print_puzzle (p);
-                                       ch = getchar ();
-                                       break;
-                       case 6: unfreeze_puzzle (p);
-                                       print_puzzle (p);
-                                       ch = getchar ();
-                                       break;
-                       case 7: do_set_clue_word (p, ACROSS);
-                                       break;
-                       case 8: do_set_clue_word (p, DOWN);
-                                       break;
-                       case 9: save_puzzle (p, filename);
-                                       printf ("%s\n",FILE_SAVED);
-                                       ch = getchar ();
-                                       break;
-                       case 10: do_set_master_password (p);
-                                        break;
-                       case 11: do_set_solution_password (p);
-                                        break;
-                       case 12: do_reset_puzzle (p);
-                                        break;
-                       case 13: do_export_puzzle (p);
-                                        break;
-                       case 14: do_export_clues (p);
-                                        break;
-                       case 15: loop = ! do_confirm_exit ();
-                                        break;
-               }
-       }
-}
-
-/* open an existing puzzle */
-void do_open_puzzle (const char *filename) 
-{
-       Puzzle p;
-       /* if no filename is provided, get it from command line */
-       if (filename == NULL) 
-       {
-               printf (INPUT_FILE);
-               char fname[256];
-               fgets(fname, 256, stdin);
-               if (strlen (fname) == 1)
-                       return;
-               filename = strtok (fname, "\n");
-       }
-
-       p = load_puzzle (filename);
-       
-       if (strcmp (p.hashed_master_password, "\0") != 0)
-       {
-               char *passwd;
-               passwd = getpass (INPUT_PASSWORD);
-               if (strlen (passwd) == 0)
-                       return;
-                                       
-               if (verify_master_password (&p, (const char*) passwd))
-                       puzzle_editor_loop (&p, filename);
-               else
-               {
-                       printf (WRONG_PASSWORD);
-                       char ch = getchar ();
-               } 
-       }
-       else
-               puzzle_editor_loop (&p, filename);
-}
-
-/* create a new blank puzzle */
-void do_new_puzzle (char *filename, int size) 
-{
-       Puzzle p; 
-       /* if filename is not provided get it from command line */
-       if (filename == NULL)
-       {
-               printf (INPUT_FILE);
-               char fname[256];
-               fgets (fname, 256, stdin);
-               if (strlen (fname) == 1)
-                       return;
-               filename = strtok (fname, "\n"); 
-       }
-       /* if no size is specified get it from command line */  
-       if (size == -1)
-       {
-               printf (INPUT_GRID_SIZE);
-               size = get_num ();
-       }
-       
-       if (size > MAX_PUZZLE_SIZE) 
-       { 
-               printf (EXCEED_MAX_GRID_SIZE);
-               char c = getchar (); 
-       }
-       else
-       {
-               init_puzzle (&p, size);
-               puzzle_editor_loop (&p, filename);
-       }
-}
-
-/* The main loop of the program */
-int main_loop () 
-{
-       /* Print the main menu */
-       while (1)
-       {
-               print_menu (WHITE, BLUE, MAIN_MENU_TITLE, MAIN_MENU, 3, 50);
-               printf (INPUT_CHOICE);
-               int ch = get_num ();
-               switch (ch)
-               {
-                       case 1: do_new_puzzle (NULL, -1);
-                                       break;
-                       case 2: do_open_puzzle (NULL);
-                                       break;
-                       case 3: exit (0);
-               }
-       }
-}
-
-int main (int argc, char* argv[]) 
-{
-       if (argc >= 2)
-       {
-               Puzzle p;
-               switch (argc)
-               {
-                       case 2 : do_open_puzzle (argv[1]);
-                                        break;
-                       case 4 : if (strcmp (argv[2], "new") == 0)
-                                        {
-                                               int grid_size = atoi (argv[3]);
-                                               do_new_puzzle (argv[1], grid_size);
-                                               break;
-                                        }
-                       default: fprintf (stderr, USAGE_LINE_1, argv[0]);
-                                        fprintf (stderr, USAGE_LINE_2);
-                                        fprintf (stderr, USAGE_LINE_3);
-                                        exit (3);
-               }
-       }
-       return (main_loop ());
-}
diff --git a/wordblox.gresource.xml b/wordblox.gresource.xml
deleted file mode 100644 (file)
index ae2f5f0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-
-<?xml version="1.0" encoding="UTF-8"?>
-<gresources>
-  <gresource prefix="/org/harishankar/wordblox">
-    <file preprocess="xml-stripblanks">wordblox_player.glade</file>
-    <file>wordblox.svg</file>
-  </gresource>
-</gresources>
diff --git a/wordblox.h b/wordblox.h
deleted file mode 100644 (file)
index 7519ff4..0000000
+++ /dev/null
@@ -1,1032 +0,0 @@
-#ifndef __WORDBLOX_H
-#define __WORDBLOX_H
-#define _XOPEN_SOURCE
-#include <unistd.h>
-#include <stdbool.h>
-#include <string.h>
-#include <ctype.h>
-#include <gd.h>
-#include <gdfontmb.h>
-#include <gdfontg.h>
-#include <zlib.h>
-#include <openssl/conf.h>
-#include <openssl/evp.h>
-#include <openssl/err.h>
-#include "constantstrings.h"
-
-#define MAX_PUZZLE_SIZE 25
-#define MAX_CLUE_LENGTH 150
-#define GRID_PIXELS 37
-
-/* Enum to define terminal colours */
-enum COLOR {
-       BLACK = 0,
-       RED= 1,
-       GREEN=2,
-       YELLOW=3,
-       BLUE=4,
-       MAGENTA=5,
-       CYAN=6,
-       WHITE=7
-};
-
-enum ATTR {
-       NORMAL = 23,
-       BOLD=1
-};
-
-enum ORIENTATION {
-       ACROSS=1,
-       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 */
-typedef struct {
-       char chars[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
-       int start_across_word[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
-       int start_down_word[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
-       String clue_across[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
-       String clue_down[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
-       int grid_size;
-       bool grid_frozen;
-       char hashed_master_password[256];
-       char hashed_solution_password[256];
-} Puzzle;
-
-/* The player data struct type - for the player app */
-typedef struct {
-       Puzzle puzzle;
-       char filename[65535];
-       bool is_loaded;
-       char char_ans[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
-       int cur_row;
-       int cur_col;
-       bool solution_revealed;
-       enum ORIENTATION current_movement;
-} MainPlayerData;
-
-/* compute the hash of a password */
-void digest_message(const unsigned char *message, 
-       size_t message_len, unsigned char **digest, unsigned int *digest_len)
-{
-       EVP_MD_CTX *mdctx;
-
-       if((mdctx = EVP_MD_CTX_new()) == NULL)
-               goto err;
-
-       if(1 != EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL))
-               goto err;
-
-       if(1 != EVP_DigestUpdate(mdctx, message, message_len))
-               goto err;
-
-       if((*digest = (unsigned char *)
-               OPENSSL_malloc(EVP_MD_size(EVP_sha256()))) == NULL)
-               goto err;
-
-       if(1 != EVP_DigestFinal_ex(mdctx, *digest, digest_len))
-               goto err;
-
-       EVP_MD_CTX_free(mdctx);
-       return;
-err:
-       EVP_MD_CTX_free(mdctx);
-       ERR_print_errors_fp(stderr);    
-       exit (2);
-}
-
-/* convert the hashed binary password to hexadecimal representation and
-   free the hashed binary password */
-void to_hexadecimal (char *hex, unsigned char *binary_pwd, unsigned int len)
-{
-       char buf[3];
-       /* keep reference to beginning of the hashed password */
-       unsigned char *binary_pw_begin = binary_pwd;
-       for (int i = 0; i < len; i ++)
-       {
-               sprintf (buf, "%02x", (*binary_pwd)&0xff);
-               strcat (hex, buf);
-               binary_pwd ++;
-       }
-       /* free the hashed password */
-       OPENSSL_free (binary_pw_begin); 
-}
-
-/* get a number from the user */
-int get_num ()
-{
-       char s[5];
-       fgets (s, 5, stdin);
-       int n = atoi (s);
-       return n;
-}
-
-/* verify solution password */
-bool verify_solution_password (Puzzle *p, const char* password)
-{
-       /* no password set */
-       if (strcmp (p->hashed_solution_password, "\0") == 0)
-               return true;
-               
-       /* hash the user input password and compare it with the stored password */
-       unsigned char* hashed_sol_password;
-       unsigned int len;
-       digest_message ((const unsigned char *)password, strlen(password),
-                                               &hashed_sol_password, &len);
-       char hashed_hex_pwd[256] = { (char) NULL };
-       to_hexadecimal (hashed_hex_pwd, hashed_sol_password, len);
-       
-       if (strcmp (p->hashed_solution_password, hashed_hex_pwd) == 0)
-               return true;
-       
-       return false;
-}
-
-
-/* verify master password */
-bool verify_master_password (Puzzle *p, const char* password)
-{
-       /* no password set */
-       if (strcmp (p->hashed_master_password, "\0") == 0)
-               return true;
-               
-       /* hash the user input password and compare it with the stored password */
-       unsigned char* hashed_mas_password;
-       unsigned int len;
-       digest_message ((const unsigned char *)password, strlen(password),
-                                               &hashed_mas_password, &len);
-       char hashed_hex_pwd[256] = { (char) NULL };
-       to_hexadecimal (hashed_hex_pwd, hashed_mas_password, len);
-       
-       if (strcmp (p->hashed_master_password, hashed_hex_pwd) == 0)
-               return true;
-       
-       return false;
-}
-
-/* Set or reset solution password for puzzle */
-void set_solution_password (Puzzle *p, const char *password)
-{
-       /* if it is a null string, reset the password */
-       if (strcmp (password, "\0") == 0)
-               strcpy (p->hashed_solution_password, "\0");
-       else 
-       {
-
-               unsigned char* hashedpwd;
-               unsigned int len;
-               digest_message ((const unsigned char *)password, strlen(password),
-                                               &hashedpwd, &len);
-               /* the hashedpwd contains binary data - we will convert it to 
-                  hexadecimal data and store in file */
-
-               to_hexadecimal (p->hashed_solution_password, hashedpwd, len);
-       }
-}
-
-/* Set or reset master password for puzzle */
-void set_master_password (Puzzle *p, const char *password)
-{
-       /* if it is a null string, reset the password */
-       if (strcmp (password, "\0") == 0)
-               strcpy (p->hashed_master_password, "\0");
-       else 
-       {
-
-               unsigned char* hashedpwd;
-               unsigned int len;
-               digest_message ((const unsigned char *)password, strlen(password),
-                                               &hashedpwd, &len);
-               /* the hashedpwd contains binary data - we will convert it to 
-                  hexadecimal data and store in file */
-
-               to_hexadecimal (p->hashed_master_password, hashedpwd, len);
-       }
-}
-
-/* Output the clues to text file */
-void export_clues (Puzzle *p, const char *filename)
-{
-       FILE *outfile = fopen (filename, "w");
-       if (outfile == NULL)
-       {
-               fprintf (stderr, "%s\n", ERROR_WRITING_FILE);
-               exit (1);
-       }
-       /* first the across clues */
-       fprintf (outfile, "ACROSS CLUES\n");
-       for (int i = 0; i < p->grid_size; i ++)
-       {
-               for (int j = 0; j < p->grid_size; j ++)
-               {
-                       if (p->start_across_word[i][j] != -1)
-                               fprintf (outfile, "%d - %s\n", p->start_across_word[i][j],
-                                                       p->clue_across[i][j]);
-               }
-       }
-       /* now the down clues */
-       fprintf (outfile, "DOWN CLUES\n");
-       for (int i = 0; i < p->grid_size; i ++)
-       {
-               for (int j = 0; j < p->grid_size; j ++)
-               {
-                       if (p->start_down_word[i][j] != -1)
-                               fprintf (outfile, "%d - %s\n", p->start_down_word[i][j],
-                                                       p->clue_down[i][j]);
-               }
-       }
-       fclose (outfile);
-}
-
-/* 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 * GRID_PIXELS;
-       FILE * outfile = fopen (filename, "wb");
-       if (outfile == NULL)
-       {
-               fprintf (stderr, "%s\n", ERROR_WRITING_FILE);
-               exit (1);
-       }
-       
-       gdImagePtr img = gdImageCreate (img_size, img_size);
-       gdImageColorAllocate (img, 255,255,255);
-       int black = gdImageColorAllocate (img, 0, 0, 0);
-       int blue = gdImageColorAllocate (img, 0, 0, 216);
-       gdFontPtr sm_fnt = gdFontGetMediumBold ();
-       gdFontPtr lg_fnt = gdFontGetGiant ();
-       
-       for (int i = 0; i < p->grid_size; i ++)
-       {
-               for (int j = 0; j < p->grid_size; j++)
-               {
-                       /* if it is a block, draw the black square */
-                       if (p->chars[i][j] == '#')
-                               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*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 */
-                               if (p->start_across_word[i][j] != -1 || 
-                                               p->start_down_word[i][j] != -1)
-                               {
-                                       if (p->start_across_word[i][j] != -1)
-                                       {
-                                               char str[5];
-                                               sprintf (str, "%d", p->start_across_word[i][j]);
-                                               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*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*GRID_PIXELS+15, 
-                                                                       i*GRID_PIXELS+10, p->chars[i][j], black);
-                               }
-                       }
-               }
-       }
-       
-       gdImagePng (img, outfile);
-       gdImageDestroy (img);
-       fclose (outfile);
-}
-
-/* Set the terminal colour */
-void set_color (enum COLOR fg, enum COLOR bg, enum ATTR at) {
-       printf ("\x1B[%d;%d;%dm", fg+30, bg+40, at);
-}
-
-/* Reset the terminal colour */
-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) 
-{
-       if (r == 0) return true;
-       if (p->chars[r-1][c] == ' ' || p->chars[r-1][c] == '#') return true;
-       return false;
-}
-/* check if next row is blank or not */
-bool next_row_blank (Puzzle *p, int r, int c)
-{
-       if (r == p->grid_size - 1) return true;
-       if (p->chars[r+1][c] == ' ' || p->chars[r+1][c] == '#') return true;
-       return false;
-}
-/* check if previous col is blank or not */
-bool prev_col_blank (Puzzle *p, int r, int c)
-{
-       if (c == 0) return true;
-       if (p->chars[r][c-1] == ' ' || p->chars[r][c-1] == '#') return true;
-       return false; 
-}
-/* check if the next col is blank or not */
-bool next_col_blank (Puzzle *p, int r, int c)
-{
-       if (c == p->grid_size -1) return true;
-       if (p->chars[r][c+1] == ' ' || p->chars[r][c+1] == '#') return true;
-       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)
-{
-       for (int i = 0; i < p->grid_size; i ++)
-       {
-               for (int j = 0; j < p->grid_size; j ++)
-               {
-                       if (p->chars[i][j] == '#')
-                               p->chars[i][j] = ' ';
-                       
-                       p->start_across_word[i][j] = -1;
-                       p->start_down_word[i][j] = -1;
-               }
-       }
-       p->grid_frozen = false;
-}
-
-/* freeze the grid - make editing impossible because it finalizes the
-   across and down words in the grid */
-void freeze_puzzle (Puzzle *p)
-{              
-       int word_num = 1;
-       bool across_word_start, down_word_start;
-       for (int i = 0; i < p->grid_size; i ++)
-       {
-               for (int j = 0; j < p->grid_size; j++)
-               {
-                       across_word_start = false; 
-                       down_word_start = false;
-                       /* if it is a blank cell - cover it with a block */
-                       if (p->chars[i][j] == ' ' || p->chars[i][j] == '#')
-                               p->chars[i][j] = '#';
-                       /* it is not a blank cell - check all possibilities */
-                       else 
-                       {
-                               bool prev_row = prev_row_blank (p, i, j);
-                               bool next_row = next_row_blank (p, i, j);
-                               bool prev_col = prev_col_blank (p, i, j);
-                               bool next_col = next_col_blank (p, i, j);
-                               if (prev_row && ! next_row)
-                                       down_word_start = true;
-                               if (prev_col && ! next_col)
-                                       across_word_start = true;
-                       }
-                       
-                       if (across_word_start == true)
-                               p->start_across_word[i][j] = word_num;
-                       else 
-                               p->start_across_word[i][j] = -1;
-                       if (down_word_start == true)
-                               p->start_down_word[i][j] = word_num;
-                       else
-                               p->start_down_word[i][j] = -1;
-                       if (across_word_start == true || down_word_start == true)
-                               word_num ++;
-               }
-       }
-       p->grid_frozen = true;
-}
-
-/* reset the entire grid */
-void init_puzzle (Puzzle *p, int grid_size) 
-{
-       p->grid_size = grid_size;
-       p->grid_frozen = false;
-       for (int i = 0; i < p->grid_size; i ++)
-       {
-               for (int j = 0; j < p->grid_size; j ++) 
-               {
-                       p->chars[i][j] = ' ';
-                       p->start_across_word[i][j] = -1;
-                       p->start_down_word[i][j] = -1;
-                       strcpy (p->clue_across[i][j], "");
-                       strcpy (p->clue_down[i][j], "");                        
-               }
-       }
-       strcpy (p->hashed_master_password, "\0");
-       strcpy (p->hashed_solution_password, "\0");
-       
-}
-
-/* save the puzzle to a file */
-void save_puzzle (Puzzle *puzzle, const char* file) 
-{
-       FILE *outfile;
-       /* First output the uncompressed contents to a temp file */
-       outfile = tmpfile ();
-       if (outfile == NULL)
-       {
-               fprintf (stderr, "%s\n", ERROR_WRITING_FILE);
-               exit (1);
-       }
-       /* grid size is the first field */
-       fprintf (outfile, "%d\n", puzzle->grid_size);
-       /* whether grid is frozen or not */
-       fprintf (outfile, "%d\n", puzzle->grid_frozen);
-       /* the hashed password */
-       fprintf (outfile, "%s\n", puzzle->hashed_master_password);
-       /* the hashed_solution_password */
-       fprintf (outfile, "%s\n", puzzle->hashed_solution_password);
-       
-       /* First output the grid characters columns/rows */
-       for (int i = 0; i < puzzle->grid_size; i ++)
-       {
-               for (int j = 0; j < puzzle->grid_size; j ++)
-                       fprintf (outfile, "%c", puzzle->chars[i][j]);
-               fprintf (outfile, "\n");
-       }
-       
-       /* Next output the start across/down numbers */
-       for (int i = 0; i < puzzle->grid_size; i ++)
-       {
-               for (int j = 0; j < puzzle->grid_size; j++)
-               {
-                       fprintf (outfile, "%d ", puzzle->start_across_word[i][j]);
-                       fprintf (outfile, "%d ", puzzle->start_down_word[i][j]);
-               }
-               fprintf (outfile, "\n");
-       }
-       
-       /* Output the across clues */
-       fprintf (outfile, "ACROSS\n");
-       /* Search the grid for across words */
-       for (int i = 0; i < puzzle->grid_size; i ++)
-       {
-               for (int j = 0; j < puzzle->grid_size; j++)
-               {
-                       /* if it is an across word, then put the word index followed by
-                       tab character (as separator) and the clue */
-                       if (puzzle->start_across_word[i][j] != -1)
-                               fprintf (outfile, "%d\t%s\n", puzzle->start_across_word[i][j], 
-                                       puzzle->clue_across[i][j]);
-               }
-       }
-       
-       /* Output the down clues */
-       fprintf (outfile, "DOWN\n");
-       /* Search the grid for down words */
-       for (int i = 0; i < puzzle->grid_size; i ++)
-       {
-               for (int j = 0; j < puzzle->grid_size; j++)
-               {
-                       /* same as across word, put the word index followed by the tab
-                       character and then the clue */
-                       if (puzzle->start_down_word[i][j] != -1)
-                               fprintf (outfile, "%d\t%s\n", puzzle->start_down_word[i][j], 
-                                       puzzle->clue_down[i][j]);
-               }
-       }
-       
-       /* Flush the buffer and rewind to beginning - to read and save into 
-       gzip compressed file */
-       fflush (outfile);
-       fseek (outfile, 0, 0);
-                       
-       /* now compress the file and save it to destination file */
-       gzFile outdestfile = gzopen (file, "wb");
-       if (outdestfile == NULL)
-       {
-               fprintf (stderr, "%s\n", ERROR_WRITING_FILE);
-               fclose (outfile);
-               exit (1);
-       }
-       char buf[128];
-       int num = fread (buf, sizeof(char), sizeof(char)*128, outfile);
-       while (num > 0)
-       {
-               int res = gzwrite (outdestfile, buf, num*sizeof(char) );
-               if (res == 0)
-               {
-                       fprintf (stderr, "%s %s\n", ERROR_WRITING_FILE, COMPRESSED);
-                       fclose (outfile);
-                       exit (1);
-               }
-               num = fread (buf, sizeof(char), sizeof(char)*128, outfile);
-       }
-       gzclose (outdestfile);
-       fclose (outfile);
-
-}
-
-/* read the puzzle from a file */
-Puzzle load_puzzle (const char* file) 
-{
-       /* First open the GZip file */
-       gzFile insourcefile = gzopen (file, "rb");
-       if (insourcefile == NULL)
-       {
-               fprintf (stderr, "%s %s\n", ERROR_READING_FILE, COMPRESSED);
-               exit (1);
-       }
-       /* Open a temporary file to uncompress the contents */
-       FILE *infile = tmpfile ();
-       if (infile == NULL)
-       {
-               fprintf (stderr, "%s\n", ERROR_READING_FILE);
-               exit (1);       
-       }
-       /* Put the uncompressed content to the temp file */
-       char buf[128];
-       int num = 0;
-       num = gzread (insourcefile, buf, 128);
-       while (num > 0)
-       {
-               int res = fwrite (buf, 1, num, infile);
-               if (res == 0)
-               {
-                       fprintf (stderr, "%s\n", ERROR_READING_FILE);
-                       fclose (infile);
-                       gzclose (insourcefile);
-                       exit (1);
-               }
-               num = gzread (insourcefile, buf, 128);
-       }
-       /* Close the gzip file */
-       gzclose (insourcefile);
-       /* Flush the temp file buffer and rewind to beginning */
-       fflush (infile);
-       fseek (infile, 0, 0);
-
-       /* Read the temporary file contents to the structure Puzzle */
-       Puzzle p;
-       char line[MAX_CLUE_LENGTH+10];
-       fgets (line, MAX_CLUE_LENGTH + 10, infile);
-       p.grid_size = atoi (line);
-       fgets (line, MAX_CLUE_LENGTH + 10, infile);
-       p.grid_frozen = atoi (line) == 0 ? false : true ;
-       fgets (line, MAX_CLUE_LENGTH + 10, infile);
-       if (strlen (line) != 1)
-               strcpy (p.hashed_master_password, strtok (line, "\n"));
-       else
-               strcpy (p.hashed_master_password, "\0");
-       fgets (line, MAX_CLUE_LENGTH + 10, infile);
-       if (strlen (line) != 1)
-               strcpy (p.hashed_solution_password, strtok (line, "\n"));
-       else
-               strcpy (p.hashed_solution_password, "\0");
-       
-       /* read each character of the grid */
-       for (int i = 0; i < p.grid_size; i ++ )
-       {
-               fgets (line, MAX_CLUE_LENGTH + 10, infile);
-               for (int j = 0; j < p.grid_size; j ++)
-                       p.chars[i][j] = line[j];
-       }
-       /* read the word numbers */
-       for (int i = 0; i < p.grid_size; i ++)
-       {
-               fgets (line, MAX_CLUE_LENGTH + 10, infile);
-               char *token = strtok (line, " ");
-               for (int j = 0; j < p.grid_size; j ++)
-               {
-                       if (token != NULL) 
-                               p.start_across_word[i][j] = atoi (token);
-                       token = strtok (NULL, " ");
-                       if (token != NULL)
-                               p.start_down_word[i][j] = atoi (token);
-                       token = strtok (NULL, " ");
-               }
-       }
-       /* read the clues */
-       fgets (line, MAX_CLUE_LENGTH + 10, infile);
-       
-       /* across clues */
-       char clues[100][MAX_CLUE_LENGTH];
-       int word_num[100];
-       int c = 0;
-       /* first read the across clues from file */
-       while (1)
-       {
-               fgets (line, MAX_CLUE_LENGTH + 10, infile);
-               /* if reached the end of across clues */
-               if (strcmp (line, "DOWN\n") == 0)
-                       break;
-               word_num[c] = atoi (strtok (line, "\t"));
-               char *cl = strtok (NULL, "\n");
-               if (cl != NULL)         
-                       strcpy (clues[c], cl);
-               else
-                       strcpy (clues[c], "\0");
-               c++;
-       }
-       /* set the clue to the correct cell in grid */
-       for (int i = 0; i < p.grid_size; i ++)
-       {
-               for (int j = 0; j < p.grid_size; j ++)
-               {
-                       for (int r = 0; r < c; r ++)
-                               if (p.start_across_word[i][j] == word_num[r])
-                                       strcpy (p.clue_across[i][j], clues[r]);
-               }
-       }
-
-       /* down clues */
-       c = 0;
-       while (fgets (line, MAX_CLUE_LENGTH + 10, infile))
-       {
-               word_num[c] = atoi (strtok (line, "\t"));
-               char* cl = strtok (NULL, "\n");
-               if (cl != NULL)
-                       strcpy (clues[c], cl);
-               else
-                       strcpy (clues[c], "\0");
-               c++;
-       }
-       for (int i = 0; i < p.grid_size; i ++)
-       {
-               for (int j = 0; j < p.grid_size; j ++)
-               {
-                       for (int r = 0; r < c; r ++)
-                               if (p.start_down_word[i][j] == word_num[r])
-                                       strcpy (p.clue_down[i][j], clues[r]);
-               }
-       }
-
-       fclose (infile);
-       return p;
-}
-
-/* display the puzzle */ 
-void print_puzzle (Puzzle *p) 
-{
-       printf ("\n");
-       set_color (WHITE, CYAN, NORMAL);
-       printf ("    ");
-       for (int i = 0; i < p->grid_size; i ++)
-               printf ("%3d", i);
-       reset_color ();
-       printf("\n");
-       for (int i = 0; i < p->grid_size; i ++)
-       {
-               set_color (WHITE, CYAN, NORMAL);
-               printf ("%3d ", i);
-               for (int j = 0; j < p->grid_size; j ++) 
-               {
-                       if (p->chars[i][j] == '#') {
-                               set_color (WHITE, BLACK, NORMAL);
-                               printf ("   ");
-                       }
-                       else 
-                       {
-                               if (p->start_across_word[i][j] != -1 || 
-                                       p->start_down_word[i][j] != -1) 
-                               {
-                                       set_color (BLUE, WHITE, NORMAL);
-                                       if (p->start_across_word[i][j] != -1)
-                                               printf ("%-2d", p->start_across_word[i][j]);
-                                       else 
-                                               printf ("%-2d", p->start_down_word[i][j]);
-                               }
-                               else
-                               {
-                                       set_color (BLACK, WHITE,NORMAL);
-                                       printf ("  ");
-                               }
-                                       
-                               set_color (BLACK, WHITE, BOLD);
-                               printf ("%c", p->chars[i][j]);
-                       }
-                       reset_color ();
-               }
-               printf ("\n");
-       }
-       /* print the clues if set */
-       if (p->grid_frozen == true) 
-       {
-               printf ("\x1B[1mACROSS - CLUES\x1B[0m\n");
-               for (int i = 0; i < p->grid_size; i ++)
-               {
-                       for (int j = 0; j < p->grid_size; j ++)
-                       {
-                               if (p->start_across_word[i][j] != -1)
-                               {
-                                       printf ("%d - %s; ", p->start_across_word[i][j], 
-                                                               p->clue_across[i][j]);
-                               }
-                       }
-               }
-               printf ("\n\x1B[1mDOWN - CLUES\x1B[0m\n");
-               for (int i = 0; i < p->grid_size; i ++)
-               {
-                       for (int j = 0; j < p->grid_size; j ++)
-                       {
-                               if (p->start_down_word[i][j] != -1)
-                               {
-                                       printf ("%d - %s; ", p->start_down_word[i][j], 
-                                                               p->clue_down[i][j]);
-                               }
-                       }
-               }
-               printf ("\n");  
-       }
-}
-
-/* function to check if a word is valid or not */
-char* is_valid_word (char *word) 
-{
-       if (word == NULL || strlen(word) == 0)
-               return NULL;
-       for (int i = 0; i < strlen (word) - 1; i ++)
-               if (! isalpha (word[i])) 
-                       return NULL;
-                       
-       return strtok (word, "\n");
-}
-
-
-/* function to set a clue for an across word */
-bool set_clue (Puzzle *p, String clue, int index, enum ORIENTATION order) 
-{
-       for (int i = 0; i < p->grid_size; i ++)
-       {
-               for (int j = 0; j < p->grid_size; j ++)
-               {
-                       if (order == ACROSS)
-                       {
-                               if (p->start_across_word[i][j] == index)
-                               {
-                                       strcpy (p->clue_across[i][j], clue);
-                                       return true;
-                               }
-                       }
-                       else if (order == DOWN)
-                       {
-                               if (p->start_down_word[i][j] == index)
-                               {
-                                       strcpy (p->clue_down[i][j], clue);
-                                       return true;
-                               }
-                       }               
-               }
-       }
-       return false;
-}
-
-/* function to print a menu */
-void print_menu (enum COLOR fg, enum COLOR bg, const char* title, 
-                                       char **items, int num_items, int padding)
-{
-               /* clear screen */
-               printf ("\e[1;1H\e[2J");
-               set_color (fg, bg, NORMAL);
-               printf ("\u2554");
-               for (int i = 0; i < padding; i ++)
-                       printf ("\u2550");
-               printf ("\u2557"); 
-               reset_color (); printf ("\n");
-               set_color (fg, bg, NORMAL);
-               printf ("\u2551");
-               set_color (fg, bg, BOLD);
-               printf ("%-*s", padding, title);
-               reset_color ();
-               set_color (fg, bg, NORMAL);
-               printf ("\u2551");
-               reset_color (); printf ("\n");
-               set_color (fg, bg, NORMAL);
-               printf ("\u2560");
-               for (int i = 0; i < padding; i ++)
-                       printf ("\u2550");
-               printf ("\u2563");
-               reset_color (); printf ("\n");
-               for (int i = 0; i < num_items; i ++) 
-               {
-                       set_color (fg, bg, NORMAL);
-                       printf ("\u2551%-*s\u2551", padding, items[i]);
-                       reset_color (); printf ("\n");
-               }
-               set_color (fg, bg, NORMAL);
-               printf ("\u255A");
-               for (int i = 0; i < padding; i ++)
-                       printf ("\u2550");
-               printf ("\u255D");
-               reset_color (); printf ("\n");
-}
-
-/* reset the player data, loading from the puzzle file */
-void reset_player_data (MainPlayerData *app_data, const char *filename)
-{
-       app_data->puzzle = load_puzzle (filename);
-
-       app_data->is_loaded = app_data->puzzle.grid_frozen;
-       app_data->cur_col = -1;
-       app_data->cur_row = -1;
-       app_data->solution_revealed = false;
-       strcpy (app_data->filename, filename);
-       /* reset the answer keys */
-       for (int i = 0; i < app_data->puzzle.grid_size; i ++)
-               for (int j = 0; j < app_data->puzzle.grid_size; j ++)
-                       app_data->char_ans[i][j] = ' ';
-       
-}
-
-/* save the user grid to a file */
-void save_user_data (MainPlayerData *app_data, const char *filename) 
-{
-       FILE *outfile;
-       outfile = fopen (filename, "wb");
-       if (outfile == NULL) 
-       {
-               fprintf (stderr, ERROR_WRITING_FILE);
-               return;
-       }
-       fprintf (outfile, "%s\n", app_data->filename);
-       for (int i = 0; i < app_data->puzzle.grid_size; i ++)
-       {
-               for (int j = 0; j < app_data->puzzle.grid_size; j ++)
-                       fprintf (outfile, "%c", app_data->char_ans[i][j]);
-               fprintf (outfile, "\n");
-       }
-       
-       fclose (outfile);
-}
-
-/* load the user grid from a file */
-void load_user_data (MainPlayerData *app_data, const char *filename)
-{
-       FILE *infile;
-       infile = fopen (filename, "rb");
-       if (infile == NULL)
-       {
-               fprintf (stderr, "%s\n", ERROR_READING_FILE);
-               return;
-       }
-
-       char puzzle_file_name[65535];
-       fgets (puzzle_file_name, 65535, infile);        
-       reset_player_data (app_data, strtok (puzzle_file_name, "\n"));
-
-       char line[MAX_PUZZLE_SIZE+10];
-       for (int i = 0; i < app_data->puzzle.grid_size; i ++)
-       {
-               fgets (line, MAX_PUZZLE_SIZE+10, infile);
-               for (int j = 0; j < app_data->puzzle.grid_size; j ++)
-                       app_data->char_ans[i][j] = line[j];
-
-       }
-       fclose (infile);
-}
-
-/* in the player app, move the current selection index left or right */
-void move_current_col (MainPlayerData *app_data, 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;
-       }
-}
-
-/* in the player app move the current selection index up or down */
-void move_current_row (MainPlayerData *app_data, 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;
-       }
-}
-
-#endif
diff --git a/wordblox.svg b/wordblox.svg
deleted file mode 100644 (file)
index d7e6745..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="64px"
-   height="64px"
-   id="svg2985"
-   version="1.1"
-   inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
-   sodipodi:docname="wordblox.svg"
-   inkscape:export-filename="/home/hari/Projects/GetAClue/resources/getaclue.png"
-   inkscape:export-xdpi="96"
-   inkscape:export-ydpi="96">
-  <defs
-     id="defs2987" />
-  <sodipodi:namedview
-     id="base"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageopacity="0.0"
-     inkscape:pageshadow="2"
-     inkscape:zoom="0.6875"
-     inkscape:cx="373.4413"
-     inkscape:cy="-67.966563"
-     inkscape:current-layer="layer1"
-     showgrid="true"
-     inkscape:document-units="px"
-     inkscape:grid-bbox="true"
-     inkscape:window-width="1366"
-     inkscape:window-height="704"
-     inkscape:window-x="0"
-     inkscape:window-y="27"
-     inkscape:window-maximized="1" />
-  <metadata
-     id="metadata2990">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g
-     id="layer1"
-     inkscape:label="Layer 1"
-     inkscape:groupmode="layer">
-    <rect
-       style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.50000000000000000;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
-       id="rect2993"
-       width="60.18182"
-       height="60.363636"
-       x="2.1818182"
-       y="2" />
-    <path
-       style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
-       d="m 22.727273,2.5454545 0,59.6363635"
-       id="path2995"
-       inkscape:connector-curvature="0" />
-    <path
-       style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
-       d="M 42.545455,2.3636367 42.545455,62"
-       id="path2995-2"
-       inkscape:connector-curvature="0" />
-    <path
-       style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
-       d="M 2.5454545,22.363636 62,22.363636"
-       id="path3022"
-       inkscape:connector-curvature="0" />
-    <path
-       style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
-       d="m 3.2727273,42.545455 58.9840237,0"
-       id="path3024"
-       inkscape:connector-curvature="0" />
-    <path
-       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="M 42.909095,11.727272 V 2 h 9.727272 9.727273 v 9.727272 9.727273 h -9.727273 -9.727272 z"
-       id="path3032"
-       inkscape:connector-curvature="0" />
-    <path
-       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="M 3.2727282,11.818181 V 2.5454545 h 9.7272728 9.727272 v 9.2727265 9.272727 H 13.000001 3.2727282 Z"
-       id="path3032-3"
-       inkscape:connector-curvature="0" />
-    <path
-       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="M 3.2727273,51.818181 V 42.545455 H 13 22.727272 v 9.272726 9.272727 H 13 3.2727273 Z"
-       id="path3032-3-7"
-       inkscape:connector-curvature="0" />
-    <path
-       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       d="M 42.545455,52.727273 V 43.454547 H 52.272728 62 V 52.727273 62 h -9.727272 -9.727273 z"
-       id="path3032-3-5"
-       inkscape:connector-curvature="0" />
-  </g>
-</svg>
diff --git a/wordblox_player.c b/wordblox_player.c
deleted file mode 100644 (file)
index 9560ac8..0000000
+++ /dev/null
@@ -1,724 +0,0 @@
-#include <gtk/gtk.h>
-
-#include "constantstrings.h"
-#include "wordblox_resource.c"
-#include "wordblox.h"
-
-GtkWidget *main_window; 
-GtkListStore *across_store;
-GtkListStore *down_store;
-
-MainPlayerData app_data;
-
-/* update the clue items store */
-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);
-                               }
-                       }
-               }
-       } 
-}
-
-/* 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)
-{
-       /* if it is solution mode, then don't do anything but reset it to 
-          non solution mode */
-       if (app_data.solution_revealed == true)
-       {
-               app_data.solution_revealed = false;
-               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;
-       }
-       
-       /* Depending on the type of button handle the movement */
-       if (event->type == GDK_BUTTON_PRESS && event->button == 1)
-       {
-               int col = (event->x - 5) / GRID_PIXELS;
-               int row = (event->y - 5) / GRID_PIXELS;
-       
-               if (app_data.puzzle.chars[row][col] != '#')
-               {
-                       if (row < app_data.puzzle.grid_size && 
-                               col < app_data.puzzle.grid_size)
-                       {
-                               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; 
-                       }
-               }
-       }
-       
-       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 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)
-       {
-               /* if the solution is revealed, don't respond to key events except
-                  to return to the non-solution mode */
-               if (app_data.solution_revealed == true)
-               {
-                       app_data.solution_revealed = false;
-                       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;
-               }
-               
-               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] = ' ';
-                                                               break;                  
-                       case GDK_KEY_a    :
-                       case GDK_KEY_A    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'A';
-                                                               break;
-                       case GDK_KEY_b    :
-                       case GDK_KEY_B    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'B';
-                                                               break;
-                       case GDK_KEY_c    :
-                       case GDK_KEY_C    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'C';
-                                                               break;
-                       case GDK_KEY_d    :
-                       case GDK_KEY_D    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'D';
-                                                               break;
-                       case GDK_KEY_e    :
-                       case GDK_KEY_E    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'E';
-                                                               break;
-                       case GDK_KEY_f    :
-                       case GDK_KEY_F    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'F';            
-                                                               break;
-                       case GDK_KEY_g    :
-                       case GDK_KEY_G    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'G';
-                                                               break;
-                       case GDK_KEY_h    :
-                       case GDK_KEY_H    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'H';
-                                                               break;
-                       case GDK_KEY_i    :
-                       case GDK_KEY_I    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'I';
-                                                               break;
-                       case GDK_KEY_j    :
-                       case GDK_KEY_J    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'J';
-                                                               break;
-                       case GDK_KEY_k    :
-                       case GDK_KEY_K    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'K';
-                                                               break;
-                       case GDK_KEY_l    :
-                       case GDK_KEY_L    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'L';
-                                                               break;
-                       case GDK_KEY_m    :
-                       case GDK_KEY_M    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'M';
-                                                               break;
-                       case GDK_KEY_n    :
-                       case GDK_KEY_N    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'N';
-                                                               break;
-                       case GDK_KEY_o    :
-                       case GDK_KEY_O    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'O';
-                                                               break;
-                       case GDK_KEY_p    :
-                       case GDK_KEY_P    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'P';
-                                                               break;
-                       case GDK_KEY_q    :
-                       case GDK_KEY_Q    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'Q';
-                                                               break;
-                       case GDK_KEY_r    :
-                       case GDK_KEY_R    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'R';
-                                                               break;
-                       case GDK_KEY_s    :
-                       case GDK_KEY_S    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'S';
-                                                               break;
-                       case GDK_KEY_t    :
-                       case GDK_KEY_T    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'T';
-                                                               break;
-                       case GDK_KEY_u    :
-                       case GDK_KEY_U    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'U';
-                                                               break;
-                       case GDK_KEY_v    :
-                       case GDK_KEY_V    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'V';
-                                                               break;
-                       case GDK_KEY_w    :
-                       case GDK_KEY_W    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'W';
-                                                               break;
-                       case GDK_KEY_x    :
-                       case GDK_KEY_X    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'X';
-                                                               break;
-                       case GDK_KEY_y    :
-                       case GDK_KEY_Y    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'Y';
-                                                               break;
-                       case GDK_KEY_z    :
-                       case GDK_KEY_Z    : 
-                                       app_data.char_ans[app_data.cur_row][app_data.cur_col] = 'Z';
-                                                               break;
-                       default                   : return FALSE;
-                                                                               
-               }
-       }
-       
-       /* 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);      
-       
-       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, colorblue, colorbacksel1, 
-                               colorbacksel2, colorsolution;
-               gdk_rgba_parse (&colorfore, "#000000"); 
-               gdk_rgba_parse (&colorback, "#ffffff");
-               gdk_rgba_parse (&colorblue, "#0000dd");
-               gdk_rgba_parse (&colorbacksel1, "#ffffaa");
-               gdk_rgba_parse (&colorbacksel2, "#aaffff");
-               gdk_rgba_parse (&colorsolution, "#990099");
-               cairo_set_line_width (cr, 3);
-               
-               /* set the size of the drawing area */
-               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 ++)
-                       {
-                               /* 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;
-                                               app_data.current_movement = ACROSS;
-                                       }
-                                       else if (app_data.puzzle.start_down_word[i][j] == 1)
-                                       {
-                                               app_data.cur_row = i; 
-                                               app_data.cur_col = j;
-                                               app_data.current_movement = DOWN;
-                                       }
-                               }
-                       
-                               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
-                                  to black */
-                               if (app_data.puzzle.chars[i][j] != '#')
-                                       gdk_cairo_set_source_rgba (cr, &colorback);
-                               
-                               /* if it is a current selection and solution reveal mode is not 
-                                  set then then set the background depending on whether across
-                                  or down movement mode is current */
-                               if (app_data.solution_revealed == false && 
-                                               app_data.cur_row == i && app_data.cur_col == j)
-                               {
-                                       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);
-                               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);
-                               }
-                               
-                               /* if solution is not revealed set the color to normal
-                                  or set it to solution color */
-                               if (app_data.solution_revealed == false)
-                                       gdk_cairo_set_source_rgba (cr, &colorfore);
-                               else
-                                       gdk_cairo_set_source_rgba (cr, &colorsolution);
-                                       
-                               cairo_select_font_face (cr, "sans serif", 
-                                                                               CAIRO_FONT_SLANT_NORMAL,
-                                                                               CAIRO_FONT_WEIGHT_BOLD);
-                               
-                               cairo_set_font_size (cr, 16);
-                               cairo_move_to (cr, j*GRID_PIXELS+GRID_PIXELS/2, 
-                                                               i*GRID_PIXELS+GRID_PIXELS-10);
-                               char ctxt[3];
-                               /* if it is solution mode reveal the answer or else the 
-                                  user input */
-                                 if (app_data.solution_revealed == false)
-                                       sprintf (ctxt, "%c", app_data.char_ans[i][j]);
-                                 else
-                                       if (app_data.puzzle.chars[i][j] != '#')
-                                               sprintf (ctxt, "%c", app_data.puzzle.chars[i][j]);
-                                       else
-                                               sprintf (ctxt, "%c", ' ');
-                               cairo_show_text (cr, (const char*) ctxt);
-
-                       }
-               }
-       }
-                       
-       return FALSE;
-
-}
-
-/* slot for reveal solution menu */
-void on_menu_reveal_solution_activate (GtkMenuItem *item, GtkDrawingArea *area)
-{
-       /* if puzzle solution is password protected ask for the password */
-       if (strlen (app_data.puzzle.hashed_solution_password) > 0)
-       {
-               GtkBuilder *builder;
-               builder = gtk_builder_new ();
-               
-               guint ret = gtk_builder_add_from_resource 
-                                               (builder, 
-                                                       "/org/harishankar/wordblox/wordblox_player.glade", 
-                                                       NULL);          
-               if (ret == 0)
-               {
-                       fprintf (stderr, ERROR_WINDOW);
-                       g_object_unref (builder);
-                       return;
-               }
-                                               
-               GtkWidget *password_dialog = GTK_WIDGET (gtk_builder_get_object 
-                                                                               (builder, "password_dialog"));
-               GtkWidget *password_text = GTK_WIDGET (gtk_builder_get_object 
-                                                                               (builder, "password_text"));
-                                                                               
-               if (password_dialog == NULL)
-               {
-                       fprintf (stderr, ERROR_WINDOW);
-                       g_object_unref (builder);
-                       return;
-               }
-               gtk_window_set_transient_for (GTK_WINDOW(password_dialog), 
-                                                                       GTK_WINDOW(main_window));
-               gtk_dialog_set_default_response (GTK_DIALOG(password_dialog), 
-               GTK_RESPONSE_ACCEPT);
-               gint res = gtk_dialog_run (GTK_DIALOG (password_dialog));
-               if (res == GTK_RESPONSE_ACCEPT)
-               {
-                       const gchar *user_pwd = gtk_entry_get_text 
-                                                                                       (GTK_ENTRY(password_text));
-                       /* if password is correct */
-                       if (verify_solution_password (&app_data.puzzle, user_pwd) == true)
-                               app_data.solution_revealed = true;
-                       /* password is incorrect */
-                       else
-                       {
-                               app_data.solution_revealed = false;
-                               GtkWidget *errordlg ;
-                               errordlg = gtk_message_dialog_new (GTK_WINDOW(main_window), 
-                                                                                               GTK_DIALOG_DESTROY_WITH_PARENT,
-                                                                                               GTK_MESSAGE_ERROR,
-                                                                                               GTK_BUTTONS_CLOSE,
-                                                                                               WRONG_PASSWORD);
-                               gtk_dialog_run (GTK_DIALOG(errordlg));
-                               gtk_widget_destroy (errordlg);
-                       }
-               }
-               
-               gtk_widget_destroy (password_text);
-               gtk_widget_destroy (password_dialog);
-               g_object_unref (builder);
-                       }
-       else
-               app_data.solution_revealed = true;
-
-       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);
-
-}
-
-/* slot for load grid state menu */
-void on_menu_load_grid_state_activate (GtkMenuItem *item, GtkDrawingArea *area)
-{
-       GtkWidget *dialog;
-       GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
-       gint res;
-       dialog = gtk_file_chooser_dialog_new (OPEN_FILE, GTK_WINDOW (main_window),
-                                                                               action,
-                                                                               "_Cancel",
-                                                                               GTK_RESPONSE_CANCEL,
-                                                                               "_Open",
-                                                                               GTK_RESPONSE_ACCEPT,
-                                                                               NULL
-                                                                               );
-                                                                               
-       res = gtk_dialog_run (GTK_DIALOG (dialog));
-       if (res == GTK_RESPONSE_ACCEPT)
-       {
-               char *filename;
-               filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
-               load_user_data (&app_data, filename);
-               g_free (filename);
-       }
-       
-       gtk_widget_destroy (dialog);
-       
-       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);
-                               
-       update_clue_items ();
-}
-
-/* slot for save grid state menu */
-void on_menu_save_grid_state_activate (GtkMenuItem *item, gpointer *data)
-{
-       if (app_data.is_loaded == false)
-               return;
-               
-       GtkWidget *dialog;
-       GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
-       gint res;
-       dialog = gtk_file_chooser_dialog_new (SAVE_FILE, GTK_WINDOW(main_window),
-                                                                               action,
-                                                                               "_Cancel",
-                                                                               GTK_RESPONSE_CANCEL,
-                                                                               "_Save",
-                                                                               GTK_RESPONSE_ACCEPT,
-                                                                               NULL);
-       res = gtk_dialog_run (GTK_DIALOG (dialog));
-       if (res == GTK_RESPONSE_ACCEPT)
-       {
-               char *filename;
-               filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
-               save_user_data (&app_data, filename);
-               g_free (filename);
-       }
-       
-       gtk_widget_destroy (dialog);
-}
-
-/* slot for exit menu */
-void on_menu_exit_activate (GtkMenuItem *item, gpointer data)
-{
-       gtk_main_quit ();
-}
-
-/* slot for open menu */
-void on_menu_open_activate (GtkMenuItem *item, GtkDrawingArea* area)
-{
-       GtkWidget *dialog;
-       GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
-       gint res;
-       dialog = gtk_file_chooser_dialog_new (OPEN_FILE, GTK_WINDOW(main_window),
-                                                                                        action, 
-                                                                                       "_Cancel", 
-                                                                                       GTK_RESPONSE_CANCEL, 
-                                                                                       "_Open",
-                                                                                       GTK_RESPONSE_ACCEPT,
-                                                                                       NULL);
-       res = gtk_dialog_run (GTK_DIALOG (dialog));
-       if (res == GTK_RESPONSE_ACCEPT)
-       {
-               char *filename;
-               filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog));
-               MainPlayerData temp;
-               reset_player_data (&temp, filename);
-
-               /* if the grid is not frozen then the game cannot be played */
-               if (temp.is_loaded == false)
-               {
-                       GtkWidget *errordlg ;
-                       errordlg = gtk_message_dialog_new (GTK_WINDOW(main_window), 
-                                                                                               GTK_DIALOG_DESTROY_WITH_PARENT,
-                                                                                               GTK_MESSAGE_ERROR,
-                                                                                               GTK_BUTTONS_CLOSE,
-                                                                                               UNFROZEN_GRID_PLAYER);
-                       gtk_dialog_run (GTK_DIALOG(errordlg));
-                       gtk_widget_destroy (errordlg);
-               }
-               else
-               {
-                       app_data = temp;
-                       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 ();           
-               g_free (filename);
-       }
-       
-       gtk_widget_destroy (dialog);
-}
-
-/* slot for about menu */
-void on_menu_about_activate (GtkMenuItem *item, gpointer data)
-{      
-       const char *AUTHOR[] =  {"V.Harishankar", NULL};
-       gtk_show_about_dialog (GTK_WINDOW(main_window), "authors",AUTHOR, 
-                                                       "program-name", PROGRAM_NAME,
-                                                       "copyright", COPYRIGHT,
-                                                       "comments", COMMENTS,
-                                                       "website", WEBSITE,
-                                                       "website-label", WEBSITE_LABEL,
-                                                       "license-type", GTK_LICENSE_GPL_2_0,
-                                                       "version", VERSION,
-                                                       (char*)NULL);
-}
-
-int main (int argc, char *argv [])
-{
-       gtk_init (&argc, &argv);
-       GdkPixbuf *icon;
-       icon = gdk_pixbuf_new_from_resource 
-                               ("/org/harishankar/wordblox/wordblox.svg", NULL);
-       if (icon == NULL)
-               fprintf (stderr, ERROR_ICON);
-       
-       GtkBuilder *builder;
-       builder = gtk_builder_new ();
-       guint ret = gtk_builder_add_from_resource (builder, 
-               "/org/harishankar/wordblox/wordblox_player.glade", NULL);
-       
-       app_data.is_loaded = false;
-       
-       if (ret == 0)
-       {
-               fprintf (stderr, ERROR_WINDOW);
-               g_object_unref (builder);
-               return 1;       
-       }
-       else 
-       {
-               main_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 (main_window != NULL)
-               {
-                       gtk_window_set_default_icon (icon);
-                       
-                       GtkWidget *draw_area = GTK_WIDGET (
-                                                       gtk_builder_get_object(builder, "puzzle_area"));
-                       
-                       /* make drawing area respond to mouse event */
-                       gtk_widget_set_events(draw_area,
-                                       gtk_widget_get_events(draw_area) 
-                                               | GDK_BUTTON_PRESS_MASK);
-               
-                       gtk_builder_connect_signals (builder, NULL);
-                       g_object_unref (builder);
-                       gtk_widget_show (main_window);
-                       gtk_main ();
-                       return 0;
-               }
-               else
-               {
-                       g_object_unref (builder);
-                       fprintf (stderr, ERROR_WINDOW);
-                       return 1;
-               }
-       } 
-}
diff --git a/wordblox_player.glade b/wordblox_player.glade
deleted file mode 100644 (file)
index dc20b5b..0000000
+++ /dev/null
@@ -1,417 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.2 -->
-<interface>
-  <requires lib="gtk+" version="3.20"/>
-  <object class="GtkListStore" id="store_across_clues">
-    <columns>
-      <!-- column-name ID -->
-      <column type="gint"/>
-      <!-- column-name Clue -->
-      <column type="gchararray"/>
-    </columns>
-  </object>
-  <object class="GtkListStore" id="store_down_clues">
-    <columns>
-      <!-- column-name ID -->
-      <column type="gint"/>
-      <!-- column-name Clue -->
-      <column type="gchararray"/>
-    </columns>
-  </object>
-  <object class="GtkWindow" id="main_window">
-    <property name="can_focus">False</property>
-    <property name="title" translatable="yes">Wordblox Player</property>
-    <property name="default_width">540</property>
-    <property name="default_height">400</property>
-    <signal name="destroy" handler="on_menu_exit_activate" swapped="no"/>
-    <child type="titlebar">
-      <placeholder/>
-    </child>
-    <child>
-      <object class="GtkBox">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="orientation">vertical</property>
-        <child>
-          <object class="GtkMenuBar" id="main_menu">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <child>
-              <object class="GtkMenuItem" id="menu_puzzle">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">_Puzzle</property>
-                <property name="use_underline">True</property>
-                <child type="submenu">
-                  <object class="GtkMenu">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <child>
-                      <object class="GtkMenuItem" id="menu_open">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">_Open...</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="on_menu_open_activate" object="puzzle_area" swapped="no"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkSeparatorMenuItem">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkMenuItem" id="menu_exit">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">E_xit</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="on_menu_exit_activate" swapped="no"/>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-            </child>
-            <child>
-              <object class="GtkMenuItem" id="menu_grid">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">_Grid</property>
-                <property name="use_underline">True</property>
-                <child type="submenu">
-                  <object class="GtkMenu">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <child>
-                      <object class="GtkMenuItem" id="menu_save_grid_state">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">_Save Grid State...</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="on_menu_save_grid_state_activate" swapped="no"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkMenuItem" id="menu_load_grid_state">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">_Load Grid State...</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="on_menu_load_grid_state_activate" object="puzzle_area" swapped="no"/>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-            </child>
-            <child>
-              <object class="GtkMenuItem" id="menu_view">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">_View</property>
-                <property name="use_underline">True</property>
-                <child type="submenu">
-                  <object class="GtkMenu">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <child>
-                      <object class="GtkMenuItem" id="menu_reveal_solution">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">_Reveal Solution...</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="on_menu_reveal_solution_activate" object="puzzle_area" swapped="no"/>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-            </child>
-            <child>
-              <object class="GtkMenuItem" id="menu_help">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">_Help</property>
-                <property name="use_underline">True</property>
-                <child type="submenu">
-                  <object class="GtkMenu">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <child>
-                      <object class="GtkMenuItem" id="menu_about">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">_About...</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="on_menu_about_activate" swapped="no"/>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkPaned">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <child>
-              <object class="GtkScrolledWindow">
-                <property name="width_request">80</property>
-                <property name="height_request">80</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="shadow_type">in</property>
-                <child>
-                  <object class="GtkViewport">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="hscroll_policy">natural</property>
-                    <property name="vscroll_policy">natural</property>
-                    <child>
-                      <object class="GtkDrawingArea" id="puzzle_area">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="has_focus">True</property>
-                        <property name="can_default">True</property>
-                        <property name="has_default">True</property>
-                        <signal name="button-press-event" handler="on_puzzle_area_button_press_event" swapped="no"/>
-                        <signal name="draw" handler="on_puzzle_area_draw" swapped="no"/>
-                        <signal name="key-press-event" handler="on_puzzle_area_key_press_event" swapped="no"/>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="resize">True</property>
-                <property name="shrink">True</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkPaned">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="orientation">vertical</property>
-                <child>
-                  <object class="GtkScrolledWindow">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="shadow_type">in</property>
-                    <child>
-                      <object class="GtkTreeView" id="list_across_clues">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="model">store_across_clues</property>
-                        <property name="enable_search">False</property>
-                        <property name="search_column">0</property>
-                        <property name="show_expanders">False</property>
-                        <child internal-child="selection">
-                          <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="resizable">True</property>
-                            <property name="title" translatable="yes">Id</property>
-                            <child>
-                              <object class="GtkCellRendererText"/>
-                              <attributes>
-                                <attribute name="text">0</attribute>
-                              </attributes>
-                            </child>
-                          </object>
-                        </child>
-                        <child>
-                          <object class="GtkTreeViewColumn" id="ClueAcross">
-                            <property name="resizable">True</property>
-                            <property name="title" translatable="yes">Clues Across</property>
-                            <child>
-                              <object class="GtkCellRendererText"/>
-                              <attributes>
-                                <attribute name="text">1</attribute>
-                                <attribute name="placeholder-text">1</attribute>
-                              </attributes>
-                            </child>
-                          </object>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="resize">True</property>
-                    <property name="shrink">True</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkScrolledWindow">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="shadow_type">in</property>
-                    <child>
-                      <object class="GtkTreeView" id="list_down_clues">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="model">store_down_clues</property>
-                        <property name="enable_search">False</property>
-                        <property name="search_column">0</property>
-                        <property name="show_expanders">False</property>
-                        <child internal-child="selection">
-                          <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">
-                            <property name="resizable">True</property>
-                            <property name="title" translatable="yes">Id</property>
-                            <child>
-                              <object class="GtkCellRendererText"/>
-                              <attributes>
-                                <attribute name="text">0</attribute>
-                              </attributes>
-                            </child>
-                          </object>
-                        </child>
-                        <child>
-                          <object class="GtkTreeViewColumn" id="ClueDown">
-                            <property name="resizable">True</property>
-                            <property name="title" translatable="yes">Clues Down</property>
-                            <child>
-                              <object class="GtkCellRendererText"/>
-                              <attributes>
-                                <attribute name="text">1</attribute>
-                              </attributes>
-                            </child>
-                          </object>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="resize">True</property>
-                    <property name="shrink">True</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="resize">True</property>
-                <property name="shrink">True</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">True</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-  </object>
-  <object class="GtkDialog" id="password_dialog">
-    <property name="can_focus">False</property>
-    <property name="title" translatable="yes">Password</property>
-    <property name="resizable">False</property>
-    <property name="hide_titlebar_when_maximized">True</property>
-    <property name="type_hint">dialog</property>
-    <property name="transient_for">main_window</property>
-    <child type="titlebar">
-      <placeholder/>
-    </child>
-    <child internal-child="vbox">
-      <object class="GtkBox">
-        <property name="can_focus">False</property>
-        <property name="margin_left">10</property>
-        <property name="margin_right">10</property>
-        <property name="margin_top">10</property>
-        <property name="margin_bottom">10</property>
-        <property name="orientation">vertical</property>
-        <property name="spacing">2</property>
-        <child internal-child="action_area">
-          <object class="GtkButtonBox">
-            <property name="can_focus">False</property>
-            <property name="layout_style">end</property>
-            <child>
-              <object class="GtkButton" id="button1">
-                <property name="label">gtk-cancel</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-                <property name="always_show_image">True</property>
-              </object>
-              <packing>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="button2">
-                <property name="label">gtk-ok</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-                <property name="always_show_image">True</property>
-              </object>
-              <packing>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">False</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkLabel">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="label" translatable="yes">Password for revealing solution</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkEntry" id="password_text">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="max_length">256</property>
-            <property name="visibility">False</property>
-            <property name="invisible_char">●</property>
-            <property name="activates_default">True</property>
-            <property name="input_purpose">password</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">3</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <action-widgets>
-      <action-widget response="-6">button1</action-widget>
-      <action-widget response="-3">button2</action-widget>
-    </action-widgets>
-  </object>
-</interface>