1 #include <config.h>
2 #include <stdio.h>
3 #include <math.h>
4 #include <time.h>
5 #include "canvas_demo.h"
6 
7 
8 #define PIECE_SIZE 50
9 
10 
11 static void
free_stuff(GtkObject * obj,gpointer data)12 free_stuff (GtkObject *obj, gpointer data)
13 {
14 	g_free (data);
15 }
16 
17 static void
test_win(GnomeCanvasItem ** board)18 test_win (GnomeCanvasItem **board)
19 {
20 	int i;
21 #if 0
22 	GtkWidget *dlg;
23 #endif
24 
25 	for (i = 0; i < 15; i++)
26 		if (!board[i] || (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (board[i]), "piece_num")) != i))
27 			return;
28 
29 #if 0
30 	dlg=gnome_ok_dialog ("You stud, you win!");
31 	gtk_window_set_modal(GTK_WINDOW(dlg),TRUE);
32 	gnome_dialog_run (GNOME_DIALOG (dlg));
33 #endif
34 }
35 
36 static char *
get_piece_color(int piece)37 get_piece_color (int piece)
38 {
39 	static char buf[50];
40 	int x, y;
41 	int r, g, b;
42 
43 	y = piece / 4;
44 	x = piece % 4;
45 
46 	r = ((4 - x) * 255) / 4;
47 	g = ((4 - y) * 255) / 4;
48 	b = 128;
49 
50 	sprintf (buf, "#%02x%02x%02x", r, g, b);
51 
52 	return buf;
53 }
54 
55 static gint
piece_event(GnomeCanvasItem * item,GdkEvent * event,gpointer data)56 piece_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data)
57 {
58 	GnomeCanvas *canvas;
59 	GnomeCanvasItem **board;
60 	GnomeCanvasItem *text;
61 	int pos, newpos;
62 	int x, y;
63 	double dx = 0.0, dy = 0.0;
64 	int move;
65 
66 	canvas = item->canvas;
67 	board = g_object_get_data (G_OBJECT (canvas), "board");
68 	pos = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "piece_pos"));
69 	text = g_object_get_data (G_OBJECT (item), "text");
70 
71 	switch (event->type) {
72 	case GDK_ENTER_NOTIFY:
73 		gnome_canvas_item_set (text,
74 				       "fill_color", "white",
75 				       NULL);
76 		break;
77 
78 	case GDK_LEAVE_NOTIFY:
79 		gnome_canvas_item_set (text,
80 				       "fill_color", "black",
81 				       NULL);
82 		break;
83 
84 	case GDK_BUTTON_PRESS:
85 		y = pos / 4;
86 		x = pos % 4;
87 
88 		move = TRUE;
89 
90 		if ((y > 0) && (board[(y - 1) * 4 + x] == NULL)) {
91 			dx = 0.0;
92 			dy = -1.0;
93 			y--;
94 		} else if ((y < 3) && (board[(y + 1) * 4 + x] == NULL)) {
95 			dx = 0.0;
96 			dy = 1.0;
97 			y++;
98 		} else if ((x > 0) && (board[y * 4 + x - 1] == NULL)) {
99 			dx = -1.0;
100 			dy = 0.0;
101 			x--;
102 		} else if ((x < 3) && (board[y * 4 + x + 1] == NULL)) {
103 			dx = 1.0;
104 			dy = 0.0;
105 			x++;
106 		} else
107 			move = FALSE;
108 
109 		if (move) {
110 			newpos = y * 4 + x;
111 			board[pos] = NULL;
112 			board[newpos] = item;
113 			g_object_set_data (G_OBJECT (item), "piece_pos", GINT_TO_POINTER (newpos));
114 			gnome_canvas_item_move (item, dx * PIECE_SIZE, dy * PIECE_SIZE);
115 			test_win (board);
116 		}
117 
118 		break;
119 
120 	default:
121 		break;
122 	}
123 
124 	return FALSE;
125 }
126 
127 #define SCRAMBLE_MOVES 256
128 
129 static void
scramble(GtkObject * object,gpointer data)130 scramble (GtkObject *object, gpointer data)
131 {
132 	GnomeCanvas *canvas;
133 	GnomeCanvasItem **board;
134 	int i;
135 	int pos, oldpos;
136 	int dir;
137 	int x, y;
138 
139 	srand (time (NULL));
140 
141 	canvas = data;
142 	board = g_object_get_data (G_OBJECT (object), "board");
143 
144 	/* First, find the blank spot */
145 
146 	for (pos = 0; pos < 16; pos++)
147 		if (board[pos] == NULL)
148 			break;
149 
150 	/* "Move the blank spot" around in order to scramble the pieces */
151 
152 	for (i = 0; i < SCRAMBLE_MOVES; i++) {
153 retry_scramble:
154 		dir = rand () % 4;
155 
156 		x = y = 0;
157 
158 		if ((dir == 0) && (pos > 3)) /* up */
159 			y = -1;
160 		else if ((dir == 1) && (pos < 12)) /* down */
161 			y = 1;
162 		else if ((dir == 2) && ((pos % 4) != 0)) /* left */
163 			x = -1;
164 		else if ((dir == 3) && ((pos % 4) != 3)) /* right */
165 			x = 1;
166 		else
167 			goto retry_scramble;
168 
169 		oldpos = pos + y * 4 + x;
170 		board[pos] = board[oldpos];
171 		board[oldpos] = NULL;
172 		g_object_set_data (G_OBJECT (board[pos]), "piece_pos", GINT_TO_POINTER (pos));
173 		gnome_canvas_item_move (board[pos], -x * PIECE_SIZE, -y * PIECE_SIZE);
174 		gnome_canvas_update_now (canvas);
175 		pos = oldpos;
176 	}
177 }
178 
179 GtkWidget *
create_canvas_fifteen(void)180 create_canvas_fifteen (void)
181 {
182 	GtkWidget *vbox;
183 	GtkWidget *alignment;
184 	GtkWidget *frame;
185 	GtkWidget *canvas;
186 	GtkWidget *button;
187 	GnomeCanvasItem **board;
188 	GnomeCanvasItem *text;
189 	int i, x, y;
190 	char buf[20];
191 
192 	vbox = gtk_vbox_new (FALSE, 4);
193 	gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
194 	gtk_widget_show (vbox);
195 
196 	alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
197 	gtk_box_pack_start (GTK_BOX (vbox), alignment, TRUE, TRUE, 0);
198 	gtk_widget_show (alignment);
199 
200 	frame = gtk_frame_new (NULL);
201 	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
202 	gtk_container_add (GTK_CONTAINER (alignment), frame);
203 	gtk_widget_show (frame);
204 
205 	/* Create the canvas and board */
206 
207 	canvas = gnome_canvas_new ();
208 	gtk_widget_set_size_request (canvas, PIECE_SIZE * 4 + 1, PIECE_SIZE * 4 + 1);
209 	gnome_canvas_set_scroll_region (GNOME_CANVAS (canvas), 0, 0, PIECE_SIZE * 4 + 1, PIECE_SIZE * 4 + 1);
210 	gtk_container_add (GTK_CONTAINER (frame), canvas);
211 	gtk_widget_show (canvas);
212 
213 	board = g_new (GnomeCanvasItem *, 16);
214 	g_object_set_data (G_OBJECT (canvas), "board", board);
215 	g_signal_connect (canvas, "destroy",
216 			  G_CALLBACK (free_stuff),
217 			  board);
218 
219 	for (i = 0; i < 15; i++) {
220 		y = i / 4;
221 		x = i % 4;
222 
223 		board[i] = gnome_canvas_item_new (gnome_canvas_root (GNOME_CANVAS (canvas)),
224 						  gnome_canvas_group_get_type (),
225 						  "x", (double) (x * PIECE_SIZE),
226 						  "y", (double) (y * PIECE_SIZE),
227 						  NULL);
228 
229 		gnome_canvas_item_new (GNOME_CANVAS_GROUP (board[i]),
230 				       gnome_canvas_rect_get_type (),
231 				       "x1", 0.0,
232 				       "y1", 0.0,
233 				       "x2", (double) PIECE_SIZE,
234 				       "y2", (double) PIECE_SIZE,
235 				       "fill_color", get_piece_color (i),
236 				       "outline_color", "black",
237 				       "width_pixels", 0,
238 				       NULL);
239 
240 		sprintf (buf, "%d", i + 1);
241 
242 		text = gnome_canvas_item_new (GNOME_CANVAS_GROUP (board[i]),
243 					      gnome_canvas_text_get_type (),
244 					      "text", buf,
245 					      "x", (double) PIECE_SIZE / 2.0,
246 					      "y", (double) PIECE_SIZE / 2.0,
247 					      "font", "Sans bold 24",
248 					      "anchor", GTK_ANCHOR_CENTER,
249 					      "fill_color", "black",
250 					      NULL);
251 
252 		g_object_set_data (G_OBJECT (board[i]), "piece_num", GINT_TO_POINTER (i));
253 		g_object_set_data (G_OBJECT (board[i]), "piece_pos", GINT_TO_POINTER (i));
254 		g_object_set_data (G_OBJECT (board[i]), "text", text);
255 		g_signal_connect (board[i], "event",
256 				  G_CALLBACK (piece_event),
257 				  NULL);
258 	}
259 
260 	board[15] = NULL;
261 
262 	/* Scramble button */
263 
264 	button = gtk_button_new_with_label ("Scramble");
265 	gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
266 	g_object_set_data (G_OBJECT (button), "board", board);
267 	g_signal_connect (button, "clicked",
268 			  G_CALLBACK (scramble),
269 			  canvas);
270 	gtk_widget_show (button);
271 
272 	return vbox;
273 }
274