2007-05-30 21:56:52 +00:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
2002-09-27 23:27:14 +00:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
2005-10-18 01:30:26 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2014-02-18 01:34:20 +00:00
*
2002-09-27 23:27:14 +00:00
*/
2021-07-12 14:18:19 +00:00
# include "base/version.h"
2003-11-05 00:59:03 +00:00
# include "common/config-manager.h"
2021-07-12 14:18:19 +00:00
# include "common/events.h"
# include "common/fs.h"
# include "common/gui_options.h"
# include "common/util.h"
# include "common/system.h"
# include "common/translation.h"
# include "gui/about.h"
# include "gui/browser.h"
# include "gui/chooser.h"
# include "gui/editgamedialog.h"
# include "gui/launcher.h"
# include "gui/massadd.h"
# include "gui/message.h"
2021-07-07 14:15:46 +00:00
# include "gui/gui-manager.h"
2021-07-12 14:18:19 +00:00
# include "gui/options.h"
# ifdef ENABLE_EVENTRECORDER
# include "gui/onscreendialog.h"
# include "gui/recorderdialog.h"
# include "gui/EventRecorder.h"
# endif
# include "gui/saveload.h"
# include "gui/unknown-game-dialog.h"
# include "gui/widgets/edittext.h"
2021-07-17 11:00:01 +00:00
# include "gui/widgets/groupedlist.h"
2021-07-12 14:18:19 +00:00
# include "gui/widgets/tab.h"
# include "gui/widgets/popup.h"
# include "gui/widgets/grid.h"
2021-07-07 14:15:46 +00:00
# include "gui/ThemeEval.h"
2021-07-12 14:18:19 +00:00
# include "engines/advancedDetector.h"
2003-11-05 00:59:03 +00:00
2021-07-12 14:18:19 +00:00
# include "graphics/cursorman.h"
# if defined(USE_CLOUD) && defined(USE_LIBCURL)
# include "backends/cloud/cloudmanager.h"
# endif
2002-09-27 23:27:14 +00:00
2003-10-08 21:59:23 +00:00
using Common : : ConfigManager ;
2002-09-27 23:27:14 +00:00
2003-11-10 23:40:48 +00:00
namespace GUI {
2021-07-12 14:18:19 +00:00
enum {
kStartCmd = ' STRT ' ,
kAboutCmd = ' ABOU ' ,
kOptionsCmd = ' OPTN ' ,
kAddGameCmd = ' ADDG ' ,
kMassAddGameCmd = ' MADD ' ,
kEditGameCmd = ' EDTG ' ,
kRemoveGameCmd = ' REMG ' ,
kLoadGameCmd = ' LOAD ' ,
kRecordGameCmd = ' RECG ' ,
kQuitCmd = ' QUIT ' ,
kSearchCmd = ' SRCH ' ,
kListSearchCmd = ' LSSR ' ,
kSearchClearCmd = ' SRCL ' ,
2021-07-22 15:54:25 +00:00
kSetGroupMethodCmd = ' GPBY ' ,
2021-07-12 14:18:19 +00:00
kCmdGlobalGraphicsOverride = ' OGFX ' ,
kCmdGlobalAudioOverride = ' OSFX ' ,
kCmdGlobalMIDIOverride = ' OMID ' ,
kCmdGlobalMT32Override = ' OM32 ' ,
kCmdGlobalVolumeOverride = ' OVOL ' ,
kCmdChooseSoundFontCmd = ' chsf ' ,
kCmdExtraBrowser = ' PEXT ' ,
kCmdExtraPathClear = ' PEXC ' ,
kCmdGameBrowser = ' PGME ' ,
kCmdSaveBrowser = ' PSAV ' ,
kCmdSavePathClear = ' PSAC '
} ;
# pragma mark -
bool LauncherFilterMatcher ( void * boss , int idx , const Common : : U32String & item , Common : : U32String token ) {
bool invert = false ;
while ( token . size ( ) & & token [ 0 ] = = ' ! ' ) {
token = token . substr ( 1 ) ;
invert = ! invert ;
}
bool result = false ;
Common : : String token8 = token ;
size_t pos = token8 . findFirstOf ( " :=~ " ) ;
if ( pos ! = token8 . npos ) {
Common : : String key = token8 . substr ( 0 , token8 . findFirstOf ( token8 [ pos ] ) ) ;
Common : : String filter = token8 . substr ( token8 . findFirstOf ( token8 [ pos ] ) + 1 ) ;
if ( key . size ( ) ) {
if ( Common : : String ( " description " ) . hasPrefix ( key ) ) {
key = " description " ;
} else if ( Common : : String ( " engineid " ) . hasPrefix ( key ) ) {
key = " engineid " ;
} else if ( Common : : String ( " gameid " ) . hasPrefix ( key ) ) {
key = " gameid " ;
} else if ( Common : : String ( " language " ) . hasPrefix ( key ) ) {
key = " language " ;
} else if ( Common : : String ( " path " ) . hasPrefix ( key ) ) {
key = " path " ;
} else if ( Common : : String ( " platform " ) . hasPrefix ( key ) ) {
key = " platform " ;
}
}
LauncherDialog * launcher = ( LauncherDialog * ) ( boss ) ;
Common : : String data = launcher - > getGameConfig ( idx , key ) ;
data . toLowercase ( ) ;
if ( token8 [ pos ] = = ' : ' ) {
result = data . contains ( filter ) ;
} else if ( token8 [ pos ] = = ' = ' ) {
result = data = = filter ;
} else if ( token8 [ pos ] = = ' ~ ' ) {
result = data . matchString ( filter ) ;
}
} else {
result = item . contains ( token ) ;
}
return invert ? ! result : result ;
}
LauncherDialog : : LauncherDialog ( const Common : : String & dialogName )
: Dialog ( dialogName ) , _title ( dialogName ) , _browser ( nullptr ) ,
2021-07-23 12:59:19 +00:00
_loadDialog ( nullptr ) , _searchClearButton ( nullptr ) , _searchDesc ( nullptr ) ,
2021-08-06 12:22:37 +00:00
_grpChooserDesc ( nullptr ) , _grpChooserPopup ( nullptr ) , _groupBy ( kGroupByNone )
2021-07-12 14:18:19 +00:00
# ifndef DISABLE_FANCY_THEMES
, _logo ( nullptr ) , _searchPic ( nullptr )
# endif // !DISABLE_FANCY_THEMES
# ifndef DISABLE_LAUNCHERDISPLAY_GRID
, _listButton ( nullptr ) , _gridButton ( nullptr )
# endif // !DISABLE_LAUNCHERDISPLAY_GRID
{
_backgroundType = GUI : : ThemeEngine : : kDialogBackgroundMain ;
GUI : : GuiManager : : instance ( ) . _launched = true ;
# ifndef DISABLE_LAUNCHERDISPLAY_GRID
2021-08-13 11:14:32 +00:00
addLayoutChooserButtons ( ) ;
2021-07-12 14:18:19 +00:00
# endif // !DISABLE_LAUNCHERDISPLAY_GRID
2021-08-08 13:44:59 +00:00
Common : : FSDirectory * mdDir = new Common : : FSDirectory ( Common : : String ( " ./metadata/ " ) ) ;
Common : : ArchiveMemberList mdFiles ;
mdDir - > listMatchingMembers ( mdFiles , " *.xml " ) ;
for ( Common : : ArchiveMemberList : : iterator md = mdFiles . begin ( ) ; md ! = mdFiles . end ( ) ; + + md ) {
if ( _metadataParser . loadStream ( ( * md ) - > createReadStream ( ) ) = = false ) {
warning ( " Failed to load XML file '%s' " , ( * md ) - > getDisplayName ( ) . c_str ( ) ) ;
_metadataParser . close ( ) ;
}
if ( _metadataParser . parse ( ) = = false ) {
warning ( " Failed to parse XML file '%s' " , ( * md ) - > getDisplayName ( ) . c_str ( ) ) ;
_metadataParser . close ( ) ;
}
}
2021-07-12 14:18:19 +00:00
}
LauncherDialog : : ~ LauncherDialog ( ) {
delete _browser ;
delete _loadDialog ;
}
void LauncherDialog : : build ( ) {
# ifndef DISABLE_FANCY_THEMES
_logo = nullptr ;
2021-08-14 16:11:21 +00:00
_grpChooserDesc = new StaticTextWidget ( this , String ( _title + " .laGroupPopupDesc " ) , U32String ( " Group by: " ) ) ;
_grpChooserPopup = new PopUpWidget ( this , String ( _title + " .laGroupPopup " ) , U32String ( " Select a criteria to group the entries " ) , kSetGroupMethodCmd ) ;
_grpChooserPopup - > appendEntry ( _ ( " None " ) , kGroupByNone ) ;
_grpChooserPopup - > appendEntry ( _ ( " First letter " ) , kGroupByFirstLetter ) ;
_grpChooserPopup - > appendEntry ( _ ( " Engine " ) , kGroupByEngine ) ;
_grpChooserPopup - > appendEntry ( _ ( " Series " ) , kGroupBySeries ) ;
_grpChooserPopup - > appendEntry ( _ ( " Publisher " ) , kGroupByCompany ) ;
_grpChooserPopup - > appendEntry ( _ ( " Language " ) , kGroupByLanguage ) ;
_grpChooserPopup - > appendEntry ( _ ( " Platform " ) , kGroupByPlatform ) ;
2021-08-14 20:07:21 +00:00
// TODO: Save the last grouping method in config
_grpChooserPopup - > setSelected ( kGroupByNone ) ;
2021-07-12 14:18:19 +00:00
if ( g_gui . xmlEval ( ) - > getVar ( " Globals.ShowLauncherLogo " ) = = 1 & & g_gui . theme ( ) - > supportsImages ( ) ) {
2021-08-14 16:11:21 +00:00
_logo = new GraphicsWidget ( this , _title + " .Logo " ) ;
2021-07-12 14:18:19 +00:00
_logo - > useThemeTransparency ( true ) ;
_logo - > setGfxFromTheme ( ThemeEngine : : kImageLogo ) ;
2021-08-14 16:11:21 +00:00
new StaticTextWidget ( this , _title + " .Version " , Common : : U32String ( gScummVMVersionDate ) ) ;
2021-07-12 14:18:19 +00:00
} else
2021-08-14 16:11:21 +00:00
new StaticTextWidget ( this , _title + " .Version " , Common : : U32String ( gScummVMFullVersion ) ) ;
2021-07-12 14:18:19 +00:00
# else
// Show ScummVM version
2021-08-14 16:11:21 +00:00
new StaticTextWidget ( this , _title + " .Version " , Common : : U32String ( gScummVMFullVersion ) ) ;
2021-07-12 14:18:19 +00:00
# endif
if ( ! g_system - > hasFeature ( OSystem : : kFeatureNoQuit ) )
2021-08-14 16:11:21 +00:00
new ButtonWidget ( this , _title + " .QuitButton " , _ ( " ~Q~uit " ) , _ ( " Quit ScummVM " ) , kQuitCmd ) ;
new ButtonWidget ( this , _title + " .AboutButton " , _ ( " A~b~out... " ) , _ ( " About ScummVM " ) , kAboutCmd ) ;
new ButtonWidget ( this , _title + " .OptionsButton " , _ ( " ~O~ptions... " ) , _ ( " Change global ScummVM options " ) , kOptionsCmd ) ;
// Above the lowest button rows: two more buttons (directly below the list box)
if ( g_system - > getOverlayWidth ( ) > 320 ) {
DropdownButtonWidget * addButton =
new DropdownButtonWidget ( this , _title + " .AddGameButton " , _ ( " ~A~dd Game... " ) , _ ( " Add games to the list " ) , kAddGameCmd ) ;
addButton - > appendEntry ( _ ( " Mass Add... " ) , kMassAddGameCmd ) ;
_addButton = addButton ;
_removeButton =
new ButtonWidget ( this , _title + " .RemoveGameButton " , _ ( " ~R~emove Game " ) , _ ( " Remove game from the list. The game data files stay intact " ) , kRemoveGameCmd ) ;
} else {
DropdownButtonWidget * addButton =
new DropdownButtonWidget ( this , _title + " .AddGameButton " , _c ( " ~A~dd Game... " , " lowres " ) , _ ( " Add games to the list " ) , kAddGameCmd ) ;
addButton - > appendEntry ( _c ( " Mass Add... " , " lowres " ) , kMassAddGameCmd ) ;
_addButton = addButton ;
_removeButton =
new ButtonWidget ( this , _title + " .RemoveGameButton " , _c ( " ~R~emove Game " , " lowres " ) , _ ( " Remove game from the list. The game data files stay intact " ) , kRemoveGameCmd ) ;
}
2021-07-12 14:18:19 +00:00
// Search box
2021-08-14 16:11:21 +00:00
_searchDesc = nullptr ;
2021-07-12 14:18:19 +00:00
# ifndef DISABLE_FANCY_THEMES
_searchPic = nullptr ;
if ( g_gui . xmlEval ( ) - > getVar ( " Globals.ShowSearchPic " ) = = 1 & & g_gui . theme ( ) - > supportsImages ( ) ) {
2021-08-14 16:11:21 +00:00
_searchPic = new GraphicsWidget ( this , _title + " .SearchPic " , _ ( " Search in game list " ) ) ;
2021-07-12 14:18:19 +00:00
_searchPic - > setGfxFromTheme ( ThemeEngine : : kImageSearch ) ;
} else
# endif
2021-08-14 16:11:21 +00:00
_searchDesc = new StaticTextWidget ( this , _title + " .SearchDesc " , _ ( " Search: " ) ) ;
2021-07-12 14:18:19 +00:00
2021-08-14 16:11:21 +00:00
_searchWidget = new EditTextWidget ( this , _title + " .Search " , _search , Common : : U32String ( ) , kSearchCmd ) ;
_searchClearButton = addClearButton ( this , _title + " .SearchClearButton " , kSearchClearCmd ) ;
2021-07-12 14:18:19 +00:00
// Create file browser dialog
_browser = new BrowserDialog ( _ ( " Select directory with game data " ) , true ) ;
// Create Load dialog
_loadDialog = new SaveLoadChooser ( _ ( " Load game: " ) , _ ( " Load " ) , false ) ;
}
void LauncherDialog : : clean ( ) {
while ( _firstWidget ) {
Widget * w = _firstWidget ;
removeWidget ( w ) ;
// This is called from rebuild() which may result from handleCommand being called by
// a child widget sendCommand call. In such a case sendCommand is still being executed
// so we should not delete yet the child widget. Thus delay the deletion.
g_gui . addToTrash ( w , this ) ;
}
delete _browser ;
delete _loadDialog ;
}
void LauncherDialog : : rebuild ( ) {
clean ( ) ;
build ( ) ;
reflowLayout ( ) ;
setDefaultFocusedWidget ( ) ;
}
int LauncherDialog : : run ( ) {
// Open up
open ( ) ;
// Start processing events
g_gui . runLoop ( ) ;
// Return the result code
return getResult ( ) ;
}
void LauncherDialog : : open ( ) {
// Clear the active domain, in case we return to the dialog from a
// failure to launch a game. Otherwise, pressing ESC will attempt to
// re-launch the same game again.
ConfMan . setActiveDomain ( " " ) ;
CursorMan . popAllCursors ( ) ;
Dialog : : open ( ) ;
updateButtons ( ) ;
}
void LauncherDialog : : close ( ) {
// Save last selection
const int sel = getSelected ( ) ;
if ( sel > = 0 )
ConfMan . set ( " lastselectedgame " , _domains [ sel ] , ConfigManager : : kApplicationDomain ) ;
else
ConfMan . removeKey ( " lastselectedgame " , ConfigManager : : kApplicationDomain ) ;
ConfMan . flushToDisk ( ) ;
Dialog : : close ( ) ;
}
struct LauncherEntry {
Common : : String key ;
Common : : String description ;
const Common : : ConfigManager : : Domain * domain ;
LauncherEntry ( Common : : String k , Common : : String d , const Common : : ConfigManager : : Domain * v ) {
key = k ; description = d , domain = v ;
}
} ;
struct LauncherEntryComparator {
bool operator ( ) ( const LauncherEntry & x , const LauncherEntry & y ) const {
return scumm_compareDictionary ( x . description . c_str ( ) , y . description . c_str ( ) ) < 0 ;
}
} ;
void LauncherDialog : : addGame ( ) {
// Allow user to add a new game to the list.
// 1) show a dir selection dialog which lets the user pick the directory
// the game data resides in.
// 2) try to auto detect which game is in the directory, if we cannot
// determine it uniquely present a list of candidates to the user
// to pick from
// 3) Display the 'Edit' dialog for that item, letting the user specify
// an alternate description (to distinguish multiple versions of the
// game, e.g. 'Monkey German' and 'Monkey English') and set default
// options for that game
// 4) If no game is found in the specified directory, return to the
// dialog.
bool looping ;
do {
looping = false ;
if ( _browser - > runModal ( ) > 0 ) {
// User made his choice...
# if defined(USE_CLOUD) && defined(USE_LIBCURL)
String selectedDirectory = _browser - > getResult ( ) . getPath ( ) ;
String bannedDirectory = CloudMan . getDownloadLocalDirectory ( ) ;
if ( selectedDirectory . size ( ) & & selectedDirectory . lastChar ( ) ! = ' / ' & & selectedDirectory . lastChar ( ) ! = ' \\ ' )
selectedDirectory + = ' / ' ;
if ( bannedDirectory . size ( ) & & bannedDirectory . lastChar ( ) ! = ' / ' & & bannedDirectory . lastChar ( ) ! = ' \\ ' ) {
if ( selectedDirectory . size ( ) ) {
bannedDirectory + = selectedDirectory . lastChar ( ) ;
} else {
bannedDirectory + = ' / ' ;
}
}
if ( selectedDirectory . size ( ) & & bannedDirectory . size ( ) & & selectedDirectory . equalsIgnoreCase ( bannedDirectory ) ) {
MessageDialog alert ( _ ( " This directory cannot be used yet, it is being downloaded into! " ) ) ;
alert . runModal ( ) ;
return ;
}
# endif
looping = ! doGameDetection ( _browser - > getResult ( ) . getPath ( ) ) ;
}
} while ( looping ) ;
}
void LauncherDialog : : massAddGame ( ) {
MessageDialog alert ( _ ( " Do you really want to run the mass game detector? "
" This could potentially add a huge number of games. " ) , _ ( " Yes " ) , _ ( " No " ) ) ;
if ( alert . runModal ( ) = = GUI : : kMessageOK & & _browser - > runModal ( ) > 0 ) {
MD5Man . clear ( ) ;
MassAddDialog massAddDlg ( _browser - > getResult ( ) ) ;
massAddDlg . runModal ( ) ;
// Update the ListWidget and force a redraw
// If new target(s) were added, update the ListWidget and move
// the selection to to first newly detected game.
Common : : String newTarget = massAddDlg . getFirstAddedTarget ( ) ;
if ( ! newTarget . empty ( ) ) {
updateListing ( ) ;
selectTarget ( newTarget ) ;
}
g_gui . scheduleTopDialogRedraw ( ) ;
}
}
Common : : String LauncherDialog : : getGameConfig ( int item , Common : : String key ) {
if ( ConfMan . hasKey ( key , _domains [ item ] ) ) {
return ConfMan . get ( key , _domains [ item ] ) ;
}
return " " ;
}
void LauncherDialog : : removeGame ( int item ) {
MessageDialog alert ( _ ( " Do you really want to remove this game configuration? " ) , _ ( " Yes " ) , _ ( " No " ) ) ;
if ( alert . runModal ( ) = = GUI : : kMessageOK ) {
// Remove the currently selected game from the list
assert ( item > = 0 ) ;
ConfMan . removeGameDomain ( _domains [ item ] ) ;
// Write config to disk
ConfMan . flushToDisk ( ) ;
// Update the ListWidget/GridWidget and force a redraw
updateListing ( ) ;
g_gui . scheduleTopDialogRedraw ( ) ;
}
}
void LauncherDialog : : editGame ( int item ) {
// Set game specific options. Most of these should be "optional", i.e. by
// default set nothing and use the global ScummVM settings. E.g. the user
// can set here an optional alternate music volume, or for specific games
// a different music driver etc.
// This is useful because e.g. MonkeyVGA needs AdLib music to have decent
// music support etc.
assert ( item > = 0 ) ;
EditGameDialog editDialog ( _domains [ item ] ) ;
if ( editDialog . runModal ( ) > 0 ) {
// User pressed OK, so make changes permanent
// Write config to disk
ConfMan . flushToDisk ( ) ;
// Update the ListWidget, reselect the edited game and force a redraw
updateListing ( ) ;
selectTarget ( editDialog . getDomain ( ) ) ;
g_gui . scheduleTopDialogRedraw ( ) ;
}
}
# ifdef ENABLE_EVENTRECORDER
void LauncherDialog : : recordGame ( int item ) {
RecorderDialog recorderDialog ;
MessageDialog alert ( _ ( " Do you want to load saved game? " ) ,
_ ( " Yes " ) , _ ( " No " ) ) ;
switch ( recorderDialog . runModal ( _domains [ item ] ) ) {
default :
// fallthrough intended
case RecorderDialog : : kRecordDialogClose :
break ;
case RecorderDialog : : kRecordDialogPlayback :
ConfMan . setActiveDomain ( _domains [ item ] ) ;
close ( ) ;
ConfMan . set ( " record_mode " , " playback " , ConfigManager : : kTransientDomain ) ;
ConfMan . set ( " record_file_name " , recorderDialog . getFileName ( ) , ConfigManager : : kTransientDomain ) ;
break ;
case RecorderDialog : : kRecordDialogRecord :
ConfMan . setActiveDomain ( _domains [ item ] ) ;
if ( alert . runModal ( ) = = GUI : : kMessageOK ) {
loadGame ( item ) ;
}
close ( ) ;
g_eventRec . setAuthor ( recorderDialog . _author ) ;
g_eventRec . setName ( recorderDialog . _name ) ;
g_eventRec . setNotes ( recorderDialog . _notes ) ;
ConfMan . set ( " record_mode " , " record " , ConfigManager : : kTransientDomain ) ;
break ;
}
}
# endif
void LauncherDialog : : loadGame ( int item ) {
String target = _domains [ item ] ;
target . toLowercase ( ) ;
EngineMan . upgradeTargetIfNecessary ( target ) ;
// Look for the plugin
const Plugin * metaEnginePlugin = nullptr ;
const Plugin * enginePlugin = nullptr ;
EngineMan . findTarget ( target , & metaEnginePlugin ) ;
// If we found a relevant plugin, find the matching engine plugin.
if ( metaEnginePlugin ) {
enginePlugin = PluginMan . getEngineFromMetaEngine ( metaEnginePlugin ) ;
}
if ( enginePlugin ) {
assert ( enginePlugin - > getType ( ) = = PLUGIN_TYPE_ENGINE ) ;
const MetaEngine & metaEngine = enginePlugin - > get < MetaEngine > ( ) ;
if ( metaEngine . hasFeature ( MetaEngine : : kSupportsListSaves ) & &
metaEngine . hasFeature ( MetaEngine : : kSupportsLoadingDuringStartup ) ) {
int slot = _loadDialog - > runModalWithMetaEngineAndTarget ( & metaEngine , target ) ;
if ( slot > = 0 ) {
ConfMan . setActiveDomain ( _domains [ item ] ) ;
ConfMan . setInt ( " save_slot " , slot , Common : : ConfigManager : : kTransientDomain ) ;
close ( ) ;
}
} else {
MessageDialog dialog
( _ ( " This game does not support loading games from the launcher. " ) , _ ( " OK " ) ) ;
dialog . runModal ( ) ;
}
} else {
MessageDialog dialog ( _ ( " ScummVM could not find any engine capable of running the selected game! " ) , _ ( " OK " ) ) ;
dialog . runModal ( ) ;
}
}
void LauncherDialog : : handleKeyDown ( Common : : KeyState state ) {
Dialog : : handleKeyDown ( state ) ;
}
void LauncherDialog : : handleKeyUp ( Common : : KeyState state ) {
Dialog : : handleKeyUp ( state ) ;
updateButtons ( ) ;
}
void LauncherDialog : : handleOtherEvent ( const Common : : Event & evt ) {
Dialog : : handleOtherEvent ( evt ) ;
if ( evt . type = = Common : : EVENT_DROP_FILE ) {
doGameDetection ( evt . path ) ;
}
}
bool LauncherDialog : : doGameDetection ( const Common : : String & path ) {
// Allow user to add a new game to the list.
// 2) try to auto detect which game is in the directory, if we cannot
// determine it uniquely present a list of candidates to the user
// to pick from
// 3) Display the 'Edit' dialog for that item, letting the user specify
// an alternate description (to distinguish multiple versions of the
// game, e.g. 'Monkey German' and 'Monkey English') and set default
// options for that game
// 4) If no game is found in the specified directory, return to the
// dialog.
// User made his choice...
Common : : FSNode dir ( path ) ;
Common : : FSList files ;
if ( ! dir . getChildren ( files , Common : : FSNode : : kListAll ) ) {
MessageDialog alert ( _ ( " ScummVM couldn't open the specified directory! " ) ) ;
alert . runModal ( ) ;
return true ;
}
// ...so let's determine a list of candidates, games that
// could be contained in the specified directory.
DetectionResults detectionResults = EngineMan . detectGames ( files ) ;
if ( detectionResults . foundUnknownGames ( ) ) {
Common : : U32String report = detectionResults . generateUnknownGameReport ( false , 80 ) ;
g_system - > logMessage ( LogMessageType : : kInfo , report . encode ( ) . c_str ( ) ) ;
}
Common : : Array < DetectedGame > candidates = detectionResults . listDetectedGames ( ) ;
int idx ;
if ( candidates . empty ( ) ) {
// No game was found in the specified directory
MessageDialog alert ( _ ( " ScummVM could not find any game in the specified directory! " ) ) ;
alert . runModal ( ) ;
idx = - 1 ;
return false ;
} else if ( candidates . size ( ) = = 1 ) {
// Exact match
idx = 0 ;
} else {
// Display the candidates to the user and let her/him pick one
U32StringArray list ;
for ( idx = 0 ; idx < ( int ) candidates . size ( ) ; idx + + ) {
Common : : U32String description = candidates [ idx ] . description ;
if ( candidates [ idx ] . hasUnknownFiles ) {
description + = Common : : U32String ( " - " ) ;
description + = _ ( " Unknown variant " ) ;
}
list . push_back ( description ) ;
}
ChooserDialog dialog ( _ ( " Pick the game: " ) ) ;
dialog . setList ( list ) ;
idx = dialog . runModal ( ) ;
}
if ( 0 < = idx & & idx < ( int ) candidates . size ( ) ) {
const DetectedGame & result = candidates [ idx ] ;
if ( result . hasUnknownFiles ) {
UnknownGameDialog dialog ( result ) ;
bool cancel = dialog . runModal ( ) = = - 1 ;
if ( cancel ) {
idx = - 1 ;
}
}
}
if ( 0 < = idx & & idx < ( int ) candidates . size ( ) ) {
const DetectedGame & result = candidates [ idx ] ;
Common : : String domain = EngineMan . createTargetForGame ( result ) ;
// Display edit dialog for the new entry
EditGameDialog editDialog ( domain ) ;
if ( editDialog . runModal ( ) > 0 ) {
// User pressed OK, so make changes permanent
// Write config to disk
ConfMan . flushToDisk ( ) ;
// Update the ListWidget, select the new item, and force a redraw
updateListing ( ) ;
selectTarget ( editDialog . getDomain ( ) ) ;
g_gui . scheduleTopDialogRedraw ( ) ;
} else {
// User aborted, remove the the new domain again
ConfMan . removeGameDomain ( domain ) ;
}
}
return true ;
}
void LauncherDialog : : handleCommand ( CommandSender * sender , uint32 cmd , uint32 data ) {
int item = getSelected ( ) ;
switch ( cmd ) {
case kAddGameCmd :
addGame ( ) ;
break ;
case kMassAddGameCmd :
massAddGame ( ) ;
break ;
case kRemoveGameCmd :
2021-07-25 16:07:19 +00:00
if ( item < 0 ) return ;
2021-07-12 14:18:19 +00:00
removeGame ( item ) ;
break ;
case kEditGameCmd :
2021-07-25 16:07:19 +00:00
if ( item < 0 ) return ;
2021-07-12 14:18:19 +00:00
editGame ( item ) ;
break ;
case kLoadGameCmd :
2021-07-25 16:07:19 +00:00
if ( item < 0 ) return ;
2021-07-12 14:18:19 +00:00
loadGame ( item ) ;
break ;
# ifdef ENABLE_EVENTRECORDER
case kRecordGameCmd :
2021-07-25 16:07:19 +00:00
if ( item < 0 ) return ;
2021-07-12 14:18:19 +00:00
recordGame ( item ) ;
break ;
# endif
case kOptionsCmd : {
GlobalOptionsDialog options ( this ) ;
options . runModal ( ) ;
}
break ;
case kAboutCmd : {
AboutDialog about ;
about . runModal ( ) ;
}
break ;
case kStartCmd :
// Start the selected game.
2021-07-25 16:07:19 +00:00
if ( item < 0 ) return ;
2021-07-12 14:18:19 +00:00
ConfMan . setActiveDomain ( _domains [ item ] ) ;
close ( ) ;
break ;
case kQuitCmd :
ConfMan . setActiveDomain ( " " ) ;
setResult ( - 1 ) ;
close ( ) ;
break ;
# ifndef DISABLE_LAUNCHERDISPLAY_GRID
case kGridSwitchCmd :
setResult ( kSwitchLauncherDialog ) ;
ConfMan . set ( " gui_launcher_chooser " , " grid " , Common : : ConfigManager : : kApplicationDomain ) ;
close ( ) ;
break ;
case kListSwitchCmd :
setResult ( kSwitchLauncherDialog ) ;
ConfMan . set ( " gui_launcher_chooser " , " list " , Common : : ConfigManager : : kApplicationDomain ) ;
close ( ) ;
break ;
# endif
default :
Dialog : : handleCommand ( sender , cmd , data ) ;
}
}
void LauncherDialog : : reflowLayout ( ) {
if ( getType ( ) = = kLauncherDisplayGrid & & ! g_gui . xmlEval ( ) - > getVar ( " Globals.GridSupported " , 0 ) ) {
setResult ( kSwitchLauncherDialog ) ;
close ( ) ;
return ;
}
# ifndef DISABLE_FANCY_THEMES
if ( g_gui . xmlEval ( ) - > getVar ( " Globals.ShowLauncherLogo " ) = = 1 & & g_gui . theme ( ) - > supportsImages ( ) ) {
StaticTextWidget * ver = ( StaticTextWidget * ) findWidget ( String ( _title + " .Version " ) . c_str ( ) ) ;
if ( ver ) {
ver - > setAlign ( g_gui . xmlEval ( ) - > getWidgetTextHAlign ( _title + " .Version " ) ) ;
ver - > setLabel ( Common : : U32String ( gScummVMVersionDate ) ) ;
}
if ( ! _logo )
_logo = new GraphicsWidget ( this , _title + " .Logo " ) ;
_logo - > useThemeTransparency ( true ) ;
_logo - > setGfxFromTheme ( ThemeEngine : : kImageLogo ) ;
} else {
StaticTextWidget * ver = ( StaticTextWidget * ) findWidget ( String ( _title + " .Version " ) . c_str ( ) ) ;
if ( ver ) {
ver - > setAlign ( g_gui . xmlEval ( ) - > getWidgetTextHAlign ( _title + " .Version " ) ) ;
ver - > setLabel ( Common : : U32String ( gScummVMFullVersion ) ) ;
}
if ( _logo ) {
removeWidget ( _logo ) ;
_logo - > setNext ( nullptr ) ;
delete _logo ;
_logo = nullptr ;
}
}
if ( g_gui . xmlEval ( ) - > getVar ( " Globals.ShowSearchPic " ) = = 1 & & g_gui . theme ( ) - > supportsImages ( ) ) {
if ( ! _searchPic )
_searchPic = new GraphicsWidget ( this , _title + " .SearchPic " ) ;
_searchPic - > setGfxFromTheme ( ThemeEngine : : kImageSearch ) ;
if ( _searchDesc ) {
removeWidget ( _searchDesc ) ;
_searchDesc - > setNext ( nullptr ) ;
delete _searchDesc ;
_searchDesc = nullptr ;
}
} else {
if ( ! _searchDesc )
_searchDesc = new StaticTextWidget ( this , _title + " .SearchDesc " , _ ( " Search: " ) ) ;
if ( _searchPic ) {
removeWidget ( _searchPic ) ;
_searchPic - > setNext ( nullptr ) ;
delete _searchPic ;
_searchPic = nullptr ;
}
}
removeWidget ( _searchClearButton ) ;
_searchClearButton - > setNext ( nullptr ) ;
delete _searchClearButton ;
_searchClearButton = addClearButton ( this , _title + " .SearchClearButton " , kSearchClearCmd ) ;
# endif
# ifndef DISABLE_LAUNCHERDISPLAY_GRID
2021-08-13 11:14:32 +00:00
addLayoutChooserButtons ( ) ;
2021-07-12 14:18:19 +00:00
# endif
_w = g_system - > getOverlayWidth ( ) ;
_h = g_system - > getOverlayHeight ( ) ;
Dialog : : reflowLayout ( ) ;
}
# ifndef DISABLE_LAUNCHERDISPLAY_GRID
2021-08-13 11:14:32 +00:00
void LauncherDialog : : addLayoutChooserButtons ( ) {
2021-07-12 14:18:19 +00:00
if ( _listButton ) {
removeWidget ( _listButton ) ;
delete _listButton ;
_listButton = nullptr ;
}
if ( _gridButton ) {
removeWidget ( _gridButton ) ;
delete _gridButton ;
_gridButton = nullptr ;
}
if ( ! g_gui . xmlEval ( ) - > getVar ( " Globals.GridSupported " , 0 ) )
return ;
_listButton = createSwitchButton ( _title + " .ListSwitch " , Common : : U32String ( " L " ) , _ ( " List view " ) , ThemeEngine : : kImageList , kListSwitchCmd ) ;
_gridButton = createSwitchButton ( _title + " .GridSwitch " , Common : : U32String ( " G " ) , _ ( " Grid view " ) , ThemeEngine : : kImageGrid , kGridSwitchCmd ) ;
}
ButtonWidget * LauncherDialog : : createSwitchButton ( const Common : : String & name , const Common : : U32String & desc , const Common : : U32String & tooltip , const char * image , uint32 cmd ) {
ButtonWidget * button ;
# ifndef DISABLE_FANCY_THEMES
if ( g_gui . xmlEval ( ) - > getVar ( " Globals.ShowChooserPics " ) = = 1 & & g_gui . theme ( ) - > supportsImages ( ) ) {
button = new PicButtonWidget ( this , name , tooltip , cmd ) ;
( ( PicButtonWidget * ) button ) - > useThemeTransparency ( true ) ;
( ( PicButtonWidget * ) button ) - > setGfx ( g_gui . theme ( ) - > getImageSurface ( image ) , kPicButtonStateEnabled , false ) ;
} else
# endif
button = new ButtonWidget ( this , name , desc , tooltip , cmd ) ;
return button ;
}
# endif // !DISABLE_LAUNCHERDISPLAY_GRID
bool LauncherDialog : : checkModifier ( int checkedModifier ) {
int modifiers = g_system - > getEventManager ( ) - > getModifierState ( ) ;
return ( modifiers & checkedModifier ) ! = 0 ;
}
# pragma mark -
2021-07-01 16:34:11 +00:00
LauncherChooser : : LauncherChooser ( ) : _impl ( nullptr ) { }
LauncherChooser : : ~ LauncherChooser ( ) {
delete _impl ;
_impl = nullptr ;
2016-10-30 18:56:35 +00:00
}
2021-07-01 16:34:11 +00:00
# ifndef DISABLE_LAUNCHERDISPLAY_GRID
LauncherDisplayType getRequestedLauncherType ( ) {
const Common : : String & userConfig = ConfMan . get ( " gui_launcher_chooser " , Common : : ConfigManager : : kApplicationDomain ) ;
// If grid needs to be disabled on certain resolutions,
// those conditions need to be added here
2021-07-07 14:15:46 +00:00
if ( userConfig . equalsIgnoreCase ( " grid " ) & & g_gui . xmlEval ( ) - > getVar ( " Globals.GridSupported " , 0 ) ) {
2021-07-01 16:34:11 +00:00
return kLauncherDisplayGrid ;
} else {
return kLauncherDisplayList ;
}
}
# endif // !DISABLE_LAUNCHERDISPLAY_GRID
void LauncherChooser : : selectLauncher ( ) {
# ifndef DISABLE_LAUNCHERDISPLAY_GRID
LauncherDisplayType requestedType = getRequestedLauncherType ( ) ;
if ( ! _impl | | _impl - > getType ( ) ! = requestedType ) {
delete _impl ;
_impl = nullptr ;
2021-07-08 10:33:17 +00:00
switch ( requestedType ) {
2021-07-01 16:34:11 +00:00
case kLauncherDisplayGrid :
2021-07-02 09:32:23 +00:00
_impl = new LauncherGrid ( Common : : U32String ( " LauncherGrid " ) ) ;
2021-07-01 16:34:11 +00:00
break ;
default :
// fallthrough intended
case kLauncherDisplayList :
# endif // !DISABLE_LAUNCHERDISPLAY_GRID
2021-07-02 09:32:23 +00:00
_impl = new LauncherSimple ( Common : : U32String ( " Launcher " ) ) ;
2021-07-01 16:34:11 +00:00
# ifndef DISABLE_LAUNCHERDISPLAY_GRID
break ;
2016-10-30 18:56:35 +00:00
}
}
2021-07-01 16:34:11 +00:00
# endif // !DISABLE_LAUNCHERDISPLAY_GRID
}
int LauncherChooser : : runModal ( ) {
if ( ! _impl )
return - 1 ;
int ret ;
do {
ret = _impl - > run ( ) ;
if ( ret = = kSwitchLauncherDialog ) {
selectLauncher ( ) ;
}
} while ( ret < - 1 ) ;
return ret ;
}
2021-07-12 14:18:19 +00:00
# pragma mark -
LauncherSimple : : LauncherSimple ( const U32String & title )
: LauncherDialog ( title ) ,
2021-08-14 16:11:21 +00:00
_list ( nullptr ) {
2021-07-12 14:18:19 +00:00
build ( ) ;
}
void LauncherSimple : : selectTarget ( const String & target ) {
if ( ! target . empty ( ) ) {
int itemToSelect = 0 ;
StringArray : : const_iterator iter ;
for ( iter = _domains . begin ( ) ; iter ! = _domains . end ( ) ; + + iter , + + itemToSelect ) {
if ( target = = * iter ) {
_list - > setSelected ( itemToSelect ) ;
break ;
}
}
}
}
2021-07-14 13:47:19 +00:00
const int LauncherSimple : : getSelected ( ) { return _list - > getSelected ( ) ; }
2021-07-12 14:18:19 +00:00
void LauncherSimple : : build ( ) {
2021-08-14 16:11:21 +00:00
LauncherDialog : : build ( ) ;
2021-07-12 14:18:19 +00:00
_startButton =
new ButtonWidget ( this , " Launcher.StartButton " , _ ( " ~S~tart " ) , _ ( " Start selected game " ) , kStartCmd ) ;
DropdownButtonWidget * loadButton =
new DropdownButtonWidget ( this , " Launcher.LoadGameButton " , _ ( " ~L~oad... " ) , _ ( " Load saved game for selected game " ) , kLoadGameCmd ) ;
# ifdef ENABLE_EVENTRECORDER
loadButton - > appendEntry ( _ ( " Record... " ) , kRecordGameCmd ) ;
# endif
_loadButton = loadButton ;
2021-08-14 16:11:21 +00:00
// Add edit button
2021-07-12 14:18:19 +00:00
if ( g_system - > getOverlayWidth ( ) > 320 ) {
_editButton =
new ButtonWidget ( this , " Launcher.EditGameButton " , _ ( " ~E~dit Game... " ) , _ ( " Change game options " ) , kEditGameCmd ) ;
} else {
_editButton =
2021-08-14 16:11:21 +00:00
new ButtonWidget ( this , " Launcher.EditGameButton " , _c ( " ~E~dit Game... " , " lowres " ) , _ ( " Change game options " ) , kEditGameCmd ) ;
2021-07-12 14:18:19 +00:00
}
// Add list with game titles
2021-07-17 11:00:01 +00:00
_list = new GroupedListWidget ( this , " Launcher.GameList " , Common : : U32String ( ) , kListSearchCmd ) ;
2021-07-12 14:18:19 +00:00
_list - > setEditable ( false ) ;
_list - > enableDictionarySelect ( true ) ;
_list - > setNumberingMode ( kListNumberingOff ) ;
_list - > setFilterMatcher ( LauncherFilterMatcher , this ) ;
// Populate the list
updateListing ( ) ;
// Restore last selection
String last ( ConfMan . get ( " lastselectedgame " , ConfigManager : : kApplicationDomain ) ) ;
selectTarget ( last ) ;
// En-/disable the buttons depending on the list selection
updateButtons ( ) ;
}
void LauncherSimple : : updateListing ( ) {
U32StringArray l ;
2021-07-22 12:42:02 +00:00
Array < const Common : : ConfigManager : : Domain * > attrs ;
2021-07-12 14:18:19 +00:00
ListWidget : : ColorList colors ;
ThemeEngine : : FontColor color ;
int numEntries = ConfMan . getInt ( " gui_list_max_scan_entries " ) ;
// Retrieve a list of all games defined in the config file
_domains . clear ( ) ;
const ConfigManager : : DomainMap & domains = ConfMan . getGameDomains ( ) ;
bool scanEntries = numEntries = = - 1 ? true : ( ( int ) domains . size ( ) < = numEntries ) ;
// Turn it into a list of pointers
Common : : List < LauncherEntry > domainList ;
for ( ConfigManager : : DomainMap : : const_iterator iter = domains . begin ( ) ; iter ! = domains . end ( ) ; + + iter ) {
// Do not list temporary targets added when starting a game from the command line
if ( iter - > _value . contains ( " id_came_from_command_line " ) )
continue ;
String description ;
if ( ! iter - > _value . tryGetVal ( " description " , description ) ) {
QualifiedGameDescriptor g = EngineMan . findTarget ( iter - > _key ) ;
if ( ! g . description . empty ( ) )
description = g . description ;
}
if ( description . empty ( ) ) {
String gameid ;
if ( ! iter - > _value . tryGetVal ( " gameid " , gameid ) ) ;
gameid = iter - > _key ;
description = Common : : String : : format ( " Unknown (target %s, gameid %s) " , iter - > _key . c_str ( ) , gameid . c_str ( ) ) ;
}
if ( ! description . empty ( ) )
domainList . push_back ( LauncherEntry ( iter - > _key , description , & iter - > _value ) ) ;
}
// Now sort the list in dictionary order
Common : : sort ( domainList . begin ( ) , domainList . end ( ) , LauncherEntryComparator ( ) ) ;
// And fill out our structures
for ( Common : : List < LauncherEntry > : : const_iterator iter = domainList . begin ( ) ; iter ! = domainList . end ( ) ; + + iter ) {
color = ThemeEngine : : kFontColorNormal ;
if ( scanEntries ) {
Common : : String path ;
if ( ! iter - > domain - > tryGetVal ( " path " , path ) | | ! Common : : FSNode ( path ) . isDirectory ( ) ) {
color = ThemeEngine : : kFontColorAlternate ;
// If more conditions which grey out entries are added we should consider
// enabling this so that it is easy to spot why a certain game entry cannot
// be started.
// description += Common::String::format(" (%s)", _("Not found"));
}
}
l . push_back ( iter - > description ) ;
colors . push_back ( color ) ;
2021-07-22 12:42:02 +00:00
attrs . push_back ( iter - > domain ) ;
2021-07-12 14:18:19 +00:00
_domains . push_back ( iter - > key ) ;
}
const int oldSel = _list - > getSelected ( ) ;
2021-07-22 12:42:02 +00:00
_list - > setList ( l , & colors ) ;
2021-07-27 18:19:04 +00:00
2021-07-22 12:42:02 +00:00
groupEntries ( attrs ) ;
2021-07-25 15:49:31 +00:00
if ( oldSel < ( int ) l . size ( ) & & oldSel > = 0 )
2021-07-12 14:18:19 +00:00
_list - > setSelected ( oldSel ) ; // Restore the old selection
else if ( oldSel ! = - 1 )
// Select the last entry if the list has been reduced
_list - > setSelected ( _list - > getList ( ) . size ( ) - 1 ) ;
updateButtons ( ) ;
// Update the filter settings, those are lost when "setList"
// is called.
_list - > setFilter ( _searchWidget - > getEditString ( ) ) ;
}
2021-07-22 12:42:02 +00:00
void LauncherSimple : : groupEntries ( const Array < const Common : : ConfigManager : : Domain * > & metadata ) {
U32StringArray attrs ;
2021-08-12 20:03:18 +00:00
Common : : StringMap metadataNames ;
2021-07-22 15:54:25 +00:00
switch ( _groupBy ) {
2021-08-12 20:27:20 +00:00
case kGroupByFirstLetter : {
2021-07-25 15:50:05 +00:00
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
2021-07-22 15:54:25 +00:00
attrs . push_back ( metadata [ i ] - > getVal ( " description " ) . substr ( 0 , 1 ) ) ;
}
_list - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " ... " ) ) ;
break ;
2021-08-12 20:27:20 +00:00
}
case kGroupByEngine : {
2021-07-25 15:50:05 +00:00
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
2021-07-22 15:54:25 +00:00
U32String engineid = metadata [ i ] - > contains ( String ( " engineid " ) ) ?
2021-08-12 20:03:18 +00:00
metadata [ i ] - > getVal ( String ( " engineid " ) ) : String ( " " ) ;
2021-07-22 15:54:25 +00:00
attrs . push_back ( engineid ) ;
}
2021-08-12 20:03:18 +00:00
_list - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " " ) ) ;
metadataNames [ " " ] = " Unknown Engine " ;
2021-08-12 20:27:20 +00:00
Common : : HashMap < String , MetadataEngine , Common : : IgnoreCase_Hash , Common : : IgnoreCase_EqualTo > : : iterator i = _metadataParser . _engineInfo . begin ( ) ;
for ( ; i ! = _metadataParser . _engineInfo . end ( ) ; + + i ) {
2021-08-12 20:03:18 +00:00
if ( i - > _value . alt_name . empty ( ) ) {
metadataNames [ i - > _key ] = i - > _value . name ;
} else {
metadataNames [ i - > _key ] = Common : : String : : format ( " %s (%s) " , i - > _value . name . c_str ( ) , i - > _value . alt_name . c_str ( ) ) ;
}
}
2021-07-22 15:54:25 +00:00
break ;
2021-08-12 20:27:20 +00:00
}
2021-08-12 21:15:00 +00:00
case kGroupByCompany : {
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
U32String gameid = metadata [ i ] - > getVal ( String ( " gameid " ) ) ;
attrs . push_back ( _metadataParser . _gameInfo [ gameid ] . company_id ) ;
}
_list - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " " ) ) ;
metadataNames [ " " ] = " Unknown Publisher " ;
Common : : HashMap < String , MetadataCompany , Common : : IgnoreCase_Hash , Common : : IgnoreCase_EqualTo > : : iterator i = _metadataParser . _companyInfo . begin ( ) ;
for ( ; i ! = _metadataParser . _companyInfo . end ( ) ; + + i ) {
if ( i - > _value . alt_name . empty ( ) ) {
metadataNames [ i - > _key ] = i - > _value . name ;
} else {
metadataNames [ i - > _key ] = Common : : String : : format ( " %s (%s) " , i - > _value . name . c_str ( ) , i - > _value . alt_name . c_str ( ) ) ;
}
}
break ;
}
2021-08-12 20:27:20 +00:00
case kGroupBySeries : {
2021-08-08 13:44:59 +00:00
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
2021-08-12 20:03:18 +00:00
U32String gameid = metadata [ i ] - > getVal ( String ( " gameid " ) ) ;
2021-08-08 13:44:59 +00:00
attrs . push_back ( _metadataParser . _gameInfo [ gameid ] . series_id ) ;
}
_list - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " " ) ) ;
2021-08-12 20:03:18 +00:00
metadataNames [ " " ] = " No Series " ;
2021-08-12 20:27:20 +00:00
Common : : HashMap < String , MetadataSeries , Common : : IgnoreCase_Hash , Common : : IgnoreCase_EqualTo > : : iterator i = _metadataParser . _seriesInfo . begin ( ) ;
for ( ; i ! = _metadataParser . _seriesInfo . end ( ) ; + + i ) {
2021-08-12 20:03:18 +00:00
metadataNames [ i - > _key ] = i - > _value . name ;
}
2021-08-08 13:44:59 +00:00
break ;
2021-08-12 20:27:20 +00:00
}
case kGroupByLanguage : {
2021-07-25 15:50:05 +00:00
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
2021-08-05 16:05:01 +00:00
U32String language = metadata [ i ] - > contains ( String ( " language " ) ) ?
2021-08-12 20:03:18 +00:00
metadata [ i ] - > getVal ( String ( " language " ) ) : String ( " " ) ;
2021-08-05 16:05:01 +00:00
attrs . push_back ( language ) ;
2021-07-22 15:54:25 +00:00
}
_list - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " " ) ) ;
2021-08-12 20:03:18 +00:00
metadataNames [ " " ] = " Language not detected " ;
2021-08-12 20:27:20 +00:00
const Common : : LanguageDescription * l = Common : : g_languages ;
for ( ; l - > code ; + + l ) {
2021-08-12 20:03:18 +00:00
metadataNames [ l - > code ] = l - > description ;
}
2021-07-22 15:54:25 +00:00
break ;
2021-08-12 20:27:20 +00:00
}
case kGroupByPlatform : {
2021-07-25 15:50:05 +00:00
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
2021-08-05 16:05:01 +00:00
U32String platform = metadata [ i ] - > contains ( String ( " Platform " ) ) ?
2021-08-12 20:03:18 +00:00
metadata [ i ] - > getVal ( String ( " Platform " ) ) : String ( " " ) ;
2021-08-05 16:05:01 +00:00
attrs . push_back ( platform ) ;
2021-07-22 15:54:25 +00:00
}
_list - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " " ) ) ;
2021-08-12 20:03:18 +00:00
metadataNames [ " " ] = " Platform not detected " ;
2021-08-12 20:27:20 +00:00
const Common : : PlatformDescription * p = Common : : g_platforms ;
for ( ; p - > code ; + + p ) {
2021-08-12 20:03:18 +00:00
metadataNames [ p - > code ] = p - > description ;
}
2021-07-22 15:54:25 +00:00
break ;
2021-08-12 20:27:20 +00:00
}
2021-07-22 15:54:25 +00:00
case kGroupByNone : // Fall-through intentional
default :
2021-08-12 20:03:18 +00:00
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
attrs . push_back ( String ( " All " ) ) ;
}
2021-07-22 15:54:25 +00:00
_list - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " " ) ) ;
break ;
2021-07-22 12:42:02 +00:00
}
2021-08-13 09:49:07 +00:00
_list - > setMetadataNames ( metadataNames ) ;
_list - > setAttributeValues ( attrs ) ;
_list - > groupByAttribute ( ) ;
2021-07-22 12:42:02 +00:00
}
2021-07-12 14:18:19 +00:00
void LauncherSimple : : handleKeyDown ( Common : : KeyState state ) {
if ( state . keycode = = Common : : KEYCODE_TAB ) {
// Toggle between the game list and the quick search field.
if ( getFocusWidget ( ) = = _searchWidget ) {
setFocusWidget ( _list ) ;
} else if ( getFocusWidget ( ) = = _list ) {
setFocusWidget ( _searchWidget ) ;
}
}
Dialog : : handleKeyDown ( state ) ;
updateButtons ( ) ;
}
void LauncherSimple : : handleCommand ( CommandSender * sender , uint32 cmd , uint32 data ) {
switch ( cmd ) {
case kListItemActivatedCmd :
case kListItemDoubleClickedCmd :
LauncherDialog : : handleCommand ( sender , kStartCmd , 0 ) ;
break ;
case kListItemRemovalRequestCmd :
LauncherDialog : : handleCommand ( sender , kRemoveGameCmd , 0 ) ;
break ;
case kListSelectionChangedCmd :
updateButtons ( ) ;
break ;
case kSearchCmd :
// Update the active search filter.
_list - > setFilter ( _searchWidget - > getEditString ( ) ) ;
break ;
case kSearchClearCmd :
// Reset the active search filter, thus showing all games again
_searchWidget - > setEditString ( Common : : U32String ( ) ) ;
_list - > setFilter ( Common : : U32String ( ) ) ;
break ;
2021-08-14 22:18:48 +00:00
case kSetGroupMethodCmd : {
2021-07-22 15:54:25 +00:00
// Change the grouping criteria
2021-08-14 22:18:48 +00:00
GroupingMethod newGroupBy = ( GroupingMethod ) data ;
if ( _groupBy ! = newGroupBy ) {
_groupBy = newGroupBy ;
updateListing ( ) ;
2021-07-22 15:54:25 +00:00
}
break ;
2021-08-14 22:18:48 +00:00
}
2021-07-12 14:18:19 +00:00
default :
LauncherDialog : : handleCommand ( sender , cmd , data ) ;
}
}
void LauncherSimple : : updateButtons ( ) {
bool enable = ( _list - > getSelected ( ) > = 0 ) ;
if ( enable ! = _startButton - > isEnabled ( ) ) {
_startButton - > setEnabled ( enable ) ;
_startButton - > markAsDirty ( ) ;
}
if ( enable ! = _editButton - > isEnabled ( ) ) {
_editButton - > setEnabled ( enable ) ;
_editButton - > markAsDirty ( ) ;
}
if ( enable ! = _removeButton - > isEnabled ( ) ) {
_removeButton - > setEnabled ( enable ) ;
_removeButton - > markAsDirty ( ) ;
}
int item = _list - > getSelected ( ) ;
bool en = enable ;
if ( item > = 0 )
en = ! ( Common : : checkGameGUIOption ( GUIO_NOLAUNCHLOAD , ConfMan . get ( " guioptions " , _domains [ item ] ) ) ) ;
if ( en ! = _loadButton - > isEnabled ( ) ) {
_loadButton - > setEnabled ( en ) ;
_loadButton - > markAsDirty ( ) ;
}
}
# pragma mark -
# ifndef DISABLE_LAUNCHERDISPLAY_GRID
LauncherGrid : : LauncherGrid ( const U32String & title )
: LauncherDialog ( title ) ,
2021-08-14 16:11:21 +00:00
_grid ( nullptr ) {
2021-07-12 14:18:19 +00:00
build ( ) ;
}
2021-08-05 15:59:08 +00:00
void LauncherGrid : : groupEntries ( const Array < const Common : : ConfigManager : : Domain * > & metadata ) {
U32StringArray attrs ;
2021-08-08 13:44:59 +00:00
Common : : StringMap metadataNames ;
2021-08-05 15:59:08 +00:00
switch ( _groupBy ) {
2021-08-12 20:27:20 +00:00
case kGroupByFirstLetter : {
2021-08-05 15:59:08 +00:00
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
attrs . push_back ( metadata [ i ] - > getVal ( " description " ) . substr ( 0 , 1 ) ) ;
}
2021-08-05 16:05:01 +00:00
_grid - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " ... " ) ) ;
2021-08-05 15:59:08 +00:00
break ;
2021-08-12 20:27:20 +00:00
}
case kGroupByEngine : {
2021-08-05 15:59:08 +00:00
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
U32String engineid = metadata [ i ] - > contains ( String ( " engineid " ) ) ?
2021-08-12 19:32:51 +00:00
metadata [ i ] - > getVal ( String ( " engineid " ) ) : String ( " " ) ;
2021-08-05 15:59:08 +00:00
attrs . push_back ( engineid ) ;
}
2021-08-08 13:44:59 +00:00
_grid - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " " ) ) ;
metadataNames [ " " ] = " Unknown Engine " ;
2021-08-12 20:27:20 +00:00
Common : : HashMap < String , MetadataEngine , Common : : IgnoreCase_Hash , Common : : IgnoreCase_EqualTo > : : iterator i = _metadataParser . _engineInfo . begin ( ) ;
for ( ; i ! = _metadataParser . _engineInfo . end ( ) ; + + i ) {
2021-08-08 13:44:59 +00:00
if ( i - > _value . alt_name . empty ( ) ) {
metadataNames [ i - > _key ] = i - > _value . name ;
} else {
metadataNames [ i - > _key ] = Common : : String : : format ( " %s (%s) " , i - > _value . name . c_str ( ) , i - > _value . alt_name . c_str ( ) ) ;
}
}
break ;
2021-08-12 20:27:20 +00:00
}
case kGroupBySeries : {
2021-08-08 13:44:59 +00:00
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
U32String gameid = metadata [ i ] - > getVal ( String ( " gameid " ) ) ;
attrs . push_back ( _metadataParser . _gameInfo [ gameid ] . series_id ) ;
}
_grid - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " " ) ) ;
metadataNames [ " " ] = " No Series " ;
2021-08-12 20:27:20 +00:00
Common : : HashMap < String , MetadataSeries , Common : : IgnoreCase_Hash , Common : : IgnoreCase_EqualTo > : : iterator i = _metadataParser . _seriesInfo . begin ( ) ;
for ( ; i ! = _metadataParser . _seriesInfo . end ( ) ; + + i ) {
2021-08-08 13:44:59 +00:00
metadataNames [ i - > _key ] = i - > _value . name ;
}
2021-08-05 15:59:08 +00:00
break ;
2021-08-12 20:27:20 +00:00
}
2021-08-12 21:15:00 +00:00
case kGroupByCompany : {
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
U32String gameid = metadata [ i ] - > getVal ( String ( " gameid " ) ) ;
attrs . push_back ( _metadataParser . _gameInfo [ gameid ] . company_id ) ;
}
_grid - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " " ) ) ;
metadataNames [ " " ] = " Unknown Publisher " ;
Common : : HashMap < String , MetadataCompany , Common : : IgnoreCase_Hash , Common : : IgnoreCase_EqualTo > : : iterator i = _metadataParser . _companyInfo . begin ( ) ;
for ( ; i ! = _metadataParser . _companyInfo . end ( ) ; + + i ) {
if ( i - > _value . alt_name . empty ( ) ) {
metadataNames [ i - > _key ] = i - > _value . name ;
} else {
metadataNames [ i - > _key ] = Common : : String : : format ( " %s (%s) " , i - > _value . name . c_str ( ) , i - > _value . alt_name . c_str ( ) ) ;
}
}
break ;
}
2021-08-12 20:27:20 +00:00
case kGroupByLanguage : {
2021-08-05 15:59:08 +00:00
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
2021-08-05 16:05:01 +00:00
U32String language = metadata [ i ] - > contains ( String ( " language " ) ) ?
2021-08-12 19:32:51 +00:00
metadata [ i ] - > getVal ( String ( " language " ) ) : String ( " " ) ;
2021-08-05 16:05:01 +00:00
attrs . push_back ( language ) ;
2021-08-05 15:59:08 +00:00
}
2021-08-05 16:05:01 +00:00
_grid - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " " ) ) ;
2021-08-12 19:32:51 +00:00
metadataNames [ " " ] = " Language not detected " ;
2021-08-12 20:27:20 +00:00
const Common : : LanguageDescription * l = Common : : g_languages ;
for ( ; l - > code ; + + l ) {
2021-08-12 19:32:51 +00:00
metadataNames [ l - > code ] = l - > description ;
}
2021-08-05 15:59:08 +00:00
break ;
2021-08-12 20:27:20 +00:00
}
case kGroupByPlatform : {
2021-08-05 15:59:08 +00:00
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
2021-08-05 16:05:01 +00:00
U32String platform = metadata [ i ] - > contains ( String ( " Platform " ) ) ?
2021-08-12 19:32:51 +00:00
metadata [ i ] - > getVal ( String ( " Platform " ) ) : String ( " " ) ;
2021-08-05 16:05:01 +00:00
attrs . push_back ( platform ) ;
2021-08-05 15:59:08 +00:00
}
2021-08-05 16:05:01 +00:00
_grid - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " " ) ) ;
2021-08-12 19:32:51 +00:00
metadataNames [ " " ] = " Platform not detected " ;
2021-08-12 20:27:20 +00:00
const Common : : PlatformDescription * p = Common : : g_platforms ;
for ( ; p - > code ; + + p ) {
2021-08-12 19:32:51 +00:00
metadataNames [ p - > code ] = p - > description ;
}
2021-08-05 15:59:08 +00:00
break ;
2021-08-12 20:27:20 +00:00
}
2021-08-05 15:59:08 +00:00
case kGroupByNone : // Fall-through intentional
default :
for ( uint i = 0 ; i < metadata . size ( ) ; + + i ) {
attrs . push_back ( String ( " All " ) ) ;
}
2021-08-05 16:05:01 +00:00
_grid - > setGroupHeaderFormat ( U32String ( " " ) , U32String ( " " ) ) ;
2021-08-05 15:59:08 +00:00
break ;
}
2021-08-13 09:49:07 +00:00
_grid - > setMetadataNames ( metadataNames ) ;
_grid - > setAttributeValues ( attrs ) ;
_grid - > groupEntries ( ) ;
2021-08-05 15:59:08 +00:00
}
2021-07-12 14:18:19 +00:00
void LauncherGrid : : handleKeyDown ( Common : : KeyState state ) {
if ( state . keycode = = Common : : KEYCODE_TAB ) {
// Toggle between the game list and the quick search field.
if ( getFocusWidget ( ) = = _searchWidget ) {
setFocusWidget ( _grid ) ;
} else {
setFocusWidget ( _searchWidget ) ;
}
}
Dialog : : handleKeyDown ( state ) ;
updateButtons ( ) ;
}
void LauncherGrid : : handleCommand ( CommandSender * sender , uint32 cmd , uint32 data ) {
switch ( cmd ) {
case kPlayButtonCmd :
case kItemDoubleClickedCmd :
LauncherDialog : : handleCommand ( sender , kStartCmd , 0 ) ;
break ;
case kEditButtonCmd :
LauncherDialog : : handleCommand ( sender , kEditGameCmd , 0 ) ;
break ;
case kLoadButtonCmd :
LauncherDialog : : handleCommand ( sender , kLoadGameCmd , 0 ) ;
break ;
case kItemClicked :
updateButtons ( ) ;
break ;
2021-08-14 20:06:25 +00:00
case kSearchCmd :
// Update the active search filter.
_grid - > setFilter ( _searchWidget - > getEditString ( ) ) ;
break ;
case kSearchClearCmd :
// Reset the active search filter, thus showing all games again
_searchWidget - > setEditString ( Common : : U32String ( ) ) ;
_grid - > setFilter ( Common : : U32String ( ) ) ;
break ;
2021-08-14 22:18:48 +00:00
case kSetGroupMethodCmd : {
2021-08-05 15:59:08 +00:00
// Change the grouping criteria
2021-08-14 22:18:48 +00:00
GroupingMethod newGroupBy = ( GroupingMethod ) data ;
if ( _groupBy ! = newGroupBy ) {
_groupBy = newGroupBy ;
updateListing ( ) ;
2021-08-05 15:59:08 +00:00
}
break ;
2021-08-14 22:18:48 +00:00
}
2021-07-12 14:18:19 +00:00
default :
LauncherDialog : : handleCommand ( sender , cmd , data ) ;
}
}
void LauncherGrid : : updateListing ( ) {
2021-08-05 15:59:08 +00:00
Array < const Common : : ConfigManager : : Domain * > attrs ;
2021-07-12 14:18:19 +00:00
// Retrieve a list of all games defined in the config file
_domains . clear ( ) ;
const ConfigManager : : DomainMap & domains = ConfMan . getGameDomains ( ) ;
// Turn it into a list of pointers
Common : : Array < LauncherEntry > domainList ;
for ( ConfigManager : : DomainMap : : const_iterator iter = domains . begin ( ) ; iter ! = domains . end ( ) ; + + iter ) {
// Do not list temporary targets added when starting a game from the command line
if ( iter - > _value . contains ( " id_came_from_command_line " ) )
continue ;
String description ;
if ( ! iter - > _value . tryGetVal ( " description " , description ) ) {
QualifiedGameDescriptor g = EngineMan . findTarget ( iter - > _key ) ;
if ( ! g . description . empty ( ) )
description = g . description ;
}
if ( description . empty ( ) ) {
String gameid ;
if ( ! iter - > _value . tryGetVal ( " gameid " , gameid ) ) ;
gameid = iter - > _key ;
description = Common : : String : : format ( " Unknown (target %s, gameid %s) " , iter - > _key . c_str ( ) , gameid . c_str ( ) ) ;
}
// Strip platform language from the title.
size_t extraPos = description . findFirstOf ( " ( " ) ;
if ( extraPos ! = Common : : String : : npos )
description = Common : : String ( description . c_str ( ) , extraPos ) ;
if ( ! description . empty ( ) )
domainList . push_back ( LauncherEntry ( iter - > _key , description , & iter - > _value ) ) ;
}
// Now sort the list in dictionary order
Common : : sort ( domainList . begin ( ) , domainList . end ( ) , LauncherEntryComparator ( ) ) ;
Common : : Array < GridItemInfo > gridList ;
int k = 0 ;
for ( Common : : Array < LauncherEntry > : : const_iterator iter = domainList . begin ( ) ; iter ! = domainList . end ( ) ; + + iter ) {
Common : : String gameid = iter - > domain - > getVal ( " gameid " ) ;
Common : : String title = iter - > description ;
Common : : String engineid = " UNK " ;
Common : : String language = " XX " ;
Common : : String platform ;
iter - > domain - > tryGetVal ( " engineid " , engineid ) ;
2021-07-14 12:57:51 +00:00
iter - > domain - > tryGetVal ( " language " , language ) ;
2021-07-12 14:18:19 +00:00
iter - > domain - > tryGetVal ( " platform " , platform ) ;
2021-08-05 15:59:08 +00:00
attrs . push_back ( iter - > domain ) ;
2021-07-12 14:18:19 +00:00
gridList . push_back ( GridItemInfo ( k + + , engineid , gameid , title , Common : : parseLanguage ( language ) , Common : : parsePlatform ( platform ) ) ) ;
}
_grid - > setEntryList ( & gridList ) ;
2021-08-05 15:59:08 +00:00
groupEntries ( attrs ) ;
2021-07-12 14:18:19 +00:00
// And fill out our structures
for ( Common : : Array < LauncherEntry > : : const_iterator iter = domainList . begin ( ) ; iter ! = domainList . end ( ) ; + + iter ) {
_domains . push_back ( iter - > key ) ;
}
}
void LauncherGrid : : updateButtons ( ) {
bool enable = ( _grid - > getSelected ( ) > = 0 ) ;
if ( enable ! = _removeButton - > isEnabled ( ) ) {
_removeButton - > setEnabled ( enable ) ;
_removeButton - > markAsDirty ( ) ;
}
}
void LauncherGrid : : selectTarget ( const String & target ) { }
2021-07-14 13:47:19 +00:00
const int LauncherGrid : : getSelected ( ) { return _grid - > getSelected ( ) ; }
2021-07-12 14:18:19 +00:00
void LauncherGrid : : build ( ) {
2021-08-14 16:11:21 +00:00
LauncherDialog : : build ( ) ;
2021-07-12 14:18:19 +00:00
// Add list with game titles
_grid = new GridWidget ( this , " LauncherGrid.IconArea " ) ;
// Populate the list
updateListing ( ) ;
// Restore last selection
String last ( ConfMan . get ( " lastselectedgame " , ConfigManager : : kApplicationDomain ) ) ;
selectTarget ( last ) ;
// En-/disable the buttons depending on the list selection
updateButtons ( ) ;
}
# endif // !DISABLE_LAUNCHERDISPLAY_GRID
2003-11-10 23:40:48 +00:00
} // End of namespace GUI