1
/* gcompris - read_colors.c
3
* Copyright (C) 2002 Pascal Georges
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 3 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, see <http://www.gnu.org/licenses/>.
22
#include <libxml/tree.h>
23
#include <libxml/parser.h>
25
#include "gcompris/gcompris.h"
27
#define SOUNDLISTFILE PACKAGE
29
static GcomprisBoard *gcomprisBoard = NULL;
30
static gboolean board_paused = TRUE;
32
static void start_board (GcomprisBoard *agcomprisBoard);
33
static void pause_board (gboolean pause);
34
static void end_board (void);
35
static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
38
static void process_ok(void);
39
static void highlight_selected(int);
40
static void game_won(void);
42
static void init_xml();
43
static gboolean read_xml_file(char *fname);
45
/* ================================================================ */
46
static GnomeCanvasGroup *boardRootItem = NULL;
47
static GnomeCanvasItem *highlight_image_item = NULL;
48
static GnomeCanvasItem *color_item = NULL;
49
static GnomeCanvasItem *clock_image_item = NULL;
50
static GdkPixbuf *clock_pixmap = NULL;
52
static GnomeCanvasItem *read_colors_create_item(GnomeCanvasGroup *parent);
53
static void read_colors_destroy_all_items(void);
54
static void read_colors_next_level(void);
55
static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
56
static void update_clock();
58
static int highlight_width, highlight_height, errors;
59
static GList * listColors = NULL;
66
static char* colors[LAST_COLOR];
68
static int X[] = {100,300,500,700,200,400,600,100,300,500,700};
69
static int Y[] = {90,90,90,90,180,180,180,270,270,270,270};
71
/* (x1,y1) and (x2, y2) are the coordinates of the rectangle where to
72
draw the color's name */
73
static int color_x1 = 240, color_x2 = 570;
74
static int color_y1 = 395, color_y2 = 490;
78
/* Description of this plugin */
79
static BoardPlugin menu_bp =
84
"Click on the corresponding color",
85
"Pascal Georges pascal.georges1@free.fr>",
103
/* =====================================================================
105
* =====================================================================*/
106
GET_BPLUGIN_INFO(read_colors)
108
/* =====================================================================
109
* in : boolean TRUE = PAUSE : FALSE = CONTINUE
110
* =====================================================================*/
111
static void pause_board (gboolean pause)
113
if(gcomprisBoard==NULL)
117
if(gamewon == TRUE && pause == FALSE) /* the game is won */
120
board_paused = pause;
123
/* =====================================================================
125
* =====================================================================*/
126
static void start_board (GcomprisBoard *agcomprisBoard) {
131
if(agcomprisBoard!=NULL) {
132
gcomprisBoard=agcomprisBoard;
133
gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), "read_colors/read_colors_background.png");
134
gcomprisBoard->level=1;
135
gcomprisBoard->maxlevel=1;
143
// we generate a list of color indexes in a random order
144
while (g_list_length(listColors) > 0)
145
listColors = g_list_remove(listColors, g_list_nth_data(listColors,0));
147
for (i=0; i<LAST_COLOR; i++)
148
list = g_list_append(list, GINT_TO_POINTER(i));
150
while ((list_length = g_list_length(list))) {
151
i = list_length == 1 ? 0 : g_random_int_range(0,g_list_length(list)-1);
152
item = g_list_nth_data(list, i);
153
listColors = g_list_append(listColors, item);
154
list = g_list_remove(list, item);
158
gtk_signal_connect(GTK_OBJECT(gcomprisBoard->canvas), "event", (GtkSignalFunc) item_event, NULL);
159
read_colors_next_level();
164
/* =====================================================================
166
* =====================================================================*/
167
static void end_board () {
169
if(gcomprisBoard!=NULL){
172
read_colors_destroy_all_items();
174
while (g_list_length(listColors) > 0)
175
listColors = g_list_remove(listColors, g_list_nth_data(listColors,0));
177
g_list_free(listColors);
180
gcomprisBoard = NULL;
183
/* =====================================================================
185
* =====================================================================*/
186
static gboolean is_our_board (GcomprisBoard *gcomprisBoard) {
188
if(g_strcasecmp(gcomprisBoard->type, "read_colors")==0) {
189
/* Set the plugin entry */
190
gcomprisBoard->plugin=&menu_bp;
196
/* =====================================================================
197
* set initial values for the next level
198
* =====================================================================*/
199
static void read_colors_next_level() {
201
read_colors_destroy_all_items();
204
/* Try the next level */
205
read_colors_create_item(gnome_canvas_root(gcomprisBoard->canvas));
207
/* show text of color to find */
208
color_item = gnome_canvas_item_new (boardRootItem,
209
gnome_canvas_text_get_type (),
210
"text", colors[GPOINTER_TO_INT(g_list_nth_data(listColors,0))],
211
"font", gc_skin_font_board_title_bold,
212
"x", (double) (color_x1+color_x2)/2,
213
"y", (double) (color_y1+color_y2)/2,
214
"anchor", GTK_ANCHOR_CENTER,
215
"fill_color", "darkblue",
219
/* =====================================================================
220
* Destroy all the items
221
* =====================================================================*/
222
static void read_colors_destroy_all_items() {
223
if(boardRootItem!=NULL)
224
gtk_object_destroy (GTK_OBJECT(boardRootItem));
226
boardRootItem = NULL;
229
/* =====================================================================
231
* =====================================================================*/
232
static GnomeCanvasItem *read_colors_create_item(GnomeCanvasGroup *parent) {
233
GdkPixbuf *highlight_pixmap = NULL;
236
boardRootItem = GNOME_CANVAS_GROUP(
237
gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
238
gnome_canvas_group_get_type (),
243
str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "read_colors_highlight.png");
244
highlight_pixmap = gc_pixmap_load(str);
246
highlight_image_item = gnome_canvas_item_new (boardRootItem,
247
gnome_canvas_pixbuf_get_type (),
248
"pixbuf", highlight_pixmap,
251
"width", (double) gdk_pixbuf_get_width(highlight_pixmap),
252
"height", (double) gdk_pixbuf_get_height(highlight_pixmap),
257
highlight_width = gdk_pixbuf_get_width(highlight_pixmap);
258
highlight_height = gdk_pixbuf_get_height(highlight_pixmap);
261
gnome_canvas_item_hide(highlight_image_item);
263
gdk_pixbuf_unref(highlight_pixmap);
265
/* setup the clock */
266
str = g_strdup_printf("%s%d.png", "gcompris/timers/clock",errors);
267
clock_pixmap = gc_pixmap_load(str);
269
clock_image_item = gnome_canvas_item_new (boardRootItem,
270
gnome_canvas_pixbuf_get_type (),
271
"pixbuf", clock_pixmap,
272
"x", (double) CLOCK_X,
273
"y", (double) CLOCK_Y,
274
"width", (double) gdk_pixbuf_get_width(clock_pixmap),
275
"height", (double) gdk_pixbuf_get_height(clock_pixmap),
284
/* =====================================================================
286
* =====================================================================*/
287
static void update_clock() {
288
char *str = g_strdup_printf("%s%d.png", "gcompris/timers/clock",errors);
290
gtk_object_destroy (GTK_OBJECT(clock_image_item));
292
clock_pixmap = gc_pixmap_load(str);
294
clock_image_item = gnome_canvas_item_new (boardRootItem,
295
gnome_canvas_pixbuf_get_type (),
296
"pixbuf", clock_pixmap,
297
"x", (double) CLOCK_X,
298
"y", (double) CLOCK_Y,
299
"width", (double) gdk_pixbuf_get_width(clock_pixmap),
300
"height", (double) gdk_pixbuf_get_height(clock_pixmap),
305
gdk_pixbuf_unref(clock_pixmap);
308
/* =====================================================================
310
* =====================================================================*/
311
static void game_won() {
312
gcomprisBoard->sublevel++;
314
listColors = g_list_remove(listColors, g_list_nth_data(listColors,0));
316
if( g_list_length(listColors) <= 0 ) { // the current board is finished : bail out
317
gc_bonus_end_display(GC_BOARD_FINISHED_TUXLOCO);
321
read_colors_next_level();
323
/* =====================================================================
325
* =====================================================================*/
326
static gboolean process_ok_timeout() {
327
gc_bonus_display(gamewon, GC_BONUS_SMILEY);
335
gc_bonus_end_display(GC_BOARD_FINISHED_TOOMANYERRORS);
341
static void process_ok() {
343
// leave time to display the right answer
344
g_timeout_add(TIME_CLICK_TO_BONUS, process_ok_timeout, NULL);
347
/* =====================================================================
349
* =====================================================================*/
350
static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
357
if (!gcomprisBoard || board_paused)
362
case GDK_BUTTON_PRESS:
363
gnome_canvas_c2w (gcomprisBoard->canvas, x, y, &x, &y);
365
for (i=0; i<LAST_COLOR; i++) {
366
if (hypot((double) (X[i]-x),(double)(Y[i]-y)) < RADIUS) {
373
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
375
highlight_selected(clicked);
376
gamewon = (clicked == GPOINTER_TO_INT(g_list_nth_data(listColors,0)));
387
/* =====================================================================
389
* =====================================================================*/
390
static void highlight_selected(int c) {
393
g_assert(c>=0 && c<LAST_COLOR);
398
x -= highlight_width/2;
399
y -= highlight_height/2;
400
gnome_canvas_item_show(highlight_image_item);
401
gc_item_absolute_move(highlight_image_item, x, y);
403
/* ===================================
405
* ==================================== */
406
static void init_xml()
410
filename = gc_file_find_absolute("%s/board1.xml",
411
gcomprisBoard->boarddir);
413
g_assert(read_xml_file(filename)== TRUE);
418
/* ==================================== */
419
static void add_xml_data(xmlDocPtr doc, xmlNodePtr xmlnode, GNode * child)
425
xmlnode = xmlnode->xmlChildrenNode;
427
xmlnode = xmlnode->next;
429
while (xmlnode != NULL) {
431
// try to match color[i]
432
for (i=0; i<LAST_COLOR; i++) {
433
sColor = g_strdup_printf("color%d", i+1);
434
if (!strcmp((char *)xmlnode->name, sColor)) {
436
gettext((char *)xmlNodeListGetString(doc, xmlnode->xmlChildrenNode, 1));
443
xmlnode = xmlnode->next;
446
// I really don't know why this test, but otherwise, the list is doubled
447
// with 1 line on 2 filled with NULL elements
453
/* ==================================== */
454
static void parse_doc(xmlDocPtr doc)
458
for(node = doc->children->children; node != NULL; node = node->next) {
459
if ( g_strcasecmp((gchar *)node->name, "Board") == 0 )
460
add_xml_data(doc, node,NULL);
464
/* ==================================== */
465
/* read an xml file into our memory structures and update our view,
466
dump any old data we have in memory if we can load a new set */
467
static gboolean read_xml_file(char *fname)
469
/* pointer to the new doc */
472
g_return_val_if_fail(fname!=NULL,FALSE);
474
/* parse the new file and put the result into newdoc */
475
doc = xmlParseFile(fname);
477
/* in case something went wrong */
481
if(/* if there is no root element */
483
/* if it doesn't have a name */
484
!doc->children->name ||
485
/* if it isn't a ImageId node */
486
g_strcasecmp((char *)doc->children->name,"ReadColors")!=0) {