Back to index

gcompris  8.2.2
shapegame.c
Go to the documentation of this file.
00001 /* gcompris - shapegame.c
00002  *
00003  * Time-stamp: <2006/08/21 23:35:01 bruno>
00004  *
00005  * Copyright (C) 2000 Bruno Coudoin
00006  *
00007  *   This program is free software; you can redistribute it and/or modify
00008  *   it under the terms of the GNU General Public License as published by
00009  *   the Free Software Foundation; either version 2 of the License, or
00010  *   (at your option) any later version.
00011  *
00012  *   This program is distributed in the hope that it will be useful,
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *   GNU General Public License for more details.
00016  *
00017  *   You should have received a copy of the GNU General Public License
00018  *   along with this program; if not, write to the Free Software
00019  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  */
00021 
00022 /* libxml includes */
00023 #include <libxml/tree.h>
00024 #include <libxml/parser.h>
00025 
00026 #include <math.h>
00027 #include <string.h>
00028 
00029 #include "gcompris/gcompris.h"
00030 
00031 #define SOUNDLISTFILE PACKAGE
00032 
00033 #define UNDEFINED "Undefined"
00034 #define SQUARE_LIMIT_DISTANCE 100.0
00035 
00036 static int gamewon;
00037 
00038 static gboolean edit_mode = FALSE;
00039 
00040 static gint addedname;      /* Defined the rules to apply to determine if the
00041                         board is done.
00042                         - by default it is puzzle like, each piece at its place
00043                         - If addedname is set, then this value is compared to the
00044                           sum of each xml name value of the placed pieces
00045                      */
00046 
00047 static GcomprisBoard *gcomprisBoard = NULL;
00048 static gboolean board_paused = TRUE;
00049 
00050 #define POINT_COLOR_OFF 0xEf000080
00051 #define POINT_COLOR_ON  0x00EF0080
00052 
00053 typedef enum
00054 {
00055   SHAPE_TARGET              = 1 << 0,
00056   SHAPE_DUMMY_TARGET = 1 << 1,
00057   SHAPE_ICON         = 1 << 2,
00058   SHAPE_BACKGROUND   = 1 << 3,
00059   SHAPE_COLORLIST    = 1 << 4
00060 } ShapeType;
00061 
00062 /* Let's define the structure for a single shape */
00063 typedef struct _Shape Shape;
00064 struct _Shape {
00065   char  *name;                            /* name of the shape */
00066   char  *tooltip;                  /* optional tooltip for the shape */
00067   char  *pixmapfile;               /* relative pixmap file name of the shape */
00068   GnomeCanvasPoints* points;              /* OR list of points for this shape */
00069   char  *targetfile;               /* OPTIONAL relative pixmap file name of the target shape, by default
00070                                       a red point is displayed */
00071   double x;                        /* x coordinate */
00072   double y;                        /* y coordinate */
00073   double w;                        /* width */
00074   double h;                        /* height */
00075   double zoomx;                           /* x zoom factor */
00076   double zoomy;                           /* y zoom factor */
00077   gint   position;                 /* depth position 0=bottom other=intermediate */
00078   char  *soundfile;                /* relative sound file to be played when pressing mouse button */
00079   ShapeType type;                  /* Type of shape */
00080 
00081   GnomeCanvasItem *item;                  /* Canvas item for this shape */
00082                                    /* Root index which this item is in the shapelist */
00083   GnomeCanvasGroup *shape_list_group_root;
00084   guint shapelistgroup_index;             /* Root index which this item is in the shapelist */
00085   Shape *icon_shape;               /* Temporary Canvas icon shape for this shape */
00086   Shape *target_shape;                    /* If this is an icon shape then point to its shape */
00087   GnomeCanvasItem *bad_item;              /* Temporary bad placed Canvas item for this shape */
00088 
00089   gboolean found;                  /* The user found this item */
00090   gboolean placed;                 /* The user placed this item */
00091   GnomeCanvasItem *target_point;          /* Target point item for this shape */
00092   GnomeCanvasItem *targetitem;            /* Target item for this shape (if targetfile is defined) */
00093 };
00094 
00095 gchar *colorlist [] =
00096   {
00097     "black",
00098     "brown",
00099     "red",
00100     "orange",
00101     "yellow",
00102     "green",
00103     "blue",
00104     "purple",
00105     "grey",
00106     "white",
00107   };
00108 
00109 /* This is the list of shape for the current game */
00110 static GList *shape_list_init      = NULL;
00111 static GList *shape_list    = NULL;
00112 static GList *shape_list_group     = NULL;
00113 static int current_shapelistgroup_index   = -1;
00114 
00115 static GnomeCanvasItem *next_shapelist_item     = NULL;        /* Canvas item button for the next shapelist */
00116 static GnomeCanvasItem *previous_shapelist_item = NULL;        /* Canvas item button for the previous shapelist */
00117 
00118 /* Let's define the structure for the shapebox list that contains the icons of the shapes */
00119 typedef struct _ShapeBox ShapeBox;
00120 struct _ShapeBox {
00121   double x;                        /* x coordinate */
00122   double y;                        /* y coordinate */
00123   double w;                        /* width */
00124   double h;                        /* height */
00125   guint  nb_shape_x;               /* Number of shape on x */
00126   guint  nb_shape_y;               /* Number of shape on y */
00127 };
00128 static ShapeBox shapeBox;
00129 
00130 #define BUTTON_SPACE        40
00131 
00132 /* Hash table of all the shapes in the list of shapes (one by different pixmap plus icon list) */
00133 static GHashTable *shapelist_table = NULL;
00134 static gint SHAPE_BOX_WIDTH_RATIO = 18;
00135 
00136 static GnomeCanvasItem      *shape_root_item;
00137 static GnomeCanvasItem      *shape_list_root_item;
00138 
00139 /* The tooltip */
00140 static GnomeCanvasGroup     *tooltip_root_item;
00141 static GnomeCanvasItem      *tooltip_text_item;
00142 static GnomeCanvasItem      *tooltip_text_item_s;
00143 static GnomeCanvasItem      *tooltip_bg_item;
00144 
00145 static void           start_board (GcomprisBoard *agcomprisBoard);
00146 static void           pause_board (gboolean pause);
00147 static void           end_board (void);
00148 static gboolean       is_our_board (GcomprisBoard *gcomprisBoard);
00149 static void           set_level (guint level);
00150 static void           process_ok(void);
00151 static gint           key_press(guint keyval, gchar *commit_str, gchar *preedit_str);
00152 static void            config_start (GcomprisBoard *agcomprisBoard,
00153                                       GcomprisProfile *aProfile);
00154 static void            config_stop (void);
00155 
00156 static void              shapegame_init_canvas(GnomeCanvasGroup *parent);
00157 static void           shapegame_destroy_all_items(void);
00158 static void           setup_item(GnomeCanvasItem *item, Shape *shape);
00159 static void           shapegame_next_level(void);
00160 static gboolean       read_xml_file(char *fname);
00161 static gboolean       write_xml_file(char *fname);
00162 static Shape         *find_closest_shape(double x, double y, double limit);
00163 static Shape         *create_shape(ShapeType type, char *name, char *tooltip,
00164                                   char *pixmapfile,  GnomeCanvasPoints* points,
00165                                   char *targetfile, double x, double y, double l, double h, double zoomx,
00166                                   double zoomy, guint position, char *soundfile);
00167 static gboolean       increment_sublevel(void);
00168 static void           create_title(char *name, double x, double y, GtkJustification justification,
00169                                   guint32 color_rgba);
00170 static gint           item_event_ok(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00171 static gint           item_event_edition(GnomeCanvasItem *item, GdkEvent *event, Shape *shape);
00172 
00173 /* Description of this plugin */
00174 static BoardPlugin menu_bp =
00175 {
00176    NULL,
00177    NULL,
00178    "Make the puzzle",
00179    "Drag and Drop the items to rebuild the object",
00180    "Bruno Coudoin <bruno.coudoin@free.fr>",
00181    NULL,
00182    NULL,
00183    NULL,
00184    NULL,
00185    start_board,
00186    pause_board,
00187    end_board,
00188    is_our_board,
00189    key_press,
00190    process_ok,
00191    set_level,
00192    NULL,
00193    NULL,
00194    config_start,
00195    config_stop
00196 };
00197 
00198 /* Description of this plugin without configuration */
00199 static BoardPlugin menu_bp_no_config =
00200 {
00201    NULL,
00202    NULL,
00203    "Make the puzzle",
00204    "Drag and Drop the items to rebuild the object",
00205    "Bruno Coudoin <bruno.coudoin@free.fr>",
00206    NULL,
00207    NULL,
00208    NULL,
00209    NULL,
00210    start_board,
00211    pause_board,
00212    end_board,
00213    is_our_board,
00214    key_press,
00215    process_ok,
00216    set_level,
00217    NULL,
00218    NULL,
00219    NULL,
00220    NULL
00221 };
00222 
00223 /*
00224  * Main entry point mandatory for each Gcompris's game
00225  * ---------------------------------------------------
00226  *
00227  */
00228 
00229 GET_BPLUGIN_INFO(shapegame)
00230 
00231 /*
00232  * in : boolean TRUE = PAUSE : FALSE = CONTINUE
00233  *
00234  */
00235 static void pause_board (gboolean pause)
00236 {
00237 
00238   if(gcomprisBoard==NULL)
00239     return;
00240 
00241   if(gamewon == TRUE && pause == FALSE) /* the game is won */
00242     {
00243       if(increment_sublevel())
00244        shapegame_next_level();
00245     }
00246 
00247   board_paused = pause;
00248 }
00249 
00250 /*
00251  */
00252 static void start_board (GcomprisBoard *agcomprisBoard)
00253 {
00254   gchar *filename = NULL;
00255   gboolean default_background = TRUE;
00256 
00257   if (strcmp(agcomprisBoard->name, "imagename")==0){
00258     GHashTable *config = gc_db_get_board_conf();
00259 
00260     gc_locale_set(g_hash_table_lookup( config, "locale"));
00261 
00262     g_hash_table_destroy(config);
00263   }
00264 
00265   if(agcomprisBoard!=NULL)
00266     {
00267       gcomprisBoard = agcomprisBoard;
00268 
00269       /* disable im_context */
00270       gcomprisBoard->disable_im_context = TRUE;
00271 
00272       /* set initial values for this level */
00273       gcomprisBoard->level = 1;
00274 
00275       /* Calculate the maxlevel based on the available data file for this board */
00276       gcomprisBoard->maxlevel=1;
00277       
00278       while( (filename = gc_file_find_absolute("%s/board%d_0.xml",
00279                                                   gcomprisBoard->boarddir,
00280                                                   gcomprisBoard->maxlevel++,
00281                                                   NULL)) )
00282        {
00283          g_free(filename);
00284 
00285        }
00286 
00287       
00288       gcomprisBoard->maxlevel--;
00289 
00290       if (strcmp(gcomprisBoard->name, "imagename")==0){
00291        gc_bar_set(GC_BAR_CONFIG|GC_BAR_LEVEL|GC_BAR_OK);
00292       } else
00293        gc_bar_set(GC_BAR_LEVEL|GC_BAR_OK);
00294 
00295 
00296       gcomprisBoard->sublevel = 0;
00297 
00298       /* In this board, the sublevels are dynamicaly discovered based on data files */
00299       gcomprisBoard->number_of_sublevel=G_MAXINT;
00300 
00301 
00302       if(gcomprisBoard->mode!=NULL)
00303        if(g_strncasecmp(gcomprisBoard->mode, "background=", 11)==0)
00304          {
00305            gchar *tmp = NULL;
00306 
00307            tmp = g_malloc(strlen(gcomprisBoard->mode));
00308            tmp = strcpy(tmp, gcomprisBoard->mode + 11);
00309 
00310            gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), tmp);
00311            default_background = FALSE;
00312            g_free(tmp);
00313          }
00314 
00315       if(default_background)
00316        {
00317          gchar *img;
00318 
00319          // Default case, load the default background
00320          img = gc_skin_image_get("gcompris-shapebg.jpg");
00321          gc_set_background(gnome_canvas_root(gcomprisBoard->canvas),
00322                               img);
00323          g_free(img);
00324        }
00325 
00326       shapegame_next_level();
00327 
00328       pause_board(FALSE);
00329 
00330       gc_cursor_set(GCOMPRIS_LINE_CURSOR);
00331 
00332     }
00333 
00334 }
00335 
00336 static void
00337 end_board ()
00338 {
00339 
00340   if(gcomprisBoard!=NULL)
00341     {
00342       pause_board(TRUE);
00343       shapegame_destroy_all_items();
00344       gcomprisBoard->level = 1;       // Restart this game to zero
00345     }
00346 
00347   if (strcmp(gcomprisBoard->name, "imagename")==0){
00348     gc_locale_reset();
00349   }
00350 
00351   gcomprisBoard = NULL;
00352   gc_cursor_set(GCOMPRIS_DEFAULT_CURSOR);
00353 }
00354 
00355 static void
00356 set_level (guint level)
00357 {
00358 
00359   if(gcomprisBoard!=NULL)
00360     {
00361       gcomprisBoard->level=level;
00362       gcomprisBoard->sublevel=0;
00363       shapegame_next_level();
00364     }
00365 }
00366 
00367 gboolean
00368 is_our_board (GcomprisBoard *gcomprisBoard)
00369 {
00370   if (gcomprisBoard)
00371     {
00372       if(g_strcasecmp(gcomprisBoard->type, "shapegame")==0)
00373        {
00374          /* Set the plugin entry */
00375          if (strcmp(gcomprisBoard->name, "imagename")==0){
00376            gcomprisBoard->plugin = &menu_bp;
00377          } else {
00378            gcomprisBoard->plugin = &menu_bp_no_config;
00379          }
00380 
00381          return TRUE;
00382        }
00383     }
00384   return FALSE;
00385 }
00386 
00387 /*
00388  * Keypress here are use for entering the editing mode
00389  */
00390 static gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str)
00391 {
00392   guint c;
00393 
00394   if(!gcomprisBoard)
00395     return FALSE;
00396 
00397   /* Add some filter for control and shift key */
00398   switch (keyval)
00399     {
00400       /* Avoid all this keys to be interpreted by this game */
00401     case GDK_Shift_L:
00402     case GDK_Shift_R:
00403     case GDK_Control_L:
00404     case GDK_Control_R:
00405     case GDK_Caps_Lock:
00406     case GDK_Shift_Lock:
00407     case GDK_Meta_L:
00408     case GDK_Meta_R:
00409     case GDK_Alt_L:
00410     case GDK_Alt_R:
00411     case GDK_Super_L:
00412     case GDK_Super_R:
00413     case GDK_Hyper_L:
00414     case GDK_Hyper_R:
00415     case GDK_Num_Lock:
00416       return FALSE;
00417     case GDK_KP_Enter:
00418     case GDK_Return:
00419       process_ok();
00420       return TRUE;
00421     case GDK_Right:
00422     case GDK_Delete:
00423     case GDK_BackSpace:
00424     case GDK_Left:
00425       break;
00426     }
00427 
00428   c = tolower(keyval);
00429 
00430   switch (c)
00431     {
00432     case 'e':
00433       /* Enter Edit Mode */
00434       gc_dialog(_("You have entered Edit mode\nMove the puzzle items;\ntype 's' to save, and\n'd' to display all the shapes"), NULL);
00435       edit_mode = TRUE;
00436       break;
00437     case 's':
00438       /* Save the current board */
00439       if(edit_mode)
00440        {
00441          write_xml_file("/tmp/gcompris-board.xml");
00442          gc_dialog(_("The data from this activity are saved under\n/tmp/gcompris-board.xml"), NULL);
00443        }
00444       break;
00445     case 'd':
00446       /* Display all the shapes */
00447       if(edit_mode)
00448        {
00449          GList *list;
00450 
00451          /* loop through all our shapes */
00452          for(list = shape_list; list != NULL; list = list->next) {
00453            Shape *shape = list->data;
00454 
00455            if(shape->type==SHAPE_TARGET)
00456              {
00457                  /* You got it right perfect */
00458                  if(shape->bad_item!=NULL)
00459                    {
00460                      gnome_canvas_item_hide(shape->bad_item);
00461                      gtk_object_destroy (GTK_OBJECT(shape->bad_item));
00462                      shape->bad_item=NULL;
00463                    }
00464                  shape->found  = TRUE;
00465                  gnome_canvas_item_show(shape->item);
00466                  gnome_canvas_item_raise_to_top(shape->item);
00467                  gnome_canvas_item_raise_to_top(shape->target_point);
00468              }
00469          }
00470        }
00471       break;
00472     default:
00473       break;
00474     }
00475 
00476   return TRUE;
00477 }
00478 
00479 /*-------------------------------------------------------------------------------*/
00480 /*-------------------------------------------------------------------------------*/
00481 /*-------------------------------------------------------------------------------*/
00482 /*-------------------------------------------------------------------------------*/
00483 
00484 /*
00485  * Returns true if increment is done, false is end of board
00486  */
00487 static gboolean increment_sublevel()
00488 {
00489   gcomprisBoard->sublevel++;
00490 
00491   if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) {
00492     /* Try the next level */
00493     gcomprisBoard->level++;
00494     gcomprisBoard->sublevel=0;
00495 
00496     if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
00497       gc_bonus_end_display(BOARD_FINISHED_RANDOM);
00498       return FALSE;
00499     }
00500 
00501   }
00502 
00503   return TRUE;
00504 }
00505 
00506 /* set initial values for the next level */
00507 static void shapegame_next_level()
00508 {
00509   char *filename;
00510 
00511   gamewon = FALSE;
00512   edit_mode = FALSE;
00513 
00514   shapegame_destroy_all_items();
00515 
00516   shapegame_init_canvas(gnome_canvas_root(gcomprisBoard->canvas));
00517 
00518   while( ((filename = gc_file_find_absolute("%s/board%d_%d.xml",
00519                                        gcomprisBoard->boarddir,
00520                                        gcomprisBoard->level,
00521                                        gcomprisBoard->sublevel,
00522                                        NULL)) == NULL)
00523         && ((gcomprisBoard->level != 1) || (gcomprisBoard->sublevel!=0)))
00524     {
00525       /* Try the next level */
00526       gcomprisBoard->sublevel = gcomprisBoard->number_of_sublevel;
00527       if(!increment_sublevel())
00528        return;
00529     }
00530 
00531   gc_bar_set_level(gcomprisBoard);
00532 
00533   read_xml_file(filename);
00534 
00535   g_free(filename);
00536 }
00537 
00538 
00539 static void process_ok()
00540 {
00541   GList *list;
00542   gboolean done = TRUE;
00543 
00544   /*
00545    * Here I implements the resolving rules.
00546    */
00547   if(addedname == INT_MAX)
00548     {
00549       /* - Default is to be puzzle like. Check that each piece is at its place */
00550 
00551       /* Loop through all the shapes to find if all target are found */
00552       for(list = shape_list; list != NULL; list = list->next) {
00553        Shape *shape = list->data;
00554 
00555        if(shape->type==SHAPE_TARGET)
00556          {
00557            if(shape->found==FALSE)
00558              done=FALSE;
00559          }
00560       }
00561     }
00562   else
00563     {
00564       /* - if addedname is set, then adding int name field of placed piece must
00565        *   equals addedname
00566        */
00567       gint total = 0;
00568 
00569       for(list = shape_list; list != NULL; list = list->next) {
00570        Shape *shape = list->data;
00571        gint   intname = 0;
00572 
00573        g_warning("   shape = %s\n", shape->name);
00574        if(shape->type==SHAPE_TARGET && shape->placed==TRUE)
00575          {
00576            intname = atoi(shape->name);
00577            total += intname;
00578            g_warning("      shape = %s   placed=TRUE\n", shape->name);
00579          }
00580 
00581       }
00582 
00583       if(total != addedname)
00584        done = FALSE;
00585 
00586       g_warning("checking for addedname=%d done=%d total=%d\n", addedname, done, total);
00587     }
00588 
00589 
00590   if(done)
00591     {
00592       gamewon = TRUE;
00593       gc_bonus_display(gamewon, BONUS_FLOWER);
00594     }
00595   else
00596     {
00597       gc_bonus_display(gamewon, BONUS_FLOWER);
00598     }
00599 
00600 }
00601 
00602 static void destroy_shape (Shape *shape)
00603 {
00604   g_free(shape->name);
00605   g_free(shape->pixmapfile);
00606   g_free(shape->targetfile);
00607   g_free(shape->soundfile);
00608   g_free(shape->tooltip);
00609   if(shape->points!=NULL)
00610     gnome_canvas_points_unref(shape->points);
00611   g_free(shape);
00612 }
00613 
00614 /* Destroy all the items */
00615 static void shapegame_destroy_all_items()
00616 {
00617   Shape *shape;
00618 
00619   /* Cleanup of the shapes */
00620   while(g_list_length(shape_list)>0)
00621     {
00622       shape = g_list_nth_data(shape_list, 0);
00623       shape_list = g_list_remove (shape_list, shape);
00624       destroy_shape(shape);
00625     }
00626 
00627   g_list_free(shape_list);
00628 
00629   if (shapelist_table)
00630     {
00631       /* Deleting the root item automatically deletes children items */
00632       gtk_object_destroy (GTK_OBJECT(shape_list_root_item));
00633       shape_list_root_item = NULL;
00634       gtk_object_destroy (GTK_OBJECT(shape_root_item));
00635       shape_root_item = NULL;
00636       gtk_object_destroy (GTK_OBJECT(tooltip_root_item));
00637       tooltip_root_item = NULL;
00638 
00639       g_hash_table_destroy (shapelist_table);
00640       shapelist_table=NULL;
00641 
00642       g_list_free(shape_list_group);
00643       shape_list_group = NULL;
00644       current_shapelistgroup_index = -1;
00645     }
00646 }
00647 
00648 static void shapegame_init_canvas(GnomeCanvasGroup *parent)
00649 {
00650   GdkPixbuf       *pixmap = NULL;
00651 
00652   shape_list_root_item = \
00653     gnome_canvas_item_new (parent,
00654                         gnome_canvas_group_get_type (),
00655                         "x", (double)0,
00656                         "y", (double)0,
00657                         NULL);
00658 
00659   shape_root_item = \
00660     gnome_canvas_item_new (parent,
00661                         gnome_canvas_group_get_type (),
00662                         "x", (double)gcomprisBoard->width/SHAPE_BOX_WIDTH_RATIO,
00663                         "y", (double)0,
00664                         NULL);
00665 
00666   /* Create the tooltip area */
00667   pixmap = gc_skin_pixmap_load("button_large.png");
00668   tooltip_root_item = GNOME_CANVAS_GROUP(
00669                                     gnome_canvas_item_new (parent,
00670                                                         gnome_canvas_group_get_type (),
00671                                                         "x", (double)10,
00672                                                         "y", (double)gcomprisBoard->height-70,
00673                                                         NULL)
00674                                     );
00675 
00676   tooltip_bg_item = \
00677     gnome_canvas_item_new (GNOME_CANVAS_GROUP(tooltip_root_item),
00678                         gnome_canvas_pixbuf_get_type (),
00679                         "pixbuf", pixmap,
00680                         "x", (double) 0,
00681                         "y", (double) 0,
00682                         NULL);
00683   gdk_pixbuf_unref(pixmap);
00684 
00685   tooltip_text_item_s = \
00686     gnome_canvas_item_new (GNOME_CANVAS_GROUP(tooltip_root_item),
00687                         gnome_canvas_text_get_type (),
00688                         "text", "",
00689                         "font", gc_skin_font_board_small,
00690                         "x", (double)gdk_pixbuf_get_width(pixmap)/2 + 1.0,
00691                         "y", 24.0 + 1.0,
00692                         "anchor", GTK_ANCHOR_CENTER,
00693                         "justification", GTK_JUSTIFY_CENTER,
00694                         "fill_color_rgba", gc_skin_color_shadow,
00695                         NULL);
00696   tooltip_text_item = \
00697     gnome_canvas_item_new (GNOME_CANVAS_GROUP(tooltip_root_item),
00698                         gnome_canvas_text_get_type (),
00699                         "text", "",
00700                         "font", gc_skin_font_board_small,
00701                         "x", (double)gdk_pixbuf_get_width(pixmap)/2,
00702                         "y", 24.0,
00703                         "anchor", GTK_ANCHOR_CENTER,
00704                         "justification", GTK_JUSTIFY_CENTER,
00705                         "fill_color_rgba", gc_skin_color_text_button,
00706                         NULL);
00707 
00708   /* Hide the tooltip */
00709   gnome_canvas_item_hide(GNOME_CANVAS_ITEM(tooltip_root_item));
00710 
00711 }
00712 
00713 /**************************************************************
00714  * Shape list management
00715  */
00716 
00717 /* Add the given shape to the list of shapes
00718  * Do nothing if the shape is already in
00719  */
00720 static void
00721 add_shape_to_list_of_shapes(Shape *shape)
00722 {
00723   GnomeCanvasItem *item;
00724   GdkPixbuf   *pixmap = NULL;
00725   GnomeCanvasGroup *shape_list_group_root = NULL;
00726   double ICON_GAP    = 5.0;
00727   double ICON_HEIGHT = (double)(shapeBox.h / shapeBox.nb_shape_y) - ICON_GAP;
00728   double ICON_WIDTH  = (double)(shapeBox.w / shapeBox.nb_shape_x) - ICON_GAP;
00729 
00730   if(!shapelist_table)
00731     shapelist_table= g_hash_table_new (g_str_hash, g_str_equal);
00732 
00733   /*----------------------------------------------------------------------*/
00734   /* If the first list is full, add the previous/forward buttons          */
00735   if(g_hash_table_size(shapelist_table)==(shapeBox.nb_shape_x * shapeBox.nb_shape_y))
00736     {
00737       pixmap = gc_skin_pixmap_load("button_backward.png");
00738       previous_shapelist_item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_list_root_item),
00739                                                  gnome_canvas_pixbuf_get_type (),
00740                                                  "pixbuf", pixmap,
00741                                                  "x", (double) shapeBox.x + (shapeBox.w/2) -
00742                                                  gdk_pixbuf_get_width(pixmap) - 2,
00743                                                  "y", (double) shapeBox.y + shapeBox.h,
00744                                                  NULL);
00745 
00746       gtk_signal_connect(GTK_OBJECT(previous_shapelist_item), "event",
00747                       (GtkSignalFunc) item_event_ok,
00748                       "previous_shapelist");
00749       gtk_signal_connect(GTK_OBJECT(previous_shapelist_item), "event",
00750                       (GtkSignalFunc) gc_item_focus_event,
00751                       NULL);
00752       gdk_pixbuf_unref(pixmap);
00753 
00754       pixmap = gc_skin_pixmap_load("button_forward.png");
00755       next_shapelist_item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_list_root_item),
00756                                              gnome_canvas_pixbuf_get_type (),
00757                                              "pixbuf", pixmap,
00758                                              "x", (double) shapeBox.x + (shapeBox.w/2) + 2,
00759                                              "y", (double) shapeBox.y + shapeBox.h,
00760                                              NULL);
00761 
00762       gtk_signal_connect(GTK_OBJECT(next_shapelist_item), "event",
00763                       (GtkSignalFunc) item_event_ok,
00764                       "next_shapelist");
00765       gtk_signal_connect(GTK_OBJECT(next_shapelist_item), "event",
00766                       (GtkSignalFunc) gc_item_focus_event,
00767                       NULL);
00768       gdk_pixbuf_unref(pixmap);
00769       gnome_canvas_item_hide(next_shapelist_item);
00770 
00771   }
00772 
00773   /*----------------------------------------------------------------------*/
00774   /* Do We need to create a new list                                      */
00775   if(g_hash_table_size(shapelist_table)%(shapeBox.nb_shape_x * shapeBox.nb_shape_y)==0)
00776     {
00777       current_shapelistgroup_index++;
00778       g_warning("Creation of the group of shape current_shapelistgroup_index=%d\n",
00779             current_shapelistgroup_index);
00780 
00781       // Hide the previous group
00782       if(current_shapelistgroup_index>=1)
00783        {
00784          g_warning(" Hide previous group\n");
00785          shape_list_group_root = GNOME_CANVAS_GROUP(g_list_nth_data(shape_list_group,
00786                                                              current_shapelistgroup_index-1));
00787          //gnome_canvas_item_hide(shape_list_group_root);
00788          item = g_list_nth_data(shape_list_group, current_shapelistgroup_index-1);
00789          gnome_canvas_item_hide(item);
00790        }
00791 
00792       // We need to start a new shape list group
00793       shape_list_group_root = \
00794        GNOME_CANVAS_GROUP(gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_list_root_item),
00795                                            gnome_canvas_group_get_type (),
00796                                            "x", (double)0,
00797                                            "y", (double)0,
00798                                            NULL));
00799 
00800       shape_list_group = g_list_append (shape_list_group, shape_list_group_root);
00801       g_warning(" current_shapelistgroup_index=%d\n", current_shapelistgroup_index);
00802 
00803     }
00804   else
00805     {
00806       // Get the current shapelist group
00807       g_warning(" get the current_shapelistgroup_index=%d\n", current_shapelistgroup_index);
00808       shape_list_group_root = g_list_nth_data(shape_list_group, current_shapelistgroup_index);
00809     }
00810 
00811   /*----------------------------------------------------------------------*/
00812   /* This pixmap is not yet in the list of shapes                         */
00813   if(g_hash_table_lookup (shapelist_table, shape->pixmapfile)==NULL)
00814     {
00815       double y_offset = 0;
00816       double x_offset = 0;
00817       GdkPixbuf *pixmap = NULL;
00818 
00819       y_offset = shapeBox.y + (ICON_HEIGHT/2 +
00820                             (g_hash_table_size(shapelist_table) % shapeBox.nb_shape_y) *
00821                             ICON_HEIGHT);
00822 
00823       x_offset = shapeBox.x + (ICON_WIDTH/2 +
00824                             ((g_hash_table_size(shapelist_table) %
00825                              ( shapeBox.nb_shape_x * shapeBox.nb_shape_y)) /
00826                             shapeBox.nb_shape_y) *
00827                             ICON_WIDTH);
00828       g_warning("  ICON_WIDTH = %f   ICON_HEIGHT = %f\n", ICON_WIDTH, ICON_HEIGHT);
00829       g_warning("x_offset = %f   y_offset = %f\n", x_offset, y_offset);
00830 
00831       /* So this shape is not yet in, let's put it in now */
00832       g_hash_table_insert (shapelist_table, shape->pixmapfile, shape);
00833 
00834       if(strcmp(shape->pixmapfile, UNDEFINED)!=0)
00835        {
00836          pixmap = gc_pixmap_load(shape->pixmapfile);
00837          if(pixmap)
00838            {
00839              double w, h;
00840              Shape *icon_shape;
00841 
00842              /* Calc a zoom factor so that the shape will fit in the shapelist
00843                whatever its current size */
00844              w = ICON_WIDTH;
00845              h = gdk_pixbuf_get_height(pixmap) * (w / gdk_pixbuf_get_width(pixmap));
00846 
00847              if(h > ICON_HEIGHT)
00848               {
00849                 h = ICON_HEIGHT;
00850                 w = gdk_pixbuf_get_width(pixmap) * ( h / gdk_pixbuf_get_height(pixmap));
00851               }
00852 
00853              item = gnome_canvas_item_new (shape_list_group_root,
00854                                        gnome_canvas_pixbuf_get_type (),
00855                                        "pixbuf", pixmap,
00856                                        "x", (double)x_offset-w/2,
00857                                        "y", (double)y_offset-h/2,
00858                                        "width", (double) w,
00859                                        "height", (double) h,
00860                                        "width_set", TRUE,
00861                                        "height_set", TRUE,
00862                                        NULL);
00863              gdk_pixbuf_unref(pixmap);
00864 
00865              icon_shape = create_shape(SHAPE_ICON, shape->name, shape->tooltip,
00866                                    shape->pixmapfile, shape->points, shape->targetfile,
00867                                    (double)0, (double)y_offset,
00868                                    (double)w, (double)h,
00869                                    (double)shape->zoomx, (double)shape->zoomy,
00870                                    0, shape->soundfile);
00871              icon_shape->item = item;
00872              icon_shape->target_shape = shape;
00873              icon_shape->shapelistgroup_index = current_shapelistgroup_index;
00874              shape->shapelistgroup_index = current_shapelistgroup_index;
00875              g_warning(" creation shape=%s shape->shapelistgroup_index=%d current_shapelistgroup_index=%d\n",
00876                    shape->name,
00877                    shape->shapelistgroup_index, current_shapelistgroup_index);
00878              icon_shape->shape_list_group_root = shape_list_group_root;
00879              setup_item(item, icon_shape);
00880              gtk_signal_connect(GTK_OBJECT(item), "event",
00881                              (GtkSignalFunc) gc_item_focus_event,
00882                              NULL);
00883            }
00884        }
00885     }
00886 }
00887 
00888 /*
00889  * Find the closest shape from the given point if it is located at
00890  * a distance under the given square limit.
00891  */
00892 static Shape *find_closest_shape(double x, double y, double limit)
00893 {
00894   GList *list;
00895   double goodDist = limit;
00896   Shape *candidateShape = NULL;
00897 
00898   /* loop through all our shapes */
00899   for(list = shape_list; list != NULL; list = list->next) {
00900     Shape *shape = list->data;
00901     double dist;
00902 
00903     if(shape->type==SHAPE_TARGET)
00904       {
00905        /* Calc the distance between this shape and the given coord */
00906        dist = sqrt(pow((shape->x-x),2) + pow((shape->y-y),2));
00907        if(dist<goodDist)
00908          {
00909            goodDist=dist;
00910            candidateShape=shape;
00911          }
00912       }
00913   }
00914 
00915   return candidateShape;
00916 }
00917 
00918 //#if 0
00919 static void dump_shape(Shape *shape)
00920 {
00921   g_warning("dump_shape name=%s found=%d type=%d ", shape->name, shape->found, shape->type);
00922   if(shape->bad_item)
00923     g_warning("bad_item=TRUE ");
00924   if(shape->icon_shape)
00925     g_warning("icon_shape=%s", shape->icon_shape->name);
00926   g_warning("\n");
00927 }
00928 //#endif
00929 
00930 /*
00931  * Given the shape, if it has an icon, it puts it back to
00932  * the list of shapes
00933  */
00934 static void shape_goes_back_to_list(Shape *shape, GnomeCanvasItem *item)
00935 {
00936   g_warning("shape_goes_back_to_list shape=%s shape->shapelistgroup_index=%d current_shapelistgroup_index=%d\n", shape->name, shape->shapelistgroup_index, current_shapelistgroup_index);
00937 
00938   if(shape->icon_shape!=NULL)
00939     {
00940       if(shape->icon_shape->target_shape)
00941        {
00942          shape->icon_shape->target_shape->placed = FALSE;
00943          g_warning("shape_goes_back_to_list setting shape->name=%s to placed=%d\n",
00944                shape->icon_shape->target_shape->name,
00945                shape->icon_shape->target_shape->placed);
00946        }
00947 
00948       /* There was a previous icon here, put it back to the list */
00949       gnome_canvas_item_move(shape->icon_shape->item,
00950                           shape->icon_shape->x - shape->x,
00951                           shape->icon_shape->y - shape->y);
00952       gnome_canvas_item_show(shape->icon_shape->item);
00953 
00954       gc_item_focus_set(shape->icon_shape->item, TRUE);
00955       shape->icon_shape=NULL;
00956 
00957       gnome_canvas_item_hide(item);
00958       gc_sound_play_ogg ("sounds/gobble.ogg", NULL);
00959     }
00960 }
00961 
00962 static gint
00963 item_event(GnomeCanvasItem *item, GdkEvent *event, Shape *shape)
00964 {
00965    static double x, y;
00966    static double offset_x, offset_y;
00967    double new_x, new_y;
00968    GdkCursor *fleur;
00969    static int dragging;
00970    double item_x, item_y;
00971    static GnomeCanvasItem *target_point_previous;
00972 
00973   if(!gcomprisBoard)
00974     return FALSE;
00975 
00976   if(board_paused)
00977     return FALSE;
00978 
00979 
00980    if(shape==NULL) {
00981      g_warning("Shape is NULL : Should not happen");
00982      return FALSE;
00983    }
00984 
00985    /* This event is a non sense in the edit mode. Also, it will crash since the data structure are */
00986    /* filled differently in edit mode                                                              */
00987    /* Redirect this event to the edit mode one so that the user can drag the object directly       */
00988    if(edit_mode)
00989      {
00990        item_event_edition(item, event, shape);
00991        return FALSE;
00992      }
00993 
00994    item_x = event->button.x;
00995    item_y = event->button.y;
00996    gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
00997 
00998    switch (event->type)
00999      {
01000      case GDK_ENTER_NOTIFY:
01001        if(shape->tooltip && shape->type == SHAPE_ICON) {
01002         gnome_canvas_item_raise_to_top(GNOME_CANVAS_ITEM(tooltip_root_item));
01003         /* WARNING: This should not be needed but if I don't do it, it's not refreshed */
01004         gnome_canvas_item_set(GNOME_CANVAS_ITEM(tooltip_bg_item),
01005                             "y", 0.0,
01006                             NULL);
01007         gnome_canvas_item_set(GNOME_CANVAS_ITEM(tooltip_text_item_s),
01008                             "text", shape->tooltip,
01009                             NULL);
01010         gnome_canvas_item_set(GNOME_CANVAS_ITEM(tooltip_text_item),
01011                             "text", shape->tooltip,
01012                             NULL);
01013         gnome_canvas_item_show(GNOME_CANVAS_ITEM(tooltip_root_item));
01014        }
01015        break;
01016      case GDK_LEAVE_NOTIFY:
01017        if(shape->tooltip && shape->type == SHAPE_ICON)
01018                gnome_canvas_item_hide(GNOME_CANVAS_ITEM(tooltip_root_item));
01019        break;
01020      case GDK_BUTTON_PRESS:
01021        switch(event->button.button)
01022          {
01023          case 1:
01024            if (event->button.state & GDK_SHIFT_MASK)
01025              {
01026             }
01027           else
01028             {
01029               target_point_previous = NULL;
01030 
01031               x = item_x;
01032               y = item_y;
01033 
01034               item_x = shape->x;
01035               item_y = shape->y;
01036 
01037               switch(shape->type)
01038                {
01039                case SHAPE_TARGET:
01040                  gnome_canvas_item_hide(GNOME_CANVAS_ITEM(item));
01041                  gc_item_focus_set(item, FALSE);
01042 
01043                  if( shape->icon_shape!=NULL)
01044                    {
01045                      item = shape->icon_shape->item;
01046                      item_x = x - (x - shape->x) * shape->icon_shape->w /
01047                        shape->w;
01048                      item_y = y - (y - shape->y) * shape->icon_shape->h /
01049                        shape->h;
01050                      gnome_canvas_item_move( item,
01051                                           item_x - shape->x,
01052                                           item_y - shape->y );
01053                      gnome_canvas_item_show( item );
01054                      gc_item_focus_set(item, TRUE);
01055                      shape->icon_shape=NULL;
01056                    }
01057                  break;
01058                case SHAPE_ICON:
01059                  if (strcmp(shape->soundfile,UNDEFINED) != 0)
01060                  {
01061                    /* If the soundfile has space ' ' in it, then it is assumed that it is a list
01062                     * of sound rather than a single one
01063                     */
01064 
01065                    char *p = NULL;
01066                    char *soundfile = g_strdup(shape->soundfile);
01067 
01068                    while ((p = strstr (soundfile, " ")))
01069                      {
01070                       *p='\0';
01071                       gc_sound_play_ogg(soundfile, NULL);
01072                       soundfile=p+1;
01073                       g_warning("soundfile = %s\n", soundfile);
01074                      }
01075 
01076                    gc_sound_play_ogg(soundfile, NULL);
01077 
01078                  }
01079                  break;
01080                default:
01081                  break;
01082                }
01083               /* This records the offset between the mouse pointer and the grabbed item center */
01084               offset_x = x - item_x;
01085               offset_y = y - item_y;
01086               g_warning("offsetx=%f offsetx=%f\n", offset_x, offset_y);
01087               if(item==NULL)
01088                return FALSE;
01089 
01090               fleur = gdk_cursor_new(GDK_FLEUR);
01091 
01092               /* Make sure this item is on top */
01093               gnome_canvas_item_raise_to_top(shape_list_root_item);
01094               gnome_canvas_item_raise_to_top(item);
01095 
01096               gc_canvas_item_grab(item,
01097                                   GDK_POINTER_MOTION_MASK |
01098                                   GDK_BUTTON_RELEASE_MASK,
01099                                   fleur,
01100                                   event->button.time);
01101               gdk_cursor_destroy(fleur);
01102               dragging = TRUE;
01103             }
01104           break;
01105 
01106          case 3:
01107           /* If There was a previous icon here, put it back to the list */
01108           shape_goes_back_to_list(shape, item);
01109           /* Mark it not found */
01110           shape->found = FALSE;
01111           break;
01112 
01113          default:
01114            break;
01115          }
01116        break;
01117 
01118      case GDK_MOTION_NOTIFY:
01119        if (dragging && (event->motion.state & GDK_BUTTON1_MASK))
01120          {
01121           Shape *targetshape = NULL;
01122           new_x = item_x;
01123           new_y = item_y;
01124 
01125           gnome_canvas_item_move(item, new_x - x, new_y - y);
01126 
01127           x = new_x;
01128           y = new_y;
01129 
01130           targetshape = find_closest_shape(item_x - offset_x,
01131                                        item_y - offset_y,
01132                                        SQUARE_LIMIT_DISTANCE);
01133           if(targetshape!=NULL)
01134             {
01135               if(target_point_previous)
01136                {
01137                  if(strcmp(shape->targetfile, UNDEFINED)==0)
01138                    {
01139                      gnome_canvas_item_set(GNOME_CANVAS_ITEM(target_point_previous),
01140                                         "fill_color_rgba", POINT_COLOR_OFF,
01141                                         NULL);
01142 
01143                      gnome_canvas_item_set(GNOME_CANVAS_ITEM(targetshape->target_point),
01144                                         "fill_color_rgba", POINT_COLOR_ON,
01145                                         NULL);
01146                    }
01147                  else
01148                    {
01149                      gc_item_focus_set(target_point_previous, FALSE);
01150                      gc_item_focus_set(targetshape->targetitem, TRUE);
01151                      target_point_previous = targetshape->targetitem;
01152                    }
01153                }
01154 
01155               if(strcmp(shape->targetfile, UNDEFINED)==0)
01156                target_point_previous = targetshape->target_point;
01157               else
01158                target_point_previous = targetshape->targetitem;
01159             }
01160           else
01161             {
01162               if(target_point_previous)
01163                {
01164                  if(strcmp(shape->targetfile, UNDEFINED)==0)
01165                    gnome_canvas_item_set(GNOME_CANVAS_ITEM(target_point_previous),
01166                                       "fill_color_rgba", POINT_COLOR_OFF,
01167                                       NULL);
01168                  else
01169                    gc_item_focus_set(target_point_previous, FALSE);
01170                }
01171               target_point_previous = NULL;
01172             }
01173         }
01174        break;
01175 
01176      case GDK_BUTTON_RELEASE:
01177        if(dragging)
01178         {
01179           Shape *targetshape = NULL;
01180 
01181           gc_canvas_item_ungrab(item, event->button.time);
01182           dragging = FALSE;
01183 
01184           if(target_point_previous)
01185             {
01186               if(strcmp(shape->targetfile, UNDEFINED)==0)
01187                gnome_canvas_item_set(GNOME_CANVAS_ITEM(target_point_previous),
01188                                    "fill_color_rgba", POINT_COLOR_OFF,
01189                                    NULL);
01190               else
01191                gc_item_focus_set(target_point_previous, FALSE);
01192             }
01193           target_point_previous = NULL;
01194 
01195           targetshape = find_closest_shape(item_x - offset_x,
01196                                        item_y - offset_y,
01197                                        SQUARE_LIMIT_DISTANCE);
01198           if(targetshape!=NULL)
01199             {
01200               /* Finish the placement of the grabbed item anyway */
01201               gnome_canvas_item_move(item,
01202                                   targetshape->x - x + offset_x,
01203                                   targetshape->y - y + offset_y);
01204               /* Hide it */
01205               gnome_canvas_item_hide(item);
01206 
01207               if(strcmp(targetshape->name, shape->name)==0)
01208                {
01209                  /* You got it right perfect */
01210                  if(targetshape->bad_item!=NULL)
01211                    {
01212                      gnome_canvas_item_hide(targetshape->bad_item);
01213                      gtk_object_destroy (GTK_OBJECT(targetshape->bad_item));
01214                      targetshape->bad_item=NULL;
01215                    }
01216                  targetshape->found  = TRUE;
01217                  shape->target_shape->placed = TRUE;
01218                  g_warning("setting shape->name=%s to placed=%d\n", shape->target_shape->name,
01219                        shape->target_shape->placed);
01220                  gnome_canvas_item_show(targetshape->item);
01221                  gnome_canvas_item_raise_to_top(targetshape->item);
01222                }
01223               else
01224                {
01225                  /* Oups wrong position, create the wrong pixmap item */
01226                  GdkPixbuf *pixmap;
01227                  GnomeCanvasItem *item;
01228 
01229                  targetshape->found = FALSE;
01230                  shape->target_shape->placed = TRUE;
01231                  g_warning("setting shape->name=%s to placed=%d\n", shape->target_shape->name,
01232                        shape->target_shape->placed);
01233                  gnome_canvas_item_hide(targetshape->item);
01234 
01235                  /* There is already a bad item, delete it */
01236                  if(targetshape->bad_item!=NULL)
01237                    gtk_object_destroy (GTK_OBJECT(targetshape->bad_item));
01238 
01239                  pixmap = gc_pixmap_load(shape->pixmapfile);
01240                  item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_root_item),
01241                                            gnome_canvas_pixbuf_get_type (),
01242                                            "pixbuf", pixmap,
01243                                            "x", (double)targetshape->x - (gdk_pixbuf_get_width(pixmap)
01244                                                                       * shape->zoomx)/2,
01245                                            "y", (double)targetshape->y - (gdk_pixbuf_get_height(pixmap)
01246                                                                       * shape->zoomy/2),
01247                                            "width", (double) gdk_pixbuf_get_width(pixmap) * shape->zoomx,
01248                                            "height", (double) gdk_pixbuf_get_height(pixmap) * shape->zoomy,
01249                                            "width_set", TRUE,
01250                                            "height_set", TRUE,
01251                                            NULL);
01252                  gdk_pixbuf_unref(pixmap);
01253 
01254                  targetshape->bad_item = item;
01255                  setup_item(item, targetshape);
01256                }
01257 
01258               /* If There was a previous icon here, put it back to the list */
01259               shape_goes_back_to_list(targetshape, item);
01260 
01261               /* Set the icon item */
01262               targetshape->icon_shape=shape;
01263 
01264             }
01265           else
01266             {
01267               /* The item has no close position */
01268               switch(shape->type)
01269                {
01270                case SHAPE_TARGET:
01271                  gnome_canvas_item_hide(item);
01272                  if( shape->icon_shape!=NULL)
01273                    {
01274                      item = shape->icon_shape->item;
01275                      gnome_canvas_item_show(item);
01276                    }
01277                  break;
01278                case SHAPE_ICON:
01279                  break;
01280                default:
01281                  break;
01282                }
01283               /* Move back the item home */
01284               gnome_canvas_item_move(item,
01285                                   shape->x - x + offset_x,
01286                                   shape->y - y + offset_y);
01287               shape->target_shape->placed = FALSE;
01288               /* Mark it not found */
01289               shape->target_shape->found = FALSE;
01290               dump_shape(shape);
01291               dump_shape(shape->target_shape);
01292             }
01293         }
01294        break;
01295 
01296      default:
01297        break;
01298      }
01299 
01300    return FALSE;
01301  }
01302 
01303 /*
01304  * Special mode to edit the board by moving the target point
01305  */
01306 static gint
01307 item_event_edition(GnomeCanvasItem *item, GdkEvent *event, Shape *shape)
01308 {
01309    static double x, y;
01310    double new_x, new_y;
01311    GdkCursor *fleur;
01312    static int dragging;
01313    double item_x, item_y;
01314 
01315   if(!gcomprisBoard)
01316     return FALSE;
01317 
01318   if(!edit_mode)
01319     return FALSE;
01320 
01321    if(shape==NULL) {
01322      g_warning("Shape is NULL : Should not happen");
01323      return FALSE;
01324    }
01325 
01326    if(shape->type != SHAPE_TARGET)
01327      return FALSE;
01328 
01329    item_x = event->button.x;
01330    item_y = event->button.y;
01331    gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
01332 
01333    switch (event->type)
01334      {
01335      case GDK_BUTTON_PRESS:
01336        switch(event->button.button)
01337          {
01338          case 1:
01339            if (event->button.state & GDK_SHIFT_MASK)
01340              {
01341               /* Cheat code to save an XML file */
01342               write_xml_file("/tmp/gcompris-board.xml");
01343             }
01344           else
01345             {
01346               x = item_x;
01347               y = item_y;
01348 
01349               item = shape->target_point;
01350 
01351               fleur = gdk_cursor_new(GDK_FLEUR);
01352 
01353               gc_canvas_item_grab(item,
01354                                   GDK_POINTER_MOTION_MASK |
01355                                   GDK_BUTTON_RELEASE_MASK,
01356                                   fleur,
01357                                   event->button.time);
01358               gdk_cursor_destroy(fleur);
01359               dragging = TRUE;
01360             }
01361           break;
01362 
01363          default:
01364            break;
01365          }
01366        break;
01367 
01368      case GDK_MOTION_NOTIFY:
01369        if (dragging && (event->motion.state & GDK_BUTTON1_MASK))
01370          {
01371           new_x = item_x;
01372           new_y = item_y;
01373 
01374           gnome_canvas_item_move(item, new_x - x, new_y - y);
01375           gnome_canvas_item_move(shape->item, new_x - x, new_y - y);
01376 
01377           // Update the shape's coordinate
01378           shape->x = shape->x + new_x - x;
01379           shape->y = shape->y + new_y - y;
01380 
01381           x = new_x;
01382           y = new_y;
01383          }
01384        break;
01385 
01386      case GDK_BUTTON_RELEASE:
01387        if(dragging)
01388         {
01389 
01390           gc_canvas_item_ungrab(item, event->button.time);
01391           gnome_canvas_item_raise_to_top(item);
01392           dragging = FALSE;
01393 
01394         }
01395        break;
01396 
01397      default:
01398        break;
01399      }
01400 
01401    return FALSE;
01402 
01403 }
01404 
01405 /* Callback for the operations */
01406 static gint
01407 item_event_ok(GnomeCanvasItem *item, GdkEvent *event, gpointer data)
01408 {
01409   GnomeCanvasItem    *root_item;
01410 
01411   if(board_paused)
01412     return FALSE;
01413 
01414   switch (event->type)
01415     {
01416     case GDK_BUTTON_PRESS:
01417       root_item = g_list_nth_data(shape_list_group, current_shapelistgroup_index);
01418       gnome_canvas_item_hide(root_item);
01419 
01420       g_warning(" item event current_shapelistgroup_index=%d\n", current_shapelistgroup_index);
01421       if(!strcmp((char *)data, "previous_shapelist"))
01422        {
01423 
01424          if(current_shapelistgroup_index>0)
01425            {
01426              current_shapelistgroup_index--;
01427            }
01428 
01429          if(current_shapelistgroup_index == 0)
01430            {
01431              gc_item_focus_set(item, TRUE);
01432              gnome_canvas_item_hide(previous_shapelist_item);
01433            }
01434 
01435          gnome_canvas_item_show(next_shapelist_item);
01436 
01437        }
01438       else if(!strcmp((char *)data, "next_shapelist"))
01439        {
01440          if(current_shapelistgroup_index<g_list_length(shape_list_group)-1)
01441            {
01442              current_shapelistgroup_index++;
01443            }
01444 
01445          if(current_shapelistgroup_index == g_list_length(shape_list_group)-1)
01446            {
01447              gc_item_focus_set(item, TRUE);
01448              gnome_canvas_item_hide(next_shapelist_item);
01449            }
01450 
01451          gnome_canvas_item_show(previous_shapelist_item);
01452 
01453        }
01454 
01455       root_item = g_list_nth_data(shape_list_group, current_shapelistgroup_index);
01456       gnome_canvas_item_show(root_item);
01457 
01458       /* FIXME : Workaround for bugged canvas */
01459       //      gnome_canvas_update_now(gcomprisBoard->canvas);
01460 
01461     default:
01462       break;
01463     }
01464   return FALSE;
01465 
01466 
01467 }
01468 
01469 static void
01470 setup_item(GnomeCanvasItem *item, Shape *shape)
01471 {
01472   gtk_signal_connect(GTK_OBJECT(item), "event",
01473                    (GtkSignalFunc) item_event,
01474                    shape);
01475 }
01476 
01477 /*
01478  * Thanks for George Lebl <jirka@5z.com> for his Genealogy example
01479  * for all the XML stuff there
01480  */
01481 
01482 /* Adds a shape to the canvas */
01483 static void
01484 add_shape_to_canvas(Shape *shape)
01485 {
01486   GdkPixbuf *pixmap;
01487   GdkPixbuf *targetpixmap;
01488   GnomeCanvasItem *item = NULL;
01489 
01490   /* checking of preconditions, this is usefull for tracking down bugs,
01491      but you should not count on these always being compiled in */
01492   g_return_if_fail(shape != NULL);
01493 
01494   if(shape->type==SHAPE_TARGET)
01495     {
01496       if(strcmp(shape->targetfile, UNDEFINED)!=0)
01497        {
01498          targetpixmap = gc_pixmap_load(shape->targetfile);
01499          shape->w = (double)gdk_pixbuf_get_width(targetpixmap) * shape->zoomx;
01500          shape->h = (double)gdk_pixbuf_get_height(targetpixmap) *shape->zoomy;
01501 
01502          item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_root_item),
01503                                    gnome_canvas_pixbuf_get_type (),
01504                                    "pixbuf", targetpixmap,
01505                                    "x", shape->x - shape->w / 2,
01506                                    "y", shape->y - shape->h / 2,
01507                                    "width",  shape->w,
01508                                    "height", shape->h,
01509                                    "width_set", TRUE,
01510                                    "height_set", TRUE,
01511                                    NULL);
01512          shape->targetitem = item;
01513          gdk_pixbuf_unref(targetpixmap);
01514        }
01515       else
01516        {
01517          int point_size = 6;
01518 
01519          /* Display a point to highlight the target location of this shape */
01520          item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_root_item),
01521                                    gnome_canvas_ellipse_get_type(),
01522                                    "x1", (double)shape->x-point_size,
01523                                    "y1", (double)shape->y-point_size,
01524                                    "x2", (double)shape->x+point_size,
01525                                    "y2", (double)shape->y+point_size,
01526                                    "fill_color_rgba", POINT_COLOR_OFF,
01527                                    "outline_color", "black",
01528                                    "width_pixels", 2,
01529                                    NULL);
01530          shape->target_point = item;
01531          gtk_signal_connect(GTK_OBJECT(item), "event",
01532                           (GtkSignalFunc) item_event_edition,
01533                           shape);
01534        }
01535       gnome_canvas_item_lower_to_bottom(item);
01536     }
01537 
01538   if(shape->points!=NULL)
01539     {
01540       g_warning("it's a point \n");
01541       item = gnome_canvas_item_new(GNOME_CANVAS_GROUP(shape_root_item),
01542                                gnome_canvas_polygon_get_type (),
01543                                "points", shape->points,
01544                                "fill_color", "grey",
01545                                "outline_color", "black",
01546                                "width_units", 1.0,
01547                                NULL);
01548     }
01549   else
01550     {
01551       g_warning("it's an image ? shape->pixmapfile=%s\n", shape->pixmapfile);
01552       if(strcmp(shape->pixmapfile, UNDEFINED)!=0)
01553        {
01554          g_warning("  Yes it is an image \n");
01555          pixmap = gc_pixmap_load(shape->pixmapfile);
01556          if(pixmap)
01557            {
01558              shape->w = (double)gdk_pixbuf_get_width(pixmap) * shape->zoomx;
01559              shape->h = (double)gdk_pixbuf_get_height(pixmap) * shape->zoomy;
01560 
01561              /* Display the shape itself but hide it until the user puts the right shape on it */
01562              /* I have to do it this way for the positionning (lower/raise) complexity          */
01563              item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_root_item),
01564                                        gnome_canvas_pixbuf_get_type (),
01565                                        "pixbuf", pixmap,
01566                                        "x", shape->x - shape->w / 2,
01567                                        "y", shape->y - shape->h / 2,
01568                                        "width", shape->w,
01569                                        "height", shape->h,
01570                                        "width_set", TRUE,
01571                                        "height_set", TRUE,
01572                                        NULL);
01573              gdk_pixbuf_unref(pixmap);
01574            }
01575        }
01576     }
01577 
01578   /* Associate this item to this shape */
01579   shape->item = item;
01580 
01581   if(shape->type==SHAPE_TARGET || shape->type==SHAPE_DUMMY_TARGET)
01582     {
01583       setup_item(item, shape);
01584 
01585       gnome_canvas_item_hide(item);
01586       add_shape_to_list_of_shapes(shape);
01587     }
01588   else if(shape->type==SHAPE_BACKGROUND)
01589     {
01590       gnome_canvas_item_lower_to_bottom(item);
01591     }
01592 
01593 }
01594 
01595 static void create_title(char *name, double x, double y, GtkJustification justification,
01596                       guint32 color_rgba)
01597 {
01598   GnomeCanvasItem *item;
01599 
01600   /* Shadow */
01601   item = \
01602     gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_root_item),
01603                         gnome_canvas_text_get_type (),
01604                         "text", gettext(name),
01605                         "font", gc_skin_font_board_medium,
01606                         "x", x + 1.0,
01607                         "y", y + 1.0,
01608                         "anchor", GTK_ANCHOR_CENTER,
01609                         "justification", justification,
01610                         "fill_color_rgba", gc_skin_color_shadow,
01611                         NULL);
01612 
01613   gnome_canvas_item_raise_to_top(item);
01614 
01615   item = \
01616     gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_root_item),
01617                         gnome_canvas_text_get_type (),
01618                         "text", gettext(name),
01619                         "font", gc_skin_font_board_medium,
01620                         "x", x,
01621                         "y", y,
01622                         "anchor", GTK_ANCHOR_CENTER,
01623                         "justification", justification,
01624                         "fill_color_rgba", color_rgba,
01625                         NULL);
01626 
01627   gnome_canvas_item_raise_to_top(item);
01628 }
01629 
01630 static Shape *
01631 create_shape(ShapeType type, char *name, char *tooltip, char *pixmapfile, GnomeCanvasPoints* points,
01632             char *targetfile, double x, double y,
01633             double w, double h, double zoomx,
01634             double zoomy, guint position, char *soundfile)
01635 {
01636   Shape *shape;
01637 
01638   /* allocate a new shape */
01639   shape = g_new(Shape,1);
01640 
01641   shape->name = g_strdup(name);
01642   if(tooltip)
01643     shape->tooltip = g_strdup(tooltip);
01644   else
01645     shape->tooltip = NULL;
01646 
01647   shape->pixmapfile = g_strdup(pixmapfile);
01648   shape->points = points;
01649   shape->targetfile = g_strdup(targetfile);
01650   shape->x = x;
01651   shape->y = y;
01652   shape->w = w;
01653   shape->h = h;
01654   shape->zoomx = zoomx;
01655   shape->zoomy = zoomy;
01656   shape->position = position;
01657   shape->type = type;
01658   shape->soundfile = g_strdup(soundfile);
01659 
01660   shape->bad_item = NULL;
01661   shape->icon_shape = NULL;
01662   shape->target_shape = NULL;
01663 
01664   shape->found  = FALSE;
01665   shape->placed = FALSE;
01666 
01667   /* add the shape to the list */
01668   shape_list = g_list_append(shape_list, shape);
01669 
01670   return shape;
01671 }
01672 
01682 static double
01683 xmlGetProp_Double(xmlNodePtr node, xmlChar *prop, double def_value)
01684 {
01685   double value;
01686   char *str;
01687 
01688   str = (char *)xmlGetProp(node, prop);
01689   if(str)
01690   {
01691        value = g_ascii_strtod(str, NULL);
01692       free(str);
01693   }
01694   else
01695       value = def_value;
01696 
01697   return value;
01698 }
01699 
01700 static void
01701 add_xml_shape_to_data(xmlDocPtr doc, xmlNodePtr xmlnode, GNode * child)
01702 {
01703   char *name, *cd ,*ctype, *justification;
01704   char *tooltip;
01705   GtkJustification justification_gtk;
01706   char *pixmapfile = NULL;
01707   char *targetfile = NULL;
01708   char *soundfile = NULL;
01709   double x, y, zoomx, zoomy;
01710   GnomeCanvasPoints* points = NULL;
01711   gchar **d;
01712   gint i, j;
01713   guint position;
01714   ShapeType type = SHAPE_TARGET;
01715   Shape *shape;
01716   xmlNodePtr xmlnamenode;
01717   char *locale;
01718   char *color_text;
01719   guint color_rgba;
01720 
01721   if(/* if the node has no name */
01722      !xmlnode->name ||
01723      /* or if the name is not "Shape" */
01724      ((g_strcasecmp((const char *)xmlnode->name,"Shape")!=0) &&
01725      /* or if the name is not "Title" */
01726       (g_strcasecmp((const char *)xmlnode->name,"Title")!=0) &&
01727      /* or if the name is not "Option" */
01728       (g_strcasecmp((const char *)xmlnode->name,"Option")!=0) )
01729      )
01730     return;
01731 
01732   pixmapfile = (char *)xmlGetProp(xmlnode, BAD_CAST "pixmapfile");
01733   if(pixmapfile) {
01734     /* If the pixmapfile starts with skin: then get the skin relative image instead */
01735     if(!strncmp(pixmapfile, "skin:", 5)) {
01736       gchar *oldpixmapfile = pixmapfile;
01737       pixmapfile = gc_skin_image_get(oldpixmapfile+5);
01738       g_free(oldpixmapfile);
01739     }
01740   }
01741 
01742   targetfile = (char *)xmlGetProp(xmlnode, BAD_CAST "targetfile");
01743 
01744   soundfile = (char *)xmlGetProp(xmlnode, BAD_CAST "sound");
01745   /*********************************/
01746   /* get the points for a polygone */
01747   /* The list of points is similar to the one define in the SVG standard */
01748   /* FIXME : The implementation is incomplete, a point still needs to be added
01749      to shapelist and add management for it's x/y coordinates */
01750   cd = (char *)xmlGetProp(xmlnode, BAD_CAST "points");
01751   if(!cd)
01752     {
01753       cd = "";
01754     }
01755   else
01756     {
01757       d = g_strsplit(cd, " ", 64);
01758 
01759       j=0;
01760       while(d[j]!=NULL)
01761        {
01762          j++;
01763        }
01764 
01765       points = gnome_canvas_points_new(j/2);
01766 
01767       for(i=0; i<j; i++)
01768        {
01769          points->coords[i] = g_ascii_strtod(d[i], NULL);
01770        }
01771       g_strfreev(d);
01772     }
01773 
01774   /* get the X coord of the shape */
01775   x = xmlGetProp_Double(xmlnode, BAD_CAST "x", 100);
01776   /* get the Y coord of the shape */
01777   y = xmlGetProp_Double(xmlnode, BAD_CAST "y", 100);
01778 
01779   /* Back up the current locale to be sure to load well C formated numbers */
01780   locale = g_strdup(gc_locale_get());
01781   gc_locale_set("C");
01782 
01783   /* get the ZOOMX coord of the shape */
01784   zoomx = xmlGetProp_Double(xmlnode, BAD_CAST "zoomx", 1);
01785 
01786   /* get the ZOOMY coord of the shape */
01787   zoomy = xmlGetProp_Double(xmlnode, BAD_CAST "zoomy", 1);
01788 
01789   /* get the POSITION of the shape */
01790   /* Position in the xml means:
01791    * 0 = BOTTOM
01792    * 1 or more = TOP
01793    */
01794   position = (guint) xmlGetProp_Double(xmlnode, BAD_CAST "position", 0);
01795 
01796   /* Back to the user locale */
01797   gc_locale_set(locale);
01798   g_free(locale);
01799 
01800   /* get the TYPE of the shape */
01801   ctype = (char *)xmlGetProp(xmlnode, BAD_CAST "type");
01802   if(ctype) {
01803     if(g_strcasecmp(ctype,"SHAPE_TARGET")==0)
01804         type = SHAPE_TARGET;
01805       else if(g_strcasecmp(ctype,"SHAPE_DUMMY_TARGET")==0)
01806         type = SHAPE_DUMMY_TARGET;
01807       else if (g_strcasecmp(ctype,"SHAPE_BACKGROUND")==0)
01808         type = SHAPE_BACKGROUND;
01809       else if (g_strcasecmp(ctype,"SHAPE_COLORLIST")==0)
01810         type = SHAPE_COLORLIST;
01811    xmlFree(ctype);
01812   }
01813   else
01814       type = SHAPE_TARGET;
01815 
01816   /* get the JUSTIFICATION of the Title */
01817   justification_gtk = GTK_JUSTIFY_CENTER; /* GTK_JUSTIFICATION_CENTER is default */
01818   justification = (char *)xmlGetProp(xmlnode, BAD_CAST "justification");
01819   if(justification) {
01820     if (strcmp(justification, "GTK_JUSTIFY_LEFT") == 0) {
01821       justification_gtk = GTK_JUSTIFY_LEFT;
01822     } else if (strcmp(justification, "GTK_JUSTIFY_RIGHT") == 0) {
01823       justification_gtk = GTK_JUSTIFY_RIGHT;
01824     } else if (strcmp(justification, "GTK_JUSTIFY_CENTER") == 0) {
01825       justification_gtk = GTK_JUSTIFY_CENTER;
01826     } else if (strcmp(justification, "GTK_JUSTIFY_FILL") == 0) {
01827       justification_gtk = GTK_JUSTIFY_FILL;
01828     }
01829     xmlFree(justification);
01830   }
01831 
01832   /* get the COLOR of the Title Specified by skin reference */
01833   color_text = (char *)xmlGetProp(xmlnode, BAD_CAST "color_skin");
01834   if(color_text) {
01835     color_rgba = gc_skin_get_color(color_text);
01836     xmlFree(color_text);
01837   } else {
01838     color_rgba = gc_skin_get_color("gcompris/content"); /* the default */
01839   }
01840 
01841   /* get the name and tooltip of the shape */
01842   name    = NULL;
01843   tooltip = NULL;
01844 
01845   xmlnamenode = xmlnode->xmlChildrenNode;
01846   while (xmlnamenode != NULL) {
01847     gchar *lang = (char *)xmlGetProp(xmlnamenode, BAD_CAST "lang");
01848     /* get the name of the shape */
01849     if (!strcmp((char *)xmlnamenode->name, "name")
01850        && (lang==NULL
01851            || !strcmp(lang, gc_locale_get())
01852            || !strncmp(lang, gc_locale_get(), 2)))
01853       {
01854           if (name)
01855               xmlFree(name);
01856               name = (char *)xmlNodeListGetString(doc, xmlnamenode->xmlChildrenNode, 1);
01857       }
01858 
01859     /* get the tooltip of the shape */
01860     if (!strcmp((char *)xmlnamenode->name, "tooltip")
01861        && (lang==NULL
01862            || !strcmp(lang, gc_locale_get())
01863            || !strncmp(lang, gc_locale_get(), 2)))
01864       {
01865           if (tooltip)
01866               xmlFree(tooltip);
01867           tooltip = (char *)xmlNodeListGetString(doc, xmlnamenode->xmlChildrenNode, 1);
01868       }
01869     xmlFree(lang);
01870     xmlnamenode = xmlnamenode->next;
01871   }
01872 
01873   /* If name is not given as an element, try to get it as a property */
01874   if(!name)
01875     name = (char *)xmlGetProp(xmlnode, BAD_CAST "name");
01876 
01877 
01878   if(g_strcasecmp((char *)xmlnode->name, "Shape")==0)
01879     {
01880       /* add the shape to the database */
01881       /* WARNING : I do not initialize the width and height since I don't need them */
01882       shape = create_shape(type, name, tooltip, pixmapfile ? pixmapfile : UNDEFINED, points,
01883                 targetfile ? targetfile : UNDEFINED, x, y,
01884                         (double)0, (double)0,
01885                         zoomx, zoomy, position,
01886                soundfile ? soundfile : UNDEFINED);
01887 
01888       /* add the shape to the list */
01889       shape_list_init = g_list_append(shape_list_init, shape);
01890     }
01891   else if (g_strcasecmp((char *)xmlnode->name, "Title")==0)
01892     {
01893       /* Readd \n is needed */
01894       gchar *newname;
01895 
01896       if(name != NULL) {
01897        newname = g_strcompress(name);
01898 
01899        create_title(newname, x, y, justification_gtk, color_rgba);
01900     g_free(newname);
01901       }
01902     }
01903   g_free(pixmapfile);
01904   g_free(soundfile);
01905   g_free(name);
01906   g_free(targetfile);
01907   g_free(tooltip);
01908 }
01909 
01910 /* parse the doc, add it to our internal structures and to the clist */
01911 static void
01912 parse_doc(xmlDocPtr doc)
01913 {
01914   xmlNodePtr node;
01915   GList *list;
01916   GnomeCanvasItem *item;
01917 
01918   /* find <Shape> nodes and add them to the list, this just
01919      loops through all the children of the root of the document */
01920   for(node = doc->children->children; node != NULL; node = node->next) {
01921     /* add the shape to the list, there are no children so
01922        we pass NULL as the node of the child */
01923     add_xml_shape_to_data(doc, node, NULL);
01924   }
01925 
01926   shape_list = g_list_copy(shape_list_init);
01927 
01928   /* Insert each of the shapes randomly */
01929   while(g_list_length(shape_list_init)>0)
01930     {
01931       Shape *shape;
01932 
01933       shape = g_list_nth_data(shape_list_init, RAND(0, (g_list_length(shape_list_init)-1)));
01934       add_shape_to_canvas(shape);
01935 
01936       shape_list_init = g_list_remove (shape_list_init, shape);
01937     }
01938 
01939   g_list_free(shape_list_init);
01940   shape_list_init = NULL;
01941 
01942   if(current_shapelistgroup_index>0) { /* If at least on shape group */
01943     item = g_list_nth_data(shape_list_group, current_shapelistgroup_index);
01944     gnome_canvas_item_hide(item);
01945     item = g_list_nth_data(shape_list_group, 0);
01946     gnome_canvas_item_show(item);
01947     gnome_canvas_item_hide(previous_shapelist_item);
01948     gnome_canvas_item_show(next_shapelist_item);
01949     current_shapelistgroup_index = 0;
01950   }
01951 
01952   /* Loop through all the shapes and */
01953   /* Arrange the order (depth) of the shapes on the canvas */
01954   /* Depending on the xml given definition in the position property */
01955   for(list = shape_list; list != NULL; list = list->next) {
01956     Shape *shape = list->data;
01957 
01958     gnome_canvas_item_lower_to_bottom(shape->item);
01959     if(shape->position>=1)
01960       gnome_canvas_item_raise(shape->item, ABS(shape->position));
01961   }
01962 }
01963 
01964 
01965 
01966 /* read an xml file into our memory structures and update our view,
01967    dump any old data we have in memory if we can load a new set */
01968 static gboolean
01969 read_xml_file(char *fname)
01970 {
01971   /* pointer to the new doc */
01972   xmlDocPtr  doc;
01973   gchar     *tmpstr;
01974 
01975   g_return_val_if_fail(fname!=NULL,FALSE);
01976 
01977   /* parse the new file and put the result into newdoc */
01978   doc = gc_net_load_xml(fname);
01979   /* in case something went wrong */
01980   if(!doc)
01981     return FALSE;
01982 
01983   if(/* if there is no root element */
01984      !doc->children ||
01985      /* if it doesn't have a name */
01986      !doc->children->name ||
01987      /* if it isn't a ShapeGame node */
01988      g_strcasecmp((char *)doc->children->name, "ShapeGame")!=0) {
01989     xmlFreeDoc(doc);
01990     return FALSE;
01991   }
01992 
01993   /*--------------------------------------------------*/
01994   /* Read OkIfAddedName property */
01995   tmpstr = (char *)xmlGetProp(doc->children, BAD_CAST "OkIfAddedName");
01996   /* if unspecified, make it INT_MAX */
01997   if(!tmpstr)
01998       addedname = INT_MAX;
01999   else
02000       addedname = atoi(tmpstr);
02001   g_warning("addedname=%d\n", addedname);
02002 
02003   /*--------------------------------------------------*/
02004   /* Read ShapeBox property */
02005   tmpstr = (char *)xmlGetProp(doc->children, BAD_CAST "shapebox_x");
02006   /* if unspecified, use the default value */
02007   if(!tmpstr)
02008       shapeBox.x = 15;
02009   else
02010     shapeBox.x = g_ascii_strtod(tmpstr, NULL);
02011   g_warning("shapeBox.x=%f\n", shapeBox.x);
02012 
02013   tmpstr = (char *)xmlGetProp(doc->children, BAD_CAST "shapebox_y");
02014   /* if unspecified, use the default value */
02015   if(!tmpstr)
02016       shapeBox.y = 25;
02017   else
02018     shapeBox.y = g_ascii_strtod(tmpstr, NULL);
02019   g_warning("shapeBox.y=%f\n", shapeBox.y);
02020 
02021   tmpstr = (char *)xmlGetProp(doc->children, BAD_CAST "shapebox_w");
02022   /* if unspecified, use the default value */
02023   if(!tmpstr)
02024       shapeBox.w = 80;
02025   else
02026     shapeBox.w = g_ascii_strtod(tmpstr, NULL);
02027   g_warning("shapeBox.w=%f\n", shapeBox.w);
02028 
02029   tmpstr = (char *)xmlGetProp(doc->children, BAD_CAST "shapebox_h");
02030   /* if unspecified, use the default value */
02031   if(!tmpstr)
02032       shapeBox.h = 430;
02033   else
02034     shapeBox.h = g_ascii_strtod(tmpstr, NULL);
02035   g_warning("shapeBox.h=%f\n", shapeBox.h);
02036 
02037   tmpstr = (char *)xmlGetProp(doc->children, BAD_CAST "shapebox_nb_shape_x");
02038   /* if unspecified, use the default value */
02039   if(!tmpstr)
02040       shapeBox.nb_shape_x = 1;
02041   else
02042       shapeBox.nb_shape_x = atoi(tmpstr);
02043   g_warning("shapeBox.nb_shape_x=%d\n", shapeBox.nb_shape_x);
02044 
02045   tmpstr = (char *)xmlGetProp(doc->children, BAD_CAST "shapebox_nb_shape_y");
02046   /* if unspecified, use the default value */
02047   if(!tmpstr)
02048       shapeBox.nb_shape_y = 5;
02049   else
02050       shapeBox.nb_shape_y = atoi(tmpstr);
02051   g_warning("shapeBox.nb_shape_y=%d\n", shapeBox.nb_shape_y);
02052 
02053 
02054   /* parse our document and replace old data */
02055   parse_doc(doc);
02056 
02057   xmlFreeDoc(doc);
02058 
02059   return TRUE;
02060 }
02061 
02062 /* add a shape to xmlnode from node */
02063 static void
02064 write_shape_to_xml(xmlNodePtr xmlnode, Shape *shape)
02065 {
02066   xmlNodePtr newxml;
02067   gchar *tmp;
02068 
02069   g_return_if_fail(xmlnode!=NULL);
02070   g_return_if_fail(shape!=NULL);
02071 
02072   /* make a new xml node (as a child of xmlnode) with an
02073      empty content */
02074   newxml = xmlNewChild(xmlnode,NULL, BAD_CAST "Shape",NULL);
02075   /* set properties on it */
02076   xmlSetProp(newxml, BAD_CAST "name", BAD_CAST shape->name);
02077   if(shape->tooltip)
02078     xmlSetProp(newxml, BAD_CAST "tooltip", BAD_CAST shape->tooltip);
02079   xmlSetProp(newxml, BAD_CAST "pixmapfile", BAD_CAST shape->pixmapfile);
02080   xmlSetProp(newxml, BAD_CAST "sound", BAD_CAST shape->soundfile);
02081 
02082   tmp = g_strdup_printf("%f", shape->x);
02083   xmlSetProp(newxml, BAD_CAST "x", BAD_CAST tmp);
02084   g_free(tmp);
02085 
02086   tmp = g_strdup_printf("%f", shape->y);
02087   xmlSetProp(newxml, BAD_CAST "y", BAD_CAST tmp);
02088   g_free(tmp);
02089 
02090   tmp = g_strdup_printf("%f", shape->zoomx);
02091   xmlSetProp(newxml, BAD_CAST "zoomx", BAD_CAST tmp);
02092   g_free(tmp);
02093 
02094   tmp = g_strdup_printf("%f", shape->zoomy);
02095   xmlSetProp(newxml, BAD_CAST "zoomy", BAD_CAST tmp);
02096   g_free(tmp);
02097 
02098   tmp = g_strdup_printf("%d", shape->position);
02099   xmlSetProp(newxml, BAD_CAST "position", BAD_CAST tmp);
02100   g_free(tmp);
02101 
02102 }
02103 
02104 /* write an xml file
02105  * This is used only for creating shapegame boards
02106  */
02107 static gboolean
02108 write_xml_file(char *fname)
02109 {
02110   /* pointer to the new doc */
02111   xmlDocPtr doc;
02112   GList *list;
02113 
02114   g_return_val_if_fail(fname!=NULL,FALSE);
02115 
02116   /* create new xml document with version 1.0 */
02117   doc = xmlNewDoc( BAD_CAST "1.0");
02118   /* create a new root node "ShapeGame" */
02119   doc->children = xmlNewDocNode(doc, NULL, BAD_CAST "ShapeGame", NULL);
02120 
02121   /* loop through all our shapes */
02122   for(list = shape_list; list != NULL; list = list->next) {
02123     Shape *shape = list->data;
02124     if(shape->type!=SHAPE_ICON)
02125       write_shape_to_xml(doc->children, shape);
02126   }
02127 
02128   /* try to save the file */
02129   if(xmlSaveFile(fname,doc) == -1) {
02130     xmlFreeDoc(doc);
02131     return FALSE;
02132   }
02133 
02134   xmlFreeDoc(doc);
02135 
02136   return TRUE;
02137 }
02138 
02139 
02140 
02141 /* ************************************* */
02142 /* *            Configuration          * */
02143 /* ************************************* */
02144 
02145 
02146 /* ======================= */
02147 /* = config_start        = */
02148 /* ======================= */
02149 
02150 static GcomprisProfile *profile_conf;
02151 static GcomprisBoard   *board_conf;
02152 
02153 static void save_table (gpointer key,
02154                      gpointer value,
02155                      gpointer user_data)
02156 {
02157   gc_db_set_board_conf ( profile_conf,
02158                          board_conf,
02159                          (gchar *) key,
02160                          (gchar *) value);
02161 }
02162 
02163 static void conf_ok(GHashTable *table)
02164 {
02165   if (!table){
02166     if (gcomprisBoard)
02167       pause_board(FALSE);
02168     return;
02169   }
02170 
02171   g_hash_table_foreach(table, (GHFunc) save_table, NULL);
02172 
02173   if ((gcomprisBoard) && (strcmp(gcomprisBoard->name, "imagename")==0)){
02174     GHashTable *config;
02175 
02176     if (profile_conf)
02177       config = gc_db_get_board_conf();
02178     else
02179       config = table;
02180 
02181     gc_locale_reset();
02182 
02183     gc_locale_set(g_hash_table_lookup( config, "locale"));
02184 
02185     if (profile_conf)
02186       g_hash_table_destroy(config);
02187 
02188     shapegame_next_level();
02189 
02190     pause_board(FALSE);
02191   }
02192 
02193   board_conf = NULL;
02194   profile_conf = NULL;
02195 
02196 }
02197 
02198 static void
02199 config_start(GcomprisBoard *agcomprisBoard,
02200                   GcomprisProfile *aProfile)
02201 {
02202   board_conf = agcomprisBoard;
02203   profile_conf = aProfile;
02204 
02205   if (gcomprisBoard)
02206     pause_board(TRUE);
02207 
02208   gchar * label = g_strdup_printf("<b>%s</b> configuration\n for profile <b>%s</b>",
02209                               agcomprisBoard->name,
02210                               aProfile? aProfile->name : "");
02211 
02212   gc_board_config_window_display( label,
02213                              (GcomprisConfCallback )conf_ok);
02214 
02215   g_free(label);
02216 
02217   /* init the combo to previously saved value */
02218   GHashTable *config = gc_db_get_conf( profile_conf, board_conf);
02219 
02220   gchar *locale = g_hash_table_lookup( config, "locale");
02221 
02222   gc_board_config_combo_locales( locale);
02223 
02224 }
02225 
02226 
02227 /* ======================= */
02228 /* = config_stop        = */
02229 /* ======================= */
02230 static void
02231 config_stop()
02232 {
02233 }