/* gcompris - shapegame.c
*
* Copyright (C) 2000 Bruno Coudoin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
/* libxml includes */
#include
#include
#include
#include
#include "gcompris/gcompris.h"
#include "gcompris/pixbuf_util.h"
#define SOUNDLISTFILE PACKAGE
#define SQUARE_LIMIT_DISTANCE 100.0
static int gamewon;
static GcomprisBoard *gcomprisBoard = NULL;
static gboolean board_paused = TRUE;
static gboolean shadow_enable;
#define POINT_COLOR_OFF 0xEf000080
#define POINT_COLOR_ON 0x00EF0080
typedef enum
{
SHAPE_TARGET = 1 << 0,
SHAPE_DUMMY_TARGET = 1 << 1,
SHAPE_ICON = 1 << 2,
SHAPE_BACKGROUND = 1 << 3,
} ShapeType;
/* Let's define the structure for a single shape */
typedef struct _Shape Shape;
struct _Shape {
char *name; /* name of the shape */
char *tooltip; /* optional tooltip for the shape */
char *pixmapfile; /* relative pixmap file name of the shape */
GnomeCanvasPoints* points; /* OR list of points for this shape */
char *targetfile; /* OPTIONAL relative pixmap file name of the target shape, by default
a red point is displayed */
double x; /* x coordinate */
double y; /* y coordinate */
double w; /* width */
double h; /* height */
double zoomx; /* x zoom factor */
double zoomy; /* y zoom factor */
gint position; /* depth position 0=bottom other=intermediate */
char *soundfile; /* relative sound file to be played when pressing mouse button */
ShapeType type; /* Type of shape */
GnomeCanvasItem *item; /* Canvas item for this shape */
/* Root index which this item is in the shapelist */
GnomeCanvasGroup *shape_list_group_root;
guint shapelistgroup_index; /* Root index which this item is in the shapelist */
Shape *icon_shape; /* Temporary Canvas icon shape for this shape */
Shape *target_shape; /* If this is an icon shape then point to its shape */
GnomeCanvasItem *target_point; /* Target point item for this shape */
GnomeCanvasItem *targetitem; /* Target item for this shape (if targetfile is defined) */
double offset_x, offset_y;
Shape *shape_place; /* the shape place in this place */
Shape *placed ; /* where is place this shape */
};
/* This is the list of shape for the current game */
static GList *shape_list = NULL;
static GList *shape_list_group = NULL;
static int current_shapelistgroup_index = -1;
static GnomeCanvasItem *next_shapelist_item = NULL; /* Canvas item button for the next shapelist */
static GnomeCanvasItem *previous_shapelist_item = NULL; /* Canvas item button for the previous shapelist */
/* Let's define the structure for the shapebox list that contains the icons of the shapes */
typedef struct _ShapeBox ShapeBox;
struct _ShapeBox {
double x; /* x coordinate */
double y; /* y coordinate */
double w; /* width */
double h; /* height */
guint nb_shape_x; /* Number of shape on x */
guint nb_shape_y; /* Number of shape on y */
};
static ShapeBox shapeBox;
/* Hash table of all the shapes in the list of shapes (one by different pixmap plus icon list) */
static GHashTable *shapelist_table = NULL;
static gint SHAPE_BOX_WIDTH = 44;
static GnomeCanvasItem *shape_root_item;
static GnomeCanvasItem *shape_list_root_item;
/* The tooltip */
static GnomeCanvasGroup *tooltip_root_item;
static GnomeCanvasItem *tooltip_text_item;
static GnomeCanvasItem *tooltip_bg_item;
static void start_board (GcomprisBoard *agcomprisBoard);
static void pause_board (gboolean pause);
static void end_board (void);
static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
static void set_level (guint level);
static void process_ok(void);
static gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str);
static void config_start (GcomprisBoard *agcomprisBoard,
GcomprisProfile *aProfile);
static void config_stop (void);
static void shapegame_init_canvas(GnomeCanvasGroup *parent);
static void shapegame_destroy_all_items(void);
static void setup_item(GnomeCanvasItem *item, Shape *shape);
static void shapegame_next_level(void);
static gboolean read_xml_file(char *fname);
static Shape *find_closest_shape(double x, double y, double limit);
static Shape *create_shape(ShapeType type, char *name, char *tooltip,
char *pixmapfile, GnomeCanvasPoints* points,
char *targetfile, double x, double y, double l, double h, double zoomx,
double zoomy, guint position, char *soundfile);
static gboolean increment_sublevel(void);
static void create_title(char *name, double x, double y, GtkJustification justification,
guint32 color_rgba);
static gint item_event_ok(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static gint item_event_drag(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
#if DEBUG
static void dump_shapes(void);
static void dump_shape(Shape *shape);
#endif
static void update_shapelist_item(void);
static void auto_process(void);
static void target_point_hide();
static gint drag_mode;
/* Description of this plugin */
static BoardPlugin menu_bp =
{
NULL,
NULL,
"Make the puzzle",
"Drag and Drop the items to rebuild the object",
"Bruno Coudoin ",
NULL,
NULL,
NULL,
NULL,
start_board,
pause_board,
end_board,
is_our_board,
key_press,
process_ok,
set_level,
NULL,
NULL,
config_start,
config_stop
};
/* Description of this plugin without configuration */
/* static BoardPlugin menu_bp_no_config = */
/* { */
/* NULL, */
/* NULL, */
/* "Make the puzzle", */
/* "Drag and Drop the items to rebuild the object", */
/* "Bruno Coudoin ", */
/* NULL, */
/* NULL, */
/* NULL, */
/* NULL, */
/* start_board, */
/* pause_board, */
/* end_board, */
/* is_our_board, */
/* key_press, */
/* process_ok, */
/* set_level, */
/* NULL, */
/* NULL, */
/* NULL, */
/* NULL */
/* }; */
/*
* Main entry point mandatory for each Gcompris's game
* ---------------------------------------------------
*
*/
GET_BPLUGIN_INFO(shapegame)
/*
* in : boolean TRUE = PAUSE : FALSE = CONTINUE
*
*/
static void pause_board (gboolean pause)
{
if(gcomprisBoard==NULL)
return;
if(gamewon == TRUE && pause == FALSE) /* the game is won */
{
if(increment_sublevel())
shapegame_next_level();
}
board_paused = pause;
}
/*
*/
static void start_board (GcomprisBoard *agcomprisBoard)
{
gchar *filename = NULL;
gboolean default_background = TRUE;
GHashTable *config = gc_db_get_board_conf();
if (strcmp(agcomprisBoard->name, "imagename")==0){
gc_locale_set(g_hash_table_lookup( config, "locale"));
}
gchar *drag_mode_str = g_hash_table_lookup( config, "drag_mode");
if (drag_mode_str && (strcmp (drag_mode_str, "NULL") != 0))
drag_mode = g_ascii_strtod(drag_mode_str, NULL);
else
drag_mode = 0;
g_hash_table_destroy(config);
if(agcomprisBoard!=NULL)
{
gcomprisBoard = agcomprisBoard;
/* disable im_context */
gcomprisBoard->disable_im_context = TRUE;
/* set initial values for this level */
gcomprisBoard->level = 1;
/* Calculate the maxlevel based on the available data file for this board */
gcomprisBoard->maxlevel=1;
/**/
while( (filename = gc_file_find_absolute("%s/board%d_0.xml",
gcomprisBoard->boarddir,
gcomprisBoard->maxlevel,
NULL)) )
{
gcomprisBoard->maxlevel++;
g_free(filename);
}
gcomprisBoard->maxlevel--;
gc_bar_set(GC_BAR_CONFIG|GC_BAR_LEVEL);
gcomprisBoard->sublevel = 0;
/* In this board, the sublevels are dynamicaly discovered based on data files */
gcomprisBoard->number_of_sublevel=G_MAXINT;
if(gcomprisBoard->mode!=NULL)
if(g_strncasecmp(gcomprisBoard->mode, "background=", 11)==0)
{
gchar *tmp = NULL;
tmp = g_malloc(strlen(gcomprisBoard->mode));
tmp = strcpy(tmp, gcomprisBoard->mode + 11);
gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), tmp);
default_background = FALSE;
g_free(tmp);
}
if(default_background)
{
gchar *img;
// Default case, load the default background
img = gc_skin_image_get("gcompris-shapebg.jpg");
gc_set_background(gnome_canvas_root(gcomprisBoard->canvas),
img);
g_free(img);
}
gc_drag_start(gnome_canvas_root(gcomprisBoard->canvas), (gc_Drag_Func) item_event_drag, drag_mode);
shapegame_next_level();
pause_board(FALSE);
}
}
static void
end_board ()
{
if(gcomprisBoard!=NULL)
{
gc_drag_stop(gnome_canvas_root(gcomprisBoard->canvas));
pause_board(TRUE);
shapegame_destroy_all_items();
gcomprisBoard->level = 1; // Restart this game to zero
}
if (strcmp(gcomprisBoard->name, "imagename")==0){
gc_locale_reset();
}
gcomprisBoard = NULL;
}
static void
set_level (guint level)
{
if(gcomprisBoard!=NULL)
{
gcomprisBoard->level=level;
gcomprisBoard->sublevel=0;
shapegame_next_level();
}
}
gboolean
is_our_board (GcomprisBoard *gcomprisBoard)
{
if (gcomprisBoard)
{
if(g_strcasecmp(gcomprisBoard->type, "shapegame")==0)
{
gcomprisBoard->plugin = &menu_bp;
return TRUE;
}
}
return FALSE;
}
/*
* Keypress here are use for entering the editing mode
*/
static gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str)
{
if(board_paused || !gcomprisBoard)
return FALSE;
/* Add some filter for control and shift key */
switch (keyval)
{
/* Avoid all this keys to be interpreted by this game */
case GDK_Shift_L:
case GDK_Shift_R:
case GDK_Control_L:
case GDK_Control_R:
case GDK_Caps_Lock:
case GDK_Shift_Lock:
case GDK_Meta_L:
case GDK_Meta_R:
case GDK_Alt_L:
case GDK_Alt_R:
case GDK_Super_L:
case GDK_Super_R:
case GDK_Hyper_L:
case GDK_Hyper_R:
case GDK_Num_Lock:
return FALSE;
case GDK_KP_Enter:
case GDK_Return:
process_ok();
return TRUE;
case GDK_Right:
case GDK_Delete:
case GDK_BackSpace:
case GDK_Left:
break;
}
return TRUE;
}
/*-------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------*/
/*
* Returns true if increment is done, false is end of board
*/
static gboolean increment_sublevel()
{
gcomprisBoard->sublevel++;
if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) {
/* Try the next level */
gcomprisBoard->level++;
gcomprisBoard->sublevel=0;
if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
gc_bonus_end_display(GC_BOARD_FINISHED_RANDOM);
return FALSE;
}
}
return TRUE;
}
/* set initial values for the next level */
static void shapegame_next_level()
{
char *filename;
gamewon = FALSE;
gc_drag_stop(gnome_canvas_root(gcomprisBoard->canvas));
shapegame_destroy_all_items();
next_shapelist_item = previous_shapelist_item = NULL;
shapegame_init_canvas(gnome_canvas_root(gcomprisBoard->canvas));
while( ((filename = gc_file_find_absolute("%s/board%d_%d.xml",
gcomprisBoard->boarddir,
gcomprisBoard->level,
gcomprisBoard->sublevel,
NULL)) == NULL)
&& ((gcomprisBoard->level != 1) || (gcomprisBoard->sublevel!=0)))
{
/* Try the next level */
gcomprisBoard->sublevel = gcomprisBoard->number_of_sublevel;
if(!increment_sublevel())
return;
}
gc_bar_set_level(gcomprisBoard);
read_xml_file(filename);
gc_drag_start(gnome_canvas_root(gcomprisBoard->canvas), (gc_Drag_Func) item_event_drag, drag_mode);
g_free(filename);
}
static void process_ok()
{
GList *list;
gboolean done = TRUE;
/* Loop through all the shapes to find if all target are found */
for(list = shape_list; list != NULL; list = list->next) {
Shape *shape = list->data;
if(shape->type==SHAPE_TARGET)
{
if(shape->placed!=shape)
done=FALSE;
}
}
if(done)
{
target_point_hide();
gamewon = TRUE;
gc_bonus_display(gamewon, GC_BONUS_FLOWER);
}
else
{
gc_bonus_display(gamewon, GC_BONUS_FLOWER);
}
}
static void destroy_shape (Shape *shape)
{
g_free(shape->name);
g_free(shape->pixmapfile);
g_free(shape->targetfile);
g_free(shape->soundfile);
g_free(shape->tooltip);
if(shape->points!=NULL)
gnome_canvas_points_unref(shape->points);
g_free(shape);
}
/* Destroy all the items */
static void shapegame_destroy_all_items()
{
Shape *shape;
/* Cleanup of the shapes */
while(g_list_length(shape_list)>0)
{
shape = g_list_nth_data(shape_list, 0);
shape_list = g_list_remove (shape_list, shape);
destroy_shape(shape);
}
g_list_free(shape_list);
if (shapelist_table)
{
/* Deleting the root item automatically deletes children items */
gtk_object_destroy (GTK_OBJECT(shape_list_root_item));
shape_list_root_item = NULL;
gtk_object_destroy (GTK_OBJECT(shape_root_item));
shape_root_item = NULL;
gtk_object_destroy (GTK_OBJECT(tooltip_root_item));
tooltip_root_item = NULL;
g_hash_table_destroy (shapelist_table);
shapelist_table=NULL;
g_list_free(shape_list_group);
shape_list_group = NULL;
current_shapelistgroup_index = -1;
}
}
static void shapegame_init_canvas(GnomeCanvasGroup *parent)
{
GdkPixbuf *pixmap = NULL;
shape_list_root_item = \
gnome_canvas_item_new (parent,
gnome_canvas_group_get_type (),
"x", (double)0,
"y", (double)0,
NULL);
shape_root_item = \
gnome_canvas_item_new (parent,
gnome_canvas_group_get_type (),
"x", (double)SHAPE_BOX_WIDTH,
"y", (double)0,
NULL);
tooltip_root_item = GNOME_CANVAS_GROUP(
gnome_canvas_item_new (parent,
gnome_canvas_group_get_type (),
"x", (double)10,
"y", (double)gcomprisBoard->height-70,
NULL)
);
/* Create the tooltip area */
pixmap = gc_skin_pixmap_load("button_large3.png");
tooltip_bg_item = \
gnome_canvas_item_new (GNOME_CANVAS_GROUP(tooltip_root_item),
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) 0,
"y", (double) 0,
NULL);
gdk_pixbuf_unref(pixmap);
tooltip_text_item = \
gnome_canvas_item_new (GNOME_CANVAS_GROUP(tooltip_root_item),
gnome_canvas_text_get_type (),
"text", "",
"font", gc_skin_font_board_small,
"x", (double)gdk_pixbuf_get_width(pixmap)/2,
"y", 24.0,
"anchor", GTK_ANCHOR_CENTER,
"justification", GTK_JUSTIFY_CENTER,
"fill_color_rgba", gc_skin_color_text_button,
NULL);
/* Hide the tooltip */
gnome_canvas_item_hide(GNOME_CANVAS_ITEM(tooltip_root_item));
}
/**************************************************************
* Shape list management
*/
/* Add the given shape to the list of shapes
* Do nothing if the shape is already in
*/
static void
add_shape_to_list_of_shapes(Shape *shape)
{
GnomeCanvasItem *item;
GdkPixbuf *pixmap = NULL;
GnomeCanvasGroup *shape_list_group_root = NULL;
double ICON_GAP = 5.0;
double ICON_HEIGHT = (double)(shapeBox.h / shapeBox.nb_shape_y) - ICON_GAP;
double ICON_WIDTH = (double)(shapeBox.w / shapeBox.nb_shape_x) - ICON_GAP;
if(!shapelist_table)
shapelist_table= g_hash_table_new (g_str_hash, g_str_equal);
/*----------------------------------------------------------------------*/
/* If the first list is full, add the previous/forward buttons */
if(g_hash_table_size(shapelist_table)==(shapeBox.nb_shape_x * shapeBox.nb_shape_y))
{
pixmap = gc_skin_pixmap_load("button_backward.png");
previous_shapelist_item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_list_root_item),
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) shapeBox.x + (shapeBox.w/2) -
gdk_pixbuf_get_width(pixmap) - 2,
"y", (double) shapeBox.y + shapeBox.h,
NULL);
gtk_signal_connect(GTK_OBJECT(previous_shapelist_item), "event",
(GtkSignalFunc) item_event_ok,
"previous_shapelist");
gtk_signal_connect(GTK_OBJECT(previous_shapelist_item), "event",
(GtkSignalFunc) gc_item_focus_event,
NULL);
gdk_pixbuf_unref(pixmap);
pixmap = gc_skin_pixmap_load("button_forward.png");
next_shapelist_item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_list_root_item),
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) shapeBox.x + (shapeBox.w/2) + 2,
"y", (double) shapeBox.y + shapeBox.h,
NULL);
gtk_signal_connect(GTK_OBJECT(next_shapelist_item), "event",
(GtkSignalFunc) item_event_ok,
"next_shapelist");
gtk_signal_connect(GTK_OBJECT(next_shapelist_item), "event",
(GtkSignalFunc) gc_item_focus_event,
NULL);
gdk_pixbuf_unref(pixmap);
gnome_canvas_item_hide(next_shapelist_item);
}
/*----------------------------------------------------------------------*/
/* Do We need to create a new list */
if(g_hash_table_size(shapelist_table)%(shapeBox.nb_shape_x * shapeBox.nb_shape_y)==0)
{
current_shapelistgroup_index++;
g_warning("Creation of the group of shape current_shapelistgroup_index=%d\n",
current_shapelistgroup_index);
// Hide the previous group
if(current_shapelistgroup_index>=1)
{
g_warning(" Hide previous group\n");
shape_list_group_root = GNOME_CANVAS_GROUP(g_list_nth_data(shape_list_group,
current_shapelistgroup_index-1));
//gnome_canvas_item_hide(shape_list_group_root);
item = g_list_nth_data(shape_list_group, current_shapelistgroup_index-1);
gnome_canvas_item_hide(item);
}
// We need to start a new shape list group
shape_list_group_root = \
GNOME_CANVAS_GROUP(gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_list_root_item),
gnome_canvas_group_get_type (),
"x", (double)0,
"y", (double)0,
NULL));
shape_list_group = g_list_append (shape_list_group, shape_list_group_root);
g_warning(" current_shapelistgroup_index=%d\n", current_shapelistgroup_index);
}
else
{
// Get the current shapelist group
g_warning(" get the current_shapelistgroup_index=%d\n", current_shapelistgroup_index);
shape_list_group_root = g_list_nth_data(shape_list_group, current_shapelistgroup_index);
}
/*----------------------------------------------------------------------*/
/* This pixmap is not yet in the list of shapes */
if(g_hash_table_lookup (shapelist_table, shape->pixmapfile)==NULL)
{
double y_offset = 0;
double x_offset = 0;
GdkPixbuf *pixmap = NULL;
y_offset = shapeBox.y + (ICON_HEIGHT/2 +
(g_hash_table_size(shapelist_table) % shapeBox.nb_shape_y) *
ICON_HEIGHT);
x_offset = shapeBox.x + (ICON_WIDTH/2 +
((g_hash_table_size(shapelist_table) %
( shapeBox.nb_shape_x * shapeBox.nb_shape_y)) /
shapeBox.nb_shape_y) *
ICON_WIDTH);
g_warning(" ICON_WIDTH = %f ICON_HEIGHT = %f\n", ICON_WIDTH, ICON_HEIGHT);
g_warning("x_offset = %f y_offset = %f\n", x_offset, y_offset);
/* So this shape is not yet in, let's put it in now */
g_hash_table_insert (shapelist_table, shape->pixmapfile, shape);
if(shape->pixmapfile)
{
pixmap = gc_pixmap_load(shape->pixmapfile);
if(pixmap)
{
double w, h;
Shape *icon_shape;
/* Calc a zoom factor so that the shape will fit in the shapelist
whatever its current size */
w = ICON_WIDTH;
h = gdk_pixbuf_get_height(pixmap) * (w / gdk_pixbuf_get_width(pixmap));
if(h > ICON_HEIGHT)
{
h = ICON_HEIGHT;
w = gdk_pixbuf_get_width(pixmap) * ( h / gdk_pixbuf_get_height(pixmap));
}
if(h < 20 || w < 20 )
{
GdkPixbuf *scale, *hand;
scale = gdk_pixbuf_scale_simple(pixmap, w, h, GDK_INTERP_BILINEAR);
gdk_pixbuf_unref(pixmap);
pixmap = gdk_pixbuf_new( GDK_COLORSPACE_RGB, TRUE, 8,
ICON_WIDTH, ICON_HEIGHT);
gdk_pixbuf_fill(pixmap,0xffffff00);
// add the shape
gdk_pixbuf_copy_area( scale, 0, 0, w, h,
pixmap, (ICON_WIDTH-w )/2, (ICON_HEIGHT-h)/2 );
gdk_pixbuf_unref(scale);
// add the hand
hand = gc_skin_pixmap_load("boardicons/leftright.svg");
h = ICON_HEIGHT/3;
w = gdk_pixbuf_get_width(hand) * h / gdk_pixbuf_get_height(hand);
scale = gdk_pixbuf_scale_simple(hand, w, h, GDK_INTERP_BILINEAR);
gdk_pixbuf_copy_area(scale, 0, 0, w, h,
pixmap, ICON_WIDTH-w,0);
gdk_pixbuf_unref(hand);
gdk_pixbuf_unref(scale);
w=ICON_WIDTH;
h=ICON_HEIGHT;
}
item = gnome_canvas_item_new (shape_list_group_root,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double)x_offset-w/2,
"y", (double)y_offset-h/2,
"width", (double) w,
"height", (double) h,
"width_set", TRUE,
"height_set", TRUE,
NULL);
gdk_pixbuf_unref(pixmap);
icon_shape = create_shape(SHAPE_ICON, shape->name, shape->tooltip,
shape->pixmapfile, shape->points, shape->targetfile,
(double)x_offset -w/2, (double)y_offset -h/2,
(double)w, (double)h,
(double)shape->zoomx, (double)shape->zoomy,
0, shape->soundfile);
icon_shape->item = item;
icon_shape->target_shape = shape;
shape->icon_shape = icon_shape;
icon_shape->shapelistgroup_index = current_shapelistgroup_index;
shape->shapelistgroup_index = current_shapelistgroup_index;
g_warning(" creation shape=%s shape->shapelistgroup_index=%d current_shapelistgroup_index=%d\n",
shape->name,
shape->shapelistgroup_index, current_shapelistgroup_index);
icon_shape->shape_list_group_root = shape_list_group_root;
setup_item(item, icon_shape);
gtk_signal_connect(GTK_OBJECT(item), "event",
(GtkSignalFunc) gc_item_focus_event,
NULL);
}
}
}
}
/*
* Find the closest shape from the given point if it is located at
* a distance under the given square limit.
*/
static Shape *find_closest_shape(double x, double y, double limit)
{
GList *list;
double goodDist = limit;
Shape *candidateShape = NULL;
/* loop through all our shapes */
for(list = shape_list; list != NULL; list = list->next) {
Shape *shape = list->data;
double dist;
if(shape->type==SHAPE_TARGET)
{
/* Calc the distance between this shape and the given coord */
dist = sqrt(pow((shape->x-x+SHAPE_BOX_WIDTH),2) + pow((shape->y-y),2));
if(distnext)
{
Shape * s = list->data;
if(s->type == SHAPE_TARGET || s->type == SHAPE_ICON)
dump_shape(s);
}
}
static void dump_shape(Shape *shape)
{
if(shape->type == SHAPE_TARGET && (shape->placed || shape->shape_place))
{
printf("%s :", shape->name);
if(shape->placed)
printf(" %s -> %s", shape->name, shape->placed->name);
else
printf(" ");
if(shape->shape_place)
printf(" %s -> %s", shape->shape_place->name, shape->name);
printf("\n");
}
}
#endif
/* it puts a shape back to the list of shapes */
static void shape_goes_back_to_list(Shape *shape)
{
if(shape -> type == SHAPE_ICON)
shape = shape -> target_shape;
gnome_canvas_item_hide(shape->item);
/* replace the icon */
gnome_canvas_item_set(shape->icon_shape->item,
"x", shape->icon_shape->x,
"y", shape->icon_shape->y, NULL);
gnome_canvas_item_show(shape->icon_shape->item);
if(shape->placed)
{
shape->placed->shape_place = NULL;
shape->placed = NULL;
}
update_shapelist_item();
gc_sound_play_ogg ("sounds/flip.wav", NULL);
}
static Shape * item_to_shape(GnomeCanvasItem *item)
{
GList *list;
for(list = shape_list; list ; list = list -> next)
{
Shape *s = list -> data;
if( s-> item == item)
return s;
}
g_warning("Can't find the shape for item %p", item);
return NULL;
}
/* switch off all point, and switch on this point
if shape is NULL, switch off all */
static
void target_point_switch_on(Shape *shape_on)
{
GList *list;
Shape *shape;
for(list = shape_list; list ; list = list ->next)
{
shape = list -> data;
if(shape->type == SHAPE_TARGET && ! shape->targetfile)
gnome_canvas_item_set(shape->target_point,
"fill_color_rgba",
shape == shape_on ? POINT_COLOR_ON : POINT_COLOR_OFF,
NULL);
}
}
/* hide all point to let the user look the real image at the end */
static
void target_point_hide()
{
GList *list;
Shape *shape;
for(list = shape_list; list ; list = list ->next)
{
shape = list -> data;
if(shape->type == SHAPE_TARGET && ! shape->targetfile)
gnome_canvas_item_hide(shape->target_point);
}
}
static gint item_event_drag(GnomeCanvasItem *item, GdkEvent *event, gpointer data)
{
static GnomeCanvasItem *shadow_item=NULL;
static GnomeCanvasItem *dragged;
double item_x, item_y;
Shape *shape, *found_shape;
if(board_paused)
return FALSE;
shape = item_to_shape(item);
switch(event->type)
{
case GDK_BUTTON_PRESS:
switch(shape -> type)
{
case SHAPE_ICON:
gc_drag_offset_save(event);
gc_drag_offset_get(&shape->offset_x, &shape->offset_y);
if (shape->soundfile)
{
/* If the soundfile has space ' ' in it, then it is assumed that it is a list
* of sound rather than a single one */
char *p = NULL;
char *soundfile = g_strdup(shape->soundfile);
char *soundfiles = soundfile;
while ((p = strstr (soundfiles, " ")))
{
*p='\0';
gc_sound_play_ogg(soundfiles, NULL);
soundfiles= p + 1;
g_warning("soundfile = %s\n", soundfiles);
}
if (soundfiles != soundfile)
gc_sound_play_ogg(soundfiles, NULL);
else
gc_sound_play_ogg(soundfile, NULL);
g_free(soundfile);
}
else
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
break;
case SHAPE_TARGET:
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
gnome_canvas_item_hide(shape->item);
// unplace this shape
shape->placed->shape_place= NULL;
shape->placed = NULL;
shape = shape -> icon_shape;
gc_drag_offset_set( shape->offset_x, shape->offset_y);
gnome_canvas_item_show(shape->item);
gc_drag_item_set(shape->item);
break;
default:
break;
}
if(shadow_enable)
{
if(shadow_item)
gtk_object_destroy(GTK_OBJECT(shadow_item));
// initialise shadow shape
GdkPixbuf *pixmap, *dest;
g_object_get(shape->target_shape->item, "pixbuf", &pixmap, NULL);
dest = gdk_pixbuf_copy(pixmap);
pixbuf_add_transparent(dest, 100);
shadow_item = gnome_canvas_item_new(GNOME_CANVAS_GROUP(shape_root_item),
gnome_canvas_pixbuf_get_type(),
"pixbuf", dest,
"width", shape->target_shape->w,
"height", shape->target_shape->h,
"width_set", TRUE,
"height_set", TRUE,
NULL);
gnome_canvas_item_hide(shadow_item);
gdk_pixbuf_unref(dest);
gdk_pixbuf_unref(pixmap);
}
dragged = shape->item;
gnome_canvas_item_reparent(shape->item, GNOME_CANVAS_GROUP(shape_list_root_item->parent));
gnome_canvas_item_raise_to_top(shape->item);
gc_drag_item_move(event);
break;
case GDK_MOTION_NOTIFY:
if (item != dragged)
break;
gc_drag_item_move(event);
item_x = event->button.x;
item_y = event->button.y;
gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
found_shape = find_closest_shape( item_x, item_y, SQUARE_LIMIT_DISTANCE);
if(shadow_enable)
{
if(found_shape)
{
gnome_canvas_item_set(shadow_item,
"x", found_shape->x - shape->target_shape->w/2,
"y", found_shape->y - shape->target_shape->h/2,
NULL);
gnome_canvas_item_show(shadow_item);
}
else
gnome_canvas_item_hide(shadow_item);
}
target_point_switch_on(found_shape);
break;
case GDK_BUTTON_RELEASE:
if (item != dragged)
break;
item_x = event->button.x;
item_y = event->button.y;
gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
if(shadow_enable && shadow_item)
{
gtk_object_destroy(GTK_OBJECT(shadow_item));
shadow_item = NULL;
}
target_point_switch_on(NULL);
gnome_canvas_item_reparent(shape->item, shape->shape_list_group_root);
found_shape = find_closest_shape( item_x, item_y, SQUARE_LIMIT_DISTANCE);
if(found_shape)
{
if(found_shape->shape_place)
shape_goes_back_to_list(found_shape->shape_place);
gc_sound_play_ogg ("sounds/line_end.wav", NULL);
/* place the target item */
gnome_canvas_item_set(shape->target_shape->item,
"x", found_shape->x - shape->target_shape->w/2,
"y", found_shape->y - shape->target_shape->h/2,
NULL);
gnome_canvas_item_show(shape->target_shape->item);
gnome_canvas_item_raise_to_top(shape->target_shape->item);
gnome_canvas_item_hide(shape->item);
shape -> target_shape -> placed = found_shape;
found_shape -> shape_place = shape -> target_shape;
auto_process();
update_shapelist_item();
}
else
{
shape_goes_back_to_list(shape);
}
break;
default:
break;
}
return FALSE;
}
static gint
item_event(GnomeCanvasItem *item, GdkEvent *event, Shape *shape)
{
if(!gcomprisBoard)
return FALSE;
if(board_paused)
return FALSE;
if(shape==NULL) {
g_warning("Shape is NULL : Should not happen");
return FALSE;
}
switch (event->type)
{
case GDK_ENTER_NOTIFY:
if(shape->tooltip && shape->type == SHAPE_ICON) {
/* WARNING: This should not be needed but if I don't do it, it's not refreshed */
gnome_canvas_item_set(GNOME_CANVAS_ITEM(tooltip_bg_item),
"y", 0.0,
NULL);
gnome_canvas_item_set(GNOME_CANVAS_ITEM(tooltip_text_item),
"text", gettext(shape->tooltip),
NULL);
gnome_canvas_item_show(GNOME_CANVAS_ITEM(tooltip_root_item));
}
break;
case GDK_LEAVE_NOTIFY:
if(shape->tooltip && shape->type == SHAPE_ICON)
gnome_canvas_item_hide(GNOME_CANVAS_ITEM(tooltip_root_item));
break;
case GDK_BUTTON_PRESS:
if(event->button.button == 3)
shape_goes_back_to_list(shape);
default:
break;
}
return FALSE;
}
static int get_element_count_listgroup(int listgroup_index)
{
int count=0, i;
Shape *sh;
for (i=0;ishapelistgroup_index == listgroup_index &&
sh->type == SHAPE_TARGET && ! sh->placed)
count ++;
}
return count;
}
static int get_no_void_group(int direction)
{
int index = current_shapelistgroup_index;
direction = direction>0 ? 1 : -1;
index += direction;
while(0 <= index && index < g_list_length(shape_list_group))
{
if(get_element_count_listgroup(index))
return index;
index += direction;
}
return current_shapelistgroup_index;
}
static void auto_process(void)
{
GList *list;
gboolean done = TRUE;
/* Loop through all the shapes to find if all target are in place */
for(list = shape_list; list != NULL; list = list->next) {
Shape *shape = list->data;
if(shape->type==SHAPE_TARGET)
{
if(shape->placed==NULL)
done=FALSE;
}
}
if(done)
process_ok();
}
static void update_shapelist_item(void)
{
if(! next_shapelist_item || !previous_shapelist_item)
return;
if(get_element_count_listgroup(current_shapelistgroup_index) ==0)
{
int index;
GnomeCanvasItem *root_item;
index = get_no_void_group(-1);
if(index == current_shapelistgroup_index)
index = get_no_void_group(1);
if(index != current_shapelistgroup_index)
{
root_item = g_list_nth_data(shape_list_group, current_shapelistgroup_index);
gnome_canvas_item_hide(root_item);
root_item = g_list_nth_data(shape_list_group, index);
gnome_canvas_item_show(root_item);
current_shapelistgroup_index = index;
}
}
if(get_no_void_group(1) == current_shapelistgroup_index)
gnome_canvas_item_hide(next_shapelist_item);
else
gnome_canvas_item_show(next_shapelist_item);
if(get_no_void_group(-1) == current_shapelistgroup_index)
gnome_canvas_item_hide(previous_shapelist_item);
else
gnome_canvas_item_show(previous_shapelist_item);
#if DEBUG
dump_shapes();
#endif
}
/* Callback for the operations */
static gint
item_event_ok(GnomeCanvasItem *item, GdkEvent *event, gpointer data)
{
GnomeCanvasItem *root_item;
if(board_paused)
return FALSE;
switch (event->type)
{
case GDK_BUTTON_PRESS:
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
root_item = g_list_nth_data(shape_list_group, current_shapelistgroup_index);
gnome_canvas_item_hide(root_item);
g_warning(" item event current_shapelistgroup_index=%d\n", current_shapelistgroup_index);
if(!strcmp((char *)data, "previous_shapelist"))
{
current_shapelistgroup_index = get_no_void_group(-1);
update_shapelist_item();
}
else if(!strcmp((char *)data, "next_shapelist"))
{
current_shapelistgroup_index = get_no_void_group(1);
update_shapelist_item();
}
root_item = g_list_nth_data(shape_list_group, current_shapelistgroup_index);
gnome_canvas_item_show(root_item);
/* FIXME : Workaround for bugged canvas */
// gnome_canvas_update_now(gcomprisBoard->canvas);
default:
break;
}
return FALSE;
}
static void
setup_item(GnomeCanvasItem *item, Shape *shape)
{
gtk_signal_connect(GTK_OBJECT(item), "event",
(GtkSignalFunc) item_event,
shape);
gtk_signal_connect(GTK_OBJECT(item), "event",
(GtkSignalFunc) gc_drag_event, NULL);
}
/*
* Thanks for George Lebl for his Genealogy example
* for all the XML stuff there
*/
/* Adds a shape to the canvas */
static void
add_shape_to_canvas(Shape *shape)
{
GdkPixbuf *pixmap;
GdkPixbuf *targetpixmap;
GnomeCanvasItem *item = NULL;
/* checking of preconditions, this is usefull for tracking down bugs,
but you should not count on these always being compiled in */
g_return_if_fail(shape != NULL);
if(shape->type==SHAPE_TARGET)
{
if(shape->targetfile)
{
targetpixmap = gc_pixmap_load(shape->targetfile);
shape->w = (double)gdk_pixbuf_get_width(targetpixmap) * shape->zoomx;
shape->h = (double)gdk_pixbuf_get_height(targetpixmap) *shape->zoomy;
item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_root_item),
gnome_canvas_pixbuf_get_type (),
"pixbuf", targetpixmap,
"x", shape->x - shape->w / 2,
"y", shape->y - shape->h / 2,
"width", shape->w,
"height", shape->h,
"width_set", TRUE,
"height_set", TRUE,
NULL);
shape->targetitem = item;
gdk_pixbuf_unref(targetpixmap);
}
else
{
int point_size = 6;
/* Display a point to highlight the target location of this shape */
item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_root_item),
gnome_canvas_ellipse_get_type(),
"x1", (double)shape->x-point_size,
"y1", (double)shape->y-point_size,
"x2", (double)shape->x+point_size,
"y2", (double)shape->y+point_size,
"fill_color_rgba", POINT_COLOR_OFF,
"outline_color", "black",
"width_pixels", 2,
NULL);
shape->target_point = item;
}
gnome_canvas_item_lower_to_bottom(item);
}
if(shape->points!=NULL)
{
g_warning("it's a point \n");
item = gnome_canvas_item_new(GNOME_CANVAS_GROUP(shape_root_item),
gnome_canvas_polygon_get_type (),
"points", shape->points,
"fill_color", "grey",
"outline_color", "black",
"width_units", 1.0,
NULL);
}
else
{
g_warning("it's an image ? shape->pixmapfile=%s\n", shape->pixmapfile);
if(shape->pixmapfile)
{
g_warning(" Yes it is an image \n");
pixmap = gc_pixmap_load(shape->pixmapfile);
if(pixmap)
{
shape->w = (double)gdk_pixbuf_get_width(pixmap) * shape->zoomx;
shape->h = (double)gdk_pixbuf_get_height(pixmap) * shape->zoomy;
/* Display the shape itself but hide it until the user puts the right shape on it */
/* I have to do it this way for the positionning (lower/raise) complexity */
item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_root_item),
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", shape->x - shape->w / 2,
"y", shape->y - shape->h / 2,
"width", shape->w,
"height", shape->h,
"width_set", TRUE,
"height_set", TRUE,
NULL);
gdk_pixbuf_unref(pixmap);
}
}
}
/* Associate this item to this shape */
shape->item = item;
if(shape->type==SHAPE_TARGET || shape->type==SHAPE_DUMMY_TARGET)
{
setup_item(item, shape);
gnome_canvas_item_hide(item);
add_shape_to_list_of_shapes(shape);
}
else if(shape->type==SHAPE_BACKGROUND)
{
gnome_canvas_item_lower_to_bottom(item);
}
}
static void create_title(char *name, double x, double y, GtkJustification justification,
guint32 color_rgba)
{
GnomeCanvasItem *item;
/* Shadow */
item = \
gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_root_item),
gnome_canvas_text_get_type (),
"text", gettext(name),
"font", gc_skin_font_board_medium,
"x", x + 1.0,
"y", y + 1.0,
"anchor", GTK_ANCHOR_CENTER,
"justification", justification,
"fill_color_rgba", gc_skin_color_shadow,
NULL);
gnome_canvas_item_raise_to_top(item);
item = \
gnome_canvas_item_new (GNOME_CANVAS_GROUP(shape_root_item),
gnome_canvas_text_get_type (),
"text", gettext(name),
"font", gc_skin_font_board_medium,
"x", x,
"y", y,
"anchor", GTK_ANCHOR_CENTER,
"justification", justification,
"fill_color_rgba", color_rgba,
NULL);
gnome_canvas_item_raise_to_top(item);
}
static Shape *
create_shape(ShapeType type, char *name, char *tooltip, char *pixmapfile, GnomeCanvasPoints* points,
char *targetfile, double x, double y,
double w, double h, double zoomx,
double zoomy, guint position, char *soundfile)
{
Shape *shape;
/* allocate a new shape */
shape = g_new0(Shape,1);
shape->name = g_strdup(name);
if(tooltip)
shape->tooltip = g_strdup(tooltip);
else
shape->tooltip = NULL;
shape->pixmapfile = g_strdup(pixmapfile);
shape->points = points;
shape->targetfile = g_strdup(targetfile);
shape->x = x;
shape->y = y;
shape->w = w;
shape->h = h;
shape->zoomx = zoomx;
shape->zoomy = zoomy;
shape->position = position;
shape->type = type;
shape->soundfile = g_strdup(soundfile);
/* add the shape to the list */
shape_list = g_list_append(shape_list, shape);
return shape;
}
/** return a double value from an nodePtr
*
* \param node
* \param prop
* \param def_value : default value
*
* \return a double value found in the 'prop' property of the 'node' or
* the default value if not found
*/
static double
xmlGetProp_Double(xmlNodePtr node, xmlChar *prop, double def_value)
{
double value;
char *str;
str = (char *)xmlGetProp(node, prop);
if(str)
{
value = g_ascii_strtod(str, NULL);
free(str);
}
else
value = def_value;
return value;
}
static void
add_xml_shape_to_data(xmlDocPtr doc, xmlNodePtr xmlnode, GNode * child, GList **list)
{
char *name, *cd ,*ctype, *justification;
char *tooltip;
GtkJustification justification_gtk;
char *pixmapfile = NULL;
char *targetfile = NULL;
char *soundfile = NULL;
double x, y, zoomx, zoomy;
GnomeCanvasPoints* points = NULL;
gchar **d;
gint i, j;
guint position;
ShapeType type = SHAPE_TARGET;
Shape *shape;
xmlNodePtr xmlnamenode;
char *locale;
char *color_text;
guint color_rgba;
if(/* if the node has no name */
!xmlnode->name ||
/* or if the name is not "Shape" */
((g_strcasecmp((const char *)xmlnode->name,"Shape")!=0) &&
/* or if the name is not "Title" */
(g_strcasecmp((const char *)xmlnode->name,"Title")!=0) &&
/* or if the name is not "Option" */
(g_strcasecmp((const char *)xmlnode->name,"Option")!=0) )
)
return;
pixmapfile = (char *)xmlGetProp(xmlnode, BAD_CAST "pixmapfile");
if(pixmapfile) {
/* If the pixmapfile starts with skin: then get the skin relative image instead */
if(!strncmp(pixmapfile, "skin:", 5)) {
gchar *oldpixmapfile = pixmapfile;
pixmapfile = gc_skin_image_get(oldpixmapfile+5);
g_free(oldpixmapfile);
}
}
targetfile = (char *)xmlGetProp(xmlnode, BAD_CAST "targetfile");
soundfile = (char *)xmlGetProp(xmlnode, BAD_CAST "sound");
/*********************************/
/* get the points for a polygone */
/* The list of points is similar to the one define in the SVG standard */
/* FIXME : The implementation is incomplete, a point still needs to be added
to shapelist and add management for it's x/y coordinates */
cd = (char *)xmlGetProp(xmlnode, BAD_CAST "points");
if(cd)
{
d = g_strsplit(cd, " ", 64);
xmlFree(cd);
j=0;
while(d[j]!=NULL)
{
j++;
}
points = gnome_canvas_points_new(j/2);
for(i=0; icoords[i] = g_ascii_strtod(d[i], NULL);
}
g_strfreev(d);
}
/* get the X coord of the shape */
x = xmlGetProp_Double(xmlnode, BAD_CAST "x", 100);
/* get the Y coord of the shape */
y = xmlGetProp_Double(xmlnode, BAD_CAST "y", 100);
/* Back up the current locale to be sure to load well C formated numbers */
locale = g_strdup(gc_locale_get());
gc_locale_set("C");
/* get the ZOOMX coord of the shape */
zoomx = xmlGetProp_Double(xmlnode, BAD_CAST "zoomx", 1);
/* get the ZOOMY coord of the shape */
zoomy = xmlGetProp_Double(xmlnode, BAD_CAST "zoomy", 1);
/* get the POSITION of the shape */
/* Position in the xml means:
* 0 = BOTTOM
* 1 or more = TOP
*/
position = (guint) xmlGetProp_Double(xmlnode, BAD_CAST "position", 0);
/* Back to the user locale */
gc_locale_set(locale);
g_free(locale);
/* get the TYPE of the shape */
ctype = (char *)xmlGetProp(xmlnode, BAD_CAST "type");
if(ctype) {
if(g_strcasecmp(ctype,"SHAPE_TARGET")==0)
type = SHAPE_TARGET;
else if(g_strcasecmp(ctype,"SHAPE_DUMMY_TARGET")==0)
type = SHAPE_DUMMY_TARGET;
else if (g_strcasecmp(ctype,"SHAPE_BACKGROUND")==0)
type = SHAPE_BACKGROUND;
xmlFree(ctype);
}
else
type = SHAPE_TARGET;
/* get the JUSTIFICATION of the Title */
justification_gtk = GTK_JUSTIFY_CENTER; /* GTK_JUSTIFICATION_CENTER is default */
justification = (char *)xmlGetProp(xmlnode, BAD_CAST "justification");
if(justification) {
if (strcmp(justification, "GTK_JUSTIFY_LEFT") == 0) {
justification_gtk = GTK_JUSTIFY_LEFT;
} else if (strcmp(justification, "GTK_JUSTIFY_RIGHT") == 0) {
justification_gtk = GTK_JUSTIFY_RIGHT;
} else if (strcmp(justification, "GTK_JUSTIFY_CENTER") == 0) {
justification_gtk = GTK_JUSTIFY_CENTER;
} else if (strcmp(justification, "GTK_JUSTIFY_FILL") == 0) {
justification_gtk = GTK_JUSTIFY_FILL;
}
xmlFree(justification);
}
/* get the COLOR of the Title Specified by skin reference */
color_text = (char *)xmlGetProp(xmlnode, BAD_CAST "color_skin");
if(color_text) {
color_rgba = gc_skin_get_color(color_text);
xmlFree(color_text);
} else {
color_rgba = gc_skin_get_color("gcompris/content"); /* the default */
}
/* get the name and tooltip of the shape */
name = NULL;
tooltip = NULL;
xmlnamenode = xmlnode->xmlChildrenNode;
while (xmlnamenode != NULL) {
gchar *lang = (char *)xmlGetProp(xmlnamenode, BAD_CAST "lang");
/* get the name of the shape */
if (!strcmp((char *)xmlnamenode->name, "name")
&& (lang==NULL
|| !strcmp(lang, gc_locale_get())
|| !strncmp(lang, gc_locale_get(), 2)))
{
if (name)
xmlFree(name);
name = (char *)xmlNodeListGetString(doc, xmlnamenode->xmlChildrenNode, 1);
}
/* get the tooltip of the shape */
if (!strcmp((char *)xmlnamenode->name, "tooltip")
&& (lang==NULL
|| !strcmp(lang, gc_locale_get())
|| !strncmp(lang, gc_locale_get(), 2)))
{
if (tooltip)
xmlFree(tooltip);
tooltip = (char *)xmlNodeListGetString(doc, xmlnamenode->xmlChildrenNode, 1);
}
xmlFree(lang);
xmlnamenode = xmlnamenode->next;
}
/* If name is not given as an element, try to get it as a property */
if(!name)
name = (char *)xmlGetProp(xmlnode, BAD_CAST "name");
if(g_strcasecmp((char *)xmlnode->name, "Shape")==0)
{
/* add the shape to the database */
/* WARNING : I do not initialize the width and height since I don't need them */
shape = create_shape(type, name, tooltip, pixmapfile , points,
targetfile, x, y,
(double)0, (double)0,
zoomx, zoomy, position,
soundfile);
/* add the shape to the list */
*list = g_list_append(*list, shape);
}
else if (g_strcasecmp((char *)xmlnode->name, "Title")==0)
{
/* Readd \n is needed */
gchar *newname;
if(name != NULL) {
newname = g_strcompress(name);
create_title(newname, x, y, justification_gtk, color_rgba);
g_free(newname);
}
}
g_free(pixmapfile);
g_free(soundfile);
g_free(name);
g_free(targetfile);
g_free(tooltip);
}
/* parse the doc, add it to our internal structures and to the clist */
static void
parse_doc(xmlDocPtr doc)
{
GList *shape_list_init = NULL;
xmlNodePtr node;
GList *list;
GnomeCanvasItem *item;
int list_length, i;
/* find nodes and add them to the list, this just
loops through all the children of the root of the document */
for(node = doc->children->children; node != NULL; node = node->next) {
/* add the shape to the list, there are no children so
we pass NULL as the node of the child */
add_xml_shape_to_data(doc, node, NULL, &shape_list_init);
}
shape_list = g_list_copy(shape_list_init);
/* Insert each of the shapes randomly */
while((list_length = g_list_length(shape_list_init)))
{
Shape *shape;
i = g_random_int_range(0, list_length);
shape = g_list_nth_data(shape_list_init, i);
add_shape_to_canvas(shape);
shape_list_init = g_list_remove (shape_list_init, shape);
}
g_list_free(shape_list_init);
shape_list_init = NULL;
if(current_shapelistgroup_index>0) { /* If at least on shape group */
item = g_list_nth_data(shape_list_group, current_shapelistgroup_index);
gnome_canvas_item_hide(item);
item = g_list_nth_data(shape_list_group, 0);
gnome_canvas_item_show(item);
gnome_canvas_item_hide(previous_shapelist_item);
gnome_canvas_item_show(next_shapelist_item);
current_shapelistgroup_index = 0;
}
/* Loop through all the shapes and */
/* Arrange the order (depth) of the shapes on the canvas */
/* Depending on the xml given definition in the position property */
for(list = shape_list; list != NULL; list = list->next) {
Shape *shape = list->data;
gnome_canvas_item_lower_to_bottom(shape->item);
if(shape->position>=1)
gnome_canvas_item_raise(shape->item, ABS(shape->position));
}
}
/* read an xml file into our memory structures and update our view,
dump any old data we have in memory if we can load a new set */
static gboolean
read_xml_file(char *fname)
{
/* pointer to the new doc */
xmlDocPtr doc;
g_return_val_if_fail(fname!=NULL,FALSE);
/* parse the new file and put the result into newdoc */
doc = xmlParseFile(fname);
/* in case something went wrong */
if(!doc)
return FALSE;
if(/* if there is no root element */
!doc->children ||
/* if it doesn't have a name */
!doc->children->name ||
/* if it isn't a ShapeGame node */
g_strcasecmp((char *)doc->children->name, "ShapeGame")!=0) {
xmlFreeDoc(doc);
return FALSE;
}
/*--------------------------------------------------*/
/* Read ShapeBox property */
shapeBox.x = xmlGetProp_Double(doc->children, BAD_CAST "shapebox_x", 15);
g_warning("shapeBox.x=%f\n", shapeBox.x);
shapeBox.y = xmlGetProp_Double(doc->children, BAD_CAST "shapebox_y", 25);
g_warning("shapeBox.y=%f\n", shapeBox.y);
shapeBox.w = xmlGetProp_Double(doc->children, BAD_CAST "shapebox_w", 80);
g_warning("shapeBox.w=%f\n", shapeBox.w);
shapeBox.h = xmlGetProp_Double(doc->children, BAD_CAST "shapebox_h", 430);
g_warning("shapeBox.h=%f\n", shapeBox.h);
shapeBox.nb_shape_x = xmlGetProp_Double(doc->children, BAD_CAST "shapebox_nb_shape_x", 1);
g_warning("shapeBox.nb_shape_x=%d\n", shapeBox.nb_shape_x);
shapeBox.nb_shape_y = xmlGetProp_Double(doc->children, BAD_CAST "shapebox_nb_shape_y", 5);
g_warning("shapeBox.nb_shape_y=%d\n", shapeBox.nb_shape_y);
/* Read shadow enable property */
shadow_enable = xmlGetProp_Double(doc->children, BAD_CAST "shadow_enable", 1);
/* parse our document and replace old data */
parse_doc(doc);
xmlFreeDoc(doc);
return TRUE;
}
/* ************************************* */
/* * Configuration * */
/* ************************************* */
/* ======================= */
/* = config_start = */
/* ======================= */
static GcomprisProfile *profile_conf;
static GcomprisBoard *board_conf;
static void save_table (gpointer key,
gpointer value,
gpointer user_data)
{
gc_db_set_board_conf ( profile_conf,
board_conf,
(gchar *) key,
(gchar *) value);
}
static void conf_ok(GHashTable *table)
{
if (!table){
if (gcomprisBoard)
pause_board(FALSE);
return;
}
g_hash_table_foreach(table, (GHFunc) save_table, NULL);
if (gcomprisBoard){
GHashTable *config;
if (profile_conf)
config = gc_db_get_board_conf();
else
config = table;
if (strcmp(gcomprisBoard->name, "imagename")==0){
gc_locale_reset();
gc_locale_set(g_hash_table_lookup( config, "locale"));
}
gchar *drag_mode_str = g_hash_table_lookup( config, "drag_mode");
if (drag_mode_str && (strcmp (drag_mode_str, "NULL") != 0))
drag_mode = (gint ) g_ascii_strtod(drag_mode_str, NULL);
else
drag_mode = 0;
if (profile_conf)
g_hash_table_destroy(config);
gc_drag_change_mode( drag_mode);
shapegame_next_level();
pause_board(FALSE);
}
board_conf = NULL;
profile_conf = NULL;
}
static void
config_start(GcomprisBoard *agcomprisBoard,
GcomprisProfile *aProfile)
{
board_conf = agcomprisBoard;
profile_conf = aProfile;
if (gcomprisBoard)
pause_board(TRUE);
gchar * label = g_strdup_printf(_("%s configuration\n for profile %s"),
agcomprisBoard->name,
aProfile? aProfile->name : "");
GcomprisBoardConf *bconf;
bconf = gc_board_config_window_display( label,
(GcomprisConfCallback )conf_ok);
g_free(label);
/* init the combo to previously saved value */
GHashTable *config = gc_db_get_conf( profile_conf, board_conf);
if (strcmp(agcomprisBoard->name, "imagename")==0){
gchar *locale = g_hash_table_lookup( config, "locale");
gc_board_config_combo_locales( bconf, locale);
}
gchar *drag_mode_str = g_hash_table_lookup( config, "drag_mode");
gint drag_previous;
if (drag_mode_str && (strcmp (drag_mode_str, "NULL") != 0))
drag_previous = (gint ) g_ascii_strtod(drag_mode_str, NULL);
else
drag_previous = 0;
gc_board_config_combo_drag(bconf, drag_mode);
}
/* ======================= */
/* = config_stop = */
/* ======================= */
static void
config_stop()
{
}