A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 2274 lines 74 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2004-2007 Antoine Cellerier <dionoea @t videolan d.t org> 11 * 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. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22#include "plugin.h" 23#include "lib/playback_control.h" 24#include "lib/configfile.h" 25#include "lib/display_text.h" 26#include "button.h" 27#include "lcd.h" 28 29#define min(a,b) (a<b?a:b) 30 31/** 32 * Key definitions 33 */ 34 35#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ 36 (CONFIG_KEYPAD == IRIVER_H300_PAD) 37# define SOL_QUIT BUTTON_OFF 38# define SOL_UP BUTTON_UP 39# define SOL_DOWN BUTTON_DOWN 40# define SOL_LEFT BUTTON_LEFT 41# define SOL_RIGHT BUTTON_RIGHT 42# define SOL_MOVE_PRE BUTTON_SELECT 43# define SOL_MOVE (BUTTON_SELECT | BUTTON_REL) 44# define SOL_DRAW BUTTON_MODE 45# define SOL_REM2CUR (BUTTON_LEFT | BUTTON_ON) 46# define SOL_CUR2STACK_PRE BUTTON_SELECT 47# define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT) 48# define SOL_REM2STACK (BUTTON_RIGHT | BUTTON_ON) 49# define SOL_REM BUTTON_REC 50# define SOL_RC_QUIT BUTTON_RC_STOP 51# define HK_MOVE "NAVI" 52# define HK_DRAW "A-B" 53# define HK_REM2CUR "PLAY+LEFT" 54# define HK_CUR2STACK "NAVI.." 55# define HK_REM2STACK "PLAY+RIGHT" 56 57#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ 58 (CONFIG_KEYPAD == IPOD_1G2G_PAD) 59# define SOL_QUIT (BUTTON_SELECT | BUTTON_REPEAT) 60# define SOL_UP BUTTON_SCROLL_BACK 61# define SOL_DOWN BUTTON_SCROLL_FWD 62# define SOL_LEFT_PRE BUTTON_LEFT 63# define SOL_LEFT (BUTTON_LEFT | BUTTON_REL) 64# define SOL_RIGHT_PRE BUTTON_RIGHT 65# define SOL_RIGHT (BUTTON_RIGHT | BUTTON_REL) 66# define SOL_MOVE_PRE BUTTON_SELECT 67# define SOL_MOVE (BUTTON_SELECT | BUTTON_REL) 68# define SOL_DRAW_PRE BUTTON_MENU 69# define SOL_DRAW (BUTTON_MENU | BUTTON_REL) 70# define SOL_REM2CUR BUTTON_PLAY 71# define SOL_CUR2STACK_PRE BUTTON_MENU 72# define SOL_CUR2STACK (BUTTON_MENU | BUTTON_REPEAT) 73# define SOL_REM2STACK_PRE BUTTON_RIGHT 74# define SOL_REM2STACK (BUTTON_RIGHT | BUTTON_REPEAT) 75# define HK_UD "SCROLL U/D" 76# define HK_MOVE "SELECT" 77# define HK_DRAW "MENU" 78# define HK_REM2CUR "PLAY" 79# define HK_CUR2STACK "MENU.." 80# define HK_REM2STACK "RIGHT.." 81 82#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) 83# define SOL_QUIT BUTTON_POWER 84# define SOL_UP BUTTON_UP 85# define SOL_DOWN BUTTON_DOWN 86# define SOL_LEFT BUTTON_LEFT 87# define SOL_RIGHT BUTTON_RIGHT 88# define SOL_MOVE_PRE BUTTON_SELECT 89# define SOL_MOVE (BUTTON_SELECT | BUTTON_REL) 90# define SOL_DRAW_PRE BUTTON_PLAY 91# define SOL_DRAW (BUTTON_PLAY | BUTTON_REL) 92# define SOL_REM2CUR_PRE BUTTON_PLAY 93# define SOL_REM2CUR (BUTTON_PLAY | BUTTON_REPEAT) 94# define SOL_CUR2STACK_PRE BUTTON_SELECT 95# define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT) 96# define SOL_REM2STACK BUTTON_REC 97# define HK_MOVE "SELECT" 98# define HK_DRAW "PLAY" 99# define HK_REM2CUR "PLAY.." 100# define HK_CUR2STACK "SELECT.." 101# define HK_REM2STACK "REC" 102 103#elif (CONFIG_KEYPAD == GIGABEAT_PAD) 104# define SOL_QUIT BUTTON_POWER 105# define SOL_UP BUTTON_UP 106# define SOL_DOWN BUTTON_DOWN 107# define SOL_LEFT BUTTON_LEFT 108# define SOL_RIGHT BUTTON_RIGHT 109# define SOL_MOVE_PRE BUTTON_SELECT 110# define SOL_MOVE (BUTTON_SELECT | BUTTON_REL) 111# define SOL_DRAW BUTTON_MENU 112# define SOL_REM2CUR (BUTTON_LEFT | BUTTON_A) 113# define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT) 114# define SOL_REM2STACK (BUTTON_RIGHT | BUTTON_A) 115# define HK_MOVE "SELECT" 116# define HK_DRAW "MENU" 117# define HK_REM2CUR "A+LEFT" 118# define HK_CUR2STACK "SELECT.." 119# define HK_REM2STACK "A+RIGHT" 120 121#elif (CONFIG_KEYPAD == SANSA_E200_PAD) 122# define SOL_QUIT BUTTON_POWER 123# define SOL_UP BUTTON_UP 124# define SOL_DOWN BUTTON_DOWN 125# define SOL_LEFT BUTTON_SCROLL_BACK 126# define SOL_RIGHT BUTTON_SCROLL_FWD 127# define SOL_MOVE BUTTON_SELECT 128# define SOL_DRAW BUTTON_REC 129# define SOL_REM2CUR BUTTON_LEFT 130# define SOL_CUR2STACK_PRE BUTTON_REC 131# define SOL_CUR2STACK (BUTTON_REC | BUTTON_RIGHT) 132# define SOL_REM2STACK BUTTON_RIGHT 133# define HK_MOVE "SELECT" 134# define HK_DRAW "REC" 135# define HK_REM2CUR "LEFT" 136# define HK_CUR2STACK "DOUBLE SELECT" 137# define HK_REM2STACK "RIGHT" 138 139#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD) 140# define SOL_QUIT (BUTTON_HOME|BUTTON_REPEAT) 141# define SOL_UP BUTTON_UP 142# define SOL_DOWN BUTTON_DOWN 143# define SOL_LEFT BUTTON_SCROLL_BACK 144# define SOL_RIGHT BUTTON_SCROLL_FWD 145# define SOL_MOVE (BUTTON_SELECT|BUTTON_REL) 146# define SOL_DRAW (BUTTON_HOME|BUTTON_REL) 147# define SOL_REM2CUR BUTTON_LEFT 148# define SOL_CUR2STACK_PRE (BUTTON_RIGHT | BUTTON_REPEAT) 149# define SOL_CUR2STACK BUTTON_RIGHT 150# define SOL_REM2STACK (BUTTON_LEFT|BUTTON_REPEAT) 151# define SOL_REM2STACK_PRE BUTTON_LEFT 152# define HK_MOVE "SHORT SELECT" 153# define HK_DRAW "SHORT HOME" 154# define HK_REM2CUR "LEFT" 155# define HK_CUR2STACK "DOUBLE SELECT" 156# define HK_REM2STACK "LEFT" 157 158#elif (CONFIG_KEYPAD == SANSA_C200_PAD) 159# define SOL_QUIT BUTTON_POWER 160# define SOL_UP BUTTON_UP 161# define SOL_DOWN BUTTON_DOWN 162# define SOL_LEFT BUTTON_LEFT 163# define SOL_RIGHT BUTTON_RIGHT 164# define SOL_MOVE_PRE BUTTON_SELECT 165# define SOL_MOVE (BUTTON_SELECT | BUTTON_REL) 166# define SOL_DRAW BUTTON_VOL_DOWN 167# define SOL_REM2CUR BUTTON_REC 168# define SOL_CUR2STACK_PRE BUTTON_SELECT 169# define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT) 170# define SOL_REM2STACK BUTTON_VOL_UP 171# define HK_MOVE "SELECT" 172# define HK_DRAW "REC" 173# define HK_REM2CUR "LEFT" 174# define HK_CUR2STACK "DOUBLE SELECT" 175# define HK_REM2STACK "RIGHT" 176 177#elif CONFIG_KEYPAD == SANSA_CLIP_PAD 178# define SOL_QUIT BUTTON_POWER 179# define SOL_UP BUTTON_UP 180# define SOL_DOWN BUTTON_DOWN 181# define SOL_LEFT BUTTON_LEFT 182# define SOL_RIGHT BUTTON_RIGHT 183# define SOL_MOVE_PRE BUTTON_SELECT 184# define SOL_MOVE (BUTTON_SELECT | BUTTON_REL) 185# define SOL_DRAW BUTTON_HOME 186# define SOL_REM2CUR BUTTON_VOL_DOWN 187# define SOL_CUR2STACK_PRE BUTTON_SELECT 188# define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT) 189# define SOL_REM2STACK BUTTON_VOL_UP 190# define HK_MOVE "SELECT" 191# define HK_DRAW "HOME" 192# define HK_REM2CUR "LEFT" 193# define HK_CUR2STACK "DOUBLE SELECT" 194# define HK_REM2STACK "RIGHT" 195 196#elif CONFIG_KEYPAD == SANSA_M200_PAD 197# define SOL_QUIT BUTTON_POWER 198# define SOL_UP BUTTON_UP 199# define SOL_DOWN BUTTON_DOWN 200# define SOL_LEFT BUTTON_LEFT 201# define SOL_RIGHT BUTTON_RIGHT 202# define SOL_MOVE_PRE BUTTON_SELECT 203# define SOL_MOVE (BUTTON_SELECT | BUTTON_REL) 204# define SOL_DRAW (BUTTON_SELECT | BUTTON_UP) 205# define SOL_REM2CUR BUTTON_VOL_DOWN 206# define SOL_CUR2STACK_PRE BUTTON_SELECT 207# define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT) 208# define SOL_REM2STACK BUTTON_VOL_UP 209# define HK_MOVE "SELECT" 210# define HK_DRAW "SELECT + UP" 211# define HK_REM2CUR "LEFT" 212# define HK_CUR2STACK "DOUBLE SELECT" 213# define HK_REM2STACK "RIGHT" 214 215#elif (CONFIG_KEYPAD == IRIVER_H10_PAD) 216# define SOL_QUIT BUTTON_POWER 217# define SOL_UP BUTTON_SCROLL_UP 218# define SOL_DOWN BUTTON_SCROLL_DOWN 219# define SOL_LEFT_PRE BUTTON_LEFT 220# define SOL_LEFT (BUTTON_LEFT | BUTTON_REL) 221# define SOL_RIGHT_PRE BUTTON_RIGHT 222# define SOL_RIGHT (BUTTON_RIGHT | BUTTON_REL) 223# define SOL_MOVE BUTTON_PLAY 224# define SOL_DRAW_PRE BUTTON_LEFT 225# define SOL_DRAW (BUTTON_LEFT | BUTTON_REPEAT) 226# define SOL_REM2CUR BUTTON_FF 227# define SOL_CUR2STACK BUTTON_REW 228# define SOL_REM2STACK_PRE BUTTON_RIGHT 229# define SOL_REM2STACK (BUTTON_RIGHT | BUTTON_REPEAT) 230# define HK_MOVE "PLAY" 231# define HK_DRAW "LEFT.." 232# define HK_REM2CUR "FF" 233# define HK_CUR2STACK "REW" 234# define HK_REM2STACK "RIGHT.." 235 236#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) 237# define SOL_QUIT BUTTON_BACK 238# define SOL_UP BUTTON_UP 239# define SOL_DOWN BUTTON_DOWN 240# define SOL_LEFT BUTTON_LEFT 241# define SOL_RIGHT BUTTON_RIGHT 242# define SOL_MOVE_PRE BUTTON_SELECT 243# define SOL_MOVE (BUTTON_SELECT | BUTTON_REL) 244# define SOL_DRAW BUTTON_MENU 245# define SOL_REM2CUR (BUTTON_LEFT | BUTTON_SELECT) 246# define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT) 247# define SOL_REM2STACK (BUTTON_RIGHT | BUTTON_SELECT) 248# define HK_MOVE "SELECT" 249# define HK_DRAW "MENU" 250# define HK_REM2CUR "SELECT+LEFT" 251# define HK_CUR2STACK "SELECT.." 252# define HK_REM2STACK "SELECT+RIGHT" 253 254#elif (CONFIG_KEYPAD == MROBE100_PAD) 255# define SOL_QUIT BUTTON_POWER 256# define SOL_UP BUTTON_UP 257# define SOL_DOWN BUTTON_DOWN 258# define SOL_LEFT BUTTON_LEFT 259# define SOL_RIGHT BUTTON_RIGHT 260# define SOL_MOVE_PRE BUTTON_SELECT 261# define SOL_MOVE (BUTTON_SELECT | BUTTON_REL) 262# define SOL_DRAW BUTTON_MENU 263# define SOL_REM2CUR (BUTTON_LEFT | BUTTON_DISPLAY) 264# define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT) 265# define SOL_REM2STACK (BUTTON_RIGHT | BUTTON_DISPLAY) 266# define HK_MOVE "SELECT" 267# define HK_DRAW "MENU" 268# define HK_REM2CUR "DISPLAY+LEFT" 269# define HK_CUR2STACK "SELECT.." 270# define HK_REM2STACK "DISPLAY+RIGHT" 271 272#elif CONFIG_KEYPAD == IAUDIO_M3_PAD 273# define SOL_QUIT BUTTON_RC_REC 274# define SOL_UP BUTTON_RC_VOL_UP 275# define SOL_DOWN BUTTON_RC_VOL_DOWN 276# define SOL_LEFT BUTTON_RC_REW 277# define SOL_RIGHT BUTTON_RC_FF 278# define SOL_MOVE BUTTON_RC_PLAY 279# define SOL_DRAW_PRE BUTTON_RC_MENU 280# define SOL_DRAW (BUTTON_RC_MENU | BUTTON_REL) 281# define SOL_REM2CUR_PRE BUTTON_RC_MENU 282# define SOL_REM2CUR (BUTTON_RC_MENU | BUTTON_REPEAT) 283# define SOL_CUR2STACK_PRE BUTTON_RC_MODE 284# define SOL_CUR2STACK (BUTTON_RC_MODE | BUTTON_REL) 285# define SOL_REM2STACK_PRE BUTTON_RC_MODE 286# define SOL_REM2STACK (BUTTON_RC_MODE | BUTTON_REPEAT) 287# define HK_LR "REW/FF" 288# define HK_UD "VOL UP/DOWN" 289# define HK_MOVE "PLAY" 290# define HK_DRAW "MENU" 291# define HK_REM2CUR "MENU.." 292# define HK_CUR2STACK "MODE" 293# define HK_REM2STACK "MODE.." 294 295#elif (CONFIG_KEYPAD == COWON_D2_PAD) 296# define SOL_QUIT BUTTON_POWER 297 298#elif CONFIG_KEYPAD == CREATIVEZVM_PAD 299# define SOL_QUIT BUTTON_BACK 300# define SOL_UP BUTTON_UP 301# define SOL_DOWN BUTTON_DOWN 302# define SOL_LEFT BUTTON_LEFT 303# define SOL_RIGHT BUTTON_RIGHT 304# define SOL_MOVE_PRE BUTTON_SELECT 305# define SOL_MOVE (BUTTON_SELECT | BUTTON_REL) 306# define SOL_DRAW BUTTON_MENU 307# define SOL_REM2CUR (BUTTON_LEFT | BUTTON_SELECT) 308# define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT) 309# define SOL_REM2STACK (BUTTON_RIGHT | BUTTON_SELECT) 310# define HK_MOVE "MIDDLE" 311# define HK_DRAW "MENU" 312# define HK_REM2CUR "PLAY+LEFT" 313# define HK_CUR2STACK "PLAY.." 314# define HK_REM2STACK "PLAY+RIGHT" 315 316#elif (CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD) 317# define SOL_QUIT BUTTON_POWER 318# define SOL_UP BUTTON_UP 319# define SOL_DOWN BUTTON_DOWN 320# define SOL_LEFT BUTTON_BACK 321# define SOL_RIGHT BUTTON_MENU 322# define SOL_MOVE (BUTTON_PLAY|BUTTON_REL) 323# define SOL_DRAW (BUTTON_PLAY|BUTTON_REPEAT) 324# define SOL_REM2CUR BUTTON_VOL_DOWN 325# define SOL_CUR2STACK_PRE (BUTTON_VOL_UP | BUTTON_REPEAT) 326# define SOL_CUR2STACK BUTTON_VOL_UP 327# define SOL_REM2STACK (BUTTON_VOL_DOWN|BUTTON_REPEAT) 328# define SOL_REM2STACK_PRE BUTTON_VOL_DOWN 329 330# define HK_MOVE "SHORT PLAY" 331# define HK_DRAW "LONG PLAY" 332# define HK_REM2CUR "VOLUME-" 333# define HK_CUR2STACK "VOLUME+" 334# define HK_REM2STACK "LONG VOLUME-" 335 336#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD 337# define SOL_QUIT BUTTON_POWER 338# define SOL_UP BUTTON_UP 339# define SOL_DOWN BUTTON_DOWN 340# define SOL_LEFT BUTTON_LEFT 341# define SOL_RIGHT BUTTON_RIGHT 342# define SOL_MOVE_PRE BUTTON_SELECT 343# define SOL_MOVE (BUTTON_SELECT | BUTTON_REL) 344# define SOL_DRAW BUTTON_MENU 345# define SOL_REM2CUR (BUTTON_LEFT | BUTTON_VIEW) 346# define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT) 347# define SOL_REM2STACK (BUTTON_RIGHT | BUTTON_VIEW) 348# define HK_MOVE "SELECT" 349# define HK_DRAW "MENU" 350# define HK_REM2CUR "VIEW+LEFT" 351# define HK_CUR2STACK "SELECT.." 352# define HK_REM2STACK "VIEW+RIGHT" 353 354#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD 355# define SOL_QUIT BUTTON_POWER 356# define SOL_UP BUTTON_UP 357# define SOL_DOWN BUTTON_DOWN 358# define SOL_LEFT BUTTON_PREV 359# define SOL_RIGHT BUTTON_NEXT 360# define SOL_MOVE_PRE BUTTON_PLAY 361# define SOL_MOVE (BUTTON_PLAY | BUTTON_REL) 362# define SOL_DRAW BUTTON_MENU 363# define SOL_REM2CUR BUTTON_LEFT 364# define SOL_CUR2STACK (BUTTON_PLAY | BUTTON_REPEAT) 365# define SOL_REM2STACK BUTTON_RIGHT 366# define HK_MOVE "PLAY" 367# define HK_DRAW "MENU" 368# define HK_REM2CUR "LEFT" 369# define HK_CUR2STACK "PLAY.." 370# define HK_REM2STACK "RIGHT" 371 372#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD 373# define SOL_QUIT BUTTON_POWER 374# define SOL_UP BUTTON_UP 375# define SOL_DOWN BUTTON_DOWN 376# define SOL_LEFT BUTTON_PREV 377# define SOL_RIGHT BUTTON_NEXT 378# define SOL_MOVE_PRE BUTTON_PLAY 379# define SOL_MOVE (BUTTON_PLAY | BUTTON_REL) 380# define SOL_DRAW BUTTON_MENU 381# define SOL_REM2CUR BUTTON_LEFT 382# define SOL_CUR2STACK (BUTTON_PLAY | BUTTON_REPEAT) 383# define SOL_REM2STACK BUTTON_RIGHT 384# define HK_MOVE "PLAY" 385# define HK_DRAW "MENU" 386# define HK_REM2CUR "LEFT" 387# define HK_CUR2STACK "PLAY..." 388# define HK_REM2STACK "RIGHT" 389 390#elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \ 391(CONFIG_KEYPAD == ONDAVX777_PAD) || \ 392CONFIG_KEYPAD == MROBE500_PAD 393# define SOL_QUIT BUTTON_POWER 394 395#elif CONFIG_KEYPAD == SAMSUNG_YH820_PAD 396# define SOL_QUIT BUTTON_REW 397# define SOL_UP BUTTON_UP 398# define SOL_DOWN BUTTON_DOWN 399# define SOL_LEFT BUTTON_LEFT 400# define SOL_RIGHT BUTTON_RIGHT 401# define SOL_MOVE BUTTON_PLAY 402# define SOL_DRAW BUTTON_FFWD 403# define SOL_REM2CUR (BUTTON_REC | BUTTON_DOWN) 404# define SOL_CUR2STACK (BUTTON_REC | BUTTON_UP) 405# define SOL_REM2STACK (BUTTON_REC | BUTTON_RIGHT) 406# define HK_MOVE "PLAY" 407# define HK_DRAW "FFWD" 408# define HK_REM2CUR "REC+DOWN" 409# define HK_CUR2STACK "REC+UP" 410# define HK_REM2STACK "REC+RIGHT" 411 412#elif CONFIG_KEYPAD == SAMSUNG_YH92X_PAD 413# define SOL_QUIT BUTTON_REW 414# define SOL_UP BUTTON_UP 415# define SOL_DOWN BUTTON_DOWN 416# define SOL_LEFT BUTTON_LEFT 417# define SOL_RIGHT BUTTON_RIGHT 418# define SOL_MOVE_PRE BUTTON_PLAY 419# define SOL_MOVE (BUTTON_PLAY | BUTTON_REL) 420# define SOL_DRAW BUTTON_FFWD 421# define SOL_REM2CUR (BUTTON_PLAY | BUTTON_DOWN) 422# define SOL_CUR2STACK (BUTTON_PLAY | BUTTON_UP) 423# define SOL_REM2STACK (BUTTON_PLAY | BUTTON_RIGHT) 424# define HK_MOVE "PLAY" 425# define HK_DRAW "FFWD" 426# define HK_REM2CUR "PLAY+DOWN" 427# define HK_CUR2STACK "PLAY+UP" 428# define HK_REM2STACK "PLAY+RIGHT" 429 430#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD 431# define SOL_QUIT BUTTON_REC 432# define SOL_UP BUTTON_UP 433# define SOL_DOWN BUTTON_DOWN 434# define SOL_LEFT BUTTON_PREV 435# define SOL_RIGHT BUTTON_NEXT 436# define SOL_MOVE_PRE BUTTON_OK 437# define SOL_MOVE (BUTTON_OK | BUTTON_REL) 438# define SOL_DRAW BUTTON_MENU 439# define SOL_REM2CUR BUTTON_CANCEL 440# define SOL_CUR2STACK BUTTON_PLAY 441# define SOL_REM2STACK (BUTTON_PLAY | BUTTON_REPEAT) 442# define HK_MOVE "OK" 443# define HK_DRAW "MENU" 444# define HK_REM2CUR "CANCEL" 445# define HK_CUR2STACK "PLAY" 446# define HK_REM2STACK "PLAY..." 447 448#elif CONFIG_KEYPAD == MPIO_HD200_PAD 449# define SOL_QUIT (BUTTON_REC | BUTTON_PLAY) 450# define SOL_UP BUTTON_REW 451# define SOL_DOWN BUTTON_FF 452# define SOL_LEFT BUTTON_VOL_DOWN 453# define SOL_RIGHT BUTTON_VOL_UP 454# define SOL_MOVE_PRE BUTTON_FUNC 455# define SOL_MOVE (BUTTON_FUNC | BUTTON_REL) 456# define SOL_DRAW BUTTON_REC 457# define SOL_REM2CUR (BUTTON_REC | BUTTON_REPEAT) 458# define SOL_CUR2STACK BUTTON_PLAY 459# define SOL_REM2STACK (BUTTON_PLAY | BUTTON_REPEAT) 460# define HK_MOVE "FUNC" 461# define HK_DRAW "REC" 462# define HK_REM2CUR "REC.." 463# define HK_CUR2STACK "PLAY" 464# define HK_REM2STACK "PLAY...." 465 466#elif CONFIG_KEYPAD == MPIO_HD300_PAD 467# define SOL_QUIT (BUTTON_MENU | BUTTON_REPEAT) 468# define SOL_UP BUTTON_UP 469# define SOL_DOWN BUTTON_DOWN 470# define SOL_LEFT BUTTON_REW 471# define SOL_RIGHT BUTTON_FF 472# define SOL_MOVE_PRE BUTTON_ENTER 473# define SOL_MOVE (BUTTON_ENTER | BUTTON_REL) 474# define SOL_DRAW BUTTON_MENU 475# define SOL_REM2CUR (BUTTON_PLAY | BUTTON_REL) 476# define SOL_CUR2STACK BUTTON_REC 477# define SOL_REM2STACK (BUTTON_PLAY | BUTTON_REPEAT) 478# define HK_MOVE "ENTER" 479# define HK_DRAW "MENU" 480# define HK_REM2CUR "PLAY" 481# define HK_CUR2STACK "ENTER..." 482# define HK_REM2STACK "PLAY...." 483 484#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD 485# define SOL_QUIT BUTTON_POWER 486# define SOL_UP BUTTON_UP 487# define SOL_DOWN BUTTON_DOWN 488# define SOL_LEFT BUTTON_LEFT 489# define SOL_RIGHT BUTTON_RIGHT 490# define SOL_MOVE BUTTON_SELECT 491# define SOL_DRAW BUTTON_BACK 492# define SOL_REM2CUR BUTTON_BOTTOMLEFT 493# define SOL_CUR2STACK BUTTON_PLAYPAUSE|BUTTON_REL 494# define SOL_REM2STACK BUTTON_PLAYPAUSE|BUTTON_REPEAT 495# define HK_MOVE "SELECT" 496# define HK_DRAW "BACK" 497# define HK_REM2CUR "BOTTOM-LEFT" 498# define HK_CUR2STACK "PLAY-PAUSE" 499# define HK_REM2STACK "BOTTOM-RIGHT" 500 501#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD) 502# define SOL_QUIT BUTTON_POWER 503# define SOL_UP BUTTON_UP 504# define SOL_DOWN BUTTON_DOWN 505# define SOL_LEFT BUTTON_SCROLL_BACK 506# define SOL_RIGHT BUTTON_SCROLL_FWD 507# define SOL_MOVE BUTTON_SELECT 508# define SOL_DRAW BUTTON_VOL_UP 509# define SOL_REM2CUR BUTTON_LEFT 510# define SOL_CUR2STACK_PRE BUTTON_VOL_DOWN 511# define SOL_CUR2STACK BUTTON_NEXT 512# define SOL_REM2STACK BUTTON_PREV 513# define HK_MOVE "SELECT" 514# define HK_DRAW "Vol+" 515# define HK_REM2CUR "LEFT" 516# define HK_CUR2STACK "NEXT" 517# define HK_REM2STACK "PREV" 518 519#elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD) 520# define SOL_QUIT BUTTON_BACK 521# define SOL_UP BUTTON_UP 522# define SOL_DOWN BUTTON_DOWN 523# define SOL_LEFT BUTTON_LEFT 524# define SOL_RIGHT BUTTON_RIGHT 525# define SOL_MOVE_PRE BUTTON_SELECT 526# define SOL_MOVE (BUTTON_SELECT | BUTTON_REL) 527# define SOL_DRAW BUTTON_MENU 528# define SOL_REM2CUR (BUTTON_USER | BUTTON_REPEAT) 529# define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT) 530# define SOL_REM2STACK BUTTON_POWER 531# define HK_MOVE "Select" 532# define HK_DRAW "Menu" 533# define HK_REM2CUR "Long User" 534# define HK_CUR2STACK "Long Select.." 535# define HK_REM2STACK "Power" 536 537#elif (CONFIG_KEYPAD == HM60X_PAD) 538# define SOL_QUIT BUTTON_POWER 539# define SOL_UP BUTTON_UP 540# define SOL_DOWN BUTTON_DOWN 541# define SOL_LEFT BUTTON_LEFT 542# define SOL_RIGHT BUTTON_RIGHT 543# define SOL_MOVE_PRE BUTTON_SELECT 544# define SOL_MOVE (BUTTON_POWER | BUTTON_SELECT) 545# define SOL_DRAW (BUTTON_POWER | BUTTON_UP) 546# define SOL_REM2CUR (BUTTON_POWER | BUTTON_DOWN) 547# define SOL_CUR2STACK (BUTTON_POWER | BUTTON_LEFT) 548# define SOL_REM2STACK (BUTTON_POWER | BUTTON_RIGHT) 549# define HK_MOVE "SELECT + POWER" 550# define HK_DRAW "UP + POWER" 551# define HK_REM2CUR "DOWN + POWER" 552# define HK_CUR2STACK "LEFT + POWER" 553# define HK_REM2STACK "RIGHT + POWER" 554 555#elif (CONFIG_KEYPAD == HM801_PAD) 556# define SOL_QUIT BUTTON_POWER 557# define SOL_UP BUTTON_UP 558# define SOL_DOWN BUTTON_DOWN 559# define SOL_LEFT BUTTON_LEFT 560# define SOL_RIGHT BUTTON_RIGHT 561# define SOL_MOVE_PRE BUTTON_PREV 562# define SOL_MOVE BUTTON_NEXT 563# define SOL_DRAW BUTTON_PLAY 564# define SOL_REM2CUR BUTTON_SELECT 565# define SOL_CUR2STACK (BUTTON_POWER | BUTTON_LEFT) 566# define SOL_REM2STACK (BUTTON_POWER | BUTTON_RIGHT) 567# define HK_MOVE "PREV" 568# define HK_DRAW "PLAY" 569# define HK_REM2CUR "SELECT" 570# define HK_CUR2STACK "POWER + LEFT" 571# define HK_REM2STACK "POWER + RIGHT" 572 573#elif (CONFIG_KEYPAD == SONY_NWZ_PAD) 574#define SOL_QUIT BUTTON_BACK 575#define SOL_UP BUTTON_UP 576#define SOL_DOWN BUTTON_DOWN 577#define SOL_LEFT BUTTON_LEFT 578#define SOL_RIGHT BUTTON_RIGHT 579#define SOL_MOVE BUTTON_PLAY 580#define SOL_DRAW (BUTTON_POWER|BUTTON_UP) 581#define SOL_REM2CUR (BUTTON_POWER|BUTTON_DOWN) 582#define SOL_CUR2STACK (BUTTON_POWER|BUTTON_LEFT) 583#define SOL_REM2STACK (BUTTON_POWER|BUTTON_RIGHT) 584#define HK_MOVE "Play" 585#define HK_DRAW "Option+Up" 586#define HK_REM2CUR "Option+Down" 587#define HK_CUR2STACK "Option+Left" 588#define HK_REM2STACK "Option+Right" 589 590#elif (CONFIG_KEYPAD == AGPTEK_ROCKER_PAD) 591#define SOL_QUIT BUTTON_POWER 592#define SOL_UP BUTTON_UP 593#define SOL_DOWN BUTTON_DOWN 594#define SOL_LEFT BUTTON_LEFT 595#define SOL_RIGHT BUTTON_RIGHT 596#define SOL_MOVE BUTTON_SELECT 597#define SOL_DRAW (BUTTON_VOLUP|BUTTON_UP) 598#define SOL_REM2CUR (BUTTON_VOLUP|BUTTON_DOWN) 599#define SOL_CUR2STACK (BUTTON_VOLUP|BUTTON_LEFT) 600#define SOL_REM2STACK (BUTTON_VOLUP|BUTTON_RIGHT) 601#define HK_MOVE "Select" 602#define HK_DRAW "Option+Up" 603#define HK_REM2CUR "Option+Down" 604#define HK_CUR2STACK "Option+Left" 605#define HK_REM2STACK "Option+Right" 606 607#elif (CONFIG_KEYPAD == CREATIVE_ZEN_PAD) 608#define SOL_QUIT BUTTON_POWER 609#define SOL_UP BUTTON_UP 610#define SOL_DOWN BUTTON_DOWN 611#define SOL_LEFT BUTTON_LEFT 612#define SOL_RIGHT BUTTON_RIGHT 613#define SOL_MOVE BUTTON_SELECT 614#define SOL_DRAW BUTTON_PLAYPAUSE 615#define SOL_REM2CUR BUTTON_BACK 616#define SOL_CUR2STACK BUTTON_MENU 617#define SOL_REM2STACK BUTTON_SHORTCUT 618#define HK_MOVE "Select" 619#define HK_DRAW "Play/pause" 620#define HK_REM2CUR "Back" 621#define HK_CUR2STACK "Menu" 622#define HK_REM2STACK "Shortcut" 623 624#elif (CONFIG_KEYPAD == DX50_PAD) 625# define SOL_QUIT (BUTTON_POWER | BUTTON_REL) 626 627#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD 628# define SOL_QUIT BUTTON_POWER 629 630#elif CONFIG_KEYPAD == XDUOO_X3_PAD 631# define SOL_QUIT BUTTON_POWER 632# define SOL_UP BUTTON_HOME 633# define SOL_DOWN BUTTON_OPTION 634# define SOL_LEFT BUTTON_PREV 635# define SOL_RIGHT BUTTON_NEXT 636# define SOL_MOVE_PRE BUTTON_PLAY 637# define SOL_MOVE (BUTTON_PLAY | BUTTON_REL) 638# define SOL_DRAW (BUTTON_POWER | BUTTON_REPEAT) 639# define SOL_REM2CUR BUTTON_VOL_DOWN 640# define SOL_CUR2STACK_PRE BUTTON_PLAY 641# define SOL_CUR2STACK (BUTTON_PLAY | BUTTON_REPEAT) 642# define SOL_REM2STACK BUTTON_VOL_UP 643# define HK_MOVE "PLAY" 644# define HK_DRAW "DBL HOME" 645# define HK_REM2CUR "PREV" 646# define HK_CUR2STACK "DBL PLAY" 647# define HK_REM2STACK "NEXT" 648 649#elif CONFIG_KEYPAD == XDUOO_X3II_PAD || CONFIG_KEYPAD == XDUOO_X20_PAD 650# define SOL_QUIT BUTTON_POWER 651# define SOL_UP BUTTON_HOME 652# define SOL_DOWN BUTTON_OPTION 653# define SOL_LEFT BUTTON_PREV 654# define SOL_RIGHT BUTTON_NEXT 655# define SOL_MOVE_PRE BUTTON_PLAY 656# define SOL_MOVE (BUTTON_PLAY | BUTTON_REL) 657# define SOL_DRAW (BUTTON_POWER | BUTTON_REPEAT) 658# define SOL_REM2CUR BUTTON_VOL_DOWN 659# define SOL_CUR2STACK_PRE BUTTON_PLAY 660# define SOL_CUR2STACK (BUTTON_PLAY | BUTTON_REPEAT) 661# define SOL_REM2STACK BUTTON_VOL_UP 662# define HK_MOVE "PLAY" 663# define HK_DRAW "DBL HOME" 664# define HK_REM2CUR "PREV" 665# define HK_CUR2STACK "DBL PLAY" 666# define HK_REM2STACK "NEXT" 667 668#elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD 669# define SOL_QUIT BUTTON_POWER 670# define SOL_UP BUTTON_HOME 671# define SOL_DOWN BUTTON_OPTION 672# define SOL_LEFT BUTTON_PREV 673# define SOL_RIGHT BUTTON_NEXT 674# define SOL_MOVE_PRE BUTTON_PLAY 675# define SOL_MOVE (BUTTON_PLAY | BUTTON_REL) 676# define SOL_DRAW (BUTTON_POWER | BUTTON_REPEAT) 677# define SOL_REM2CUR BUTTON_VOL_DOWN 678# define SOL_CUR2STACK_PRE BUTTON_PLAY 679# define SOL_CUR2STACK (BUTTON_PLAY | BUTTON_REPEAT) 680# define SOL_REM2STACK BUTTON_VOL_UP 681# define HK_MOVE "PLAY" 682# define HK_DRAW "DBL HOME" 683# define HK_REM2CUR "PREV" 684# define HK_CUR2STACK "DBL PLAY" 685# define HK_REM2STACK "NEXT" 686 687#elif CONFIG_KEYPAD == IHIFI_770_PAD || CONFIG_KEYPAD == IHIFI_800_PAD 688# define SOL_QUIT BUTTON_POWER 689# define SOL_UP BUTTON_PREV 690# define SOL_DOWN BUTTON_NEXT 691# define SOL_LEFT BUTTON_HOME 692# define SOL_RIGHT BUTTON_VOL_DOWN 693# define SOL_MOVE_PRE BUTTON_VOL_UP 694# define SOL_MOVE (BUTTON_PLAY | BUTTON_REL) 695# define SOL_DRAW (BUTTON_POWER | BUTTON_REPEAT) 696# define SOL_REM2CUR (BUTTON_POWER | BUTTON_VOL_DOWN) 697# define SOL_CUR2STACK_PRE BUTTON_PLAY 698# define SOL_CUR2STACK (BUTTON_PLAY | BUTTON_REPEAT) 699# define SOL_REM2STACK (BUTTON_POWER | BUTTON_VOL_UP) 700# define HK_MOVE "PLAY" 701# define HK_DRAW "DBL POWER" 702# define HK_REM2CUR "POWER" 703# define HK_CUR2STACK "DBL PLAY" 704# define HK_REM2STACK "POWER+" 705 706#elif CONFIG_KEYPAD == EROSQ_PAD 707# define SOL_QUIT BUTTON_POWER 708# define SOL_UP BUTTON_PREV 709# define SOL_DOWN BUTTON_NEXT 710# define SOL_LEFT BUTTON_SCROLL_BACK 711# define SOL_RIGHT BUTTON_SCROLL_FWD 712# define SOL_MOVE_PRE BUTTON_PLAY 713# define SOL_MOVE (BUTTON_PLAY | BUTTON_REL) 714# define SOL_DRAW (BUTTON_POWER | BUTTON_REPEAT) 715# define SOL_REM2CUR BUTTON_VOL_DOWN 716# define SOL_CUR2STACK_PRE BUTTON_PLAY 717# define SOL_CUR2STACK (BUTTON_PLAY | BUTTON_REPEAT) 718# define SOL_REM2STACK BUTTON_VOL_UP 719# define HK_MOVE "PLAY" 720# define HK_DRAW "DBL HOME" 721# define HK_REM2CUR "PREV" 722# define HK_CUR2STACK "DBL PLAY" 723# define HK_REM2STACK "NEXT" 724 725#elif CONFIG_KEYPAD == FIIO_M3K_PAD 726# define SOL_QUIT BUTTON_POWER 727# define SOL_UP BUTTON_UP 728# define SOL_DOWN BUTTON_DOWN 729# define SOL_LEFT BUTTON_LEFT 730# define SOL_RIGHT BUTTON_RIGHT 731# define SOL_MOVE_PRE BUTTON_SELECT 732# define SOL_MOVE (BUTTON_SELECT|BUTTON_REL) 733# define SOL_DRAW BUTTON_PLAY 734# define SOL_REM2CUR BUTTON_VOL_DOWN 735# define SOL_CUR2STACK_PRE BUTTON_SELECT 736# define SOL_CUR2STACK (BUTTON_SELECT|BUTTON_REPEAT) 737# define SOL_REM2STACK BUTTON_VOL_UP 738# define HK_MOVE "SELECT" 739# define HK_DRAW "PLAY" 740# define HK_REM2CUR "VOL-" 741# define HK_CUR2STACK "HOLD SELECT" 742# define HK_REM2STACK "VOL+" 743 744#elif CONFIG_KEYPAD == SHANLING_Q1_PAD 745# define SOL_QUIT BUTTON_POWER 746 747#elif CONFIG_PAD == SDL_APP 748# define SOL_QUIT (BUTTON_SELECT | BUTTON_MENU) 749# define SOL_UP BUTTON_UP 750# define SOL_DOWN BUTTON_DOWN 751# define SOL_LEFT_PRE BUTTON_LEFT 752# define SOL_LEFT (BUTTON_LEFT | BUTTON_SELECT) 753# define SOL_RIGHT_PRE BUTTON_RIGHT 754# define SOL_RIGHT (BUTTON_RIGHT | BUTTON_SELECT) 755# define SOL_MOVE_PRE BUTTON_SELECT 756# define SOL_MOVE (BUTTON_SELECT | BUTTON_UP) 757# define SOL_DRAW_PRE BUTTON_MENU 758# define HK_UD "SCROLL U/D" 759# define HK_MOVE "SELECT" 760# define HK_DRAW "MENU" 761# define HK_REM2CUR "PLAY" 762# define HK_CUR2STACK "MENU.." 763# define HK_REM2STACK "RIGHT.." 764#elif CONFIG_KEYPAD == RG_NANO_PAD 765# define SOL_QUIT BUTTON_START 766# define SOL_UP BUTTON_UP 767# define SOL_DOWN BUTTON_DOWN 768# define SOL_LEFT BUTTON_LEFT 769# define SOL_RIGHT BUTTON_RIGHT 770# define SOL_MOVE BUTTON_A 771# define SOL_DRAW BUTTON_X 772# define SOL_REM2CUR BUTTON_L 773# define SOL_CUR2STACK BUTTON_B 774# define SOL_REM2STACK BUTTON_R 775# define HK_MOVE "A" 776# define HK_DRAW "X" 777# define HK_REM2CUR "L" 778# define HK_CUR2STACK "B" 779# define HK_REM2STACK "R" 780 781#elif CONFIG_KEYPAD == MA_PAD 782# define SOL_QUIT (BUTTON_LEFT|BUTTON_REPEAT) 783# define SOL_UP BUTTON_UP 784# define SOL_DOWN BUTTON_DOWN 785# define SOL_LEFT BUTTON_LEFT 786# define SOL_RIGHT BUTTON_RIGHT 787# define SOL_MOVE_PRE BUTTON_MENU 788# define SOL_MOVE (BUTTON_MENU|BUTTON_REPEAT) 789# define SOL_DRAW BUTTON_PLAY 790# define SOL_REM2CUR (BUTTON_MENU|BUTTON_DOWN) 791# define SOL_CUR2STACK_PRE BUTTON_BACK 792# define SOL_CUR2STACK (BUTTON_BACK|BUTTON_REPEAT) 793# define SOL_REM2STACK (BUTTON_MENU|BUTTON_UP) 794# define HK_MOVE "MENU" 795# define HK_DRAW "PLAY" 796# define HK_REM2CUR "MENU+DOWN" 797# define HK_CUR2STACK "BACK" 798# define HK_REM2STACK "MENU+UP" 799 800 801#else 802#error No keymap defined! 803#endif 804 805#ifdef HAVE_TOUCHSCREEN 806//#ifndef SOL_QUIT 807//# define SOL_QUIT BUTTON_TOPLEFT 808//endif 809#ifndef SOL_UP 810# define SOL_UP BUTTON_TOPMIDDLE 811#endif 812#ifndef SOL_DOWN 813# define SOL_DOWN BUTTON_BOTTOMMIDDLE 814#endif 815#ifndef SOL_LEFT 816# define SOL_LEFT BUTTON_MIDLEFT 817#endif 818#ifndef SOL_RIGHT 819# define SOL_RIGHT BUTTON_MIDRIGHT 820#endif 821#ifndef SOL_MOVE 822# define SOL_MOVE BUTTON_CENTER 823# define HK_MOVE "CENTRE" 824#endif 825#ifndef SOL_DRAW 826# define SOL_DRAW BUTTON_TOPLEFT 827# define HK_DRAW "TOPLEFT" 828#endif 829#ifndef SOL_REM2CUR 830# define SOL_REM2CUR BUTTON_TOPRIGHT 831# define HK_REM2CUR "TOPRIGHT" 832#endif 833#ifndef SOL_CUR2STACK 834# define SOL_CUR2STACK BUTTON_BOTTOMLEFT 835# define HK_CUR2STACK "BOTTOMLEFT" 836#endif 837#ifndef SOL_REM2STACK 838# define SOL_REM2STACK BUTTON_BOTTOMRIGHT 839# define HK_REM2STACK "BOTTOMRIGHT" 840#endif 841 842#endif 843 844#ifndef HK_LR 845# define HK_LR "LEFT/RIGHT" 846#endif 847#ifndef HK_UD 848# define HK_UD "UP/DOWN" 849#endif 850 851/** 852 * Misc constants, graphics and other defines 853 */ 854 855#include "pluginbitmaps/card_back.h" 856#include "pluginbitmaps/card_deck.h" 857#include "pluginbitmaps/solitaire_suitsi.h" 858 859#define CARD_GFX_WIDTH BMPWIDTH_card_back 860#define CARD_GFX_HEIGHT BMPHEIGHT_card_back 861#define CARD_WIDTH (BMPWIDTH_card_back+2) 862#define CARD_HEIGHT (BMPHEIGHT_card_back+2) 863 864#if LCD_WIDTH >= 640 865# define MARGIN 4 866# define LARGE_CARD 867# define SYMBOL_HEIGHT 24 868 869#elif LCD_WIDTH >= 320 870# define MARGIN 4 871# define LARGE_CARD 872# define SYMBOL_HEIGHT 12 873#elif LCD_WIDTH >= 220 874# define MARGIN 3 875# define LARGE_CARD 876# define SYMBOL_HEIGHT 12 877#elif LCD_WIDTH >= 160 878# define MARGIN 2 879# define SYMBOL_HEIGHT 11 880#elif LCD_WIDTH >= 128 881# define MARGIN 1 882# define SYMBOL_HEIGHT 10 883#else 884# define MARGIN 0 885# define SYMBOL_HEIGHT 8 886#endif 887 888#define CARD_START (CARD_HEIGHT+2*MARGIN+1) 889 890/* background color */ 891#ifdef HAVE_LCD_COLOR 892# define BACKGROUND_COLOR LCD_RGBPACK(0,157,0) 893# define FRAME_COLOR LCD_RGBPACK(23,119,218) 894#elif LCD_DEPTH > 1 895# define BACKGROUND_COLOR LCD_WHITE 896# define FRAME_COLOR LCD_BLACK 897#endif 898 899 900#define CONFIG_FILENAME "sol.cfg" 901 902#define NOT_A_CARD -1 903 904/* number of cards per suit */ 905#define CARDS_PER_SUIT 13 906 907/* number of suits */ 908#define SUITS 4 909 910#define NUM_CARDS ( CARDS_PER_SUIT * SUITS ) 911 912/* number of columns */ 913#define COL_NUM 7 914 915/* pseudo column numbers to be used for cursor coordinates */ 916/* columns COL_NUM to COL_NUM + SUITS - 1 correspond to the final stacks */ 917#define STACKS_COL COL_NUM 918/* column COL_NUM + SUITS corresponds to the remains' stack */ 919#define REM_COL (STACKS_COL + SUITS) 920 921#define NOT_A_COL -1 922 923#if defined(SOL_LEFT_PRE) || defined(SOL_RIGHT_PRE) || \ 924 defined(SOL_DOWN_PRE) || defined(SOL_UP_PRE) || \ 925 defined(SOL_CUR2STACK_PRE) || defined(SOL_MOVE_PRE) || \ 926 defined(SOL_REM2CUR_PRE) || defined(SOL_REM2STACK_PRE) || \ 927 defined(SOL_DRAW_PRE) 928# define NEED_LASTBUTTON_VAR 929#endif 930 931typedef struct 932{ 933 signed char suit; 934 signed char num; 935 bool known : 1; 936 bool used : 1; /* this is what is used when dealing cards */ 937 signed char next; 938} card_t; 939 940 941/** 942 * LCD card drawing routines 943 */ 944 945static void draw_cursor( int x, int y ) 946{ 947 rb->lcd_set_drawmode( DRMODE_COMPLEMENT ); 948 rb->lcd_fillrect( x+1, y+1, CARD_GFX_WIDTH, CARD_GFX_HEIGHT ); 949#ifdef LARGE_CARD 950 rb->lcd_drawpixel( x+1, y+1 ); 951 rb->lcd_drawpixel( x+1, y+CARD_HEIGHT-2 ); 952 rb->lcd_drawpixel( x+CARD_WIDTH-2, y+1 ); 953 rb->lcd_drawpixel( x+CARD_WIDTH-2, y+CARD_HEIGHT-2 ); 954#endif 955 rb->lcd_set_drawmode( DRMODE_SOLID ); 956} 957 958/* Draw a card's border, select it if it's selected and draw the cursor 959 * if the cursor is currently over the card */ 960static void draw_card_ext( int x, int y, bool selected, bool cursor ) 961{ 962#if LCD_DEPTH > 1 963 int oldfg = rb->lcd_get_foreground(); 964 965 rb->lcd_set_foreground( LCD_BLACK ); 966#endif 967#ifdef LARGE_CARD 968 rb->lcd_hline( x+2, x+CARD_WIDTH-3, y ); 969 rb->lcd_hline( x+2, x+CARD_WIDTH-3, y+CARD_HEIGHT-1 ); 970 rb->lcd_vline( x, y+2, y+CARD_HEIGHT-3 ); 971 rb->lcd_vline( x+CARD_WIDTH-1, y+2, y+CARD_HEIGHT-3 ); 972 rb->lcd_drawpixel( x+1, y+1 ); 973 rb->lcd_drawpixel( x+1, y+CARD_HEIGHT-2 ); 974 rb->lcd_drawpixel( x+CARD_WIDTH-2, y+1 ); 975 rb->lcd_drawpixel( x+CARD_WIDTH-2, y+CARD_HEIGHT-2 ); 976#else 977 rb->lcd_hline( x+1, x+CARD_WIDTH-2, y ); 978 rb->lcd_hline( x+1, x+CARD_WIDTH-2, y+CARD_HEIGHT-1 ); 979 rb->lcd_vline( x, y+1, y+CARD_HEIGHT-2 ); 980 rb->lcd_vline( x+CARD_WIDTH-1, y+1, y+CARD_HEIGHT-2 ); 981#endif 982 983 if( selected ) 984 { 985#if LCD_DEPTH > 1 986 rb->lcd_set_foreground( FRAME_COLOR ); 987#endif 988 rb->lcd_drawrect( x+1, y+1, CARD_WIDTH-2, CARD_HEIGHT-2 ); 989#ifdef LARGE_CARD 990 rb->lcd_drawrect( x+2, y+2, CARD_WIDTH-4, CARD_HEIGHT-4 ); 991#endif 992 } 993#if LCD_DEPTH > 1 994 rb->lcd_set_foreground( oldfg ); 995#endif 996 997 if( cursor ) 998 { 999 draw_cursor( x, y ); 1000 } 1001} 1002 1003/* Draw a card's inner graphics */ 1004static void draw_card( card_t *card, int x, int y, 1005 bool selected, bool cursor ) 1006{ 1007 if( card->known ) 1008 { 1009 rb->lcd_bitmap_part( card_deck, CARD_GFX_WIDTH * card->num, 1010 CARD_GFX_HEIGHT * card->suit, 1011 STRIDE(SCREEN_MAIN, 1012 BMPWIDTH_card_deck, BMPHEIGHT_card_deck), 1013 x+1, y+1, CARD_GFX_WIDTH, CARD_GFX_HEIGHT ); 1014 } 1015 else 1016 { 1017 rb->lcd_bitmap( card_back, x+1, y+1, 1018 CARD_GFX_WIDTH, CARD_GFX_HEIGHT ); 1019 } 1020 draw_card_ext( x, y, selected, cursor ); 1021} 1022 1023/* Draw an empty stack */ 1024static void draw_empty_stack( int s, int x, int y, bool cursor ) 1025{ 1026 rb->lcd_bitmap_part( solitaire_suitsi, 0, 1027 CARD_GFX_HEIGHT * s, 1028 STRIDE( SCREEN_MAIN, 1029 BMPWIDTH_solitaire_suitsi, BMPHEIGHT_solitaire_suitsi), 1030 x+1, y+1, CARD_GFX_WIDTH, CARD_GFX_HEIGHT ); 1031 1032 draw_card_ext( x, y, false, cursor ); 1033} 1034 1035/* Help */ 1036static bool solitaire_help( void ) 1037{ 1038 static char* help_text[] = { 1039 "Solitaire", "", "Controls", "", 1040 HK_LR ":", "Move", "the", "cursor", "to", "the", 1041 "previous/", "next", "column.", "", 1042 HK_UD ":", "Move", "the", "cursor", "up/", "down", "in", "the", 1043 "column.", "", 1044 HK_MOVE ":", "Select", "cards,", "move", "cards...", "", 1045 HK_DRAW ":", "Deselect", "a", "card", "if", "it", "was", "selected.", 1046 "Else", "draw", "new", "card(s)", "from", "the", "remains", 1047 "stack.", "", "", 1048 "Shortcuts", "", 1049 HK_REM2CUR ":", "Put", "the", "card", "on", "top", "of", "the", 1050 "remains", "stack", "on", "top", "of", "the", "cursor.", "", 1051 HK_CUR2STACK ":", "Put", "the", "card", "under", "the", "cursor", 1052 "on", "one", "of", "the", "4", "final", "stacks.", "", 1053 HK_REM2STACK ":", "Put", "the", "card", "on", "top", "of", "the", 1054 "remains", "stack", "on", "one", "of", "the", "4", "final", 1055 "stacks." 1056 }; 1057 static struct style_text formation[]={ 1058 { 0, TEXT_CENTER|TEXT_UNDERLINE }, 1059 { 2, C_RED }, 1060 { 48, C_RED }, 1061 LAST_STYLE_ITEM 1062 }; 1063 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true)) 1064 return true; 1065 return false; 1066} 1067 1068/** 1069 * Custom menu / options 1070 */ 1071 1072#define CFGFILE_VERSION 0 1073 1074struct sol_config { 1075 int draw_type; 1076}; 1077 1078struct sol_config sol_disk = {0}; 1079struct sol_config sol; 1080 1081static struct configdata config[] = { 1082 { TYPE_INT, 0, 1, { .int_p = &sol_disk.draw_type }, "draw_type", NULL } 1083}; 1084 1085static const struct opt_items drawcards[2] = { 1086 { "Draw Three Cards", -1 }, 1087 { "Draw One Card", -1 }, 1088}; 1089 1090void solitaire_init(void); 1091 1092/* menu return codes */ 1093enum { MENU_RESUME, MENU_SAVE_AND_QUIT, MENU_QUIT, MENU_USB }; 1094 1095static bool _ingame; 1096static int solitaire_menu_cb(int action, 1097 const struct menu_item_ex *this_item, 1098 struct gui_synclist *this_list) 1099{ 1100 (void)this_list; 1101 int i = (intptr_t)this_item; 1102 if( action == ACTION_REQUEST_MENUITEM ) 1103 { 1104 if((!_ingame && (i==0 || i==5)) || ( _ingame && i==2 )) 1105 return ACTION_EXIT_MENUITEM; 1106 } 1107 return action; 1108} 1109 1110static int solitaire_menu(bool in_game) 1111{ 1112 int selected = 0; 1113 int result = -1; 1114 1115 MENUITEM_STRINGLIST(menu, "Solitaire Menu", solitaire_menu_cb, 1116 "Resume Game", "Start New Game", 1117 "Draw Cards Option", 1118 "Help", "Playback Control", 1119 "Quit without Saving", "Quit"); 1120 _ingame = in_game; 1121 1122 while (result < 0) 1123 { 1124 switch (rb->do_menu(&menu, &selected, NULL, false)) 1125 { 1126 default: 1127 result = MENU_RESUME; 1128 break; 1129 1130 case MENU_ATTACHED_USB: 1131 result = MENU_USB; 1132 break; 1133 1134 case 0: 1135 result = MENU_RESUME; 1136 break; 1137 1138 case 1: 1139 solitaire_init(); 1140 result = MENU_RESUME; 1141 break; 1142 1143 case 2: 1144 if (rb->set_option("Draw Cards Option", &sol.draw_type, 1145 RB_INT, drawcards, 2, NULL)) 1146 result = MENU_USB; 1147 break; 1148 1149 case 3: 1150 if (solitaire_help()) 1151 result = MENU_USB; 1152 break; 1153 1154 case 4: 1155 playback_control(NULL); 1156 break; 1157 1158 case 5: 1159 result = MENU_QUIT; 1160 break; 1161 1162 case 6: 1163 result = MENU_SAVE_AND_QUIT; 1164 break; 1165 } 1166 } 1167 return result; 1168} 1169 1170/** 1171 * Global variables 1172 */ 1173 1174/* player's cursor */ 1175int cur_card; 1176/* player's cursor column num */ 1177int cur_col; 1178 1179/* selected card */ 1180int sel_card; 1181 1182/* the deck */ 1183card_t deck[ NUM_CARDS ]; 1184 1185/* the remaining cards */ 1186/* first card of the remains' stack */ 1187int rem; 1188/* upper visible card from the remains' stack */ 1189int cur_rem; 1190/* number of cards drawn from the remains stack - 1 */ 1191int count_rem; 1192/* number of cards per draw of the remains' stack */ 1193int cards_per_draw; 1194 1195/* the 7 game columns */ 1196int cols[COL_NUM]; 1197/* the 4 final stacks */ 1198int stacks[SUITS]; 1199 1200/** 1201 * Card handling routines 1202 */ 1203 1204static int next_random_card( card_t *deck ) 1205{ 1206 int i,r; 1207 1208 r = rb->rand()%(NUM_CARDS)+1; 1209 i = 0; 1210 1211 while( r>0 ) 1212 { 1213 i = (i + 1)%(NUM_CARDS); 1214 if( !deck[i].used ) r--; 1215 } 1216 1217 deck[i].used = true; 1218 1219 return i; 1220} 1221 1222 1223/* initialize the game */ 1224void solitaire_init( void ) 1225{ 1226 1227 int c; 1228 int i, j; 1229 1230 /* number of cards that are drawn on the remains' stack (by pressing F2) */ 1231 if( sol.draw_type == 0 ) 1232 { 1233 cards_per_draw = 3; 1234 } 1235 else 1236 { 1237 cards_per_draw = 1; 1238 } 1239 1240 /* init deck */ 1241 for( i=0; i<SUITS; i++ ) 1242 { 1243 for( j=0; j<CARDS_PER_SUIT; j++ ) 1244 { 1245#define card deck[i*CARDS_PER_SUIT+j] 1246 card.suit = i; 1247 card.num = j; 1248 card.known = true; 1249 card.used = false; 1250 card.next = NOT_A_CARD; 1251#undef card 1252 } 1253 } 1254 1255 /* deal the cards ... */ 1256 /* ... in the columns */ 1257 for( i=0; i<COL_NUM; i++ ) 1258 { 1259 c = NOT_A_CARD; 1260 for( j=0; j<=i; j++ ) 1261 { 1262 if( c == NOT_A_CARD ) 1263 { 1264 cols[i] = next_random_card( deck ); 1265 c = cols[i]; 1266 } 1267 else 1268 { 1269 deck[c].next = next_random_card( deck ); 1270 c = deck[c].next; 1271 } 1272 if( j < i ) 1273 deck[c].known = false; 1274 } 1275 } 1276 1277 /* ... shuffle what's left of the deck */ 1278 rem = next_random_card(deck); 1279 c = rem; 1280 1281 for( i=1; i < NUM_CARDS - COL_NUM * (COL_NUM + 1)/2; i++ ) 1282 { 1283 deck[c].next = next_random_card( deck ); 1284 c = deck[c].next; 1285 } 1286 1287 /* we now finished dealing the cards. The game can start ! (at last) */ 1288 1289 /* init the stack */ 1290 for( i = 0; i<SUITS; i++ ) 1291 { 1292 stacks[i] = NOT_A_CARD; 1293 } 1294 1295 /* the cursor starts on upper left card */ 1296 cur_card = cols[0]; 1297 cur_col = 0; 1298 1299 /* no card is selected */ 1300 sel_card = NOT_A_CARD; 1301 1302 /* init the remainder */ 1303 cur_rem = NOT_A_CARD; 1304 1305 count_rem = -1; 1306} 1307 1308/* find the column number in which 'card' can be found */ 1309static int find_card_col( int card ) 1310{ 1311 int i; 1312 int c; 1313 1314 if( card == NOT_A_CARD ) return NOT_A_COL; 1315 1316 for( i=0; i<COL_NUM; i++ ) 1317 { 1318 c = cols[i]; 1319 while( c != NOT_A_CARD ) 1320 { 1321 if( c == card ) return i; 1322 c = deck[c].next; 1323 } 1324 } 1325 1326 for( i=0; i<SUITS; i++ ) 1327 { 1328 c = stacks[i]; 1329 while( c != NOT_A_CARD ) 1330 { 1331 if( c == card ) return STACKS_COL + i; 1332 c = deck[c].next; 1333 } 1334 } 1335 1336 return REM_COL; 1337} 1338 1339/* find the card preceding 'card' */ 1340/* if it doesn't exist, return NOT_A_CARD */ 1341static int find_prev_card( int card ){ 1342 int i; 1343 1344 for( i=0; i < NUM_CARDS; i++ ) 1345 { 1346 if( deck[i].next == card ) return i; 1347 } 1348 1349 return NOT_A_CARD; 1350} 1351 1352/* find the last card of a given column */ 1353static int find_last_card( int col ) 1354{ 1355 int c; 1356 1357 if( col < COL_NUM ) 1358 { 1359 c = cols[col]; 1360 } 1361 else if( col < REM_COL ) 1362 { 1363 c = stacks[col - STACKS_COL]; 1364 } 1365 else 1366 { 1367 c = cur_rem; 1368 } 1369 1370 if(c == NOT_A_CARD) 1371 return c; 1372 else 1373 { 1374 while(deck[c].next != NOT_A_CARD) 1375 c = deck[c].next; 1376 return c; 1377 } 1378} 1379 1380enum move { MOVE_OK, MOVE_NOT_OK }; 1381 1382static enum move move_card( int dest_col, int src_card ) 1383{ 1384 /* the column on which to take src_card */ 1385 int src_col; 1386 1387 /* the last card of dest_col */ 1388 int dest_card; 1389 1390 /* the card under src_card */ 1391 int src_card_prev; 1392 1393 /* you can't move no card (at least, it doesn't have any consequence) */ 1394 if( src_card == NOT_A_CARD ) return MOVE_NOT_OK; 1395 /* you can't put a card back on the remains' stack */ 1396 if( dest_col == REM_COL ) return MOVE_NOT_OK; 1397 /* you can't move an unknown card */ 1398 if( !deck[src_card].known ) return MOVE_NOT_OK; 1399 1400 src_col = find_card_col( src_card ); 1401 dest_card = find_last_card( dest_col ); 1402 src_card_prev = find_prev_card( src_card ); 1403 1404 /* you can't move more than one card at a time from the final stack */ 1405 /* to the rest of the game */ 1406 if( src_col >= COL_NUM && src_col < REM_COL 1407 && deck[src_card].next != NOT_A_CARD ) 1408 { 1409 return MOVE_NOT_OK; 1410 } 1411 1412 /* if we (that means dest) are on one of the 7 columns ... */ 1413 if( dest_col < COL_NUM ) 1414 { 1415 /* ... check is we are on an empty color and that the src is a king */ 1416 if( dest_card == NOT_A_CARD 1417 && deck[src_card].num == CARDS_PER_SUIT - 1 ) 1418 { 1419 /* this is a winning combination */ 1420 cols[dest_col] = src_card; 1421 } 1422 /* ... or check if the cards follow one another and have 1423 * different colorsuit */ 1424 else if(( deck[dest_card].suit + deck[src_card].suit)%2==1 1425 && deck[dest_card].num == deck[src_card].num + 1 ) 1426 { 1427 /* this is a winning combination */ 1428 deck[dest_card].next = src_card; 1429 } 1430 /* ... or, humpf, well that's not good news */ 1431 else 1432 { 1433 /* this is not a winning combination */ 1434 return MOVE_NOT_OK; 1435 } 1436 } 1437 /* if we are on one of the 4 final stacks ... */ 1438 else if( dest_col < REM_COL ) 1439 { 1440 /* ... check if we are on an empty stack... */ 1441 if( dest_card == NOT_A_CARD ) 1442 { 1443 /* ... and the src is an ace and this is the correct final stack */ 1444 if( deck[src_card].num == 0 1445 && deck[src_card].suit == dest_col - STACKS_COL ) 1446 { 1447 /* this is a winning combination */ 1448 stacks[dest_col - STACKS_COL] = src_card; 1449 } 1450 else 1451 { 1452 /* this is not a winning combination */ 1453 return MOVE_NOT_OK; 1454 } 1455 } 1456 else /* non-empty stack */ 1457 { 1458 /* ...check if the cards follow one another, have the same suit and 1459 * {that src has no .next element or is from the remains' stack} */ 1460 if( deck[dest_card].suit == deck[src_card].suit 1461 && deck[dest_card].num + 1 == deck[src_card].num 1462 && (deck[src_card].next == NOT_A_CARD || src_col == REM_COL) ) 1463 { 1464 /* this is a winning combination */ 1465 deck[dest_card].next = src_card; 1466 } 1467 /* ... or, well that's not good news */ 1468 else 1469 { 1470 /* this is not a winning combination */ 1471 return MOVE_NOT_OK; 1472 } 1473 } 1474 } 1475 /* if we are on the remains' stack */ 1476 else 1477 { 1478 /* you can't move a card back to the remains' stack */ 1479 return MOVE_NOT_OK; 1480 } 1481 1482 /* if the src card is from the remains' stack, we don't want to take 1483 * the following cards */ 1484 if( src_col == REM_COL ) 1485 { 1486 /* if src card is the first card from the stack */ 1487 if( src_card_prev == NOT_A_CARD ) 1488 { 1489 rem = deck[src_card].next; 1490 } 1491 /* if src card is not the first card from the stack */ 1492 else 1493 { 1494 deck[src_card_prev].next = deck[src_card].next; 1495 } 1496 deck[src_card].next = NOT_A_CARD; 1497 cur_rem = src_card_prev; 1498 count_rem--; 1499 } 1500 /* if the src card is from somewhere else, just take everything */ 1501 else 1502 { 1503 if( src_card_prev == NOT_A_CARD ) 1504 { 1505 if( src_col < COL_NUM ) 1506 { 1507 cols[src_col] = NOT_A_CARD; 1508 } 1509 else 1510 { 1511 stacks[src_col - STACKS_COL] = NOT_A_CARD; 1512 } 1513 } 1514 else 1515 { 1516 deck[src_card_prev].next = NOT_A_CARD; 1517 deck[src_card_prev].known = true; 1518 } 1519 } 1520 sel_card = NOT_A_CARD; 1521 /* tada ! */ 1522 return MOVE_OK; 1523} 1524 1525enum { SOLITAIRE_WIN, SOLITAIRE_SAVE_AND_QUIT, SOLITAIRE_QUIT, SOLITAIRE_USB }; 1526 1527/** 1528 * Bouncing cards at the end of the game 1529 */ 1530 1531#define BC_ACCEL ((1<<16)*LCD_HEIGHT/128) 1532#define BC_MYSPEED (6*BC_ACCEL) 1533#define BC_MXSPEED (6*LCD_HEIGHT/128) 1534 1535static int bouncing_cards( void ) 1536{ 1537 int i, j, x, vx, y, fp_y, fp_vy, button; 1538 1539 /* flush the button queue */ 1540 while( ( button = rb->button_get( false ) ) != BUTTON_NONE ) 1541 { 1542 if( rb->default_event_handler( button ) == SYS_USB_CONNECTED ) 1543 return SOLITAIRE_USB; 1544 } 1545 1546 /* fun stuff :) */ 1547 for( i = CARDS_PER_SUIT-1; i>=0; i-- ) 1548 { 1549 for( j = 0; j < SUITS; j++ ) 1550 { 1551 x = LCD_WIDTH-(CARD_WIDTH*4+4+MARGIN)+CARD_WIDTH*j+j+1; 1552 fp_y = MARGIN<<16; 1553 1554#if LCD_WIDTH > 200 1555 vx = rb->rand() % (4*BC_MXSPEED/3-2) - BC_MXSPEED; 1556 if( vx >= -1 ) 1557 vx += 3; 1558#else 1559 vx = rb->rand() % (4*BC_MXSPEED/3) - BC_MXSPEED; 1560 if( vx >= 0 ) 1561 vx++; 1562#endif 1563 1564 fp_vy = -rb->rand() % BC_MYSPEED; 1565 1566 while( x < LCD_WIDTH && x + CARD_WIDTH > 0 ) 1567 { 1568 fp_vy += BC_ACCEL; 1569 x += vx; 1570 fp_y += fp_vy; 1571 if( fp_y >= (LCD_HEIGHT-CARD_HEIGHT) << 16 ) 1572 { 1573 fp_vy = -fp_vy*4/5; 1574 fp_y = (LCD_HEIGHT-CARD_HEIGHT) << 16; 1575 } 1576 y = fp_y >> 16; 1577 draw_card( &deck[j*CARDS_PER_SUIT+i], x, y, 1578 false, false ); 1579 rb->lcd_update_rect( x<0?0:x, y<0?0:y, 1580 CARD_WIDTH, CARD_HEIGHT ); 1581 1582 button = rb->button_get_w_tmo( 2 ); 1583 if( rb->default_event_handler( button ) == SYS_USB_CONNECTED ) 1584 return SOLITAIRE_USB; 1585 if( button == SOL_QUIT || button == SOL_MOVE ) 1586 return SOLITAIRE_WIN; 1587 } 1588 } 1589 } 1590 return SOLITAIRE_WIN; 1591} 1592 1593/** 1594 * Game save/load routines 1595 */ 1596static void get_save_filename( char *buf ) 1597{ 1598#ifdef APPLICATION 1599 rb->snprintf(buf, sizeof(buf), PLUGIN_DATA_DIR "/sol.save"); 1600#else 1601 char *s; 1602 rb->strcpy( buf, rb->plugin_get_current_filename() ); 1603 s = rb->strrchr( buf, '/' ) + 1; 1604 *s = '\0'; 1605 rb->strcat( s, "sol.save" ); 1606#endif 1607} 1608 1609static int open_save_file( int flags ) 1610{ 1611 char buf[MAX_PATH]; 1612 get_save_filename( buf ); 1613 return rb->open( buf, flags, 0666); 1614} 1615 1616static void delete_save_file( void ) 1617{ 1618 char buf[MAX_PATH]; 1619 get_save_filename( buf ); 1620 rb->remove( buf ); 1621} 1622 1623#ifdef write 1624# undef write 1625#endif 1626static int save_write( int fd, const void *buf, size_t count, int *checksum ) 1627{ 1628 size_t i; 1629 if( rb->write( fd, buf, count ) < (ssize_t)count ) 1630 return 1; 1631 for( i = 0; i < count; i++ ) 1632 *checksum += (int)(((const char *)buf)[i]); 1633 return 0; 1634} 1635 1636#ifdef read 1637# undef read 1638#endif 1639static int save_read( int fd, void *buf, size_t count, int *checksum ) 1640{ 1641 size_t i; 1642 if( rb->read( fd, buf, count ) < (ssize_t)count ) 1643 return 1; 1644 for( i = 0; i < count; i++ ) 1645 *checksum -= (int)(((const char *)buf)[i]); 1646 return 0; 1647} 1648 1649static int save_game( void ) 1650{ 1651 int fd = open_save_file( O_CREAT|O_WRONLY|O_TRUNC ); 1652 int checksum = 42; 1653 if( fd < 0 ) 1654 return -1; 1655 if( save_write( fd, &cur_card, sizeof( int ), &checksum ) 1656 || save_write( fd, &cur_col, sizeof( int ), &checksum ) 1657 || save_write( fd, &sel_card, sizeof( int ), &checksum ) 1658 || save_write( fd, deck, NUM_CARDS * sizeof( card_t ), &checksum ) 1659 || save_write( fd, &rem, sizeof( int ), &checksum ) 1660 || save_write( fd, &cur_rem, sizeof( int ), &checksum ) 1661 || save_write( fd, &count_rem, sizeof( int ), &checksum ) 1662 || save_write( fd, &cards_per_draw, sizeof( int ), &checksum ) 1663 || save_write( fd, cols, COL_NUM * sizeof( int ), &checksum ) 1664 || save_write( fd, stacks, SUITS * sizeof( int ), &checksum ) 1665 || ( rb->write( fd, &checksum, sizeof( int ) ) < (ssize_t)(sizeof( int ) ) ) ) 1666 { 1667 rb->close( fd ); 1668 rb->splash( 2*HZ, "Error while saving game. Aborting." ); 1669 return -2; 1670 } 1671 rb->close( fd ); 1672 return 0; 1673} 1674 1675static int load_game( void ) 1676{ 1677 int checksum, retval; 1678 1679 int fd = open_save_file( O_RDONLY ); 1680 if( fd < 0 ) 1681 return -1; 1682 1683 retval = 0; /* Assume good case */ 1684 if( ( rb->lseek( fd, -(off_t)sizeof( int ), SEEK_END ) == -((ssize_t)sizeof( int ))-1 ) 1685 || ( rb->read( fd, &checksum, sizeof( int ) ) < ((ssize_t)sizeof( int )) ) 1686 || ( rb->lseek( fd, 0, SEEK_SET ) == -1 ) 1687 || save_read( fd, &cur_card, sizeof( int ), &checksum ) 1688 || save_read( fd, &cur_col, sizeof( int ), &checksum ) 1689 || save_read( fd, &sel_card, sizeof( int ), &checksum ) 1690 || save_read( fd, deck, NUM_CARDS * sizeof( card_t ), &checksum ) 1691 || save_read( fd, &rem, sizeof( int ), &checksum ) 1692 || save_read( fd, &cur_rem, sizeof( int ), &checksum ) 1693 || save_read( fd, &count_rem, sizeof( int ), &checksum ) 1694 || save_read( fd, &cards_per_draw, sizeof( int ), &checksum ) 1695 || save_read( fd, cols, COL_NUM * sizeof( int ), &checksum ) 1696 || save_read( fd, stacks, SUITS * sizeof( int ), &checksum ) ) 1697 { 1698 rb->splash( 2*HZ, "Error while loading saved game. Aborting." ); 1699 retval = -2; 1700 } 1701 else if( checksum != 42 ) 1702 { 1703 rb->splash( 2*HZ, "Save file was corrupted. Aborting." ); 1704 retval = -3; 1705 } 1706 1707 rb->close( fd ); 1708 delete_save_file(); 1709 return retval; 1710} 1711 1712/** 1713 * The main game loop 1714 * 1715 * If skipmenu is defined to SOLITAIRE_QUIT, the menu will be skipped and 1716 * game will resume. 1717 */ 1718 1719static int solitaire( int skipmenu ) 1720{ 1721 1722 int i,j; 1723 int button; 1724#ifdef NEED_LASTBUTTON_VAR 1725 int lastbutton = 0; 1726#endif 1727 int c,h,prevcard; 1728 int biggest_col_length; 1729 1730 rb->srand( *rb->current_tick ); 1731 if( skipmenu != SOLITAIRE_QUIT ) 1732 { 1733 switch( solitaire_menu(false) ) 1734 { 1735 case MENU_SAVE_AND_QUIT: 1736 return SOLITAIRE_QUIT; 1737 1738 case MENU_USB: 1739 return SOLITAIRE_USB; 1740 } 1741 solitaire_init(); 1742 } 1743 1744 while( true ) 1745 { 1746 rb->lcd_clear_display(); 1747 1748 /* get the biggest column length so that display can be "optimized" */ 1749 biggest_col_length = 0; 1750 1751 for(i=0;i<COL_NUM;i++) 1752 { 1753 j = 0; 1754 c = cols[i]; 1755 1756 if( c != NOT_A_CARD ) 1757 { 1758 while( true ) 1759 { 1760 /* don't include the last card in the column length. */ 1761 if( deck[c].next == NOT_A_CARD ) 1762 { 1763 break; /* no successor: get outta here. */ 1764 } 1765 else 1766 { 1767 if( deck[c].known ) 1768 j += 2; 1769 else 1770 j++; 1771 } 1772 c = deck[c].next; 1773 } 1774 /* make column distinguishable from an empty column, 1775 * and avoid division by zero while displaying */ 1776 if( j == 0 ) 1777 j = 1; 1778 } 1779 if( j > biggest_col_length ) 1780 biggest_col_length = j; 1781 } 1782 1783 /* check if there are cards remaining in the game. */ 1784 /* if there aren't any, that means you won :) */ 1785 if( biggest_col_length == 0 && rem == NOT_A_CARD ) 1786 { 1787 rb->lcd_update(); 1788 rb->splash( HZ, "You Won :)" ); 1789 return bouncing_cards(); 1790 } 1791 1792 /* draw the columns */ 1793 for( i = 0; i < COL_NUM; i++ ) 1794 { 1795 c = cols[i]; 1796 j = CARD_START; 1797 while( true ) 1798 { 1799 if( c == NOT_A_CARD ) 1800 { 1801 /* draw the cursor on empty columns */ 1802 if( cur_col == i ) 1803 { 1804 draw_cursor( MARGIN + i * (CARD_WIDTH 1805 +(LCD_WIDTH-COL_NUM*CARD_WIDTH-2*MARGIN)/(COL_NUM-1)), 1806 j ); 1807 } 1808 break; 1809 } 1810 1811 draw_card( &deck[c], MARGIN + i * (CARD_WIDTH 1812 +(LCD_WIDTH-COL_NUM*CARD_WIDTH-2*MARGIN)/(COL_NUM-1)), 1813 j, c == sel_card, c == cur_card ); 1814 1815 h = c; 1816 c = deck[c].next; 1817 if( c == NOT_A_CARD ) break; 1818 1819 /* This is where we change the spacing between cards so that 1820 * they don't overflow out of the LCD */ 1821 if( h == cur_card ) 1822 j += SYMBOL_HEIGHT; 1823 else if( deck[h].known ) 1824 j += min( SYMBOL_HEIGHT, 1825 2 * (LCD_HEIGHT - CARD_START - CARD_HEIGHT - MARGIN) 1826 / biggest_col_length ); 1827 else 1828 j += min( SYMBOL_HEIGHT / 2, 1829 (LCD_HEIGHT - CARD_START - CARD_HEIGHT - MARGIN) 1830 / biggest_col_length ); 1831 } 1832 } 1833 1834 /* draw the stacks */ 1835 for( i=0; i<SUITS; i++ ) 1836 { 1837 c = find_last_card( STACKS_COL + i ); 1838 1839 if( c != NOT_A_CARD ) 1840 { 1841 draw_card( &deck[c], 1842 LCD_WIDTH-(CARD_WIDTH*4+4+MARGIN)+CARD_WIDTH*i+i+1, 1843 MARGIN, 1844 c == sel_card, cur_col == STACKS_COL + i ); 1845 } 1846 else 1847 { 1848 draw_empty_stack( i, 1849 LCD_WIDTH-(CARD_WIDTH*4+4+MARGIN)+CARD_WIDTH*i+i+1, 1850 MARGIN, cur_col == STACKS_COL + i ); 1851 } 1852 } 1853 1854 /* draw the remains */ 1855 if( rem != NOT_A_CARD && 1856 ( cur_rem == NOT_A_CARD || deck[cur_rem].next != NOT_A_CARD ) ) 1857 { 1858 /* gruik ! (we want to display a card back) */ 1859 deck[rem].known = false; 1860 draw_card( &deck[rem], MARGIN, MARGIN, false, false ); 1861 deck[rem].known = true; 1862 } 1863 1864 if( rem != NOT_A_CARD && cur_rem != NOT_A_CARD ) 1865 { 1866 if( count_rem < 0 ) 1867 { 1868 prevcard = rem; 1869 count_rem = 0; 1870 while( prevcard != cur_rem && count_rem < cards_per_draw-1 ) 1871 { 1872 prevcard = deck[prevcard].next; 1873 count_rem++; 1874 } 1875 } 1876 prevcard = cur_rem; 1877 j = CARD_WIDTH+2*MARGIN+1; 1878 for( i = 0; i < count_rem; i++ ) 1879 prevcard = find_prev_card(prevcard); 1880 for( i = 0; i <= count_rem; i++ ) 1881 { 1882 draw_card( &deck[prevcard], j, 1883 MARGIN, sel_card == prevcard, 1884 cur_card == prevcard ); 1885 prevcard = deck[prevcard].next; 1886 j += CARD_WIDTH/2; 1887 } 1888 } 1889 if( ( cur_rem == NOT_A_CARD || rem == NOT_A_CARD ) 1890 && cur_col == REM_COL ) 1891 { 1892 draw_cursor( CARD_WIDTH+2*MARGIN+1, MARGIN ); 1893 } 1894 1895 rb->lcd_update(); 1896 1897 /* what to do when a key is pressed ... */ 1898 button = rb->button_get( true ); 1899#if (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_FUZE_PAD) 1900 if (button&(BUTTON_SCROLL_BACK|BUTTON_SCROLL_FWD)) 1901 button = button & (~BUTTON_REPEAT); 1902#endif 1903 switch( button ) 1904 { 1905 /* move cursor to the last card of the previous column 1906 * or to the previous final stack 1907 * or to the remains stack */ 1908 case SOL_RIGHT: 1909#ifdef SOL_RIGHT_PRE 1910 if( lastbutton != SOL_RIGHT_PRE ) 1911 break; 1912#endif 1913 if( cur_col >= COL_NUM ) 1914 { 1915 cur_col = 0; 1916 } 1917 else if( cur_col == COL_NUM - 1 ) 1918 { 1919 cur_col = REM_COL; 1920 } 1921 else 1922 { 1923 cur_col = (cur_col+1)%(REM_COL+1); 1924 } 1925 if(cur_col == REM_COL) 1926 { 1927 cur_card = cur_rem; 1928 break; 1929 } 1930 cur_card = find_last_card( cur_col ); 1931 break; 1932 1933 /* move cursor to the last card of the next column 1934 * or to the next final stack 1935 * or to the remains stack */ 1936 case SOL_LEFT: 1937#ifdef SOL_LEFT_PRE 1938 if( lastbutton != SOL_LEFT_PRE ) 1939 break; 1940#endif 1941 if( cur_col == 0 ) 1942 { 1943 cur_col = REM_COL; 1944 } 1945 else if( cur_col >= COL_NUM ) 1946 { 1947 cur_col = COL_NUM - 1; 1948 } 1949 else 1950 { 1951 cur_col = (cur_col + REM_COL)%(REM_COL+1); 1952 } 1953 if( cur_col == REM_COL ) 1954 { 1955 cur_card = cur_rem; 1956 break; 1957 } 1958 cur_card = find_last_card( cur_col ); 1959 break; 1960 1961 /* move cursor to card that's bellow */ 1962 case SOL_DOWN: 1963#ifdef SOL_DOWN_PRE 1964 if( lastbutton != SOL_DOWN_PRE ) 1965 break; 1966#else 1967 case SOL_DOWN|BUTTON_REPEAT: 1968#endif 1969 if( cur_col >= COL_NUM ) 1970 { 1971 cur_col = (cur_col - COL_NUM + 1)%(SUITS + 1) + COL_NUM; 1972 if( cur_col == REM_COL ) 1973 { 1974 cur_card = cur_rem; 1975 } 1976 else 1977 { 1978 cur_card = find_last_card( cur_col ); 1979 } 1980 break; 1981 } 1982 if( cur_card == NOT_A_CARD ) break; 1983 if( deck[cur_card].next != NOT_A_CARD ) 1984 { 1985 cur_card = deck[cur_card].next; 1986 } 1987 else 1988 { 1989 cur_card = cols[cur_col]; 1990 while( !deck[ cur_card].known 1991 && deck[cur_card].next != NOT_A_CARD ) 1992 { 1993 cur_card = deck[cur_card].next; 1994 } 1995 } 1996 break; 1997 1998 /* move cursor to card that's above */ 1999 case SOL_UP: 2000#ifdef SOL_UP_PRE 2001 if( lastbutton != SOL_UP_PRE ) 2002 break; 2003#else 2004 case SOL_UP|BUTTON_REPEAT: 2005#endif 2006 if( cur_col >= COL_NUM ) 2007 { 2008 cur_col = (cur_col - COL_NUM + SUITS)%(SUITS + 1) + COL_NUM; 2009 if( cur_col == REM_COL ) 2010 { 2011 cur_card = cur_rem; 2012 } 2013 else 2014 { 2015 cur_card = find_last_card( cur_col ); 2016 } 2017 break; 2018 } 2019 if( cur_card == NOT_A_CARD ) break; 2020 do { 2021 cur_card = find_prev_card( cur_card ); 2022 if( cur_card == NOT_A_CARD ) 2023 { 2024 cur_card = find_last_card( cur_col ); 2025 } 2026 } while( deck[cur_card].next != NOT_A_CARD 2027 && !deck[cur_card].known ); 2028 break; 2029 2030 /* Try to put card under cursor on one of the stacks */ 2031 case SOL_CUR2STACK: 2032#ifdef SOL_CUR2STACK_PRE 2033 if( lastbutton != SOL_CUR2STACK_PRE ) 2034 break; 2035#endif 2036 move_card( deck[cur_card].suit + STACKS_COL, cur_card ); 2037 break; 2038 2039 /* Move cards arround, Uncover cards, ... */ 2040 case SOL_MOVE: 2041#ifdef SOL_MOVE_PRE 2042 if( lastbutton != SOL_MOVE_PRE ) 2043 break; 2044#endif 2045 2046 if( sel_card == NOT_A_CARD ) 2047 { 2048 if( cur_card != NOT_A_CARD ) 2049 { 2050 if( deck[cur_card].next == NOT_A_CARD 2051 && !deck[cur_card].known ) 2052 { 2053 /* reveal a hidden card */ 2054 deck[cur_card].known = true; 2055 } 2056 else if( cur_col == REM_COL && cur_rem == NOT_A_CARD ) 2057 { 2058 break; 2059 } 2060 else 2061 { 2062 /* select a card */ 2063 sel_card = cur_card; 2064 } 2065 } 2066 } 2067 else if( sel_card == cur_card ) 2068 { 2069 /* unselect card or try putting card on 2070 * one of the 4 stacks */ 2071 if( move_card( deck[sel_card].suit + COL_NUM, sel_card ) 2072 == MOVE_OK && cur_col == REM_COL ) 2073 { 2074 cur_card = cur_rem; 2075 } 2076 sel_card = NOT_A_CARD; 2077 } 2078 else 2079 { 2080 /* try moving cards */ 2081 /* The flexible move must not be used from the remains stack. */ 2082 if (find_card_col(sel_card) == REM_COL) 2083 { 2084 if (move_card( cur_col, sel_card ) == MOVE_NOT_OK) 2085 sel_card = NOT_A_CARD; 2086 } 2087 else 2088 { 2089 do { 2090 if (move_card( cur_col, sel_card) == MOVE_OK) 2091 break; 2092 sel_card = find_prev_card(sel_card); 2093 } while (sel_card != NOT_A_CARD); 2094 } 2095 } 2096 break; 2097 2098 /* If the card on the top of the remains can be put where 2099 * the cursor is, go ahead */ 2100 case SOL_REM2CUR: 2101#ifdef SOL_REM2CUR_PRE 2102 if( lastbutton != SOL_REM2CUR_PRE ) 2103 break; 2104#endif 2105 move_card( cur_col, cur_rem ); 2106 break; 2107 2108 /* If the card on top of the remains can be put on one 2109 * of the stacks, do so */ 2110 case SOL_REM2STACK: 2111#ifdef SOL_REM2STACK_PRE 2112 if( lastbutton != SOL_REM2STACK_PRE ) 2113 break; 2114#endif 2115 move_card( deck[cur_rem].suit + COL_NUM, cur_rem ); 2116 break; 2117 2118#ifdef SOL_REM 2119 case SOL_REM: 2120 if( sel_card != NOT_A_CARD ) 2121 { 2122 /* unselect selected card */ 2123 sel_card = NOT_A_CARD; 2124 break; 2125 } 2126 if( rem != NOT_A_CARD && cur_rem != NOT_A_CARD ) 2127 { 2128 sel_card = cur_rem; 2129 break; 2130 } 2131 break; 2132#endif 2133 2134 /* unselect selected card or ... 2135 * draw new cards from the remains of the deck */ 2136 case SOL_DRAW: 2137#ifdef SOL_DRAW_PRE 2138 if( lastbutton != SOL_DRAW_PRE ) 2139 break; 2140#endif 2141 if( sel_card != NOT_A_CARD ) 2142 { 2143 /* unselect selected card */ 2144 sel_card = NOT_A_CARD; 2145 break; 2146 } 2147 if( rem != NOT_A_CARD ) 2148 { 2149 int cur_rem_old = cur_rem; 2150 count_rem = -1; 2151 /* draw new cards form the remains of the deck */ 2152 if( cur_rem == NOT_A_CARD ) 2153 { 2154 /*if the cursor card is null*/ 2155 cur_rem = rem; 2156 i = cards_per_draw - 1; 2157 count_rem++; 2158 } 2159 else 2160 { 2161 i = cards_per_draw; 2162 } 2163 2164 while( i > 0 && deck[cur_rem].next != NOT_A_CARD ) 2165 { 2166 cur_rem = deck[cur_rem].next; 2167 i--; 2168 count_rem++; 2169 } 2170 /* test if any cards are really left on 2171 * the remains' stack */ 2172 if( i == cards_per_draw ) 2173 { 2174 cur_rem = NOT_A_CARD; 2175 count_rem = -1; 2176 } 2177 /* if cursor was on remains' stack when new cards were 2178 * drawn, put cursor on top of remains' stack */ 2179 if( cur_col == REM_COL && cur_card == cur_rem_old ) 2180 { 2181 cur_card = cur_rem; 2182 sel_card = NOT_A_CARD; 2183 } 2184 } 2185 break; 2186 2187 /* Show the menu */ 2188#ifdef SOL_RC_QUIT 2189 case SOL_RC_QUIT: 2190#endif 2191 case SOL_QUIT: 2192 switch( solitaire_menu(true) ) 2193 { 2194 case MENU_SAVE_AND_QUIT: 2195 return SOLITAIRE_SAVE_AND_QUIT; 2196 2197 case MENU_QUIT: 2198 return SOLITAIRE_QUIT; 2199 2200 case MENU_USB: 2201 return SOLITAIRE_USB; 2202 } 2203 break; 2204 2205 case SYS_POWEROFF: 2206 case SYS_REBOOT: 2207 return SOLITAIRE_SAVE_AND_QUIT; 2208 2209 default: 2210 if( rb->default_event_handler( button ) == SYS_USB_CONNECTED ) 2211 return SOLITAIRE_USB; 2212 break; 2213 } 2214 2215#ifdef NEED_LASTBUTTON_VAR 2216 if( button != BUTTON_NONE ) 2217 lastbutton = button; 2218#endif 2219 2220 /* fix incoherences concerning cur_col and cur_card */ 2221 c = find_card_col( cur_card ); 2222 if( c != NOT_A_COL && c != cur_col ) 2223 cur_card = find_last_card( cur_col ); 2224 2225 if( cur_card == NOT_A_CARD 2226 && find_last_card( cur_col ) != NOT_A_CARD ) 2227 cur_card = find_last_card( cur_col ); 2228 2229 rb->yield(); 2230 } 2231} 2232 2233/** 2234 * Plugin entry point 2235 */ 2236 2237enum plugin_status plugin_start(const void* parameter ) 2238{ 2239 int result; 2240 2241 /* plugin init */ 2242 (void)parameter; 2243 2244 configfile_load(CONFIG_FILENAME, config, 2245 sizeof(config) / sizeof(config[0]), CFGFILE_VERSION); 2246 rb->memcpy(&sol, &sol_disk, sizeof(sol)); /* copy to running config */ 2247 2248 if( load_game() == 0 ) 2249 { 2250 rb->splash( HZ, "Resuming saved game." ); 2251 result = SOLITAIRE_QUIT; 2252 } 2253 else 2254 result = SOLITAIRE_WIN; 2255 2256 /* play the game :) 2257 * Keep playing if a game was won (that means display the menu after 2258 * winning instead of quiting) */ 2259 while( ( result = solitaire( result ) ) == SOLITAIRE_WIN ); 2260 2261 if( result != SOLITAIRE_QUIT ) 2262 /* result == SOLITAIRE_USB || result == SOLITAIRE_SAVE_AND_QUIT */ 2263 save_game(); 2264 2265 if (rb->memcmp(&sol, &sol_disk, sizeof(sol))) /* save settings if changed */ 2266 { 2267 rb->memcpy(&sol_disk, &sol, sizeof(sol)); 2268 configfile_save(CONFIG_FILENAME, config, 2269 sizeof(config) / sizeof(config[0]), CFGFILE_VERSION); 2270 } 2271 2272 /* Exit the plugin */ 2273 return ( result == SOLITAIRE_USB ) ? PLUGIN_USB_CONNECTED : PLUGIN_OK; 2274}