colors.c 12.9 KB
Newer Older
1 2
/* gcompris - colors.c
 *
3
 * Copyright (C) 2002, 2008 Pascal Georges
4 5 6
 *
 *   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
7
 *   the Free Software Foundation; either version 3 of the License, or
8 9 10 11 12 13 14 15
 *   (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
16
 *   along with this program; if not, see <http://www.gnu.org/licenses/>.
17 18 19 20 21 22
 */

#include "gcompris/gcompris.h"

#define SOUNDLISTFILE PACKAGE

23 24
static GcomprisBoard *gcomprisBoard = NULL;
static gboolean board_paused = TRUE;
25

26 27 28 29
static void		 start_board (GcomprisBoard *agcomprisBoard);
static void		 pause_board (gboolean pause);
static void		 end_board (void);
static gboolean		 is_our_board (GcomprisBoard *gcomprisBoard);
30 31
static int gamewon;

32 33 34 35
static void		 process_ok(void);
static void		 highlight_selected(int);
static void		 game_won(void);
static void		 repeat(void);
36 37 38
static void		 colors_config_start(GcomprisBoard *agcomprisBoard,
					     GcomprisProfile *aProfile);
static void		 colors_config_stop(void);
39 40

/* ================================================================ */
41
static GooCanvasItem *boardRootItem = NULL;
42
static GooCanvasItem *highlight_image_item = NULL;
43

44
static GooCanvasItem *colors_create_item(GooCanvasItem *parent);
45 46
static void colors_destroy_all_items(void);
static void colors_next_level(void);
Bruno Coudoin's avatar
Bruno Coudoin committed
47 48 49 50 51
static gboolean
item_event (GooCanvasItem *item,
	    GooCanvasItem *target,
	    GdkEventButton *event,
	    gpointer data);
52 53
static int highlight_width, highlight_height;
static GList * listColors = NULL;
Bruno Coudoin's avatar
Bruno Coudoin committed
54
static gint timer_id = 0;
55

56 57
static SoundPolicy sound_policy;

58
#define LAST_COLOR 10
59
static gchar *colors[LAST_COLOR*2] = {
60 61 62 63 64 65 66 67 68 69
  "blue", 	N_("Click on the blue duck"),
  "brown",	N_("Click on the brown duck"),
  "green",	N_("Click on the green duck"),
  "grey",	N_("Click on the grey duck"),
  "orange",	N_("Click on the orange duck"),
  "purple",	N_("Click on the purple duck"),
  "red",	N_("Click on the red duck"),
  "yellow",	N_("Click on the yellow duck"),
  "black",	N_("Click on the black duck"),
  "white",	N_("Click on the white duck")
70 71
};

72 73 74 75
static int X[] = {75,212,242,368,414,533,578,709};
static int Y[] = {25,170,180,335,337,500};

/* Description of this plugin */
76
static BoardPlugin menu_bp =
77 78 79
  {
    NULL,
    NULL,
80 81 82
    "Colors",
    "Click on the right color",
    "Pascal Georges <pascal.georges1@free.fr>",
83 84 85 86 87 88 89 90 91
    NULL,
    NULL,
    NULL,
    NULL,
    start_board,
    pause_board,
    end_board,
    is_our_board,
    NULL,
92
    NULL,
93
    NULL,//set_level,
94
    NULL,
95
    repeat,
96 97
    colors_config_start,
    colors_config_stop
98 99 100 101 102
  };

/* =====================================================================
 *
 * =====================================================================*/
103
GET_BPLUGIN_INFO(colors)
104

105 106 107 108 109

/* ======================= */
/* = config_start        = */
/* ======================= */

110 111
static GcomprisProfile *profile_conf;
static GcomprisBoard   *board_conf;
112

113 114 115
static void save_table (gpointer key,
			gpointer value,
			gpointer user_data)
116
{
117
  gc_db_set_board_conf ( profile_conf,
Bruno Coudoin's avatar
Bruno Coudoin committed
118 119 120
			 board_conf,
			 (gchar *) key,
			 (gchar *) value);
121 122
}

123 124
static void
conf_ok(GHashTable *table)
125
{
126 127 128 129 130 131
  if (!table){
    if (gcomprisBoard)
      pause_board(FALSE);
    return;
  }

132
  g_hash_table_foreach(table, (GHFunc) save_table, NULL);
133

134
  if (gcomprisBoard){
135
    GHashTable *config = gc_db_get_board_conf();
136

137
    if (profile_conf)
138
      config = gc_db_get_board_conf();
139 140 141
    else
      config = table;

142
    gc_locale_set(g_hash_table_lookup(config, "locale_sound"));
143

144 145
    if (profile_conf)
      g_hash_table_destroy(config);
146 147 148 149

    colors_next_level();

    pause_board(FALSE);
150

151
  }
152
  board_conf = NULL;
153
  profile_conf = NULL;
154 155
}

