Back to index

gcompris  8.2.2
enumerate.c
Go to the documentation of this file.
00001 /* gcompris - enumerate.c
00002  *
00003  * Copyright (C) 2001 Bruno Coudoin
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU General Public License as published by
00007  *   the Free Software Foundation; either version 2 of the License, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details.
00014  *
00015  *   You should have received a copy of the GNU General Public License
00016  *   along with this program; if not, write to the Free Software
00017  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #include <string.h>
00021 
00022 #include "gcompris/gcompris.h"
00023 
00024 #define SOUNDLISTFILE PACKAGE
00025 
00026 static GcomprisBoard *gcomprisBoard = NULL;
00027 static gboolean board_paused = TRUE;
00028 
00029 static void    start_board (GcomprisBoard *agcomprisBoard);
00030 static gint    key_press(guint keyval, gchar *commit_str, gchar *preedit_str);
00031 static void    pause_board (gboolean pause);
00032 static void    end_board (void);
00033 static void    process_ok(void);
00034 static gboolean       is_our_board (GcomprisBoard *gcomprisBoard);
00035 static void    set_level (guint level);
00036 static int     gamewon;
00037 static void    game_won(void);
00038 
00039 static GnomeCanvasGroup *boardRootItem = NULL;
00040 
00041 static GnomeCanvasItem      *enumerate_create_item(GnomeCanvasGroup *parent);
00042 static void           enumerate_destroy_all_items(void);
00043 static void           enumerate_next_level(void);
00044 static gint           item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00045 static gint           item_event_focus(GnomeCanvasItem *item, GdkEvent *event, guint index);
00046 
00047 #define ANSWER_X     BOARDWIDTH - 150
00048 #define ANSWER_WIDTH 40
00049 #define ANSWER_HEIGHT       40
00050 
00051 static int number_of_item_type     = 0;
00052 static int number_of_item_max      = 0;
00053 
00054 // List of images to use in the game
00055 static gchar *imageList[] =
00056 {
00057   "gcompris/food/banana.png",
00058   "gcompris/food/orange.png",
00059   "gcompris/food/milk_shake.png",
00060   "gcompris/food/pear.png",
00061   "gcompris/food/grapefruit.png",
00062   "gcompris/food/yahourt.png",
00063   "gcompris/food/milk_cup.png",
00064   "gcompris/food/suggar_box.png",
00065   "gcompris/food/butter.png",
00066   "gcompris/food/chocolate.png",
00067   "gcompris/food/cookie.png",
00068   "gcompris/food/french_croissant.png",
00069   "gcompris/food/chocolate_cake.png",
00070   "gcompris/food/marmelade.png",
00071   "gcompris/food/baby_bottle.png",
00072   "gcompris/food/bread_slice.png",
00073   "gcompris/food/round_cookie.png",
00074 };
00075 #define NUMBER_OF_IMAGES G_N_ELEMENTS(imageList)
00076 
00077 static guint          answer[NUMBER_OF_IMAGES];
00078 static guint          answer_to_find[NUMBER_OF_IMAGES];
00079 static GnomeCanvasItem      *answer_item[NUMBER_OF_IMAGES];
00080 static GnomeCanvasItem      *answer_item_focus[NUMBER_OF_IMAGES];
00081 static guint           current_focus      = 0;
00082 
00083 
00084 /* Description of this plugin */
00085 static BoardPlugin menu_bp =
00086   {
00087     NULL,
00088     NULL,
00089     N_("Numeration training"),
00090     N_("Place the items in the best way to count them"),
00091     "Bruno Coudoin <bruno.coudoin@free.fr>",
00092     NULL,
00093     NULL,
00094     NULL,
00095     NULL,
00096     start_board,
00097     pause_board,
00098     end_board,
00099     is_our_board,
00100     key_press,
00101     process_ok,
00102     set_level,
00103     NULL,
00104     NULL,
00105     NULL,
00106     NULL
00107   };
00108 
00109 /*
00110  * Main entry point mandatory for each Gcompris's game
00111  * ---------------------------------------------------
00112  *
00113  */
00114 
00115 GET_BPLUGIN_INFO(enumerate)
00116 
00117 /*
00118  * in : boolean TRUE = PAUSE : FALSE = CONTINUE
00119  *
00120  */
00121 static void pause_board (gboolean pause)
00122 {
00123   if(gcomprisBoard==NULL)
00124     return;
00125 
00126   if(gamewon == TRUE && pause == FALSE) /* the game is won */
00127     {
00128       game_won();
00129     }
00130 
00131   board_paused = pause;
00132 }
00133 
00134 /*
00135  */
00136 static void start_board (GcomprisBoard *agcomprisBoard)
00137 {
00138 
00139   if(agcomprisBoard!=NULL)
00140     {
00141       gcomprisBoard=agcomprisBoard;
00142 
00143       /* disable im_context */
00144       gcomprisBoard->disable_im_context = TRUE;
00145 
00146       gcomprisBoard->level=1;
00147       gcomprisBoard->maxlevel=9;
00148       gcomprisBoard->sublevel=1;
00149       gcomprisBoard->number_of_sublevel=1; /* Go to next level after this number of 'play' */
00150       gc_bar_set(GC_BAR_LEVEL|GC_BAR_OK);
00151 
00152       gc_set_background(gnome_canvas_root(gcomprisBoard->canvas),
00153                            "images/enumerate_background.png");
00154 
00155       enumerate_next_level();
00156 
00157       gamewon = FALSE;
00158       pause_board(FALSE);
00159     }
00160 }
00161 /* ======================================= */
00162 static void end_board ()
00163 {
00164   if(gcomprisBoard!=NULL)
00165     {
00166       pause_board(TRUE);
00167       enumerate_destroy_all_items();
00168     }
00169   gcomprisBoard = NULL;
00170 }
00171 
00172 /* Get the user keys to use to get the answer */
00173 static gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str)
00174 {
00175   char str[2];
00176   GnomeCanvasItem    *item = NULL;
00177 
00178   if(!gcomprisBoard)
00179     return FALSE;
00180 
00181   /* Add some filter for control and shift key */
00182   switch (keyval)
00183     {
00184     case GDK_Shift_L:
00185     case GDK_Shift_R:
00186     case GDK_Control_L:
00187     case GDK_Control_R:
00188     case GDK_Caps_Lock:
00189     case GDK_Shift_Lock:
00190     case GDK_Meta_L:
00191     case GDK_Meta_R:
00192     case GDK_Alt_L:
00193     case GDK_Alt_R:
00194     case GDK_Super_L:
00195     case GDK_Super_R:
00196     case GDK_Hyper_L:
00197     case GDK_Hyper_R:
00198     case GDK_Mode_switch:
00199     case GDK_dead_circumflex:
00200     case GDK_Num_Lock:
00201       return FALSE;
00202     case GDK_KP_Enter:
00203     case GDK_Return:
00204       process_ok();
00205       return TRUE;
00206     }
00207 
00208   sprintf(str, "%c", keyval);
00209 
00210   item = answer_item[current_focus];
00211 
00212   if(GNOME_IS_CANVAS_TEXT(item))
00213     {
00214       gchar *oldtext;
00215       gchar *newtext;
00216 
00217       gtk_object_get (GTK_OBJECT (item), "text", &oldtext, NULL);
00218 
00219       switch(keyval)
00220        {
00221        case GDK_BackSpace:
00222        case GDK_Delete:
00223 
00224          if(oldtext[1] != '\0')
00225            newtext = g_strndup(oldtext, strlen(oldtext)-1);
00226          else
00227            newtext = "?";
00228 
00229          break;
00230 
00231        default:
00232 
00233          if(keyval<'0' || keyval>'9')
00234            str[0]='0';
00235 
00236          if(oldtext[0] == '?' && strlen(oldtext)==1)
00237            {
00238              oldtext[0] = ' ';
00239              g_strstrip(oldtext);
00240            }
00241 
00242          if(strlen(oldtext)<2)
00243            newtext = g_strconcat(oldtext, &str, NULL);
00244          else
00245            newtext = g_strdup(oldtext);
00246          break;
00247 
00248        }
00249 
00250       if(newtext[0] != '?')
00251        answer[current_focus] = atoi(newtext);
00252 
00253       gnome_canvas_item_set (item,
00254                           "text", newtext,
00255                           NULL);
00256 
00257       g_free(oldtext);
00258     }
00259 
00260   return TRUE;
00261 }
00262 
00263 /* ======================================= */
00264 static void set_level (guint level)
00265 {
00266 
00267   if(gcomprisBoard!=NULL)
00268     {
00269       gcomprisBoard->level=level;
00270       gcomprisBoard->sublevel=1;
00271       enumerate_next_level();
00272     }
00273 }
00274 /* ======================================= */
00275 static gboolean is_our_board (GcomprisBoard *gcomprisBoard)
00276 {
00277   if (gcomprisBoard)
00278     {
00279       if(g_strcasecmp(gcomprisBoard->type, "enumerate")==0)
00280        {
00281          /* Set the plugin entry */
00282          gcomprisBoard->plugin=&menu_bp;
00283 
00284          return TRUE;
00285        }
00286     }
00287   return FALSE;
00288 }
00289 
00290 /*-------------------------------------------------------------------------------*/
00291 /*-------------------------------------------------------------------------------*/
00292 /* set initial values for the next level */
00293 static void enumerate_next_level()
00294 {
00295 
00296   gc_bar_set_level(gcomprisBoard);
00297 
00298   enumerate_destroy_all_items();
00299   gamewon = FALSE;
00300 
00301   /* Select level difficulty */
00302   switch(gcomprisBoard->level)
00303     {
00304     case 1:
00305       number_of_item_type = 1;
00306       number_of_item_max  = 5;
00307       break;
00308     case 2:
00309       number_of_item_type = 2;
00310       number_of_item_max  = 5;
00311       break;
00312     case 3:
00313       number_of_item_type = 3;
00314       number_of_item_max  = 5;
00315       break;
00316     case 4:
00317       number_of_item_type = 3;
00318       number_of_item_max  = 5;
00319       break;
00320     case 5:
00321       number_of_item_type = 4;
00322       number_of_item_max  = 5;
00323       break;
00324     case 6:
00325       number_of_item_type = 4;
00326       number_of_item_max  = 6;
00327       break;
00328     case 7:
00329       number_of_item_type = 4;
00330       number_of_item_max  = 7;
00331       break;
00332     case 8:
00333       number_of_item_type = 4;
00334       number_of_item_max  = 10;
00335       break;
00336     default:
00337       number_of_item_type = 5;
00338       number_of_item_max = 10;
00339     }
00340 
00341   current_focus = 0;
00342 
00343   /* Try the next level */
00344   enumerate_create_item(gnome_canvas_root(gcomprisBoard->canvas));
00345 
00346 }
00347 /* ==================================== */
00348 /* Destroy all the items */
00349 static void enumerate_destroy_all_items()
00350 {
00351   if(boardRootItem!=NULL)
00352     gtk_object_destroy (GTK_OBJECT(boardRootItem));
00353 
00354   boardRootItem = NULL;
00355 }
00356 /* ==================================== */
00357 static GnomeCanvasItem *enumerate_create_item(GnomeCanvasGroup *parent)
00358 {
00359   int i,j;
00360   int current_y;
00361   GnomeCanvasItem *item = NULL;
00362   GdkPixbuf *pixmap = NULL;
00363   GdkPixbuf *pixmap_answer = NULL;
00364 
00365   boardRootItem = GNOME_CANVAS_GROUP(
00366                                  gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
00367                                                      gnome_canvas_group_get_type (),
00368                                                      "x", (double) 0,
00369                                                      "y", (double) 0,
00370 
00371                                                      NULL));
00372 
00373   current_y = BOARDHEIGHT;
00374 
00375   for(i=0; i<number_of_item_type; i++)
00376     {
00377 
00378       pixmap = gc_pixmap_load(imageList[i]);
00379 
00380       answer_to_find[i] = RAND(1, number_of_item_max);
00381       answer[i] = 0;
00382 
00383       for(j=0; j<answer_to_find[i]; j++)
00384        {
00385          guint x, y;
00386 
00387          x = RAND(0, ANSWER_X-gdk_pixbuf_get_width(pixmap)-ANSWER_WIDTH);
00388          y = RAND(0, BOARDHEIGHT-gdk_pixbuf_get_height(pixmap));
00389 
00390          item = gnome_canvas_item_new (boardRootItem,
00391                                    gnome_canvas_pixbuf_get_type (),
00392                                    "pixbuf", pixmap,
00393                                    "x", (double) x,
00394                                    "y", (double) y,
00395                                    NULL);
00396 
00397          gtk_signal_connect(GTK_OBJECT(item), "event", (GtkSignalFunc) item_event, NULL);
00398        }
00399 
00400       gdk_pixbuf_unref(pixmap);
00401 
00402       /* Display the answer area */
00403       current_y -= ANSWER_HEIGHT*2;
00404 
00405       pixmap_answer = gc_pixmap_load("images/enumerate_answer.png");
00406 
00407       item = \
00408        gnome_canvas_item_new (boardRootItem,
00409                             gnome_canvas_pixbuf_get_type (),
00410                             "pixbuf", pixmap_answer,
00411                             "x", (double) ANSWER_X - ANSWER_WIDTH/2,
00412                             "y", (double) current_y - ANSWER_HEIGHT/2,
00413                             NULL);
00414 
00415       gtk_signal_connect(GTK_OBJECT(item), "event", (GtkSignalFunc) item_event_focus, GINT_TO_POINTER(i));
00416 
00417       gdk_pixbuf_unref(pixmap_answer);
00418 
00419       pixmap_answer = gc_pixmap_load("images/enumerate_answer_focus.png");
00420 
00421       answer_item_focus[i] = \
00422        gnome_canvas_item_new (boardRootItem,
00423                             gnome_canvas_pixbuf_get_type (),
00424                             "pixbuf", pixmap_answer,
00425                             "x", (double) ANSWER_X - ANSWER_WIDTH/2,
00426                             "y", (double) current_y - ANSWER_HEIGHT/2,
00427                             NULL);
00428 
00429       gdk_pixbuf_unref(pixmap_answer);
00430       gnome_canvas_item_hide(answer_item_focus[i]);
00431 
00432       item = gnome_canvas_item_new (boardRootItem,
00433                                 gnome_canvas_pixbuf_get_type (),
00434                                 "pixbuf", pixmap,
00435                                 "x", (double) ANSWER_X,
00436                                 "y", (double) current_y,
00437                                 "width", (double) gdk_pixbuf_get_width(pixmap)*ANSWER_HEIGHT/gdk_pixbuf_get_height(pixmap),
00438                                 "height", (double) ANSWER_HEIGHT,
00439                                 "width_set", TRUE,
00440                                 "height_set", TRUE,
00441                                 NULL);
00442 
00443 
00444       gtk_signal_connect(GTK_OBJECT(item), "event", (GtkSignalFunc) item_event_focus,  GINT_TO_POINTER(i));
00445 
00446       gtk_signal_connect(GTK_OBJECT(item), "event",
00447                       (GtkSignalFunc) gc_item_focus_event,
00448                       NULL);
00449 
00450       answer_item[i] = \
00451        gnome_canvas_item_new (boardRootItem,
00452                             gnome_canvas_text_get_type (),
00453                             "text", "?",
00454                             "font", gc_skin_font_board_big,
00455                             "x", (double) ANSWER_X + 2.5*ANSWER_WIDTH,
00456                             "y", (double) current_y + ANSWER_HEIGHT/2,
00457                             "anchor", GTK_ANCHOR_EAST,
00458                             "fill_color", "blue",
00459                             NULL);
00460       gtk_signal_connect(GTK_OBJECT(answer_item[i]), "event", (GtkSignalFunc) item_event_focus,
00461                       GINT_TO_POINTER(i));
00462 
00463     }
00464 
00465   gnome_canvas_item_show(answer_item_focus[current_focus]);
00466 
00467   return NULL;
00468 }
00469 /* ==================================== */
00470 static void game_won()
00471 {
00472   gcomprisBoard->sublevel++;
00473 
00474   if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) {
00475     /* Try the next level */
00476     gcomprisBoard->sublevel=1;
00477     gcomprisBoard->level++;
00478     if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
00479       gc_bonus_end_display(BOARD_FINISHED_RANDOM);
00480       return;
00481     }
00482     gc_sound_play_ogg ("sounds/bonus.ogg", NULL);
00483   }
00484   enumerate_next_level();
00485 }
00486 
00487 /* ==================================== */
00488 static gint
00489 item_event_focus(GnomeCanvasItem *item, GdkEvent *event, guint index)
00490 {
00491 
00492    switch (event->type)
00493      {
00494      case GDK_BUTTON_PRESS:
00495        gnome_canvas_item_hide(answer_item_focus[current_focus]);
00496        current_focus = index;
00497        gnome_canvas_item_show(answer_item_focus[current_focus]);
00498        return TRUE;
00499        break;
00500      default:
00501        break;
00502      }
00503 
00504    return FALSE;
00505 }
00506 
00507 /* ==================================== */
00508 static gint
00509 item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data)
00510 {
00511   static double x, y;
00512   double item_x, item_y;
00513   GdkCursor *fleur;
00514   static int dragging;
00515   double new_x, new_y;
00516 
00517   item_x = event->button.x;
00518   item_y = event->button.y;
00519   gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
00520 
00521   if(board_paused)
00522     return FALSE;
00523 
00524 
00525    switch (event->type)
00526      {
00527      case GDK_BUTTON_PRESS:
00528        switch(event->button.button)
00529          {
00530          case 1:
00531           x = item_x;
00532           y = item_y;
00533 
00534           gnome_canvas_item_raise_to_top(item);
00535 
00536           fleur = gdk_cursor_new(GDK_FLEUR);
00537           gc_canvas_item_grab(item,
00538                               GDK_POINTER_MOTION_MASK |
00539                               GDK_BUTTON_RELEASE_MASK,
00540                               fleur,
00541                               event->button.time);
00542           gdk_cursor_destroy(fleur);
00543           dragging = TRUE;
00544            break;
00545 
00546          case 3:
00547          case 4:
00548           /* fish up */
00549           gnome_canvas_item_move(item, 0.0, -3.0);
00550           break;
00551 
00552          case 2:
00553          case 5:
00554           /* fish down */
00555           gnome_canvas_item_move(item, 0.0, 3.0);
00556           break;
00557 
00558          default:
00559            break;
00560          }
00561        break;
00562 
00563      case GDK_MOTION_NOTIFY:
00564        if (dragging && (event->motion.state & GDK_BUTTON1_MASK))
00565          {
00566           double x1, x2, y1, y2;
00567 
00568           gnome_canvas_item_get_bounds(item,  &x1, &y1, &x2, &y2);
00569 
00570            new_x = item_x;
00571            new_y = item_y;
00572 
00573           /* Check board boundaries */
00574           if((x1 < 0 && new_x<x)|| (x2 > BOARDWIDTH && new_x>x))
00575             {
00576               new_x = x;
00577             }
00578           if((y1 < 0 && new_y<y) || (y2 > BOARDHEIGHT && new_y>y))
00579             {
00580               new_y = y;
00581             }
00582 
00583           gnome_canvas_item_move(item, new_x - x, new_y - y);
00584           x = new_x;
00585           y = new_y;
00586          }
00587        break;
00588 
00589      case GDK_BUTTON_RELEASE:
00590        if(dragging)
00591         {
00592           gc_canvas_item_ungrab(item, event->button.time);
00593           dragging = FALSE;
00594         }
00595        break;
00596 
00597      default:
00598        break;
00599      }
00600 
00601   return FALSE;
00602 }
00603 
00604 static void process_ok()
00605 {
00606   guint i;
00607   gboolean win = TRUE;
00608 
00609   for(i=0; i<number_of_item_type; i++)
00610     {
00611       printf("answer[%d]=%d answer_to_find[%d]=%d\n",i,  answer[i], i, answer_to_find[i]);
00612       if(answer[i] != answer_to_find[i])
00613        win = FALSE;
00614     }
00615 
00616   if(win) {
00617     gamewon = TRUE;
00618     gc_bonus_display(gamewon, BONUS_SMILEY);
00619   } else {
00620     gamewon = FALSE;
00621     gc_bonus_display(gamewon, BONUS_SMILEY);
00622   }
00623 }
00624