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