Commit FS#9617 - Keymaps for Plugins fuze by Thomas Martitz.
[kugel-rb.git] / apps / plugins / sliding_puzzle.c
blob7aa1ed36a84f9b0aad62b48636bac0795c27a359
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Vicentini Martin
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "plugin.h"
23 #ifdef HAVE_LCD_BITMAP
24 PLUGIN_HEADER
26 /* variable button definitions */
27 #if CONFIG_KEYPAD == RECORDER_PAD
28 #define PUZZLE_QUIT BUTTON_OFF
29 #define PUZZLE_LEFT BUTTON_LEFT
30 #define PUZZLE_RIGHT BUTTON_RIGHT
31 #define PUZZLE_UP BUTTON_UP
32 #define PUZZLE_DOWN BUTTON_DOWN
33 #define PUZZLE_SHUFFLE BUTTON_F1
34 #define PUZZLE_PICTURE BUTTON_F2
36 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
37 #define PUZZLE_QUIT BUTTON_OFF
38 #define PUZZLE_LEFT BUTTON_LEFT
39 #define PUZZLE_RIGHT BUTTON_RIGHT
40 #define PUZZLE_UP BUTTON_UP
41 #define PUZZLE_DOWN BUTTON_DOWN
42 #define PUZZLE_SHUFFLE BUTTON_F1
43 #define PUZZLE_PICTURE BUTTON_F2
45 #elif CONFIG_KEYPAD == ONDIO_PAD
46 #define PUZZLE_QUIT BUTTON_OFF
47 #define PUZZLE_LEFT BUTTON_LEFT
48 #define PUZZLE_RIGHT BUTTON_RIGHT
49 #define PUZZLE_UP BUTTON_UP
50 #define PUZZLE_DOWN BUTTON_DOWN
51 #define PUZZLE_SHUFFLE_PICTURE_PRE BUTTON_MENU
52 #define PUZZLE_SHUFFLE (BUTTON_MENU | BUTTON_REPEAT)
53 #define PUZZLE_PICTURE (BUTTON_MENU | BUTTON_REL)
55 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
56 (CONFIG_KEYPAD == IRIVER_H300_PAD)
57 #define PUZZLE_QUIT BUTTON_OFF
58 #define PUZZLE_LEFT BUTTON_LEFT
59 #define PUZZLE_RIGHT BUTTON_RIGHT
60 #define PUZZLE_UP BUTTON_UP
61 #define PUZZLE_DOWN BUTTON_DOWN
62 #define PUZZLE_SHUFFLE BUTTON_SELECT
63 #define PUZZLE_PICTURE BUTTON_ON
65 #define PUZZLE_RC_QUIT BUTTON_RC_STOP
67 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
68 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
69 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
70 #define PUZZLE_QUIT (BUTTON_SELECT | BUTTON_MENU)
71 #define PUZZLE_LEFT BUTTON_LEFT
72 #define PUZZLE_RIGHT BUTTON_RIGHT
73 #define PUZZLE_UP BUTTON_MENU
74 #define PUZZLE_DOWN BUTTON_PLAY
75 #define PUZZLE_SHUFFLE (BUTTON_SELECT | BUTTON_LEFT)
76 #define PUZZLE_PICTURE (BUTTON_SELECT | BUTTON_RIGHT)
78 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
79 #define PUZZLE_QUIT BUTTON_POWER
80 #define PUZZLE_LEFT BUTTON_LEFT
81 #define PUZZLE_RIGHT BUTTON_RIGHT
82 #define PUZZLE_UP BUTTON_UP
83 #define PUZZLE_DOWN BUTTON_DOWN
84 #define PUZZLE_SHUFFLE BUTTON_REC
85 #define PUZZLE_PICTURE BUTTON_PLAY
87 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
88 #define PUZZLE_QUIT BUTTON_POWER
89 #define PUZZLE_LEFT BUTTON_LEFT
90 #define PUZZLE_RIGHT BUTTON_RIGHT
91 #define PUZZLE_UP BUTTON_UP
92 #define PUZZLE_DOWN BUTTON_DOWN
93 #define PUZZLE_SHUFFLE BUTTON_SELECT
94 #define PUZZLE_PICTURE BUTTON_A
96 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
97 (CONFIG_KEYPAD == SANSA_C200_PAD)
98 #define PUZZLE_QUIT BUTTON_POWER
99 #define PUZZLE_LEFT BUTTON_LEFT
100 #define PUZZLE_RIGHT BUTTON_RIGHT
101 #define PUZZLE_UP BUTTON_UP
102 #define PUZZLE_DOWN BUTTON_DOWN
103 #define PUZZLE_SHUFFLE BUTTON_REC
104 #define PUZZLE_PICTURE BUTTON_SELECT
106 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
107 #define PUZZLE_QUIT BUTTON_POWER
108 #define PUZZLE_LEFT BUTTON_LEFT
109 #define PUZZLE_RIGHT BUTTON_RIGHT
110 #define PUZZLE_UP BUTTON_UP
111 #define PUZZLE_DOWN BUTTON_DOWN
112 /* FIXME:
113 #define PUZZLE_SHUFFLE BUTTON_HOME */
114 #define PUZZLE_SHUFFLE BUTTON_SELECT|BUTTON_DOWN
115 #define PUZZLE_PICTURE BUTTON_SELECT
117 #elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
118 #define PUZZLE_QUIT BUTTON_POWER
119 #define PUZZLE_LEFT BUTTON_LEFT
120 #define PUZZLE_RIGHT BUTTON_RIGHT
121 #define PUZZLE_UP BUTTON_UP
122 #define PUZZLE_DOWN BUTTON_DOWN
123 #define PUZZLE_SHUFFLE BUTTON_HOME
124 #define PUZZLE_PICTURE BUTTON_SELECT
126 #elif (CONFIG_KEYPAD == SANSA_M200_PAD)
127 #define PUZZLE_QUIT BUTTON_POWER
128 #define PUZZLE_LEFT BUTTON_LEFT
129 #define PUZZLE_RIGHT BUTTON_RIGHT
130 #define PUZZLE_UP BUTTON_UP
131 #define PUZZLE_DOWN BUTTON_DOWN
132 #define PUZZLE_SHUFFLE (BUTTON_SELECT | BUTTON_UP)
133 #define PUZZLE_PICTURE (BUTTON_SELECT | BUTTON_REL)
135 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
136 #define PUZZLE_QUIT BUTTON_POWER
137 #define PUZZLE_LEFT BUTTON_LEFT
138 #define PUZZLE_RIGHT BUTTON_RIGHT
139 #define PUZZLE_UP BUTTON_SCROLL_UP
140 #define PUZZLE_DOWN BUTTON_SCROLL_DOWN
141 #define PUZZLE_SHUFFLE BUTTON_REW
142 #define PUZZLE_PICTURE BUTTON_PLAY
144 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
145 #define PUZZLE_QUIT BUTTON_BACK
146 #define PUZZLE_LEFT BUTTON_LEFT
147 #define PUZZLE_RIGHT BUTTON_RIGHT
148 #define PUZZLE_UP BUTTON_UP
149 #define PUZZLE_DOWN BUTTON_DOWN
150 #define PUZZLE_SHUFFLE BUTTON_SELECT
151 #define PUZZLE_PICTURE BUTTON_MENU
153 #elif (CONFIG_KEYPAD == MROBE100_PAD)
154 #define PUZZLE_QUIT BUTTON_POWER
155 #define PUZZLE_LEFT BUTTON_LEFT
156 #define PUZZLE_RIGHT BUTTON_RIGHT
157 #define PUZZLE_UP BUTTON_UP
158 #define PUZZLE_DOWN BUTTON_DOWN
159 #define PUZZLE_SHUFFLE BUTTON_SELECT
160 #define PUZZLE_PICTURE BUTTON_DISPLAY
162 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
163 #define PUZZLE_QUIT BUTTON_RC_REC
164 #define PUZZLE_LEFT BUTTON_RC_REW
165 #define PUZZLE_RIGHT BUTTON_RC_FF
166 #define PUZZLE_UP BUTTON_RC_VOL_UP
167 #define PUZZLE_DOWN BUTTON_RC_VOL_DOWN
168 #define PUZZLE_SHUFFLE BUTTON_RC_MODE
169 #define PUZZLE_PICTURE BUTTON_RC_MENU
171 #elif (CONFIG_KEYPAD == COWOND2_PAD)
172 #define PUZZLE_QUIT BUTTON_POWER
173 #define PUZZLE_QUIT_TEXT "[POWER]"
175 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
176 #define PUZZLE_QUIT BUTTON_BACK
177 #define PUZZLE_LEFT BUTTON_LEFT
178 #define PUZZLE_RIGHT BUTTON_RIGHT
179 #define PUZZLE_UP BUTTON_UP
180 #define PUZZLE_DOWN BUTTON_DOWN
181 #define PUZZLE_SHUFFLE BUTTON_PLAY
182 #define PUZZLE_PICTURE BUTTON_MENU
184 #else
185 #error No keymap defined!
186 #endif
188 #ifdef HAVE_TOUCHSCREEN
189 #ifndef PUZZLE_QUIT
190 #define PUZZLE_QUIT BUTTON_TOPLEFT
191 #endif
192 #ifndef PUZZLE_LEFT
193 #define PUZZLE_LEFT BUTTON_MIDLEFT
194 #endif
195 #ifndef PUZZLE_RIGHT
196 #define PUZZLE_RIGHT BUTTON_MIDRIGHT
197 #endif
198 #ifndef PUZZLE_UP
199 #define PUZZLE_UP BUTTON_TOPMIDDLE
200 #endif
201 #ifndef PUZZLE_DOWN
202 #define PUZZLE_DOWN BUTTON_BOTTOMMIDDLE
203 #endif
204 #ifndef PUZZLE_SHUFFLE
205 #define PUZZLE_SHUFFLE BUTTON_BOTTOMLEFT
206 #endif
207 #ifndef PUZZLE_PICTURE
208 #define PUZZLE_PICTURE BUTTON_CENTER
209 #endif
210 #ifndef PUZZLE_QUIT_TEXT
211 #define PUZZLE_QUIT_TEXT "[TOPLEFT]"
212 #endif
213 #ifndef PUZZLE_SHUFFLE_TEXT
214 #define PUZZLE_SHUFFLE_TEXT "[BOTTOMLEFT]"
215 #endif
216 #ifndef PUZZLE_PICTURE_TEXT
217 #define PUZZLE_PICTURE_TEXT "[CENTER]"
218 #endif
219 #endif
221 #include "pluginbitmaps/sliding_puzzle.h"
222 #define IMAGE_WIDTH BMPWIDTH_sliding_puzzle
223 #define IMAGE_HEIGHT BMPHEIGHT_sliding_puzzle
224 #define IMAGE_SIZE IMAGE_WIDTH
226 static const struct plugin_api* rb;
228 /* use a square image, (the default Archos bitmap looks square on its display)
229 Puzzle image dimension is min(lcd_height,lcd_width)
230 4x4 is more convenient for square puzzles
231 Note: sliding_puzzle.bmp should be evenly divisible by SPOTS_X
232 and SPOTS_Y, otherwise lcd_bitmap_part stride won't be correct */
233 #define SPOTS_X 4
234 #define SPOTS_Y 4
235 #define SPOTS_WIDTH (IMAGE_WIDTH / SPOTS_X)
236 #define SPOTS_HEIGHT (IMAGE_HEIGHT / SPOTS_Y)
237 #define NUM_SPOTS (SPOTS_X*SPOTS_Y)
238 #define HOLE_ID (NUM_SPOTS)
239 #define INITIAL_HOLE (HOLE_ID-1)
241 enum picmodes
243 PICMODE_NUMERALS = 0,
244 PICMODE_INITIAL_PICTURE,
245 PICMODE_DEFAULT_PICTURE,
246 #ifdef HAVE_ALBUMART
247 PICMODE_ALBUM_ART,
248 #endif
249 // PICMODE_RANDOM,
250 PICMODE_LAST_XXX /* placeholder */
253 static const char* const picmode_descriptions[] = {
254 "Numerals",
255 "Viewer Picture",
256 "Default Picture",
257 #ifdef HAVE_ALBUMART
258 "Album Art",
259 #endif
260 "Shouldn't Get Here",
263 static int spots[NUM_SPOTS];
264 static int hole = INITIAL_HOLE, moves;
265 static unsigned char s[32];
266 static enum picmodes picmode = PICMODE_INITIAL_PICTURE;
267 static int num_font = FONT_UI;
268 static int moves_font = FONT_UI;
269 static int moves_y = 0;
271 static unsigned char img_buf
272 [BM_SCALED_SIZE(IMAGE_WIDTH,IMAGE_HEIGHT,FORMAT_NATIVE,0)]
273 __attribute__ ((aligned(16)));
274 #ifdef HAVE_ALBUMART
275 static char albumart_path[MAX_PATH+1];
276 #endif
277 static char img_buf_path[MAX_PATH+1];
279 static const fb_data * puzzle_bmp_ptr;
280 /* initial_bmp_path points to selected bitmap if this game is launched
281 as a viewer for a .bmp file, or NULL if game is launched regular way */
282 static const char * initial_bmp_path=NULL;
284 #ifdef HAVE_ALBUMART
285 const char * get_albumart_bmp_path(void)
287 struct mp3entry* track = rb->audio_current_track();
289 if (!track || !track->path || track->path[0] == '\0')
290 return NULL;
292 if (!rb->search_albumart_files(track, "", albumart_path, MAX_PATH ) )
293 return NULL;
295 albumart_path[ MAX_PATH ] = '\0';
296 return albumart_path;
298 #endif
300 const char * get_random_bmp_path(void)
302 return(initial_bmp_path);
305 static bool load_resize_bitmap(void)
307 int rc;
308 const char * filename = NULL;
310 /* initially assume using the built-in default */
311 puzzle_bmp_ptr = sliding_puzzle;
313 switch( picmode ){
314 /* some modes don't even need to touch disk and trivially succeed */
315 case PICMODE_NUMERALS:
316 case PICMODE_DEFAULT_PICTURE:
317 default:
318 return(true);
320 #ifdef HAVE_ALBUMART
321 case PICMODE_ALBUM_ART:
322 filename = get_albumart_bmp_path();
323 break;
324 #endif
326 case PICMODE_RANDOM:
327 if(NULL == (filename=get_random_bmp_path()) )
328 filename = initial_bmp_path;
329 break;
331 case PICMODE_INITIAL_PICTURE:
332 filename = initial_bmp_path;
333 break;
336 if( filename != NULL )
338 /* if we already loaded image before, don't touch disk */
339 if( 0 == rb->strcmp( filename, img_buf_path ) )
341 puzzle_bmp_ptr = (const fb_data *)img_buf;
342 return true;
345 struct bitmap main_bitmap;
346 rb->memset(&main_bitmap,0,sizeof(struct bitmap));
347 main_bitmap.data = img_buf;
349 main_bitmap.width = IMAGE_WIDTH;
350 main_bitmap.height = IMAGE_HEIGHT;
352 rc = rb->read_bmp_file( filename, &main_bitmap,
353 sizeof(img_buf),
354 FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_DITHER,
355 NULL);
356 if( rc > 0 )
358 puzzle_bmp_ptr = (const fb_data *)img_buf;
359 rb->strcpy( img_buf_path, filename );
360 return true;
364 /* something must have failed. get_albumart_bmp_path could return
365 NULL if albumart doesn't exist or couldn't be loaded, or
366 read_bmp_file could have failed. return false and caller should
367 try the next mode (PICMODE_DEFAULT_PICTURE and PICMODE_NUMERALS will
368 always succeed) */
369 return false;
372 /* draws a spot at the coordinates (x,y), range of p is 1-20 */
373 static void draw_spot(int p, int x, int y)
375 int w, h;
377 if (p == HOLE_ID)
379 #if LCD_DEPTH==1
380 /* the bottom-right cell of the default sliding_puzzle image is
381 an appropriate hole graphic */
382 rb->lcd_bitmap_part(sliding_puzzle, ((p-1)%SPOTS_X)*SPOTS_WIDTH,
383 ((p-1)/SPOTS_X)*SPOTS_HEIGHT,
384 IMAGE_WIDTH, x, y, SPOTS_WIDTH, SPOTS_HEIGHT);
385 #else
386 /* just draw a black rectangle */
387 int old_fg = rb->lcd_get_foreground();
388 rb->lcd_set_foreground(LCD_BLACK);
389 rb->lcd_fillrect(x,y,SPOTS_WIDTH,SPOTS_HEIGHT);
390 rb->lcd_set_foreground(old_fg);
391 #endif
393 else if (picmode != PICMODE_NUMERALS)
395 rb->lcd_bitmap_part( puzzle_bmp_ptr, ((p-1)%SPOTS_X)*SPOTS_WIDTH,
396 ((p-1)/SPOTS_X)*SPOTS_HEIGHT,
397 IMAGE_WIDTH, x, y, SPOTS_WIDTH, SPOTS_HEIGHT);
398 } else {
399 rb->lcd_drawrect(x, y, SPOTS_WIDTH, SPOTS_HEIGHT);
400 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
401 rb->lcd_fillrect(x+1, y+1, SPOTS_WIDTH-2, SPOTS_HEIGHT-2);
402 rb->lcd_set_drawmode(DRMODE_SOLID);
403 rb->snprintf(s, sizeof(s), "%d", p);
404 rb->lcd_setfont(num_font);
405 rb->lcd_getstringsize(s, &w, &h);
406 rb->lcd_putsxy(x + (SPOTS_WIDTH/2) - w / 2,
407 y + (SPOTS_HEIGHT/2) - h / 2, s);
411 /* check if the puzzle is solved */
412 static bool puzzle_finished(void)
414 int i;
415 for (i=0; i<NUM_SPOTS; i++)
416 if (spots[i] != (i+1))
417 return false;
418 return true;
421 /* move a piece in any direction */
422 static void move_spot(int x, int y)
424 int i, w;
425 spots[hole] = spots[hole-x-SPOTS_X*y];
426 hole -= (x+SPOTS_X*y);
427 moves++;
428 rb->lcd_setfont(moves_font);
429 #if LCD_WIDTH > LCD_HEIGHT
430 rb->snprintf(s, sizeof(s), "%d", moves);
431 w = rb->lcd_getstringsize(s, NULL, NULL);
432 rb->lcd_putsxy((IMAGE_WIDTH+1+(LCD_WIDTH-IMAGE_WIDTH-1)/2) - w / 2,
433 moves_y, s);
434 #else
435 (void)w;
436 rb->snprintf(s, sizeof(s), "Moves: %d", moves);
437 rb->lcd_putsxy(3, moves_y, s);
438 #endif
439 for(i=1;i<=4;i++)
441 draw_spot(HOLE_ID,
442 (hole%SPOTS_X)*SPOTS_WIDTH,
443 (hole/SPOTS_X)*SPOTS_HEIGHT);
444 draw_spot(spots[hole],
445 (hole%SPOTS_X)*SPOTS_WIDTH + (i*x*SPOTS_WIDTH)/5,
446 (hole/SPOTS_X)*SPOTS_HEIGHT + (i*y*SPOTS_HEIGHT)/5);
447 rb->lcd_update();
448 rb->sleep(HZ/50);
450 draw_spot(HOLE_ID,
451 (hole%SPOTS_X)*SPOTS_WIDTH,
452 (hole/SPOTS_X)*SPOTS_HEIGHT);
453 draw_spot(spots[hole],
454 ((hole%SPOTS_X)+x)*SPOTS_WIDTH,
455 ((hole/SPOTS_X)+y)*SPOTS_HEIGHT);
456 rb->lcd_update();
458 spots[hole] = HOLE_ID;
461 static void draw_playfield(void)
463 int i, w;
465 rb->lcd_clear_display();
466 rb->lcd_setfont(moves_font);
467 #if LCD_WIDTH > LCD_HEIGHT
468 rb->lcd_vline(IMAGE_WIDTH, 0, LCD_HEIGHT-1);
469 w = rb->lcd_getstringsize("Moves", NULL, NULL);
470 rb->lcd_putsxy((IMAGE_WIDTH+1+(LCD_WIDTH-IMAGE_WIDTH-1)/2) - w / 2,
471 10, "Moves");
472 rb->snprintf(s, sizeof(s), "%d", moves);
473 w = rb->lcd_getstringsize(s, NULL, NULL);
474 rb->lcd_putsxy((IMAGE_WIDTH+1+(LCD_WIDTH-IMAGE_WIDTH-1)/2) - w / 2,
475 moves_y, s);
476 #else
477 (void)w;
478 rb->lcd_hline(0, LCD_WIDTH-1, IMAGE_HEIGHT);
479 rb->snprintf(s, sizeof(s), "Moves: %d", moves);
480 rb->lcd_putsxy(3, moves_y, s);
481 #endif
483 /* draw spots to the lcd */
484 for (i=0; i<NUM_SPOTS; i++)
485 draw_spot(spots[i], (i%SPOTS_X)*SPOTS_WIDTH, (i/SPOTS_X)*SPOTS_HEIGHT);
487 rb->lcd_update();
490 /* initializes the puzzle */
491 static void puzzle_init(void)
493 int i, r, temp, tsp[NUM_SPOTS];
495 moves = 0;
497 /* shuffle spots */
498 for (i=NUM_SPOTS-1; i>=0; i--) {
499 r = (rb->rand() % (i+1));
501 temp = spots[r];
502 spots[r] = spots[i];
503 spots[i] = temp;
505 if (spots[i]==HOLE_ID)
506 hole = i;
509 /* test if the puzzle is solvable */
510 for (i=0; i<NUM_SPOTS; i++)
511 tsp[i] = spots[i];
512 r=0;
514 /* First, check if the problem has even or odd parity,
515 depending on where the empty square is */
516 if ((((SPOTS_X-1)-hole%SPOTS_X) + ((SPOTS_Y-1)-hole/SPOTS_X))%2 == 1)
517 ++r;
519 /* Now check how many swaps we need to solve it */
520 for (i=0; i<NUM_SPOTS-1; i++) {
521 while (tsp[i] != (i+1)) {
522 temp = tsp[i];
523 tsp[i] = tsp[temp-1];
524 tsp[temp-1] = temp;
525 ++r;
529 /* if the random puzzle isn't solvable just change two spots */
530 if (r%2 == 1) {
531 if (spots[0]!=HOLE_ID && spots[1]!=HOLE_ID) {
532 temp = spots[0];
533 spots[0] = spots[1];
534 spots[1] = temp;
535 } else {
536 temp = spots[2];
537 spots[2] = spots[3];
538 spots[3] = temp;
542 draw_playfield();
545 /* the main game loop */
546 static int puzzle_loop(void)
548 int button;
549 int lastbutton = BUTTON_NONE;
550 bool load_success;
552 puzzle_init();
553 while(true) {
554 button = rb->button_get(true);
555 switch (button) {
556 #ifdef PUZZLE_RC_QUIT
557 case PUZZLE_RC_QUIT:
558 #endif
559 case PUZZLE_QUIT:
560 /* get out of here */
561 return PLUGIN_OK;
563 case PUZZLE_SHUFFLE:
564 #ifdef PUZZLE_SHUFFLE_PICTURE_PRE
565 if (lastbutton != PUZZLE_SHUFFLE_PICTURE_PRE)
566 break;
567 #endif
568 /* mix up the pieces */
569 puzzle_init();
570 break;
572 case PUZZLE_PICTURE:
573 #ifdef PUZZLE_SHUFFLE_PICTURE_PRE
574 if (lastbutton != PUZZLE_SHUFFLE_PICTURE_PRE)
575 break;
576 #endif
577 /* change picture */
578 picmode = (picmode+1)%PICMODE_LAST_XXX;
580 /* if load_resize_bitmap fails to load bitmap, try next picmode
584 load_success = load_resize_bitmap();
585 if( !load_success )
586 picmode = (picmode+1)%PICMODE_LAST_XXX;
588 while( !load_success );
590 /* tell the user what mode we picked in the end! */
591 rb->splash(HZ,picmode_descriptions[ picmode ] );
592 draw_playfield();
593 break;
595 case PUZZLE_LEFT:
596 if ((hole%SPOTS_X)<(SPOTS_X-1) && !puzzle_finished())
597 move_spot(-1, 0);
598 break;
600 case PUZZLE_RIGHT:
601 if ((hole%SPOTS_X)>0 && !puzzle_finished())
602 move_spot(1, 0);
603 break;
605 case PUZZLE_UP:
606 if ((hole/SPOTS_X)<(SPOTS_Y-1) && !puzzle_finished())
607 move_spot(0, -1);
608 break;
610 case PUZZLE_DOWN:
611 if ((hole/SPOTS_X)>0 && !puzzle_finished())
612 move_spot(0, 1);
613 break;
615 default:
616 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
617 return PLUGIN_USB_CONNECTED;
618 break;
620 if (button != BUTTON_NONE)
621 lastbutton = button;
625 enum plugin_status plugin_start(const struct plugin_api* api,
626 const void* parameter)
628 int i, w, h;
630 rb = api;
632 initial_bmp_path=(const char *)parameter;
633 picmode = PICMODE_INITIAL_PICTURE;
634 img_buf_path[0] = '\0';
636 /* If launched as a viewer, just go straight to the game without
637 bothering with the splash or instructions page */
638 if(parameter==NULL)
640 /* if not launched as a viewer, use default puzzle, and show help */
641 picmode = PICMODE_DEFAULT_PICTURE;
643 /* print title */
644 rb->lcd_getstringsize((unsigned char *)"Sliding Puzzle", &w, &h);
645 w = (w+1)/2;
646 h = (h+1)/2;
647 rb->lcd_clear_display();
648 rb->lcd_putsxy(LCD_WIDTH/2-w, (LCD_HEIGHT/2)-h,
649 (unsigned char *)"Sliding Puzzle");
650 rb->lcd_update();
651 rb->sleep(HZ);
653 /* print instructions */
654 rb->lcd_clear_display();
655 rb->lcd_setfont(FONT_SYSFIXED);
656 #if CONFIG_KEYPAD == RECORDER_PAD || CONFIG_KEYPAD == ARCHOS_AV300_PAD
657 rb->lcd_putsxy(3, 18, "[OFF] to stop");
658 rb->lcd_putsxy(3, 28, "[F1] shuffle");
659 rb->lcd_putsxy(3, 38, "[F2] change pic");
660 #elif CONFIG_KEYPAD == ONDIO_PAD
661 rb->lcd_putsxy(0, 18, "[OFF] to stop");
662 rb->lcd_putsxy(0, 28, "[MODE..] shuffle");
663 rb->lcd_putsxy(0, 38, "[MODE] change pic");
664 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
665 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
666 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
667 rb->lcd_putsxy(0, 18, "[S-MENU] to stop");
668 rb->lcd_putsxy(0, 28, "[S-LEFT] shuffle");
669 rb->lcd_putsxy(0, 38, "[S-RIGHT] change pic");
670 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
671 (CONFIG_KEYPAD == IRIVER_H300_PAD)
672 rb->lcd_putsxy(0, 18, "[STOP] to stop");
673 rb->lcd_putsxy(0, 28, "[SELECT] shuffle");
674 rb->lcd_putsxy(0, 38, "[PLAY] change pic");
675 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
676 rb->lcd_putsxy(0, 18, "[OFF] to stop");
677 rb->lcd_putsxy(0, 28, "[REC] shuffle");
678 rb->lcd_putsxy(0, 38, "[PLAY] change pic");
679 #elif CONFIG_KEYPAD == GIGABEAT_PAD
680 rb->lcd_putsxy(0, 18, "[OFF] to stop");
681 rb->lcd_putsxy(0, 28, "[SELECT] shuffle");
682 rb->lcd_putsxy(0, 38, "[A] change pic");
683 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
684 (CONFIG_KEYPAD == SANSA_C200_PAD)
685 rb->lcd_putsxy(0, 18, "[OFF] to stop");
686 rb->lcd_putsxy(0, 28, "[REC] shuffle");
687 rb->lcd_putsxy(0, 38, "[SELECT] change pic");
688 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
689 rb->lcd_putsxy(0, 18, "[OFF] to stop");
690 rb->lcd_putsxy(0, 28, "[REW] shuffle");
691 rb->lcd_putsxy(0, 38, "[PLAY] change pic");
692 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
693 rb->lcd_putsxy(0, 18, "[REC] to stop");
694 rb->lcd_putsxy(0, 28, "[MODE] shuffle");
695 rb->lcd_putsxy(0, 38, "[MENU] change pic");
696 #endif
697 #ifdef HAVE_TOUCHSCREEN
698 rb->lcd_putsxy(0, 18, PUZZLE_QUIT_TEXT " to stop");
699 rb->lcd_putsxy(0, 28, PUZZLE_SHUFFLE_TEXT " shuffle");
700 rb->lcd_putsxy(0, 38, PUZZLE_PICTURE_TEXT " change pic");
701 #endif
702 #ifdef HAVE_ALBUMART
703 rb->lcd_putsxy(0,48," pic->albumart->num");
704 #else
705 rb->lcd_putsxy(0,48," pic<->num");
706 #endif
707 rb->lcd_update();
708 rb->button_get_w_tmo(HZ*2);
711 hole = INITIAL_HOLE;
713 if( !load_resize_bitmap() )
715 rb->lcd_clear_display();
716 rb->splash(HZ*2,"Failed to load bitmap!");
717 return PLUGIN_OK;
720 /* Calculate possible font sizes and text positions */
721 rb->lcd_setfont(FONT_UI);
722 rb->lcd_getstringsize("15", &w, &h);
723 if ((w > (SPOTS_WIDTH-2)) || (h > (SPOTS_HEIGHT-2)))
724 num_font = FONT_SYSFIXED;
726 #if LCD_WIDTH > LCD_HEIGHT
727 rb->lcd_getstringsize("Moves", &w, &h);
728 if (w > (LCD_WIDTH-IMAGE_WIDTH-1))
729 moves_font = FONT_SYSFIXED;
730 rb->lcd_setfont(moves_font);
731 rb->lcd_getstringsize("Moves", &w, &h);
732 moves_y = 10 + h;
733 #else
734 rb->lcd_getstringsize("Moves: 999", &w, &h);
735 if ((w > LCD_WIDTH) || (h > (LCD_HEIGHT-IMAGE_HEIGHT-1)))
736 moves_font = FONT_SYSFIXED;
737 rb->lcd_setfont(moves_font);
738 rb->lcd_getstringsize("Moves: 999", &w, &h);
739 moves_y = (IMAGE_HEIGHT+1+(LCD_HEIGHT-IMAGE_HEIGHT-1)/2) - h / 2;
740 #endif
741 for (i=0; i<NUM_SPOTS; i++)
742 spots[i]=(i+1);
744 #ifdef HAVE_LCD_COLOR
745 rb->lcd_set_background(LCD_BLACK);
746 rb->lcd_set_foreground(LCD_WHITE);
747 rb->lcd_set_backdrop(NULL);
748 #elif LCD_DEPTH > 1
749 rb->lcd_set_background(LCD_WHITE);
750 rb->lcd_set_foreground(LCD_BLACK);
751 rb->lcd_set_backdrop(NULL);
752 #endif
754 draw_playfield();
755 rb->sleep(HZ*2);
757 return puzzle_loop();
760 #endif