156
static void
157 158 159
colors_config_start(GcomprisBoard *agcomprisBoard,
		    GcomprisProfile *aProfile)
{
160 161 162
  board_conf = agcomprisBoard;
  profile_conf = aProfile;

163
  gchar *label;
164 165 166

  if (gcomprisBoard)
    pause_board(TRUE);
167

168
  label = g_strdup_printf(_("<b>%1$s</b> configuration\n for profile <b>%2$s</b>"),
169
			  agcomprisBoard->name, aProfile ? aProfile->name : "");
170

171
  GcomprisBoardConf *bconf = gc_board_config_window_display(label, conf_ok);
172

173
  g_free(label);
174

175
  /* init the combo to previously saved value */
176
  GHashTable *config = gc_db_get_conf( profile_conf, board_conf);
177

178
  gchar *saved_locale_sound = g_hash_table_lookup( config, "locale_sound");
179

180
  gc_board_config_combo_locales_asset(bconf, _("Select sound locale"), saved_locale_sound,
181
				"voices/$LOCALE/colors/purple.ogg");
182 183

  g_hash_table_destroy(config);
184

185
}
186

187

188 189 190
/* ======================= */
/* = config_stop        = */
/* ======================= */
191
static void
192 193 194 195 196
colors_config_stop()
{
}


197 198 199 200 201 202 203 204
/* =====================================================================
 * in : boolean TRUE = PAUSE : FALSE = CONTINUE
 * =====================================================================*/
static void pause_board (gboolean pause)
{
  if(gcomprisBoard==NULL)
    return;

Bruno Coudoin's avatar
Bruno Coudoin committed
205 206 207 208 209
  if (timer_id) {
    gtk_timeout_remove (timer_id);
    timer_id = 0;
  }

210
  if(gamewon == TRUE && pause == FALSE) /* the game is won */
211
    game_won();
212 213 214 215 216 217 218

  board_paused = pause;
}

/* =====================================================================
 *
 * =====================================================================*/
Bruno Coudoin's avatar
Bruno Coudoin committed
219 220
static void start_board (GcomprisBoard *agcomprisBoard)
{
221
  GcomprisProperties	*properties = gc_prop_get();
222
  GHashTable *config = gc_db_get_board_conf();
223

224
  gc_locale_set(g_hash_table_lookup(config, "locale_sound"));
225

226
  g_hash_table_destroy(config);
227

228
  gc_sound_bg_pause();
229

230
  if(agcomprisBoard!=NULL) {
231
    gcomprisBoard=agcomprisBoard;
Bruno Coudoin's avatar
Bruno Coudoin committed
232 233
    gc_set_background(goo_canvas_get_root_item(gcomprisBoard->canvas),
		      "colors/colors_bg.png");
234 235
    gcomprisBoard->level=1;
    gcomprisBoard->maxlevel=1;
236 237

    if(properties->fx) {
238
      gc_bar_set(GC_BAR_CONFIG|GC_BAR_REPEAT);
239 240 241 242 243

      /* initial state to restore */
      sound_policy = gc_sound_policy_get();
      gc_sound_policy_set(PLAY_AND_INTERRUPT);

244
    } else {
245
      gc_bar_set(GC_BAR_CONFIG);
246
    }
Bruno Coudoin's avatar
Bruno Coudoin committed
247
    gc_bar_location(5, -1, 0.8);
248 249 250

    gamewon = FALSE;

Bruno Coudoin's avatar
Bruno Coudoin committed
251 252 253
    g_signal_connect(goo_canvas_get_root_item(gcomprisBoard->canvas),
		     "button_press_event", (GtkSignalFunc) item_event, NULL);

254 255 256
    colors_next_level();
    pause_board(FALSE);
  }
257 258 259 260 261
}

/* =====================================================================
 *
 * =====================================================================*/
