Back to index

gcompris  8.2.2
read_colors.c
Go to the documentation of this file.
00001 /* gcompris - read_colors.c
00002  *
00003  * Copyright (C) 2002 Pascal Georges
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU General Public License as published by
00007  *   the Free Software Foundation; either version 2 of the License, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details.
00014  *
00015  *   You should have received a copy of the GNU General Public License
00016  *   along with this program; if not, write to the Free Software
00017  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #include <string.h>
00021 
00022 /* libxml includes */
00023 #include <libxml/tree.h>
00024 #include <libxml/parser.h>
00025 
00026 #include "gcompris/gcompris.h"
00027 
00028 #define SOUNDLISTFILE PACKAGE
00029 
00030 static GcomprisBoard *gcomprisBoard = NULL;
00031 static gboolean board_paused = TRUE;
00032 
00033 static void           start_board (GcomprisBoard *agcomprisBoard);
00034 static void           pause_board (gboolean pause);
00035 static void           end_board (void);
00036 static gboolean              is_our_board (GcomprisBoard *gcomprisBoard);
00037 static int gamewon;
00038 
00039 static void           process_ok(void);
00040 static void           highlight_selected(int);
00041 static void           game_won(void);
00042 
00043 static void           init_xml();
00044 static gboolean       read_xml_file(char *fname);
00045 
00046 /* ================================================================ */
00047 static GnomeCanvasGroup *boardRootItem = NULL;
00048 static GnomeCanvasItem *highlight_image_item = NULL;
00049 static GnomeCanvasItem *color_item = NULL;
00050 static GnomeCanvasItem *clock_image_item = NULL;
00051 static GdkPixbuf *clock_pixmap = NULL;
00052 
00053 static GnomeCanvasItem *read_colors_create_item(GnomeCanvasGroup *parent);
00054 static void read_colors_destroy_all_items(void);
00055 static void read_colors_next_level(void);
00056 static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00057 static void update_clock();
00058 
00059 static int highlight_width, highlight_height, errors;
00060 static GList * listColors = NULL;
00061 
00062 #define LAST_COLOR 11
00063 #define MAX_ERRORS 10
00064 #define CLOCK_X 40
00065 #define CLOCK_Y 420
00066 
00067 static char* colors[LAST_COLOR];
00068 
00069 static int X[] = {100,300,500,700,200,400,600,100,300,500,700};
00070 static int Y[] = {90,90,90,90,180,180,180,270,270,270,270};
00071 
00072 /* (x1,y1) and (x2, y2) are the coordinates of the rectangle where to
00073    draw the color's name */
00074 static int color_x1 = 240, color_x2 = 570;
00075 static int color_y1 = 395, color_y2 = 490;
00076 
00077 #define RADIUS 60
00078 
00079 /* Description of this plugin */
00080 static BoardPlugin menu_bp =
00081   {
00082     NULL,
00083     NULL,
00084     "Read Colors",
00085     "Click on the corresponding color",
00086     "Pascal Georges pascal.georges1@free.fr>",
00087     NULL,
00088     NULL,
00089     NULL,
00090     NULL,
00091     start_board,
00092     pause_board,
00093     end_board,
00094     is_our_board,
00095     NULL,
00096     process_ok,
00097     NULL,//set_level,
00098     NULL,
00099     NULL,
00100     NULL,
00101     NULL
00102   };
00103 
00104 /* =====================================================================
00105  *
00106  * =====================================================================*/
00107 GET_BPLUGIN_INFO(read_colors)
00108 
00109 /* =====================================================================
00110  * in : boolean TRUE = PAUSE : FALSE = CONTINUE
00111  * =====================================================================*/
00112 static void pause_board (gboolean pause)
00113 {
00114   if(gcomprisBoard==NULL)
00115     return;
00116 
00117   gc_bar_hide(FALSE);
00118   if(gamewon == TRUE && pause == FALSE) /* the game is won */
00119     game_won();
00120 
00121   board_paused = pause;
00122 }
00123 
00124 /* =====================================================================
00125  *
00126  * =====================================================================*/
00127 static void start_board (GcomprisBoard *agcomprisBoard) {
00128   GList * list = NULL;
00129   int * item;
00130   int i;
00131 
00132   if(agcomprisBoard!=NULL) {
00133     gcomprisBoard=agcomprisBoard;
00134     gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), "read_colors/read_colors_background.png");
00135     gcomprisBoard->level=1;
00136     gcomprisBoard->maxlevel=1;
00137     gc_bar_set(0);
00138 
00139     gamewon = FALSE;
00140     errors = MAX_ERRORS;
00141 
00142     init_xml();
00143 
00144     // we generate a list of color indexes in a random order
00145     while (g_list_length(listColors) > 0)
00146       listColors = g_list_remove(listColors, g_list_nth_data(listColors,0));
00147 
00148     for (i=0; i<LAST_COLOR; i++)
00149       list = g_list_append(list, GINT_TO_POINTER(i));
00150 
00151     while ((g_list_length(list) > 0)) {
00152       i = RAND(0,g_list_length(list)-1);
00153       item = g_list_nth_data(list, i);
00154       listColors = g_list_append(listColors, item);
00155       list = g_list_remove(list, item);
00156     }
00157     g_list_free(list);
00158 
00159     gtk_signal_connect(GTK_OBJECT(gcomprisBoard->canvas), "event",  (GtkSignalFunc) item_event, NULL);
00160     read_colors_next_level();
00161     pause_board(FALSE);
00162   }
00163 }
00164 
00165 /* =====================================================================
00166  *
00167  * =====================================================================*/
00168 static void end_board () {
00169 
00170   if(gcomprisBoard!=NULL){
00171     pause_board(TRUE);
00172     gc_score_end();
00173     read_colors_destroy_all_items();
00174     // free list
00175     while (g_list_length(listColors) > 0)
00176       listColors = g_list_remove(listColors, g_list_nth_data(listColors,0));
00177 
00178     g_list_free(listColors);
00179     listColors = NULL;
00180   }
00181   gcomprisBoard = NULL;
00182 }
00183 
00184 /* =====================================================================
00185  *
00186  * =====================================================================*/
00187 static gboolean is_our_board (GcomprisBoard *gcomprisBoard) {
00188   if (gcomprisBoard) {
00189     if(g_strcasecmp(gcomprisBoard->type, "read_colors")==0) {
00190       /* Set the plugin entry */
00191       gcomprisBoard->plugin=&menu_bp;
00192       return TRUE;
00193     }
00194   }
00195   return FALSE;
00196 }
00197 /* =====================================================================
00198  * set initial values for the next level
00199  * =====================================================================*/
00200 static void read_colors_next_level() {
00201 
00202   read_colors_destroy_all_items();
00203   gamewon = FALSE;
00204 
00205   /* Try the next level */
00206   read_colors_create_item(gnome_canvas_root(gcomprisBoard->canvas));
00207 
00208   /* show text of color to find */
00209   color_item = gnome_canvas_item_new (boardRootItem,
00210                                   gnome_canvas_text_get_type (),
00211                                   "text", colors[GPOINTER_TO_INT(g_list_nth_data(listColors,0))],
00212                                   "font", gc_skin_font_board_title_bold,
00213                                   "x", (double) (color_x1+color_x2)/2,
00214                                   "y", (double) (color_y1+color_y2)/2,
00215                                   "anchor", GTK_ANCHOR_CENTER,
00216                                   "fill_color", "darkblue",
00217                                   NULL);
00218 
00219 }
00220 /* =====================================================================
00221  * Destroy all the items
00222  * =====================================================================*/
00223 static void read_colors_destroy_all_items() {
00224   if(boardRootItem!=NULL)
00225     gtk_object_destroy (GTK_OBJECT(boardRootItem));
00226 
00227   boardRootItem = NULL;
00228 }
00229 
00230 /* =====================================================================
00231  *
00232  * =====================================================================*/
00233 static GnomeCanvasItem *read_colors_create_item(GnomeCanvasGroup *parent) {
00234   GdkPixbuf *highlight_pixmap = NULL;
00235   char *str = NULL;
00236 
00237   boardRootItem = GNOME_CANVAS_GROUP(
00238                                  gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
00239                                                      gnome_canvas_group_get_type (),
00240                                                      "x", (double) 0,
00241                                                      "y", (double) 0,
00242                                                      NULL));
00243 
00244   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "read_colors_highlight.png");
00245   highlight_pixmap = gc_pixmap_load(str);
00246 
00247   highlight_image_item = gnome_canvas_item_new (boardRootItem,
00248                                           gnome_canvas_pixbuf_get_type (),
00249                                           "pixbuf", highlight_pixmap,
00250                                           "x", (double) 0,
00251                                           "y", (double) 0,
00252                                           "width", (double) gdk_pixbuf_get_width(highlight_pixmap),
00253                                           "height", (double) gdk_pixbuf_get_height(highlight_pixmap),
00254                                           "width_set", TRUE,
00255                                           "height_set", TRUE,
00256                                           NULL);
00257 
00258   highlight_width = gdk_pixbuf_get_width(highlight_pixmap);
00259   highlight_height = gdk_pixbuf_get_height(highlight_pixmap);
00260 
00261   g_free(str);
00262   gnome_canvas_item_hide(highlight_image_item);
00263 
00264   gdk_pixbuf_unref(highlight_pixmap);
00265 
00266   /* setup the clock */
00267   str = g_strdup_printf("%s%d.png", "gcompris/timers/clock",errors);
00268   clock_pixmap = gc_pixmap_load(str);
00269 
00270   clock_image_item = gnome_canvas_item_new (boardRootItem,
00271                                        gnome_canvas_pixbuf_get_type (),
00272                                        "pixbuf", clock_pixmap,
00273                                        "x", (double) CLOCK_X,
00274                                        "y", (double) CLOCK_Y,
00275                                        "width", (double) gdk_pixbuf_get_width(clock_pixmap),
00276                                        "height", (double) gdk_pixbuf_get_height(clock_pixmap),
00277                                        "width_set", TRUE,
00278                                        "height_set", TRUE,
00279                                        NULL);
00280 
00281   g_free(str);
00282 
00283   return NULL;
00284 }
00285 /* =====================================================================
00286  *
00287  * =====================================================================*/
00288 static void update_clock() {
00289   char *str = g_strdup_printf("%s%d.png", "gcompris/timers/clock",errors);
00290 
00291   gtk_object_destroy (GTK_OBJECT(clock_image_item));
00292 
00293   clock_pixmap = gc_pixmap_load(str);
00294 
00295   clock_image_item = gnome_canvas_item_new (boardRootItem,
00296                                        gnome_canvas_pixbuf_get_type (),
00297                                        "pixbuf", clock_pixmap,
00298                                        "x", (double) CLOCK_X,
00299                                        "y", (double) CLOCK_Y,
00300                                        "width", (double) gdk_pixbuf_get_width(clock_pixmap),
00301                                        "height", (double) gdk_pixbuf_get_height(clock_pixmap),
00302                                        "width_set", TRUE,
00303                                        "height_set", TRUE,
00304                                        NULL);
00305 
00306   gdk_pixbuf_unref(clock_pixmap);
00307   g_free(str);
00308 }
00309 /* =====================================================================
00310  *
00311  * =====================================================================*/
00312 static void game_won() {
00313   gcomprisBoard->sublevel++;
00314 
00315   listColors = g_list_remove(listColors, g_list_nth_data(listColors,0));
00316 
00317   if( g_list_length(listColors) <= 0 ) { // the current board is finished : bail out
00318     gc_bonus_end_display(BOARD_FINISHED_TUXLOCO);
00319     return;
00320   }
00321 
00322   read_colors_next_level();
00323 }
00324 /* =====================================================================
00325  *
00326  * =====================================================================*/
00327 static gboolean process_ok_timeout() {
00328   gc_bonus_display(gamewon, BONUS_SMILEY);
00329   if (!gamewon)
00330     errors--;
00331   if (errors <1)
00332     errors = 1;
00333   update_clock();
00334 
00335   if (errors <= 1) {
00336     gc_bonus_end_display(BOARD_FINISHED_TOOMANYERRORS);
00337   }
00338 
00339        return FALSE;
00340 }
00341 
00342 static void process_ok() {
00343   gc_bar_hide(TRUE);
00344   // leave time to display the right answer
00345   g_timeout_add(TIME_CLICK_TO_BONUS, process_ok_timeout, NULL);
00346 }
00347 
00348 /* =====================================================================
00349  *
00350  * =====================================================================*/
00351 static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
00352   double x, y;
00353   int i, clicked;
00354 
00355   x = event->button.x;
00356   y = event->button.y;
00357 
00358   if (!gcomprisBoard || board_paused)
00359     return FALSE;
00360 
00361   switch (event->type)
00362     {
00363     case GDK_BUTTON_PRESS:
00364       gnome_canvas_c2w (gcomprisBoard->canvas, x, y, &x, &y);
00365       clicked = -1;
00366       for (i=0; i<LAST_COLOR; i++) {
00367        if (hypot((double) (X[i]-x),(double)(Y[i]-y)) < RADIUS) {
00368          clicked = i;
00369          break;
00370        }
00371       }
00372 
00373       if (clicked >= 0) {
00374        board_paused = TRUE;
00375        highlight_selected(clicked);
00376        gamewon = (clicked == GPOINTER_TO_INT(g_list_nth_data(listColors,0)));
00377        process_ok();
00378       }
00379       break;
00380 
00381     default:
00382       break;
00383     }
00384   return FALSE;
00385 }
00386 
00387 /* =====================================================================
00388  *
00389  * =====================================================================*/
00390 static void highlight_selected(int c) {
00391   int x, y;
00392 
00393   g_assert(c>=0 && c<LAST_COLOR);
00394 
00395   x = X[c];
00396   y = Y[c];
00397 
00398   x -= highlight_width/2;
00399   y -= highlight_height/2;
00400   gnome_canvas_item_show(highlight_image_item);
00401   gc_item_absolute_move(highlight_image_item, x, y);
00402 }
00403 /* ===================================
00404  *                XML stuff
00405  * ==================================== */
00406 static void init_xml()
00407 {
00408   char *filename;
00409 
00410   filename = gc_file_find_absolute("%s/board1.xml",
00411                                gcomprisBoard->boarddir);
00412 
00413   g_assert(read_xml_file(filename)== TRUE);
00414 
00415   g_free(filename);
00416 }
00417 
00418 /* ==================================== */
00419 static void add_xml_data(xmlDocPtr doc, xmlNodePtr xmlnode, GNode * child)
00420 {
00421   char *text = NULL;
00422   char *sColor = NULL;
00423   int i;
00424 
00425   xmlnode = xmlnode->xmlChildrenNode;
00426 
00427   xmlnode = xmlnode->next;
00428 
00429   while (xmlnode != NULL) {
00430 
00431     // try to match color[i]
00432     for (i=0; i<LAST_COLOR; i++) {
00433       sColor = g_strdup_printf("color%d", i+1);
00434       if (!strcmp((char *)xmlnode->name, sColor)) {
00435        text = \
00436          gettext((char *)xmlNodeListGetString(doc, xmlnode->xmlChildrenNode, 1));
00437        colors[i] = text;
00438        g_free(sColor);
00439        break;
00440       }
00441       g_free(sColor);
00442     } // end for
00443     xmlnode = xmlnode->next;
00444   }
00445 
00446   // I really don't know why this test, but otherwise, the list is doubled
00447   // with 1 line on 2 filled with NULL elements
00448   if ( text == NULL)
00449     return;
00450 
00451 }
00452 
00453 /* ==================================== */
00454 static void parse_doc(xmlDocPtr doc)
00455 {
00456   xmlNodePtr node;
00457 
00458   for(node = doc->children->children; node != NULL; node = node->next) {
00459     if ( g_strcasecmp((gchar *)node->name, "Board") == 0 )
00460       add_xml_data(doc, node,NULL);
00461   }
00462 
00463 }
00464 /* ==================================== */
00465 /* read an xml file into our memory structures and update our view,
00466    dump any old data we have in memory if we can load a new set */
00467 static gboolean read_xml_file(char *fname)
00468 {
00469   /* pointer to the new doc */
00470   xmlDocPtr doc;
00471 
00472   g_return_val_if_fail(fname!=NULL,FALSE);
00473 
00474   /* parse the new file and put the result into newdoc */
00475   doc = gc_net_load_xml(fname);
00476 
00477   /* in case something went wrong */
00478   if(!doc)
00479     return FALSE;
00480 
00481   if(/* if there is no root element */
00482      !doc->children ||
00483      /* if it doesn't have a name */
00484      !doc->children->name ||
00485      /* if it isn't a ImageId node */
00486      g_strcasecmp((char *)doc->children->name,"ReadColors")!=0) {
00487     xmlFreeDoc(doc);
00488     return FALSE;
00489   }
00490 
00491   parse_doc(doc);
00492   xmlFreeDoc(doc);
00493   return TRUE;
00494 }