X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=rack-fancy.c;h=abd22286f155ad02347875aeaf1507230768af5d;hb=bcb2db8e93ce94b662e7118b92230c6eb749ee22;hp=38c125394e9c8aeeaa6f4070cf643dafc8b3f362;hpb=f8d083966703a2b0efb6db1782a14a1a0b5d56f4;p=wordgame diff --git a/rack-fancy.c b/rack-fancy.c index 38c1253..abd2228 100644 --- a/rack-fancy.c +++ b/rack-fancy.c @@ -16,9 +16,160 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." */ #include +#include #include +#include +#include +#include +#include +#include + +#include "word-game.h" #include "demo-item.h" +#define MAX_TILES 7 + +typedef struct _tile +{ + char letter; + int rack_index; + int x, y; + int size; + GooCanvasItem *item; + gboolean guessed; +} tile_t; + +typedef struct _rack +{ + tile_t *tiles[MAX_TILES]; + int num_tiles; +} rack_t; + +static rack_t the_rack; + +static char the_guess[MAX_TILES]; +static int the_guess_index = 0; + +#define LETTER_SIZE 60 +#define LETTER_PAD 5 + +static void +rack_tile_position (int i, int *x, int *y) +{ + *x = 20 + i * (LETTER_SIZE + LETTER_PAD); + *y = 85; +} + +static void +guess_tile_position (int i, int *x, int *y) +{ + rack_tile_position (i, x, y); + *y -= (LETTER_SIZE + LETTER_PAD); +} + +static void +tile_paint (cairo_t *cr, void *closure) +{ + tile_t *tile = closure; + + cairo_pattern_t *gradient; + cairo_text_extents_t extents; + int rad = (int) (tile->size / 2); + int cx = tile->size / 2; + int cy = cx; + int tx, ty; + double spot_angle = M_PI / 4.0; + double spot_rad = rad / 2.0; + char string[2]; + + cairo_save (cr); + + gradient = cairo_pattern_create_radial (cx - spot_rad * cos (spot_angle), + cy - spot_rad * sin (spot_angle), + 0.0, + cx - spot_rad * cos (spot_angle), + cy - spot_rad * sin (spot_angle), + rad + spot_rad); + cairo_pattern_add_color_stop_rgb (gradient, 0.0, 1.0, 1.0, 1.0); + cairo_pattern_add_color_stop_rgb (gradient, 1.0, 0.33, 0.33, 0.33); + + cairo_set_source (cr, gradient); + + cairo_arc (cr, + cx, cy, + rad, 0, 2 * M_PI); + + cairo_fill (cr); + + cairo_select_font_face (cr, "mono", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size (cr, 1.8 * rad); + + string[0] = tile->letter; + string[1] = '\0'; + cairo_text_extents (cr, string, &extents); + tx = cx - extents.width / 2 - extents.x_bearing; + ty = cy - extents.height / 2 - extents.y_bearing; + + cairo_set_source_rgb (cr, 0.7, 0.7, 0.7); + cairo_move_to (cr, tx + 1, ty + 1); + cairo_show_text (cr, string); + + cairo_set_source_rgb (cr, 0.33, 0.33, 0.33); + cairo_move_to (cr, tx - 1, ty - 1); + cairo_show_text (cr, string); + + cairo_set_source_rgb (cr, 0.2, 0.3, 0.8); + cairo_move_to (cr, tx, ty); + cairo_show_text (cr, string); + + cairo_restore (cr); +} + +static void +tile_move_to (tile_t *tile, int x, int y) +{ + cairo_matrix_t matrix; + + cairo_matrix_init_translate (&matrix, x, y); + goo_canvas_item_set_transform (tile->item, &matrix); +} + +static void +tile_glide_to (tile_t *tile, int x, int y) +{ + goo_canvas_item_animate (tile->item, x, y, + 1.0, 0, + 500, 40, + GOO_CANVAS_ANIMATE_FREEZE); + tile->x = x; + tile->y = y; +} + +static tile_t * +tile_create (GooCanvasItem *parent, + char letter, int rack_index) +{ + tile_t *tile; + + tile = g_malloc (sizeof (tile_t)); + tile->letter = tolower (letter); + tile->rack_index = rack_index; + rack_tile_position (rack_index, &tile->x, &tile->y); + tile->size = LETTER_SIZE; + tile->item = goo_demo_item_new (parent, + tile->size, + tile_paint, + tile); + + tile_move_to (tile, tile->x, tile->y); + + tile->guessed = FALSE; + + return tile; +} + static gboolean on_delete_event (GtkWidget *window, GdkEvent *event, @@ -27,6 +178,123 @@ on_delete_event (GtkWidget *window, exit (0); } +static int +rand_within (int num_values) +{ + return (int) ((double) num_values * (rand() / (RAND_MAX + 1.0))); +} + +static void +shuffle (int *array, int length) +{ + int i, r, tmp; + + for (i = 0; i < length; i++) + { + r = i + rand_within (length - i); + tmp = array[i]; + array[i] = array[r]; + array[r] = tmp; + } +} + +static void +rack_init (rack_t *rack, GooCanvasItem *parent, char *word) +{ + int i; + + for (i = 0; i < MIN (MAX_TILES, strlen (word)); i++) + rack->tiles[i] = tile_create (parent, word[i], i); + rack->num_tiles = i; + while (i < MAX_TILES) + rack->tiles[i] = NULL; +} + +static gboolean +rack_shuffle (rack_t *rack) +{ + int indices[MAX_TILES]; + int i, x, y; + + for (i = 0; i < rack->num_tiles; i++) + indices[i] = i; + + shuffle (indices, rack->num_tiles); + + for (i = 0; i < rack->num_tiles; i++) { + rack->tiles[i]->rack_index = indices[i]; + rack_tile_position (indices[i], &x, &y); + tile_glide_to (rack->tiles[i], x, y); + } + + return TRUE; +} + +static gboolean +on_key_press_event (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data) +{ + int i, x, y; + char guess_letter; + rack_t *rack = user_data; + + if (event->keyval == GDK_space) { + for (i = 0; i < rack->num_tiles; i++) { + if (rack->tiles[i]->guessed) { + rack_tile_position (rack->tiles[i]->rack_index, &x, &y); + tile_glide_to (rack->tiles[i], x, y); + rack->tiles[i]->guessed = FALSE; + } + } + the_guess_index = 0; + rack_shuffle (rack); + return TRUE; + } + + if (event->keyval == GDK_BackSpace) { + gboolean found = FALSE; + int found_index; + x = 0; + for (i = 0; i < rack->num_tiles; i++) { + /* XXX: evil stuff here... please refactor a lot */ + if (the_guess[the_guess_index-1] == rack->tiles[i]->letter && + rack->tiles[i]->guessed && + rack->tiles[i]->x > x) + { + found = TRUE; + found_index = i; + } + } + if (found) { + rack_tile_position (rack->tiles[found_index]->rack_index, &x, &y); + tile_glide_to (rack->tiles[found_index], x, y); + rack->tiles[found_index]->guessed = FALSE; + the_guess_index--; + return TRUE; + } + return FALSE; + } + + /* XXX: event->string is deprecated, but the non-deprecated + * input-method stuff (GtkIMContext) is extremely non-obvious to + * use. */ + guess_letter = tolower (event->string[0]); + for (i = 0; i < rack->num_tiles; i++) { + if (guess_letter == rack->tiles[i]->letter && + ! rack->tiles[i]->guessed) + { + guess_tile_position (the_guess_index, &x, &y); + tile_glide_to (rack->tiles[i], x, y); + rack->tiles[i]->guessed = TRUE; + the_guess[the_guess_index++] = guess_letter; + return TRUE; + } + } + + return FALSE; +} + static GtkWidget * create_window (void) { @@ -38,6 +306,10 @@ create_window (void) g_signal_connect (window, "delete_event", (GtkSignalFunc) on_delete_event, NULL); + gtk_widget_add_events (window, GDK_KEY_PRESS_MASK); + g_signal_connect (window, "key_press_event", + (GtkSignalFunc) on_key_press_event, &the_rack); + scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN); @@ -50,21 +322,11 @@ create_window (void) return scrolled_window; } -static gboolean -on_button_press (GooCanvasItem *item, - GooCanvasItem *target, - GdkEventButton *event, - gpointer data) -{ - g_print ("demo item received button press event\n"); - return TRUE; -} - static void -create_canvas (GtkWidget *parent) +create_canvas (GtkWidget *parent, char *word) { GtkWidget *canvas; - GooCanvasItem *root, *rect; + GooCanvasItem *root; canvas = goo_canvas_new (); gtk_widget_set_size_request (canvas, 400, 400); @@ -74,25 +336,34 @@ create_canvas (GtkWidget *parent) root = goo_canvas_get_root_item (GOO_CANVAS (canvas)); - rect = goo_demo_item_new (root, 30, 20, 50, 30, - "fill-color", "purple", - NULL); - - g_signal_connect (rect, "button_press_event", - (GtkSignalFunc) on_button_press, NULL); - + rack_init (&the_rack, root, word); } int main (int argc, char *argv[]) { + struct timeval tv; + bag_t bag; + char rack[8]; + int i; GtkWidget *window; - gtk_init (&argc, &argv); + gettimeofday (&tv, NULL); + srand (tv.tv_sec ^ tv.tv_usec); + + bag_init (&bag); + bag_shuffle (&bag); + + memcpy (rack, bag.tiles, 7); + rack[7] = '\0'; + for (i = 0; i < 7; i++) + rack[i] = toupper (rack[i]); + + gtk_init (&argc, &argv); window = create_window (); - create_canvas (window); + create_canvas (window, rack); gtk_main ();