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