PageRenderTime 128ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/source/mupen64launcher/src/cselector.cpp

https://github.com/notaz/mupen64plus-pandora
C++ | 2678 lines | 2291 code | 284 blank | 103 comment | 522 complexity | 06c0ec8b69bad6d99a5ac29ad332b597 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, LGPL-3.0, GPL-3.0, LGPL-2.1
  1. /**
  2. * @section LICENSE
  3. *
  4. * PickleLauncher
  5. * Copyright (C) 2010-2011 Scott Smith
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. * @section LOCATION
  21. */
  22. #include "cselector.h"
  23. CSelector::CSelector() : CBase(),
  24. Redraw (true),
  25. SkipFrame (false),
  26. Rescan (true),
  27. RefreshList (true),
  28. SetOneEntryValue (false),
  29. SetAllEntryValue (false),
  30. TextScrollDir (true),
  31. ExtractAllFiles (false),
  32. DrawState_Title (true),
  33. DrawState_About (true),
  34. DrawState_Filter (true),
  35. DrawState_FilePath (true),
  36. DrawState_Index (true),
  37. DrawState_ZipMode (true),
  38. DrawState_Preview (true),
  39. DrawState_ButtonL (true),
  40. DrawState_ButtonR (true),
  41. Mode (MODE_SELECT_ENTRY),
  42. LastSelectedEntry (0),
  43. TextScrollOffset (0),
  44. CurScrollSpeed (0),
  45. CurScrollPause (0),
  46. ListNameHeight (0),
  47. FramesDrawn (0),
  48. FramesSkipped (0),
  49. FramesSleep (0),
  50. #if defined(DEBUG)
  51. FPSDrawn (0),
  52. FPSSkip (0),
  53. FPSSleep (0),
  54. FrameCountTime (0),
  55. LoopTimeAverage (0),
  56. #endif
  57. FrameEndTime (0),
  58. FrameStartTime (0),
  59. FrameDelay (0),
  60. Mouse (),
  61. Joystick (NULL),
  62. Screen (NULL),
  63. ImageBackground (NULL),
  64. ImagePointer (NULL),
  65. ImageSelectPointer (NULL),
  66. ImagePreview (NULL),
  67. ImageTitle (NULL),
  68. ImageAbout (NULL),
  69. ImageFilePath (NULL),
  70. ImageFilter (NULL),
  71. ImageIndex (NULL),
  72. ImageZipMode (NULL),
  73. #if defined(DEBUG)
  74. ImageDebug (NULL),
  75. #endif
  76. ImageButtons (),
  77. Fonts (),
  78. Config (),
  79. Profile (),
  80. System (),
  81. ConfigPath (DEF_CONFIG),
  82. ProfilePath (DEF_PROFILE),
  83. ZipListPath (DEF_ZIPLIST),
  84. EventReleased (),
  85. EventPressCount (),
  86. ButtonModesLeft (),
  87. ButtonModesRight (),
  88. DisplayList (),
  89. LabelButtons (),
  90. ListNames (),
  91. ItemsEntry (),
  92. ItemsArgument (),
  93. ItemsValue (),
  94. ItemsDefPlugin (),
  95. WhichPlugin (0),
  96. ItemsRomOption (),
  97. ItemsRomPlugin (),
  98. WhichRomPlugin (0),
  99. RectEntries (),
  100. RectButtonsLeft (),
  101. RectButtonsRight (),
  102. ScreenRectsDirty ()
  103. {
  104. Fonts.resize( FONT_SIZE_TOTAL, NULL );
  105. ButtonModesLeft.resize( BUTTONS_MAX_LEFT );
  106. ButtonModesRight.resize( BUTTONS_MAX_RIGHT );
  107. RectButtonsLeft.resize( BUTTONS_MAX_LEFT );
  108. RectButtonsRight.resize( BUTTONS_MAX_RIGHT );
  109. ImageButtons.resize( EVENT_TOTAL, NULL );
  110. LabelButtons.resize( EVENT_TOTAL, "" );
  111. LabelButtons.at(EVENT_ONE_UP) = BUTTON_LABEL_ONE_UP;
  112. LabelButtons.at(EVENT_ONE_DOWN) = BUTTON_LABEL_ONE_DOWN;
  113. LabelButtons.at(EVENT_PAGE_UP) = BUTTON_LABEL_PAGE_UP;
  114. LabelButtons.at(EVENT_PAGE_DOWN) = BUTTON_LABEL_PAGE_DOWN;
  115. LabelButtons.at(EVENT_DIR_UP) = BUTTON_LABEL_DIR_UP;
  116. LabelButtons.at(EVENT_DIR_DOWN) = BUTTON_LABEL_DIR_DOWN;
  117. LabelButtons.at(EVENT_ZIP_MODE) = BUTTON_LABEL_ZIP_MODE;
  118. LabelButtons.at(EVENT_CFG_APP) = BUTTON_LABEL_CONFIG;
  119. LabelButtons.at(EVENT_CFG_ITEM) = BUTTON_LABEL_EDIT;
  120. LabelButtons.at(EVENT_SET_ONE) = BUTTON_LABEL_SET_ONE;
  121. LabelButtons.at(EVENT_SET_ALL) = BUTTON_LABEL_SET_ALL;
  122. LabelButtons.at(EVENT_BACK) = BUTTON_LABEL_BACK;
  123. LabelButtons.at(EVENT_SELECT) = BUTTON_LABEL_SELECT;
  124. LabelButtons.at(EVENT_QUIT) = BUTTON_LABEL_QUIT;
  125. DisplayList.resize( MODE_TOTAL );
  126. EventPressCount.resize( EVENT_TOTAL, EVENT_LOOPS_OFF );
  127. EventReleased.resize( EVENT_TOTAL, false );
  128. }
  129. CSelector::~CSelector()
  130. {
  131. }
  132. int8_t CSelector::Run( int32_t argc, char** argv )
  133. {
  134. int8_t result;
  135. int16_t selection;
  136. result = 0;
  137. ProcessArguments( argc, argv );
  138. System.SetCPUClock( Config.CPUClock );
  139. // Load video,input,profile resources
  140. if (OpenResources())
  141. {
  142. result = 1;
  143. }
  144. // Display and poll the user for a selection
  145. if (result == 0)
  146. {
  147. selection = DisplayScreen();
  148. // Setup a exec script for execution following termination of this application
  149. if (selection >= 0)
  150. {
  151. if (RunExec( selection ))
  152. {
  153. result = 1;
  154. }
  155. }
  156. else if (selection < -1)
  157. {
  158. result = 1;
  159. }
  160. else
  161. {
  162. result = 0;
  163. }
  164. }
  165. // Release resources
  166. CloseResources( result );
  167. return result;
  168. }
  169. void CSelector::ProcessArguments( int argc, char** argv )
  170. {
  171. uint8_t arg_index;
  172. string launcher;
  173. string argument;
  174. launcher = string(argv[0]);
  175. Profile.LauncherName = launcher.substr( launcher.find_last_of('/')+1 );
  176. Profile.LauncherPath = launcher.substr( 0, launcher.find_last_of('/')+1 );
  177. if (Profile.LauncherPath.compare("./") == 0 || Profile.LauncherPath.length() == 0)
  178. {
  179. Profile.LauncherPath = string(getenv("PWD"))+"/";
  180. }
  181. #if defined(DEBUG)
  182. Log( "Running from '%s'\n", launcher.c_str() );
  183. #endif
  184. Log( "Running from '%s' as '%s'\n", Profile.LauncherPath.c_str(), Profile.LauncherName.c_str() );
  185. for (arg_index=0; arg_index<argc; arg_index++ )
  186. {
  187. argument = string(argv[arg_index]);
  188. if (argument.compare( ARG_RESETGUI ) == 0)
  189. {
  190. Config.ResetGUI = true;
  191. }
  192. else
  193. if (argument.compare( ARG_PROFILE ) == 0)
  194. {
  195. ProfilePath = string(argv[++arg_index]);
  196. }
  197. else
  198. if (argument.compare( ARG_CONFIG ) == 0)
  199. {
  200. ConfigPath = string(argv[++arg_index]);
  201. }
  202. else
  203. if (argument.compare( ARG_ZIPLIST ) == 0)
  204. {
  205. ZipListPath = string(argv[++arg_index]);
  206. }
  207. }
  208. }
  209. int8_t CSelector::OpenResources( void )
  210. {
  211. uint8_t button_index;
  212. uint32_t flags;
  213. string text;
  214. Log( "Loading config.\n" );
  215. if (Config.Load( ConfigPath ))
  216. {
  217. Log( "Failed to load config\n" );
  218. return 1;
  219. }
  220. Log( "Loading ziplist.\n" );
  221. if (Config.UseZipSupport == true && Profile.Minizip.LoadUnzipList( ZipListPath ))
  222. {
  223. Log( "Failed to load ziplist\n" );
  224. return 1;
  225. }
  226. // Initialize defaults, Video and Audio subsystems
  227. Log( "Initializing SDL.\n" );
  228. if (SDL_Init( SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_TIMER|SDL_INIT_JOYSTICK )==-1)
  229. {
  230. Log( "Failed to initialize SDL: %s.\n", SDL_GetError() );
  231. return 1;
  232. }
  233. Log( "SDL initialized.\n" );
  234. // Setup SDL Screen
  235. flags = SCREEN_FLAGS;
  236. if (Config.Fullscreen == true)
  237. {
  238. flags |= SDL_FULLSCREEN;
  239. }
  240. Screen = SDL_SetVideoMode( Config.ScreenWidth, Config.ScreenHeight, Config.ScreenDepth, flags );
  241. if (Screen == NULL)
  242. {
  243. Log( "Failed to %dx%dx%d video mode: %s\n", Config.ScreenWidth, Config.ScreenHeight, Config.ScreenDepth, SDL_GetError() );
  244. return 1;
  245. }
  246. // Refresh entire screen for the first frame
  247. UpdateRect( 0, 0, Config.ScreenWidth, Config.ScreenHeight );
  248. // Load joystick
  249. #if !defined(PANDORA) && !defined(X86)
  250. Joystick = SDL_JoystickOpen(0);
  251. if (Joystick == NULL)
  252. {
  253. Log( "Warning failed to open first joystick: %s\n", SDL_GetError() );
  254. }
  255. #endif
  256. // Setup TTF SDL
  257. if (TTF_Init() == -1)
  258. {
  259. Log( "Failed to init TTF_Init: %s\n", TTF_GetError() );
  260. return 1;
  261. }
  262. // Load ttf font
  263. Fonts.at(FONT_SIZE_SMALL) = TTF_OpenFont( Config.PathFont.c_str(), Config.FontSizes.at(FONT_SIZE_SMALL) );
  264. if (!Fonts.at(FONT_SIZE_SMALL))
  265. {
  266. Log( "Failed to open small TTF_OpenFont: %s\n", TTF_GetError() );
  267. return 1;
  268. }
  269. Fonts.at(FONT_SIZE_MEDIUM) = TTF_OpenFont( Config.PathFont.c_str(), Config.FontSizes.at(FONT_SIZE_MEDIUM) );
  270. if (!Fonts.at(FONT_SIZE_MEDIUM))
  271. {
  272. Log( "Failed to open medium TTF_OpenFont: %s\n", TTF_GetError() );
  273. return 1;
  274. }
  275. Fonts.at(FONT_SIZE_LARGE) = TTF_OpenFont( Config.PathFont.c_str(), Config.FontSizes.at(FONT_SIZE_LARGE) );
  276. if (!Fonts.at(FONT_SIZE_LARGE))
  277. {
  278. Log( "Failed to open large TTF_OpenFont: %s\n", TTF_GetError() );
  279. return 1;
  280. }
  281. Log( "Loading profile.\n" );
  282. if (Profile.Load( ProfilePath, Config.Delimiter ))
  283. {
  284. Log( "Failed to load profile\n" );
  285. return 1;
  286. }
  287. // Load images
  288. ImageBackground = LoadImage( Config.PathBackground );
  289. for (button_index=0; button_index<Config.PathButtons.size(); button_index++)
  290. {
  291. ImageButtons.at(button_index) = LoadImage( Config.PathButtons.at(button_index) );
  292. }
  293. // Mouse pointer
  294. if (Config.ShowPointer==true)
  295. {
  296. ImagePointer = LoadImage( Config.PathPointer );
  297. if (ImagePointer == NULL)
  298. {
  299. SDL_ShowCursor( SDL_ENABLE );
  300. }
  301. else
  302. {
  303. SDL_ShowCursor( SDL_DISABLE );
  304. }
  305. }
  306. else
  307. {
  308. SDL_ShowCursor( SDL_DISABLE );
  309. }
  310. // List selector pointer
  311. ImageSelectPointer = LoadImage( Config.PathSelectPointer );
  312. if (ImageSelectPointer == NULL)
  313. {
  314. ImageSelectPointer = TTF_RenderText_Solid( Fonts.at(FONT_SIZE_MEDIUM), ENTRY_ARROW, Config.Colors.at(COLOR_BLACK) );
  315. }
  316. // Title text
  317. text = string(APPNAME) + " " + string(APPVERSION);
  318. if (Profile.TargetApp.length() > 0)
  319. {
  320. text += " for " + Profile.TargetApp;
  321. }
  322. ImageTitle = TTF_RenderText_Solid( Fonts.at(FONT_SIZE_LARGE), text.c_str(), Config.Colors.at(Config.ColorFontFiles) );
  323. if (ImageTitle == NULL)
  324. {
  325. Log( "Failed to create TTF surface with TTF_RenderText_Solid: %s\n", TTF_GetError() );
  326. return 1;
  327. }
  328. // About text
  329. text = "Written by " + string(APPAUTHOR) + " " + string(APPCOPYRIGHT);
  330. ImageAbout = TTF_RenderText_Solid( Fonts.at(FONT_SIZE_SMALL), text.c_str(), Config.Colors.at(Config.ColorFontFiles) );
  331. if (ImageAbout == NULL)
  332. {
  333. Log( "Failed to create TTF surface with TTF_RenderText_Solid: %s\n", TTF_GetError() );
  334. return 1;
  335. }
  336. return 0;
  337. }
  338. void CSelector::CloseResources( int8_t result )
  339. {
  340. uint8_t button_index;
  341. if (result == 0)
  342. {
  343. Config.Save( ConfigPath );
  344. Profile.Save( ProfilePath, Config.Delimiter );
  345. }
  346. if (Config.UseZipSupport == true)
  347. {
  348. Profile.Minizip.SaveUnzipList( ZipListPath );
  349. }
  350. // Close joystick
  351. if (Joystick != NULL)
  352. {
  353. Log( "Closing SDL Joystick.\n" );
  354. SDL_JoystickClose( Joystick );
  355. Joystick = NULL;
  356. }
  357. // Close fonts
  358. Log( "Closing TTF fonts.\n" );
  359. if (Fonts.at(FONT_SIZE_SMALL) != NULL)
  360. {
  361. TTF_CloseFont( Fonts.at(FONT_SIZE_SMALL) );
  362. Fonts.at(FONT_SIZE_SMALL) = NULL;
  363. }
  364. if (Fonts.at(FONT_SIZE_MEDIUM) != NULL)
  365. {
  366. TTF_CloseFont( Fonts.at(FONT_SIZE_MEDIUM) );
  367. Fonts.at(FONT_SIZE_MEDIUM) = NULL;
  368. }
  369. if (Fonts.at(FONT_SIZE_LARGE) != NULL)
  370. {
  371. TTF_CloseFont( Fonts.at(FONT_SIZE_LARGE) );
  372. Fonts.at(FONT_SIZE_LARGE) = NULL;
  373. }
  374. // Free images
  375. FREE_IMAGE( ImageBackground );
  376. FREE_IMAGE( ImagePointer );
  377. FREE_IMAGE( ImageSelectPointer );
  378. FREE_IMAGE( ImagePreview );
  379. FREE_IMAGE( ImageTitle );
  380. FREE_IMAGE( ImageAbout );
  381. FREE_IMAGE( ImageFilePath );
  382. FREE_IMAGE( ImageFilter );
  383. FREE_IMAGE( ImageIndex );
  384. FREE_IMAGE( ImageZipMode );
  385. #if defined(DEBUG)
  386. FREE_IMAGE( ImageDebug );
  387. #endif
  388. for (button_index=0; button_index<ImageButtons.size(); button_index++)
  389. {
  390. FREE_IMAGE( ImageButtons.at(button_index) );
  391. }
  392. Log( "Quitting TTF.\n" );
  393. TTF_Quit();
  394. Log( "Quitting SDL.\n" );
  395. SDL_Quit();
  396. // Flush all std buffers before exit
  397. fflush( stdout );
  398. fflush( stderr );
  399. }
  400. int16_t CSelector::DisplayScreen( void )
  401. {
  402. while (IsEventOff(EVENT_QUIT) == true && (IsEventOff(EVENT_SELECT) == true || Mode != MODE_SELECT_ENTRY) )
  403. {
  404. // Get user input
  405. if (PollInputs())
  406. {
  407. return -2;
  408. }
  409. // Select the mode
  410. SelectMode();
  411. // Configure the buttons according to the mode
  412. if (ConfigureButtons())
  413. {
  414. return -2;
  415. }
  416. // Draw the selector
  417. if (DisplaySelector())
  418. {
  419. return -2;
  420. }
  421. // Update the screen
  422. UpdateScreen();
  423. }
  424. if (IsEventOn( EVENT_QUIT ) == true)
  425. {
  426. // Detete any files exracted from zip
  427. Profile.Minizip.DelUnzipFiles();
  428. return -1;
  429. }
  430. else
  431. {
  432. return DisplayList.at(MODE_SELECT_ENTRY).absolute;
  433. }
  434. }
  435. void CSelector::UpdateRect( int16_t x, int16_t y, int16_t w, int16_t h )
  436. {
  437. SDL_Rect rect;
  438. if (Config.ScreenFlip == false)
  439. {
  440. // Safety Checks
  441. if( x < 0 )
  442. {
  443. x = 0;
  444. Log( "ERROR: UpdateRect X was out of bounds\n" );
  445. }
  446. if( y < 0 )
  447. {
  448. y = 0;
  449. Log( "ERROR: UpdateRect Y was out of bounds\n" );
  450. }
  451. if( h < 0 )
  452. {
  453. h = 0;
  454. Log( "ERROR: UpdateRect X was out of bounds\n" );
  455. }
  456. if( w < 0 )
  457. {
  458. w = 0;
  459. Log( "ERROR: UpdateRect Y was out of bounds\n" );
  460. }
  461. if( x > Config.ScreenWidth )
  462. {
  463. x = Config.ScreenWidth-1;
  464. Log( "ERROR: UpdateRect X was out of bounds\n" );
  465. }
  466. if( y > Config.ScreenHeight )
  467. {
  468. y = Config.ScreenHeight-1;
  469. Log( "ERROR: UpdateRect Y was out of bounds\n" );
  470. }
  471. if( x + w > Config.ScreenWidth )
  472. {
  473. w = Config.ScreenWidth-x;
  474. Log( "ERROR: UpdateRect W was out of bounds\n" );
  475. }
  476. if( y + h > Config.ScreenHeight )
  477. {
  478. h = Config.ScreenHeight-y;
  479. Log( "ERROR: UpdateRect H was out of bounds\n" );
  480. }
  481. rect.x = x;
  482. rect.y = y;
  483. rect.w = w;
  484. rect.h = h;
  485. ScreenRectsDirty.push_back( rect );
  486. }
  487. }
  488. void CSelector::UpdateScreen( void )
  489. {
  490. #if defined(DEBUG_FORCE_REDRAW)
  491. Redraw = true;
  492. #endif
  493. if (SkipFrame == false && Redraw == true)
  494. {
  495. if (Config.ScreenFlip == true)
  496. {
  497. if (SDL_Flip( Screen ) != 0)
  498. {
  499. Log( "Failed to swap the buffers: %s\n", SDL_GetError() );
  500. }
  501. }
  502. else
  503. {
  504. SDL_UpdateRects( Screen, ScreenRectsDirty.size(), &ScreenRectsDirty[0] );
  505. }
  506. Redraw = false;
  507. FramesDrawn++;
  508. }
  509. else
  510. {
  511. if (SkipFrame == true)
  512. {
  513. FramesSkipped++;
  514. }
  515. else
  516. {
  517. FramesSleep++;
  518. }
  519. }
  520. ScreenRectsDirty.clear();
  521. FrameEndTime = SDL_GetTicks();
  522. FrameDelay = (MS_PER_SEC/FRAMES_PER_SEC) - (FrameEndTime - FrameStartTime);
  523. #if defined(DEBUG_FPS)
  524. LoopTimeAverage = (LoopTimeAverage + (FrameEndTime - FrameStartTime))/2;
  525. #endif
  526. if (FrameDelay < 0)
  527. {
  528. if (FramesSkipped/FramesDrawn < FRAME_SKIP_RATIO)
  529. {
  530. SkipFrame = true;
  531. }
  532. else // Force a frame to be drawn
  533. {
  534. SkipFrame = false;
  535. }
  536. }
  537. else
  538. {
  539. SkipFrame = false;
  540. SDL_Delay( MIN(FrameDelay, MS_PER_SEC) );
  541. }
  542. FrameStartTime = SDL_GetTicks();
  543. #if defined(DEBUG_FPS)
  544. if (FrameStartTime - FrameCountTime >= MS_PER_SEC)
  545. {
  546. FrameCountTime = FrameStartTime;
  547. FPSDrawn = FramesDrawn;
  548. FPSSkip = FramesSkipped;
  549. FPSSleep = FramesSleep;
  550. FramesDrawn = 1;
  551. FramesSkipped = 0;
  552. FramesSleep = 0;
  553. cout << "DEBUG total " << i_to_a(FPSDrawn+FPSSkip+FPSSleep)
  554. << " fps " << i_to_a(FPSDrawn) << " skip " << i_to_a(FPSSkip) << " slp " << i_to_a(FPSSleep)
  555. << " loop " << i_to_a(LoopTimeAverage) << endl;
  556. }
  557. #endif
  558. }
  559. void CSelector::SelectMode( void )
  560. {
  561. uint8_t old_mode;
  562. old_mode = Mode;
  563. switch (Mode)
  564. {
  565. case MODE_SELECT_ENTRY:
  566. if (IsEventOn( EVENT_CFG_ITEM ) == true)
  567. {
  568. if (ItemsEntry.size()>0)
  569. {
  570. if (ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Type == TYPE_FILE )
  571. // || (ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Type == TYPE_DIR && Profile.LaunchableDirs == true))
  572. {
  573. // Profile.ScanRomPlugins(Profile.FilePath+ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Name, ItemsRomOption);
  574. // Per Rom Plugin selection. Find ROMCRC and Load Plugins for this rom
  575. Mode = MODE_ROM_OPTION;
  576. }
  577. }
  578. }
  579. else if (IsEventOn( EVENT_CFG_APP ) == true)
  580. {
  581. Mode = MODE_SELECT_OPTION;
  582. }
  583. break;
  584. case MODE_SELECT_ARGUMENT:
  585. if (IsEventOn( EVENT_BACK ) == true)
  586. {
  587. Mode = MODE_SELECT_ENTRY;
  588. }
  589. if (IsEventOn( EVENT_SELECT ) == true)
  590. {
  591. Mode = MODE_SELECT_VALUE;
  592. }
  593. break;
  594. case MODE_SELECT_VALUE:
  595. if (IsEventOn( EVENT_BACK ) == true)
  596. {
  597. Mode = MODE_SELECT_ARGUMENT;
  598. }
  599. break;
  600. case MODE_SELECT_OPTION:
  601. if (IsEventOn( EVENT_BACK ) == true)
  602. {
  603. Mode = MODE_SELECT_ENTRY;
  604. }
  605. if (IsEventOn( EVENT_SELECT ) == true)
  606. {
  607. WhichPlugin = DisplayList.at(MODE_SELECT_OPTION).absolute;
  608. Mode = MODE_SELECT_PLUGIN;
  609. }
  610. break;
  611. case MODE_ROM_OPTION:
  612. if (IsEventOn( EVENT_BACK ) == true)
  613. {
  614. Mode = MODE_SELECT_ENTRY;
  615. }
  616. if (IsEventOn( EVENT_SELECT ) == true)
  617. {
  618. WhichPlugin = DisplayList.at(MODE_ROM_OPTION).absolute;
  619. Mode = MODE_ROM_PLUGIN;
  620. }
  621. break;
  622. case MODE_SELECT_PLUGIN:
  623. if (IsEventOn( EVENT_BACK ) == true)
  624. {
  625. Mode = MODE_SELECT_OPTION;
  626. }
  627. if (IsEventOn( EVENT_SELECT ) == true)
  628. {
  629. Profile.SaveDef1Plugin(WhichPlugin, DisplayList.at(MODE_SELECT_PLUGIN).absolute);
  630. Mode = MODE_SELECT_OPTION;
  631. }
  632. break;
  633. case MODE_ROM_PLUGIN:
  634. if (IsEventOn( EVENT_BACK ) == true)
  635. {
  636. Mode = MODE_ROM_OPTION;
  637. }
  638. if (IsEventOn( EVENT_SELECT ) == true)
  639. {
  640. Profile.SaveRom1Plugin(WhichPlugin, ItemsRomPlugin[DisplayList.at(MODE_ROM_PLUGIN).absolute].Entry);
  641. Mode = MODE_ROM_OPTION;
  642. }
  643. break;
  644. default:
  645. Mode = MODE_SELECT_ENTRY;
  646. Log( "Error: Unknown Mode\n" );
  647. break;
  648. }
  649. if (Mode != old_mode)
  650. {
  651. DrawState_ButtonL = true;
  652. DrawState_ButtonR = true;
  653. Rescan = true;
  654. }
  655. }
  656. int8_t CSelector::DisplaySelector( void )
  657. {
  658. SDL_Rect rect_pos = { Config.EntryXOffset, Config.EntryYOffset, 0 ,0 };
  659. if (Rescan)
  660. {
  661. RescanItems();
  662. RefreshList = true;
  663. Rescan = false;
  664. }
  665. if (RefreshList)
  666. {
  667. PopulateList();
  668. DrawState_Index = true;
  669. Redraw = true;
  670. RefreshList = false;
  671. }
  672. if (Redraw == true || CurScrollPause != 0 || CurScrollSpeed != 0 || TextScrollOffset != 0)
  673. {
  674. if (Config.ScreenFlip == true)
  675. {
  676. DrawState_Title = true;
  677. DrawState_About = true;
  678. DrawState_Filter = true;
  679. DrawState_FilePath = true;
  680. DrawState_Index = true;
  681. DrawState_ZipMode = true;
  682. DrawState_Preview = true;
  683. DrawState_ButtonL = true;
  684. DrawState_ButtonR = true;
  685. }
  686. #if defined(DEBUG_DRAW_STATES)
  687. else
  688. {
  689. cout << "DEBUG "
  690. << " " << i_to_a(DrawState_Title)
  691. << " " << i_to_a(DrawState_About)
  692. << " " << i_to_a(DrawState_Filter)
  693. << " " << i_to_a(DrawState_FilePath)
  694. << " " << i_to_a(DrawState_Index)
  695. << " " << i_to_a(DrawState_ZipMode)
  696. << " " << i_to_a(DrawState_Preview)
  697. << " " << i_to_a(DrawState_ButtonL)
  698. << " " << i_to_a(DrawState_ButtonR) << endl;
  699. }
  700. #endif
  701. // Draw background or clear screen
  702. DrawBackground();
  703. // Draw text titles to the screen
  704. if (DrawText( rect_pos ))
  705. {
  706. return 1;
  707. }
  708. // Draw the buttons for touchscreen
  709. if (DrawButtons( rect_pos ))
  710. {
  711. return 1;
  712. }
  713. // Draw the names for the items for display
  714. if (DrawNames( rect_pos ))
  715. {
  716. return 1;
  717. }
  718. // Custom mouse pointer
  719. if (Config.ShowPointer == true && ImagePointer != NULL)
  720. {
  721. ApplyImage( Mouse.x, Mouse.y, ImagePointer, Screen, NULL );
  722. }
  723. }
  724. return 0;
  725. }
  726. void CSelector::DirectoryUp( void )
  727. {
  728. if (Profile.FilePath.length() > 0)
  729. {
  730. if (Profile.FilePath.at( Profile.FilePath.length()-1) == '/')
  731. {
  732. Profile.FilePath.erase( Profile.FilePath.length()-1 );
  733. }
  734. Profile.FilePath = Profile.FilePath.substr( 0, Profile.FilePath.find_last_of('/', Profile.FilePath.length()-1) ) + '/';
  735. DrawState_FilePath = true;
  736. Rescan = true;
  737. }
  738. else
  739. {
  740. Log( "Error: Filepath is empty\n" );
  741. }
  742. }
  743. void CSelector::DirectoryDown( void )
  744. {
  745. if (DisplayList.at(MODE_SELECT_ENTRY).absolute < (int16_t)ItemsEntry.size() )
  746. {
  747. if (ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Type == TYPE_DIR )
  748. {
  749. Profile.FilePath += ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Name + '/';
  750. DrawState_FilePath = true;
  751. Rescan = true;
  752. EventPressCount.at(EVENT_SELECT) = EVENT_LOOPS_OFF;
  753. }
  754. }
  755. else
  756. {
  757. Log( "Error: Item index of %d too large for size of scanitems %d\n", DisplayList.at(MODE_SELECT_ENTRY).absolute, ItemsEntry.size() );
  758. }
  759. }
  760. void CSelector::ZipUp( void )
  761. {
  762. DrawState_FilePath = true;
  763. DrawState_ZipMode = true;
  764. DrawState_ButtonL = true;
  765. Rescan = true;
  766. Profile.ZipFile = "";
  767. }
  768. void CSelector::ZipDown( void )
  769. {
  770. DrawState_FilePath = true;
  771. DrawState_ZipMode = true;
  772. DrawState_ButtonL = true;
  773. Rescan = true;
  774. Profile.ZipFile = ItemsEntry.at(DisplayList.at(Mode).absolute).Name;
  775. EventPressCount.at( EVENT_SELECT ) = EVENT_LOOPS_OFF;
  776. }
  777. void CSelector::RescanItems( void )
  778. {
  779. uint16_t total;
  780. switch (Mode)
  781. {
  782. case MODE_SELECT_ENTRY:
  783. Profile.ScanDir( Profile.FilePath, Config.ShowHidden, Config.UseZipSupport, ItemsEntry );
  784. total = ItemsEntry.size();
  785. break;
  786. case MODE_SELECT_ARGUMENT:
  787. Profile.ScanEntry( ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute), ItemsArgument );
  788. total = ItemsArgument.size();
  789. break;
  790. case MODE_SELECT_VALUE:
  791. Profile.ScanArgument( ItemsArgument.at(DisplayList.at(MODE_SELECT_ARGUMENT).absolute), ItemsValue );
  792. total = ItemsValue.size();
  793. break;
  794. case MODE_SELECT_OPTION:
  795. //Profile.ScanOptions( ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute), ItemsArgument );
  796. Profile.ScanDefPlugins( ItemsArgument );
  797. total = ItemsArgument.size();
  798. break;
  799. case MODE_ROM_OPTION:
  800. //Profile.ScanOptions( ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute), ItemsArgument );
  801. Profile.ScanRomPlugins(Profile.FilePath+ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Name, ItemsRomOption);
  802. total = ItemsRomOption.size();
  803. break;
  804. case MODE_SELECT_PLUGIN:
  805. //Profile.ScanOptions( ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute), ItemsArgument );
  806. Profile.ScanDef1Plugins( WhichPlugin, ItemsDefPlugin );
  807. total = ItemsDefPlugin.size();
  808. break;
  809. case MODE_ROM_PLUGIN:
  810. //Profile.ScanOptions( ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute), ItemsArgument );
  811. Profile.ScanRom1Plugins( WhichPlugin, ItemsRomPlugin );
  812. total = ItemsRomPlugin.size();
  813. break;
  814. default:
  815. total = 0;
  816. Log( "Error: Unknown Mode\n" );
  817. break;
  818. }
  819. if (total > Config.MaxEntries)
  820. {
  821. RectEntries.resize( Config.MaxEntries );
  822. }
  823. else
  824. {
  825. RectEntries.resize( total );
  826. }
  827. ListNames.resize( RectEntries.size() );
  828. DisplayList.at(Mode).absolute = 0;
  829. DisplayList.at(Mode).relative = 0;
  830. DisplayList.at(Mode).first = 0;
  831. DisplayList.at(Mode).last = 0;
  832. DisplayList.at(Mode).total = total;
  833. }
  834. void CSelector::PopulateList( void )
  835. {
  836. // Set limits
  837. SelectionLimits( DisplayList.at( Mode ) );
  838. switch (Mode)
  839. {
  840. case MODE_SELECT_ENTRY:
  841. PopModeEntry();
  842. break;
  843. case MODE_SELECT_ARGUMENT:
  844. PopModeArgument();
  845. break;
  846. case MODE_SELECT_VALUE:
  847. PopModeValue();
  848. break;
  849. case MODE_SELECT_OPTION:
  850. PopModeOption();
  851. break;
  852. case MODE_ROM_OPTION:
  853. PopModeRomOption();
  854. break;
  855. case MODE_SELECT_PLUGIN:
  856. PopModePlugin();
  857. break;
  858. case MODE_ROM_PLUGIN:
  859. PopModeRomPlugin();
  860. break;
  861. default:
  862. Log( "Error: CSelector::PopulateList Unknown Mode\n" );
  863. break;
  864. }
  865. }
  866. void CSelector::PopModeEntry( void )
  867. {
  868. uint16_t i;
  869. uint16_t index;
  870. for (i=0; i<ListNames.size(); i++)
  871. {
  872. index = DisplayList.at( MODE_SELECT_ENTRY ).first+i;
  873. if (CheckRange( index, ItemsEntry.size() ))
  874. {
  875. ListNames.at(i).text.clear();
  876. if (ItemsEntry.at(index).Entry >= 0)
  877. {
  878. ListNames.at(i).text = Profile.Entries.at(ItemsEntry.at(index).Entry).Alias;
  879. }
  880. if (ListNames.at(i).text.length() == 0)
  881. {
  882. ListNames.at(i).text = ItemsEntry.at(index).Name;
  883. }
  884. if (Config.ShowExts == false)
  885. {
  886. ListNames.at(i).text = ListNames.at(i).text.substr( 0, ListNames.at(i).text.find_last_of(".") );
  887. }
  888. ListNames.at(i).text = ListNames.at(i).text;
  889. if (index == DisplayList.at(Mode).absolute)
  890. {
  891. ListNames.at(i).font = FONT_SIZE_LARGE;
  892. LoadPreview( ListNames.at(i).text ); // Load preview
  893. }
  894. else
  895. {
  896. ListNames.at(i).font = FONT_SIZE_MEDIUM;
  897. }
  898. ListNames.at(i).color = Config.ColorFontFiles;
  899. if (ItemsEntry.at(index).Type == TYPE_DIR)
  900. {
  901. ListNames.at(i).color = Config.ColorFontFolders;
  902. }
  903. }
  904. else
  905. {
  906. Log( "Error: CSelector::PopulateModeSelectEntry Index Error\n" );
  907. }
  908. }
  909. }
  910. void CSelector::PopModeArgument( void )
  911. {
  912. uint16_t i;
  913. uint16_t index;
  914. for (i=0; i<ListNames.size(); i++)
  915. {
  916. index = DisplayList.at(MODE_SELECT_ARGUMENT).first+i;
  917. if (CheckRange( index, ItemsArgument.size() ))
  918. {
  919. ListNames.at(i).text = ItemsArgument.at(index).Name;
  920. if (i == DisplayList.at(MODE_SELECT_ARGUMENT).absolute)
  921. {
  922. ListNames.at(i).font = FONT_SIZE_LARGE;
  923. }
  924. else
  925. {
  926. ListNames.at(i).font = FONT_SIZE_MEDIUM;
  927. }
  928. ListNames.at(i).color = Config.ColorFontFiles;
  929. }
  930. else
  931. {
  932. Log( "Error: PopModeArgument index is out of range\n" );
  933. }
  934. }
  935. }
  936. void CSelector::PopModeValue( void )
  937. {
  938. uint16_t i;
  939. uint16_t index;
  940. int16_t defvalue;
  941. int16_t entry;
  942. listoption_t argument;
  943. if (CheckRange(DisplayList.at(MODE_SELECT_ARGUMENT).absolute, ItemsArgument.size() ))
  944. {
  945. argument = ItemsArgument.at(DisplayList.at(MODE_SELECT_ARGUMENT).absolute);
  946. for (i=0; i<ListNames.size(); i++)
  947. {
  948. index = DisplayList.at(MODE_SELECT_VALUE).first+i;
  949. if (CheckRange( index, ItemsValue.size() ))
  950. {
  951. ListNames.at(i).text = ItemsValue.at(index);
  952. if (index == DisplayList.at(MODE_SELECT_VALUE).absolute)
  953. {
  954. ListNames.at(i).font = FONT_SIZE_LARGE;
  955. }
  956. else
  957. {
  958. ListNames.at(i).font = FONT_SIZE_MEDIUM;
  959. }
  960. // Detect the default value
  961. if (ItemsArgument.at(DisplayList.at(MODE_SELECT_ARGUMENT).absolute).Command >= 0)
  962. {
  963. if (SetAllEntryValue == true)
  964. {
  965. Profile.Commands.at(argument.Command).Arguments.at(argument.Argument).Default = DisplayList.at(MODE_SELECT_VALUE).absolute;
  966. }
  967. defvalue = Profile.Commands.at(argument.Command).Arguments.at(argument.Argument).Default;
  968. }
  969. else
  970. {
  971. if (SetAllEntryValue == true)
  972. {
  973. Profile.Extensions.at(argument.Extension).Arguments.at(argument.Argument).Default = DisplayList.at(MODE_SELECT_VALUE).absolute;
  974. }
  975. defvalue = Profile.Extensions.at(argument.Extension).Arguments.at(argument.Argument).Default;
  976. }
  977. if (index==defvalue)
  978. {
  979. ListNames.at(i).text += '*';
  980. }
  981. // Set the color for the selected item for the entry
  982. ListNames.at(i).color = Config.ColorFontFiles;
  983. if (ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Entry<0)
  984. {
  985. // A custom value has been selected, so create a new entry
  986. if (SetOneEntryValue == true)
  987. {
  988. entry = Profile.AddEntry( argument, ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Name );
  989. if (entry>0)
  990. {
  991. ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Entry = entry;
  992. }
  993. else
  994. {
  995. Log( "Error: Could not create new entry\n" );
  996. }
  997. }
  998. else if (index==defvalue)
  999. {
  1000. ListNames.at(i).color = COLOR_RED;
  1001. }
  1002. }
  1003. if (ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Entry>=0)
  1004. {
  1005. if (ItemsArgument.at(DisplayList.at(MODE_SELECT_ARGUMENT).absolute).Command >= 0)
  1006. {
  1007. if (SetOneEntryValue == true || SetAllEntryValue == true)
  1008. {
  1009. Profile.Entries.at(ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Entry).CmdValues.at(argument.Command+argument.Argument) = DisplayList.at(MODE_SELECT_VALUE).absolute;
  1010. }
  1011. if (index == Profile.Entries.at(ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Entry).CmdValues.at(argument.Command+argument.Argument))
  1012. {
  1013. ListNames.at(i).color = COLOR_RED;
  1014. }
  1015. }
  1016. else
  1017. {
  1018. if (SetOneEntryValue == true || SetAllEntryValue == true)
  1019. {
  1020. Profile.Entries.at(ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Entry).ArgValues.at(argument.Argument) = DisplayList.at(MODE_SELECT_VALUE).absolute;
  1021. }
  1022. if (index == Profile.Entries.at(ItemsEntry.at(DisplayList.at(MODE_SELECT_ENTRY).absolute).Entry).ArgValues.at(argument.Argument))
  1023. {
  1024. ListNames.at(i).color = COLOR_RED;
  1025. }
  1026. }
  1027. }
  1028. }
  1029. else
  1030. {
  1031. Log( "Error: PopModeValue index is out of range\n" );
  1032. }
  1033. }
  1034. }
  1035. else
  1036. {
  1037. Log( "Error: PopModeValue argument index out of range\n" );
  1038. }
  1039. }
  1040. void CSelector::PopModeOption( void )
  1041. {
  1042. uint16_t i;
  1043. uint16_t index;
  1044. for (i=0; i<ListNames.size(); i++)
  1045. {
  1046. index = DisplayList.at(MODE_SELECT_OPTION).first+i;
  1047. if (CheckRange( index, ItemsArgument.size() ))
  1048. {
  1049. ListNames.at(i).text = ItemsArgument.at(index).Name;
  1050. if (i == DisplayList.at(MODE_SELECT_OPTION).absolute)
  1051. {
  1052. ListNames.at(i).font = FONT_SIZE_LARGE;
  1053. }
  1054. else
  1055. {
  1056. ListNames.at(i).font = FONT_SIZE_MEDIUM;
  1057. }
  1058. ListNames.at(i).color = Config.ColorFontFiles;
  1059. }
  1060. else
  1061. {
  1062. Log( "Error: PopModeOption index is out of range\n" );
  1063. }
  1064. }
  1065. }
  1066. void CSelector::PopModePlugin( void )
  1067. {
  1068. uint16_t i;
  1069. uint16_t index;
  1070. for (i=0; i<ListNames.size(); i++)
  1071. {
  1072. index = DisplayList.at(MODE_SELECT_PLUGIN).first+i;
  1073. if (CheckRange( index, ItemsDefPlugin.size() ))
  1074. {
  1075. ListNames.at(i).text = ItemsDefPlugin.at(index).Name;
  1076. if (i == DisplayList.at(MODE_SELECT_PLUGIN).absolute)
  1077. {
  1078. ListNames.at(i).font = FONT_SIZE_LARGE;
  1079. }
  1080. else
  1081. {
  1082. ListNames.at(i).font = FONT_SIZE_MEDIUM;
  1083. }
  1084. if (ItemsDefPlugin.at(index).Type == TYPE_DIR)
  1085. ListNames.at(i).color = COLOR_RED;
  1086. else
  1087. ListNames.at(i).color = Config.ColorFontFiles;
  1088. }
  1089. else
  1090. {
  1091. Log( "Error: PopModePlugin index is out of range\n" );
  1092. }
  1093. }
  1094. }
  1095. void CSelector::PopModeRomOption( void )
  1096. {
  1097. uint16_t i;
  1098. uint16_t index;
  1099. for (i=0; i<ListNames.size(); i++)
  1100. {
  1101. index = DisplayList.at(MODE_ROM_OPTION).first+i;
  1102. if (CheckRange( index, ItemsRomOption.size() ))
  1103. {
  1104. ListNames.at(i).text = ItemsRomOption.at(index).Name;
  1105. if (i == DisplayList.at(MODE_ROM_OPTION).absolute)
  1106. {
  1107. ListNames.at(i).font = FONT_SIZE_LARGE;
  1108. }
  1109. else
  1110. {
  1111. ListNames.at(i).font = FONT_SIZE_MEDIUM;
  1112. }
  1113. ListNames.at(i).color = Config.ColorFontFiles;
  1114. }
  1115. else
  1116. {
  1117. Log( "Error: PopModeOption index is out of range\n" );
  1118. }
  1119. }
  1120. }
  1121. void CSelector::PopModeRomPlugin( void )
  1122. {
  1123. uint16_t i;
  1124. uint16_t index;
  1125. for (i=0; i<ListNames.size(); i++)
  1126. {
  1127. index = DisplayList.at(MODE_ROM_PLUGIN).first+i;
  1128. if (CheckRange( index, ItemsRomPlugin.size() ))
  1129. {
  1130. ListNames.at(i).text = ItemsRomPlugin.at(index).Name;
  1131. if (i == DisplayList.at(MODE_ROM_PLUGIN).absolute)
  1132. {
  1133. ListNames.at(i).font = FONT_SIZE_LARGE;
  1134. }
  1135. else
  1136. {
  1137. ListNames.at(i).font = FONT_SIZE_MEDIUM;
  1138. }
  1139. if (ItemsRomPlugin.at(index).Type == TYPE_DIR)
  1140. ListNames.at(i).color = COLOR_RED;
  1141. else
  1142. ListNames.at(i).color = Config.ColorFontFiles;
  1143. }
  1144. else
  1145. {
  1146. Log( "Error: PopModePlugin index is out of range\n" );
  1147. }
  1148. }
  1149. }
  1150. void CSelector::LoadPreview( const string& name )
  1151. {
  1152. string filename;
  1153. SDL_Surface* preview = NULL;
  1154. if (ImagePreview != NULL)
  1155. {
  1156. DrawState_Preview = true;
  1157. }
  1158. FREE_IMAGE( ImagePreview );
  1159. filename = Config.PreviewsPath + "/" + name.substr( 0, name.find_last_of(".")) + ".png";
  1160. preview = LoadImage( filename.c_str() );
  1161. if (preview != NULL)
  1162. {
  1163. ImagePreview = ScaleSurface( preview, Config.PreviewWidth, Config.PreviewHeight );
  1164. FREE_IMAGE( preview );
  1165. DrawState_Preview = true;
  1166. }
  1167. }
  1168. int8_t CSelector::DrawNames( SDL_Rect& location )
  1169. {
  1170. uint16_t entry_index;
  1171. uint16_t startx, starty;
  1172. int16_t offset;
  1173. SDL_Rect rect_clip;
  1174. SDL_Surface* text_surface = NULL;
  1175. if (Config.AutoLayout == false)
  1176. {
  1177. location.x = Config.PosX_ListNames;
  1178. location.y = Config.PosY_ListNames;
  1179. }
  1180. startx = location.x;
  1181. starty = location.y;
  1182. if (ListNames.size() <= 0)
  1183. {
  1184. // Empty directories or zip files
  1185. if (Config.UseZipSupport == true && Profile.ZipFile.length() > 0)
  1186. {
  1187. text_surface = TTF_RenderText_Solid( Fonts.at(FONT_SIZE_MEDIUM), EMPTY_ZIP_LABEL, Config.Colors.at(COLOR_BLACK) );
  1188. }
  1189. else
  1190. {
  1191. text_surface = TTF_RenderText_Solid( Fonts.at(FONT_SIZE_MEDIUM), EMPTY_DIR_LABEL, Config.Colors.at(COLOR_BLACK) );
  1192. }
  1193. if (text_surface != NULL)
  1194. {
  1195. location.x += ImageSelectPointer->w;
  1196. rect_clip.x = 0;
  1197. rect_clip.y = 0;
  1198. rect_clip.w = Config.DisplayListMaxWidth-location.x;
  1199. rect_clip.h = text_surface->h;
  1200. ApplyImage( location.x, location.y, text_surface, Screen, &rect_clip );
  1201. ListNameHeight = MAX(ListNameHeight, location.y+text_surface->h );
  1202. location.x -= ImageSelectPointer->w;
  1203. location.y += text_surface->h + Config.EntryYDelta;
  1204. FREE_IMAGE( text_surface );
  1205. }
  1206. else
  1207. {
  1208. Log( "Failed to create TTF surface with TTF_RenderText_Solid: %s\n", TTF_GetError() );
  1209. return 1;
  1210. }
  1211. }
  1212. else
  1213. {
  1214. for (entry_index=0; entry_index<ListNames.size(); entry_index++)
  1215. {
  1216. offset = 0;
  1217. // Draw the selector pointer
  1218. if (entry_index == DisplayList.at(Mode).relative)
  1219. {
  1220. ApplyImage( location.x, location.y, ImageSelectPointer, Screen, NULL );
  1221. // Reset scroll settings
  1222. if (entry_index != LastSelectedEntry)
  1223. {
  1224. CurScrollPause = 0;
  1225. CurScrollSpeed = 0;
  1226. TextScrollOffset = 0;
  1227. TextScrollDir = true;
  1228. }
  1229. LastSelectedEntry = entry_index;
  1230. }
  1231. text_surface = TTF_RenderText_Solid( Fonts.at(ListNames.at(entry_index).font), ListNames.at(entry_index).text.c_str(), Config.Colors.at(ListNames.at(entry_index).color) );
  1232. if (text_surface != NULL)
  1233. {
  1234. location.x += ImageSelectPointer->w;
  1235. RectEntries.at(entry_index).x = location.x;
  1236. RectEntries.at(entry_index).y = location.y;
  1237. RectEntries.at(entry_index).w = text_surface->w;
  1238. RectEntries.at(entry_index).h = text_surface->h;
  1239. if (text_surface->w > (Config.DisplayListMaxWidth-location.x) )
  1240. {
  1241. RectEntries.at(entry_index).w = Config.DisplayListMaxWidth-location.x;
  1242. if (Config.TextScrollOption == true && DisplayList.at(Mode).relative == entry_index)
  1243. {
  1244. offset = TextScrollOffset;
  1245. if (CurScrollPause > 1)
  1246. {
  1247. CurScrollPause++;
  1248. if (CurScrollPause >= Config.ScrollPauseSpeed)
  1249. {
  1250. CurScrollPause = 1;
  1251. }
  1252. }
  1253. else
  1254. {
  1255. CurScrollSpeed++;
  1256. if (CurScrollSpeed >= Config.ScrollSpeed)
  1257. {
  1258. CurScrollSpeed = 1;
  1259. if (TextScrollDir == true)
  1260. {
  1261. TextScrollOffset += Config.ScreenRatioW;
  1262. }
  1263. else
  1264. {
  1265. TextScrollOffset -= Config.ScreenRatioW;
  1266. }
  1267. Redraw = true;
  1268. }
  1269. if (RectEntries.at(entry_index).w+TextScrollOffset >= text_surface->w)
  1270. {
  1271. TextScrollDir = false;
  1272. CurScrollPause = 2;
  1273. }
  1274. else if (TextScrollOffset <= 0)
  1275. {
  1276. TextScrollDir = true;
  1277. CurScrollPause = 2;
  1278. }
  1279. }
  1280. }
  1281. }
  1282. rect_clip.w = Config.DisplayListMaxWidth-location.x;
  1283. rect_clip.h = text_surface->h;
  1284. rect_clip.x = offset;
  1285. rect_clip.y = 0;
  1286. ApplyImage( location.x, location.y, text_surface, Screen, &rect_clip );
  1287. ListNameHeight = MAX(ListNameHeight, location.y+text_surface->h );
  1288. location.x -= ImageSelectPointer->w;
  1289. location.y += text_surface->h + Config.EntryYDelta;
  1290. FREE_IMAGE( text_surface );
  1291. }
  1292. else
  1293. {
  1294. Log( "Failed to create TTF surface with TTF_RenderText_Solid: %s\n", TTF_GetError() );
  1295. return 1;
  1296. }
  1297. }
  1298. }
  1299. UpdateRect( startx, starty, Config.DisplayListMaxWidth-startx, ListNameHeight-starty );
  1300. return 0;
  1301. }
  1302. void CSelector::SelectionLimits( item_pos_t& pos )
  1303. {
  1304. if (pos.absolute <= pos.first)
  1305. {
  1306. pos.relative = 0;
  1307. if (pos.absolute < 0)
  1308. {
  1309. pos.absolute = 0;
  1310. }
  1311. pos.first = pos.absolute;
  1312. if (pos.total < Config.MaxEntries)
  1313. {
  1314. pos.last = (pos.total-1);
  1315. }
  1316. else
  1317. {
  1318. pos.last = pos.absolute+(Config.MaxEntries-1);
  1319. }
  1320. }
  1321. else if (pos.absolute >= pos.last)
  1322. {
  1323. if (pos.absolute > (int16_t)(pos.total-1))
  1324. {
  1325. pos.absolute = (pos.total-1);
  1326. }
  1327. pos.first = pos.absolute-(Config.MaxEntries-1);
  1328. pos.last = pos.absolute;
  1329. if (pos.total < Config.MaxEntries)
  1330. {
  1331. pos.relative = (pos.total-1);
  1332. }
  1333. else
  1334. {
  1335. pos.relative = Config.MaxEntries-1;
  1336. }
  1337. if (pos.first < 0)
  1338. {
  1339. pos.first = 0;
  1340. }
  1341. }
  1342. }
  1343. void CSelector::DrawBackground( void )
  1344. {
  1345. if (ImageBackground != NULL)
  1346. {
  1347. ApplyImage( 0, 0, ImageBackground, Screen, NULL );
  1348. }
  1349. else
  1350. {
  1351. SDL_FillRect( Screen, NULL, rgb_to_int(Config.Colors.at(Config.ColorBackground)) );
  1352. }
  1353. }
  1354. int8_t CSelector::ConfigureButtons( void )
  1355. {
  1356. uint16_t i;
  1357. // Common button mappings
  1358. ButtonModesLeft.at(0) = EVENT_ONE_UP;
  1359. ButtonModesLeft.at(1) = EVENT_PAGE_UP;
  1360. ButtonModesLeft.at(2) = EVENT_PAGE_DOWN;
  1361. ButtonModesLeft.at(3) = EVENT_ONE_DOWN;
  1362. ButtonModesRight.at(0) = EVENT_QUIT;
  1363. // Specific button mappings
  1364. switch (Mode)
  1365. {
  1366. case MODE_SELECT_ENTRY:
  1367. ButtonModesLeft.at(4) = EVENT_DIR_UP;
  1368. ButtonModesLeft.at(5) = EVENT_DIR_DOWN;
  1369. if (Config.UseZipSupport == true && Profile.ZipFile.length() > 0)
  1370. {
  1371. ButtonModesLeft.at(6) = EVENT_ZIP_MODE;
  1372. }
  1373. else
  1374. {
  1375. ButtonModesLeft.at(6) = EVENT_NONE;
  1376. }
  1377. ButtonModesRight.at(1) = EVENT_SELECT;
  1378. ButtonModesRight.at(2) = EVENT_CFG_ITEM;
  1379. ButtonModesRight.at(3) = EVENT_NONE;
  1380. ButtonModesRight.at(3) = EVENT_CFG_APP; // TODO
  1381. break;
  1382. case MODE_SELECT_ARGUMENT:
  1383. ButtonModesLeft.at(4) = EVENT_NONE;
  1384. ButtonModesLeft.at(5) = EVENT_NONE;
  1385. ButtonModesLeft.at(6) = EVENT_NONE;
  1386. ButtonModesRight.at(1) = EVENT_BACK;
  1387. ButtonModesRight.at(2) = EVENT_SELECT;
  1388. ButtonModesRight.at(3) = EVENT_NONE;
  1389. break;
  1390. case MODE_SELECT_VALUE:
  1391. ButtonModesLeft.at(4) = EVENT_NONE;
  1392. ButtonModesLeft.at(5) = EVENT_NONE;
  1393. ButtonModesLeft.at(6) = EVENT_NONE;
  1394. ButtonModesRight.at(1) = EVENT_BACK;
  1395. ButtonModesRight.at(2) = EVENT_SET_ALL;
  1396. ButtonModesRight.at(3) = EVENT_SET_ONE;
  1397. break;
  1398. case MODE_SELECT_OPTION:
  1399. ButtonModesLeft.at(4) = EVENT_NONE;
  1400. ButtonModesLeft.at(5) = EVENT_NONE;
  1401. ButtonModesLeft.at(6) = EVENT_NONE;
  1402. ButtonModesRight.at(1) = EVENT_BACK;
  1403. ButtonModesRight.at(2) = EVENT_SELECT;
  1404. ButtonModesRight.at(3) = EVENT_NONE;
  1405. break;
  1406. case MODE_SELECT_PLUGIN:
  1407. ButtonModesLeft.at(4) = EVENT_NONE;
  1408. ButtonModesLeft.at(5) = EVENT_NONE;
  1409. ButtonModesLeft.at(6) = EVENT_NONE;
  1410. ButtonModesRight.at(1) = EVENT_BACK;
  1411. ButtonModesRight.at(2) = EVENT_SELECT;
  1412. ButtonModesRight.at(3) = EVENT_NONE;
  1413. break;
  1414. case MODE_ROM_OPTION:
  1415. ButtonModesLeft.at(4) = EVENT_NONE;
  1416. ButtonModesLeft.at(5) = EVENT_NONE;
  1417. ButtonModesLeft.at(6) = EVENT_NONE;
  1418. ButtonModesRight.at(1) = EVENT_BACK;
  1419. ButtonModesRight.at(2) = EVENT_SELECT;
  1420. ButtonModesRight.at(3) = EVENT_NONE;
  1421. break;
  1422. case MODE_ROM_PLUGIN:
  1423. ButtonModesLeft.at(4) = EVENT_NONE;
  1424. ButtonModesLeft.at(5) = EVENT_NONE;
  1425. ButtonModesLeft.at(6) = EVENT_NONE;
  1426. ButtonModesRight.at(1) = EVENT_BACK;
  1427. ButtonModesRight.at(2) = EVENT_SELECT;
  1428. ButtonModesRight.at(3) = EVENT_NONE;
  1429. break;
  1430. default:
  1431. Log( "Error: Unknown Mode\n" );
  1432. return 1;
  1433. break;
  1434. }
  1435. // Overides for button driven by config options
  1436. for (i=0; i<ButtonModesLeft.size(); i++ )
  1437. {
  1438. if (Config.ButtonModesLeftEnable.at(i) == false)
  1439. {
  1440. ButtonModesLeft.at(i) = EVENT_NONE;
  1441. }
  1442. }
  1443. for (i=0; i<ButtonModesRight.size(); i++ )
  1444. {
  1445. if (Config.ButtonModesRightEnable.at(i) == false)
  1446. {
  1447. ButtonModesRight.at(i) = EVENT_NONE;
  1448. }
  1449. }
  1450. return 0;
  1451. }
  1452. int8_t CSelector::DrawButtons( SDL_Rect& location )
  1453. {
  1454. uint8_t button;
  1455. SDL_Rect preview;
  1456. if (Config.AutoLayout == false)
  1457. {
  1458. location.x = Config.PosX_ButtonLeft;
  1459. location.y = Config.PosY_ButtonLeft;
  1460. }
  1461. // Draw buttons on left
  1462. if (DrawState_ButtonL == true)
  1463. {
  1464. for (button=0; button<BUTTONS_MAX_LEFT; button++)
  1465. {
  1466. RectButtonsLeft.at(button).x = location.x;
  1467. RectButtonsLeft.at(button).y = location.y+(Config.ButtonHeightLeft*button)+(Config.EntryYOffset*button);
  1468. RectButtonsLeft.at(button).w = Config.ButtonWidthLeft;
  1469. RectButtonsLeft.at(button).h = Config.ButtonHeightLeft;
  1470. if (ButtonModesLeft.at(button) != EVENT_NONE)
  1471. {
  1472. if (DrawButton( ButtonModesLeft.at(button), Fonts.at(FONT_SIZE_LARGE), RectButtonsLeft.at(button) ))
  1473. {
  1474. return 1;
  1475. }
  1476. }
  1477. UpdateRect( RectButtonsLeft.at(button).x, RectButtonsLeft.at(button).y, RectButtonsLeft.at(button).w, RectButtonsLeft.at(button).h );
  1478. }
  1479. DrawState_ButtonL = false;
  1480. }
  1481. location.x += Config.ButtonWidthLeft + Config.EntryXOffset;
  1482. // Draw buttons on right
  1483. if (DrawState_ButtonR == true)
  1484. {
  1485. for (button=0; button<BUTTONS_MAX_RIGHT; button++)
  1486. {
  1487. if (Config.AutoLayout == false)
  1488. {
  1489. RectButtonsRight.at(button).x = Config.PosX_ButtonRight;
  1490. RectButtonsRight.at(button).y = Config.PosY_ButtonRight-(Config.ButtonHeightRight*(button+1))-(Config.EntryYOffset*(button+3));
  1491. }
  1492. else
  1493. {
  1494. RectButtonsRight.at(button).x = Config.ScreenWidth-Config.ButtonWidthRight-Config.EntryXOffset;
  1495. RectButtonsRight.at(button).y = Config.ScreenHeight-(Config.ButtonHeightRight*(button+1))-(Config.EntryYOffset*(button+3));
  1496. }
  1497. RectButtonsRight.at(button).w = Config.ButtonWidthRight;
  1498. RectButtonsRight.at(button).h = Config.ButtonHeightRight;
  1499. if (ButtonModesRight.at(button) != EVENT_NONE)
  1500. {
  1501. if (DrawButton( ButtonModesRight.at(button), Fonts.at(FONT_SIZE_LARGE), RectButtonsRight.at(button) ))
  1502. {
  1503. return 1;
  1504. }
  1505. }
  1506. UpdateRect( RectButtonsRight.at(button).x, RectButtonsRight.at(button).y, RectButtonsRight.at(button).w, RectButtonsRight.at(button).h );
  1507. }
  1508. DrawState_ButtonR = false;
  1509. }
  1510. //Display the preview graphic
  1511. if (Mode == MODE_SELECT_ENTRY && DrawState_Preview == true)
  1512. {
  1513. preview.x = Config.ScreenWidth-Config.PreviewWidth-Config.EntryXOffset;
  1514. preview.y = Config.ScreenHeight-Config.PreviewHeight-(Config.ButtonHeightRight*3)-(Config.EntryYOffset*6);
  1515. if (ImagePreview != NULL)
  1516. {
  1517. ApplyImage( preview.x, preview.y, ImagePreview, Screen, NULL );
  1518. }
  1519. UpdateRect( preview.x, preview.y, Config.PreviewWidth, Config.PreviewHeight );
  1520. DrawState_Preview = false;
  1521. }
  1522. return 0;
  1523. }
  1524. int8_t CSelector::DrawButton( uint8_t button, TTF_Font* font, SDL_Rect& location )
  1525. {
  1526. SDL_Surface* text_surface = NULL;
  1527. SDL_Rect rect_text;
  1528. if (ImageButtons.at(button) != NULL)
  1529. {
  1530. ApplyImage( location.x, location.y, ImageButtons.at(button), Screen, NULL );
  1531. }
  1532. else
  1533. {
  1534. SDL_FillRect( Screen, &location, rgb_to_int(Config.Colors.at(Config.ColorButton)) );
  1535. }
  1536. if (Config.ShowLabels == true)
  1537. {
  1538. text_surface = TTF_RenderText_Solid( font, LabelButtons.at(button).c_str(), Config.Colors.at(Config.ColorFontButton) );
  1539. rect_text.x = location.x + ((location.w-text_surface->w)/2);
  1540. rect_text.y = location.y + ((location.h-text_surface->h)/2);
  1541. if (text_surface != NULL)
  1542. {
  1543. ApplyImage( rect_text.x, rect_text.y, text_surface, Screen, NULL );
  1544. FREE_IMAGE( text_surface );
  1545. }
  1546. else
  1547. {
  1548. Log( "Failed to create TTF surface with TTF_RenderText_Solid: %s\n", TTF_GetError() );
  1549. return 1;
  1550. }
  1551. }
  1552. return 0;
  1553. }
  1554. int8_t CSelector::DrawText( SDL_Rect& location )
  1555. {
  1556. int16_t total;
  1557. int16_t prev_width;
  1558. int16_t prev_height;
  1559. int16_t max_height;
  1560. string text;
  1561. SDL_Rect box, clip;
  1562. prev_width = 0;
  1563. prev_height = 0;
  1564. if (Config.AutoLayout == false)
  1565. {
  1566. location.x = Config.PosX_Title;
  1567. location.y = Config.PosY_Title;
  1568. }
  1569. // Title text
  1570. if (ImageTitle != NULL)
  1571. {
  1572. if (DrawState_Title == true)
  1573. {
  1574. ApplyImage( location.x, location.y, ImageTitle, Screen, NULL );
  1575. UpdateRect( location.x, location.y, ImageTitle->w, ImageTitle->h );
  1576. DrawState_Title = false;
  1577. }
  1578. location.y += ImageTitle->h + Config.EntryYDelta;
  1579. }
  1580. // Entry Filter and Filepath (they can overlap so both are drawn when either change)
  1581. if (Mode == MODE_SELECT_ENTRY)
  1582. {
  1583. if (DrawState_FilePath == true || DrawState_Filter == true )
  1584. {
  1585. // Entry Filter
  1586. if (ImageFilter != NULL)
  1587. {
  1588. prev_width = ImageFilter->w;
  1589. prev_height = ImageFilter->h;
  1590. }
  1591. else
  1592. {
  1593. prev_width = 0;
  1594. prev_height = 0;
  1595. }
  1596. max_height = prev_height;
  1597. FREE_IMAGE( ImageFilter );
  1598. if (Profile.EntryFilter.length() > 0)
  1599. {
  1600. ImageFilter = TTF_RenderText_Solid( Fonts.at(FONT_SIZE_MEDIUM), Profile.EntryFilter.c_str(), Config.Colors.at(Config.ColorFontFiles) );
  1601. if (ImageFilter != NULL)
  1602. {
  1603. clip.x = 0;
  1604. clip.y = 0;
  1605. clip.w = Config.FilePathMaxWidth;
  1606. clip.h = ImageFilter->h;
  1607. if (ImageFilter->w > Config.FilePathMaxWidth)
  1608. {
  1609. clip.x = ImageFilter->w-Config.FilePathMaxWidth;
  1610. }
  1611. location.x = Config.ScreenWidth - ImageFilter->w - Config.EntryXOffset;
  1612. ApplyImage( location.x, location.y, ImageFilter, Screen, &clip );
  1613. max_height = MAX( max_height, ImageFilePath->h );
  1614. }
  1615. else
  1616. {
  1617. Log( "Failed to create TTF surface with TTF_RenderText_Solid: %s\n", TTF_GetError() );
  1618. return 1;
  1619. }
  1620. }
  1621. location.x = Config.EntryXOffset;
  1622. // File path
  1623. if (ImageFilePath != NULL)
  1624. {
  1625. prev_width = ImageFilePath->w;
  1626. prev_height = ImageFilePath->h;
  1627. }
  1628. else
  1629. {
  1630. prev_width = 0;
  1631. prev_height = 0;
  1632. }
  1633. max_height = MAX( max_height, prev_height );
  1634. FREE_IMAGE(ImageFilePath);
  1635. text = Profile.FilePath;
  1636. if (Profile.ZipFile.length())
  1637. {
  1638. text += "->" + Profile.ZipFile;
  1639. }
  1640. ImageFilePath = TTF_RenderText_Solid( Fonts.at(FONT_SIZE_MEDIUM), text.c_str(), Config.Colors.at(Config.ColorFontFiles) );
  1641. if (ImageFilePath != NULL)
  1642. {
  1643. clip.x = 0;
  1644. clip.y = 0;
  1645. clip.w = Config.FilePathMaxWidth;
  1646. clip.h = ImageFilePath->h;
  1647. if (ImageFilePath->w > Config.FilePathMaxWidth)
  1648. {
  1649. clip.x = ImageFilePath->w-Config.FilePathMaxWidth;
  1650. }
  1651. ApplyImage( location.x, location.y, ImageFilePath, Screen, &clip );
  1652. max_height = MAX( max_height, ImageFilePath->h );
  1653. }
  1654. else
  1655. {
  1656. Log( "Failed to create TTF surface with TTF_RenderText_Solid: %s\n", TTF_GetError() );
  1657. return 1;
  1658. }
  1659. UpdateRect( 0, location.y, Config.ScreenWidth, max_height );
  1660. DrawState_FilePath = false;
  1661. DrawState_Filter = false;
  1662. }
  1663. }
  1664. if (ImageFilePath != NULL)
  1665. {
  1666. location.y += ImageFilePath->h + Config.EntryYOffset;
  1667. }
  1668. // About text
  1669. if (ImageAbout != NULL)
  1670. {
  1671. if (DrawState_About == true)
  1672. {
  1673. box.x = Config.ScreenWidth - ImageAbout->w - Config.EntryXOffset;
  1674. box.y = Config.ScreenHeight - ImageAbout->h - Config.EntryYOffset;
  1675. ApplyImage( box.x, box.y, ImageAbout, Screen, NULL );
  1676. UpdateRect( box.x, box.y, ImageAbout->w, ImageAbout->h );
  1677. DrawState_About = false;
  1678. }
  1679. }
  1680. // Item count
  1681. switch (Mode)
  1682. {
  1683. case MODE_SELECT_ENTRY:
  1684. total = ItemsEntry.size();
  1685. break;
  1686. case MODE_SELECT_ARGUMENT: // fall through
  1687. case MODE_SELECT_OPTION:
  1688. total = ItemsArgument.size();
  1689. break;
  1690. case MODE_SELECT_VALUE:
  1691. total = ItemsValue.size();
  1692. break;
  1693. case MODE_SELECT_PLUGIN:
  1694. total = ItemsDefPlugin.size();
  1695. break;
  1696. default:
  1697. total = 0;
  1698. text = "Error: Unknown mode";
  1699. break;
  1700. }
  1701. // Draw index
  1702. if (DrawState_Index == true)
  1703. {
  1704. if (ImageIndex != NULL)
  1705. {
  1706. prev_width = ImageIndex->w;
  1707. prev_height = ImageIndex->h;
  1708. }
  1709. else
  1710. {
  1711. prev_width = 0;
  1712. prev_height = 0;
  1713. }
  1714. FREE_IMAGE( ImageIndex );
  1715. text = "0 of 0";
  1716. if (total > 0)
  1717. {
  1718. text = i_to_a(DisplayList.at(Mode).absolute+1) + " of " + i_to_a(total);
  1719. }
  1720. ImageIndex = TTF_RenderText_Solid(Fonts.at(FONT_SIZE_SMALL), text.c_str(), Config.Colors.at(Config.ColorFontFiles));
  1721. if (ImageIndex != NULL)
  1722. {
  1723. box.x = Config.EntryXOffset;
  1724. box.y = Config.ScreenHeight - ImageIndex->h - Config.EntryYOffset;
  1725. ApplyImage( box.x, box.y, ImageIndex, Screen, NULL );
  1726. UpdateRect( box.x, box.y, MAX(ImageIndex->w, prev_width), MAX(ImageIndex->h, prev_height) );
  1727. }
  1728. else
  1729. {
  1730. Log( "Failed to create TTF surface with TTF_RenderText_Solid: %s\n", TTF_GetError());
  1731. return 1;
  1732. }
  1733. DrawState_Index = false;
  1734. }
  1735. // Zip extract option
  1736. if (DrawState_ZipMode == true)
  1737. {
  1738. if (Config.UseZipSupport == true && Profile.ZipFile.length() > 0)
  1739. {
  1740. if (ImageZipMode != NULL)
  1741. {
  1742. prev_width = ImageZipMode->w;
  1743. prev_height = ImageZipMode->h;
  1744. }
  1745. else
  1746. {
  1747. prev_width = 0;
  1748. prev_height = 0;
  1749. }
  1750. FREE_IMAGE( ImageZipMode );
  1751. if (ExtractAllFiles == true)
  1752. {
  1753. text = "Extract All";
  1754. }
  1755. else
  1756. {
  1757. text = "Extract Selection";
  1758. }
  1759. ImageZipMode = TTF_RenderText_Solid(Fonts.at(FONT_SIZE_SMALL), text.c_str(), Config.Colors.at(Config.ColorFontFiles));
  1760. if (ImageZipMode == NULL)
  1761. {
  1762. Log( "Failed to create TTF surface with TTF_RenderText_Solid: %s\n", TTF_GetError());
  1763. return 1;
  1764. }
  1765. }
  1766. if (ImageZipMode != NULL)
  1767. {
  1768. box.x = 5*Config.EntryXOffset;
  1769. box.y = Config.ScreenHeight - ImageZipMode->h - Config.EntryYOffset;
  1770. if (Config.UseZipSupport == true && Profile.ZipFile.length() > 0)
  1771. {
  1772. ApplyImage( box.x, box.y, ImageZipMode, Screen, NULL );
  1773. }
  1774. UpdateRect( box.x, box.y, MAX(ImageZipMode->w, prev_width), MAX(ImageZipMode->h, prev_height) );
  1775. }
  1776. DrawState_ZipMode = false;
  1777. }
  1778. #if defined(DEBUG)
  1779. if (ImageDebug != NULL)
  1780. {
  1781. prev_width = ImageDebug->w;
  1782. prev_height = ImageDebug->h;
  1783. }
  1784. else
  1785. {
  1786. prev_width = 0;
  1787. prev_height = 0;
  1788. }
  1789. FREE_IMAGE( ImageDebug );
  1790. text = "DEBUG abs " + i_to_a(DisplayList.at(Mode).absolute) + " rel " + i_to_a(DisplayList.at(Mode).relative)
  1791. + " F " + i_to_a(DisplayList.at(Mode).first) + " L " + i_to_a(DisplayList.at(Mode).last)
  1792. + " T " + i_to_a(DisplayList.at(Mode).total)
  1793. + " fps " + i_to_a(FPSDrawn) + " skp " + i_to_a(FPSSkip) + " slp " + i_to_a(FPSSleep)
  1794. + " lp " + i_to_a(LoopTimeAverage);
  1795. ImageDebug = TTF_RenderText_Solid( Fonts.at(FONT_SIZE_SMALL), text.c_str(), Config.Colors.at(Config.ColorFontFiles) );
  1796. if (ImageDebug != NULL)
  1797. {
  1798. box.x = Config.EntryXOffset;
  1799. box.y = Config.ScreenHeight - ImageDebug->h;
  1800. ApplyImage( box.x, box.y, ImageDebug, Screen, NULL );
  1801. UpdateRect( box.x, box.y, MAX(ImageDebug->w, prev_width), MAX(ImageDebug->h, prev_height) );
  1802. }
  1803. else
  1804. {
  1805. Log( "Failed to create TTF surface with TTF_RenderText_Solid: %s\n", TTF_GetError() );
  1806. return 1;
  1807. }
  1808. #endif
  1809. return 0;
  1810. }
  1811. int8_t CSelector::RunExec( uint16_t selection )
  1812. {
  1813. bool entry_found;
  1814. uint16_t i, j, k;
  1815. int16_t ext_index;
  1816. string filename;
  1817. string filepath;
  1818. string command;
  1819. string extension;
  1820. string value;
  1821. string cmdpath, cmdname;
  1822. entry_t* entry = NULL;
  1823. argforce_t* argforce = NULL;
  1824. exeforce_t* exeforce = NULL;
  1825. argument_t* argument = NULL;
  1826. // Find a entry for argument values
  1827. entry_found = false;
  1828. if (!CheckRange( selection, ItemsEntry.size() ))
  1829. {
  1830. Log( "Error: RunExec selection is out of range\n" );
  1831. return 1;
  1832. }
  1833. if (ItemsEntry.at(selection).Entry >= 0)
  1834. {
  1835. entry = &Profile.Entries.at(ItemsEntry.at(selection).Entry);
  1836. entry_found = true;
  1837. }
  1838. // Find a executable for file extension
  1839. filename = ItemsEntry.at(selection).Name;
  1840. if (ItemsEntry.at(selection).Type == TYPE_DIR)
  1841. {
  1842. extension = EXT_DIRS;
  1843. }
  1844. else
  1845. {
  1846. extension = filename.substr( filename.find_last_of(".")+1 );
  1847. }
  1848. ext_index = Profile.FindExtension( extension );
  1849. if (CheckRange( ext_index, Profile.Extensions.size() ))
  1850. {
  1851. command.clear();
  1852. // Unzip if needed
  1853. if (Config.UseZipSupport == true && Profile.ZipFile.length() > 0)
  1854. {
  1855. mkdir( Config.ZipPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );
  1856. if (ExtractAllFiles == true) // Extract all
  1857. {
  1858. Profile.Minizip.ExtractFiles( Profile.FilePath + Profile.ZipFile, Config.ZipPath );
  1859. }
  1860. else // Extract one
  1861. {
  1862. Profile.Minizip.ExtractFile( Profile.FilePath + Profile.ZipFile, Config.ZipPath, filename );
  1863. }
  1864. filepath = Config.ZipPath + "/";
  1865. }
  1866. else
  1867. {
  1868. filepath = Profile.FilePath;
  1869. }
  1870. // Setup commands
  1871. for (i=0; i<Profile.Commands.size(); i++)
  1872. {
  1873. command += "cd " + Profile.Commands.at(i).Path + "; ";
  1874. command += Profile.Commands.at(i).Command;
  1875. for (j=0; j<Profile.Commands.at(i).Arguments.size(); j++)
  1876. {
  1877. if (Profile.Commands.at(i).Arguments.at(j).Flag.compare(VALUE_NOVALUE) != 0)
  1878. {
  1879. command += " " + Profile.Commands.at(i).Arguments.at(j).Flag;
  1880. }
  1881. if (Profile.Commands.at(i).Arguments.at(j).Flag.compare(VALUE_FLAGONLY) !=0 )
  1882. {
  1883. if (entry_found==true)
  1884. {
  1885. command += " " + Profile.Commands.at(i).Arguments.at(j).Values.at(entry->CmdValues.at(j));
  1886. }
  1887. else
  1888. {
  1889. command += " " + Profile.Commands.at(i).Arguments.at(j).Values.at(Profile.Commands.at(i).Arguments.at(j).Default);
  1890. }
  1891. }
  1892. }
  1893. command += "; ";
  1894. }
  1895. // Check exe forces
  1896. cmdpath = Profile.Extensions.at(ext_index).exePath;
  1897. cmdname = Profile.Extensions.at(ext_index).exeName;
  1898. for (j=0; j<Profile.Extensions.at(ext_index).ExeForces.size(); j++)
  1899. {
  1900. exeforce = &Profile.Extensions.at(ext_index).ExeForces.at(j);
  1901. for (k=0; k<exeforce->Files.size(); k++)
  1902. {
  1903. if (exeforce->Files.at(k).compare( lowercase(filename) ) == 0)
  1904. {
  1905. cmdpath = exeforce->exePath;
  1906. cmdname = exeforce->exeName;
  1907. break;
  1908. }
  1909. }
  1910. }
  1911. // Add Executable to command
  1912. command += "cd " + cmdpath + "; ";
  1913. command += "LD_LIBRARY_PATH=/mnt/utmp/mupen64plus2/lib:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH; ";
  1914. command += "./" + cmdname;
  1915. // Setup arguments
  1916. for (i=0; i<Profile.Extensions.at(ext_index).Arguments.size(); i++)
  1917. {
  1918. value.clear();
  1919. argument = &Profile.Extensions.at(ext_index).Arguments.at(i);
  1920. // Check arg forces
  1921. for (j=0; j<Profile.Extensions.at(ext_index).ArgForces.size(); j++)
  1922. {
  1923. argforce = &Profile.Extensions.at(ext_index).ArgForces.at(j);
  1924. if (argforce->Path.compare( Profile.FilePath ) == 0)
  1925. {
  1926. if (i == argforce->Argument)
  1927. {
  1928. Log( "Setting argforce on arg %d\n", i );
  1929. value = argforce->Value;
  1930. break;
  1931. }
  1932. }
  1933. }
  1934. // Check arguments for default value or custom entry value
  1935. if (value.length() <= 0 )
  1936. {
  1937. if (entry_found==true)
  1938. {
  1939. if (CheckRange( i, entry->ArgValues.size() ))
  1940. {
  1941. value = argument->Values.at( entry->ArgValues.at(i) );
  1942. }
  1943. else
  1944. {
  1945. Log( "Error: RunExec i is out of range\n" );
  1946. return 1;
  1947. }
  1948. }
  1949. else
  1950. {
  1951. if (CheckRange( argument->Default, argument->Values.size() ))
  1952. {
  1953. value = argument->Values.at( argument->Default );
  1954. }
  1955. else
  1956. {
  1957. Log( "Error: RunExec argument->Default is out of range\n" );
  1958. return 1;
  1959. }
  1960. }
  1961. }
  1962. // Add the argument if used
  1963. if (value.length() > 0)
  1964. {
  1965. if (value.compare( VALUE_NOVALUE ) != 0 )
  1966. {
  1967. command += " " + argument->Flag + " ";
  1968. if (value.compare( VALUE_FLAGONLY ) !=0 )
  1969. {
  1970. if (value.compare( VALUE_FILENAME ) == 0)
  1971. {
  1972. if (Config.FilenameArgNoExt == true)
  1973. {
  1974. filename = filename.substr( 0, filename.find_last_of(".") );
  1975. }
  1976. if (entry_found==true)
  1977. {
  1978. command += '\"';
  1979. if (Config.FilenameAbsPath == true)
  1980. {
  1981. command += entry->Path;
  1982. }
  1983. command += entry->Name + '\"';
  1984. }
  1985. else
  1986. {
  1987. command += '\"';
  1988. if (Config.FilenameAbsPath == true)
  1989. {
  1990. command += filepath;
  1991. }
  1992. command += filename + '\"';
  1993. }
  1994. }
  1995. else
  1996. {
  1997. command += value;
  1998. }
  1999. }
  2000. }
  2001. }
  2002. }
  2003. }
  2004. else
  2005. {
  2006. Log( "Warning no extension was found for this file type\n" );
  2007. return 1;
  2008. }
  2009. command += "; sync;";
  2010. if (Config.ReloadLauncher == true)
  2011. {
  2012. command += " cd " + Profile.LauncherPath + ";";
  2013. command += " exec ./" + Profile.LauncherName ;
  2014. // Arguments
  2015. command += " " + string(ARG_PROFILE) + " " + ProfilePath;
  2016. command += " " + string(ARG_CONFIG) + " " + ConfigPath;
  2017. command += " " + string(ARG_ZIPLIST) + " " + ZipListPath;
  2018. }
  2019. Log( "Running command: '%s'\n", command.c_str());
  2020. CloseResources(0);
  2021. execlp( "/bin/bash", "/bin/bash", "-c", command.c_str(), NULL );
  2022. //if execution continues then something went wrong and as we already called SDL_Quit we cannot continue, try reloading
  2023. Log( "Error executing selected application, re-launching %s\n", APPNAME);
  2024. chdir( Profile.LauncherPath.c_str() );
  2025. execlp( Profile.LauncherName.c_str(), Profile.LauncherName.c_str(), NULL );
  2026. return 0;
  2027. }
  2028. int8_t CSelector::PollInputs( void )
  2029. {
  2030. int16_t newsel;
  2031. uint16_t index;
  2032. string keyname;
  2033. SDL_Event event;
  2034. for (index=0; index<EventReleased.size(); index++)
  2035. {
  2036. if (EventReleased.at(index) == true)
  2037. {
  2038. EventReleased.at(index) = false;
  2039. EventPressCount.at(index) = EVENT_LOOPS_OFF;
  2040. #if defined(DEBUG)
  2041. //Log( "DEBUG EventReleased %d\n", index );
  2042. #endif
  2043. }
  2044. else if (EventPressCount.at(index) != EVENT_LOOPS_OFF)
  2045. {
  2046. EventPressCount.at(index)--;
  2047. if (EventPressCount.at(index) < EVENT_LOOPS_ON)
  2048. {
  2049. EventPressCount.at(index) = EVENT_LOOPS;
  2050. }
  2051. }
  2052. }
  2053. // Sanity check
  2054. if (!CheckRange( Mode, DisplayList.size() ))
  2055. {
  2056. Log( "Error: PollInputs Mode out of range\n" );
  2057. return 1;
  2058. }
  2059. while (SDL_PollEvent( &event ))
  2060. {
  2061. switch( event.type )
  2062. {
  2063. case SDL_KEYDOWN:
  2064. keyname = SDL_GetKeyName( event.key.keysym.sym );
  2065. if (keyname.length() == 1 || event.key.keysym.sym == SDLK_BACKSPACE)
  2066. {
  2067. if (Config.EntryFastMode == ENTRY_FAST_MODE_ALPHA)
  2068. {
  2069. DisplayList.at(Mode).absolute = Profile.AlphabeticIndices.at(event.key.keysym.sym-SDLK_a);
  2070. Profile.EntryFilter.clear();
  2071. }
  2072. else if (Config.EntryFastMode == ENTRY_FAST_MODE_FILTER)
  2073. {
  2074. if (event.key.keysym.sym==SDLK_BACKSPACE || event.key.keysym.sym==SDLK_DELETE)
  2075. {
  2076. if (Profile.EntryFilter.length() > 0)
  2077. {
  2078. Profile.EntryFilter.erase( Profile.EntryFilter.length()-1 );
  2079. }
  2080. }
  2081. else
  2082. {
  2083. Profile.EntryFilter += keyname;
  2084. }
  2085. DrawState_Filter = true;
  2086. Rescan = true;
  2087. }
  2088. }
  2089. else
  2090. {
  2091. bool used=false;
  2092. for (index=0; index<EventPressCount.size(); index++)
  2093. {
  2094. if (event.key.keysym.sym == Config.KeyMaps.at(index))
  2095. {
  2096. EventPressCount.at(index) = EVENT_LOOPS_ON;
  2097. used = true;
  2098. }
  2099. }
  2100. // some hardcoded aternates keys
  2101. if (!used)
  2102. {
  2103. if (event.key.keysym.sym == SDLK_END)
  2104. {
  2105. EventPressCount.at(EVENT_SELECT) = EVENT_LOOPS_ON;
  2106. used = true;
  2107. }
  2108. }
  2109. if (!used && Config.UnusedKeysLaunch)
  2110. {
  2111. EventPressCount.at(EVENT_SELECT) = EVENT_LOOPS_ON;
  2112. }
  2113. }
  2114. break;
  2115. case SDL_KEYUP:
  2116. {
  2117. bool used=false;
  2118. for (index=0; index<EventReleased.size(); index++)
  2119. {
  2120. if (event.key.keysym.sym == Config.KeyMaps.at(index))
  2121. {
  2122. EventReleased.at(index) = true;
  2123. used = true;
  2124. }
  2125. }
  2126. // some hardcoded aternates keys
  2127. if (!used)
  2128. {
  2129. if (event.key.keysym.sym == SDLK_END)
  2130. {
  2131. EventReleased.at(EVENT_SELECT) = true;
  2132. used = true;
  2133. }
  2134. }
  2135. if (!used && Config.UnusedKeysLaunch)
  2136. {
  2137. EventReleased.at(EVENT_SELECT) = true;
  2138. }
  2139. }
  2140. break;
  2141. case SDL_JOYBUTTONDOWN:
  2142. for (index=0; index<EventPressCount.size(); index++)
  2143. {
  2144. if (event.jbutton.button == Config.JoyMaps.at(index))
  2145. {
  2146. EventPressCount.at(index) = EVENT_LOOPS_ON;
  2147. }
  2148. else if (Config.UnusedJoysLaunch)
  2149. {
  2150. EventPressCount.at(EVENT_SELECT) = EVENT_LOOPS_ON;
  2151. }
  2152. }
  2153. break;
  2154. case SDL_JOYBUTTONUP:
  2155. for (index=0; index<EventReleased.size(); index++)
  2156. {
  2157. if (event.jbutton.button == Config.JoyMaps.at(index))
  2158. {
  2159. EventReleased.at(index) = true;
  2160. }
  2161. else if (Config.UnusedJoysLaunch)
  2162. {
  2163. EventReleased.at(EVENT_SELECT) = true;
  2164. }
  2165. }
  2166. break;
  2167. case SDL_JOYAXISMOTION:
  2168. if (event.jaxis.value < -Config.AnalogDeadZone)
  2169. {
  2170. if (event.jaxis.axis == 0)
  2171. {
  2172. if (IsEventOff(EVENT_PAGE_UP))
  2173. {
  2174. EventPressCount.at(EVENT_PAGE_UP) = EVENT_LOOPS_ON;
  2175. }
  2176. EventReleased.at(EVENT_PAGE_DOWN) = true;
  2177. }
  2178. if (event.jaxis.axis == 1)
  2179. {
  2180. if (IsEventOff(EVENT_ONE_UP))
  2181. {
  2182. EventPressCount.at(EVENT_ONE_UP) = EVENT_LOOPS_ON;
  2183. }
  2184. EventReleased.at(EVENT_ONE_DOWN) = true;
  2185. }
  2186. }
  2187. else if (event.jaxis.value > Config.AnalogDeadZone)
  2188. {
  2189. if (event.jaxis.axis == 0)
  2190. {
  2191. if (IsEventOff(EVENT_PAGE_DOWN))
  2192. {
  2193. EventPressCount.at(EVENT_PAGE_DOWN) = EVENT_LOOPS_ON;
  2194. }
  2195. EventReleased.at(EVENT_PAGE_UP) = true;
  2196. }
  2197. if (event.jaxis.axis == 1)
  2198. {
  2199. if (IsEventOff(EVENT_ONE_DOWN))
  2200. {
  2201. EventPressCount.at(EVENT_ONE_DOWN) = EVENT_LOOPS_ON;
  2202. }
  2203. EventReleased.at(EVENT_ONE_UP) = true;
  2204. }
  2205. }
  2206. else
  2207. {
  2208. EventReleased.at(EVENT_ONE_UP) = true;
  2209. EventReleased.at(EVENT_ONE_DOWN) = true;
  2210. EventReleased.at(EVENT_PAGE_UP) = true;
  2211. EventReleased.at(EVENT_PAGE_DOWN) = true;
  2212. }
  2213. break;
  2214. case SDL_MOUSEMOTION:
  2215. Mouse.x = event.motion.x;
  2216. Mouse.y = event.motion.y;
  2217. for (index=0; index<RectEntries.size(); index++)
  2218. {
  2219. if (CheckRectCollision( &Mouse, &RectEntries.at(index) ))
  2220. {
  2221. // Determine item being hovered over by the pointer
  2222. newsel = DisplayList.at(Mode).first+index;
  2223. // Only need to refresh the names when a new entry is hovered
  2224. if (newsel != DisplayList.at(Mode).absolute)
  2225. {
  2226. DisplayList.at(Mode).absolute = newsel;
  2227. DisplayList.at(Mode).relative = index;
  2228. RefreshList = true;
  2229. }
  2230. break;
  2231. }
  2232. }
  2233. break;
  2234. case SDL_MOUSEBUTTONDOWN:
  2235. switch (event.button.button)
  2236. {
  2237. case SDL_BUTTON_LEFT:
  2238. case SDL_BUTTON_MIDDLE:
  2239. case SDL_BUTTON_RIGHT:;
  2240. Mouse.x = event.button.x;
  2241. Mouse.y = event.button.y;
  2242. for (index=0; index<RectButtonsLeft.size(); index++)
  2243. {
  2244. if (ButtonModesLeft.at(index)!=EVENT_NONE)
  2245. {
  2246. if (CheckRectCollision( &Mouse, &RectButtonsLeft.at(index) ))
  2247. {
  2248. EventPressCount.at(ButtonModesLeft.at(index)) = EVENT_LOOPS_ON;
  2249. #if defined(DEBUG)
  2250. Log( "DEBUG LeftButton Active %d %d\n", ButtonModesLeft.at(index), index );
  2251. #endif
  2252. }
  2253. }
  2254. }
  2255. for (index=0; index<RectButtonsRight.size(); index++)
  2256. {
  2257. if (ButtonModesRight.at(index)!=EVENT_NONE)
  2258. {
  2259. if (CheckRectCollision( &Mouse, &RectButtonsRight.at(index) ))
  2260. {
  2261. EventPressCount.at(ButtonModesRight.at(index)) = EVENT_LOOPS_ON;
  2262. #if defined(DEBUG)
  2263. Log( "DEBUG RightButton Active %d %d\n", ButtonModesRight.at(index), index );
  2264. #endif
  2265. }
  2266. }
  2267. }
  2268. break;
  2269. case SDL_BUTTON_WHEELUP:
  2270. EventPressCount.at(EVENT_ONE_UP) = EVENT_LOOPS_ON;
  2271. break;
  2272. case SDL_BUTTON_WHEELDOWN:
  2273. EventPressCount.at(EVENT_ONE_DOWN) = EVENT_LOOPS_ON;
  2274. break;
  2275. default:
  2276. break;
  2277. }
  2278. break;
  2279. case SDL_MOUSEBUTTONUP:
  2280. switch (event.button.button)
  2281. {
  2282. case SDL_BUTTON_LEFT:
  2283. case SDL_BUTTON_MIDDLE:
  2284. case SDL_BUTTON_RIGHT:
  2285. case SDL_BUTTON_WHEELUP:
  2286. case SDL_BUTTON_WHEELDOWN:
  2287. Mouse.x = event.button.x;
  2288. Mouse.y = event.button.y;
  2289. for (index=0; index<EventReleased.size(); index++)
  2290. {
  2291. EventReleased.at(index) = true;
  2292. }
  2293. #if defined(DEBUG)
  2294. Log( "DEBUG Releasing all events\n" );
  2295. #endif
  2296. break;
  2297. default:
  2298. break;
  2299. }
  2300. break;
  2301. default:
  2302. break;
  2303. }
  2304. }
  2305. // List navigation
  2306. if (IsEventOn(EVENT_ONE_UP)==true)
  2307. {
  2308. DisplayList.at(Mode).absolute--;
  2309. DisplayList.at(Mode).relative--;
  2310. RefreshList = true;
  2311. }
  2312. if (IsEventOn(EVENT_ONE_DOWN)==true)
  2313. {
  2314. DisplayList.at(Mode).absolute++;
  2315. DisplayList.at(Mode).relative++;
  2316. RefreshList = true;
  2317. }
  2318. if (IsEventOn(EVENT_PAGE_UP)==true)
  2319. {
  2320. DisplayList.at(Mode).absolute -= Config.MaxEntries;
  2321. DisplayList.at(Mode).relative = 0;
  2322. RefreshList = true;
  2323. }
  2324. if (IsEventOn(EVENT_PAGE_DOWN)==true)
  2325. {
  2326. DisplayList.at(Mode).absolute += Config.MaxEntries;
  2327. DisplayList.at(Mode).relative = Config.MaxEntries-1;
  2328. RefreshList = true;
  2329. }
  2330. // Path navigation
  2331. if (Mode == MODE_SELECT_ENTRY)
  2332. {
  2333. // Go up into a dir
  2334. if (Rescan == false && IsEventOn(EVENT_DIR_UP) == true)
  2335. {
  2336. if (Config.UseZipSupport == 1 && Profile.ZipFile.length() > 0)
  2337. {
  2338. ZipUp();
  2339. }
  2340. else
  2341. {
  2342. if (Profile.LaunchableDirs == false)
  2343. {
  2344. DirectoryUp();
  2345. }
  2346. }
  2347. }
  2348. // Go down into a dir
  2349. if (Rescan == false && ((IsEventOn(EVENT_DIR_DOWN) == true) || (IsEventOn(EVENT_SELECT) == true)))
  2350. {
  2351. if (ItemsEntry.size()>0)
  2352. {
  2353. if (ItemsEntry.at(DisplayList.at(Mode).absolute).Type == TYPE_DIR)
  2354. {
  2355. if (Profile.LaunchableDirs == false)
  2356. {
  2357. DirectoryDown();
  2358. }
  2359. }
  2360. else if (Config.UseZipSupport == 1 && ItemsEntry.at(DisplayList.at(Mode).absolute).Type == TYPE_ZIP)
  2361. {
  2362. ZipDown();
  2363. }
  2364. }
  2365. else
  2366. {
  2367. EventPressCount.at( EVENT_SELECT ) = EVENT_LOOPS_OFF;
  2368. }
  2369. }
  2370. }
  2371. // Value configuration
  2372. if (Mode == MODE_SELECT_VALUE)
  2373. {
  2374. SetOneEntryValue = false;
  2375. SetAllEntryValue = false;
  2376. if (IsEventOn(EVENT_SET_ONE) == true)
  2377. {
  2378. RefreshList = true;
  2379. SetOneEntryValue = true;
  2380. }
  2381. if (IsEventOn(EVENT_SET_ALL) == true)
  2382. {
  2383. RefreshList = true;
  2384. SetAllEntryValue = true;
  2385. }
  2386. }
  2387. if (IsEventOn(EVENT_ZIP_MODE) == true)
  2388. {
  2389. Redraw = true;
  2390. DrawState_ZipMode = true;
  2391. ExtractAllFiles = !ExtractAllFiles;
  2392. }
  2393. return 0;
  2394. }