Bruno Coudoin's avatar
Bruno Coudoin committed
262 263
static void end_board ()
{
264

Bruno Coudoin's avatar
Bruno Coudoin committed
265
  if(gcomprisBoard!=NULL) {
266 267
    GcomprisProperties	*properties = gc_prop_get();

Bruno Coudoin's avatar
Bruno Coudoin committed
268 269 270
    g_signal_handlers_disconnect_by_func(goo_canvas_get_root_item(gcomprisBoard->canvas),
					 (GtkSignalFunc) item_event, NULL);

271
    pause_board(TRUE);
272
    gc_score_end();
273 274 275 276 277 278
    colors_destroy_all_items();
    // free list
    while (g_list_length(listColors) > 0)
      listColors = g_list_remove(listColors, g_list_nth_data(listColors,0));
    g_list_free(listColors);
    listColors=NULL;
279 280 281 282 283

    if(properties->fx) {
      gc_sound_policy_set(sound_policy);
    }

284
  }
285
  gc_locale_reset();
286
  gcomprisBoard = NULL;
287
  gc_sound_bg_resume();
288 289 290 291 292
}

/* =====================================================================
 *
 * =====================================================================*/
Bruno Coudoin's avatar
Bruno Coudoin committed
293 294
static gboolean is_our_board (GcomprisBoard *gcomprisBoard)
{
295 296 297 298 299 300
  if (gcomprisBoard) {
    if(g_strcasecmp(gcomprisBoard->type, "colors")==0) {
      /* Set the plugin entry */
      gcomprisBoard->plugin=&menu_bp;
      return TRUE;
    }
301 302 303 304 305 306
  }
  return FALSE;
}
/* =====================================================================
 * set initial values for the next level
 * =====================================================================*/
Bruno Coudoin's avatar
Bruno Coudoin committed
307 308
static void colors_next_level()
{
Bruno Coudoin's avatar
Bruno Coudoin committed
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
  if (g_list_length(listColors) == 0)
    {
      GList * list = NULL;
      int * item;
      int i, list_length;

      // we generate a list of color indexes in a random order
      for (i=0; i<LAST_COLOR; i++)
	list = g_list_append(list, GINT_TO_POINTER(i));

      while ((list_length = g_list_length(list))) {
	i = list_length == 1 ? 0 : g_random_int_range(0,g_list_length(list)-1);
	item = g_list_nth_data(list, i);
	listColors = g_list_append(listColors, item);
	list = g_list_remove(list, item);
      }
      g_list_free(list);
    }

328 329 330 331
  colors_destroy_all_items();
  gamewon = FALSE;

  /* Try the next level */
332
  colors_create_item(goo_canvas_get_root_item(gcomprisBoard->canvas));
333
  repeat();
334 335
}
/* ======================================= */
Bruno Coudoin's avatar
Bruno Coudoin committed
336 337
static void repeat ()
{
338

339
  if(gcomprisBoard!=NULL)
340
    {
341
      char *str  = NULL;
342
      GcomprisProperties *properties = gc_prop_get();
343

344
      str = g_strdup_printf("voices/$LOCALE/colors/%s.ogg",
345
			    colors[GPOINTER_TO_INT(g_list_nth_data(listColors, 0))*2]);
346

347
      /* If we don't find a sound in our locale or the sounds are disabled */
348
      if(str && properties->fx)
349
	gc_sound_play_ogg(str, NULL);
350

351
      g_free(str);
352

353
      str = g_strdup(gettext(colors[GPOINTER_TO_INT(g_list_nth_data(listColors, 0))*2+1]));
354

355 356 357
      goo_canvas_text_new (boardRootItem,
			   str,
			   (double) BOARDWIDTH/2,
358
			   (double) 10,
359 360
			   -1,
			   GTK_ANCHOR_CENTER,
361 362
			   "font", gc_skin_font_subtitle,
			   "fill-color", "black",
363
			   NULL);
364
      g_free(str);
365
    }
366 367 368 369
}
/* =====================================================================
 * Destroy all the items
 * =====================================================================*/
Bruno Coudoin's avatar
Bruno Coudoin committed
370 371
static void colors_destroy_all_items()
{
Bruno Coudoin's avatar
Bruno Coudoin committed
372 373 374 375 376
  if (timer_id) {
    gtk_timeout_remove (timer_id);
    timer_id = 0;
  }

377
  if(boardRootItem!=NULL)
Bruno Coudoin's avatar
Bruno Coudoin committed
378
    goo_canvas_item_remove(boardRootItem);
379 380 381 382 383 384 385

  boardRootItem = NULL;
}

/* =====================================================================
 *
 * =====================================================================*/
Bruno Coudoin's avatar
Bruno Coudoin committed
386 387
static GooCanvasItem *colors_create_item(GooCanvasItem *parent)
{
388 389 390
  GdkPixbuf *highlight_pixmap = NULL;
  char *str = NULL;

Bruno Coudoin's avatar
Bruno Coudoin committed
391 392 393
  boardRootItem = goo_canvas_group_new (goo_canvas_get_root_item(gcomprisBoard->canvas),
					NULL);

394 395

  str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "colors_highlight.png");
