1 /* Copyright (C) 2000 Tim Northover <tim@pnorthover.freeserve.co.uk>
2 * using xpms from Tim Whittock
3 *
4 * Map editor for GNU robots game
5 *
6 * GNU Robots is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GNU Robots is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Robots. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /* compile with:
21 gcc mapedit.c -omapedit -I../lib `gtk-config --cflags --libs` */
22
23 /* Usage: mapedit [filename] */
24
25 #include <gtk/gtk.h> /* xwindows functions */
26 #include <stdio.h> /* for file functions */
27 #include <stdlib.h> /* for atoi */
28
29 /* indexes into the blocks array */
30
31 #define SPACE 0
32 #define FOOD 1
33 #define WALL 2
34 #define BADDIE 3
35 #define PRIZE 4
36
37 /* this is 1 more than the real size to allow for a border around
38 images: */
39
40 #define IMGSIZE 17
41
42 /* Stores information on blocks for display and storage */
43
44 typedef struct
45 {
46 int type; /* probably unnecessary at the moment,
47 but potentially useful (pointers) */
48 char *name; /* for display */
49 char save_char; /* character in map files */
50 char **xpm_data; /* again at the moment not really necessary,
51 but potentially */
52 GdkPixmap *pixmap; /* The image in gtk useable form */
53 }
54 BlockType;
55
56 typedef struct
57 {
58 int width, height;
59 char *data; /* will contain index into blocks array */
60 }
61 GridType;
62
63 GridType grid; /* The internal grid representation */
64
65 /* Now define known blocks -- leave xpm_data & pixmap for later init */
66
67 BlockType blocks[] = { {SPACE, "Empty Space", '.', NULL, NULL},
68 {FOOD, "Food", '+', NULL, NULL},
69 {WALL, "Wall", '#', NULL, NULL},
70 {BADDIE, "Baddie", '@', NULL, NULL},
71 {PRIZE, "Prize", '$', NULL, NULL}
72 };
73
74 int nblocks = 5; /* number of blocks */
75
76 GtkEntry *width_text, *height_text; /* for use by the size setting
77 button -- not ideal as
78 globals but simpler */
79
80 int dragging; /* whether to change "grid" --
81 modified by button_press &
82 button_release */
83
84 int current_tool; /* index into blocks */
85
86 GtkWidget *grid_window; /* main window for displaying map --
87 used by various functions */
88
89 /* initialisation/end funcs */
90
91 /* blocks global */
92 void init_blocks ();
93
94 /* initialises global "grid" -- doesn't touch anything X related */
95 void init_grid (char *filename);
96
97 /* used at beginning and in load button func to actually set "grid" */
98 void load_file (char *filename);
99
100 /* used to report failure to load/save file */
101 void message_box (char *title, char *message);
102
103 /* ATM only frees "grid.data" */
104 void freestuff ();
105
106 /* creates a box with pixmap & label -- for toolbox display */
107 GtkWidget *create_pixmap_with_label (GtkWidget * parent, GdkPixmap * pixmap,
108 char *text);
109 /* handler function when new tool is clicked */
110 void change_tool (GtkWidget * widget, gpointer data);
111
112
113 /* Grid update hanlders */
114
115 /* (mouse) button pressed in map window -- start draw */
116 void button_press (GtkFixed * fixed, GdkEventButton * event, gpointer data);
117
118 /* mouse moved in map window -- checks "dragging" */
119 void mouse_move (GtkFixed * fixed, GdkEventMotion * event, gpointer data);
120
121 /* stop drawing */
122 void button_release (GtkFixed * fixed, GdkEventButton * event, gpointer data);
123
124 /* sets "grid" and individual pixmap on map window */
125 void update_grid (GtkFixed * fixed, int x, int y);
126
127 /* creates radio button vertical box (for tools) */
128 GtkWidget *create_toolbox_box (GtkWidget * parent, GtkSignalFunc func);
129
130 /* creates box with load, save... */
131 GtkWidget *create_command_box (char *filename);
132
133 /* creates window for both of above widgets */
134 GtkWidget *create_toolbox_window (char *filename);
135
136 /* creates map display window */
137 GtkWidget *create_grid_window ();
138
139 /* clicked routine for Save */
140 void save_button (GtkWidget * widget, GtkEntry * textbox);
141
142 /* clicked routine for Load */
143 void load_button (GtkWidget * widget, GtkEntry * textbox);
144
145 /* clicked routine for Set Size */
146 void set_size (GtkWidget * widget, gpointer data);
147
148 /* destroys current map window and creates a new one from "grid" */
149 void recreate_grid_window ();
150
151 int
main(int argc,char ** argv)152 main (int argc, char **argv)
153 {
154 char *filename;
155 FILE *fp; /* for checking filename given */
156
157 GtkWidget *toolbox; /* main window -- currently unused but
158 saved for future -- and it's nice
159 to know I know something about the
160 window I've created */
161
162 /* Global initialisation */
163
164 if (argc > 1) /* check if filename specified */
165 {
166 filename = argv[1];
167 fp = fopen (filename, "r");
168 if (!fp)
169 {
170 g_print ("Could not open file '%s'\n", filename);
171 g_print ("Usage: %s [filename]\n", argv[0]);
172 return 1;
173 }
174 fclose (fp);
175 }
176 else
177 filename = NULL;
178
179 gtk_init (&argc, &argv); /* must be before any other gtk_functions... */
180 current_tool = SPACE;
181 init_blocks (); /* ...like the ones in here */
182
183 init_grid (filename); /* loads file or creates 16x16 grid
184 with SPACE */
185
186 toolbox = create_toolbox_window (filename); /* main window creation */
187
188 gtk_main (); /* Main message loop -- Go! */
189
190 return 0; /* Everything went fine (from our
191 perspective) */
192 }
193
194 /* initialises the rest of the "blocks" array */
195 void
init_blocks()196 init_blocks ()
197 {
198 int i; /* counter */
199 GdkColormap *colour; /* necessary for creating pixmaps
200 -- otherwise warnings ensue */
201 #include "xpm/food.xpm"
202 #include "xpm/space.xpm"
203 #include "xpm/prize.xpm"
204 #include "xpm/baddie.xpm"
205 #include "xpm/wall.xpm"
206
207 /* These could be set globally, but this avoids making the xpm data
208 global */
209
210 blocks[0].xpm_data = space_xpm;
211 blocks[1].xpm_data = food_xpm;
212 blocks[2].xpm_data = wall_xpm;
213 blocks[3].xpm_data = baddie_xpm;
214 blocks[4].xpm_data = prize_xpm;
215
216 colour = gdk_colormap_get_system (); /* needed to prevent warnings */
217
218 for (i = 0; i < nblocks; i++)
219 {
220 blocks[i].pixmap =
221 gdk_pixmap_colormap_create_from_xpm_d (NULL, colour, NULL, NULL,
222 blocks[i].xpm_data);
223 }
224 }
225
226 /* either loads file or creates blank map -- called at beginning */
227
228 void
init_grid(char * filename)229 init_grid (char *filename)
230 {
231 int i; /* counter */
232
233 if (filename) /* file specified -- only false first
234 time if no command line options */
235 {
236 load_file (filename);
237 }
238
239 else
240 {
241 grid.width = grid.height = 16;
242
243 grid.data = (char *) g_malloc (grid.width * grid.height * sizeof (char)); /* grab memory */
244
245 for (i = 0; i < grid.width * grid.height; i++) /* initialise grid */
246 {
247 grid.data[i] = SPACE;
248 }
249 }
250 }
251
252 /* callback for radio buttons -- changes tool */
253
254 void
change_tool(GtkWidget * widget,gpointer data)255 change_tool (GtkWidget * widget, gpointer data)
256 {
257 /* can't just pass integer -- need GINT_TO_POINTER and converse */
258
259 current_tool = GPOINTER_TO_INT (data);
260 }
261
262 /* This creates a pixmap and a label from data -- returns hbox with contents */
263
264 GtkWidget *
create_pixmap_with_label(GtkWidget * parent,GdkPixmap * pixmap,char * text)265 create_pixmap_with_label (GtkWidget * parent, GdkPixmap * pixmap, char *text)
266 {
267 GtkWidget *pixmapwid, *box, *label; /* All variables -- easier
268 than doubling up */
269
270 box = gtk_hbox_new (FALSE, 2);
271
272 /* Create them */
273
274 pixmapwid = gtk_pixmap_new (pixmap, NULL);
275 gtk_widget_show (pixmapwid);
276 label = gtk_label_new (text);
277 gtk_widget_show (label);
278
279 /* Put them in the box */
280
281 gtk_box_pack_start (GTK_BOX (box), pixmapwid, FALSE, FALSE, 4);
282 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 4);
283 gtk_widget_show (box);
284
285 return box;
286 }
287
288 /* This creates a vbox with each tool in linked to specified function */
289
290 GtkWidget *
create_toolbox_box(GtkWidget * parent,GtkSignalFunc func)291 create_toolbox_box (GtkWidget * parent, GtkSignalFunc func)
292 {
293 int i; /* counter */
294 GtkWidget *box; /* Box to return */
295 GtkWidget *button; /* radio button for tools */
296 GtkWidget *pixmap; /* Picture to display -- with label */
297
298 box = gtk_vbox_new (FALSE, 2);
299
300 for (i = 0, button = NULL; i < nblocks; i++)
301 {
302 pixmap = create_pixmap_with_label (parent, blocks[i].pixmap, blocks[i].name); /* actually a box -- but contains a pixmap */
303
304 /* create button radio group -- use ?: to prevent special case */
305
306 button =
307 gtk_radio_button_new (button ?
308 gtk_radio_button_group (GTK_RADIO_BUTTON
309 (button)) : NULL);
310
311 gtk_container_add (GTK_CONTAINER (button), pixmap);
312
313 gtk_signal_connect (GTK_OBJECT (button), "clicked",
314 GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (i));
315
316 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
317
318 gtk_widget_show (button);
319 }
320
321 return box; /* return a nice package */
322 }
323
324 /* callback for clicking save button -- currently only way so it does
325 th work here */
326
327 void
save_button(GtkWidget * widget,GtkEntry * textbox)328 save_button (GtkWidget * widget, GtkEntry * textbox)
329 {
330 /* textbox is passed as data in ...signal_connect */
331
332 int i, j; /* counters -- width & height */
333 FILE *fp;
334 char *filename; /* obtained from "textbox" */
335
336 if (!grid_window) /* Don't save if they've closed the window */
337 {
338 return;
339 }
340
341 /* Open and check file */
342
343 filename = gtk_entry_get_text (GTK_ENTRY (textbox));
344 fp = fopen (filename, "w");
345
346 if (!fp) /* can't proceed */
347 {
348 message_box ("Error:", "Could not save file");
349 return; /* Can't proceed */
350 }
351
352 /* Write file */
353
354 for (i = 0; i < grid.height; i++)
355 {
356 for (j = 0; j < grid.width; j++)
357 fputc (blocks[(int) grid.data[i * grid.width + j]].save_char, fp); /* put the save_char for correct "blocks" entry */
358
359 fputc ('\n', fp); /* newline */
360 }
361
362 fclose (fp);
363 }
364
365 /* actual function to load file -- don't put more spare \n's at end
366 than width -- it won't like it */
367
368 void
load_file(char * filename)369 load_file (char *filename)
370 {
371 FILE *fp;
372 int length; /* length of file */
373
374 int ctr, i, first; /* counter into data,
375 counter for finding correct block,
376 whether first line */
377
378 char *data, c; /* buffer and current character */
379
380 /* standard open and check... */
381
382 fp = fopen (filename, "r");
383
384 if (!fp)
385 {
386 message_box ("Error", "Could not open file");
387 return;
388 }
389
390 /* find file size -- and allocation */
391
392 fseek (fp, 0, SEEK_END);
393 length = ftell (fp);
394 rewind (fp); /* for reading */
395
396 data = (char *) g_malloc (length * sizeof (char));
397
398 /* will be larger than necessary -- but only by (height) bytes
399 usually */
400
401 ctr = 0; /* index into "data" */
402
403 first = 1; /* first line */
404
405 while ((c = fgetc (fp)) != EOF)
406 {
407 /* This is executed more frequently than strictly necessary
408 (ideally only on \n as well as normal) -- but this ensures
409 things work */
410
411 data[ctr] = WALL; /* Sensible default (used in xrobots
412 as default) */
413
414 /* find correct block */
415
416 for (i = 0; i < nblocks; i++)
417 if (c == blocks[i].save_char)
418 {
419 data[ctr++] = i;
420 break;
421 }
422
423 if (c == '\n' && first) /* end of first line -- now know width */
424 {
425 first = 0; /* not first any more */
426 grid.width = ctr;
427 }
428 }
429 fclose (fp); /* Done here */
430
431 grid.height = length / (grid.width + 1); /* height * (width + newlines) == file size (roughly) */
432
433 g_free (grid.data); /* free the old... */
434
435 grid.data = data; /* ...and replace with new */
436 }
437
438 /* Actual load button clicked -- calls load_file for hard work*/
439
440 void
load_button(GtkWidget * widget,GtkEntry * textbox)441 load_button (GtkWidget * widget, GtkEntry * textbox)
442 {
443 char *filename;
444
445 filename = gtk_entry_get_text (textbox);
446 load_file (filename);
447
448 recreate_grid_window (); /* destroys current window and creates new */
449 }
450
451 /* Callback for Setting Size button */
452
453 void
set_size(GtkWidget * widget,gpointer data)454 set_size (GtkWidget * widget, gpointer data)
455 {
456 int x, y, i;
457
458 x = atoi (gtk_entry_get_text (width_text));
459 y = atoi (gtk_entry_get_text (height_text));
460 if (x > 0 && y > 0 && (x != grid.width || y != grid.height))
461 /* check data in boxes (don't change to same size as now) */
462 {
463 grid.width = x;
464 grid.height = y;
465
466 if (grid.data)
467 g_free (grid.data);
468
469 grid.data =
470 (char *) g_malloc (grid.width * grid.height * sizeof (char));
471
472 for (i = 0; i < grid.width * grid.height; i++) /* note that current grid is not saved or scaled */
473 grid.data[i] = SPACE;
474
475 recreate_grid_window (); /* inform gtk of change */
476 }
477 }
478
479 /* destroys current map window and creates new */
480
481 void
recreate_grid_window()482 recreate_grid_window ()
483 {
484 if (grid_window) /* just in case -- person could have
485 closed the window */
486 {
487 gtk_widget_destroy (grid_window);
488 }
489 grid_window = create_grid_window ();
490 }
491
492 /* create box of functions -- very tedious */
493
494 GtkWidget *
create_command_box(char * filename)495 create_command_box (char *filename)
496 {
497 char str[255]; /* to set text boxes based on
498 width/height -- I know it's
499 unlikely that it will be 255 chars
500 long */
501
502 GtkWidget *vbox, *sizebox; /* vbox == main box for widgets,
503 sizebox == box for Entrys & labels
504 for size */
505
506 GtkWidget *button, *textbox; /* generic button followed by textbox
507 for filename */
508
509 GtkWidget *label, *xsize, *ysize; /* stuff for setting size */
510
511 vbox = gtk_vbox_new (FALSE, 3); /* create main box */
512
513 /* create filename textentry */
514
515 textbox = gtk_entry_new ();
516
517 gtk_entry_set_text (GTK_ENTRY (textbox),
518 filename ? filename : "newmap.map");
519
520 gtk_widget_show (textbox);
521
522 gtk_box_pack_start (GTK_BOX (vbox), textbox, FALSE, FALSE, 2);
523
524 /* create save button & link with callback */
525
526 button = gtk_button_new_with_label ("Save");
527
528 gtk_signal_connect (GTK_OBJECT (button), "clicked",
529 GTK_SIGNAL_FUNC (save_button), textbox); /* note it gets the filename as data */
530
531 gtk_widget_show (button);
532
533 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 2);
534
535 /* create the load button & link */
536
537 button = gtk_button_new_with_label ("Load");
538
539 gtk_signal_connect (GTK_OBJECT (button), "clicked",
540 GTK_SIGNAL_FUNC (load_button), textbox); /* Also gets callback */
541
542 gtk_widget_show (button);
543
544 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 2);
545
546 /* create row for size controls -- except actual button */
547
548 sizebox = gtk_hbox_new (FALSE, 1);
549
550 /* X label & text */
551
552 label = gtk_label_new ("X:");
553 gtk_widget_show (label);
554
555 gtk_box_pack_start (GTK_BOX (sizebox), label, FALSE, FALSE, 1);
556
557 xsize = gtk_entry_new_with_max_length (3);
558 width_text = GTK_ENTRY (xsize);
559 sprintf (str, "%d", grid.width);
560 gtk_entry_set_text (GTK_ENTRY (xsize), str);
561 gtk_widget_set_usize (xsize, 30, 20);
562 gtk_widget_show (xsize);
563
564 gtk_box_pack_start (GTK_BOX (sizebox), xsize, FALSE, FALSE, 1);
565
566 /* Y label && text */
567
568 label = gtk_label_new ("Y:");
569 gtk_widget_show (label);
570
571 gtk_box_pack_start (GTK_BOX (sizebox), label, FALSE, FALSE, 1);
572
573 ysize = gtk_entry_new_with_max_length (3);
574 height_text = GTK_ENTRY (ysize);
575 sprintf (str, "%d", grid.height);
576 gtk_entry_set_text (GTK_ENTRY (ysize), str);
577 gtk_widget_set_usize (ysize, 30, 20);
578 gtk_widget_show (ysize);
579
580 gtk_box_pack_start (GTK_BOX (sizebox), ysize, FALSE, FALSE, 1);
581
582 gtk_widget_show (sizebox);
583 gtk_box_pack_start (GTK_BOX (vbox), sizebox, FALSE, FALSE, 2);
584
585 /* Done size controls */
586
587 /* Actual size button */
588
589 button = gtk_button_new_with_label ("Set Size");
590
591 gtk_signal_connect (GTK_OBJECT (button), "clicked",
592 GTK_SIGNAL_FUNC (set_size), NULL);
593
594 gtk_widget_show (button);
595
596 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 2);
597
598 return vbox; /* return nice simple package */
599 }
600
601 /* This creates and initialises the toolbox window (actually the MAIN
602 WINDOW)*/
603
604 GtkWidget *
create_toolbox_window(char * filename)605 create_toolbox_window (char *filename)
606 {
607 GtkWidget *window; /* main window */
608
609 GtkWidget *toolbox, *command_box, *hbox; /* three important components (hbox to store others) */
610
611 grid_window = create_grid_window (); /* map window controlled by
612 this -- needs to be able to
613 load */
614
615 /* Create our window -- its closure causes the app to quit... */
616
617 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
618 gtk_window_set_title (GTK_WINDOW (window), "Toolbox");
619
620 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
621 GTK_SIGNAL_FUNC (gtk_exit), NULL); /* ... as setup on this line */
622
623 /* create and display two panes of display */
624
625 toolbox = create_toolbox_box (window, change_tool);
626 gtk_widget_show (toolbox);
627 command_box = create_command_box (filename);
628 gtk_widget_show (command_box);
629
630 /* join two panes together */
631
632 hbox = gtk_hbox_new (FALSE, 5);
633 gtk_box_pack_start (GTK_BOX (hbox), toolbox, FALSE, FALSE, 5);
634 gtk_box_pack_start (GTK_BOX (hbox), command_box, FALSE, FALSE, 5);
635 gtk_widget_show (hbox);
636 gtk_container_add (GTK_CONTAINER (window), hbox);
637
638 /* show window */
639
640 gtk_widget_show (window);
641 return window; /* give it back to main */
642 }
643
644 /* receives position to change -- puts correct pixmap in place */
645
646 /* See Fixed(Wibble1) in create_grid_window for description of fixed */
647
648 void
update_grid(GtkFixed * fixed,int x,int y)649 update_grid (GtkFixed * fixed, int x, int y)
650 {
651 int length, i, dx, dy; /* length == how many children are in fixed,
652 i == counter for iteration,
653 dx, dy == How far apart the current position is from the desired one */
654
655 GList *children; /* children of fixed -- i.e. the
656 pixmap widgets */
657
658 GtkFixedChild *child; /* individual child of fixed */
659
660 grid.data[x + y * grid.width] = current_tool;
661
662 /* initialise for search */
663
664 children = fixed->children;
665 length = g_list_length (children);
666
667 /* start finding -- this is a horrible kludge, but the simplest to
668 code */
669
670 for (i = 0; i < length; i++)
671 {
672 child = (GtkFixedChild *) g_list_nth_data (children, i); /* get current thing */
673
674 dx = x - (child->x / IMGSIZE); /* position in pixels -- must be changed to reality */
675
676 dy = y - (child->y / IMGSIZE);
677
678 if (dx == 0 && dy == 0) /* if correct position */
679 {
680 gtk_pixmap_set (GTK_PIXMAP (child->widget),
681 blocks[current_tool].pixmap, NULL); /* change the pixmap */
682
683 break; /* and quit -- don't compound folly */
684 }
685 }
686 }
687
688 /* handler for drawing -- set dragging true */
689
690 void
button_press(GtkFixed * fixed,GdkEventButton * event,gpointer data)691 button_press (GtkFixed * fixed, GdkEventButton * event, gpointer data)
692 {
693 int i, j; /* positions */
694
695 dragging = 1;
696
697 i = (int) (event->x / IMGSIZE);
698 j = (int) (event->y / IMGSIZE);
699
700 update_grid (fixed, i, j); /* set current square so user doesn't
701 have to move mouse */
702 }
703
704 /* callback for mouse moved on map window -- checks dragging */
705
706 /* This is not ideal as it puts extra load on the cpu when the mouse
707 is moving in the map window */
708
709 void
mouse_move(GtkFixed * fixed,GdkEventMotion * event,gpointer data)710 mouse_move (GtkFixed * fixed, GdkEventMotion * event, gpointer data)
711 {
712 int i, j;
713
714 i = (int) (event->x / IMGSIZE);
715 j = (int) (event->y / IMGSIZE);
716 if (dragging)
717 update_grid (fixed, i, j);
718 }
719
720 /* stop drawing */
721
722 void
button_release(GtkFixed * fixed,GdkEventButton * event,gpointer data)723 button_release (GtkFixed * fixed, GdkEventButton * event, gpointer data)
724 {
725 dragging = 0;
726 }
727
728 /* called when user closes window -- sets grid_window to NULL to
729 prevent recreate_grid_window segfaulting */
730
731 void
destroy_func(GtkWidget * widget,gpointer data)732 destroy_func (GtkWidget * widget, gpointer data)
733 {
734 *((GtkWidget **) data) = NULL;
735 grid_window = NULL;
736 }
737
738 /* Does the donkeywork in creating the map view */
739
740 GtkWidget *
create_grid_window()741 create_grid_window ()
742 {
743 int i, j, type; /* i, j for iteration through "grid.data",
744 type == index into blocks -- stored
745 for convenience */
746
747 GtkWidget *window; /* actual window */
748 GtkWidget *fixed; /* layout manager for pictures */
749
750 GtkWidget *pixmap; /* temporary sotrage for each picture
751 while in use */
752
753 /* first create and set up main features */
754
755 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
756 gtk_signal_connect (GTK_OBJECT (window), "destroy",
757 GTK_SIGNAL_FUNC (destroy_func), &window);
758 gtk_window_set_title (GTK_WINDOW (window), "Map View");
759
760 /* Fixed(Wibble1):
761 fixed is a method of storing widgets by position,
762 1. I create a sequence of pixmap widgets and place them in correct positions,
763 2. I initialise them to the correct picture,
764 3. I link the fixed's press, motion & release events to something to find which
765 pixmap is under pointer and change picture & "grid" */
766
767 fixed = gtk_fixed_new ();
768
769 for (i = 0; i < grid.width; i++)
770 for (j = 0; j < grid.height; j++)
771 {
772 type = grid.data[i + j * grid.width];
773 pixmap = gtk_pixmap_new (blocks[type].pixmap, NULL);
774
775 gtk_fixed_put (GTK_FIXED (fixed), pixmap, i * IMGSIZE, j * IMGSIZE); /* position */
776
777 gtk_widget_show (pixmap);
778 }
779
780 /* enable events needed... */
781
782 gtk_widget_set_events (fixed,
783 GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK |
784 GDK_BUTTON_RELEASE_MASK);
785
786 /* ... and take control */
787
788 gtk_signal_connect (GTK_OBJECT (fixed), "button_press_event",
789 GTK_SIGNAL_FUNC (button_press), NULL);
790
791 gtk_signal_connect (GTK_OBJECT (fixed), "motion_notify_event",
792 GTK_SIGNAL_FUNC (mouse_move), NULL);
793
794 gtk_signal_connect (GTK_OBJECT (fixed), "button_release_event",
795 GTK_SIGNAL_FUNC (button_release), NULL);
796
797 gtk_widget_show (fixed);
798
799 gtk_container_add (GTK_CONTAINER (window), fixed); /* window only contains pictures */
800
801 gtk_widget_show (window);
802
803 return window; /* give the window back to
804 create_toolbox_window */
805 }
806
807 /* Free all the rubbish */
808
809 void
freestuff()810 freestuff ()
811 {
812 g_free (grid.data);
813 }
814
815 /* Doesn't look very nice but is functional (message box and code) */
816
817 void
message_box(char * title,char * text)818 message_box (char *title, char *text)
819 {
820 GtkWidget *label, *window, *button, *box;
821
822 window = gtk_window_new (GTK_WINDOW_DIALOG); /* make window */
823
824 gtk_window_set_title (GTK_WINDOW (window), title);
825
826 label = gtk_label_new (text); /* Label as required */
827
828 gtk_widget_show (label);
829
830 button = gtk_button_new_with_label ("OK"); /* Just an OK button
831 that kills the
832 window */
833
834 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
835 GTK_SIGNAL_FUNC (gtk_widget_destroy),
836 (gpointer) window);
837
838 gtk_widget_show (button);
839
840 box = gtk_vbox_new (FALSE, 3); /* Put everything in... */
841
842 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 3);
843 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
844
845 gtk_widget_show (box);
846
847 gtk_container_add (GTK_CONTAINER (window), box);
848
849 gtk_widget_show (window); /* ... and show */
850
851 /* Don't return anything -- no interaction necessary */
852 }
853