396
  highlight_pixmap = gc_pixmap_load(str);
397

398 399 400 401 402
  highlight_image_item = goo_canvas_image_new (boardRootItem,
					       highlight_pixmap,
					       0,
					       0,
					       NULL);
403 404 405 406 407 408

  highlight_width = gdk_pixbuf_get_width(highlight_pixmap);
  highlight_height = gdk_pixbuf_get_height(highlight_pixmap);

  g_free(str);

Bruno Coudoin's avatar
Bruno Coudoin committed
409
  g_object_set (highlight_image_item, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
410 411 412 413 414 415 416 417

  gdk_pixbuf_unref(highlight_pixmap);

  return NULL;
}
/* =====================================================================
 *
 * =====================================================================*/
Bruno Coudoin's avatar
Bruno Coudoin committed
418 419
static void game_won()
{
420 421
  gcomprisBoard->sublevel++;

422
  listColors = g_list_remove(listColors, g_list_nth_data(listColors,0));
423

424
  colors_next_level();
425 426 427 428
}
/* =====================================================================
 *
 * =====================================================================*/
Bruno Coudoin's avatar
Bruno Coudoin committed
429 430
static gboolean process_ok_timeout()
{
Bruno Coudoin's avatar
Bruno Coudoin committed
431
  timer_id = 0;
432
  gc_bonus_display(gamewon, GC_BONUS_GNU);
433
  return FALSE;
434 435
}

Bruno Coudoin's avatar
Bruno Coudoin committed
436 437
static void process_ok()
{
438
  // leave time to display the right answer
Bruno Coudoin's avatar
Bruno Coudoin committed
439 440
  timer_id = g_timeout_add(TIME_CLICK_TO_BONUS,
			   process_ok_timeout, NULL);
441
}
Bruno Coudoin's avatar
Bruno Coudoin committed
442

443 444 445
/* =====================================================================
 *
 * =====================================================================*/
Bruno Coudoin's avatar
Bruno Coudoin committed
446 447 448 449 450 451
static gboolean
item_event (GooCanvasItem *item,
	    GooCanvasItem *target,
	    GdkEventButton *event,
	    gpointer data)
{
452 453
  double x, y;
  int i, j, clicked;
454

Bruno Coudoin's avatar
Bruno Coudoin committed
455 456
  x = event->x;
  y = event->y;
457

458
  if (!gcomprisBoard || board_paused)
459 460
    return FALSE;

Bruno Coudoin's avatar
Bruno Coudoin committed
461 462 463 464 465
  clicked = -1;
  for (i=0; i<4; i++) {
    for (j=0; j<2; j++) {
      if (x>X[i*2] && x<X[i*2+1] && y>Y[j*2] && y<Y[j*2+1]) {
	clicked = j*4 + i;
466
      }
467
    }
Bruno Coudoin's avatar
Bruno Coudoin committed
468 469 470 471 472 473 474 475 476 477 478 479 480 481
  }
  if (x>X[2] && x<X[3] && y>Y[4] && y<Y[5])
    clicked = 8;
  if (x>X[4] && x<X[5] && y>Y[4] && y<Y[5])
    clicked = 9;

  if (clicked >= 0) {
    gc_sound_play_ogg ("sounds/bleep.wav", NULL);
    board_paused = TRUE;
    highlight_selected(clicked);
    gamewon = (clicked == GPOINTER_TO_INT(g_list_nth_data(listColors,0)));
    process_ok();
  }

482 483 484 485 486 487 488
  return FALSE;
}

/* =====================================================================
 *
 * =====================================================================*/
static void highlight_selected(int c) {
489 490
  int x, y;

491
  g_assert(c>=0 && c<=9);
492 493 494 495 496 497 498 499 500 501 502 503 504

  if (c<8) {
    x = (X[(c%4)*2] + X[(c%4)*2+1]) /2;
    y = (Y[(int)(c/4)*2] + Y[(int)(c/4)*2+1]) /2;
  } else {
    y = (Y[4]+Y[5]) /2;
    if (c==8)
      x = (X[2] + X[3]) /2;
    else
      x = (X[4] + X[5]) /2;
  }
  x -= highlight_width/2;
  y -= highlight_height/2;
Bruno Coudoin's avatar
Bruno Coudoin committed
505
  g_object_set (highlight_image_item, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
506
  gc_item_absolute_move(highlight_image_item, x, y);
507
}