mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-04-10 19:15:13 +00:00
Merge branch 'stable-3.2' of https://gitlab.com/es-de/emulationstation-de into feat/update
This commit is contained in:
commit
7efa875fa2
12
.gitignore
vendored
12
.gitignore
vendored
|
@ -40,6 +40,16 @@ es-de.worker.js
|
|||
es-core/src/InputOverlay.*
|
||||
es-core/src/utils/PlatformUtilAndroid.*
|
||||
|
||||
# iOS
|
||||
ios/
|
||||
Frameworks/
|
||||
CMakeScripts
|
||||
*.xcodeproj/
|
||||
es-de.xcarchive/
|
||||
es-app/src/UIKitMain.cpp
|
||||
es-core/src/InputOverlay.*
|
||||
es-core/src/utils/PlatformUtilIOS.*
|
||||
|
||||
# AppImage
|
||||
AppDir
|
||||
*.AppImage
|
||||
|
@ -110,7 +120,9 @@ CPackSourceConfig.cmake
|
|||
|
||||
# VSCode
|
||||
.vscode/
|
||||
.continueignore
|
||||
|
||||
# RetroDECK
|
||||
.flatpak-builder
|
||||
builddir
|
||||
esde-repo
|
||||
|
|
195
ANDROID-DEV.md
195
ANDROID-DEV.md
|
@ -64,14 +64,15 @@ The following emulators are configured for FileProvider access:
|
|||
* J2ME Loader
|
||||
* JL-Mod
|
||||
* Lynx.emu
|
||||
* MAME4droid 2024 (for most systems)
|
||||
* MAME4droid Current (for most systems)
|
||||
* MAME4droid
|
||||
* MD.emu (genesis, mastersystem, megadrive, megadrivejp)
|
||||
* MD.emu (genesis, mark3, mastersystem, megadrive, megadrivejp)
|
||||
* NES.emu
|
||||
* NGP.emu
|
||||
* Panda3DS
|
||||
* PCE.emu (pcengine, supergrafx and tg16 systems)
|
||||
* Ruffle
|
||||
* SkyEmu
|
||||
* Skyline
|
||||
* Swan.emu
|
||||
* SWF Player
|
||||
|
@ -232,6 +233,12 @@ If you prefer to apply the NetherSX2 patch yourself (i.e. build the APK) then yo
|
|||
|
||||
https://github.com/Trixarian/NetherSX2-patch
|
||||
|
||||
### Azahar
|
||||
|
||||
This emulator can be downloaded from their GitHub site.
|
||||
|
||||
https://github.com/azahar-emu/azahar/releases
|
||||
|
||||
### Cemu
|
||||
|
||||
This emulator can be downloaded from the following GitHub site. Note that this repository is not from the official Cemu project, we consider Cemu as experimental on Android for the time being.
|
||||
|
@ -290,12 +297,11 @@ https://play.google.com/store/apps/details?id=com.github.stenzek.duckstation
|
|||
|
||||
### EKA2L1
|
||||
|
||||
This emulator can be downloaded from their GitHub site.
|
||||
This emulator can be installed from the Play store or it can be downloaded from their GitHub site.
|
||||
|
||||
https://play.google.com/store/apps/details?id=com.github.eka2l1 \
|
||||
https://github.com/EKA2L1/EKA2L1/releases
|
||||
|
||||
There does not seem to be a way to launch individual EKA2L1 games from a frontend application on Android, instead ES-DE will simply launch the EKA2L1 user interface and you'll have to manually start your game from there.
|
||||
|
||||
### ePSXe
|
||||
|
||||
This emulator can be installed from the Play store as a paid app.
|
||||
|
@ -356,7 +362,7 @@ This PICO-8 game engine/emulator can be installed from the Play store.
|
|||
|
||||
https://play.google.com/store/apps/details?id=me.dt2dev.infinity
|
||||
|
||||
Note that this emulator has a strange behavior where it will return to the home app whenever you exit a game, so unless ES-DE is set as your home app you'll need to manually switch back to it after exiting Infinity.
|
||||
Note that since a recent emulator update it seems like individual games can no longer be launched from ES-DE, instead you'll just see the list of carts and you need to manually start the game from inside Infinity.
|
||||
|
||||
### IrataJaguar
|
||||
|
||||
|
@ -386,18 +392,18 @@ This emulator which is forked from Citra can be downloaded from their GitHub sit
|
|||
|
||||
https://github.com/Lime3DS/Lime3DS/releases
|
||||
|
||||
### MAME4droid 2024 and MAME4droid
|
||||
### MAME4droid Current and MAME4droid
|
||||
|
||||
These emulators can be installed from the Play store or from their GitHub sites. It's strongly recommended to go for the _MAME4droid 2024_ version as this is updated with a recent MAME release while the older _MAME4droid_ is using an ancient MAME release.
|
||||
These emulators can be installed from the Play store or from their GitHub sites. It's strongly recommended to go for the _MAME4droid Current_ version (previously named _MAME4droid 2024_) as this is updated with a recent MAME release while the older _MAME4droid_ is using an ancient MAME release.
|
||||
|
||||
Note that for MAME4droid 2024 there's an exception when it comes to setting up the ROM path. Instead of selecting each separate system directory (as is done on most other standalone emulators) you must select the root of the ROMs directory tree. To change the ROM path open _Settings_ in MAME4droid 2024, then select _General_ and then _Change ROMs path_. After restarting the emulator choose _External storage_ and then the ROMs directory which contains all your ES-DE system directories. If you instead choose a specific system directory like ROMs/arcade or ROMs/neogeo then only that specific system will work when launching games from ES-DE.
|
||||
Note that for MAME4droid Current there's an exception when it comes to setting up the ROM path. Instead of selecting each separate system directory (as is done on most other standalone emulators) you must select the root of the ROMs directory tree. To change the ROM path open _Settings_ in MAME4droid Current, then select _General_ and then _Change ROMs path_. After restarting the emulator choose _External storage_ and then the ROMs directory which contains all your ES-DE system directories. If you instead choose a specific system directory like ROMs/arcade or ROMs/neogeo then only that specific system will work when launching games from ES-DE.
|
||||
|
||||
https://play.google.com/store/apps/details?id=com.seleuco.mame4d2024 \
|
||||
https://play.google.com/store/apps/details?id=com.seleuco.mame4droid \
|
||||
https://github.com/seleuco/MAME4droid-2024/releases \
|
||||
https://github.com/seleuco/MAME4droid-0.139u1-/releases
|
||||
|
||||
Be aware that MAME4droid 2024 requires specific input configuration for some systems. For instance to navigate the mouse cursor when using touch input you'll need to got into the _Settings_ menu, then _Input_, then _Touch controller_ and change _Mode_ to _Analog Stick_.
|
||||
Be aware that MAME4droid Current requires specific input configuration for some systems. For instance to navigate the mouse cursor when using touch input you'll need to got into the _Settings_ menu, then _Input_, then _Touch controller_ and change _Mode_ to _Analog Stick_.
|
||||
|
||||
If using a physical controller for mouse input (via the thumbstick) then you will need to map the mouse buttons to physical controller buttons. You do this via the MAME input settings. Bring up the MAME menu by pressing both thumbsticks, or by pressing the _Start_ and _Coin_ buttons on the touch overlay. Go into _Input Settings_ then _Input Assignments (this system)_ where you can assign physical buttons to the mouse buttons.
|
||||
|
||||
|
@ -471,15 +477,17 @@ This emulator is in early development and there currently seems to be no way to
|
|||
|
||||
https://github.com/wheremyfoodat/Panda3DS/releases
|
||||
|
||||
### Pizza Boy GBA and Pizza Boy GBC
|
||||
### Pizza Boy emulators
|
||||
|
||||
The Pizza Boy GBA and Pizza Boy GBC emulators can be installed from the Play store. There are Basic (free) versions and Pro (paid) versions available.
|
||||
As of writing this, the Basic version of the GBA emulator does not seem to be able to launch games from ES-DE, but the Pro version is working fine. Both the Basic and Pro versions of the GBC emulator are working correctly.
|
||||
The Pizza Boy GBA/A, Pizza Boy GBC/C and Pizza Boy SC emulators can be installed from the Play store. There are Basic (free) versions and Pro (paid) versions available.
|
||||
At the time of writing the Basic version of the GBA/A emulator does not seem to be able to launch zipped games, but both the Basic and Pro versions of the GBC/C and SC emulators are working correctly.
|
||||
|
||||
https://play.google.com/store/apps/details?id=it.dbtecno.pizzaboygba \
|
||||
https://play.google.com/store/apps/details?id=it.dbtecno.pizzaboygbapro \
|
||||
https://play.google.com/store/apps/details?id=it.dbtecno.pizzaboy \
|
||||
https://play.google.com/store/apps/details?id=it.dbtecno.pizzaboypro
|
||||
https://play.google.com/store/apps/details?id=it.dbtecno.pizzaboypro \
|
||||
https://play.google.com/store/apps/details?id=it.dbtecno.pizzaboyscbasic \
|
||||
https://play.google.com/store/apps/details?id=it.dbtecno.pizzaboyscpro
|
||||
|
||||
### Play!
|
||||
|
||||
|
@ -520,11 +528,19 @@ https://play.google.com/store/apps/details?id=io.recompiled.redream
|
|||
|
||||
### ScummVM
|
||||
|
||||
ScummVM can be installed from the Play store. There are also daily builds available on their GitHub site. Such a build may be required to be able to launch games from ES-DE until the Play store version has been updated.
|
||||
ScummVM can be installed from the Play store. There are also daily builds available on their GitHub site.
|
||||
|
||||
https://play.google.com/store/apps/details?id=org.scummvm.scummvm\
|
||||
https://buildbot.scummvm.org/#/dailybuilds
|
||||
|
||||
### SkyEmu
|
||||
|
||||
Note that frontend support was added to SkyEmu in version 4 so you need that to be able to use it with ES-DE.
|
||||
|
||||
At the time of writing this version can only be downloaded from their GitHub automatic build system.
|
||||
|
||||
https://github.com/skylersaleh/SkyEmu/actions
|
||||
|
||||
### Skyline
|
||||
|
||||
This emulator is not in active development any longer, but the latest release can be found on archive.org.
|
||||
|
@ -585,6 +601,8 @@ This emulator can be installed from the Play store. Note that only the paid Pro
|
|||
|
||||
https://play.google.com/store/apps/details?id=org.devmiyax.yabasanshioro2.pro
|
||||
|
||||
**Note:** At the time of writing this emulator is broken on some devices and will simply display the error message _Cannot initialize SH2_ on game launch. The issue was apparently introduced in a recent update and is awaiting a fix from the developer.
|
||||
|
||||
## Device compatibility
|
||||
|
||||
This is clearly not a complete list of Android devices, but rather those we know have been tested with ES-DE and for which there is a known status.
|
||||
|
@ -630,8 +648,6 @@ This is clearly not a complete list of Android devices, but rather those we know
|
|||
| Huawei | Mate 20 Pro | 10 | Yes | None | |
|
||||
| Huawei | MatePad 11 (2021) | 13 | Yes | None | |
|
||||
| Infinix | Zero 30 5G | 13 | Yes | None | |
|
||||
| Kinhank | G1 | 11 | No | Unable to install | Possibly 32-bit operating system? |
|
||||
| Kinhank | Super Console X5 Pro | 12 (TV) | No | None | Custom 64-bit Android TV OS |
|
||||
| KTPocket | KT-R1 | GammaOS 12 | Yes | None | |
|
||||
| Lenovo | Legion Y700 (2022) | 12 | Yes | None | |
|
||||
| Lenovo | Legion Y700 (2023) | 13 | Yes | None | |
|
||||
|
@ -724,55 +740,55 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| System name | Full name | Default emulator | Alternative emulators | Needs BIOS | Recommended game setup |
|
||||
| :-------------------- | :--------------------------------------------- | :-------------------------------- | :-------------------------------- | :----------- | :----------------------------------- |
|
||||
| 3do | 3DO Interactive Multiplayer | Opera | Real3DOPlayer **(Standalone)** | Yes | |
|
||||
| adam | Coleco Adam | MAME4droid 2024 [Diskette] **(Standalone)** | MAME4droid 2024 [Tape] **(Standalone)**,<br>MAME4droid 2024 [Cartridge] **(Standalone)**,<br>MAME4droid 2024 [Software list] **(Standalone)**,<br>ColEm **(Standalone)** | Yes for MAME4droid 2024 | |
|
||||
| adam | Coleco Adam | MAME4droid Current [Diskette] **(Standalone)** | MAME4droid Current [Tape] **(Standalone)**,<br>MAME4droid Current [Cartridge] **(Standalone)**,<br>MAME4droid Current [Software list] **(Standalone)**,<br>ColEm **(Standalone)** | Yes for MAME4droid Current | |
|
||||
| ags | Adventure Game Studio Game Engine | _Placeholder_ | | | |
|
||||
| amiga | Commodore Amiga | PUAE | PUAE 2021 | Yes | See the specific _Commodore Amiga and CDTV_ section in the user guide |
|
||||
| amiga1200 | Commodore Amiga 1200 | PUAE | PUAE 2021 | Yes | See the specific _Commodore Amiga and CDTV_ section in the user guide |
|
||||
| amiga600 | Commodore Amiga 600 | PUAE | PUAE 2021 | Yes | See the specific _Commodore Amiga and CDTV_ section in the user guide |
|
||||
| amigacd32 | Commodore Amiga CD32 | PUAE | PUAE 2021 | Yes | See the specific _Commodore Amiga and CDTV_ section in the user guide |
|
||||
| amstradcpc | Amstrad CPC | Caprice32 | CrocoDS,<br>MAME4droid 2024 **(Standalone)** | Yes for MAME4droid 2024 | Single archive or disk file |
|
||||
| amstradcpc | Amstrad CPC | Caprice32 | CrocoDS,<br>MAME4droid Current **(Standalone)** | Yes for MAME4droid Current | Single archive or disk file |
|
||||
| android | Google Android | _Placeholder_ | | | |
|
||||
| androidapps | Android Apps | _Native apps_ | | No | |
|
||||
| androidgames | Android Games | _Native apps_ | | No | |
|
||||
| apple2 | Apple II | MAME4droid 2024 **(Standalone)** | | Yes | See the specific _Apple II_ section in the user guide |
|
||||
| apple2gs | Apple IIGS | MAME4droid 2024 **(Standalone)** | | Yes | See the specific _Apple IIGS_ section in the user guide |
|
||||
| arcade | Arcade | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME4droid 2024 **(Standalone)**,<br>MAME4droid **(Standalone)**,<br>NEO.emu **(Standalone)**,<br>FinalBurn Neo,<br>FB Alpha 2012,<br>Geolith,<br>Flycast,<br>Flycast **(Standalone)** | Depends | See the specific _Arcade and Neo Geo_ section in the user guide |
|
||||
| arcadia | Emerson Arcadia 2001 | DroidArcadia **(Standalone**) | MAME4droid 2024 **(Standalone)** | No | Single archive or ROM file |
|
||||
| archimedes | Acorn Archimedes | MAME4droid 2024 [Model A440/1] **(Standalone)** | MAME4droid 2024 [Model A3000] **(Standalone)**,<br>MAME4droid 2024 [Model A310] **(Standalone)**,<br>MAME4droid 2024 [Model A540] **(Standalone)** | Yes | |
|
||||
| apple2 | Apple II | MAME4droid Current **(Standalone)** | | Yes | See the specific _Apple II_ section in the user guide |
|
||||
| apple2gs | Apple IIGS | MAME4droid Current **(Standalone)** | | Yes | See the specific _Apple IIGS_ section in the user guide |
|
||||
| arcade | Arcade | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME4droid Current **(Standalone)**,<br>MAME4droid **(Standalone)**,<br>NEO.emu **(Standalone)**,<br>FinalBurn Neo,<br>FB Alpha 2012,<br>Geolith,<br>Flycast,<br>Flycast **(Standalone)** | Depends | See the specific _Arcade and Neo Geo_ section in the user guide |
|
||||
| arcadia | Emerson Arcadia 2001 | DroidArcadia **(Standalone**) | MAME4droid Current **(Standalone)** | No | Single archive or ROM file |
|
||||
| archimedes | Acorn Archimedes | MAME4droid Current [Model A440/1] **(Standalone)** | MAME4droid Current [Model A3000] **(Standalone)**,<br>MAME4droid Current [Model A310] **(Standalone)**,<br>MAME4droid Current [Model A540] **(Standalone)** | Yes | |
|
||||
| arduboy | Arduboy Miniature Game System | Arduous | Ardens | No | Single archive or .hex file |
|
||||
| astrocde | Bally Astrocade | MAME4droid 2024 **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| astrocde | Bally Astrocade | MAME4droid Current **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| atari2600 | Atari 2600 | Stella | Stella 2014,<br>Stella 2023,<br>2600.emu **(Standalone)** | No | Single archive or ROM file |
|
||||
| atari5200 | Atari 5200 | a5200 | Atari800 | Yes | Single archive or ROM file |
|
||||
| atari7800 | Atari 7800 ProSystem | ProSystem | MAME4droid 2024 **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| atari7800 | Atari 7800 ProSystem | ProSystem | MAME4droid Current **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| atari800 | Atari 800 | Atari800 | | Yes | |
|
||||
| atarijaguar | Atari Jaguar | Virtual Jaguar | IrataJaguar **(Standalone)**,<br>MAME4droid 2024 **(Standalone)** | Yes for MAME4droid 2024 | Single archive or ROM file |
|
||||
| atarijaguar | Atari Jaguar | Virtual Jaguar | IrataJaguar **(Standalone)**,<br>MAME4droid Current **(Standalone)** | Yes for MAME4droid Current | Single archive or ROM file |
|
||||
| atarijaguarcd | Atari Jaguar CD | _Placeholder_ | | | |
|
||||
| atarilynx | Atari Lynx | Handy | Beetle Lynx,<br>Lynx.emu **(Standalone)** | No | Single archive or ROM file |
|
||||
| atarilynx | Atari Lynx | Handy | Beetle Lynx,<br>Holani,<br>Lynx.emu **(Standalone)** | No | Single archive or ROM file |
|
||||
| atarist | Atari ST [also STE and Falcon] | Hatari | | Yes | Single archive or image file for single-diskette games, .m3u playlist for multi-diskette games |
|
||||
| atarixe | Atari XE | Atari800 | | Yes | |
|
||||
| atomiswave | Sammy Corporation Atomiswave | Flycast | Flycast **(Standalone)** | Depends | Single archive file |
|
||||
| bbcmicro | Acorn Computers BBC Micro | MAME4droid 2024 **(Standalone)** | | Yes | Single archive or diskette image file |
|
||||
| bbcmicro | Acorn Computers BBC Micro | MAME4droid Current **(Standalone)** | b2 | Yes | Single archive or diskette image file |
|
||||
| c64 | Commodore 64 | VICE x64sc Accurate | VICE x64 Fast,<br>VICE x64 SuperCPU,<br>VICE x128,<br>C64.emu **(Standalone)** | No | Single archive or image file for tape, cartridge or single-diskette games, .m3u playlist for multi-diskette games |
|
||||
| cdimono1 | Philips CD-i | SAME CDi | MAME4droid 2024 **(Standalone)** | Yes | Single .bin/.cue pair |
|
||||
| cdimono1 | Philips CD-i | SAME CDi | MAME4droid Current **(Standalone)** | Yes | Single .bin/.cue pair |
|
||||
| cdtv | Commodore CDTV | PUAE | PUAE 2021 | Yes | |
|
||||
| chailove | ChaiLove Game Engine | ChaiLove | | | |
|
||||
| channelf | Fairchild Channel F | FreeChaF | MAME4droid 2024 **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| coco | Tandy Color Computer | MAME4droid 2024 [Cartridge] **(Standalone)** | MAME4droid 2024 [Tape] **(Standalone)** | Yes | See the specific _Tandy Color Computer_ section in the user guide |
|
||||
| channelf | Fairchild Channel F | FreeChaF | MAME4droid Current **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| coco | Tandy Color Computer | MAME4droid Current [Cartridge] **(Standalone)** | MAME4droid Current [Tape] **(Standalone)** | Yes | See the specific _Tandy Color Computer_ section in the user guide |
|
||||
| colecovision | Coleco ColecoVision | blueMSX | Gearcoleco,<br>MSX.emu **(Standalone)**,<br>ColEm **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| consolearcade | Console Arcade Systems | MAME - Current | MAME4droid 2024 **(Standalone)**,<br>Flycast,<br>Flycast **(Standalone)**,<br>Play! **(Standalone)** | Depends | See the specific _Console Arcade Systems_ section in the user guide |
|
||||
| cps | Capcom Play System | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME4droid 2024 **(Standalone)**,<br>MAME4droid **(Standalone)**,<br>FinalBurn Neo,<br>FB Alpha 2012,<br>FB Alpha 2012 CPS-1,<br>FB Alpha 2012 CPS-2,<br>FB Alpha 2012 CPS-3 | Depends | |
|
||||
| cps1 | Capcom Play System I | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME4droid 2024 **(Standalone)**,<br>MAME4droid **(Standalone)**,<br>FinalBurn Neo,<br>FB Alpha 2012,<br>FB Alpha 2012 CPS-1 | Depends | |
|
||||
| cps2 | Capcom Play System II | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME4droid 2024 **(Standalone)**,<br>MAME4droid **(Standalone)**,<br>FB Alpha 2012,<br>FB Alpha 2012 CPS-2 | Depends | |
|
||||
| cps3 | Capcom Play System III | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME4droid 2024 **(Standalone)**,<br>MAME4droid **(Standalone)**,<br>FB Alpha 2012,<br>FB Alpha 2012 CPS-3 | Depends | |
|
||||
| crvision | VTech CreatiVision | MAME4droid 2024 **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| daphne | Daphne Arcade LaserDisc Emulator | MAME4droid 2024 **(Standalone)** | DirkSimple | Depends | See the specific _LaserDisc Games_ section in the user guide |
|
||||
| consolearcade | Console Arcade Systems | MAME - Current | MAME4droid Current **(Standalone)**,<br>Flycast,<br>Flycast **(Standalone)**,<br>Play! **(Standalone)** | Depends | See the specific _Console Arcade Systems_ section in the user guide |
|
||||
| cps | Capcom Play System | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME4droid Current **(Standalone)**,<br>MAME4droid **(Standalone)**,<br>FinalBurn Neo,<br>FB Alpha 2012,<br>FB Alpha 2012 CPS-1,<br>FB Alpha 2012 CPS-2,<br>FB Alpha 2012 CPS-3 | Depends | |
|
||||
| cps1 | Capcom Play System I | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME4droid Current **(Standalone)**,<br>MAME4droid **(Standalone)**,<br>FinalBurn Neo,<br>FB Alpha 2012,<br>FB Alpha 2012 CPS-1 | Depends | |
|
||||
| cps2 | Capcom Play System II | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME4droid Current **(Standalone)**,<br>MAME4droid **(Standalone)**,<br>FB Alpha 2012,<br>FB Alpha 2012 CPS-2 | Depends | |
|
||||
| cps3 | Capcom Play System III | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME4droid Current **(Standalone)**,<br>MAME4droid **(Standalone)**,<br>FB Alpha 2012,<br>FB Alpha 2012 CPS-3 | Depends | |
|
||||
| crvision | VTech CreatiVision | MAME4droid Current **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| daphne | Daphne Arcade LaserDisc Emulator | MAME4droid Current **(Standalone)** | DirkSimple | Depends | See the specific _LaserDisc Games_ section in the user guide |
|
||||
| desktop | Desktop Applications | _Placeholder_ | | | |
|
||||
| doom | Doom | PrBoom | | No | |
|
||||
| dos | DOS (PC) | DOSBox-Pure | DOSBox-Core,<br>DOSBox-SVN,<br>VirtualXT | No | See the specific _DOS / PC_ section in the user guide |
|
||||
| dragon32 | Dragon Data Dragon 32 | MAME4droid 2024 Dragon 32 [Tape] **(Standalone)** | MAME4droid 2024 Dragon 32 [Cartridge] **(Standalone)**,<br>MAME4droid 2024 Dragon 64 [Tape] **(Standalone)**,<br>MAME4droid 2024 Dragon 64 [Cartridge] **(Standalone)** | Yes | See the specific _Dragon 32 and Tano Dragon_ section in the user guide |
|
||||
| dragon32 | Dragon Data Dragon 32 | MAME4droid Current Dragon 32 [Tape] **(Standalone)** | MAME4droid Current Dragon 32 [Cartridge] **(Standalone)**,<br>MAME4droid Current Dragon 64 [Tape] **(Standalone)**,<br>MAME4droid Current Dragon 64 [Cartridge] **(Standalone)** | Yes | See the specific _Dragon 32 and Tano Dragon_ section in the user guide |
|
||||
| dreamcast | Sega Dreamcast | Flycast | Flycast **(Standalone)**,<br>Redream **(Standalone)** | No | In separate folder interpreted as a file, with .m3u playlist if multi-disc game |
|
||||
| easyrpg | EasyRPG Game Engine | EasyRPG | | No | |
|
||||
| electron | Acorn Electron | MAME4droid 2024 [Tape] **(Standalone)** | MAME4droid 2024 [Diskette DFS] **(Standalone)**,<br>MAME4droid 2024 [Diskette ADFS] **(Standalone)** | Yes | Single archive, or single tape or diskette image file |
|
||||
| electron | Acorn Electron | MAME4droid Current [Tape] **(Standalone)** | MAME4droid Current [Diskette DFS] **(Standalone)**,<br>MAME4droid Current [Diskette ADFS] **(Standalone)** | Yes | Single archive, or single tape or diskette image file |
|
||||
| emulators | Emulators | _Native apps_ | | No | |
|
||||
| epic | Epic Games Store | _Placeholder_ | | | |
|
||||
| famicom | Nintendo Family Computer | Mesen | Nestopia UE,<br>FCEUmm,<br>QuickNES,<br>NES.emu **(Standalone)**,<br>iNES **(Standalone)**,<br>Nesoid **(Standalone)** | No | Single archive or ROM file |
|
||||
|
@ -780,39 +796,40 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| fbneo | FinalBurn Neo | FinalBurn Neo | | Yes | |
|
||||
| fds | Nintendo Famicom Disk System | Mesen | Nestopia UE,<br>FCEUmm,<br>NES.emu **(Standalone)**,<br>iNES **(Standalone)**,<br>Nesoid **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| flash | Adobe Flash | Ruffle **(Standalone)** | SWF Player **(Standalone)** | No | Single .swf file |
|
||||
| fm7 | Fujitsu FM-7 | MAME4droid 2024 [FM-7 Diskette] **(Standalone)** | MAME4droid 2024 [FM-7 Tape] **(Standalone)**,<br>MAME4droid 2024 [FM-7 Software list] **(Standalone)**,<br>MAME4droid 2024 [FM77AV Diskette] **(Standalone)**,<br>MAME4droid 2024 [FM77AV Tape] **(Standalone)**,<br>MAME4droid 2024 [FM77AV Software list] **(Standalone)** | Yes | For tape files you need to manually start the cassette player from the MAME menu after the "load" command, as well as entering the "run" command after loading is complete |
|
||||
| fmtowns | Fujitsu FM Towns | MAME4droid 2024 **(Standalone)** | | Yes | See the specific _Fujitsu FM Towns_ section in the user guide |
|
||||
| fm7 | Fujitsu FM-7 | MAME4droid Current [FM-7 Diskette] **(Standalone)** | MAME4droid Current [FM-7 Tape] **(Standalone)**,<br>MAME4droid Current [FM-7 Software list] **(Standalone)**,<br>MAME4droid Current [FM77AV Diskette] **(Standalone)**,<br>MAME4droid Current [FM77AV Tape] **(Standalone)**,<br>MAME4droid Current [FM77AV Software list] **(Standalone)** | Yes | For tape files you need to manually start the cassette player from the MAME menu after the "load" command, as well as entering the "run" command after loading is complete |
|
||||
| fmtowns | Fujitsu FM Towns | MAME4droid Current **(Standalone)** | | Yes | See the specific _Fujitsu FM Towns_ section in the user guide |
|
||||
| fpinball | Future Pinball | _Placeholder_ | | | |
|
||||
| gamate | Bit Corporation Gamate | MAME4droid 2024 **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| gameandwatch | Nintendo Game and Watch | Multi (MESS) | MAME4droid 2024 Local Artwork **(Standalone)**,<br>MAME4droid 2024 **(Standalone)**,<br>Handheld Electronic (GW) | No | See the specific _LCD handheld games_ section in the user guide |
|
||||
| gamecom | Tiger Electronics Game.com | MAME4droid 2024 **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| gamegear | Sega Game Gear | Genesis Plus GX | Genesis Plus GX Wide,<br>Gearsystem,<br>SMS Plus GX,<br>PicoDrive,<br>MasterGear **(Standalone)** | No | Single archive or ROM file |
|
||||
| gb | Nintendo Game Boy | Gambatte | SameBoy,<br>Gearboy,<br>TGB Dual,<br>DoubleCherryGB,<br>Mesen-S,<br>bsnes,<br>mGBA,<br>VBA-M,<br>GBC.emu **(Standalone)**,<br>My OldBoy! **(Standalone**),<br>Pizza Boy GBC **(Standalone)** | No | Single archive or ROM file |
|
||||
| gba | Nintendo Game Boy Advance | mGBA | VBA-M,<br>VBA Next,<br>gpSP,<br>GBA.emu **(Standalone)**,<br>My Boy! **(Standalone)**,<br>NooDS **(Standalone)**,<br>Pizza Boy GBA **(Standalone)** | No | Single archive or ROM file |
|
||||
| gbc | Nintendo Game Boy Color | Gambatte | SameBoy,<br>Gearboy,<br>TGB Dual,<br>DoubleCherryGB,<br>Mesen-S,<br>bsnes,<br>mGBA,<br>VBA-M,<br>GBC.emu **(Standalone)**,<br>My OldBoy! **(Standalone**),<br>Pizza Boy GBC **(Standalone)** | No | Single archive or ROM file |
|
||||
| gamate | Bit Corporation Gamate | MAME4droid Current **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| gameandwatch | Nintendo Game and Watch | Multi (MESS) | MAME4droid Current Local Artwork **(Standalone)**,<br>MAME4droid Current **(Standalone)**,<br>Handheld Electronic (GW) | No | See the specific _LCD handheld games_ section in the user guide |
|
||||
| gamecom | Tiger Electronics Game.com | MAME4droid Current **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| gamegear | Sega Game Gear | Genesis Plus GX | Genesis Plus GX Wide,<br>Gearsystem,<br>SMS Plus GX,<br>PicoDrive,<br>Pizza Boy SC **(Standalone)**,<br>MasterGear **(Standalone)** | No | Single archive or ROM file |
|
||||
| gb | Nintendo Game Boy | Gambatte | SameBoy,<br>Gearboy,<br>TGB Dual,<br>DoubleCherryGB,<br>Mesen-S,<br>bsnes,<br>mGBA,<br>VBA-M,<br>GBC.emu **(Standalone)**,<br>SkyEmu **(Standalone)**,<br>My OldBoy! **(Standalone**),<br>Pizza Boy GBC **(Standalone)** | No | Single archive or ROM file |
|
||||
| gba | Nintendo Game Boy Advance | mGBA | VBA-M,<br>VBA Next,<br>gpSP,<br>NooDS,<br>NooDS **(Standalone)**,<br>GBA.emu **(Standalone)**,<br>SkyEmu **(Standalone)**,<br>My Boy! **(Standalone)**,<br>Pizza Boy GBA **(Standalone)** | No | Single archive or ROM file |
|
||||
| gbc | Nintendo Game Boy Color | Gambatte | SameBoy,<br>Gearboy,<br>TGB Dual,<br>DoubleCherryGB,<br>Mesen-S,<br>bsnes,<br>mGBA,<br>VBA-M,<br>GBC.emu **(Standalone)**,<br>SkyEmu **(Standalone)**,<br>My OldBoy! **(Standalone**),<br>Pizza Boy GBC **(Standalone)** | No | Single archive or ROM file |
|
||||
| gc | Nintendo GameCube | Dolphin | Dolphin **(Standalone)**,<br>Dolphin MMJR **(Standalone)**,<br>Dolphin MMJR2 **(Standalone)** | No | Disc image file for single-disc games, .m3u playlist for multi-disc games |
|
||||
| genesis | Sega Genesis | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>MD.emu **(Standalone)** | No | Single archive or ROM file |
|
||||
| gmaster | Hartung Game Master | MAME4droid 2024 **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| gx4000 | Amstrad GX4000 | Caprice32 | CrocoDS,<br>MAME4droid 2024 **(Standalone)** | No | Single archive or ROM file |
|
||||
| intellivision | Mattel Electronics Intellivision | FreeIntv | MAME4droid 2024 **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| genesis | Sega Genesis | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>MD.emu **(Standalone)**,<br>Pizza Boy SC **(Standalone)** | No | Single archive or ROM file |
|
||||
| gmaster | Hartung Game Master | MAME4droid Current **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| gx4000 | Amstrad GX4000 | Caprice32 | CrocoDS,<br>MAME4droid Current **(Standalone)** | No | Single archive or ROM file |
|
||||
| intellivision | Mattel Electronics Intellivision | FreeIntv | MAME4droid Current **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| j2me | Java 2 Micro Edition (J2ME) | J2ME Loader **(Standalone)** | JL-Mod **(Standalone)**,<br>SquirrelJME | No | Single .jar file |
|
||||
| kodi | Kodi Home Theatre Software | _Placeholder_ | | | |
|
||||
| laserdisc | LaserDisc Games | MAME4droid 2024 **(Standalone)** | DirkSimple | Depends | See the specific _LaserDisc Games_ section in the user guide |
|
||||
| lcdgames | LCD Handheld Games | Multi (MESS) | MAME4droid 2024 Local Artwork **(Standalone)**,<br>MAME4droid 2024 **(Standalone)**,<br>Handheld Electronic (GW) | No | See the specific _LCD handheld games_ section in the user guide |
|
||||
| laserdisc | LaserDisc Games | MAME4droid Current **(Standalone)** | DirkSimple | Depends | See the specific _LaserDisc Games_ section in the user guide |
|
||||
| lcdgames | LCD Handheld Games | Multi (MESS) | MAME4droid Current Local Artwork **(Standalone)**,<br>MAME4droid Current **(Standalone)**,<br>Handheld Electronic (GW) | No | See the specific _LCD handheld games_ section in the user guide |
|
||||
| lowresnx | LowRes NX Fantasy Console | LowRes NX | | No | Single ROM file |
|
||||
| lutris | Lutris Open Gaming Platform | _Placeholder_ | | | |
|
||||
| lutro | Lutro Game Engine | Lutro | | | |
|
||||
| macintosh | Apple Macintosh | MAME4droid 2024 Mac SE Bootable **(Standalone)** | MAME4droid 2024 Mac SE Boot Disk **(Standalone)**,<br>MAME4droid 2024 Mac Plus Bootable **(Standalone)**,<br>MAME4droid 2024 Mac Plus Boot Disk **(Standalone)** | Yes | See the specific _Apple Macintosh_ section in the user guide |
|
||||
| mame | Multiple Arcade Machine Emulator | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME4droid 2024 **(Standalone)**,<br>MAME4droid **(Standalone)**,<br>NEO.emu **(Standalone)**,<br>FinalBurn Neo,<br>FB Alpha 2012,<br>Geolith,<br>Flycast,<br>Flycast **(Standalone)** | Depends | See the specific _Arcade and Neo Geo_ section in the user guide |
|
||||
| macintosh | Apple Macintosh | MAME4droid Current Mac SE Bootable **(Standalone)** | MAME4droid Current Mac SE Boot Disk **(Standalone)**,<br>MAME4droid Current Mac Plus Bootable **(Standalone)**,<br>MAME4droid Current Mac Plus Boot Disk **(Standalone)** | Yes | See the specific _Apple Macintosh_ section in the user guide |
|
||||
| mame | Multiple Arcade Machine Emulator | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME4droid Current **(Standalone)**,<br>MAME4droid **(Standalone)**,<br>NEO.emu **(Standalone)**,<br>FinalBurn Neo,<br>FB Alpha 2012,<br>Geolith,<br>Flycast,<br>Flycast **(Standalone)** | Depends | See the specific _Arcade and Neo Geo_ section in the user guide |
|
||||
| mame-advmame | AdvanceMAME | _Placeholder_ | | | |
|
||||
| mastersystem | Sega Master System | Genesis Plus GX | Genesis Plus GX Wide,<br>SMS Plus GX,<br>Gearsystem,<br>PicoDrive,<br>MD.emu **(Standalone)**,<br>MasterGear **(Standalone)** | No | Single archive or ROM file |
|
||||
| mark3 | Sega Mark III | Genesis Plus GX | Genesis Plus GX Wide,<br>SMS Plus GX,<br>Gearsystem,<br>PicoDrive,<br>MD.emu **(Standalone)**,<br>Pizza Boy SC **(Standalone)**,<br>MasterGear **(Standalone)** | No | Single archive or ROM file |
|
||||
| mastersystem | Sega Master System | Genesis Plus GX | Genesis Plus GX Wide,<br>SMS Plus GX,<br>Gearsystem,<br>PicoDrive,<br>MD.emu **(Standalone)**,<br>Pizza Boy SC **(Standalone)**,<br>MasterGear **(Standalone)** | No | Single archive or ROM file |
|
||||
| megacd | Sega Mega-CD | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>MD.emu **(Standalone)** | Yes | |
|
||||
| megacdjp | Sega Mega-CD [Japan] | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>MD.emu **(Standalone)** | Yes | |
|
||||
| megadrive | Sega Mega Drive | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>MD.emu **(Standalone)** | No | Single archive or ROM file |
|
||||
| megadrivejp | Sega Mega Drive [Japan] | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>MD.emu **(Standalone)** | No | Single archive or ROM file |
|
||||
| megaduck | Creatronic Mega Duck | SameDuck | MAME4droid 2024 **(Standalone)** | No | Single archive or ROM file |
|
||||
| megadrive | Sega Mega Drive | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>MD.emu **(Standalone)**,<br>Pizza Boy SC **(Standalone)** | No | Single archive or ROM file |
|
||||
| megadrivejp | Sega Mega Drive [Japan] | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>MD.emu **(Standalone)**,<br>Pizza Boy SC **(Standalone)** | No | Single archive or ROM file |
|
||||
| megaduck | Creatronic Mega Duck | SameDuck | MAME4droid Current **(Standalone)** | No | Single archive or ROM file |
|
||||
| mess | Multi Emulator Super System | Multi (MESS) | | Depends | |
|
||||
| model2 | Sega Model 2 | MAME - Current | MAME4droid 2024 **(Standalone)** | Yes | See the specific _Arcade and Neo Geo_ section in the user guide |
|
||||
| model2 | Sega Model 2 | MAME - Current | MAME4droid Current **(Standalone)** | Yes | See the specific _Arcade and Neo Geo_ section in the user guide |
|
||||
| model3 | Sega Model 3 | _Placeholder_ | | | |
|
||||
| moto | Thomson MO/TO Series | Theodore | | | |
|
||||
| msx | MSX | blueMSX | fMSX,<br>fMSX **(Standalone)**,<br>MSX.emu **(Standalone)** | Yes except for fMSX standalone | |
|
||||
|
@ -824,20 +841,20 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| naomi | Sega NAOMI | Flycast | Flycast **(Standalone)** | Yes | Single archive file + .chd file in subdirectory if GD-ROM game |
|
||||
| naomi2 | Sega NAOMI 2 | Flycast | Flycast **(Standalone)** | Yes | Single archive file + .chd file in subdirectory if GD-ROM game |
|
||||
| naomigd | Sega NAOMI GD-ROM | Flycast | Flycast **(Standalone)** | Yes | Single archive file + .chd file in subdirectory if GD-ROM game |
|
||||
| n3ds | Nintendo 3DS | Citra | Citra **(Standalone)**,<br>Citra Canary **(Standalone)**,<br>Citra MMJ **(Standalone)**,<br>Mandarine **(Standalone)**,<br>Lime3DS **(Standalone)**,<br>Panda3DS **(Standalone)** | No | Single ROM file |
|
||||
| n3ds | Nintendo 3DS | Citra | Citra **(Standalone)**,<br>Citra Canary **(Standalone)**,<br>Citra MMJ **(Standalone)**,<br>Azahar **(Standalone)**,<br>Mandarine **(Standalone)**,<br>Lime3DS **(Standalone)**,<br>Panda3DS **(Standalone)** | No | Single ROM file |
|
||||
| n64 | Nintendo 64 | Mupen64Plus-Next | M64Plus FZ **(Standalone)**,<br>Mupen64Plus AE **(Standalone)**,<br>ParaLLEl N64 | No | Single archive or ROM file |
|
||||
| n64dd | Nintendo 64DD | Mupen64Plus-Next | M64Plus FZ **(Standalone)**,<br>Mupen64Plus AE **(Standalone)**,<br>ParaLLEl N64 | Yes | |
|
||||
| nds | Nintendo DS | melonDS DS | melonDS,<br>melonDS **(Standalone)**,<br>melonDS Nightly **(Standalone)**,<br>DeSmuME,<br>DeSmuME 2015,<br>DraStic **(Standalone)**,<br>NooDS **(Standalone)** | No | Single archive or ROM file |
|
||||
| neogeo | SNK Neo Geo | FinalBurn Neo | Geolith,<br>NEO.emu **(Standalone)**,<br>MAME4droid 2024 **(Standalone)**,<br>MAME4droid **(Standalone)** | Yes | See the specific _Arcade and Neo Geo_ section in the user guide |
|
||||
| neogeocd | SNK Neo Geo CD | NeoCD | MAME4droid 2024 **(Standalone)** | Yes | .chd (NeoCD and MAME4droid 2024 only) or .cue file |
|
||||
| neogeocdjp | SNK Neo Geo CD [Japan] | NeoCD | MAME4droid 2024 **(Standalone)** | Yes | .chd (NeoCD and MAME4droid 2024 only) or .cue file |
|
||||
| nds | Nintendo DS | melonDS DS | melonDS,<br>melonDS **(Standalone)**,<br>melonDS Nightly **(Standalone)**,<br>DeSmuME,<br>DeSmuME 2015,<br>NooDS,<br>NooDS **(Standalone)**,<br>DraStic **(Standalone)**,<br>SkyEmu **(Standalone)** | No | Single archive or ROM file |
|
||||
| neogeo | SNK Neo Geo | FinalBurn Neo | Geolith,<br>NEO.emu **(Standalone)**,<br>MAME4droid Current **(Standalone)**,<br>MAME4droid **(Standalone)** | Yes | See the specific _Arcade and Neo Geo_ section in the user guide |
|
||||
| neogeocd | SNK Neo Geo CD | NeoCD | MAME4droid Current **(Standalone)** | Yes | .chd (NeoCD and MAME4droid Current only) or .cue file |
|
||||
| neogeocdjp | SNK Neo Geo CD [Japan] | NeoCD | MAME4droid Current **(Standalone)** | Yes | .chd (NeoCD and MAME4droid Current only) or .cue file |
|
||||
| nes | Nintendo Entertainment System | Mesen | Nestopia UE,<br>FCEUmm,<br>QuickNES,<br>NES.emu **(Standalone)**,<br>iNES **(Standalone)**,<br>Nesoid **(Standalone)** | No | Single archive or ROM file |
|
||||
| ngage | Nokia N-Gage | EKA2L1 **(Standalone)** | | Yes | See the specific _Symbian and Nokia N-Gage_ section in the User guide |
|
||||
| ngp | SNK Neo Geo Pocket | Beetle NeoPop | RACE,<br>NGP.emu **(Standalone)** | No | Single archive or ROM file |
|
||||
| ngpc | SNK Neo Geo Pocket Color | Beetle NeoPop | RACE,<br>NGP.emu **(Standalone)** | No | Single archive or ROM file |
|
||||
| odyssey2 | Magnavox Odyssey 2 | O2EM | MAME4droid 2024 **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| odyssey2 | Magnavox Odyssey 2 | O2EM | MAME4droid Current **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| openbor | OpenBOR Game Engine | OpenBOR **(Standalone)** | | No | See the specific _OpenBOR_ section in the User guide |
|
||||
| oric | Tangerine Computer Systems Oric | MAME4droid 2024 **(Standalone)** | | Yes | See the specific _Tangerine Computer Systems Oric_ section in the user guide |
|
||||
| oric | Tangerine Computer Systems Oric | MAME4droid Current **(Standalone)** | | Yes | See the specific _Tangerine Computer Systems Oric_ section in the user guide |
|
||||
| palm | Palm OS | Mu | | | |
|
||||
| pc | IBM PC | DOSBox-Pure | DOSBox-Core,<br>DOSBox-SVN,<br>VirtualXT | No | See the specific _DOS / PC_ section in the user guide |
|
||||
| pc88 | NEC PC-8800 Series | QUASI88 | | Yes | |
|
||||
|
@ -849,56 +866,57 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| pico8 | PICO-8 Fantasy Console | Fake-08 | Retro8,<br>Infinity **(Standalone)** | No | See the specific _PICO-8_ section in the User guide |
|
||||
| plus4 | Commodore Plus/4 | VICE xplus4 | | No | Single archive or image file for tape, cartridge or single-diskette games, .m3u playlist for multi-diskette games |
|
||||
| pokemini | Nintendo Pokémon Mini | PokeMini | | No | |
|
||||
| ports | Ports | ECWolf (Wolfenstein 3D) | NXEngine (Cave Story),<br>OpenLara (Tomb Raider),<br>Super Bros War | Yes for ECWolf | |
|
||||
| ports | Ports | ECWolf (Wolfenstein 3D) | CannonBall (OutRun),<br>Mr.Boom (Bomberman),<br>NXEngine (Cave Story),<br>OpenLara (Tomb Raider),<br>Super Bros War | Yes for ECWolf | |
|
||||
| ps2 | Sony PlayStation 2 | AetherSX2 **(Standalone)** | Play! **(Standalone)** | Yes for AetherSX2 | |
|
||||
| ps3 | Sony PlayStation 3 | _Placeholder_ | | | |
|
||||
| ps4 | Sony PlayStation 4 | _Placeholder_ | | | |
|
||||
| psp | Sony PlayStation Portable | PPSSPP | PPSSPP **(Standalone)** | No | Single disc image file |
|
||||
| psvita | Sony PlayStation Vita | Vita3K **(Standalone)** | | Yes | See the specific _Sony PlayStation Vita_ section in the User guide |
|
||||
| psx | Sony PlayStation | Beetle PSX | Beetle PSX HW,<br>PCSX ReARMed,<br>SwanStation,<br>DuckStation **(Standalone)**,<br>ePSXe **(Standalone)**,<br>FPseNG **(Standalone)**,<br>FPse **(Standalone)** | Yes | .chd file for single-disc games, .m3u playlist for multi-disc games |
|
||||
| pv1000 | Casio PV-1000 | MAME4droid 2024 **(Standalone)** | | No | Single archive or ROM file |
|
||||
| pv1000 | Casio PV-1000 | MAME4droid Current **(Standalone)** | | No | Single archive or ROM file |
|
||||
| quake | Quake | TyrQuake | vitaQuake 2,<br>vitaQuake 2 [Rogue],<br>vitaQuake 2 [Xatrix],<br>vitaQuake 2 [Zaero] | No | |
|
||||
| samcoupe | MGT SAM Coupé | Speccy **(Standalone)** | | No | Single archive or ROM file |
|
||||
| satellaview | Nintendo Satellaview | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x EX+ **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-mercury Accuracy,<br>Mesen-S | | |
|
||||
| satellaview | Nintendo Satellaview | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x EX+ **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-jg,<br>bsnes-mercury Accuracy,<br>Mesen-S | | |
|
||||
| saturn | Sega Saturn | Beetle Saturn | YabaSanshiro,<br>Yaba Sanshiro 2 **(Standalone)**,<br>Yabause,<br>Saturn.emu **(Standalone)** | Yes | .chd file for single-disc games, .m3u playlist for multi-disc games |
|
||||
| saturnjp | Sega Saturn [Japan] | Beetle Saturn | YabaSanshiro,<br>Yaba Sanshiro 2 **(Standalone)**,<br>Yabause,<br>Saturn.emu **(Standalone)** | Yes | .chd file for single-disc games, .m3u playlist for multi-disc games |
|
||||
| scummvm | ScummVM Game Engine | ScummVM | ScummVM **(Standalone)** | No | See the specific _ScummVM_ section in the user guide |
|
||||
| scv | Epoch Super Cassette Vision | MAME4droid 2024 **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| scv | Epoch Super Cassette Vision | MAME4droid Current **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| sega32x | Sega Mega Drive 32X | PicoDrive | | No | Single archive or ROM file |
|
||||
| sega32xjp | Sega Super 32X [Japan] | PicoDrive | | No | Single archive or ROM file |
|
||||
| sega32xna | Sega Genesis 32X [North America] | PicoDrive | | No | Single archive or ROM file |
|
||||
| segacd | Sega CD | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>MD.emu **(Standalone)** | Yes | |
|
||||
| sfc | Nintendo SFC (Super Famicom) | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x EX+ **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-mercury Accuracy,<br>Beetle Supafaust,<br>Mesen-S | No | Single archive or ROM file |
|
||||
| sfc | Nintendo SFC (Super Famicom) | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x EX+ **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-jg,<br>bsnes-mercury Accuracy,<br>Beetle Supafaust,<br>Mesen-S | No | Single archive or ROM file |
|
||||
| sg-1000 | Sega SG-1000 | Genesis Plus GX | Genesis Plus GX Wide,<br>Gearsystem,<br>blueMSX,<br>MasterGear **(Standalone)** | No | Single archive or ROM file |
|
||||
| sgb | Nintendo Super Game Boy | Mesen-S | SameBoy,<br>mGBA | | Single archive or ROM file |
|
||||
| snes | Nintendo SNES (Super Nintendo) | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x EX+ **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-mercury Accuracy,<br>Beetle Supafaust,<br>Mesen-S | No | Single archive or ROM file |
|
||||
| snesna | Nintendo SNES (Super Nintendo) [North America] | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x EX+ **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-mercury Accuracy,<br>Beetle Supafaust,<br>Mesen-S | No | Single archive or ROM file |
|
||||
| snes | Nintendo SNES (Super Nintendo) | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x EX+ **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-jg,<br>bsnes-mercury Accuracy,<br>Beetle Supafaust,<br>Mesen-S | No | Single archive or ROM file |
|
||||
| snesna | Nintendo SNES (Super Nintendo) [North America] | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x EX+ **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-jg,<br>bsnes-mercury Accuracy,<br>Beetle Supafaust,<br>Mesen-S | No | Single archive or ROM file |
|
||||
| solarus | Solarus Game Engine | _Placeholder_ | | | |
|
||||
| spectravideo | Spectravideo | blueMSX | | | |
|
||||
| steam | Valve Steam | _Placeholder_ | | | |
|
||||
| stv | Sega Titan Video Game System | MAME - Current | MAME4droid 2024 **(Standalone)**,<br>MAME4droid **(Standalone)** | Yes | Single archive file |
|
||||
| sufami | Bandai SuFami Turbo | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x EX+ **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-mercury Accuracy | | |
|
||||
| stv | Sega Titan Video Game System | MAME - Current | MAME4droid Current **(Standalone)**,<br>MAME4droid **(Standalone)** | Yes | Single archive file |
|
||||
| sufami | Bandai SuFami Turbo | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x EX+ **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-jg,<br>bsnes-mercury Accuracy | | |
|
||||
| supergrafx | NEC SuperGrafx | Beetle SuperGrafx | Beetle PCE,<br>PCE.emu **(Standalone)** | No | Single archive or ROM file |
|
||||
| supervision | Watara Supervision | Potator | MAME4droid 2024 **(Standalone)** | No | Single archive or ROM file |
|
||||
| supracan | Funtech Super A'Can | MAME4droid 2024 **(Standalone)** | | Yes | Single archive or ROM file. You need a supracan.zip archive that contains a valid internal_68k.bin file and an empty file named umc6650.bin |
|
||||
| supervision | Watara Supervision | Potator | MAME4droid Current **(Standalone)** | No | Single archive or ROM file |
|
||||
| supracan | Funtech Super A'Can | MAME4droid Current **(Standalone)** | | Yes | Single archive or ROM file. You need a supracan.zip archive that contains a valid internal_68k.bin file and an empty file named umc6650.bin |
|
||||
| switch | Nintendo Switch | Skyline **(Standalone)** | | Yes | |
|
||||
| symbian | Symbian | EKA2L1 **(Standalone)** | | Yes | See the specific _Symbian and Nokia N-Gage_ section in the User guide |
|
||||
| tanodragon | Tano Dragon | MAME4droid 2024 [Tape] **(Standalone)** | MAME4droid 2024 [Cartridge] **(Standalone)** | Yes | See the specific _Dragon 32 and Tano Dragon_ section in the user guide |
|
||||
| tanodragon | Tano Dragon | MAME4droid Current [Tape] **(Standalone)** | MAME4droid Current [Cartridge] **(Standalone)** | Yes | See the specific _Dragon 32 and Tano Dragon_ section in the user guide |
|
||||
| tg16 | NEC TurboGrafx-16 | Beetle PCE | Beetle PCE FAST,<br>Beetle SuperGrafx,<br>PCE.emu **(Standalone)** | No | Single archive or ROM file |
|
||||
| tg-cd | NEC TurboGrafx-CD | Beetle PCE | Beetle PCE FAST,<br>Beetle SuperGrafx,<br>PCE.emu **(Standalone)** | Yes | |
|
||||
| ti99 | Texas Instruments TI-99 | MAME4droid 2024 **(Standalone)** | | Yes | See the specific _Texas Instruments TI-99_ section in the user guide |
|
||||
| ti99 | Texas Instruments TI-99 | MAME4droid Current **(Standalone)** | | Yes | See the specific _Texas Instruments TI-99_ section in the user guide |
|
||||
| tic80 | TIC-80 Fantasy Computer | TIC-80 | | No | Single .tic file |
|
||||
| to8 | Thomson TO8 | Theodore | | | |
|
||||
| triforce | Namco-Sega-Nintendo Triforce | _Placeholder_ | | | |
|
||||
| trs-80 | Tandy TRS-80 | _Placeholder_ | | | |
|
||||
| type-x | Taito Type X | Winlator Cmod Glibc **(Standalone)** | Winlator Cmod PRoot **(Standalone)** | No | See the _Winlator_ section elsewhere in this document |
|
||||
| uzebox | Uzebox Open Source Console | Uzem | | | |
|
||||
| vectrex | GCE Vectrex | vecx | MAME4droid 2024 **(Standalone)** | Yes for MAME4droid 2024 | Single archive or ROM file |
|
||||
| vectrex | GCE Vectrex | vecx | MAME4droid Current **(Standalone)** | Yes for MAME4droid Current | Single archive or ROM file |
|
||||
| vic20 | Commodore VIC-20 | VICE xvic | | No | Single archive or tape, cartridge or diskette image file |
|
||||
| videopac | Philips Videopac G7000 | O2EM | MAME4droid 2024 **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| videopac | Philips Videopac G7000 | O2EM | MAME4droid Current **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| vircon32 | Vircon32 Virtual Console | Vircon32 | | No | Single archive or ROM file |
|
||||
| virtualboy | Nintendo Virtual Boy | Beetle VB | Virtual Virtual Boy **(Standalone)** | No | Single archive or ROM file |
|
||||
| vpinball | Visual Pinball | Visual Pinball **(Standalone)** | | No | See the specific _Visual Pinball_ section in the user guide |
|
||||
| vsmile | VTech V.Smile | MAME4droid 2024 **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| vsmile | VTech V.Smile | MAME4droid Current **(Standalone)** | | Yes | Single archive or ROM file |
|
||||
| wasm4 | WASM-4 Fantasy Console | WASM-4 | | No | Single .wasm file |
|
||||
| wii | Nintendo Wii | Dolphin | Dolphin **(Standalone)**,<br>Dolphin MMJR **(Standalone)**,<br>Dolphin MMJR2 **(Standalone)** | No | |
|
||||
| wiiu | Nintendo Wii U | Cemu **(Standalone)** | | No | See the specific _Nintendo Wii U_ section in the user guide |
|
||||
|
@ -907,10 +925,11 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| windows9x | Microsoft Windows 9x | DOSBox-Pure | | No | |
|
||||
| wonderswan | Bandai WonderSwan | Beetle Cygne | Swan.emu **(Standalone)** | No | Single archive or ROM file |
|
||||
| wonderswancolor | Bandai WonderSwan Color | Beetle Cygne | Swan.emu **(Standalone)** | No | Single archive or ROM file |
|
||||
| x1 | Sharp X1 | X Millennium | MAME4droid 2024 [Diskette] **(Standalone)**,<br>MAME4droid 2024 [Tape] **(Standalone)** | Yes for MAME4droid 2024 | Single archive or diskette/tape file |
|
||||
| x68000 | Sharp X68000 | PX68k | MAME4droid 2024 **(Standalone)** | Yes | |
|
||||
| x1 | Sharp X1 | X Millennium | MAME4droid Current [Diskette] **(Standalone)**,<br>MAME4droid Current [Tape] **(Standalone)** | Yes for MAME4droid Current | Single archive or diskette/tape file |
|
||||
| x68000 | Sharp X68000 | PX68k | MAME4droid Current **(Standalone)** | Yes | |
|
||||
| xbox | Microsoft Xbox | _Placeholder_ | | | |
|
||||
| xbox360 | Microsoft Xbox 360 | _Placeholder_ | | | |
|
||||
| xboxone | Microsoft Xbox One | _Placeholder_ | | | |
|
||||
| zmachine | Infocom Z-machine | MojoZork | | No | |
|
||||
| zx81 | Sinclair ZX81 | EightyOne | | No | |
|
||||
| zxnext | Sinclair ZX Spectrum Next | _Placeholder_ | | | |
|
||||
|
|
13
ANDROID.md
13
ANDROID.md
|
@ -290,12 +290,11 @@ https://play.google.com/store/apps/details?id=com.github.stenzek.duckstation
|
|||
|
||||
### EKA2L1
|
||||
|
||||
This emulator can be downloaded from their GitHub site.
|
||||
This emulator can be installed from the Play store or it can be downloaded from their GitHub site.
|
||||
|
||||
https://play.google.com/store/apps/details?id=com.github.eka2l1 \
|
||||
https://github.com/EKA2L1/EKA2L1/releases
|
||||
|
||||
There does not seem to be a way to launch individual EKA2L1 games from a frontend application on Android, instead ES-DE will simply launch the EKA2L1 user interface and you'll have to manually start your game from there.
|
||||
|
||||
### ePSXe
|
||||
|
||||
This emulator can be installed from the Play store as a paid app.
|
||||
|
@ -356,7 +355,7 @@ This PICO-8 game engine/emulator can be installed from the Play store.
|
|||
|
||||
https://play.google.com/store/apps/details?id=me.dt2dev.infinity
|
||||
|
||||
Note that this emulator has a strange behavior where it will return to the home app whenever you exit a game, so unless ES-DE is set as your home app you'll need to manually switch back to it after exiting Infinity.
|
||||
Note that since a recent emulator update it seems like individual games can no longer be launched from ES-DE, instead you'll just see the list of carts and you need to manually start the game from inside Infinity.
|
||||
|
||||
### IrataJaguar
|
||||
|
||||
|
@ -520,7 +519,7 @@ https://play.google.com/store/apps/details?id=io.recompiled.redream
|
|||
|
||||
### ScummVM
|
||||
|
||||
ScummVM can be installed from the Play store. There are also daily builds available on their GitHub site. Such a build may be required to be able to launch games from ES-DE until the Play store version has been updated.
|
||||
ScummVM can be installed from the Play store. There are also daily builds available on their GitHub site.
|
||||
|
||||
https://play.google.com/store/apps/details?id=org.scummvm.scummvm\
|
||||
https://buildbot.scummvm.org/#/dailybuilds
|
||||
|
@ -585,6 +584,8 @@ This emulator can be installed from the Play store. Note that only the paid Pro
|
|||
|
||||
https://play.google.com/store/apps/details?id=org.devmiyax.yabasanshioro2.pro
|
||||
|
||||
**Note:** At the time of writing this emulator is broken on some devices and will simply display the error message _Cannot initialize SH2_ on game launch. The issue was apparently introduced in a recent update and is awaiting a fix from the developer.
|
||||
|
||||
## Device compatibility
|
||||
|
||||
This is clearly not a complete list of Android devices, but rather those we know have been tested with ES-DE and for which there is a known status.
|
||||
|
@ -630,8 +631,6 @@ This is clearly not a complete list of Android devices, but rather those we know
|
|||
| Huawei | Mate 20 Pro | 10 | Yes | None | |
|
||||
| Huawei | MatePad 11 (2021) | 13 | Yes | None | |
|
||||
| Infinix | Zero 30 5G | 13 | Yes | None | |
|
||||
| Kinhank | G1 | 11 | No | Unable to install | Possibly 32-bit operating system? |
|
||||
| Kinhank | Super Console X5 Pro | 12 (TV) | No | None | Custom 64-bit Android TV OS |
|
||||
| KTPocket | KT-R1 | GammaOS 12 | Yes | None | |
|
||||
| Lenovo | Legion Y700 (2022) | 12 | Yes | None | |
|
||||
| Lenovo | Legion Y700 (2023) | 13 | Yes | None | |
|
||||
|
|
87
CHANGELOG.md
87
CHANGELOG.md
|
@ -1,5 +1,92 @@
|
|||
# ES-DE Frontend - Changelog
|
||||
|
||||
## Version 3.2.0 / 3.2.0-xx (in development)
|
||||
|
||||
**Release date:** TBD
|
||||
|
||||
### Release overview
|
||||
|
||||
### Detailed list of changes
|
||||
|
||||
* Added a system status element showing the Blueooth, Wi-Fi, cellular and battery status on screen
|
||||
* Added a "Display clock" setting to the UI settings menu to display an on screen clock (disabled by default)
|
||||
* Added translations for Traditional Chinese (zh_TW)
|
||||
* Added support for the Sony PlayStation 4 (ps4) game system on Linux, macOS and Windows using the shadPS4 emulator
|
||||
* Added support for the Vircon32 Virtual Console (vircon32) game system
|
||||
* Added support for the Sega Mark III (mark3) game system
|
||||
* Increased the roundness for all corners in the menu system and for the notification popups
|
||||
* Increased the background blur slightly when a menu is open
|
||||
* Added an option to completely disable the game launch screen (via the UI settings menu)
|
||||
* Made the menu and launch screen scale up at the same speed regardless of the display refresh rate
|
||||
* Added a screensaver-game-select custom event
|
||||
* Added game-select and system-select custom events and a corresponding "Browsing custom events" menu option
|
||||
* Added RPCS3 Game Serial as an alternative emulator for the consolearcade and ps3 systems on Linux, macOS and Windows
|
||||
* Added the NooDS RetroArch core as an alternative emulator for the gba and nds systems
|
||||
* Added the bsnes-jg RetroArch core as an alternative emulator for the satellaview, sfc, snes, snesna and sufami systems
|
||||
* Added the Holani RetroArch core as an alternative emulator for the atarilynx system
|
||||
* Added the b2 RetroArch core as an alternative emulator for the bbcmicro system
|
||||
* Added the CannonBall RetroArch core as an alternative emulator for the ports system
|
||||
* Added the Mr.Boom RetroArch core as an alternative emulator for the ports system
|
||||
* Added Mesen standalone as an alternative emulator for the colecovision, wonderswan and wonderswancolor systems on Linux and Windows
|
||||
* Added Azahar standalone as an alternative emulator for the n3ds system
|
||||
* Added A7800 standalone as an alternative emulator for the atari7800 system on Linux and Windows
|
||||
* (Android) Changed from MAME4droid 2024 to MAME4droid Current for all systems where only this emulator was supported
|
||||
* (Android) Added a find rule entry for the new Cemu package name
|
||||
* (Android) Added MAME4droid Current emulator entries for all systems where MAME4droid 2024 was supported
|
||||
* (Android) Added SkyEmu standalone as an alternative emulator for the gb, gba, gbc and nds systems
|
||||
* (Android) Added Pizza Boy SC standalone as an alternative emulator for the gamegear, genesis, mastersystem, megadrive and megadrivejp systems
|
||||
* (Android) Changed all RetroArch core entries to use absolute paths (this makes the ancient Play store release work correctly)
|
||||
* (Windows) Added MFME standalone (fruit machine emulator) as an alternative emulator for the arcade and mame systems
|
||||
* (Windows) Added XM6 TypeG standalone as an alternative emulator for the x68000 system
|
||||
* (Linux) Added MFME Wine and MFME Proton as alternative emulators for the arcade and mame systems
|
||||
* (Linux) Added XM6 TypeG Wine and XM6 TypeG Proton as alternative emulators for the x68000 system
|
||||
* (Linux) Added a find rule entry for the new PCSX2 binary name (pcsx2)
|
||||
* (Linux) Added a find rule entry for the new DuckStation binary name (duckstation)
|
||||
* (Linux) Added support for the Flatpak release of Ruffle
|
||||
* (Linux) Added support for the manually downloaded release of Mesen
|
||||
* (Linux) Changed the AppImage find rule for Mandarine to mandarine-qt*.AppImage
|
||||
* Enabled directories interpreted as files with MAME RetroArch for the apple2, apple2gs and fmtowns systems on Linux, macOS and Windows
|
||||
* Added the .gam file extension to the arcade system on Linux and Windows
|
||||
* Added the .m3u file extension to the sega32x, sega32xjp and sega32xna systems
|
||||
* Added the .ruf file extension to the flash system
|
||||
* Added initial support for the Microsoft Xbox One (xboxone) game system (still awaiting emulator support)
|
||||
* Added a %ROMRAWWIN% variable to pass the game ROM path with Windows-style backslash directory separators
|
||||
* Refactored the helpsystem code and added support for using an arbitrary amount of helpsystem elements
|
||||
* Added support for specifying which specific entries to display for the helpsystem elements
|
||||
* Added an "entryLayout" property to the helpsystem element to control the display order for the icons and text
|
||||
* Added an "entryRelativeScale" property to the helpsystem element to control the relative scale between the icons and text
|
||||
* Added "rotation", "rotationOrigin", "backgroundColor" and "backgroundColorEnd" properties to the helpsystem element
|
||||
* Added "backgroundHorizontalPadding" and "backgroundVerticalPadding properties to the helpsystem element
|
||||
* Added "backgroundGradientType" and "backgroundCornerRadius" properties to the helpsystem element
|
||||
* Added a "clock" element to make it possible to customize the layout and position of the clock
|
||||
* Added "imageSize", "imageMaxSize", "imageCropSize" and "imageCropPos" properties to the video element
|
||||
* Added a "fadeInType" property to the video element to fade in from black or from transparency
|
||||
* Added support for a "none" value to the video element imageType property
|
||||
* Added a BackgroundComponent to replace NinePatchComponent for rendering menu and popup backgrounds
|
||||
* (Android) Changed the target SDK version to 35 (Android 15)
|
||||
* The LANG and LANGUAGE variables are now set explicitly to the UTF-8 character encoding on Linux, macOS and Android
|
||||
* Added support for the 8:7 display aspect ratio
|
||||
* (macOS) Added a build script for cross-compiling for x86_64 when using an ARM processor
|
||||
* (Linux) Added the BlueZ library as a dependency
|
||||
* Added support for building against libgit2 v1.9.0 and later
|
||||
* Added support for building against ICU 76.1 and later
|
||||
* Updated SDL to 2.32.2 on Android, Windows, macOS and the Linux AppImage builds
|
||||
* Updated the MAME index files to include ROMs up to MAME version 0.275
|
||||
* Bundled the February 2025 release of the Mozilla TLS/SSL certificates
|
||||
* Made a small adjustment to the button_y_PS helpsystem button
|
||||
* Translation updates for multiple languages
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* The text element containerStartDelay timer was sometimes not reset which made vertical text scrolling start too early under some circumstances
|
||||
* The selectedItemOffset property did not work correctly for carousels with a single item
|
||||
* Returning from a game when running in the background ignored the video element delay property for the first playback
|
||||
* A double free in GuiLaunchScreen could cause an unclean application shutdown
|
||||
* Applying rounded corners caused rendering artfifacts if the texture did not use premultiplied alpha
|
||||
* The menus would sometimes contain fractional rows at extreme resolutions such as 1080x1920
|
||||
* (Windows) There could be double quotation marks added to the launch command under some special circumstances
|
||||
* (Android) There was a PLACEHOLDER entry present for the consolearcade system in the es_systems.xml file
|
||||
|
||||
## Version 3.1.1 / 3.1.1-39
|
||||
|
||||
**Release date:** 2024-12-13
|
||||
|
|
80
CMake/Packages/FindBluez.cmake
Normal file
80
CMake/Packages/FindBluez.cmake
Normal file
|
@ -0,0 +1,80 @@
|
|||
# - try to find Bluez
|
||||
#
|
||||
# Cache Variables: (probably not for direct use in your scripts)
|
||||
# BLUEZ_INCLUDE_DIR
|
||||
# BLUEZ_LIBRARY
|
||||
#
|
||||
# Non-cache variables you might use in your CMakeLists.txt:
|
||||
# BLUEZ_FOUND
|
||||
# BLUEZ_INCLUDE_DIRS
|
||||
# BLUEZ_LIBRARIES
|
||||
#
|
||||
# Requires these CMake modules:
|
||||
# FindPackageHandleStandardArgs (known included with CMake >=2.6.2)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Rylie Pavlik <rylie@ryliepavlik.com>
|
||||
# https://ryliepavlik.com/
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright 2009-2010, Iowa State University
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
if(WIN32 OR APPLE OR NOT UNIX)
|
||||
if(NOT Bluez_FIND_QUIETLY)
|
||||
message(STATUS "Platform not supported by Bluez - skipping search")
|
||||
endif()
|
||||
else()
|
||||
set(BLUEZ_ROOT_DIR
|
||||
"${BLUEZ_ROOT_DIR}"
|
||||
CACHE
|
||||
PATH
|
||||
"Directory to search")
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
set(_LIBSUFFIXES lib64 lib)
|
||||
else()
|
||||
set(_LIBSUFFIXES lib)
|
||||
endif()
|
||||
|
||||
find_library(BLUEZ_LIBRARY
|
||||
NAMES
|
||||
bluetooth
|
||||
HINTS
|
||||
"${BLUEZ_ROOT_DIR}"
|
||||
PATH_SUFFIXES
|
||||
"${_LIBSUFFIXES}")
|
||||
|
||||
# Might want to look close to the library first for the includes.
|
||||
get_filename_component(_libdir "${BLUEZ_LIBRARY}" PATH)
|
||||
|
||||
find_path(BLUEZ_INCLUDE_DIR
|
||||
NAMES
|
||||
bluetooth/bluetooth.h
|
||||
HINTS
|
||||
"${_libdir}/.."
|
||||
PATHS
|
||||
"${BLUEZ_ROOT_DIR}"
|
||||
PATH_SUFFIXES
|
||||
include/)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Bluez
|
||||
DEFAULT_MSG
|
||||
BLUEZ_LIBRARY
|
||||
BLUEZ_INCLUDE_DIR)
|
||||
|
||||
if(BLUEZ_FOUND)
|
||||
set(BLUEZ_LIBRARIES "${BLUEZ_LIBRARY}")
|
||||
set(BLUEZ_INCLUDE_DIRS "${BLUEZ_INCLUDE_DIR}")
|
||||
mark_as_advanced(BLUEZ_ROOT_DIR)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(BLUEZ_INCLUDE_DIR
|
||||
BLUEZ_LIBRARY)
|
|
@ -9,7 +9,10 @@
|
|||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
if(APPLE)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES iOS)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 14.0 CACHE STRING "iOS deployment target")
|
||||
elseif(APPLE)
|
||||
# Set this to the minimum supported macOS version, and also update
|
||||
# es-app/assets/ES-DE_Info.plist accordingly.
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0 CACHE STRING "macOS deployment target")
|
||||
|
@ -19,7 +22,7 @@ endif()
|
|||
project(es-de)
|
||||
|
||||
# Application version, update this when making a new release.
|
||||
set(ES_VERSION 3.1.1)
|
||||
set(ES_VERSION 3.2.0)
|
||||
|
||||
# Set this to ON to show verbose compiler output (e.g. compiler flags, include directories etc.)
|
||||
set(CMAKE_VERBOSE_MAKEFILE OFF CACHE BOOL "Show verbose compiler output" FORCE)
|
||||
|
@ -91,6 +94,15 @@ if(EXISTS /usr/include/bcm_host.h)
|
|||
message("-- Building on a Raspberry Pi (64-bit OS)")
|
||||
endif()
|
||||
|
||||
# iOS.
|
||||
if(IOS)
|
||||
message("-- Building for iOS (arm64)")
|
||||
set(GLES ON)
|
||||
set(BUNDLED_CERTS ON)
|
||||
add_compile_definitions(__IOS__)
|
||||
include(${CMAKE_SOURCE_DIR}/ios/cmake/variables.cmake)
|
||||
endif()
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
# Emscripten WebAssembly build.
|
||||
|
||||
|
@ -118,12 +130,12 @@ if(GLSYSTEM MATCHES "Desktop OpenGL")
|
|||
find_package(OpenGL REQUIRED)
|
||||
elseif(ANDROID)
|
||||
find_package(OpenGLES3 REQUIRED)
|
||||
elseif(GLES AND NOT EMSCRIPTEN)
|
||||
elseif(GLES AND NOT IOS AND NOT EMSCRIPTEN)
|
||||
find_package(OpenGLES2 REQUIRED)
|
||||
endif()
|
||||
|
||||
# On macOS and Windows all dependencies are kept in-tree in the "external" directory.
|
||||
if(APPLE)
|
||||
# On macOS, iOS and Windows all dependencies are kept in-tree in the "external" directory.
|
||||
if(APPLE AND NOT IOS)
|
||||
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/external/FFmpeg)
|
||||
message(FATAL_ERROR "-- You need to build the dependencies in ./external first")
|
||||
endif()
|
||||
|
@ -132,7 +144,7 @@ elseif(WIN32)
|
|||
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/external/pugixml/pugixml.dll)
|
||||
message(FATAL_ERROR "-- You need to build the dependencies in ./external first")
|
||||
endif()
|
||||
elseif(NOT EMSCRIPTEN AND NOT ANDROID)
|
||||
elseif(NOT EMSCRIPTEN AND NOT ANDROID AND NOT IOS)
|
||||
find_package(CURL REQUIRED)
|
||||
find_package(FFmpeg REQUIRED)
|
||||
find_package(FreeImage REQUIRED)
|
||||
|
@ -150,9 +162,10 @@ if(CEC)
|
|||
find_package(libCEC REQUIRED)
|
||||
endif()
|
||||
|
||||
# Add ALSA for Linux.
|
||||
# Add ALSA and BlueZ for Linux.
|
||||
if(CMAKE_SYSTEM_NAME MATCHES Linux)
|
||||
find_package(ALSA REQUIRED)
|
||||
find_package(Bluez REQUIRED)
|
||||
endif()
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
@ -279,8 +292,8 @@ if(ASAN OR UBSAN)
|
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_ASSERTIONS -D_FORTIFY_SOURCE=3")
|
||||
endif()
|
||||
|
||||
# The following removes half of the ranlib warnings on macOS regarding no symbols for files
|
||||
# that are #ifdef'ed away. There must be a way to remove the other half as well?
|
||||
# The following removes the ranlib warnings on macOS regarding missing symbols for files that have
|
||||
# been #ifdef'ed away.
|
||||
if(APPLE)
|
||||
SET(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
|
||||
SET(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
|
||||
|
@ -378,7 +391,7 @@ if(DEINIT_ON_LAUNCH)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(AUR_BUILD OR FLATPAK_BUILD OR RETRODECK OR RPI OR HAIKU OR CMAKE_SYSTEM_NAME MATCHES FreeBSD)
|
||||
if(AUR_BUILD OR FLATPAK_BUILD OR RETRODECK OR RPI OR HAIKU OR IOS OR CMAKE_SYSTEM_NAME MATCHES FreeBSD)
|
||||
set(APPLICATION_UPDATER OFF)
|
||||
endif()
|
||||
|
||||
|
@ -462,8 +475,19 @@ set(COMMON_INCLUDE_DIRS ${CURL_INCLUDE_DIR}
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/external/utfcpp/source
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/es-core/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/es-pdf-converter/src)
|
||||
|
||||
if(APPLE)
|
||||
if(IOS)
|
||||
set(COMMON_INCLUDE_DIRS ${COMMON_INCLUDE_DIRS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/curl/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/ffmpeg-kit/src/ffmpeg
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/FreeImage/Source
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/freetype/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/gettext/gettext-runtime/intl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/libgit2/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/harfbuzz/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/icu/icu4c/source/common
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/pugixml/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/SDL)
|
||||
elseif(APPLE)
|
||||
set(COMMON_INCLUDE_DIRS ${COMMON_INCLUDE_DIRS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/FFmpeg
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/freeimage/FreeImage/Source
|
||||
|
@ -508,6 +532,7 @@ elseif(ANDROID)
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/external/SDL_Android)
|
||||
else()
|
||||
set(COMMON_INCLUDE_DIRS ${COMMON_INCLUDE_DIRS}
|
||||
${BLUEZ_INCLUDE_DIRS}
|
||||
${FFMPEG_INCLUDE_DIRS}
|
||||
${FreeImage_INCLUDE_DIRS}
|
||||
${FREETYPE_INCLUDE_DIRS}
|
||||
|
@ -538,7 +563,30 @@ endif()
|
|||
#---------------------------------------------------------------------------------------------------
|
||||
# Dependency libraries.
|
||||
|
||||
if(APPLE)
|
||||
if(IOS)
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES}
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libavcodec.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libavfilter.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libavformat.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libavutil.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libswresample.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libswscale.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libcurl.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libfontconfig.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libfreeimage.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libfreetype.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libgit.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libharfbuzz.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libicudata.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libicui18n.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libicuuc.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libintl.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libopenjpeg.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libpoppler.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libpoppler-cpp.xcframework
|
||||
${PROJECT_SOURCE_DIR}/Frameworks/libSDL.xcframework
|
||||
${PROJECT_SOURCE_DIR}/libpugixml.a)
|
||||
elseif(APPLE)
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES}
|
||||
${CURL_LIBRARIES}
|
||||
${PROJECT_SOURCE_DIR}/libavcodec.60.dylib
|
||||
|
@ -579,6 +627,8 @@ elseif(WIN32)
|
|||
${PROJECT_SOURCE_DIR}/rlottie.lib
|
||||
${PROJECT_SOURCE_DIR}/SDL2main.lib
|
||||
${PROJECT_SOURCE_DIR}/SDL2.lib
|
||||
iphlpapi.dll
|
||||
bthprops.lib
|
||||
Winmm.dll)
|
||||
elseif(ANDROID)
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES}
|
||||
|
@ -639,7 +689,8 @@ elseif(EMSCRIPTEN)
|
|||
${PROJECT_SOURCE_DIR}/libfreetype.a
|
||||
${PROJECT_SOURCE_DIR}/libpugixml.a)
|
||||
else()
|
||||
set(COMMON_LIBRARIES ${CURL_LIBRARIES}
|
||||
set(COMMON_LIBRARIES ${BLUEZ_LIBRARIES}
|
||||
${CURL_LIBRARIES}
|
||||
${FFMPEG_LIBRARIES}
|
||||
${FreeImage_LIBRARIES}
|
||||
${FREETYPE_LIBRARIES}
|
||||
|
@ -660,13 +711,16 @@ if(NOT WIN32)
|
|||
if(ANDROID)
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} ${PROJECT_SOURCE_DIR}/android_${ANDROID_ABI}/liblunasvg.a)
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} ${PROJECT_SOURCE_DIR}/android_${ANDROID_ABI}/librlottie.a)
|
||||
elseif(IOS)
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} ${PROJECT_SOURCE_DIR}/${CMAKE_BUILD_TYPE}/liblunasvg.a)
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} ${PROJECT_SOURCE_DIR}/${CMAKE_BUILD_TYPE}/librlottie.a)
|
||||
else()
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} ${PROJECT_SOURCE_DIR}/liblunasvg.a)
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} ${PROJECT_SOURCE_DIR}/librlottie.a)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
if(APPLE AND NOT IOS)
|
||||
# See es-app/CMakeLists.txt for an explation for why an extra "Resources" directory
|
||||
# has been added to the install prefix.
|
||||
set(CMAKE_INSTALL_PREFIX "/Applications/ES-DE.app/Contents/Resources")
|
||||
|
|
14
CREDITS.md
14
CREDITS.md
|
@ -42,13 +42,16 @@ SilverGreen93 \
|
|||
Lulzee \
|
||||
**Swedish** \
|
||||
Leon Styhre \
|
||||
Daniel Nylander \
|
||||
**Japanese** \
|
||||
冰棍 \
|
||||
**Korean** \
|
||||
wakeboxer \
|
||||
**Simplified Chinese** \
|
||||
邻家小熊 \
|
||||
冰棍
|
||||
冰棍 \
|
||||
**Traditional Chinese** \
|
||||
Hsin Chiang
|
||||
|
||||
# Licenses
|
||||
|
||||
|
@ -56,6 +59,9 @@ Please find the individual license files inside the [licenses](https://gitlab.co
|
|||
|
||||
# Libraries
|
||||
|
||||
BlueZ \
|
||||
https://github.com/bluez/bluez
|
||||
|
||||
CImg \
|
||||
https://www.cimg.eu
|
||||
|
||||
|
@ -130,6 +136,9 @@ https://batocera.org
|
|||
The MD5 hash functions were adapted from code by the BZFlag project \
|
||||
https://www.bzflag.org
|
||||
|
||||
Some battery detection functionality for macOS was based on code from Battery Percentage Notifier \
|
||||
https://github.com/Abhigyan126/Custom_Low_Battery_Warning
|
||||
|
||||
The scanline GLSL shader was adapted from code by the RetroArch project \
|
||||
https://www.retroarch.com
|
||||
|
||||
|
@ -162,6 +171,9 @@ https://fonts.google.com/noto/specimen/Noto+Emoji
|
|||
Ubuntu font \
|
||||
https://design.ubuntu.com/font
|
||||
|
||||
System status icons (some customizations have been made) \
|
||||
https://phosphoricons.com
|
||||
|
||||
MAME ROM information \
|
||||
https://www.mamedev.org
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ There are some dependencies that need to be fulfilled in order to build ES-DE. T
|
|||
All of the required packages can be installed with apt-get:
|
||||
|
||||
```
|
||||
sudo apt-get install build-essential clang-format git cmake gettext libharfbuzz-dev libicu-dev libsdl2-dev libavcodec-dev libavfilter-dev libavformat-dev libavutil-dev libfreeimage-dev libfreetype6-dev libgit2-dev libcurl4-openssl-dev libpugixml-dev libasound2-dev libgl1-mesa-dev libpoppler-cpp-dev
|
||||
sudo apt-get install build-essential clang-format git cmake gettext libharfbuzz-dev libicu-dev libsdl2-dev libavcodec-dev libavfilter-dev libavformat-dev libavutil-dev libfreeimage-dev libfreetype6-dev libgit2-dev libcurl4-openssl-dev libpugixml-dev libasound2-dev libbluetooth-dev libgl1-mesa-dev libpoppler-cpp-dev
|
||||
```
|
||||
|
||||
**Fedora**
|
||||
|
@ -40,7 +40,7 @@ https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -
|
|||
|
||||
Then you can use dnf to install all the required packages:
|
||||
```
|
||||
sudo dnf install gcc-c++ clang-tools-extra cmake gettext harfbuzz-devel libicu-devel libasan rpm-build SDL2-devel ffmpeg-devel freeimage-devel freetype-devel libgit2-devel curl-devel pugixml-devel alsa-lib-devel mesa-libGL-devel poppler-cpp-devel
|
||||
sudo dnf install gcc-c++ clang-tools-extra cmake gettext harfbuzz-devel libicu-devel libasan rpm-build SDL2-devel ffmpeg-devel freeimage-devel freetype-devel libgit2-devel curl-devel pugixml-devel alsa-lib-devel bluez-libs-devel mesa-libGL-devel poppler-cpp-devel
|
||||
```
|
||||
|
||||
**Manjaro**
|
||||
|
@ -55,7 +55,7 @@ sudo pacman -S gcc clang make cmake gettext harfbuzz icu pkgconf sdl2 ffmpeg fre
|
|||
|
||||
All of the required packages can be installed with apt-get:
|
||||
```
|
||||
sudo apt-get install clang-format cmake gettext libharfbuzz-dev libicu-dev libraspberrypi-dev libsdl2-dev libavcodec-dev libavfilter-dev libavformat-dev libavutil-dev libfreeimage-dev libfreetype6-dev libgit2-dev libcurl4-gnutls-dev libpugixml-dev libpoppler-cpp-dev
|
||||
sudo apt-get install clang-format cmake gettext libharfbuzz-dev libicu-dev libraspberrypi-dev libsdl2-dev libavcodec-dev libavfilter-dev libavformat-dev libavutil-dev libfreeimage-dev libfreetype6-dev libgit2-dev libcurl4-gnutls-dev libpugixml-dev libbluetooth-dev libpoppler-cpp-dev
|
||||
```
|
||||
|
||||
For a 64-bit build it's very important that you include libraspberrypi-dev because if this package is not installed then the file /usr/include/bcm_host.h is not present on the filesystem. This leads to CMake not detecting that it's indeed a Raspberry Pi and it will attempt to make a regular Linux build instead.
|
||||
|
@ -455,7 +455,7 @@ The first time you run haikuporter it will take a while as dependencies for all
|
|||
|
||||
Following this you can install the package into the running system:
|
||||
```
|
||||
cp ~/haikuports/packages/es_de-3.1.0-1-x86_64.hpkg /boot/system/packages
|
||||
cp ~/haikuports/packages/es_de-3.1.1-1-x86_64.hpkg /boot/system/packages
|
||||
```
|
||||
|
||||
## Building on macOS
|
||||
|
@ -580,6 +580,19 @@ export ASAN_OPTIONS=detect_container_overflow=0
|
|||
|
||||
Running ES-DE from the build directory may be a bit flaky as there is no Info.plist file available which is required for setting the proper window mode and such. It's therefore recommended to run the application from the installation directory for any more in-depth testing. But normal debugging can of course be done from the build directory.
|
||||
|
||||
**Cross-compiling for x86_64**
|
||||
|
||||
To cross-compile for x86_64 using an ARM processor you only need to change two things.
|
||||
|
||||
First you need to run `tools/macOS_dependencies_build_x86_cross.sh` instead of `tools/macOS_dependencies_build.sh`
|
||||
|
||||
Second you need to pass the target architecture using the CMAKE_OSX_ARCHITECTURES variable such as this:
|
||||
```
|
||||
cmake -DCMAKE_OSX_ARCHITECTURES=x86_64 .
|
||||
```
|
||||
|
||||
Following this you can just build and package the application in the same way as a native ARM build.
|
||||
|
||||
**Code signing**
|
||||
|
||||
A detailed explanation of macOS code signing is beyond the scope of this document, but the CMake option MACOS_CODESIGN_IDENTITY is used to specify the code signing certificate identity, for example:
|
||||
|
@ -1153,6 +1166,10 @@ Sets the transfer timeout per HTTPS request. Minimum value is 0 seconds (infinit
|
|||
|
||||
Normally the scraper will stop whenever an HTTP error code with value 400 or above is returned from the scraper service, but by default there is an exception for 404 errors (resource not found). Changing this setting to _false_ will make the scraper handle 404 errors as all other error codes, meaning it will run through the configured retry attempts and then display an error notification dialog if the resource could not be retrieved.
|
||||
|
||||
**SystemStatusDisplayAll**
|
||||
|
||||
If setting this to true then all system status indicators (Bluetooth icon, Wi-Fi icon, cellular icon, battery icon and battery percentage indicator) will always be displayed, assuming they have been enabled in the _UI settings_ menu and via the `entries` property for the `systemstatus` element. The only purpose of this setting is for theme developers to be able to see all indicators when working on their theme design.
|
||||
|
||||
**UIMode_passkey**
|
||||
|
||||
The passkey to use to change from the _Kiosk_ or _Kid_ UI modes to the _Full_ UI mode.
|
||||
|
@ -1577,7 +1594,9 @@ The following variables are expanded for the `command` tag:
|
|||
|
||||
`%ROM%` - Replaced with the absolute path to the selected ROM, with most special characters escaped with a backslash.
|
||||
|
||||
`%ROMRAW%` - Replaced with the unescaped, absolute path to the selected ROM. If your emulator is picky about paths, you might want to use this instead of %ROM%, but enclosed in quotes.
|
||||
`%ROMRAW%` - Replaced with the unescaped, absolute path to the selected ROM. If your emulator is picky about paths, you might want to use this instead of %ROM%, but enclosed in quotes.
|
||||
|
||||
`%ROMRAWWIN%` - Works just like `%ROMRAW%` except that the forward slashes as directory separators are replaced with backslashes (which is the directory separator used on the Windows operating system). This variable is not available on Windows.
|
||||
|
||||
`%ROMPATH%` - Replaced with the path defined in the setting ROMDirectory in es_settings.xml. If combined with a path that contains blankspaces, then it must be surrounded by quotation marks, for example `%ROMPATH%"\Arcade Games"`. Note that the quotation mark must be located before the directory separator in this case.
|
||||
|
||||
|
@ -1778,9 +1797,9 @@ The es_systems.xml file on Android utilizes variables heavily to implement the _
|
|||
There are two main ways to pass options to emulators, using _extras_ or using the _data_ URI. There can only be a single data URI but there can be an arbitrary amount of extras. To understand more about the way this works, you can read about the _putExtra()_ and and _setData()_ functions here:\
|
||||
https://developer.android.com/reference/android/content/Intent
|
||||
|
||||
`%EXTRA_` - This passes an _extra_ which contains any additional information that the emulator may support. This is provided as a key/value pair where you define the key name following the literal %EXTRA_ string and terminate it with a % sign and then assign the value using an equal sign. For example %EXTRA_LIBRETRO%=puae_libretro_android.so will pass the extra named _LIBRETRO_ with its value set to _puae_libretro_android.so_. You can pass an unlimited number of extras and you can also use various ROM variables in combination with this as described below. It's also possible to use the `%BASENAME%`, `%GAMEDIRRAW%`, `%ROMPATHRAW%` and `%ROMRAW%` variables inside an `%EXTRA_` variable definition, which will expand to the basename of the game file, the directory of the game file, the ROM directory and the path to the game file respectively.
|
||||
`%EXTRA_` - This passes an _extra_ which contains any additional information that the emulator may support. This is provided as a key/value pair where you define the key name following the literal %EXTRA_ string and terminate it with a % sign and then assign the value using an equal sign. For example %EXTRA_LIBRETRO%=puae_libretro_android.so will pass the extra named _LIBRETRO_ with its value set to _puae_libretro_android.so_. You can pass an unlimited number of extras and you can also use various ROM variables in combination with this as described below. It's also possible to use the `%BASENAME%`, `%GAMEDIRRAW%`, `%ROMPATHRAW%`, `%ROMRAW%` and `%ROMRAWWIN%` variables inside an `%EXTRA_` variable definition. This will expand to the basename of the game file, the directory of the game file, the ROM directory, the path to the game file with standard forward slashes as directory separators, and the path to the game file with Windows backslashes as directory separators, respectively.
|
||||
|
||||
`%EXTRAARRAY_` - Defines an array of comma-separated string values following the key name. Only literal strings and special variables are supported, so this can't be used in combination with any ROM variables. As commas are used as separator characters, you'll need to escape any comma signs that you want to include in the actual value. For example %EXTRAARRAY_Parameters%=pone,p\\,two,pthree will pass the extra named _Parameters_ with the three separate array entries _pone_, _p,two_ and _pthree_. It's also possible to use the `%BASENAME%`, `%GAMEDIRRAW%`, `%ROMPATHRAW%` and `%ROMRAW%` variables inside an `%EXTRAARRAY_` variable definition, which will expand to the basename of the game file, the directory of the game file, the ROM directory and the path to the game file respectively.
|
||||
`%EXTRAARRAY_` - Defines an array of comma-separated string values following the key name. Only literal strings and special variables are supported, so this can't be used in combination with any ROM variables. As commas are used as separator characters, you'll need to escape any comma signs that you want to include in the actual value. For example %EXTRAARRAY_Parameters%=pone,p\\,two,pthree will pass the extra named _Parameters_ with the three separate array entries _pone_, _p,two_ and _pthree_. It's also possible to use the `%BASENAME%`, `%GAMEDIRRAW%`, `%ROMPATHRAW%`, `%ROMRAW%` and `%ROMRAWWIN%` variables inside an `%EXTRAARRAY_` variable definition. This will expand to the basename of the game file, the directory of the game file, the ROM directory, the path to the game file with standard forward slashes as directory separators, and the path to the game file with Windows backslashes as directory separators, respectively.
|
||||
|
||||
`%EXTRABOOL_` - Sets an extra with a boolean value, i.e. true/1 or false/0.
|
||||
|
||||
|
@ -2158,23 +2177,30 @@ On Windows it's also possible to place .lnk shortcut files in the event director
|
|||
|
||||
There are up to four parameters that will be passed to these scripts, as detailed below:
|
||||
|
||||
| Event | Parameters* | Description |
|
||||
| :----------------------- | :------------------------------------------------- | :-------------------------------------------------------------------------- |
|
||||
| startup | | Application startup |
|
||||
| quit | | Application quit/shutdown |
|
||||
| reboot | | System reboot (quit event triggered as well) |
|
||||
| poweroff | | System power off (quit event triggered as well) |
|
||||
| config-changed | | On saving application settings or controller configuration |
|
||||
| settings-changed | | On saving application settings (config-changed event triggered as well) |
|
||||
| controls-changed | | On saving controller configuration (config-changed event triggered as well) |
|
||||
| theme-changed | New theme name, old theme name | When manually changing themes in the UI Settings menu |
|
||||
| game-start | ROM path, game name, system name, system full name | On game launch |
|
||||
| game-end | ROM path, game name, system name, system full name | On game end (or on application wakeup if running in the background) |
|
||||
| screensaver-start | _timer_ or _manual_ | Screensaver started via timer or manually |
|
||||
| screensaver-end | _cancel_ or _game-jump_ or _game-start_ | Screensaver ended via cancellation, jump to game or start/launch of game |
|
||||
| Event | Parameters* | Description |
|
||||
| :----------------------- | :------------------------------------------------- | :------------------------------------------------------------------------------------------------ |
|
||||
| startup | | Application startup |
|
||||
| quit | | Application quit/shutdown |
|
||||
| reboot | | System reboot (quit event triggered as well) |
|
||||
| poweroff | | System power off (quit event triggered as well) |
|
||||
| config-changed | | On saving application settings or controller configuration |
|
||||
| settings-changed | | On saving application settings (config-changed event triggered as well) |
|
||||
| controls-changed | | On saving controller configuration (config-changed event triggered as well) |
|
||||
| theme-changed | New theme name, old theme name | When manually changing themes in the UI Settings menu |
|
||||
| game-start | ROM path, game name, system name, system full name | On game launch |
|
||||
| game-end | ROM path, game name, system name, system full name | On game end (or on application wakeup if running in the background) |
|
||||
| screensaver-start | _timer_ or _manual_ | Screensaver started via timer or manually |
|
||||
| screensaver-end | _cancel_ or _game-jump_ or _game-start_ | Screensaver ended via cancellation, jump to game or start/launch of game |
|
||||
| screensaver-game-select | ROM path, game name, system name, system full name | Screensaver selected a new random game |
|
||||
| game-select | ROM path, game name, system name, system full name | On browsing games in the gamelist view, requires enabling of the _Browsing custom events_ setting |
|
||||
| system-select | System name, system full name, system ROM path | On browsing systems in the system view, requires enabling of the _Browsing custom events_ setting |
|
||||
|
||||
***)** Parameters in _italics_ are literal strings.
|
||||
|
||||
Note that the _game-select_ and _system-select_ events require that the _Browsing custom events_ option in the Other settings menu is enabled. Also note that enabling this could lead to a lot of latency in the application as the event is triggered so frequently. So only enable these events if you really need them. And if you do, then make sure to execute scripts that run their activities in the background and immediately return to ES-DE, rather than blocking ES-DE during the script execution.
|
||||
|
||||
For the _game-select_ event, when starting to fast scroll in the gamelist view, an event containing blank parameters will be triggered so that you can detect this state.
|
||||
|
||||
We'll go through two examples:
|
||||
* Creating a log file that will record the start and end time for each game we play, letting us see how much time we spend on retro-gaming
|
||||
* Changing the system resolution when launching and returning from a game in order to run the emulator at a lower resolution than ES-DE
|
||||
|
|
|
@ -460,7 +460,7 @@ The first time you run haikuporter it will take a while as dependencies for all
|
|||
|
||||
Following this you can install the package into the running system:
|
||||
```
|
||||
cp ~/haikuports/packages/es_de-3.1.0-1-x86_64.hpkg /boot/system/packages
|
||||
cp ~/haikuports/packages/es_de-3.1.1-1-x86_64.hpkg /boot/system/packages
|
||||
```
|
||||
|
||||
## Building on macOS
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2024 Northwestern Software AB
|
||||
Copyright (c) 2024-2025 Northwestern Software AB
|
||||
Copyright (c) 2020-2024 Leon Styhre
|
||||
Copyright (c) 2014 Alec Lofquist
|
||||
|
||||
|
|
355
THEMES-DEV.md
355
THEMES-DEV.md
|
@ -253,6 +253,26 @@ git remote add system-logos https://gitlab.com/es-de/themes/system-logos.git
|
|||
```
|
||||
After doing this you'll be able to pull repository updates as described above.
|
||||
|
||||
### External repositories
|
||||
|
||||
In addition to the official asset repositories there are some external theme resources that are not maintained by the ES-DE project.
|
||||
|
||||
System icon set by Zoidburg:
|
||||
|
||||
https://github.com/Zoidburg13/ES-DE-System-Icon-Set
|
||||
|
||||
Console/system logos by Dan Patrick (GitHub mirror, not officially maintained by Patrick):
|
||||
|
||||
https://github.com/PRO100BYTE/console-logos
|
||||
|
||||
High-resolution photos of classic gaming hardware:
|
||||
|
||||
https://commons.wikimedia.org/wiki/User:Evan-Amos
|
||||
|
||||
Large set of controller and game cartridge images in SVG and PNG formats:
|
||||
|
||||
https://archive.org/details/@pineapple_graphics
|
||||
|
||||
## Simple example theme
|
||||
|
||||
Here is a very simple theme that changes the color of the game name text:
|
||||
|
@ -771,6 +791,7 @@ The following languages are supported:
|
|||
| ja_JP | Japanese | 日本語 |
|
||||
| ko_KR | Korean | 한국어 |
|
||||
| zh_CN | Simplified Chinese | 简体中文 |
|
||||
| zh_TW | Traditional Chinese | 繁體中文 |
|
||||
|
||||
Note that the native name is what is shown inside the _UI Settings_ menu for the _Theme Language_ and _Application Language_ settings.
|
||||
|
||||
|
@ -1188,6 +1209,7 @@ Unlike the types just mentioned, aspectRatio entries can not be set to arbitrary
|
|||
| 3:2 | 3:2_vertical | 2160x1440 |
|
||||
| 4:3 | 4:3_vertical | 320x240, 640x480, 800x600, 1024x768, 1600x1200 |
|
||||
| 5:4 | 5:4_vertical | 1280x1024 |
|
||||
| 8:7 | 8:7_vertical | 1240x1080 |
|
||||
| 19.5:9 | 19.5:9_vertical | 2340x1080, 2532x1170 |
|
||||
| 20:9 | 20:9_vertical | 2400x1080, 1600x720 |
|
||||
| 21:9 | 21:9_vertical | 2560x1080, 3840x1600, 5120x2160 |
|
||||
|
@ -1935,7 +1957,7 @@ Properties:
|
|||
- Default is `1.5`
|
||||
- This property can only be used when `textHorizontalScrolling` has been set to `true`
|
||||
* `fontPath` - type: PATH
|
||||
- Path to a TrueType font (.ttf) used as fallback if there is no `staticImage` / `imageType` image defined or found, and if `defaultImage` has not been defined.
|
||||
- Path to a TrueType or OpenType font (.ttf or .otf) used as fallback if there is no `staticImage` / `imageType` image defined or found, and if `defaultImage` has not been defined.
|
||||
* `fontSize` - type: FLOAT
|
||||
- Size of the font as a percentage of screen height for horizontally oriented screens or screen width for vertically oriented screens (e.g. for a value of `0.1`, the text's height would be 10% of the screen height). This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area. This property value is effectively multiplied by the `itemScale` value for the currently selected item (but if this property is omitted then the default value will not get multiplied by `itemScale`).
|
||||
- Minimum value is `0.001` and maximum value is `1.5`. Note that when running at a really low resolution, the minimum value may get clamped to a larger relative size.
|
||||
|
@ -2189,7 +2211,7 @@ Properties:
|
|||
- Default is `1.5`
|
||||
- This property can only be used when `textHorizontalScrolling` has been set to `true`
|
||||
* `fontPath` - type: PATH
|
||||
- Path to a TrueType font (.ttf) used as fallback if there is no `staticImage` / `imageType` image defined or found, and if `defaultImage` has not been defined.
|
||||
- Path to a TrueType or OpenType font (.ttf or .otf) used as fallback if there is no `staticImage` / `imageType` image defined or found, and if `defaultImage` has not been defined.
|
||||
* `fontSize` - type: FLOAT
|
||||
- Size of the font as a percentage of screen height for horizontally oriented screens or screen width for vertically oriented screens (e.g. for a value of `0.1`, the text's height would be 10% of the screen height). This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area.
|
||||
- Minimum value is `0.001` and maximum value is `1.5`. Note that when running at a really low resolution, the minimum value may get clamped to a larger relative size.
|
||||
|
@ -2294,7 +2316,7 @@ Properties:
|
|||
- Default is the same value as `selectedColor`
|
||||
* `selectedBackgroundColor` - type: COLOR
|
||||
- Background color of the highlighted entry for the primary entry type. This follows the sizing of the selector bar and is expanded downwards so you'll probably want to adjust its position using `selectorVerticalOffset` if you have defined a custom selector height using `selectorHeight`
|
||||
- Default is `00000000`
|
||||
- Default is `00000000` (no background is drawn)
|
||||
* `selectedSecondaryBackgroundColor` - type: COLOR
|
||||
- Background color of the highlighted entry for the secondary entry type. This follows the sizing of the selector bar and is expanded downwards so you'll probably want to adjust its position using `selectorVerticalOffset` if you have defined a custom selector height using `selectorHeight`
|
||||
- Default is the same value as `selectedBackgroundColor`
|
||||
|
@ -2550,6 +2572,23 @@ Properties:
|
|||
- Minimum value per axis is `0` and maximum value per axis is `1`
|
||||
- Default is `0.5 0.5` (texture is centered)
|
||||
- This property can only be used if `cropSize` is used.
|
||||
* `imageSize` - type: NORMALIZED_PAIR
|
||||
- This property works exactly the same as `size` but applies only to the static image.
|
||||
- Minimum value per axis is `0.01` and maximum value per axis is `2`. If specifying a value outside the allowed range then no attempt will be made to preserve the aspect ratio.
|
||||
- Default is the same value as `size`
|
||||
* `imageMaxSize` - type: NORMALIZED_PAIR
|
||||
- This property works exactly the same as `maxSize` but applies only to the static image.
|
||||
- Minimum value per axis is `0.01` and maximum value per axis is `2`
|
||||
- Default is the same value as `maxSize`
|
||||
* `imageCropSize` - type: NORMALIZED_PAIR
|
||||
- This property works exactly the same as `cropSize` but applies only to the static image.
|
||||
- Minimum value per axis is `0.01` and maximum value per axis is `2`
|
||||
- Default is the same value as `cropSize`
|
||||
* `imageCropPos` - type: NORMALIZED_PAIR
|
||||
- If the static image has been cropped using `imageCropSize` then this property makes it possible to position the texture within the cropped area. The first value of the pair is the X axis where `0` means align to the left and `1` means align to the right, and the second value of the pair is the Y axis where `0` means align on top and `1` means align at the bottom. Any arbitrary floating point values between 0 and 1 can be used for granular positioning.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `1`
|
||||
- Default is `0.5 0.5` (texture is centered)
|
||||
- This property can only be used if `imageCropSize` is used.
|
||||
* `origin` - type: NORMALIZED_PAIR
|
||||
- Where on the element `pos` refers to. For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place the element exactly in the middle of the screen. If the position and size attributes are themeable, origin is implied.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `1`
|
||||
|
@ -2575,7 +2614,7 @@ Properties:
|
|||
* `defaultImage` - type: PATH
|
||||
- Path to a default image file. If the `imageType` property has a value set, then the default image will be displayed if the selected game does not have an image for any of the defined types. If `imageType` is not defined, then the default image will be shown if there is no video file found and if `default` has not been set. This property is also applied to any custom collection that does not contain any games when browsing the grouped custom collections system.
|
||||
* `imageType` - type: STRING
|
||||
- This displays a game image of a certain media type, either before the video starts to play if `delay` is set to a non-zero value, or if there is no video file found and `default` has not been defined. Multiple types can be defined, in which case the entries should be delimited by commas or by whitespace characters (tabs, spaces or line breaks). The media will be searched for in the order that the entries have been defined. If no image is found, then the space will be left blank unless either the `default` or `defaultImage` properties have been set. To use this property from the `system` view, you will first need to add a `gameselector` element. If `delay` is set to zero, then this property has no effect. Defining duplicate values is considered an error and will result in the property getting ignored.
|
||||
- This displays a game image of a certain media type, either before the video starts to play if `delay` is set to a non-zero value, or if there is no video file found and `default` has not been defined. Multiple types can be defined, in which case the entries should be delimited by commas or by whitespace characters (tabs, spaces or line breaks). The media will be searched for in the order that the entries have been defined. If no image is found, then the space will be left blank unless either the `default` or `defaultImage` properties have been set. To use this property from the `system` view, you will first need to add a `gameselector` element. If `delay` is set to zero, then this property has no effect. There is also a special type named `none` which will display no game media, but that will still enable the `delay` property as if game media was present. This makes it possible to leave the space blank during the delay period, or to display an image defined using the `defaultImage` property. Defining duplicate values is considered an error and will result in the property getting ignored.
|
||||
- Valid values:
|
||||
- `image` - This will look for a `miximage`, and if that is not found `screenshot` is tried next, then `titlescreen` and finally `cover`. This is just a convenient shortcut and it's equivalent to explicitly defining `miximage, screenshot, titlescreen, cover`
|
||||
- `miximage` - This will look for a miximage.
|
||||
|
@ -2587,6 +2626,7 @@ Properties:
|
|||
- `3dbox` - This will look for a 3D box image.
|
||||
- `physicalmedia` - This will look for a physical media image.
|
||||
- `fanart` - This will look for a fan art image.
|
||||
- `none` - This will not display any game media, but it will still enable the `defaultImage` and `delay` properties.
|
||||
* `metadataElement` - type: BOOLEAN
|
||||
- By default game metadata and media are faded out during gamelist fast-scrolling and text metadata fields, ratings and badges are hidden when enabling the _Hide metadata fields_ setting for a game entry. Using this property it's possible to explicitly define static video elements that should be treated as if they were game media files. This property is ignored if `path` is not set.
|
||||
- Default is `false`
|
||||
|
@ -2632,8 +2672,9 @@ Properties:
|
|||
- Valid values are `horizontal` or `vertical`
|
||||
- Default is `horizontal`
|
||||
* `pillarboxes` - type: BOOLEAN
|
||||
- Whether to render black pillarboxes (and to a lesses extent letterboxes) for videos with aspect ratios where this is applicable. This is for instance useful for arcade game videos in vertical orientation.
|
||||
- Whether to render black pillarboxes (and to a lesser extent letterboxes) for videos with aspect ratios where this is applicable. This is for instance useful for arcade game videos in vertical orientation.
|
||||
- Default is `true`
|
||||
- This property can only be used if `fadeInType` is set to `black`
|
||||
* `pillarboxThreshold` - type: NORMALIZED_PAIR
|
||||
- Normally it doesn't look very good to add really narrow pillarboxes or letterboxes, so by default they are skipped if the actual video size is not reaching a threshold value as compared to the overall defined video area size. By modifying this property it's possible to control that threshold, as for some theme designs it will look better with the consistency of always rendering the pillarboxes/letterboxes even if they are narrow. To clarify, the default X axis value of 0.85 means that if the video width is 85% or less as compared to the X axis defined by the `size` property, then pillarboxes will be rendered. So setting the `pillarboxThreshold` value to `1 1` will always apply pillarboxes/letterboxes regardless of the video file dimension.
|
||||
- Minimum value per axis is `0.2` and maximum value per axis is `1`
|
||||
|
@ -2645,8 +2686,12 @@ Properties:
|
|||
- Delay in seconds before video will start playing. During the delay period the game image defined via the `imageType` property will be displayed. If that property is not set, then the `delay` property will be ignored.
|
||||
- Minimum value is `0` and maximum value is `15`
|
||||
- Default is `1.5`
|
||||
* `fadeInType` - type: STRING
|
||||
- The method to use when fading in the video. If set to `black` then a black frame is rendered behind the video and the video is faded in on top of this frame. If set to `transparent` then the video is faded in from transparency. The latter will however remove the black frame completely, which also disables the `pillarboxes` property.
|
||||
- Valid values are `black` or `transparent`
|
||||
- Default is `black`
|
||||
* `fadeInTime` - type: FLOAT
|
||||
- Time in seconds to fade in the video from pure black. This is completely unrelated to the `scrollFadeIn` property. Note that if this is set to zero it may seem as if the property doesn't work correctly as many ScreenScraper videos have a fade-in baked into the actual video stream. Setting this property to lower than 0.3 seconds or so is generally a bad idea for videos that don't have a fade-in baked in as transitions from the static image will then look like a bad jump cut.
|
||||
- Time in seconds to fade in the video from pure black, or from transparency depending on what value `fadeInType` is set to. This is completely unrelated to the `scrollFadeIn` property. Note that if this is set to zero it may seem as if the property doesn't work correctly as many ScreenScraper videos have a fade-in baked into the actual video stream. Setting this property to lower than 0.3 seconds or so is generally a bad idea for videos that don't have a fade-in baked in as transitions from the static image will then look like a bad jump cut.
|
||||
- Minimum value is `0` and maximum value is `8`
|
||||
- Default is `1`
|
||||
* `scrollFadeIn` - type: BOOLEAN
|
||||
|
@ -2837,9 +2882,10 @@ Properties:
|
|||
- Minimum value is `0.1` and maximum value is `2`
|
||||
- Default is `0.5`
|
||||
* `customBadgeIcon` - type: PATH
|
||||
- A badge icon override. Specify the badge type in the attribute `badge`. The available badges are the ones listed above.
|
||||
- A badge icon override. Specify the badge type using the `badge` attribute, such as `<customBadgeIcon badge="favorite">./assets/favorite.svg</customBadgeIcon>`
|
||||
- The available badges are the ones listed above.
|
||||
* `customControllerIcon` - type: PATH
|
||||
- A controller icon override. Specify the controller type in the attribute `controller`.
|
||||
- A controller icon override. Specify the controller type using the `controller` attribute, such as `<customControllerIcon controller="gamepad_xbox">./assets/gamepad_xbox.svg</customControllerIcon>`
|
||||
- These are the available types:
|
||||
- `gamepad_generic`,
|
||||
`gamepad_nintendo_nes`,
|
||||
|
@ -3060,7 +3106,7 @@ Properties:
|
|||
- Default is `1.5`
|
||||
- This property can only be used when `containerType` is `horizontal`
|
||||
* `fontPath` - type: PATH
|
||||
- Path to a TrueType font (.ttf).
|
||||
- Path to a TrueType or OpenType font (.ttf or .otf)
|
||||
* `fontSize` - type: FLOAT
|
||||
- Size of the font as a percentage of screen height for horizontally oriented screens or screen width for vertically oriented screens (e.g. for a value of `0.1`, the text's height would be 10% of the screen height). This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area.
|
||||
- Minimum value is `0.001` and maximum value is `1.5`. Note that when running at a really low resolution, the minimum value may get clamped to a larger relative size. The font is allowed to overflow the height of the element by 100%, i.e. `fontSize` can be set to twice that of the y axis of the `size` property. Any value above that will be clamped.
|
||||
|
@ -3077,7 +3123,7 @@ Properties:
|
|||
* `color` - type: COLOR
|
||||
- Default is `000000FF`
|
||||
* `backgroundColor` - type: COLOR
|
||||
- Default is `00000000`
|
||||
- Default is `00000000` (no background is drawn)
|
||||
* `backgroundMargins` - type: NORMALIZED_PAIR
|
||||
- Adds margins to the text background, assuming it has a color set. The first value of the pair is the left margin and the second value is the right margin, which means it's possible to set these margins completely independently. Margins are applied after all other positioning and sizing calculations and they are rendered outside the text debug rectangle boundaries.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `0.5`
|
||||
|
@ -3156,7 +3202,7 @@ Properties:
|
|||
- Minimum value is `0` and maximum value is the value of the `gameselector` element property `gameCount` minus 1. If a value outside this range is defined, then it will be automatically clamped to a valid value.
|
||||
- Default is `0`
|
||||
* `fontPath` - type: PATH
|
||||
- Path to a TrueType font (.ttf).
|
||||
- Path to a TrueType or OpenType font (.ttf or .otf)
|
||||
* `fontSize` - type: FLOAT
|
||||
- Size of the font as a percentage of screen height for horizontally oriented screens or screen width for vertically oriented screens (e.g. for a value of `0.1`, the text's height would be 10% of the screen height). This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area.
|
||||
- Minimum value is `0.001` and maximum value is `1.5`. Note that when running at a really low resolution, the minimum value may get clamped to a larger relative size. The font is allowed to overflow the height of the element by 100%, i.e. `fontSize` can be set to twice that of the y axis of the `size` property. Any value above that will be clamped.
|
||||
|
@ -3247,7 +3293,7 @@ Properties:
|
|||
- `never` - Don't set element as stationary during any transitions.
|
||||
- Default is `never`
|
||||
* `fontPath` - type: PATH
|
||||
- Path to a TrueType font (.ttf).
|
||||
- Path to a TrueType or OpenType font (.ttf or .otf)
|
||||
* `fontSize` - type: FLOAT
|
||||
- Size of the font as a percentage of screen height for horizontally oriented screens or screen width for vertically oriented screens (e.g. for a value of `0.1`, the text's height would be 10% of the screen height). This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area.
|
||||
- Minimum value is `0.001` and maximum value is `1.5`. Note that when running at a really low resolution, the minimum value may get clamped to a larger relative size. The font is allowed to overflow the height of the element by 100%, i.e. `fontSize` can be set to twice that of the y axis of the `size` property. Any value above that will be clamped.
|
||||
|
@ -3375,58 +3421,103 @@ Properties:
|
|||
|
||||
#### helpsystem
|
||||
|
||||
The helpsystem is a special element that displays a context-sensitive list of actions the user can take at any time. You should try and keep the position constant throughout every screen. Note that this element does not have a zIndex value, instead it's always rendered on top of all other elements. It also has to have its name attribute set to `help` or the configuration will not get loaded.
|
||||
The helpsystem is a special element that displays a context-sensitive list of actions the user can take at any time. You should try and keep the position constant throughout every screen. Note that this element does not have a zIndex value, instead it's always rendered on top of all other elements (but below the menu).
|
||||
|
||||
It's possible to set this element as right-aligned or center-aligned using a combination of the `pos` and `origin` properties. For example `<pos>1 1</pos>` and `<origin>1 1</origin>` will place it in the lower right corner of the screen.
|
||||
|
||||
Keep in mind that the width of this element can vary depending on a number of factors, for example the _Toggle favorites_ and _Random system or game_ buttons can be enabled or disabled via the _UI Settings_ menu. Test extensively with the menu system as well, especially the virtual keyboard which displays a number of helpsystem entries.
|
||||
|
||||
Using the `entries` property it's possible to restrict which help entries to display, and it's also possible to create multiple helpsystem elements and split up the entries between them.
|
||||
|
||||
Note however that you can't display the same icon file for multiple elements, if you attempt to do this then the icon will only be shown for one of the elements. This is due to internal optimizations to reduce latency when updating the helpsystem. But there is a workaround available by using separate icon files and loading them via the `customButtonIcon` property. As long as they are separate files it will be possible to load them and make it seem like the same icon file is displayed for multiple elements.
|
||||
|
||||
Supported views:
|
||||
* `system`
|
||||
* `gamelist`
|
||||
|
||||
Instances per view:
|
||||
* `single`
|
||||
* `unlimited`
|
||||
|
||||
Properties:
|
||||
* `pos` - type: NORMALIZED_PAIR
|
||||
- Default is `0.012 0.9515` for horizontally oriented screens and `0.012 0.975` for vertically oriented screens
|
||||
* `posDimmed` - type: NORMALIZED_PAIR
|
||||
- Position when a menu is open (background is dimmed).
|
||||
- Position when a menu is open (background is dimmed). This property mostly exists for backward compatibility purposes, the recommended approach is to setup a separate helpsystem element with `scope` set to `menu`
|
||||
- Default is the same value as `pos`
|
||||
* `origin` - type: NORMALIZED_PAIR
|
||||
- Where on the element `pos` refers to. For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place the element exactly in the middle of the screen.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `1`
|
||||
- Default is `0 0`
|
||||
* `originDimmed` - type: NORMALIZED_PAIR
|
||||
- Origin when a menu is open (background is dimmed).
|
||||
- Origin when a menu is open (background is dimmed). This property mostly exists for backward compatibility purposes, the recommended approach is to setup a separate helpsystem element with `scope` set to `menu`
|
||||
- Minimum value per axis is `0` and maximum value per axis is `1`
|
||||
- Default is the same value as `origin`
|
||||
* `rotation` - type: FLOAT
|
||||
- Angle in degrees that the element should be rotated. Positive values will rotate clockwise, negative values will rotate counterclockwise.
|
||||
- Default is `0`
|
||||
* `rotationOrigin` - type: NORMALIZED_PAIR
|
||||
- Point around which the element will be rotated.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `1`
|
||||
- Default is `0.5 0.5`
|
||||
* `textColor` - type: COLOR
|
||||
- Default is `777777FF`
|
||||
* `textColorDimmed` - type: COLOR
|
||||
- Text color when a menu is open (background is dimmed).
|
||||
- Text color when a menu is open (background is dimmed). This property mostly exists for backward compatibility purposes, the recommended approach is to setup a separate helpsystem element with `scope` set to `menu`
|
||||
- Default is the same value as `textColor`
|
||||
* `iconColor` - type: COLOR
|
||||
- Default is `777777FF`
|
||||
* `iconColorDimmed` - type: COLOR
|
||||
- Icon color when a menu is open (background is dimmed).
|
||||
- Icon color when a menu is open (background is dimmed). This property mostly exists for backward compatibility purposes, the recommended approach is to setup a separate helpsystem element with `scope` set to `menu`
|
||||
- Default is the same value as `iconColor`
|
||||
* `fontPath` - type: PATH
|
||||
* `fontSize` - type: FLOAT
|
||||
- This property implicitly sets the icon size and is therefore the means to change the overall size of the helpsystem element. This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area.
|
||||
- This property implicitly sets the text and icon size and is therefore the means to change the overall size of the helpsystem element. This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area.
|
||||
- Minimum value is `0.001` and maximum value is `1.5`. Note that when running at a really low resolution, the minimum value may get clamped to a larger relative size.
|
||||
- Default is `0.035` for horizontally oriented screens and `0.025` for vertically oriented screens
|
||||
* `fontSizeDimmed` - type: FLOAT
|
||||
- Font size when a menu is open (background is dimmed).
|
||||
- Font size when a menu is open (background is dimmed). This property mostly exists for backward compatibility purposes, the recommended approach is to setup a separate helpsystem element with `scope` set to `menu`
|
||||
- Minimum value is `0.001` and maximum value is `1.5`. Note that when running at a really low resolution, the minimum value may get clamped to a larger relative size.
|
||||
- Default is the same value as `fontSize`
|
||||
* `scope` - type: STRING
|
||||
- This property makes it possible to specify when the helpsystem element should be displayed. If it's set to `view` then it will only be displayed in the system and gamelist views and will be hidden when the menu is open. The opposite is true if it's set to `menu`, in this case the element will only be shown when the menu is open. Setting the property to `shared` will display the element both in the system and gamelist views and when the menu is open. Finally, setting it to `none` will not display the element at all, which is useful for special cases where there is shared configuration between multiple elements and you wish to disable one or more of these elements per view.
|
||||
- Valid values are `shared`, `view`, `menu` or `none`
|
||||
- Default is `shared`
|
||||
* `entries` - type: STRING
|
||||
- This property controls which help entries that should be displayed, which can for instance be useful for narrow aspect ratio displays where all entries would otherwise not fit on screen. The entries are specified as a list of strings delimited by commas or by whitespace characters (tabs, spaces or line breaks). These are the available entries:\
|
||||
`all`,
|
||||
`back`,
|
||||
`start`,
|
||||
`a`,
|
||||
`b`,
|
||||
`x`,
|
||||
`y`,
|
||||
`l`,
|
||||
`r`,
|
||||
`lt`,
|
||||
`rt`,
|
||||
`left/right`,
|
||||
`down`,
|
||||
`up`,
|
||||
`up/down`,
|
||||
`up/down/left/right`,
|
||||
`ltrt`,
|
||||
`lr`,
|
||||
`thumbstickclick`
|
||||
- Default is `all` which displays all entries
|
||||
* `entryLayout` - type: STRING
|
||||
- Controls the layout of the individual help element pairs. If set to `iconFirst` then the icon is shown to the left followed by the text, and if set to `textFirst` then the text is shown to the left followed by the icon.
|
||||
- Valid values are `iconFirst` or `textFirst`
|
||||
- Default is `iconFirst`
|
||||
* `entryRelativeScale` - type: FLOAT
|
||||
- Defines the relative scale between the text and icons. If set to a value higher than `1` then the text will maintain its default size and the icons will be scaled down, and if set to a value lower than `1` then the icons will maintain their default size and the text will be scaled down. Note that regardless of what value this property is set to, the overall height of the element will always be defined by the `fontSize` property.
|
||||
- Minimum value is `0.2` and maximum value is `3`
|
||||
- Default is `1` (text and icons are set to the same scale)
|
||||
* `entrySpacing` - type: FLOAT
|
||||
- Spacing between the help element pairs.
|
||||
- Minimum value is `0` and maximum value is `0.04`
|
||||
- Default is `0.00833`
|
||||
* `entrySpacingDimmed` - type: FLOAT
|
||||
- Spacing between the help element pairs when a menu is open (background is dimmed).
|
||||
- Spacing between the help element pairs when a menu is open (background is dimmed). This property mostly exists for backward compatibility purposes, the recommended approach is to setup a separate helpsystem element with `scope` set to `menu`
|
||||
- Minimum value is `0` and maximum value is `0.04`
|
||||
- Default is the same value as `entrySpacing`
|
||||
* `iconTextSpacing` - type: FLOAT
|
||||
|
@ -3434,22 +3525,46 @@ Properties:
|
|||
- Minimum value is `0` and maximum value is `0.04`
|
||||
- Default is `0.00416`
|
||||
* `iconTextSpacingDimmed` - type: FLOAT
|
||||
- Spacing between the icon and text within a help element pair when a menu is open (background is dimmed).
|
||||
- Spacing between the icon and text within a help element pair when a menu is open (background is dimmed). This property mostly exists for backward compatibility purposes, the recommended approach is to setup a separate helpsystem element with `scope` set to `menu`
|
||||
- Minimum value is `0` and maximum value is `0.04`
|
||||
- Default is the same value as `iconTextSpacing`
|
||||
* `letterCase` - type: STRING
|
||||
- Valid values are `uppercase`, `lowercase` or `capitalize`
|
||||
- Default is `uppercase`
|
||||
* `backgroundColor` - type: COLOR
|
||||
- Default is `00000000` (no background is drawn)
|
||||
* `backgroundColorEnd` - type: COLOR
|
||||
- Works in the exact same way as `backgroundColor` but can be set as the end color to apply a color gradient.
|
||||
- Default is the same value as `backgroundColor`
|
||||
* `backgroundGradientType` - type: STRING
|
||||
- The direction to apply the color gradient if both `backgroundColor` and `backgroundColorEnd` have been defined.
|
||||
- Valid values are `horizontal` or `vertical`
|
||||
- Default is `horizontal`
|
||||
* `backgroundHorizontalPadding` - type: NORMALIZED_PAIR
|
||||
- This property makes it possible to apply a horizontal padding around the element if `backgroundColor` has been defined. Note that this additional sizing will not have any effect on the `pos` and `origin` properties, these will remain constant. Or in other words, changing the `backgroundHorizontalPadding` property value will not change the position of the overall element. The first value of the pair is the padding to the left of the element and the second value of the pair is the padding to the right of the element.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `0.2`
|
||||
- Default is `0 0`
|
||||
- This property can only be used if `backgroundColor` has a value defined.
|
||||
* `backgroundVerticalPadding` - type: NORMALIZED_PAIR
|
||||
- This property makes it possible to apply a vertical padding around the element if `backgroundColor` has been defined. Note that this additional sizing will not have any effect on the `pos` and `origin` properties, these will remain constant. Or in other words, changing the `backgroundVerticalPadding` property value will not change the position of the overall element. The first value of the pair is the padding at the top of the element and the second value of the pair is the padding at the bottom of the element.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `0.2`
|
||||
- Default is `0 0`
|
||||
- This property can only be used if `backgroundColor` has a value defined.
|
||||
* `backgroundCornerRadius` - type: FLOAT
|
||||
- Setting this property higher than zero applies rounded corners to the element background, assuming it has a color set. The radius is a percentage of the screen width. Note that the maximum allowed value is quite arbitrary as the renderer will in practice limit the maximum roundness so it can never go beyond half the background height. It means that setting this property sufficiently high will produce perfectly rounded sides for the background. You normally want to combine this property with `backgroundHorizontalPadding` and `backgroundVerticalPadding` to first add some extra space around the helpsystem.
|
||||
- Minimum value is `0` and maximum value is `0.5`
|
||||
- Default is `0` (corners are not rounded)
|
||||
- This property can only be used if `backgroundColor` has a value defined.
|
||||
* `opacity` - type: FLOAT
|
||||
- Controls the level of transparency.
|
||||
- Minimum value is `0.2` and maximum value is `1`
|
||||
- Default is `1`
|
||||
* `opacityDimmed` - type: FLOAT
|
||||
- Controls the level of transparency when a menu is open (background is dimmed).
|
||||
- Controls the level of transparency when a menu is open (background is dimmed). This property mostly exists for backward compatibility purposes, the recommended approach is to setup a separate helpsystem element with `scope` set to `menu`
|
||||
- Minimum value is `0.2` and maximum value is `1`
|
||||
- Default is the same value as `opacity`
|
||||
* `customButtonIcon` - type: PATH
|
||||
- A button icon override. Specify the button type in the attribute `button`.
|
||||
- A button icon override. Specify the button type using the `button` attribute, such as `<customButtonIcon button="button_a_XBOX">./assets/button_a_XBOX.svg</customButtonIcon>`
|
||||
- The available buttons are: \
|
||||
`dpad_updown`,
|
||||
`dpad_leftright`,
|
||||
|
@ -3491,3 +3606,195 @@ Properties:
|
|||
`button_y_SNES`,
|
||||
`button_back_SNES`,
|
||||
`button_start_SNES`
|
||||
|
||||
#### systemstatus
|
||||
|
||||
Displays system status indicators, more specifically Bluetooth, Wi-Fi, cellular and battery status.
|
||||
|
||||
Note that this element does not have a zIndex value, instead it's always rendered on top of all other elements and it's also rendered when the menu is open. In addition to this it's stationary and will not move during slide transitions or fade out during fade transitions.
|
||||
|
||||
You can define multiple elements to split up the indicators.
|
||||
|
||||
During theme development you can force-enable all the system indicators by setting SystemStatusDisplayAll to true in es_settings.xml, you can read more about this option in the [INSTALL-DEV.md](INSTALL-DEV.md#settings-not-configurable-via-the-gui) document.
|
||||
|
||||
Supported views:
|
||||
* `system`
|
||||
* `gamelist`
|
||||
|
||||
Instances per view:
|
||||
* `unlimited`
|
||||
|
||||
Properties:
|
||||
* `pos` - type: NORMALIZED_PAIR
|
||||
- Default is `0.982 0.016`
|
||||
* `height` - type: FLOAT
|
||||
- The sizing for this element works a bit different compared to most other elements as the width is automatically calculated based on the aspect ratio of the indicator icons plus the value set for the `entrySpacing` property. And in order to keep sizing consistent across horizontal and vertical screen orientations and to also align with the sizing logic used by the `helpsystem` and `clock` elements, the `height` property works similarly to the `fontSize` property used by those elements. This means the actual height calculation in pixels is made as a percentage of the screen height for horizontally oriented screens or the screen width for vertically oriented screens.
|
||||
- Minimum value is `0.01` and maximum value is `0.5`
|
||||
- Default is `0.035`
|
||||
* `origin` - type: NORMALIZED_PAIR
|
||||
- Where on the element `pos` refers to. For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place the element exactly in the middle of the screen.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `1`
|
||||
- Default is `1 0`
|
||||
* `rotation` - type: FLOAT
|
||||
- Angle in degrees that the element should be rotated. Positive values will rotate clockwise, negative values will rotate counterclockwise.
|
||||
- Default is `0`
|
||||
* `rotationOrigin` - type: NORMALIZED_PAIR
|
||||
- Point around which the element will be rotated.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `1`
|
||||
- Default is `0.5 0.5`.
|
||||
* `scope` - type: STRING
|
||||
- This property makes it possible to specify when the systemstatus element should be displayed. If it's set to `view` then it will only be displayed in the system and gamelist views and will be hidden when the menu is open. The opposite is true if it's set to `menu`, in this case the element will only be shown when the menu is open. Setting the property to `shared` will display the element both in the system and gamelist views and when the menu is open. Finally, setting it to `none` will not display the element at all, which is useful for special cases where there is shared configuration between multiple elements and you wish to disable one or more of these elements per view.
|
||||
- Valid values are `shared`, `view`, `menu` or `none`
|
||||
- Default is `shared`
|
||||
* `fontPath` - type: PATH
|
||||
- Path to a TrueType or OpenType font (.ttf or .otf) which is used for the battery percentage indicator.
|
||||
* `textRelativeScale` - type: FLOAT.
|
||||
- This property makes it possible to size the battery percentage text relative to the overall element height, or in other words relative to the height of the indicator icons.
|
||||
- Minimum value is `0.5` and maximum value is `1`
|
||||
- Default is `0.9`
|
||||
* `color` - type: COLOR
|
||||
- Color of the icons and battery percentage text.
|
||||
- Default is `FFFFFFFF`
|
||||
* `backgroundColor` - type: COLOR
|
||||
- If this property is defined then a colored rectangle is drawn behind the entire element.
|
||||
- Default is `00000000` (no background is drawn)
|
||||
* `backgroundColorEnd` - type: COLOR
|
||||
- Works in the exact same way as `backgroundColor` but can be set as the end color to apply a color gradient.
|
||||
- Default is the same value as `backgroundColor`
|
||||
* `backgroundGradientType` - type: STRING
|
||||
- The direction to apply the color gradient if both `backgroundColor` and `backgroundColorEnd` have been defined.
|
||||
- Valid values are `horizontal` or `vertical`
|
||||
- Default is `horizontal`
|
||||
* `backgroundHorizontalPadding` - type: NORMALIZED_PAIR
|
||||
- This property makes it possible to apply a horizontal padding around the element if `backgroundColor` has been defined. Note that this additional sizing will not have any effect on the `pos` and `origin` properties, these will remain constant. Or in other words, changing the `backgroundHorizontalPadding` property value will not change the position of the overall element. The first value of the pair is the padding to the left of the element and the second value of the pair is the padding to the right of the element.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `0.2`
|
||||
- Default is `0 0`
|
||||
- This property can only be used if `backgroundColor` has a value defined.
|
||||
* `backgroundVerticalPadding` - type: NORMALIZED_PAIR
|
||||
- This property makes it possible to apply a vertical padding around the element if `backgroundColor` has been defined. Note that this additional sizing will not have any effect on the `pos` and `origin` properties, these will remain constant. Or in other words, changing the `backgroundVerticalPadding` property value will not change the position of the overall element. The first value of the pair is the padding at the top of the element and the second value of the pair is the padding at the bottom of the element.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `0.2`
|
||||
- Default is `0 0`
|
||||
- This property can only be used if `backgroundColor` has a value defined.
|
||||
* `backgroundCornerRadius` - type: FLOAT
|
||||
- Setting this property higher than zero applies rounded corners to the element background, assuming `backgroundColor` has been defined. The radius is a percentage of the screen width. Note that the maximum allowed value is quite arbitrary as the renderer will in practice limit the maximum roundness so it can never go beyond half the background height. It means that setting this property sufficiently high will produce perfectly rounded sides for the element background. You normally want to combine this property with `backgroundHorizontalPadding` and `backgroundVerticalPadding` to first add some extra space around the system indicators.
|
||||
- Minimum value is `0` and maximum value is `0.5`
|
||||
- Default is `0` (corners are not rounded)
|
||||
- This property can only be used if `backgroundColor` has a value defined.
|
||||
* `entries` - type: STRING
|
||||
- The system indicators that should be displayed. Make sure to always display all entries as it's up to the user to disable any unwanted indicators from the UI settings menu. The sole purpose of this property is to be able to split up the indicators across multiple elements. The entries are specified as a list of strings delimited by commas or by whitespace characters (tabs, spaces or line breaks). The order in which the entries are defined has no effect as they will always be displayed in the default order. Available values are:
|
||||
- `bluetooth` - Indicates whether there's a Bluetooth adapter enabled on the device
|
||||
- `wifi` - Indicates whether Wi-Fi is enabled on the device
|
||||
- `cellular` - Indicates whether cellular traffic is enabled on the device (Android only)
|
||||
- `battery` - Indicates whether there's a battery available in the device, in which case different icons will be displayed if the battery is charging or not, and if not charging there are discreet icons for different capacity levels (low, medium, high and full). A capacity percentage text is also displayed next to the battery icon unless the user has disabled this in the UI settings menu.
|
||||
- `all` - Including this value will enable all system indicators.
|
||||
- Default is `all`
|
||||
* `entrySpacing` - type: FLOAT
|
||||
- Spacing between the system indicators. Note that this spacing is not applied between the battery icon and the battery percentage text.
|
||||
- Minimum value is `0` and maximum value is `0.04`
|
||||
- Default is `0.005`
|
||||
* `customIcon` - type: PATH
|
||||
- An icon override. Specify the icon type using the `icon` attribute, such as `<customIcon icon="icon_wifi">./assets/wifi.svg</customIcon>`
|
||||
- The available icons are: \
|
||||
`icon_bluetooth`,
|
||||
`icon_wifi`,
|
||||
`icon_cellular`,
|
||||
`icon_battery_charging`,
|
||||
`icon_battery_low`,
|
||||
`icon_battery_medium`,
|
||||
`icon_battery_high`,
|
||||
`icon_battery_full`
|
||||
* `opacity` - type: FLOAT
|
||||
- Controls the level of transparency.
|
||||
- Minimum value is `0` and maximum value is `1`
|
||||
- Default is `1`
|
||||
|
||||
#### clock
|
||||
|
||||
Displays the current time and/or date as a text string. The format is HH:MM by default, but this can be changed using the `format` property. It's strongly recommended to configure the clock identically for both the system and gamelist views to make the user experience coherent.
|
||||
|
||||
Note that this element does not have a zIndex value, instead it's always rendered on top of all other elements and it's also rendered when the menu is open. In addition to this it's stationary and will not move during slide transitions or fade out during fade transitions.
|
||||
|
||||
You can define multiple elements to for instance display the date on one side of the screen and the time on the other side of the screen.
|
||||
|
||||
Supported views:
|
||||
* `system`
|
||||
* `gamelist`
|
||||
|
||||
Instances per view:
|
||||
* `unlimited`
|
||||
|
||||
Properties:
|
||||
* `pos` - type: NORMALIZED_PAIR
|
||||
- Default is `0.018 0.016`
|
||||
* `size` - type: NORMALIZED_PAIR
|
||||
- Possible combinations:
|
||||
- `0 0` - automatically size so text fits on one line (expanding horizontally).
|
||||
- `w 0` - automatically wrap text so it doesn't go beyond `w` (expanding vertically).
|
||||
- `w h` - works like a "text box". If `h` is non-zero and `h` <= `fontSize` (implying it should be a single line of text), text that goes beyond `w` will be truncated with an ellipsis (...)
|
||||
* `origin` - type: NORMALIZED_PAIR
|
||||
- Where on the element `pos` refers to. For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place the element exactly in the middle of the screen. If the position and size attributes are themeable, origin is implied.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `1`
|
||||
- Default is `0 0`
|
||||
* `rotation` - type: FLOAT
|
||||
- Angle in degrees that the element should be rotated. Positive values will rotate clockwise, negative values will rotate counterclockwise.
|
||||
- Default is `0`
|
||||
* `rotationOrigin` - type: NORMALIZED_PAIR
|
||||
- Point around which the element will be rotated.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `1`
|
||||
- Default is `0.5 0.5`.
|
||||
* `scope` - type: STRING
|
||||
- This property makes it possible to specify when the clock element should be displayed. If it's set to `view` then it will only be displayed in the system and gamelist views and will be hidden when the menu is open. The opposite is true if it's set to `menu`, in this case the element will only be shown when the menu is open. Setting the property to `shared` will display the element both in the system and gamelist views and when the menu is open. Finally, setting it to `none` will not display the element at all, which is useful for special cases where there is shared configuration between multiple elements and you wish to disable one or more of these elements per view.
|
||||
- Valid values are `shared`, `view`, `menu` or `none`
|
||||
- Default is `shared`
|
||||
* `fontPath` - type: PATH
|
||||
- Path to a TrueType or OpenType font (.ttf or .otf)
|
||||
* `fontSize` - type: FLOAT
|
||||
- Size of the font as a percentage of screen height for horizontally oriented screens or screen width for vertically oriented screens (e.g. for a value of `0.1`, the text's height would be 10% of the screen height). This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area.
|
||||
- Minimum value is `0.001` and maximum value is `1.5`. Note that when running at a really low resolution, the minimum value may get clamped to a larger relative size. The font is allowed to overflow the height of the element by 100%, i.e. `fontSize` can be set to twice that of the y axis of the `size` property. Any value above that will be clamped.
|
||||
- Default is `0.035`
|
||||
* `horizontalAlignment` - type: STRING
|
||||
- Controls alignment on the X axis.
|
||||
- Valid values are `left`, `center` or `right`
|
||||
- Default is `left`
|
||||
* `verticalAlignment` - type: STRING
|
||||
- Controls alignment on the Y axis.
|
||||
- Valid values are `top`, `center` or `bottom`
|
||||
- Default is `center`
|
||||
* `color` - type: COLOR
|
||||
- Default is `FFFFFFFF`
|
||||
* `backgroundColor` - type: COLOR
|
||||
- Default is `00000000` (no background is drawn)
|
||||
* `backgroundColorEnd` - type: COLOR
|
||||
- Works in the exact same way as `backgroundColor` but can be set as the end color to apply a color gradient.
|
||||
- Default is the same value as `backgroundColor`
|
||||
* `backgroundGradientType` - type: STRING
|
||||
- The direction to apply the color gradient if both `backgroundColor` and `backgroundColorEnd` have been defined.
|
||||
- Valid values are `horizontal` or `vertical`
|
||||
- Default is `horizontal`
|
||||
* `backgroundHorizontalPadding` - type: NORMALIZED_PAIR
|
||||
- This property makes it possible to apply a horizontal padding around the element if `backgroundColor` has been defined. Note that this additional sizing will not have any effect on the `pos` and `origin` properties, these will remain constant. Or in other words, changing the `backgroundHorizontalPadding` property value will not change the position of the overall element. The first value of the pair is the padding to the left of the element and the second value of the pair is the padding to the right of the element.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `0.2`
|
||||
- Default is `0 0`
|
||||
- This property can only be used if `backgroundColor` has a value defined.
|
||||
* `backgroundVerticalPadding` - type: NORMALIZED_PAIR
|
||||
- This property makes it possible to apply a vertical padding around the element if `backgroundColor` has been defined. Note that this additional sizing will not have any effect on the `pos` and `origin` properties, these will remain constant. Or in other words, changing the `backgroundVerticalPadding` property value will not change the position of the overall element. The first value of the pair is the padding at the top of the element and the second value of the pair is the padding at the bottom of the element.
|
||||
- Minimum value per axis is `0` and maximum value per axis is `0.2`
|
||||
- Default is `0 0`
|
||||
- This property can only be used if `backgroundColor` has a value defined.
|
||||
* `backgroundCornerRadius` - type: FLOAT
|
||||
- Setting this property higher than zero applies rounded corners to the element background, assuming it has a color set. The radius is a percentage of the screen width. Note that the maximum allowed value is quite arbitrary as the renderer will in practice limit the maximum roundness so it can never go beyond half the background height. It means that setting this property sufficiently high will produce perfectly rounded sides for the background. You normally want to combine this property with `backgroundHorizontalPadding` and `backgroundVerticalPadding` to first add some extra space around the clock.
|
||||
- Minimum value is `0` and maximum value is `0.5`
|
||||
- Default is `0` (corners are not rounded)
|
||||
- This property can only be used if `backgroundColor` has a value defined.
|
||||
* `format` - type: STRING
|
||||
- %Y: The year, including the century (1900)
|
||||
- %m: The month number [01,12]
|
||||
- %d: The day of the month [01,31]
|
||||
- %H: The hour (24-hour clock) [00,23]
|
||||
- %M: The minute [00,59]
|
||||
- %S: The second [00,59]
|
||||
- Default is `%H:%M`
|
||||
* `opacity` - type: FLOAT
|
||||
- Controls the level of transparency. If set to `0` the element will be disabled.
|
||||
- Minimum value is `0` and maximum value is `1`
|
||||
- Default is `1`
|
||||
|
|
20
THEMES.md
20
THEMES.md
|
@ -251,6 +251,26 @@ git remote add system-logos https://gitlab.com/es-de/themes/system-logos.git
|
|||
```
|
||||
After doing this you'll be able to pull repository updates as described above.
|
||||
|
||||
### External repositories
|
||||
|
||||
In addition to the official asset repositories there are some external theme resources that are not maintained by the ES-DE project.
|
||||
|
||||
System icon set by Zoidburg:
|
||||
|
||||
https://github.com/Zoidburg13/ES-DE-System-Icon-Set
|
||||
|
||||
Console/system logos by Dan Patrick (GitHub mirror, not officially maintained by Patrick):
|
||||
|
||||
https://github.com/PRO100BYTE/console-logos
|
||||
|
||||
High-resolution photos of classic gaming hardware:
|
||||
|
||||
https://commons.wikimedia.org/wiki/User:Evan-Amos
|
||||
|
||||
Large set of controller and game cartridge images in SVG and PNG formats:
|
||||
|
||||
https://archive.org/details/@pineapple_graphics
|
||||
|
||||
## Simple example theme
|
||||
|
||||
Here is a very simple theme that changes the color of the game name text:
|
||||
|
|
217
USERGUIDE-DEV.md
217
USERGUIDE-DEV.md
|
@ -120,6 +120,8 @@ _This is the dialog shown if no game files were found. It lets you configure the
|
|||
|
||||
## Upgrading to a newer release
|
||||
|
||||
**Linux, macOS and Windows**
|
||||
|
||||
**Note:** Before upgrading ES-DE, make sure that you have not made any system customizations anywhere in the installation directory structure as these files will be overwritten during the upgrade process. All customizations should go into ~/ES-DE/custom_systems/ as described elsewhere in this guide. None of the upgrade methods mentioned below will ever touch any files inside your ES-DE directory tree.
|
||||
|
||||
There is a built-in application updater that can automatically upgrade the Linux AppImages, and for Windows and macOS there is support for downloading the packages directly inside ES-DE. Just be aware that these will need to be manually installed. Using the application updater is straightforward, just follow the on-screen instructions. For the AppImage releases the old file is retained by renaming it, adding its version to the filename followed by the .OLD extension, for example `ES-DE_x64_SteamDeck.AppImage_3.0.0.OLD`
|
||||
|
@ -128,7 +130,20 @@ Note that the updater will keep whatever filename you had for your running AppIm
|
|||
|
||||
On Windows and macOS you can specify to which directory you want to save the downloaded file. The default is `C:\Users\myusername\Downloads` on Windows and `/Users/myusername/Downloads` on macOS.
|
||||
|
||||
On Android the update process differs depending on whether you have the Patreon release or a release from either the Samsung Galaxy Store or Huawei AppGallery. For the store versions you simply update via the store app. For the Patreon release you'll get an email (sent to the address you used when buying ES-DE there) whenever there is a new version. For all Android releases, unless you have modifed the option _Check for application updates_ you'll see a popup on application startup whenever there's a new release available.
|
||||
To perform the upgrade on macOS simply open the .dmg file and install ES-DE on top of the old installation (i.e. replacing it).
|
||||
|
||||
For the Windows installer release simply run the .exe file and select uninstallation of the old version before installing the new version. For the Windows portable release refer to the README.txt file in the zip archive for instructions on how to perform the update.
|
||||
|
||||
**Android**
|
||||
|
||||
On Android the update process differs depending on whether you have the Patreon release or a release from either the Samsung Galaxy Store or Huawei AppGallery. For the store versions you simply update via the store app. For the Patreon release you'll get an email (sent to the address you used on Patreon) whenever there is a new version. This email contains a download link to the latest APK, and to apply the update you simply run this APK file. This is a safe operation that will not change or remove any of your data such as settings, scraped media etc.
|
||||
|
||||
Also for the Patreon release you'll see a popup on application startup whenever there's a new version available, unless you have modifed the option _Check for application updates_ in the _Other settings_ menu. Note that such notifications are not shown for the Galaxy Store and AppGallery releases as those store apps have their built-in update notifications.
|
||||
|
||||
For the Patreon release you can also resend the latest update email to yourself using the self-service resend tool:\
|
||||
https://resend.es-de.org
|
||||
|
||||
**After the upgrade**
|
||||
|
||||
Regardless of package format and operating system it's a good idea to update the ROM directory tree after upgrading to a new version. It's possible that the new ES-DE release adds support for more systems and emulators compared to the version you previously had installed. The easiest way to do this is via the _Create/update system directories_ entry in the _Utilities_ menu. Alternatively the _--create-system-dirs_ command line option can be used. Both methods work identically and will create any missing system directories and also update the systems.txt and systeminfo.txt files. This is a safe operation as it will not overwrite or delete your game files.
|
||||
|
||||
|
@ -252,6 +267,10 @@ On some GPUs with buggy drivers, ES-DE may only display a black screen on startu
|
|||
ES-DE.exe --resolution 1281 800
|
||||
```
|
||||
|
||||
Another potential workaround for some buggy drivers is to set ES-DE to compatibility mode and/or select _Disable full-screen optimizations_. These options are available when right-clicking on ES-DE.exe in the file manager and chosing _Properties_ and then selecting the _Compatibility_ tab.
|
||||
|
||||
Yet another issue with buggy GPU drivers is that for computers with multiple GPUs such as gaming laptops with integrated Intel graphics in addition to a discrete GPU (e.g. from Nvidia) there may be issues when window switching between ES-DE and other applications. In such cases severe screen flickering may get introduced. This is normally worked around by explicitly setting ES-DE to use the discrete GPU in the Windows graphics settings.
|
||||
|
||||
Some computers using Intel Iris Xe GPUs refuse to start ES-DE or display excessive graphics corruption. These problems are seemingly caused by driver bugs and do not occur when using Linux with the same hardware. There is no known solution or workaround to this issue other than switching to Linux or waiting for Intel to resolve the problem with a driver update.
|
||||
|
||||
Some older games (and possibly emulators too) may not work correctly or even start at all if ES-DE is set to run in the background while a game is launched. So if you experience strange issues with some games, make sure that the setting _Run in background (while game is launched)_ is disabled. If launching any of these problematic games from the _desktop_ system, also make sure to use the default emulator entry _Suspend ES-DE_ and not the alternative emulator _Keep ES-DE running_.
|
||||
|
@ -282,8 +301,6 @@ There is a very annoying default configuration when using Sony controllers like
|
|||
|
||||
One macOS-specific requirement is that the RetroArch setting _Start in Fullscreen mode_ is enabled or ES-DE will not be able to switch to the emulator window when launching games. As a workaround you can switch to the window manually using Command + Tab but it probably doesn't make sense to run emulators in windowed mode anyway. This issue has not been observed with any other emulators.
|
||||
|
||||
At the time of writing there is an additional issue with the ARM release of RetroArch where ES-DE will not be able to consistently switch to its window on game launch if the setting _Close windows when quitting an application_ under the _Desktop & Dock_ entry in the macOS _System Settings_ has been set to disabled. This error does not occur for the Intel/x86 release of RetroArch or with any other standalone emulators (including those built specifically for the ARM architecture).
|
||||
|
||||
The first time you launch a RetroArch-emulated game from within ES-DE the operating system will present you with a security option with the following description:
|
||||
|
||||
`"ES-DE" would like to access files in your Documents folder.`
|
||||
|
@ -627,12 +644,12 @@ If ES-DE is unable to find an emulator when a game is launched, a notification p
|
|||
|
||||
## Using the Steam release of RetroArch
|
||||
|
||||
As this release of RetroArch is executed via the Steam application it's behaving a bit glitchy and strange with ES-DE (which is due to the nature of Steam). In addition to this there seem to be some bugs in either Steam or RetroArch, or both. The following issues have been observed:
|
||||
As this release of RetroArch is executed via the Steam application it's behaving a bit glitchy and strange with ES-DE (which is due to the nature of Steam). The following issues have been observed:
|
||||
|
||||
* ES-DE will continue to run in the background due to the way that Steam works
|
||||
* Game launching is not seamless and there will be some flickering
|
||||
* If the Steam GUI is visible, focus may not return to ES-DE when exiting a game. Minimizing Steam increases the chances of this working properly but it's not guaranteed to completely fix the problem
|
||||
* Filenames containing apostrophes do not work, you need to rename these game files to be able to launch them
|
||||
* Game launching may not be seamless, with screen flickering and similar on some devices and operating systems
|
||||
* If the Steam GUI is visible, focus may not return to ES-DE when exiting a game (this seems to be caused by the Steam overlay)
|
||||
* There may be additional focusing and window switching issues caused by the Steam overlay
|
||||
* Core searches will not work, if an emulator core is missing there will be no error notification inside ES-DE and game launching will just silently fail
|
||||
* Logging output from emulators is not possible due to ES-DE running in the background
|
||||
|
||||
|
@ -643,7 +660,7 @@ Simply add alternative emulator entries such as the following example (which ena
|
|||
<command label="Nestopia UE (Steam)">%RUNINBACKGROUND% %EMULATOR_STEAM% -applaunch 1118310 -L nestopia_libretro %ROM%</command>
|
||||
```
|
||||
|
||||
This will work on both Linux and Windows.
|
||||
This will work on both Linux and Windows (and possibly macOS too).
|
||||
|
||||
A complete entry for the nes system could look like the following:
|
||||
```xml
|
||||
|
@ -704,9 +721,10 @@ The following emulators are supported in AppImage format when using the bundled
|
|||
| gc | Triforce | dolphin-emu-triforce*.AppImage |
|
||||
| macintosh | Basilisk II | BasiliskII*.AppImage |
|
||||
| macintosh | SheepShaver | SheepShaver*.AppImage |
|
||||
| n3ds | Azahar | azahar*.AppImage |
|
||||
| n3ds | Citra | citra-qt*.AppImage |
|
||||
| n3ds | Lime3DS | lime3ds.AppImage |
|
||||
| n3ds | Mandarine | mandarine-qt.AppImage |
|
||||
| n3ds | Mandarine | mandarine-qt*.AppImage |
|
||||
| n3ds | Panda3DS | Alber-*.AppImage |
|
||||
| n64/n64dd | Rosalie's Mupen GUI | RMG*.AppImage |
|
||||
| nds | melonDS | melonDS*.AppImage |
|
||||
|
@ -714,9 +732,12 @@ The following emulators are supported in AppImage format when using the bundled
|
|||
| ps2 | PCSX2 | pcsx2*.AppImage |
|
||||
| ps2 | Play! | Play!*.AppImage |
|
||||
| ps3 | RPCS3 | rpcs3*.AppImage |
|
||||
| ps4 | shadPS4 | Shadps4-qt*.AppImage |
|
||||
| ps4 | shadPS4 | Shadps4-sdl*.AppImage |
|
||||
| psvita | Vita3K | Vita3K*.AppImage |
|
||||
| psx | DuckStation | DuckStation*.AppImage |
|
||||
| snes | Snes9x | Snes9x*.AppImage |
|
||||
| switch | Ryujinx | \*yujinx\*.AppImage |
|
||||
| xbox | xemu | xemu*.AppImage |
|
||||
| wii | Dolphin | Dolphin_Emulator*.AppImage |
|
||||
| wiiu | Cemu | Cemu*.AppImage |
|
||||
|
@ -790,12 +811,15 @@ The following manually downloaded emulators are supported when using the bundled
|
|||
|
||||
| System name | Emulator | Filename |
|
||||
| :-------------------------------------- | :--------------- | :-------------------------------- |
|
||||
| _Multiple_ | Mesen | Mesen/Mesen |
|
||||
| adam/colecovision | ColEm | colem/colem |
|
||||
| amiga/amiga1200/amiga600/amigacd32/cdtv | Amiberry | amiberry/amiberry |
|
||||
| amstradcpc | ACE-DL | AceDL/AceDL |
|
||||
| amstradcpc | CPCemu | cpcemu/cpcemu |
|
||||
| apple2 | LinApple | linapple/linapple |
|
||||
| arcade/mame/model3 | Supermodel | Supermodel/supermodel |
|
||||
| atari2600 | Gopher2600 | gopher2600/gopher2600_linux_amd64 |
|
||||
| atari7800 | A7800 | a7800-linux/a7800 |
|
||||
| atarijaguar/atarijaguarcd | BigPEmu | bigpemu/bigpemu |
|
||||
| coco/dragon32/tanodragon | XRoar | xroar/xroar |
|
||||
| daphne | Hypseus Singe | hypseus-singe/hypseus.bin |
|
||||
|
@ -807,12 +831,12 @@ The following manually downloaded emulators are supported when using the bundled
|
|||
| fmtowns | Tsugaru | tsugaru/Tsugaru_CUI |
|
||||
| gb/gba/gbc/nds | SkyEmu | SkyEmu/SkyEmu |
|
||||
| gb/gbc | Gearboy | gearboy/gearboy |
|
||||
| model3 | Supermodel | Supermodel/supermodel |
|
||||
| famicom/nes | puNES | punes/punes |
|
||||
| mame-advmame | AdvanceMAME | advancemame/advmame |
|
||||
| oric | Oricutron | oricutron/Oricutron |
|
||||
| pc88 | QUASI88 | quasi88/quasi88 |
|
||||
| pico8 | PICO-8 | pico-8/pico8 |
|
||||
| ps4 | shadPS4 | shadps4/shadps4 |
|
||||
| psvita | Vita3K | Vita3K/Vita3K |
|
||||
| samcoupe | SimCoupé | simcoupe/simcoupe |
|
||||
| saturn/saturnjp | Kronos | kronos/kronos |
|
||||
|
@ -910,10 +934,12 @@ The following Windows emulators are supported, and the setup for most of these i
|
|||
|
||||
| System name | Emulator | Filename |
|
||||
| :------------------------ | :--------------- | :-----------------------|
|
||||
| arcade/mame | MFME | MFME/MFME.exe |
|
||||
| atarijaguar/atarijaguarcd | BigPEmu | BigPEmu/BigPEmu.exe |
|
||||
| famicom/nes | 3dSen | 3dSen/3dSen.exe |
|
||||
| model2 | Model 2 Emulator | m2emulator/EMULATOR.EXE |
|
||||
| x68000 | XM6 Pro-68k | XM6 Pro-68k/XM6.exe |
|
||||
| x68000 | XM6 TypeG | xm6_typeg/xm6g.exe |
|
||||
| xbox360 | xenia | xenia/xenia.exe |
|
||||
| xbox360 | xenia | xenia/xenia_canary.exe |
|
||||
|
||||
|
@ -2019,7 +2045,7 @@ These games are shipped as self-contained units with the game engine binary incl
|
|||
|
||||
For this example we'll go with the game _Ultimate Sonic Mugen_.
|
||||
|
||||
On Windows, go into the game directory, right click on the `Ikemen_GO.exe` file, select _Create Shortcut_ followed by _Create Desktop Shortcut_. This will create a file with the .lnk extension. Rename the file to `Ultimate Sonic Mugen.lnk` and try to run this file to make sure that the game starts and runs correctly. Note that this setup is not portable, if you move your game files somewhere else you will need to manually update your shortcuts as these contain absolute paths.
|
||||
On Windows, go into the game directory, right click on the `Ikemen_GO.exe` file, select _Create Shortcut_ followed by _Create Desktop Shortcut_. This will create a file with the .lnk extension. Rename the file to `Ultimate Sonic Mugen.lnk` and try to run this file to make sure that the game starts and runs correctly. Note that this setup is not portable, if you move your game files somewhere else you will need to manually update your shortcut files as these contain absolute paths.
|
||||
|
||||
On Linux and macOS, go into the game directory and rename the `Ikemen_GO_Linux` or `Ikemen_GO_MacOS` binary to the name of the game and add the .mugen extension to the filename, for example `Ultimate Sonic Mugen.mugen`. Try to run this file to make sure that the game starts and runs correctly.
|
||||
|
||||
|
@ -2251,7 +2277,7 @@ The second option on Windows is to unpack the game somewhere outside the ROMs di
|
|||
~\ROMs\openbor\The Endless Quest.lnk
|
||||
```
|
||||
|
||||
The drawback to using shortcuts is that they're not portable, if you change the location of your games, you will need to manually update the shortcuts as well.
|
||||
The drawback to using shortcuts is that they're not portable, if you change the location of your games, you will need to manually update the shortcut files as well.
|
||||
|
||||
**Linux:**
|
||||
|
||||
|
@ -2394,7 +2420,7 @@ vkquake_arcane_dimensions.sh:
|
|||
|
||||
You don't need to set execution permissions for these scripts, ES-DE will run them anyway.
|
||||
|
||||
**Method 3, AppImages** _Linux only_
|
||||
**Method 3, AppImages** _(Linux only)_
|
||||
|
||||
On Linux it's also possible to launch AppImages directly without having to call them from a shell script. For emulators it's generally required to keep their AppImages in the `~/Applications/` directory and symlink them into the ROMs directory tree, but for other applications and games it may be fine to store them directly in the ROMs tree. In order for this to work you need to use one of the alternative emulator entries that enable AppImages to be launched. It will not work if attempting to use the emulator entries that run scripts and shortcuts. You can set the alternative emulator per game/file from the metadata editor.
|
||||
|
||||
|
@ -2443,7 +2469,7 @@ For Linux, macOS and Windows there's an alternative to using ScummVM for a limit
|
|||
|
||||
### Sony PlayStation 3
|
||||
|
||||
There are two ways to add PS3 games to ES-DE, by using shortcuts or by adding game directories directly to the ~/ROMs/ps3 folder and interpreting these as files. Shortcuts is generally the way to go as it's easier to setup and for HDD/pkg games it's the only way to make it work unless you manually create symlinks to the internal RPCS3 directory structure. So another benefit with shortcuts is consistency as both HDD/pkg games and disc-based games will be setup in the same manner. This also means that the same RPCS3 emulator entry can be used to launch every game. The drawback to using shortcuts is that they're not portable, if you change the location of RPCS3 or your games, you need to manually update the shortcuts as well.
|
||||
There are three ways to add PS3 games to ES-DE, by using shortcuts, by adding game serial files and by adding game directories directly to the ~/ROMs/ps3 folder and interpreting these as files. Shortcuts is generally the way to go as they're easier to setup. Launching as directories also doesn't work for HDD/pkg games unless you symlink from the internal RPCS3 directory structure. So another benefit with shortcuts and game serials is consistency as both HDD/pkg games and disc-based games will be setup in the same manner. This also means that the same RPCS3 emulator entry can be used to launch every game. The drawback to using shortcuts is that they're not portable, if you change the location of RPCS3 or your games, you need to manually update the shortcut files as well.
|
||||
|
||||
Be aware that if you still want to have games installed using the directory method, then you will need to change to the alternative emulator _RPCS3 Directory (Standalone)_ or you won't be able to launch these games. As is the case for all alternative emulator entries, this can be configured system-wide or on a per-game basis.
|
||||
|
||||
|
@ -2453,7 +2479,7 @@ Apart from this you need to install the PS3 system firmware to use the emulator,
|
|||
|
||||
**Method 1, shortcuts**
|
||||
|
||||
First install your games inside RPCS3, then right click on each entry and select _Create Shortcut_ followed by _Create Desktop Shortcut_. On Windows this will create shortcuts with the .lnk extension, on macOS they will have the .app extension and on Linux they will have the .desktop extension.
|
||||
First install your games inside RPCS3, then right click on each entry and select _Manage Game_ followed by _Create Desktop Shortcut_. On Windows this will create shortcuts with the .lnk extension, on macOS they will have the .app extension and on Linux they will have the .desktop extension.
|
||||
|
||||
Then simply move these files from your desktop to your ~/ROMs/ps3 directory and you're done. Here's an example of what this could look like on Linux:
|
||||
```
|
||||
|
@ -2475,7 +2501,18 @@ If using the AppImage release of RPCS3 on Linux then another issue may be that t
|
|||
|
||||
Regardless of how you've installed RPCS3, make sure to always test the shortcuts outside ES-DE first, because if they don't work from the desktop, then they will not work from inside ES-DE either.
|
||||
|
||||
**Method 2, directories**
|
||||
**Method 2, game serial**
|
||||
|
||||
First install your games inside RPCS3, then create an empty file in `~/ROMs/ps3` and name it as the game name followed by the .ps3 file extension, such as the following:
|
||||
```
|
||||
~/ROMs/ps3/Braid.ps3
|
||||
```
|
||||
|
||||
Then add the game serial to this file. This ID can be found inside the RPCS3 GUI, in the _Serial_ column. For example the game _Braid_ has a serial that is NPUB30133. So simply add the string NPUB30133 to the `Braid.ps3` file using a text editor or similar and the setup for this game is complete.
|
||||
|
||||
Be aware that you need to change to the alternative emulator entry _RPCS3 Game Serial (Standalone)_ for this to work.
|
||||
|
||||
**Method 3, directories**
|
||||
|
||||
This approach is only intended for disc-based games as for HDD/pkg games you should use shortcuts instead. When using this method you need to retain the directory structure of the Blu-ray disc, and each directory needs to be renamed by adding the .ps3 extension. This will make ES-DE interpret the directory as if it were a file and pass that directory to the emulator when launching a game.
|
||||
|
||||
|
@ -2488,6 +2525,56 @@ It's possible to create a symlink instead, and in this case only the symlink nee
|
|||
|
||||
When using this setup method you need to set the alternative emulator to _RPCS3 Directory (Standalone)_ or game launching will not work.
|
||||
|
||||
### Sony PlayStation 4
|
||||
|
||||
There are three ways to add PS4 games to ES-DE, by using shortcuts, by adding game serial files and by running the eboot.bin files directly. Running eboot.bin files is not really recommended though and it's better to go for one of the other alternatives.
|
||||
|
||||
The drawback to using shortcuts is that they're not portable, if you change the location of shadPS4, you need to manually update the shortcut files as well.
|
||||
|
||||
Unless you want to run eboot.bin files directly from inside ES-DE it's recommended to install the games outside of the ROMs directory tree so they don't need to be scanned on startup. This could take quite some time as these games may contain many thousands of files each. An alternative would be to place a `noload.txt` file inside each game directory but it's easier to just install the games elsewhere.
|
||||
|
||||
_On macOS you need to configure shadPS4 to run in fullscreen mode or otherwise window switching will not work when launching games from ES-DE._
|
||||
|
||||
**Method 1, shortcuts**
|
||||
|
||||
_Note that this option is not currently available on macOS due to shadPS4 not exporting proper shortcut files on this operating system at the time of writing._
|
||||
|
||||
First install your games inside shadPS4, then right click on each entry and select _Create Shortcut_. On Windows this will create shortcuts with the .lnk extension and on Linux they will have the .desktop extension.
|
||||
|
||||
Then simply move these files from your desktop to your ~/ROMs/ps4 directory and you're done. Here's an example of what this could look like on Linux:
|
||||
```
|
||||
~/ROMs/ps4/Bloodborne™.desktop
|
||||
~/ROMs/ps4/Sonic Mania.desktop
|
||||
```
|
||||
|
||||
Note that if using the AppImage release of shadPS4 there is currently a bug where the .desktop files will include the wrong path to the emulator binary. The Exec key will look something like this:
|
||||
```
|
||||
Exec=/tmp/.mount_ShadpsjENLoI/usr/bin/shadps4 "/home/myusername/ROMs/ps4/CUSA00900/eboot.bin"
|
||||
```
|
||||
|
||||
You need to change this to the full path of the AppImage file, such as:
|
||||
```
|
||||
Exec=/home/myusername/Applications/Shadps4-qt.AppImage "/home/myusername/ROMs/ps4/CUSA00900/eboot.bin"
|
||||
```
|
||||
Regardless of how you've installed shadPS4, make sure to always test the shortcuts outside ES-DE first, because if they don't work from the desktop, then they will not work from inside ES-DE either.
|
||||
|
||||
**Method 2, game serial**
|
||||
|
||||
First install your games inside shadPS4, then create an empty file in `~/ROMs/ps4` and name it as the game name followed by the .ps4 file extension, such as the following:
|
||||
```
|
||||
~/ROMs/ps4/Sonic Mania.ps4
|
||||
```
|
||||
|
||||
Then add the game serial to this file. This ID can be found inside the shadPS4 GUI, in the _Serial_ column. For example the game _Sonic Mania_ has a serial that is CUSA07010. So simply add the string CUSA07010 to the `Sonic Mania.ps4` file using a text editor or similar and the setup for this game is complete.
|
||||
|
||||
Be aware that you need to change to the alternative emulator entry _shadPS4 Game Serial (Standalone)_ for this to work.
|
||||
|
||||
**Method 3, eboot.bin**
|
||||
|
||||
This method which is not really recommended requires that you install the games directly to the `~/ROMs/ps4` directory and browse to the eboot.bin file for each game to launch it. You can optionally use the _Folder link_ functionality to launch the games directly from the main gamelist view, as explained elsewhere in this guide.
|
||||
|
||||
Be aware that you need to change to the alternative emulator entry _shadPS4 eboot.bin (Standalone)_ for this to work.
|
||||
|
||||
### Sony PlayStation Vita
|
||||
|
||||
There is also a video on the official ES-DE YouTube channel on how to setup Vita3K:\
|
||||
|
@ -2506,6 +2593,11 @@ Then add the game Title ID to this file. This ID can be found inside the Vita3K
|
|||
|
||||
Game launching and scraping should now work fine in ES-DE.
|
||||
|
||||
To simplify the setup described above there is a convenient archive of .psvita files available that covers most of the game library for this console. It can be downloaded from here:\
|
||||
https://github.com/Jetup13/Retroid-Pocket-5-Wiki/wiki/Emulators-and-Formats#vita3k-frontend-support
|
||||
|
||||
Just extract the corresponding file for any game you have installed in Vita3K and place it in ~/ROMs/psvita and you're good to go.
|
||||
|
||||
### Steam
|
||||
|
||||
These games can easily be added to ES-DE using shortcuts, just be aware that this requires that the games have been installed locally.
|
||||
|
@ -3300,7 +3392,7 @@ Animation to play when opening the main menu or the gamelist options menu. Also
|
|||
|
||||
**Launch screen duration**
|
||||
|
||||
This configures for how long to display the game launch screen when starting a game. The options are _Normal_, _Brief_, _Long_ and _Disabled_. If set to _Disabled_, a simple notification popup will be displayed instead.
|
||||
This configures for how long to display the game launch screen when starting a game. The options are _Normal_, _Brief_, _Long_, _Popup_ and _Disabled_. If set to _Popup_, a simple notification popup will be displayed instead of the launch screen and if set to _Disabled_ then game launching will be instantaneous.
|
||||
|
||||
**UI mode**
|
||||
|
||||
|
@ -3310,6 +3402,10 @@ Sets the user interface mode for the application to _Full, Kiosk_ or _Kid_. See
|
|||
|
||||
Whether to enable the selection of a random entry in the system or gamelist view via a button press, by default mapped to the click button of either thumbstick. The options are _Games only, Games and systems_ or _Disabled_. The help system will also visually indicate the status of this setting.
|
||||
|
||||
**System status settings** _(Not available on FreeBSD and Haiku)_
|
||||
|
||||
Submenu containing all the settings for the system status indicators. These are described in detail below.
|
||||
|
||||
**Media viewer settings**
|
||||
|
||||
Submenu containing all the settings for the media viewer. These are described in detail below.
|
||||
|
@ -3322,7 +3418,11 @@ Submenu containing all the settings for the screensaver. These are described in
|
|||
|
||||
Themes can optionally contain variant trigger configuration which changes the layout on a per-gamelist basis if there is no game media available, or if there is no game videos available. This option makes it possible to disable that functionality and always apply the default configuration for the selected variant. Disabling this option may speed up the application slightly.
|
||||
|
||||
**Blur background when menu is open** _Always applied if screen is rotated 90 or 270 degrees_
|
||||
**Display clock**
|
||||
|
||||
Displays a clock on screen at all times. By default it's located in the upper left corner and displays as hours and minutes, but themes can customize its layout and position.
|
||||
|
||||
**Blur background when menu is open** _(Always applied if screen is rotated 90 or 270 degrees)_
|
||||
|
||||
This option will blur the background behind the menu slightly. Normally this can be left enabled, but if you have a really slow GPU, disabling this option may make the application feel a bit more responsive. For technical reasons this setting is always enabled if the screen is rotated 90 or 270 degrees, and in this case the menu option will also be grayed out.
|
||||
|
||||
|
@ -3358,6 +3458,30 @@ Activating or deactivating the ability to filter your gamelists. This can normal
|
|||
|
||||
Activates or deactivates the built-in help system that provides contextual information regarding button usage.
|
||||
|
||||
#### System status settings
|
||||
|
||||
This menu makes it possible to enable or disable various system indicators. Just be aware that these options have no effect if there are no such hardware devices present.
|
||||
|
||||
**Display Bluetooth status indicator**
|
||||
|
||||
Indicates whether there's a Bluetooth adapter enabled on the device.
|
||||
|
||||
**Display Wi-Fi status indicator**
|
||||
|
||||
Indicates whether Wi-Fi is enabled on the device.
|
||||
|
||||
**Display cellular status indicator** _(Android only)_
|
||||
|
||||
Indicates whether cellular traffic is enabled on the device.
|
||||
|
||||
**Display battery status indicator**
|
||||
|
||||
Indicates whether there's a battery available in the device, in which case different icons will be displayed if the battery is charging or not, and if not charging there are discreet icons for different capacity levels (low, medium, high and full).
|
||||
|
||||
**Display battery charge percentage**
|
||||
|
||||
If there's a battery in the device, then this setting controls whether to display the charge/capacity percentage text next to the battery icon.
|
||||
|
||||
#### Media viewer settings
|
||||
|
||||
Settings for the media viewer that is accessible from the gamelist views.
|
||||
|
@ -3625,11 +3749,11 @@ This gives the choice of which key combination to use to quit the application. T
|
|||
|
||||
The metadata for a game is updated by scraping or by manual editing it using the metadata editor, but also when launching it as this updates the _Times played_ counter and the _Last played_ timestamp. This setting enables you to define when to write such metadata changes to the gamelist.xml files. Setting the option to _Never_ will disable writing to these files altogether, except for some special conditions such as when a game is manually deleted using the metadata editor, when scraping using the multi-scraper (the multi-scraper will always save any updates immediately to the gamelist.xml files) or when changing the system-wide alternative emulator. In theory _On exit_ will give some small performance gains, but it's normally recommended to leave the setting at its default value which is _Always_. Note that with the option set to _Never_, any updates such as the _Last played_ date will still be shown on screen, but during the next application startup any values previously saved to the gamelist.xml files will be read in again. As well, when changing this setting to _Always_ from either of the two other options, any pending changes will be immediately written to the gamelist.xml files.
|
||||
|
||||
**Check for application updates** _Not available for some builds_
|
||||
**Check for application updates** _(Not available for some builds)_
|
||||
|
||||
By default a check for new ES-DE versions will be done on every application startup and a notification will be displayed if there is a new release available for download. Using this option the frequency of these checks can be set to _Always_, _Daily_, _Weekly_, _Monthly_ or _Never_. This setting is not available on some platforms and package formats such as the Android app store releases, the Linux AUR release and the semi-official FreeBSD and Raspberry Pi releases where pre-built packages are not provided.
|
||||
|
||||
**Include prereleases in update checks** _Always enabled for prereleases_
|
||||
**Include prereleases in update checks** _(Always enabled for prereleases)_
|
||||
|
||||
For platforms and package formats where the previous setting above is available there is also the option of whether to include prereleases when checking for application updates. Note that this is always enabled when running an ES-DE prerelease so in this case the setting will be grayed out.
|
||||
|
||||
|
@ -3661,6 +3785,10 @@ You can mark games as hidden in the metadata editor, which is useful for instanc
|
|||
|
||||
It's possible to trigger custom scripts for a number of actions in ES-DE, as is discussed [below](USERGUIDE-DEV.md#custom-event-scripts), and this setting decides whether this functionality is enabled.
|
||||
|
||||
**Browsing custom events**
|
||||
|
||||
This option, which depends on _Enable custom event scripts_ being activated, will also generate custom events when navigating the system and gamelist views. Note that this could introduce a lot of latency into the application so only enable it if you absolutely need it.
|
||||
|
||||
**Only show games from gamelist.xml files**
|
||||
|
||||
If enabled, only games that have metadata saved to the gamelist.xml files will be shown in ES-DE. This option is intended primarily for testing and debugging purposes so it should normally not be enabled. When changing this setting ES-DE will automatically reload.
|
||||
|
@ -3788,13 +3916,13 @@ The following filters can be applied:
|
|||
|
||||
**Kidgame**
|
||||
|
||||
**Hidden** _If the "Show hidden games" option is enabled_
|
||||
**Hidden** _(If the "Show hidden games" option is enabled)_
|
||||
|
||||
**Broken**
|
||||
|
||||
**Controller**
|
||||
|
||||
**Alternative emulator** _If the "Enable alternative emulators per game" option is enabled_
|
||||
**Alternative emulator** _(If the "Enable alternative emulators per game" option is enabled)_
|
||||
|
||||
With the exception of the game name text filter, all available filter values are assembled from metadata from the actual gamelist, so if there is no data to filter for the specific field, the text _Nothing to filter_ will be displayed. This for example happens for the _Completed_ filter if there are no games marked as having been completed in the current gamelist. The same happens if a metadata setting is identical for all games, such as all games being flagged as favorites.
|
||||
|
||||
|
@ -4114,30 +4242,30 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| androidgames | Android Games | _Placeholder_ | | | |
|
||||
| apple2 | Apple II | LinApple **(Standalone)** [L],<br>Mednafen **(Standalone)** [M],<br>AppleWin **(Standalone)** [W] | Mednafen **(Standalone)** [LW],<br>MAME - Current,<br>MAME **(Standalone)**,<br>izapple2 **(Standalone)** [LW] | Yes for Mednafen and MAME | See the specific _Apple II_ section elsewhere in this guide |
|
||||
| apple2gs | Apple IIGS | MAME - Current | MAME **(Standalone)** | Yes | See the specific _Apple IIGS_ section elsewhere in this guide |
|
||||
| arcade | Arcade | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME **(Standalone)**,<br>FinalBurn Neo,<br>FinalBurn Neo **(Standalone)** [LW],<br>FB Alpha 2012,<br>Geolith,<br>Flycast,<br>Flycast **(Standalone)**,<br>Flycast Dojo **(Standalone)**,<br>Kronos [LW],<br>Model 2 Emulator **(Standalone)** [W],<br>Model 2 Emulator [Suspend ES-DE] **(Standalone)** [W],<br>Supermodel **(Standalone)** [LW],<br> _Shortcut or script_ | Depends | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| arcade | Arcade | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME **(Standalone)**,<br>FinalBurn Neo,<br>FinalBurn Neo **(Standalone)** [LW],<br>FB Alpha 2012,<br>Geolith,<br>Flycast,<br>Flycast **(Standalone)**,<br>Flycast Dojo **(Standalone)**,<br>Kronos [LW],<br>Model 2 Emulator **(Standalone)** [W],<br>Model 2 Emulator [Suspend ES-DE] **(Standalone)** [W],<br>Supermodel **(Standalone)** [LW],<br>MFME **(Standalone)** [LW],<br> _Shortcut or script_ | Depends | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| arcadia | Emerson Arcadia 2001 | MAME - Current | MAME **(Standalone)**,<br>WinArcadia **(Standalone)** | No | Single archive or ROM file |
|
||||
| archimedes | Acorn Archimedes | MAME [Model A440/1] **(Standalone)** | MAME [Model A3000] **(Standalone)**,<br>MAME [Model A310] **(Standalone)**,<br>MAME [Model A540] **(Standalone)** | Yes | |
|
||||
| arduboy | Arduboy Miniature Game System | Arduous | Ardens | No | Single archive or .hex file |
|
||||
| astrocde | Bally Astrocade | MAME - Current | MAME **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| atari2600 | Atari 2600 | Stella | Stella 2014,<br>Stella 2023,<br>Stella **(Standalone)**,<br>Gopher2600 **(Standalone)** [LW],<br>ares **(Standalone)** | No | Single archive or ROM file |
|
||||
| atari5200 | Atari 5200 | a5200 | Atari800,<br>Atari800 **(Standalone)**,<br>Altirra **(Standalone)** [W] | Yes except for Altirra | Single archive or ROM file |
|
||||
| atari7800 | Atari 7800 ProSystem | ProSystem | MAME - Current,<br>MAME **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| atari7800 | Atari 7800 ProSystem | ProSystem | MAME - Current,<br>MAME **(Standalone)**,<br>A7800 **(Standalone)** [LW] | Yes | Single archive or ROM file |
|
||||
| atari800 | Atari 800 | Atari800 | Atari800 **(Standalone)**,<br>Altirra **(Standalone)** [W] | Yes except for Altirra | |
|
||||
| atarijaguar | Atari Jaguar | Virtual Jaguar | BigPEmu **(Standalone)** [LW],<br>BigPEmu **(Wine)** [L],<br>BigPEmu **(Proton)** [L],<br>MAME **(Standalone)** | Yes for MAME | See the specific _Atari Jaguar and Atari Jaguar CD_ section elsewhere in this guide |
|
||||
| atarijaguarcd | Atari Jaguar CD | BigPEmu **(Standalone)** [LW] | BigPEmu **(Wine)** [L],<br>BigPEmu **(Proton)** [L] | No | See the specific _Atari Jaguar and Atari Jaguar CD_ section elsewhere in this guide |
|
||||
| atarilynx | Atari Lynx | Handy | Beetle Lynx,<br>Mednafen **(Standalone)** | No | Single archive or ROM file |
|
||||
| atarilynx | Atari Lynx | Handy | Beetle Lynx,<br>Mednafen **(Standalone)**,<br>Holani | No | Single archive or ROM file |
|
||||
| atarist | Atari ST [also STE and Falcon] | Hatari | Hatari **(Standalone)** | Yes | Single archive or image file for single-diskette games, .m3u playlist for multi-diskette games |
|
||||
| atarixe | Atari XE | Atari800 | Atari800 **(Standalone)**,<br>Altirra **(Standalone)** [W] | Yes except for Altirra | |
|
||||
| atomiswave | Sammy Corporation Atomiswave | Flycast | Flycast **(Standalone)**,<br>Flycast Dojo **(Standalone)**,<br>Demul **(Standalone)** [W] | Depends | Single archive file |
|
||||
| bbcmicro | Acorn Computers BBC Micro | MAME **(Standalone)** | BeebEm **(Standalone)** [W] | Yes | Single archive (MAME only) or diskette image file |
|
||||
| bbcmicro | Acorn Computers BBC Micro | MAME **(Standalone)** | b2,<br>BeebEm **(Standalone)** [W] | Yes | Single archive (MAME only) or diskette image file |
|
||||
| c64 | Commodore 64 | VICE x64sc Accurate | VICE x64sc Accurate **(Standalone)**,<br>VICE x64 Fast,<br>VICE x64 SuperCPU,<br>VICE x128,<br>Frodo | No | Single archive or image file for tape, cartridge or single-diskette games, .m3u playlist for multi-diskette games |
|
||||
| cdimono1 | Philips CD-i | SAME CDi | CDi 2015 @,<br>MAME **(Standalone)** | Yes | Single .bin/.cue pair |
|
||||
| cdtv | Commodore CDTV | PUAE | PUAE 2021,<br>FS-UAE **(Standalone)**,<br>Amiberry **(Standalone)** [LM] | Yes | See the specific _Commodore Amiga and CDTV_ section elsewhere in this guide |
|
||||
| chailove | ChaiLove Game Engine | ChaiLove | | | |
|
||||
| channelf | Fairchild Channel F | FreeChaF | MAME - Current,<br>MAME **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| coco | Tandy Color Computer | XRoar CoCo 2 NTSC **(Standalone)** | XRoar CoCo 2 PAL **(Standalone)**,<br>MAME [Cartridge] **(Standalone)**,<br>MAME [Tape] **(Standalone)** | Yes | See the specific _Tandy Color Computer_ section elsewhere in this guide |
|
||||
| colecovision | Coleco ColecoVision | blueMSX | Gearcoleco,<br>openMSX **(Standalone)**,<br>ares **(Standalone)**,<br>ColEm **(Standalone)** [LW] | Yes | Single archive or ROM file |
|
||||
| consolearcade | Console Arcade Systems | MAME - Current | MAME **(Standalone)**,<br>Flycast,<br>Flycast **(Standalone)**,<br>Flycast Dojo **(Standalone)**,<br>Kronos [LW],<br>Mednafen [Sega Saturn] **(Standalone)**,<br>Play! **(Standalone)**,<br>RPCS3 Shortcut **(Standalone)**,<br>Triforce **(Standalone)** [LW],<br>xemu **(Standalone)**,<br>Cxbx-Reloaded **(Standalone)** [W],<br> _Shortcut or script_ | Depends | See the specific _Console Arcade Systems_ section elsewhere in this guide |
|
||||
| colecovision | Coleco ColecoVision | blueMSX | Gearcoleco,<br>openMSX **(Standalone)**,<br>ares **(Standalone)**,<br>Mesen **(Standalone)** [LW],<br>ColEm **(Standalone)** [LW] | Yes | Single archive or ROM file |
|
||||
| consolearcade | Console Arcade Systems | MAME - Current | MAME **(Standalone)**,<br>Flycast,<br>Flycast **(Standalone)**,<br>Flycast Dojo **(Standalone)**,<br>Kronos [LW],<br>Mednafen [Sega Saturn] **(Standalone)**,<br>Play! **(Standalone)**,<br>RPCS3 Shortcut **(Standalone)**,<br>RPCS3 Game Serial **(Standalone)**,<br>Triforce **(Standalone)** [LW],<br>xemu **(Standalone)**,<br>Cxbx-Reloaded **(Standalone)** [W],<br> _Shortcut or script_ | Depends | See the specific _Console Arcade Systems_ section elsewhere in this guide |
|
||||
| cps | Capcom Play System | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME **(Standalone)**,<br>FinalBurn Neo,<br>FinalBurn Neo **(Standalone)** [LW],<br>FB Alpha 2012,<br>FB Alpha 2012 CPS-1,<br>FB Alpha 2012 CPS-2,<br>FB Alpha 2012 CPS-3 | Depends | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| cps1 | Capcom Play System I | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME **(Standalone)**,<br>FinalBurn Neo,<br>FinalBurn Neo **(Standalone)** [LW],<br>FB Alpha 2012,<br>FB Alpha 2012 CPS-1 | Depends | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| cps2 | Capcom Play System II | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME **(Standalone)**,<br>FinalBurn Neo,<br>FinalBurn Neo **(Standalone)** [LW],<br>FB Alpha 2012,<br>FB Alpha 2012 CPS-2 | Depends | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
|
@ -4166,7 +4294,7 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| gamecom | Tiger Electronics Game.com | MAME - Current | MAME **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| gamegear | Sega Game Gear | Genesis Plus GX | Genesis Plus GX Wide,<br>Gearsystem,<br>SMS Plus GX,<br>PicoDrive,<br>Mednafen **(Standalone)**,<br>Mesen **(Standalone)** [LW],<br>ares **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| gb | Nintendo Game Boy | Gambatte | SameBoy,<br>SameBoy **(Standalone)**,<br>Gearboy,<br>Gearboy **(Standalone)** [LW],<br>TGB Dual,<br>DoubleCherryGB [LW],<br>Mesen-S,<br>Mesen **(Standalone)** [LW],<br>bsnes,<br>mGBA,<br>mGBA **(Standalone)**,<br>VBA-M,<br>VBA-M **(Standalone)**,<br>Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>SkyEmu **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| gba | Nintendo Game Boy Advance | mGBA | mGBA **(Standalone)**,<br>VBA-M,<br>VBA-M **(Standalone)**,<br>VBA Next,<br>gpSP,<br>Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>SkyEmu **(Standalone)**,<br>NooDS **(Standalone)** [LW] | Yes for ares | Single archive or ROM file |
|
||||
| gba | Nintendo Game Boy Advance | mGBA | mGBA **(Standalone)**,<br>VBA-M,<br>VBA-M **(Standalone)**,<br>VBA Next,<br>gpSP,<br>NooDS,<br>NooDS **(Standalone)** [LW],<br>Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>SkyEmu **(Standalone)** | Yes for ares | Single archive or ROM file |
|
||||
| gbc | Nintendo Game Boy Color | Gambatte | SameBoy,<br>SameBoy **(Standalone)**,<br>Gearboy,<br>Gearboy **(Standalone)** [LW],<br>TGB Dual,<br>DoubleCherryGB [LW],<br>Mesen-S,<br>Mesen **(Standalone)** [LW],<br>bsnes,<br>mGBA,<br>mGBA **(Standalone)**,<br>VBA-M,<br>VBA-M **(Standalone)**,<br>Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>SkyEmu **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| gc | Nintendo GameCube | Dolphin | Dolphin **(Standalone)**,<br>PrimeHack **(Standalone)** [LW],<br>Triforce **(Standalone)** [LW] | No | Disc image file for single-disc games, .m3u playlist for multi-disc games |
|
||||
| genesis | Sega Genesis | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>BlastEm,<br>BlastEm **(Standalone)** [L],<br>Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
|
@ -4181,8 +4309,9 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| lutris | Lutris Open Gaming Platform | Lutris **(Standalone)** [L] | | No | See the specific _Lutris_ section elsewhere in this guide |
|
||||
| lutro | Lutro Game Engine | Lutro | | | |
|
||||
| macintosh | Apple Macintosh | MAME Mac SE Bootable **(Standalone)** | MAME Mac SE Boot Disk **(Standalone)**,<br>MAME Mac Plus Bootable **(Standalone)**,<br>MAME Mac Plus Boot Disk **(Standalone)**,<br>Basilisk II **(Standalone)**,<br>SheepShaver **(Standalone)** | Yes | See the specific _Apple Macintosh_ section elsewhere in this guide |
|
||||
| mame | Multiple Arcade Machine Emulator | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME **(Standalone)**,<br>FinalBurn Neo,<br>FinalBurn Neo **(Standalone)** [LW],<br>FB Alpha 2012,<br>Geolith,<br>Flycast,<br>Flycast **(Standalone)**,<br>Flycast Dojo **(Standalone)**,<br>Kronos [LW],<br>Model 2 Emulator **(Standalone)** [W],<br>Model 2 Emulator [Suspend ES-DE] **(Standalone)** [W],<br>Supermodel **(Standalone)** [LW],<br> _Shortcut or script_ | Depends | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| mame | Multiple Arcade Machine Emulator | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2003,<br>MAME 2000,<br>MAME **(Standalone)**,<br>FinalBurn Neo,<br>FinalBurn Neo **(Standalone)** [LW],<br>FB Alpha 2012,<br>Geolith,<br>Flycast,<br>Flycast **(Standalone)**,<br>Flycast Dojo **(Standalone)**,<br>Kronos [LW],<br>Model 2 Emulator **(Standalone)** [W],<br>Model 2 Emulator [Suspend ES-DE] **(Standalone)** [W],<br>Supermodel **(Standalone)** [LW],<br>MFME **(Standalone)** [LW],<br> _Shortcut or script_ | Depends | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| mame-advmame | AdvanceMAME | AdvanceMAME **(Standalone)** [LW] | | Depends | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| mark3 | Sega Mark III | Genesis Plus GX | Genesis Plus GX Wide,<br>SMS Plus GX,<br>Gearsystem,<br>PicoDrive,<br>Mednafen **(Standalone)**,<br>Mesen **(Standalone)** [LW],<br>ares **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| mastersystem | Sega Master System | Genesis Plus GX | Genesis Plus GX Wide,<br>SMS Plus GX,<br>Gearsystem,<br>PicoDrive,<br>Mednafen **(Standalone)**,<br>Mesen **(Standalone)** [LW],<br>ares **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| megacd | Sega Mega-CD | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>ares **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | Yes | |
|
||||
| megacdjp | Sega Mega-CD [Japan] | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>ares **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | Yes | |
|
||||
|
@ -4199,13 +4328,13 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| msxturbor | MSX Turbo R | blueMSX | openMSX **(Standalone)**,<br>openMSX No Machine **(Standalone)** | Yes | |
|
||||
| mugen | M.U.G.E.N Game Engine | Ikemen GO **(Standalone)** | | No | See the specific _M.U.G.E.N Game Engine_ section elsewhere in this guide |
|
||||
| multivision | Othello Multivision | Gearsystem | Mesen **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| n3ds | Nintendo 3DS | Citra [LW],<br>Citra **(Standalone)** [M] | Citra 2018 [LW],<br>Citra **(Standalone)** [LW]<br>Mandarine **(Standalone)**,<br>Lime3DS **(Standalone)**,<br>Panda3DS **(Standalone)** | No | Single ROM file |
|
||||
| n3ds | Nintendo 3DS | Citra [LW],<br>Citra **(Standalone)** [M] | Citra 2018 [LW],<br>Citra **(Standalone)** [LW],<br>Azahar **(Standalone)**,<br>Mandarine **(Standalone)**,<br>Lime3DS **(Standalone)**,<br>Panda3DS **(Standalone)** | No | Single ROM file |
|
||||
| n64 | Nintendo 64 | Mupen64Plus-Next | Mupen64Plus **(Standalone)**,<br>ParaLLEl N64,<br>simple64 **(Standalone)** [LW],<br>Rosalie's Mupen GUI **(Standalone)** [LW],<br>Project64 **(Standalone)** [W],<br>ares **(Standalone)**,<br>sixtyforce **(Standalone)** [M] | No | Single archive or ROM file |
|
||||
| n64dd | Nintendo 64DD | ParaLLEl N64 [LW],<br>Mupen64Plus-Next [M] | Mupen64Plus-Next [LW],<br>ParaLLEl N64 [M],<br>Rosalie's Mupen GUI **(Standalone)** [LW],<br>ares **(Standalone)** | Yes | See the specific _Nintendo 64DD_ section elsewhere in this guide |
|
||||
| naomi | Sega NAOMI | Flycast | Flycast **(Standalone)**,<br>Flycast Dojo **(Standalone)**,<br>Demul **(Standalone)** [W] | Yes | Single archive file + .chd file in subdirectory if GD-ROM game |
|
||||
| naomi2 | Sega NAOMI 2 | Flycast | Flycast **(Standalone)**,<br>Flycast Dojo **(Standalone)**,<br>Demul **(Standalone)** [W] | Yes | Single archive file + .chd file in subdirectory if GD-ROM game |
|
||||
| naomigd | Sega NAOMI GD-ROM | Flycast | Flycast **(Standalone)**,<br>Flycast Dojo **(Standalone)** | Yes | Single archive file + .chd file in subdirectory if GD-ROM game |
|
||||
| nds | Nintendo DS | melonDS DS | melonDS @,<br>melonDS **(Standalone)**,<br>DeSmuME,<br>DeSmuME 2015,<br>DeSmuME **(Standalone)** [L],<br>SkyEmu **(Standalone)**,<br>NooDS **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| nds | Nintendo DS | melonDS DS | melonDS @,<br>melonDS **(Standalone)**,<br>DeSmuME,<br>DeSmuME 2015,<br>DeSmuME **(Standalone)** [L],<br>NooDS,<br>NooDS **(Standalone)** [LW],<br>SkyEmu **(Standalone)** | No | Single archive or ROM file |
|
||||
| neogeo | SNK Neo Geo | FinalBurn Neo | FinalBurn Neo **(Standalone)** [LW],<br>Geolith,<br>MAME **(Standalone)** | Yes | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| neogeocd | SNK Neo Geo CD | NeoCD | FinalBurn Neo,<br>FinalBurn Neo **(Standalone)** [LW],<br>MAME **(Standalone)** | Yes | .chd (NeoCD and MAME only) or .cue file |
|
||||
| neogeocdjp | SNK Neo Geo CD [Japan] | NeoCD | FinalBurn Neo,<br>FinalBurn Neo **(Standalone)** [LW],<br>MAME **(Standalone)** | Yes | .chd (NeoCD and MAME only) or .cue file |
|
||||
|
@ -4227,17 +4356,17 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| pico8 | PICO-8 Fantasy Console | PICO-8 **(Standalone)** | PICO-8 Splore **(Standalone)**,<br>Retro8 | No | See the specific _PICO-8_ section elsewhere in this guide |
|
||||
| plus4 | Commodore Plus/4 | VICE xplus4 | VICE xplus4 **(Standalone)** | No | Single archive or image file for tape, cartridge or single-diskette games, .m3u playlist for multi-diskette games |
|
||||
| pokemini | Nintendo Pokémon Mini | PokeMini | | No | |
|
||||
| ports | Ports | _Shortcut or script_ | _AppImage_ [L],<br>ECWolf (Wolfenstein 3D),<br>NXEngine (Cave Story),<br>OpenLara (Tomb Raider) [LW],<br>Super Bros War | Yes for ECWolf | See the specific _Ports and desktop applications_ section elsewhere in this guide |
|
||||
| ports | Ports | _Shortcut or script_ | _AppImage_ [L],<br>ECWolf (Wolfenstein 3D),<br>CannonBall (OutRun),<br>Mr.Boom (Bomberman),<br>NXEngine (Cave Story),<br>OpenLara (Tomb Raider) [LW],<br>Super Bros War | Yes for ECWolf | See the specific _Ports and desktop applications_ section elsewhere in this guide |
|
||||
| ps2 | Sony PlayStation 2 | LRPS2 [LW],<br>PCSX2 **(Standalone)** [M] | PCSX2 [LW] @,<br>PCSX2 **(Standalone)** [LW],<br>PCSX2 Legacy **(Standalone)** @,<br>Play! **(Standalone)**,<br>AetherSX2 **(Standalone)** [M] | Yes except for Play! | |
|
||||
| ps3 | Sony PlayStation 3 | RPCS3 Shortcut **(Standalone)** | RPCS3 Directory **(Standalone)** | Yes | See the specific _Sony PlayStation 3_ section elsewhere in this guide |
|
||||
| ps4 | Sony PlayStation 4 | _Placeholder_ | | | |
|
||||
| ps3 | Sony PlayStation 3 | RPCS3 Shortcut **(Standalone)** | RPCS3 Game Serial **(Standalone)**,<br>RPCS3 Directory **(Standalone)** | Yes | See the specific _Sony PlayStation 3_ section elsewhere in this guide |
|
||||
| ps4 | Sony PlayStation 4 | shadPS4 Shortcut **(Standalone)** [LW],<br>shadPS4 Game Serial **(Standalone)** [M] | shadPS4 Game Serial **(Standalone)** [LW],<br>shadPS4 eboot.bin **(Standalone)** | No | See the specific _Sony PlayStation 4_ section elsewhere in this guide |
|
||||
| psp | Sony PlayStation Portable | PPSSPP | PPSSPP **(Standalone)** | No | Single disc image file |
|
||||
| psvita | Sony PlayStation Vita | Vita3K **(Standalone)** | | Yes | See the specific _Sony PlayStation Vita_ section elsewhere in this guide |
|
||||
| psx | Sony PlayStation | Beetle PSX | Beetle PSX HW,<br>PCSX ReARMed,<br>SwanStation,<br>DuckStation **(Standalone)**,<br>Mednafen **(Standalone)** | Yes | .chd file for single-disc games, .m3u playlist for multi-disc games |
|
||||
| pv1000 | Casio PV-1000 | MAME - Current | MAME **(Standalone)** | No | Single archive or ROM file |
|
||||
| quake | Quake | TyrQuake | vitaQuake 2,<br>vitaQuake 2 [Rogue],<br>vitaQuake 2 [Xatrix],<br>vitaQuake 2 [Zaero],<br>vitaQuake 3 [LW],<br> _Shortcut or script_ | No | |
|
||||
| samcoupe | MGT SAM Coupé | SimCoupé **(Standalone)** | | No | Single archive or ROM file |
|
||||
| satellaview | Nintendo Satellaview | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-mercury Accuracy,<br>bsnes **(Standalone)** [LW],<br>Mesen-S,<br>Mesen **(Standalone)** [LW],<br>ares **(Standalone)** | | |
|
||||
| satellaview | Nintendo Satellaview | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-jg,<br>bsnes-mercury Accuracy,<br>bsnes **(Standalone)** [LW],<br>Mesen-S,<br>Mesen **(Standalone)** [LW],<br>ares **(Standalone)** | | |
|
||||
| saturn | Sega Saturn | Beetle Saturn | Kronos [LW],<br>Kronos **(Standalone)** [LW],<br>YabaSanshiro [LW],<br>Yaba Sanshiro 2 **(Standalone)** [W],<br>Yabause,<br>Mednafen **(Standalone)**,<br>SSF **(Standalone)** [W] | Yes | .chd file for single-disc games, .m3u playlist for multi-disc games |
|
||||
| saturnjp | Sega Saturn [Japan] | Beetle Saturn | Kronos [LW],<br>Kronos **(Standalone)** [LW],<br>YabaSanshiro [LW],<br>Yaba Sanshiro 2 **(Standalone)** [W],<br>Yabause,<br>Mednafen **(Standalone)**,<br>SSF **(Standalone)** [W] | Yes | .chd file for single-disc games, .m3u playlist for multi-disc games |
|
||||
| scummvm | ScummVM Game Engine | ScummVM | ScummVM **(Standalone)**,<br>DREAMM **(Standalone)** | No | See the specific _ScummVM_ section elsewhere in this guide |
|
||||
|
@ -4246,16 +4375,16 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| sega32xjp | Sega Super 32X [Japan] | PicoDrive | ares **(Standalone)** | No | Single archive or ROM file |
|
||||
| sega32xna | Sega Genesis 32X [North America] | PicoDrive | ares **(Standalone)** | No | Single archive or ROM file |
|
||||
| segacd | Sega CD | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>ares **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | Yes | |
|
||||
| sfc | Nintendo SFC (Super Famicom) | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-mercury Accuracy,<br>bsnes **(Standalone)** [LW],<br>Beetle Supafaust [LW],<br>Mesen-S,<br>Mesen **(Standalone)** [LW],<br>Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| sfc | Nintendo SFC (Super Famicom) | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-jg,<br>bsnes-mercury Accuracy,<br>bsnes **(Standalone)** [LW],<br>Beetle Supafaust [LW],<br>Mesen-S,<br>Mesen **(Standalone)** [LW],<br>Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| sg-1000 | Sega SG-1000 | Genesis Plus GX | Genesis Plus GX Wide,<br>Gearsystem,<br>blueMSX,<br>Mesen **(Standalone)** [LW],<br>ares **(Standalone)** | No | Single archive or ROM file |
|
||||
| sgb | Nintendo Super Game Boy | Mesen-S | Mesen **(Standalone)** [LW],<br>SameBoy,<br>mGBA,<br>mGBA **(Standalone)** | | Single archive or ROM file |
|
||||
| snes | Nintendo SNES (Super Nintendo) | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-mercury Accuracy,<br>bsnes **(Standalone)** [LW],<br>Beetle Supafaust [LW],<br>Mesen-S,<br>Mesen **(Standalone)** [LW],<br>Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| snesna | Nintendo SNES (Super Nintendo) [North America] | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-mercury Accuracy,<br>bsnes **(Standalone)** [LW],<br>Beetle Supafaust [LW],<br>Mesen-S,<br>Mesen **(Standalone)** [LW],<br>Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| snes | Nintendo SNES (Super Nintendo) | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-jg,<br>bsnes-mercury Accuracy,<br>bsnes **(Standalone)** [LW],<br>Beetle Supafaust [LW],<br>Mesen-S,<br>Mesen **(Standalone)** [LW],<br>Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| snesna | Nintendo SNES (Super Nintendo) [North America] | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-jg,<br>bsnes-mercury Accuracy,<br>bsnes **(Standalone)** [LW],<br>Beetle Supafaust [LW],<br>Mesen-S,<br>Mesen **(Standalone)** [LW],<br>Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>jgenesis **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| solarus | Solarus Game Engine | Solarus **(Standalone)** | | No | Single .solarus game file |
|
||||
| spectravideo | Spectravideo | blueMSX | | | |
|
||||
| steam | Valve Steam | Steam **(Standalone)** | | No | See the specific _Steam_ section elsewhere in this guide |
|
||||
| stv | Sega Titan Video Game System | Kronos [LW],<br>MAME - Current [M] | MAME - Current [LW],<br>MAME **(Standalone)**,<br>Mednafen **(Standalone)** | Yes | Single archive file |
|
||||
| sufami | Bandai SuFami Turbo | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-mercury Accuracy,<br>bsnes **(Standalone)** [LW],<br>ares **(Standalone)** | | |
|
||||
| sufami | Bandai SuFami Turbo | Snes9x - Current | Snes9x 2010,<br>Snes9x 2005 Plus,<br>Snes9x **(Standalone)**,<br>bsnes,<br>bsnes-hd,<br>bsnes-jg,<br>bsnes-mercury Accuracy,<br>bsnes **(Standalone)** [LW],<br>ares **(Standalone)** | | |
|
||||
| supergrafx | NEC SuperGrafx | Beetle SuperGrafx | Beetle PCE,<br>Mednafen **(Standalone)**,<br>Mesen **(Standalone)** [LW],<br>ares **(Standalone)** | No | Single archive or ROM file |
|
||||
| supervision | Watara Supervision | Potator | MAME - Current,<br>MAME **(Standalone)** | No | Single archive or ROM file |
|
||||
| supracan | Funtech Super A'Can | MAME - Current | MAME **(Standalone)** | Yes | Single archive or ROM file. You need a supracan.zip archive that contains a valid internal_68k.bin file and an empty file named umc6650.bin |
|
||||
|
@ -4274,6 +4403,7 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| vectrex | GCE Vectrex | vecx | MAME - Current,<br>MAME **(Standalone)** | Yes for MAME | Single archive or ROM file |
|
||||
| vic20 | Commodore VIC-20 | VICE xvic | VICE xvic **(Standalone)** | No | Single archive or tape, cartridge or diskette image file |
|
||||
| videopac | Philips Videopac G7000 | O2EM | MAME - Current,<br>MAME **(Standalone)** | Yes | Single archive or ROM file |
|
||||
| vircon32 | Vircon32 Virtual Console | Vircon32 | Vircon32 **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| virtualboy | Nintendo Virtual Boy | Beetle VB | Mednafen **(Standalone)** | No | Single archive or ROM file |
|
||||
| vpinball | Visual Pinball | Visual Pinball **(Standalone)** | | No | See the specific _Visual Pinball_ section elsewhere in this guide |
|
||||
| vsmile | VTech V.Smile | MAME - Current | MAME **(Standalone)** | Yes | Single archive or ROM file |
|
||||
|
@ -4283,12 +4413,13 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| windows | Microsoft Windows | _Suspend ES-DE_ | _Keep ES-DE running_,<br> _AppImage (Suspend ES-DE)_ [L],<br> _AppImage (Keep ES-DE running)_ [L] | No | Shortcut (.desktop/.app/.lnk) file, script or AppImage |
|
||||
| windows3x | Microsoft Windows 3.x | DOSBox-X **(Standalone)** | DOSBox-Pure,<br> _Shortcut or script (Suspend ES-DE)_,<br> _Shortcut or script (Keep ES-DE running)_,<br> _AppImage (Suspend ES-DE)_ [L],<br> _AppImage (Keep ES-DE running)_ [L] | No | See the specific _Microsoft Windows 3.x and 9x_ section elsewhere in this guide |
|
||||
| windows9x | Microsoft Windows 9x | DOSBox-X **(Standalone)** | DOSBox-Pure,<br> _Shortcut or script (Suspend ES-DE)_,<br> _Shortcut or script (Keep ES-DE running)_,<br> _AppImage (Suspend ES-DE)_ [L],<br> _AppImage (Keep ES-DE running)_ [L] | No | See the specific _Microsoft Windows 3.x and 9x_ section elsewhere in this guide |
|
||||
| wonderswan | Bandai WonderSwan | Beetle Cygne | Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>ares [Benesse Pocket Challenge V2] **(Standalone)** | No | Single archive or ROM file |
|
||||
| wonderswancolor | Bandai WonderSwan Color | Beetle Cygne | Mednafen **(Standalone)**,<br>ares **(Standalone)** | No | Single archive or ROM file |
|
||||
| wonderswan | Bandai WonderSwan | Beetle Cygne | Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>ares [Benesse Pocket Challenge V2] **(Standalone)**,<br>Mesen **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| wonderswancolor | Bandai WonderSwan Color | Beetle Cygne | Mednafen **(Standalone)**,<br>ares **(Standalone)**,<br>Mesen **(Standalone)** [LW] | No | Single archive or ROM file |
|
||||
| x1 | Sharp X1 | X Millennium | MAME [Diskette] **(Standalone)**,<br>MAME [Tape] **(Standalone)** | Yes for MAME | Single archive or diskette/tape file |
|
||||
| x68000 | Sharp X68000 | PX68k | MAME **(Standalone)**,<br>XM6 Pro-68k **(Standalone)** [W],<br>XM6 Pro-68k **(Wine)** [L],<br>XM6 Pro-68k **(Proton)** [L] | Yes except for XM6 Pro-68k | |
|
||||
| x68000 | Sharp X68000 | PX68k | MAME **(Standalone)**,<br>XM6 Pro-68k **(Standalone)** [W],<br>XM6 TypeG **(Standalone**) [W],<br>XM6 Pro-68k **(Wine)** [L],<br>XM6 Pro-68k **(Proton)** [L],<br>XM6 TypeG **(Wine)** [L],<br>XM6 TypeG **(Proton)** [L] | Yes for PX68k and MAME | |
|
||||
| xbox | Microsoft Xbox | xemu **(Standalone)** | Cxbx-Reloaded **(Standalone)** [W] | Yes for xemu | Single .iso file for xemu or unpacked .iso directory for Cxbx-Reloaded |
|
||||
| xbox360 | Microsoft Xbox 360 | xenia **(Standalone)** [W],<br>xenia **(Wine)** [L] | xenia **(Proton)** [L],<br> _Shortcut or script_ [L] | No | See the specific _Microsoft Xbox 360_ section elsewhere in this guide |
|
||||
| xboxone | Microsoft Xbox One | _Placeholder_ | | | |
|
||||
| zmachine | Infocom Z-machine | MojoZork | Gargoyle **(Standalone)** | No | |
|
||||
| zx81 | Sinclair ZX81 | EightyOne | | No | |
|
||||
| zxnext | Sinclair ZX Spectrum Next | #CSpect **(Standalone)** [LW],<br>ZEsarUX **(Standalone)** [M] | ZEsarUX **(Standalone)** [LW] | No | In separate folder interpreted as a file |
|
||||
|
|
38
USERGUIDE.md
38
USERGUIDE.md
|
@ -118,6 +118,8 @@ _This is the dialog shown if no game files were found. It lets you configure the
|
|||
|
||||
## Upgrading to a newer release
|
||||
|
||||
**Linux, macOS and Windows**
|
||||
|
||||
**Note:** Before upgrading ES-DE, make sure that you have not made any system customizations anywhere in the installation directory structure as these files will be overwritten during the upgrade process. All customizations should go into ~/ES-DE/custom_systems/ as described elsewhere in this guide. None of the upgrade methods mentioned below will ever touch any files inside your ES-DE directory tree.
|
||||
|
||||
There is a built-in application updater that can automatically upgrade the Linux AppImages, and for Windows and macOS there is support for downloading the packages directly inside ES-DE. Just be aware that these will need to be manually installed. Using the application updater is straightforward, just follow the on-screen instructions. For the AppImage releases the old file is retained by renaming it, adding its version to the filename followed by the .OLD extension, for example `ES-DE_x64_SteamDeck.AppImage_3.0.0.OLD`
|
||||
|
@ -126,7 +128,20 @@ Note that the updater will keep whatever filename you had for your running AppIm
|
|||
|
||||
On Windows and macOS you can specify to which directory you want to save the downloaded file. The default is `C:\Users\myusername\Downloads` on Windows and `/Users/myusername/Downloads` on macOS.
|
||||
|
||||
On Android the update process differs depending on whether you have the Patreon release or a release from either the Samsung Galaxy Store or Huawei AppGallery. For the store versions you simply update via the store app. For the Patreon release you'll get an email (sent to the address you used when buying ES-DE there) whenever there is a new version. For all Android releases, unless you have modifed the option _Check for application updates_ you'll see a popup on application startup whenever there's a new release available.
|
||||
To perform the upgrade on macOS simply open the .dmg file and install ES-DE on top of the old installation (i.e. replacing it).
|
||||
|
||||
For the Windows installer release simply run the .exe file and select uninstallation of the old version before installing the new version. For the Windows portable release refer to the README.txt file in the zip archive for instructions on how to perform the update.
|
||||
|
||||
**Android**
|
||||
|
||||
On Android the update process differs depending on whether you have the Patreon release or a release from either the Samsung Galaxy Store or Huawei AppGallery. For the store versions you simply update via the store app. For the Patreon release you'll get an email (sent to the address you used on Patreon) whenever there is a new version. This email contains a download link to the latest APK, and to apply the update you simply run this APK file. This is a safe operation that will not change or remove any of your data such as settings, scraped media etc.
|
||||
|
||||
Also for the Patreon release you'll see a popup on application startup whenever there's a new version available, unless you have modifed the option _Check for application updates_ in the _Other settings_ menu. Note that such notifications are not shown for the Galaxy Store and AppGallery releases as those store apps have their built-in update notifications.
|
||||
|
||||
For the Patreon release you can also resend the latest update email to yourself using the self-service resend tool:\
|
||||
https://resend.es-de.org
|
||||
|
||||
**After the upgrade**
|
||||
|
||||
Regardless of package format and operating system it's a good idea to update the ROM directory tree after upgrading to a new version. It's possible that the new ES-DE release adds support for more systems and emulators compared to the version you previously had installed. The easiest way to do this is via the _Create/update system directories_ entry in the _Utilities_ menu. Alternatively the _--create-system-dirs_ command line option can be used. Both methods work identically and will create any missing system directories and also update the systems.txt and systeminfo.txt files. This is a safe operation as it will not overwrite or delete your game files.
|
||||
|
||||
|
@ -250,6 +265,10 @@ On some GPUs with buggy drivers, ES-DE may only display a black screen on startu
|
|||
ES-DE.exe --resolution 1281 800
|
||||
```
|
||||
|
||||
Another potential workaround for some buggy drivers is to set ES-DE to compatibility mode and/or select _Disable full-screen optimizations_. These options are available when right-clicking on ES-DE.exe in the file manager and chosing _Properties_ and then selecting the _Compatibility_ tab.
|
||||
|
||||
Yet another issue with buggy GPU drivers is that for computers with multiple GPUs such as gaming laptops with integrated Intel graphics in addition to a discrete GPU (e.g. from Nvidia) there may be issues when window switching between ES-DE and other applications. In such cases severe screen flickering may get introduced. This is normally worked around by explicitly setting ES-DE to use the discrete GPU in the Windows graphics settings.
|
||||
|
||||
Some computers using Intel Iris Xe GPUs refuse to start ES-DE or display excessive graphics corruption. These problems are seemingly caused by driver bugs and do not occur when using Linux with the same hardware. There is no known solution or workaround to this issue other than switching to Linux or waiting for Intel to resolve the problem with a driver update.
|
||||
|
||||
Some older games (and possibly emulators too) may not work correctly or even start at all if ES-DE is set to run in the background while a game is launched. So if you experience strange issues with some games, make sure that the setting _Run in background (while game is launched)_ is disabled. If launching any of these problematic games from the _desktop_ system, also make sure to use the default emulator entry _Suspend ES-DE_ and not the alternative emulator _Keep ES-DE running_.
|
||||
|
@ -280,8 +299,6 @@ There is a very annoying default configuration when using Sony controllers like
|
|||
|
||||
One macOS-specific requirement is that the RetroArch setting _Start in Fullscreen mode_ is enabled or ES-DE will not be able to switch to the emulator window when launching games. As a workaround you can switch to the window manually using Command + Tab but it probably doesn't make sense to run emulators in windowed mode anyway. This issue has not been observed with any other emulators.
|
||||
|
||||
At the time of writing there is an additional issue with the ARM release of RetroArch where ES-DE will not be able to consistently switch to its window on game launch if the setting _Close windows when quitting an application_ under the _Desktop & Dock_ entry in the macOS _System Settings_ has been set to disabled. This error does not occur for the Intel/x86 release of RetroArch or with any other standalone emulators (including those built specifically for the ARM architecture).
|
||||
|
||||
The first time you launch a RetroArch-emulated game from within ES-DE the operating system will present you with a security option with the following description:
|
||||
|
||||
`"ES-DE" would like to access files in your Documents folder.`
|
||||
|
@ -625,12 +642,12 @@ If ES-DE is unable to find an emulator when a game is launched, a notification p
|
|||
|
||||
## Using the Steam release of RetroArch
|
||||
|
||||
As this release of RetroArch is executed via the Steam application it's behaving a bit glitchy and strange with ES-DE (which is due to the nature of Steam). In addition to this there seem to be some bugs in either Steam or RetroArch, or both. The following issues have been observed:
|
||||
As this release of RetroArch is executed via the Steam application it's behaving a bit glitchy and strange with ES-DE (which is due to the nature of Steam). The following issues have been observed:
|
||||
|
||||
* ES-DE will continue to run in the background due to the way that Steam works
|
||||
* Game launching is not seamless and there will be some flickering
|
||||
* If the Steam GUI is visible, focus may not return to ES-DE when exiting a game. Minimizing Steam increases the chances of this working properly but it's not guaranteed to completely fix the problem
|
||||
* Filenames containing apostrophes do not work, you need to rename these game files to be able to launch them
|
||||
* Game launching may not be seamless, with screen flickering and similar on some devices and operating systems
|
||||
* If the Steam GUI is visible, focus may not return to ES-DE when exiting a game (this seems to be caused by the Steam overlay)
|
||||
* There may be additional focusing and window switching issues caused by the Steam overlay
|
||||
* Core searches will not work, if an emulator core is missing there will be no error notification inside ES-DE and game launching will just silently fail
|
||||
* Logging output from emulators is not possible due to ES-DE running in the background
|
||||
|
||||
|
@ -641,7 +658,7 @@ Simply add alternative emulator entries such as the following example (which ena
|
|||
<command label="Nestopia UE (Steam)">%RUNINBACKGROUND% %EMULATOR_STEAM% -applaunch 1118310 -L nestopia_libretro %ROM%</command>
|
||||
```
|
||||
|
||||
This will work on both Linux and Windows.
|
||||
This will work on both Linux and Windows (and possibly macOS too).
|
||||
|
||||
A complete entry for the nes system could look like the following:
|
||||
```xml
|
||||
|
@ -2504,6 +2521,11 @@ Then add the game Title ID to this file. This ID can be found inside the Vita3K
|
|||
|
||||
Game launching and scraping should now work fine in ES-DE.
|
||||
|
||||
To simplify the setup described above there is a convenient archive of .psvita files available that covers most of the game library for this console. It can be downloaded from here:\
|
||||
https://github.com/Jetup13/Retroid-Pocket-5-Wiki/wiki/Emulators-and-Formats#vita3k-frontend-support
|
||||
|
||||
Just extract the corresponding file for any game you have installed in Vita3K and place it in ~/ROMs/psvita and you're good to go.
|
||||
|
||||
### Steam
|
||||
|
||||
These games can easily be added to ES-DE using shortcuts, just be aware that this requires that the games have been installed locally.
|
||||
|
|
|
@ -44,6 +44,7 @@ set(ES_HEADERS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperSingle.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScreensaverOptions.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiSettings.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiSystemStatusOptions.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiThemeDownloader.h
|
||||
|
||||
# Scrapers
|
||||
|
@ -95,6 +96,7 @@ set(ES_SOURCES
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperSingle.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScreensaverOptions.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiSettings.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiSystemStatusOptions.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiThemeDownloader.cpp
|
||||
|
||||
# Scrapers
|
||||
|
@ -111,17 +113,21 @@ set(ES_SOURCES
|
|||
)
|
||||
|
||||
if(WIN32)
|
||||
LIST(APPEND ES_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/assets/ES-DE.rc)
|
||||
list(APPEND ES_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/assets/ES-DE.rc)
|
||||
endif()
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
# OS-specific installation and package generation setup.
|
||||
|
||||
# Define target.
|
||||
if(APPLE)
|
||||
if(IOS)
|
||||
include(${CMAKE_SOURCE_DIR}/ios/cmake/ios.cmake)
|
||||
elseif(APPLE)
|
||||
include_directories(${COMMON_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
add_executable(ES-DE ${ES_SOURCES} ${ES_HEADERS})
|
||||
target_link_libraries(ES-DE ${COMMON_LIBRARIES} es-core)
|
||||
target_link_libraries(ES-DE ${COMMON_LIBRARIES} "-framework CoreFoundation -framework IOKit"
|
||||
"-framework SystemConfiguration"
|
||||
"-framework IOBluetooth" es-core)
|
||||
set_target_properties(ES-DE PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
if(CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 15.0.0)
|
||||
target_link_options(ES-DE PRIVATE LINKER:-no_warn_duplicate_libraries)
|
||||
|
@ -202,7 +208,7 @@ if(WIN32)
|
|||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/themes/modern-es-de DESTINATION themes)
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/themes/slate-es-de DESTINATION themes)
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/resources DESTINATION .)
|
||||
elseif(APPLE)
|
||||
elseif(APPLE AND NOT IOS)
|
||||
# For completely unknown reasons, when generating a Bundle using cpack, an extra 'Resources'
|
||||
# directory is added to the target path. Simply adding the two dots as a prefix fixes the
|
||||
# problem, but doing so would break 'make install' which was actually behaving correctly.
|
||||
|
@ -288,7 +294,7 @@ elseif(HAIKU)
|
|||
DESTINATION data/es-de/themes)
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/resources
|
||||
DESTINATION data/es-de)
|
||||
elseif(NOT ANDROID)
|
||||
elseif(NOT ANDROID AND NOT IOS)
|
||||
install(TARGETS es-de RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
install(TARGETS es-pdf-convert RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES Linux OR CMAKE_SYSTEM_NAME MATCHES FreeBSD)
|
||||
|
@ -350,6 +356,11 @@ endif()
|
|||
|
||||
# Settings per operating system and generator type.
|
||||
if(APPLE)
|
||||
# In case we're cross-compiling for x86_64 using an ARM processor.
|
||||
if(CPU_ARCHITECTURE MATCHES arm64 AND CMAKE_OSX_ARCHITECTURES MATCHES x86_64)
|
||||
set(CPU_ARCHITECTURE x64)
|
||||
endif()
|
||||
|
||||
set(CPACK_GENERATOR Bundle)
|
||||
set(CPACK_PACKAGE_FILE_NAME ES-DE_${CPACK_PACKAGE_VERSION}-${CPU_ARCHITECTURE})
|
||||
set(CPACK_DMG_VOLUME_NAME "ES-DE ${CPACK_PACKAGE_VERSION}")
|
||||
|
|
|
@ -24,7 +24,7 @@ BEGIN
|
|||
VALUE "FileDescription", "ES-DE\0"
|
||||
VALUE "FileVersion", RESOURCE_VERSION_STRING
|
||||
VALUE "InternalName", "ES-DE.exe\0"
|
||||
VALUE "LegalCopyright", "Copyright (c) 2024 Northwestern Software AB\0"
|
||||
VALUE "LegalCopyright", "Copyright (c) 2024-2025 Northwestern Software AB\0"
|
||||
VALUE "LegalTrademarks", "\0"
|
||||
VALUE "OriginalFilename", "ES-DE.exe\0"
|
||||
VALUE "ProductName", "ES-DE\0"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>3.1.1</string>
|
||||
<string>3.2.0</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
|
@ -11,7 +11,7 @@
|
|||
<key>CFBundleExecutable</key>
|
||||
<string>ES-DE</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>ES-DE 3.1.1</string>
|
||||
<string>ES-DE 3.2.0</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>ES-DE.icns</string>
|
||||
<key>CFBundleName</key>
|
||||
|
@ -21,9 +21,9 @@
|
|||
<key>CFBundleSignature</key>
|
||||
<string>ESDE</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.1.1</string>
|
||||
<string>3.2.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>3.1.1</string>
|
||||
<string>3.2.0</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
|
@ -38,8 +38,10 @@
|
|||
<string>NSApplication</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>ES-DE</string>
|
||||
<key>NSBluetoothAlwaysUsageDescription</key>
|
||||
<string>ES-DE checks the status of the Bluetooth adapter in order to display the corresponding system status indicator on screen</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright (c) 2024 Northwestern Software AB
|
||||
<string>Copyright (c) 2024-2025 Northwestern Software AB
|
||||
Copyright (c) 2020-2024 Leon Styhre
|
||||
Copyright (c) 2014 Alec Lofquist
|
||||
Licensed under the MIT license</string>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2024 Northwestern Software AB
|
||||
Copyright (c) 2024-2025 Northwestern Software AB
|
||||
Copyright (c) 2020-2024 Leon Styhre
|
||||
Copyright (c) 2014 Alec Lofquist
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2024 Northwestern Software AB
|
||||
Copyright (c) 2024-2025 Northwestern Software AB
|
||||
Copyright (c) 2020-2024 Leon Styhre
|
||||
Copyright (c) 2014 Alec Lofquist
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ ES-DE Frontend - Portable installation on Windows
|
|||
-------------------------------------------------
|
||||
|
||||
ES-DE release:
|
||||
3.1.1
|
||||
3.2.0
|
||||
|
||||
The latest version can be downloaded from https://es-de.org
|
||||
|
||||
|
@ -42,6 +42,7 @@ Preconfigured emulator locations:
|
|||
Emulators\RetroArch-Win64\retroarch.exe
|
||||
Emulators\RetroArch\retroarch.exe
|
||||
Emulators\3dSen\3dSen.exe
|
||||
Emulators\a7800\a7800.exe
|
||||
Emulators\AceDL\AceDL.exe
|
||||
Emulators\AdvanceMAME\advmame.exe
|
||||
Emulators\Altirra\Altirra64.exe
|
||||
|
@ -50,6 +51,7 @@ Emulators\AppleWin\AppleWin.exe
|
|||
Emulators\ArcadeFlashWeb\ArcadeFlashWeb.exe
|
||||
Emulators\ares\ares.exe
|
||||
Emulators\atari800\atari800.exe
|
||||
Emulators\azahar\azahar.exe
|
||||
Emulators\BasiliskII\BasiliskII.exe
|
||||
Emulators\BeebEm\BeebEm.exe
|
||||
Emulators\BigPEmu\BigPEmu.exe
|
||||
|
@ -94,6 +96,7 @@ Emulators\mandarine\mandarine-qt.exe
|
|||
Emulators\mednafen\mednafen.exe
|
||||
Emulators\melonDS\melonDS.exe
|
||||
Emulators\Mesen\Mesen.exe
|
||||
Emulators\MFME\MFME.exe
|
||||
Emulators\mGBA\mGBA.exe
|
||||
Emulators\mupen64plus\mupen64plus-ui-console.exe
|
||||
Emulators\noods\noods.exe
|
||||
|
@ -119,6 +122,7 @@ Emulators\ryujinx\Ryujinx.Ava.exe
|
|||
Emulators\sameboy\sameboy.exe
|
||||
Emulators\scummvm\scummvm.exe
|
||||
Emulators\sdl2trs\sdl2trs64.exe
|
||||
Emulators\shadPS4\shadPS4.exe
|
||||
Emulators\SheepShaver\SheepShaver.exe
|
||||
Emulators\SimCoupe\SimCoupe.exe
|
||||
Emulators\simple64\simple64-gui.exe
|
||||
|
@ -138,6 +142,7 @@ Emulators\VICE\xplus4.exe
|
|||
Emulators\VICE\bin\xplus4.exe
|
||||
Emulators\VICE\xvic.exe
|
||||
Emulators\VICE\bin\xvic.exe
|
||||
Emulators\Vircon32\Emulator\Vircon32.exe
|
||||
Emulators\VPinballX\VPinballX_GL64.exe
|
||||
Emulators\VPinballX\VPinballX64.exe
|
||||
Emulators\Vita3K\Vita3K.exe
|
||||
|
@ -146,6 +151,7 @@ Emulators\xemu\xemu.exe
|
|||
Emulators\xenia\xenia.exe
|
||||
Emulators\xenia_canary\xenia_canary.exe
|
||||
Emulators\XM6 Pro-68k\XM6.exe
|
||||
Emulators\xm6_typeg\xm6g.exe
|
||||
Emulators\xroar\xroar.exe
|
||||
Emulators\yabasanshiro\yabasanshiro.exe
|
||||
Emulators\ZEsarUX\zesarux.exe
|
||||
|
|
Binary file not shown.
|
@ -3,12 +3,12 @@ DESCRIPTION="ES-DE (EmulationStation Desktop Edition) is a frontend for browsing
|
|||
multi-platform collection. It comes preconfigured for use with a large selection \
|
||||
of emulators and game engines."
|
||||
HOMEPAGE="https://es-de.org"
|
||||
COPYRIGHT="2024 Northwestern Software AB"
|
||||
COPYRIGHT="2024-2025 Northwestern Software AB"
|
||||
LICENSE="MIT"
|
||||
REVISION="1"
|
||||
srcGitRev="842c9966eb73efb3436a4df2dfdd66063ce7361c"
|
||||
srcGitRev="a59b8016be3ccaab0a678a552128d06b32e7dc01"
|
||||
SOURCE_URI="https://gitlab.com/es-de/emulationstation-de/-/archive/$srcGitRev/emulationstation-de-$srcGitRev.tar.gz"
|
||||
CHECKSUM_SHA256="52c820beddba7e08014f589120c087d6b84b79a88b6213bf13a4e025fd728285"
|
||||
CHECKSUM_SHA256="492abe6b9e32158a177acf42ce212f15775eeb7f7f6171cd2ffd5c2c6c7686b4"
|
||||
SOURCE_FILENAME="emulationstation-de-$portVersion-$srcGitRev.tar.gz"
|
||||
SOURCE_DIR="emulationstation-de-$srcGitRev"
|
||||
ADDITIONAL_FILES="es-de.rdef.in"
|
|
@ -38,6 +38,9 @@
|
|||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="3.1.1" date="2024-12-13">
|
||||
<url>https://gitlab.com/es-de/emulationstation-de/-/releases</url>
|
||||
</release>
|
||||
<release version="3.1.0" date="2024-09-13">
|
||||
<url>https://gitlab.com/es-de/emulationstation-de/-/releases</url>
|
||||
</release>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "MameNames.h"
|
||||
#include "Scripting.h"
|
||||
#include "SystemData.h"
|
||||
#include "SystemStatus.h"
|
||||
#include "UIModeController.h"
|
||||
#include "Window.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
|
@ -156,6 +157,9 @@ const std::string FileData::getROMDirectory()
|
|||
{
|
||||
#if defined(__ANDROID__)
|
||||
return AndroidVariables::sROMDirectory;
|
||||
#elif defined(__IOS__)
|
||||
std::string dir {Utils::FileSystem::getHomePath() + "/Documents/ROMs"};
|
||||
return dir;
|
||||
#endif
|
||||
|
||||
const std::string& romDirSetting {Settings::getInstance()->getString("ROMDirectory")};
|
||||
|
@ -187,6 +191,10 @@ const std::string FileData::getROMDirectory()
|
|||
|
||||
const std::string FileData::getMediaDirectory()
|
||||
{
|
||||
#if defined(__IOS__)
|
||||
return Utils::FileSystem::getAppDataDirectory() + "/downloaded_media/";
|
||||
#endif
|
||||
|
||||
const std::string& mediaDirSetting {Settings::getInstance()->getString("MediaDirectory")};
|
||||
std::string mediaDirPath;
|
||||
|
||||
|
@ -896,6 +904,10 @@ void FileData::launchGame()
|
|||
std::string romPath {Utils::FileSystem::getEscapedPath(mPath)};
|
||||
std::string baseName {Utils::FileSystem::getStem(mPath)};
|
||||
std::string romRaw {Utils::FileSystem::getPreferredPath(mPath)};
|
||||
#if !defined(_WIN64)
|
||||
std::string romRawWindows {
|
||||
Utils::String::replace(Utils::FileSystem::getPreferredPath(mPath), "/", "\\")};
|
||||
#endif
|
||||
|
||||
// For the special case where a directory has a supported file extension and is therefore
|
||||
// interpreted as a file, check if there is a matching filename inside the directory.
|
||||
|
@ -1772,6 +1784,9 @@ void FileData::launchGame()
|
|||
command = Utils::String::replace(command, "%BASENAME%", baseName);
|
||||
command = Utils::String::replace(command, "%FILENAME%", fileName);
|
||||
command = Utils::String::replace(command, "%ROMRAW%", romRaw);
|
||||
#if !defined(_WIN64)
|
||||
command = Utils::String::replace(command, "%ROMRAWWIN%", romRawWindows);
|
||||
#endif
|
||||
command = Utils::String::replace(command, "%ROMPATH%",
|
||||
Utils::FileSystem::getEscapedPath(getROMDirectory()));
|
||||
#else
|
||||
|
@ -1901,6 +1916,8 @@ void FileData::launchGame()
|
|||
extraValue =
|
||||
Utils::String::replace(extraValue, "%ROMPATHRAW%", getROMDirectory());
|
||||
extraValue = Utils::String::replace(extraValue, "%ROMRAW%", romRaw);
|
||||
extraValue =
|
||||
Utils::String::replace(extraValue, "%ROMRAWWIN%", romRawWindows);
|
||||
extraValue = Utils::String::replace(extraValue, "%BASENAME%", baseName);
|
||||
extraValue = Utils::String::replace(extraValue, "//", "/");
|
||||
|
||||
|
@ -1926,6 +1943,12 @@ void FileData::launchGame()
|
|||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
// Hack to remove double quotation marks as these can occur under some special circumstances.
|
||||
const int quotationCount {static_cast<int>(
|
||||
std::count_if(command.cbegin(), command.cend(), [](char c) { return c == '\"'; }))};
|
||||
if (quotationCount % 2 != 0)
|
||||
command = Utils::String::replace(command, "\"\"", "\"");
|
||||
|
||||
command = Utils::String::replace(
|
||||
command, "%ESPATH%", Utils::String::replace(Utils::FileSystem::getExePath(), "/", "\\"));
|
||||
command = Utils::String::replace(command, "%EMUDIR%",
|
||||
|
@ -2096,10 +2119,12 @@ returnValue = Utils::Platform::launchGameUnix(command, startDirectory, runInBack
|
|||
}
|
||||
|
||||
// Unless we're running in the background while the game is launched, re-enable the text
|
||||
// scrolling that was disabled in ViewController.
|
||||
// scrolling that was disabled in ViewController. Also poll the system status immediately
|
||||
// in case something changed while the game was running.
|
||||
if (!runInBackground) {
|
||||
window->setAllowTextScrolling(true);
|
||||
window->setAllowFileAnimation(true);
|
||||
SystemStatus::getInstance().setPollImmediately(true);
|
||||
}
|
||||
|
||||
// Update number of times the game has been launched.
|
||||
|
|
|
@ -70,11 +70,10 @@ bool MediaViewer::startMediaViewer(FileData* game)
|
|||
ViewController::getInstance()->pauseViewVideos();
|
||||
Window::getInstance()->stopInfoPopup();
|
||||
|
||||
HelpStyle style;
|
||||
style.font = Font::get(FONT_SIZE_MINI);
|
||||
style.origin = {0.5f, 0.5f};
|
||||
style.iconColor = 0xAAAAAAFF;
|
||||
style.textColor = 0xAAAAAAFF;
|
||||
mHelp = std::make_unique<HelpComponent>(Font::get(FONT_SIZE_MINI));
|
||||
mHelp->setHelpOrigin(glm::vec2 {0.5, 0.5f});
|
||||
mHelp->setHelpTextColor(0xAAAAAAFF);
|
||||
mHelp->setHelpIconColor(0xAAAAAAFF);
|
||||
|
||||
mEntryCount = std::to_string(mImages.size() + (mVideo == nullptr ? 0 : 1));
|
||||
|
||||
|
@ -85,17 +84,15 @@ bool MediaViewer::startMediaViewer(FileData* game)
|
|||
|
||||
if (mHelpInfoPosition == HelpInfoPosition::TOP) {
|
||||
mMediaType->setPosition(mRenderer->getScreenWidth() * 0.01f, mFrameHeight / 2.0f);
|
||||
style.position = glm::vec2 {mRenderer->getScreenWidth() / 2.0f, mFrameHeight / 2.0f};
|
||||
mHelp->setHelpPosition(glm::vec2 {mRenderer->getScreenWidth() / 2.0f, mFrameHeight / 2.0f});
|
||||
}
|
||||
else if (mHelpInfoPosition == HelpInfoPosition::BOTTOM) {
|
||||
mMediaType->setPosition(mRenderer->getScreenWidth() * 0.01f,
|
||||
mRenderer->getScreenHeight() - (mFrameHeight / 2.0f));
|
||||
style.position = glm::vec2 {mRenderer->getScreenWidth() / 2.0f,
|
||||
mRenderer->getScreenHeight() - (mFrameHeight / 2.0f)};
|
||||
mHelp->setHelpPosition(glm::vec2 {mRenderer->getScreenWidth() / 2.0f,
|
||||
mRenderer->getScreenHeight() - (mFrameHeight / 2.0f)});
|
||||
}
|
||||
|
||||
mHelp = std::make_unique<HelpComponent>();
|
||||
mHelp->setStyle(style);
|
||||
mHelp->setPrompts(getHelpPrompts());
|
||||
|
||||
return true;
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
#include "ConvertPDF.h"
|
||||
#endif
|
||||
|
||||
|
@ -56,7 +56,7 @@ bool PDFViewer::startPDFViewer(FileData* game)
|
|||
{
|
||||
ViewController::getInstance()->pauseViewVideos();
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
#if !defined(__ANDROID__) && !defined(__IOS__)
|
||||
#if defined(_WIN64)
|
||||
const std::string convertBinary {"/es-pdf-converter/es-pdf-convert.exe"};
|
||||
#else
|
||||
|
@ -176,11 +176,10 @@ bool PDFViewer::startPDFViewer(FileData* game)
|
|||
else
|
||||
mFrameHeight = Font::get(FONT_SIZE_MINI)->getLetterHeight() * 1.9f;
|
||||
|
||||
HelpStyle style;
|
||||
style.font = Font::get(FONT_SIZE_MINI);
|
||||
style.origin = {0.5f, 0.5f};
|
||||
style.iconColor = 0xAAAAAAFF;
|
||||
style.textColor = 0xAAAAAAFF;
|
||||
mHelp = std::make_unique<HelpComponent>(Font::get(FONT_SIZE_MINI));
|
||||
mHelp->setHelpOrigin(glm::vec2 {0.5, 0.5f});
|
||||
mHelp->setHelpTextColor(0xAAAAAAFF);
|
||||
mHelp->setHelpIconColor(0xAAAAAAFF);
|
||||
|
||||
mEntryCount = std::to_string(mPages.size());
|
||||
|
||||
|
@ -191,17 +190,15 @@ bool PDFViewer::startPDFViewer(FileData* game)
|
|||
|
||||
if (mHelpInfoPosition == HelpInfoPosition::TOP) {
|
||||
mEntryNumText->setPosition(mRenderer->getScreenWidth() * 0.01f, mFrameHeight / 2.0f);
|
||||
style.position = glm::vec2 {mRenderer->getScreenWidth() / 2.0f, mFrameHeight / 2.0f};
|
||||
mHelp->setHelpPosition(glm::vec2 {mRenderer->getScreenWidth() / 2.0f, mFrameHeight / 2.0f});
|
||||
}
|
||||
else if (mHelpInfoPosition == HelpInfoPosition::BOTTOM) {
|
||||
mEntryNumText->setPosition(mRenderer->getScreenWidth() * 0.01f,
|
||||
mRenderer->getScreenHeight() - (mFrameHeight / 2.0f));
|
||||
style.position = glm::vec2 {mRenderer->getScreenWidth() / 2.0f,
|
||||
mRenderer->getScreenHeight() - (mFrameHeight / 2.0f)};
|
||||
mHelp->setHelpPosition(glm::vec2 {mRenderer->getScreenWidth() / 2.0f,
|
||||
mRenderer->getScreenHeight() - (mFrameHeight / 2.0f)});
|
||||
}
|
||||
|
||||
mHelp = std::make_unique<HelpComponent>();
|
||||
mHelp->setStyle(style);
|
||||
mHelp->setPrompts(getHelpPrompts());
|
||||
|
||||
convertPage(mCurrentPage);
|
||||
|
@ -305,7 +302,7 @@ bool PDFViewer::getDocumentInfo()
|
|||
// Close process and thread handles.
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
#elif defined(__ANDROID__)
|
||||
#elif defined(__ANDROID__) || defined(__IOS__)
|
||||
if (ConvertPDF::processFile(mManualPath, "-fileinfo", 0, 0, 0, commandOutput) == -1)
|
||||
return false;
|
||||
#else
|
||||
|
@ -449,7 +446,7 @@ void PDFViewer::convertPage(int pageNum)
|
|||
CloseHandle(childStdoutRead);
|
||||
WaitForSingleObject(pi.hThread, INFINITE);
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
#elif (__ANDROID__)
|
||||
#elif (__ANDROID__) || defined(__IOS__)
|
||||
ConvertPDF::processFile(mManualPath, "-convert", pageNum,
|
||||
static_cast<int>(mPages[pageNum].width),
|
||||
static_cast<int>(mPages[pageNum].height), imageData);
|
||||
|
@ -478,7 +475,7 @@ void PDFViewer::convertPage(int pageNum)
|
|||
#if defined(_WIN64)
|
||||
if (!processReturnValue || (static_cast<int>(imageDataSize) <
|
||||
mPages[pageNum].width * mPages[pageNum].height * 4)) {
|
||||
#elif defined(__ANDROID__)
|
||||
#elif defined(__ANDROID__) || defined(__IOS__)
|
||||
if (static_cast<int>(imageDataSize) < mPages[pageNum].width * mPages[pageNum].height * 4) {
|
||||
#else
|
||||
if (returnValue != 0 || (static_cast<int>(imageDataSize) <
|
||||
|
|
|
@ -143,6 +143,7 @@ namespace PlatformIds
|
|||
"uzebox", // Uzebox Open Source Console
|
||||
"vectrex", // GCE Vectrex
|
||||
"vic20", // Commodore VIC-20
|
||||
"vircon32", // Vircon32 Virtual Console
|
||||
"virtualboy", // Nintendo Virtual Boy
|
||||
"vpinball", // Visual Pinball
|
||||
"vsmile", // VTech V.Smile
|
||||
|
@ -156,6 +157,7 @@ namespace PlatformIds
|
|||
"x68000", // Sharp X68000
|
||||
"xbox", // Microsoft Xbox
|
||||
"xbox360", // Microsoft Xbox 360
|
||||
"xboxone", // Microsoft Xbox One
|
||||
"zmachine", // Infocom Z-machine
|
||||
"zx81", // Sinclair ZX81
|
||||
"zxnext", // Sinclair ZX Spectrum Next
|
||||
|
|
|
@ -142,6 +142,7 @@ namespace PlatformIds
|
|||
UZEBOX,
|
||||
VECTREX,
|
||||
COMMODORE_VIC20,
|
||||
VIRCON32,
|
||||
NINTENDO_VIRTUAL_BOY,
|
||||
VISUAL_PINBALL,
|
||||
VTECH_VSMILE,
|
||||
|
@ -155,6 +156,7 @@ namespace PlatformIds
|
|||
SHARP_X68000,
|
||||
MICROSOFT_XBOX,
|
||||
MICROSOFT_XBOX_360,
|
||||
MICROSOFT_XBOX_ONE,
|
||||
GAMEENGINE_Z_MACHINE,
|
||||
SINCLAIR_ZX81_SINCLAR,
|
||||
SINCLAIR_ZX_SPECTRUM_NEXT,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "FileData.h"
|
||||
#include "Log.h"
|
||||
#include "Scripting.h"
|
||||
#include "SystemData.h"
|
||||
#include "UIModeController.h"
|
||||
#include "components/VideoFFmpegComponent.h"
|
||||
|
@ -88,6 +89,7 @@ void Screensaver::startScreensaver(bool generateMediaList)
|
|||
if (Settings::getInstance()->getBool("ScreensaverSlideshowCustomImages")) {
|
||||
if (generateMediaList)
|
||||
generateCustomImageList();
|
||||
|
||||
pickRandomCustomImage(path);
|
||||
|
||||
// We've cycled through all games, so start from the beginning again.
|
||||
|
@ -103,7 +105,9 @@ void Screensaver::startScreensaver(bool generateMediaList)
|
|||
else {
|
||||
if (generateMediaList)
|
||||
generateImageList();
|
||||
|
||||
pickRandomImage(path);
|
||||
triggerCustomEvent();
|
||||
}
|
||||
|
||||
// We've cycled through all games, so start from the beginning again.
|
||||
|
@ -151,7 +155,9 @@ void Screensaver::startScreensaver(bool generateMediaList)
|
|||
// Load a random video.
|
||||
if (generateMediaList)
|
||||
generateVideoList();
|
||||
|
||||
pickRandomVideo(path);
|
||||
triggerCustomEvent();
|
||||
|
||||
// We've cycled through all games, so start from the beginning again.
|
||||
if (mVideoFiles.size() == 0 && mFilesInventory.size() > 0)
|
||||
|
@ -783,3 +789,13 @@ void Screensaver::generateOverlayInfo()
|
|||
mGameOverlayRectangleCoords.push_back(mGameOverlay->getSize().x + marginX * 2.0f);
|
||||
mGameOverlayRectangleCoords.push_back(mGameOverlay->getSize().y);
|
||||
}
|
||||
|
||||
void Screensaver::triggerCustomEvent()
|
||||
{
|
||||
if (mCurrentGame == nullptr)
|
||||
return;
|
||||
|
||||
Scripting::fireEvent("screensaver-game-select", mCurrentGame->getPath(),
|
||||
mCurrentGame->metadata.get("name"), mCurrentGame->getSystem()->getName(),
|
||||
mCurrentGame->getSystem()->getFullName());
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ private:
|
|||
void pickRandomVideo(std::string& path);
|
||||
void pickRandomCustomImage(std::string& path);
|
||||
void generateOverlayInfo();
|
||||
void triggerCustomEvent();
|
||||
|
||||
Renderer* mRenderer;
|
||||
Window* mWindow;
|
||||
|
|
|
@ -26,7 +26,6 @@ private:
|
|||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); }
|
||||
|
||||
MenuComponent mMenu;
|
||||
bool mHasSystems;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
GuiApplicationUpdater::GuiApplicationUpdater()
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mBackground {":/graphics/frame.svg"}
|
||||
, mGrid {glm::ivec2 {4, 11}}
|
||||
, mDownloadPercentage {0}
|
||||
, mLinuxAppImage {false}
|
||||
|
@ -161,13 +160,13 @@ GuiApplicationUpdater::GuiApplicationUpdater()
|
|||
};
|
||||
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||
getHelpStyle(), 0.0f, _("ENTER DOWNLOAD DIRECTORY"),
|
||||
currentDownloadDirectory, directoryFunc, false));
|
||||
0.0f, _("ENTER DOWNLOAD DIRECTORY"), currentDownloadDirectory,
|
||||
directoryFunc, false));
|
||||
}
|
||||
else {
|
||||
mWindow->pushGui(
|
||||
new GuiTextEditPopup(getHelpStyle(), _("ENTER DOWNLOAD DIRECTORY"),
|
||||
currentDownloadDirectory, directoryFunc, false));
|
||||
mWindow->pushGui(new GuiTextEditPopup(_("ENTER DOWNLOAD DIRECTORY"),
|
||||
currentDownloadDirectory, directoryFunc,
|
||||
false));
|
||||
}
|
||||
});
|
||||
buttons.push_back(mButton2);
|
||||
|
@ -180,20 +179,20 @@ GuiApplicationUpdater::GuiApplicationUpdater()
|
|||
mThread.reset();
|
||||
}
|
||||
if (mDownloading) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(), _("DOWNLOAD ABORTED") + "\n" + _("NO PACKAGE SAVED TO DISK"),
|
||||
_("OK"), nullptr, "", nullptr, "", nullptr, nullptr, true, true,
|
||||
(mRenderer->getIsVerticalOrientation() ?
|
||||
0.70f :
|
||||
0.45f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
||||
mWindow->pushGui(
|
||||
new GuiMsgBox(_("DOWNLOAD ABORTED") + "\n" + _("NO PACKAGE SAVED TO DISK"), _("OK"),
|
||||
nullptr, "", nullptr, "", nullptr, nullptr, true, true,
|
||||
(mRenderer->getIsVerticalOrientation() ?
|
||||
0.70f :
|
||||
0.45f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
||||
}
|
||||
else if (mHasDownloaded || mReadyToInstall) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(), _("PACKAGE WAS DOWNLOADED AND CAN BE MANUALLY INSTALLED"), _("OK"),
|
||||
nullptr, "", nullptr, "", nullptr, nullptr, true, true,
|
||||
(mRenderer->getIsVerticalOrientation() ?
|
||||
0.60f :
|
||||
0.35f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
||||
mWindow->pushGui(
|
||||
new GuiMsgBox(_("PACKAGE WAS DOWNLOADED AND CAN BE MANUALLY INSTALLED"), _("OK"),
|
||||
nullptr, "", nullptr, "", nullptr, nullptr, true, true,
|
||||
(mRenderer->getIsVerticalOrientation() ?
|
||||
0.60f :
|
||||
0.35f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
||||
}
|
||||
delete this;
|
||||
});
|
||||
|
|
|
@ -38,18 +38,11 @@ public:
|
|||
private:
|
||||
void onSizeChanged() override;
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override
|
||||
{
|
||||
if (ViewController::getInstance()->getState().viewing == ViewController::ViewMode::NOTHING)
|
||||
return HelpStyle();
|
||||
else
|
||||
return ViewController::getInstance()->getViewHelpStyle();
|
||||
}
|
||||
|
||||
Renderer* mRenderer;
|
||||
BusyComponent mBusyAnim;
|
||||
|
||||
NinePatchComponent mBackground;
|
||||
BackgroundComponent mBackground;
|
||||
ComponentGrid mGrid;
|
||||
std::shared_ptr<ComponentGrid> mButtons;
|
||||
std::shared_ptr<ButtonComponent> mButton1;
|
||||
|
|
|
@ -45,8 +45,8 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(std::string title)
|
|||
}
|
||||
|
||||
// Automatic collections.
|
||||
mCollectionSystemsAuto = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("SELECT COLLECTIONS"), true);
|
||||
mCollectionSystemsAuto =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("SELECT COLLECTIONS"), true);
|
||||
std::map<std::string, CollectionSystemData, StringComparator> autoSystems {
|
||||
CollectionSystemsManager::getInstance()->getAutoCollectionSystems()};
|
||||
// Add automatic systems.
|
||||
|
@ -95,8 +95,8 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(std::string title)
|
|||
});
|
||||
|
||||
// Custom collections.
|
||||
mCollectionSystemsCustom = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("SELECT COLLECTIONS"), true);
|
||||
mCollectionSystemsCustom =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("SELECT COLLECTIONS"), true);
|
||||
std::map<std::string, CollectionSystemData, StringComparator> customSystems {
|
||||
CollectionSystemsManager::getInstance()->getCustomCollectionSystems()};
|
||||
// Add custom systems.
|
||||
|
@ -178,8 +178,7 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(std::string title)
|
|||
row.makeAcceptInputHandler([this, unusedFolders] {
|
||||
auto ss = new GuiSettings(_("SELECT THEME FOLDER"));
|
||||
std::shared_ptr<OptionListComponent<std::string>> folderThemes {
|
||||
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(),
|
||||
_("SELECT THEME FOLDER"), true)};
|
||||
std::make_shared<OptionListComponent<std::string>>(_("SELECT THEME FOLDER"), true)};
|
||||
// Add custom systems.
|
||||
for (auto it = unusedFolders.cbegin(); it != unusedFolders.cend(); ++it) {
|
||||
ComponentListRow row;
|
||||
|
@ -224,13 +223,13 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(std::string title)
|
|||
const float verticalPosition {
|
||||
mRenderer->getIsVerticalOrientation() ? getMenu().getPosition().y : 0.0f};
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||
getHelpStyle(), verticalPosition, _("NEW COLLECTION NAME"), "",
|
||||
createCollectionCall, false, _("CREATE"), _("CREATE COLLECTION?")));
|
||||
verticalPosition, _("NEW COLLECTION NAME"), "", createCollectionCall, false,
|
||||
_("CREATE"), _("CREATE COLLECTION?")));
|
||||
});
|
||||
}
|
||||
else {
|
||||
row.makeAcceptInputHandler([this, createCollectionCall] {
|
||||
mWindow->pushGui(new GuiTextEditPopup(getHelpStyle(), _("NEW COLLECTION NAME"), "",
|
||||
mWindow->pushGui(new GuiTextEditPopup(_("NEW COLLECTION NAME"), "",
|
||||
createCollectionCall, false, _("CREATE"),
|
||||
_("CREATE COLLECTION?")));
|
||||
});
|
||||
|
@ -251,7 +250,7 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(std::string title)
|
|||
row.makeAcceptInputHandler([this, customSystems] {
|
||||
auto ss = new GuiSettings(_("COLLECTION TO DELETE"));
|
||||
std::shared_ptr<OptionListComponent<std::string>> customCollections {
|
||||
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(), "", true)};
|
||||
std::make_shared<OptionListComponent<std::string>>("", true)};
|
||||
for (std::map<std::string, CollectionSystemData, StringComparator>::const_iterator it =
|
||||
customSystems.cbegin();
|
||||
it != customSystems.cend(); ++it) {
|
||||
|
@ -259,7 +258,6 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(std::string title)
|
|||
std::string name {(*it).first};
|
||||
std::function<void()> deleteCollectionCall = [this, name] {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
Utils::String::format(
|
||||
_("THIS WILL PERMANENTLY DELETE THE COLLECTION\n'%s'\nARE YOU SURE?"),
|
||||
Utils::String::toUpper(name).c_str()),
|
||||
|
@ -318,8 +316,8 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(std::string title)
|
|||
addRow(row);
|
||||
|
||||
// Custom collections grouping.
|
||||
auto collectionCustomGrouping = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("GROUP CUSTOM COLLECTIONS"), false);
|
||||
auto collectionCustomGrouping =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("GROUP CUSTOM COLLECTIONS"), false);
|
||||
const std::string& selectedCustomGrouping {
|
||||
Settings::getInstance()->getString("CollectionCustomGrouping")};
|
||||
collectionCustomGrouping->add(_("IF UNTHEMED"), "unthemed",
|
||||
|
|
|
@ -124,16 +124,15 @@ void GuiGamelistFilter::addFiltersToMenu()
|
|||
row.makeAcceptInputHandler([this, updateVal] {
|
||||
const float verticalPosition {
|
||||
Renderer::getIsVerticalOrientation() ? mMenu.getPosition().y : 0.0f};
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||
getHelpStyle(), verticalPosition, _("GAME NAME"), mTextFilterField->getValue(),
|
||||
updateVal, false, _("OK"), _("APPLY CHANGES?")));
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(verticalPosition, _("GAME NAME"),
|
||||
mTextFilterField->getValue(), updateVal,
|
||||
false, _("OK"), _("APPLY CHANGES?")));
|
||||
});
|
||||
}
|
||||
else {
|
||||
row.makeAcceptInputHandler([this, updateVal] {
|
||||
mWindow->pushGui(new GuiTextEditPopup(getHelpStyle(), _("GAME NAME"),
|
||||
mTextFilterField->getValue(), updateVal, false,
|
||||
_("OK"), _("APPLY CHANGES?")));
|
||||
mWindow->pushGui(new GuiTextEditPopup(_("GAME NAME"), mTextFilterField->getValue(),
|
||||
updateVal, false, _("OK"), _("APPLY CHANGES?")));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -172,11 +171,9 @@ void GuiGamelistFilter::addFiltersToMenu()
|
|||
// For bool values, make the selection exclusive so that both True and False can't be
|
||||
// selected at the same time. This should be changed to a SwitchComponent at some point.
|
||||
if (exclusiveSelect)
|
||||
optionList = std::make_shared<OptionListComponent<std::string>>(getHelpStyle(),
|
||||
menuLabel, true, true);
|
||||
optionList = std::make_shared<OptionListComponent<std::string>>(menuLabel, true, true);
|
||||
else
|
||||
optionList = std::make_shared<OptionListComponent<std::string>>(getHelpStyle(),
|
||||
menuLabel, true, false);
|
||||
optionList = std::make_shared<OptionListComponent<std::string>>(menuLabel, true, false);
|
||||
|
||||
// Still display fields that can't be filtered in the menu, but notify the user and set
|
||||
// the OptionListComponent as disabled.
|
||||
|
|
|
@ -28,7 +28,6 @@ public:
|
|||
bool input(InputConfig* config, Input input) override;
|
||||
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); }
|
||||
|
||||
private:
|
||||
void initializeMenu();
|
||||
|
|
|
@ -103,7 +103,7 @@ GuiGamelistOptions::GuiGamelistOptions(SystemData* system)
|
|||
mCurrentFirstCharacter = Utils::String::getFirstCharacter(file->getSortName());
|
||||
}
|
||||
|
||||
mJumpToLetterList = std::make_shared<LetterList>(getHelpStyle(), _("JUMP TO..."), false);
|
||||
mJumpToLetterList = std::make_shared<LetterList>(_("JUMP TO..."), false);
|
||||
|
||||
// Enable key repeat so that the left or right button can be held to cycle through
|
||||
// the letters.
|
||||
|
@ -122,7 +122,7 @@ GuiGamelistOptions::GuiGamelistOptions(SystemData* system)
|
|||
// Add the sorting entry, unless this is the grouped custom collections list.
|
||||
if (!mIsCustomCollectionGroup) {
|
||||
// Sort list by selected sort type (persistent throughout the program session).
|
||||
mListSort = std::make_shared<SortList>(getHelpStyle(), _("SORT GAMES BY"), false);
|
||||
mListSort = std::make_shared<SortList>(_("SORT GAMES BY"), false);
|
||||
FileData* root {nullptr};
|
||||
if (mIsCustomCollection)
|
||||
root = getGamelist()->getCursor()->getSystem()->getRootFolder();
|
||||
|
|
|
@ -30,7 +30,6 @@ public:
|
|||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); }
|
||||
|
||||
private:
|
||||
void openGamelistFilter();
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
|
||||
GuiLaunchScreen::GuiLaunchScreen()
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mBackground {":/graphics/frame.svg"}
|
||||
, mGrid {nullptr}
|
||||
, mGrid {glm::ivec2 {3, 8}}
|
||||
, mMarquee {nullptr}
|
||||
{
|
||||
addChild(&mBackground);
|
||||
addChild(&mGrid);
|
||||
mWindow->setLaunchScreen(this);
|
||||
}
|
||||
|
||||
|
@ -33,9 +33,6 @@ GuiLaunchScreen::~GuiLaunchScreen()
|
|||
|
||||
void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
||||
{
|
||||
mGrid = new ComponentGrid(glm::ivec2 {3, 8});
|
||||
addChild(mGrid);
|
||||
|
||||
mImagePath = game->getMarqueePath();
|
||||
|
||||
// We need to unload the image first as it may be cached at a modified resolution
|
||||
|
@ -46,12 +43,13 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
|||
}
|
||||
|
||||
mScaleUp = 0.5f;
|
||||
mScaleAccumulator = 0;
|
||||
const float titleFontSize {0.060f};
|
||||
const float gameNameFontSize {0.073f};
|
||||
|
||||
// Spacer row.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {1, 0}, false, false,
|
||||
glm::ivec2 {1, 1});
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {1, 0}, false, false,
|
||||
glm::ivec2 {1, 1});
|
||||
|
||||
// Title.
|
||||
mTitle = std::make_shared<TextComponent>(
|
||||
|
@ -59,19 +57,19 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
|||
Font::get(titleFontSize *
|
||||
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())),
|
||||
mMenuColorTertiary, ALIGN_CENTER);
|
||||
mGrid->setEntry(mTitle, glm::ivec2 {1, 1}, false, true, glm::ivec2 {1, 1});
|
||||
mGrid.setEntry(mTitle, glm::ivec2 {1, 1}, false, true, glm::ivec2 {1, 1});
|
||||
|
||||
// Spacer row.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {1, 2}, false, false,
|
||||
glm::ivec2 {1, 1});
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {1, 2}, false, false,
|
||||
glm::ivec2 {1, 1});
|
||||
|
||||
// Row for the marquee.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {1, 3}, false, false,
|
||||
glm::ivec2 {1, 1});
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {1, 3}, false, false,
|
||||
glm::ivec2 {1, 1});
|
||||
|
||||
// Spacer row.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {1, 4}, false, false,
|
||||
glm::ivec2 {1, 1});
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {1, 4}, false, false,
|
||||
glm::ivec2 {1, 1});
|
||||
|
||||
// Game name.
|
||||
mGameName = std::make_shared<TextComponent>(
|
||||
|
@ -79,24 +77,24 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
|||
Font::get(gameNameFontSize *
|
||||
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())),
|
||||
mMenuColorTitle, ALIGN_CENTER);
|
||||
mGrid->setEntry(mGameName, glm::ivec2 {1, 5}, false, true, glm::ivec2 {1, 1});
|
||||
mGrid.setEntry(mGameName, glm::ivec2 {1, 5}, false, true, glm::ivec2 {1, 1});
|
||||
|
||||
// System name.
|
||||
mSystemName = std::make_shared<TextComponent>("SYSTEM NAME", Font::get(FONT_SIZE_MEDIUM),
|
||||
mMenuColorTertiary, ALIGN_CENTER);
|
||||
mGrid->setEntry(mSystemName, glm::ivec2 {1, 6}, false, true, glm::ivec2 {1, 1});
|
||||
mGrid.setEntry(mSystemName, glm::ivec2 {1, 6}, false, true, glm::ivec2 {1, 1});
|
||||
|
||||
// Spacer row.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {1, 7}, false, false,
|
||||
glm::ivec2 {1, 1});
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {1, 7}, false, false,
|
||||
glm::ivec2 {1, 1});
|
||||
|
||||
// Left spacer.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {0, 0}, false, false,
|
||||
glm::ivec2 {1, 8});
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {0, 0}, false, false,
|
||||
glm::ivec2 {1, 8});
|
||||
|
||||
// Right spacer.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {2, 0}, false, false,
|
||||
glm::ivec2 {1, 8});
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {2, 0}, false, false,
|
||||
glm::ivec2 {1, 8});
|
||||
|
||||
// Adjust the width depending on the aspect ratio of the screen, to make the screen look
|
||||
// somewhat coherent regardless of screen type. The 1.778 aspect ratio value is the 16:9
|
||||
|
@ -135,30 +133,30 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
|||
|
||||
// Set row heights.
|
||||
if (mImagePath != "")
|
||||
mGrid->setRowHeightPerc(0, 0.09f, false);
|
||||
mGrid.setRowHeightPerc(0, 0.09f, false);
|
||||
else
|
||||
mGrid->setRowHeightPerc(0, 0.15f, false);
|
||||
mGrid->setRowHeightPerc(1, mTitle->getFont()->getLetterHeight() * 1.70f / mSize.y, false);
|
||||
mGrid->setRowHeightPerc(2, 0.05f, false);
|
||||
mGrid.setRowHeightPerc(0, 0.15f, false);
|
||||
mGrid.setRowHeightPerc(1, mTitle->getFont()->getLetterHeight() * 1.70f / mSize.y, false);
|
||||
mGrid.setRowHeightPerc(2, 0.05f, false);
|
||||
if (mImagePath != "")
|
||||
mGrid->setRowHeightPerc(3, 0.35f, false);
|
||||
mGrid.setRowHeightPerc(3, 0.35f, false);
|
||||
else
|
||||
mGrid->setRowHeightPerc(3, 0.01f, false);
|
||||
mGrid->setRowHeightPerc(4, 0.05f, false);
|
||||
mGrid->setRowHeightPerc(5, mGameName->getFont()->getHeight() * 0.80f / mSize.y, false);
|
||||
mGrid->setRowHeightPerc(6, mSystemName->getFont()->getHeight() * 0.90f / mSize.y, false);
|
||||
mGrid.setRowHeightPerc(3, 0.01f, false);
|
||||
mGrid.setRowHeightPerc(4, 0.05f, false);
|
||||
mGrid.setRowHeightPerc(5, mGameName->getFont()->getHeight() * 0.80f / mSize.y, false);
|
||||
mGrid.setRowHeightPerc(6, mSystemName->getFont()->getHeight() * 0.90f / mSize.y, false);
|
||||
|
||||
// Set left and right spacers column widths.
|
||||
mGrid->setColWidthPerc(0, 0.025f);
|
||||
mGrid->setColWidthPerc(2, 0.025f);
|
||||
mGrid.setColWidthPerc(0, 0.025f);
|
||||
mGrid.setColWidthPerc(2, 0.025f);
|
||||
|
||||
mGrid->setSize(mSize);
|
||||
mGrid.setSize(mSize);
|
||||
|
||||
float totalRowHeight {0.0f};
|
||||
|
||||
// Hack to adjust the window height to the row boundary.
|
||||
for (int i = 0; i < 7; ++i)
|
||||
totalRowHeight += mGrid->getRowHeight(i);
|
||||
for (int i {0}; i < 7; ++i)
|
||||
totalRowHeight += mGrid.getRowHeight(i);
|
||||
|
||||
setSize(mSize.x, totalRowHeight);
|
||||
|
||||
|
@ -176,15 +174,15 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
|||
mMarquee->cropTransparentPadding(
|
||||
mRenderer->getScreenWidth() *
|
||||
(multiplier * (1.778f / mRenderer->getScreenAspectRatio())),
|
||||
mGrid->getRowHeight(3));
|
||||
mGrid.getRowHeight(3));
|
||||
|
||||
mMarquee->setOrigin(0.5f, 0.5f);
|
||||
glm::vec3 currentPos {mMarquee->getPosition()};
|
||||
|
||||
// Position the image in the middle of row four.
|
||||
currentPos.x = mSize.x / 2.0f;
|
||||
currentPos.y = mGrid->getRowHeight(0) + mGrid->getRowHeight(1) + mGrid->getRowHeight(2) +
|
||||
mGrid->getRowHeight(3) / 2.0f;
|
||||
currentPos.y = mGrid.getRowHeight(0) + mGrid.getRowHeight(1) + mGrid.getRowHeight(2) +
|
||||
mGrid.getRowHeight(3) / 2.0f;
|
||||
mMarquee->setPosition(currentPos);
|
||||
}
|
||||
|
||||
|
@ -199,10 +197,7 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
|||
|
||||
void GuiLaunchScreen::closeLaunchScreen()
|
||||
{
|
||||
if (mGrid) {
|
||||
delete mGrid;
|
||||
mGrid = nullptr;
|
||||
}
|
||||
mGrid.clearChildren();
|
||||
|
||||
if (mMarquee) {
|
||||
delete mMarquee;
|
||||
|
@ -219,21 +214,22 @@ void GuiLaunchScreen::closeLaunchScreen()
|
|||
void GuiLaunchScreen::onSizeChanged()
|
||||
{
|
||||
// Update mGrid size.
|
||||
mGrid->setSize(mSize);
|
||||
mGrid.setSize(mSize);
|
||||
}
|
||||
|
||||
void GuiLaunchScreen::update(int deltaTime)
|
||||
{
|
||||
if (Settings::getInstance()->getString("MenuOpeningEffect") == "none")
|
||||
mScaleUp = 1.0f;
|
||||
else if (mScaleUp < 1.0f)
|
||||
mScaleUp = glm::clamp(mScaleUp + 0.07f, 0.0f, 1.0f);
|
||||
if (Settings::getInstance()->getString("MenuOpeningEffect") == "scale-up")
|
||||
mScaleAccumulator += deltaTime;
|
||||
}
|
||||
|
||||
void GuiLaunchScreen::render(const glm::mat4& /*parentTrans*/)
|
||||
void GuiLaunchScreen::render(const glm::mat4&)
|
||||
{
|
||||
// Scale up animation.
|
||||
setScale(mScaleUp);
|
||||
if (Settings::getInstance()->getString("MenuOpeningEffect") == "scale-up" && mScaleUp < 1.0f) {
|
||||
mScaleUp = glm::clamp(glm::mix(0.5f, 1.0f, static_cast<float>(mScaleAccumulator) / 110.0f),
|
||||
0.5f, 1.0f);
|
||||
setScale(mScaleUp);
|
||||
}
|
||||
|
||||
glm::mat4 trans {Renderer::getIdentity() * getTransform()};
|
||||
mRenderer->setMatrix(trans);
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
#include "GuiComponent.h"
|
||||
#include "Window.h"
|
||||
#include "components/BackgroundComponent.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
#include "components/ImageComponent.h"
|
||||
#include "components/NinePatchComponent.h"
|
||||
#include "components/TextComponent.h"
|
||||
|
||||
class FileData;
|
||||
|
@ -34,8 +34,8 @@ public:
|
|||
|
||||
private:
|
||||
Renderer* mRenderer;
|
||||
NinePatchComponent mBackground;
|
||||
ComponentGrid* mGrid;
|
||||
BackgroundComponent mBackground;
|
||||
ComponentGrid mGrid;
|
||||
|
||||
std::shared_ptr<TextComponent> mTitle;
|
||||
std::shared_ptr<TextComponent> mGameName;
|
||||
|
@ -45,6 +45,7 @@ private:
|
|||
std::string mImagePath;
|
||||
|
||||
float mScaleUp;
|
||||
int mScaleAccumulator;
|
||||
};
|
||||
|
||||
#endif // ES_APP_GUIS_GUI_LAUNCH_SCREEN_H
|
||||
|
|
|
@ -19,8 +19,8 @@ GuiMediaViewerOptions::GuiMediaViewerOptions(const std::string& title)
|
|||
{
|
||||
|
||||
// Help prompts.
|
||||
auto mediaViewerHelpPrompts = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("HELP PROMPTS"), false);
|
||||
auto mediaViewerHelpPrompts =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("HELP PROMPTS"), false);
|
||||
std::string selectedHelpPrompts {Settings::getInstance()->getString("MediaViewerHelpPrompts")};
|
||||
mediaViewerHelpPrompts->add(_("TOP"), "top", selectedHelpPrompts == "top");
|
||||
mediaViewerHelpPrompts->add(_("BOTTOM"), "bottom", selectedHelpPrompts == "bottom");
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "guis/GuiOrphanedDataCleanup.h"
|
||||
#include "guis/GuiScraperMenu.h"
|
||||
#include "guis/GuiScreensaverOptions.h"
|
||||
#include "guis/GuiSystemStatusOptions.h"
|
||||
#include "guis/GuiTextEditKeyboardPopup.h"
|
||||
#include "guis/GuiTextEditPopup.h"
|
||||
#include "guis/GuiThemeDownloader.h"
|
||||
|
@ -44,6 +45,10 @@
|
|||
#include "utils/PlatformUtilAndroid.h"
|
||||
#endif
|
||||
|
||||
#if defined(__IOS__)
|
||||
#include "InputOverlay.h"
|
||||
#endif
|
||||
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -147,8 +152,7 @@ void GuiMenu::openUIOptions()
|
|||
std::map<std::string, ThemeData::Theme, ThemeData::StringComparator>::const_iterator
|
||||
selectedTheme;
|
||||
|
||||
auto theme =
|
||||
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(), _("THEME"), false);
|
||||
auto theme = std::make_shared<OptionListComponent<std::string>>(_("THEME"), false);
|
||||
|
||||
ComponentListRow themeDownloaderInputRow;
|
||||
themeDownloaderInputRow.elements.clear();
|
||||
|
@ -213,20 +217,22 @@ void GuiMenu::openUIOptions()
|
|||
s->setNeedsReloading();
|
||||
s->setNeedsGoToStart();
|
||||
s->setNeedsCollectionsUpdate();
|
||||
s->setNeedsClearHelpPromptsImageCache();
|
||||
s->setInvalidateCachedBackground();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Theme variants.
|
||||
auto themeVariant = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("THEME VARIANT"), false);
|
||||
auto themeVariant =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("THEME VARIANT"), false);
|
||||
s->addWithLabel(_("THEME VARIANT"), themeVariant);
|
||||
s->addSaveFunc([themeVariant, s] {
|
||||
if (themeVariant->getSelected() != Settings::getInstance()->getString("ThemeVariant")) {
|
||||
Settings::getInstance()->setString("ThemeVariant", themeVariant->getSelected());
|
||||
s->setNeedsSaving();
|
||||
s->setNeedsReloading();
|
||||
s->setNeedsClearHelpPromptsImageCache();
|
||||
s->setInvalidateCachedBackground();
|
||||
}
|
||||
});
|
||||
|
@ -278,8 +284,8 @@ void GuiMenu::openUIOptions()
|
|||
Settings::getInstance()->getString("ThemeVariant"));
|
||||
|
||||
// Theme color schemes.
|
||||
auto themeColorScheme = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("THEME COLOR SCHEME"), false);
|
||||
auto themeColorScheme =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("THEME COLOR SCHEME"), false);
|
||||
s->addWithLabel(_("THEME COLOR SCHEME"), themeColorScheme);
|
||||
s->addSaveFunc([themeColorScheme, s] {
|
||||
if (themeColorScheme->getSelected() !=
|
||||
|
@ -287,6 +293,7 @@ void GuiMenu::openUIOptions()
|
|||
Settings::getInstance()->setString("ThemeColorScheme", themeColorScheme->getSelected());
|
||||
s->setNeedsSaving();
|
||||
s->setNeedsReloading();
|
||||
s->setNeedsClearHelpPromptsImageCache();
|
||||
s->setInvalidateCachedBackground();
|
||||
}
|
||||
});
|
||||
|
@ -331,14 +338,15 @@ void GuiMenu::openUIOptions()
|
|||
Settings::getInstance()->getString("ThemeColorScheme"));
|
||||
|
||||
// Theme font sizes.
|
||||
auto themeFontSize = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("THEME FONT SIZE"), false);
|
||||
auto themeFontSize =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("THEME FONT SIZE"), false);
|
||||
s->addWithLabel(_("THEME FONT SIZE"), themeFontSize);
|
||||
s->addSaveFunc([themeFontSize, s] {
|
||||
if (themeFontSize->getSelected() != Settings::getInstance()->getString("ThemeFontSize")) {
|
||||
Settings::getInstance()->setString("ThemeFontSize", themeFontSize->getSelected());
|
||||
s->setNeedsSaving();
|
||||
s->setNeedsReloading();
|
||||
s->setNeedsClearHelpPromptsImageCache();
|
||||
s->setInvalidateCachedBackground();
|
||||
}
|
||||
});
|
||||
|
@ -373,8 +381,8 @@ void GuiMenu::openUIOptions()
|
|||
Settings::getInstance()->getString("ThemeFontSize"));
|
||||
|
||||
// Theme aspect ratios.
|
||||
auto themeAspectRatio = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("THEME ASPECT RATIO"), false);
|
||||
auto themeAspectRatio =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("THEME ASPECT RATIO"), false);
|
||||
s->addWithLabel(_("THEME ASPECT RATIO"), themeAspectRatio);
|
||||
s->addSaveFunc([themeAspectRatio, s] {
|
||||
if (themeAspectRatio->getSelected() !=
|
||||
|
@ -382,6 +390,7 @@ void GuiMenu::openUIOptions()
|
|||
Settings::getInstance()->setString("ThemeAspectRatio", themeAspectRatio->getSelected());
|
||||
s->setNeedsSaving();
|
||||
s->setNeedsReloading();
|
||||
s->setNeedsClearHelpPromptsImageCache();
|
||||
s->setInvalidateCachedBackground();
|
||||
}
|
||||
});
|
||||
|
@ -417,8 +426,8 @@ void GuiMenu::openUIOptions()
|
|||
Settings::getInstance()->getString("ThemeAspectRatio"));
|
||||
|
||||
// Theme transitions.
|
||||
auto themeTransitions = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("THEME TRANSITIONS"), false);
|
||||
auto themeTransitions =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("THEME TRANSITIONS"), false);
|
||||
std::string selectedThemeTransitions {Settings::getInstance()->getString("ThemeTransitions")};
|
||||
themeTransitions->add(_("AUTOMATIC"), "automatic", selectedThemeTransitions == "automatic");
|
||||
// If there are no objects returned, then there must be a manually modified entry in the
|
||||
|
@ -532,14 +541,15 @@ void GuiMenu::openUIOptions()
|
|||
Settings::getInstance()->getString("ThemeTransitions"));
|
||||
|
||||
// Theme language.
|
||||
auto themeLanguage = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("THEME LANGUAGE"), false);
|
||||
auto themeLanguage =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("THEME LANGUAGE"), false);
|
||||
s->addWithLabel(_("THEME LANGUAGE"), themeLanguage);
|
||||
s->addSaveFunc([themeLanguage, s] {
|
||||
if (themeLanguage->getSelected() != Settings::getInstance()->getString("ThemeLanguage")) {
|
||||
Settings::getInstance()->setString("ThemeLanguage", themeLanguage->getSelected());
|
||||
s->setNeedsSaving();
|
||||
s->setNeedsReloading();
|
||||
s->setNeedsClearHelpPromptsImageCache();
|
||||
s->setInvalidateCachedBackground();
|
||||
}
|
||||
});
|
||||
|
@ -575,8 +585,8 @@ void GuiMenu::openUIOptions()
|
|||
Settings::getInstance()->getString("ThemeLanguage"));
|
||||
|
||||
// Application language.
|
||||
auto applicationLanguage = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("APPLICATION LANGUAGE"), false);
|
||||
auto applicationLanguage =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("APPLICATION LANGUAGE"), false);
|
||||
std::string selectedApplicationLanguage {
|
||||
Settings::getInstance()->getString("ApplicationLanguage")};
|
||||
applicationLanguage->add(_("AUTOMATIC"), "automatic",
|
||||
|
@ -599,6 +609,7 @@ void GuiMenu::openUIOptions()
|
|||
applicationLanguage->add("日本語", "ja_JP", selectedApplicationLanguage == "ja_JP");
|
||||
applicationLanguage->add("한국어", "ko_KR", selectedApplicationLanguage == "ko_KR");
|
||||
applicationLanguage->add("简体中文", "zh_CN", selectedApplicationLanguage == "zh_CN");
|
||||
applicationLanguage->add("繁體中文", "zh_TW", selectedApplicationLanguage == "zh_TW");
|
||||
// If there are no objects returned, then there must be a manually modified entry in the
|
||||
// configuration file. Simply set the application langauge to "automatic" in this case.
|
||||
if (applicationLanguage->getSelectedObjects().size() == 0)
|
||||
|
@ -616,12 +627,13 @@ void GuiMenu::openUIOptions()
|
|||
s->setNeedsRescanROMDirectory();
|
||||
s->setNeedsReloading();
|
||||
s->setNeedsCollectionsUpdate();
|
||||
s->setNeedsClearHelpPromptsImageCache();
|
||||
}
|
||||
});
|
||||
|
||||
// Quick system select (navigate between systems in the gamelist view).
|
||||
auto quickSystemSelect = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("QUICK SYSTEM SELECT"), false);
|
||||
auto quickSystemSelect =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("QUICK SYSTEM SELECT"), false);
|
||||
std::string selectedQuickSelect {Settings::getInstance()->getString("QuickSystemSelect")};
|
||||
quickSystemSelect->add(_("LEFT/RIGHT OR SHOULDERS"), "leftrightshoulders",
|
||||
selectedQuickSelect == "leftrightshoulders");
|
||||
|
@ -646,8 +658,8 @@ void GuiMenu::openUIOptions()
|
|||
});
|
||||
|
||||
// Optionally start in selected system/gamelist.
|
||||
auto startupSystem = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("GAMELIST ON STARTUP"), false);
|
||||
auto startupSystem =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("GAMELIST ON STARTUP"), false);
|
||||
startupSystem->add(_("NONE"), "", Settings::getInstance()->getString("StartupSystem") == "");
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||
it != SystemData::sSystemVector.cend(); ++it) {
|
||||
|
@ -675,8 +687,8 @@ void GuiMenu::openUIOptions()
|
|||
});
|
||||
|
||||
// Systems sorting.
|
||||
auto systemsSorting = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("SYSTEMS SORTING"), false);
|
||||
auto systemsSorting =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("SYSTEMS SORTING"), false);
|
||||
std::string selectedSystemsSorting {Settings::getInstance()->getString("SystemsSorting")};
|
||||
systemsSorting->add(_("FULL NAMES OR CUSTOM"), "default", selectedSystemsSorting == "default");
|
||||
systemsSorting->add(_("RELEASE YEAR"), "year", selectedSystemsSorting == "year");
|
||||
|
@ -706,7 +718,7 @@ void GuiMenu::openUIOptions()
|
|||
// Default gamelist sort order.
|
||||
std::string sortOrder;
|
||||
auto defaultSortOrder = std::make_shared<OptionListComponent<const FileData::SortType*>>(
|
||||
getHelpStyle(), _p("short", "GAMES DEFAULT SORT ORDER"), false);
|
||||
_p("short", "GAMES DEFAULT SORT ORDER"), false);
|
||||
// Exclude the System sort options.
|
||||
unsigned int numSortTypes {static_cast<unsigned int>(FileSorts::SortTypes.size() - 2)};
|
||||
for (unsigned int i {0}; i < numSortTypes; ++i) {
|
||||
|
@ -744,8 +756,8 @@ void GuiMenu::openUIOptions()
|
|||
});
|
||||
|
||||
// Menu color scheme.
|
||||
auto menuColorScheme = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("MENU COLOR SCHEME"), false);
|
||||
auto menuColorScheme =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("MENU COLOR SCHEME"), false);
|
||||
const std::string selectedMenuColor {Settings::getInstance()->getString("MenuColorScheme")};
|
||||
menuColorScheme->add(_("DARK"), "dark", selectedMenuColor == "dark");
|
||||
menuColorScheme->add(_("DARK AND RED"), "darkred", selectedMenuColor == "darkred");
|
||||
|
@ -769,8 +781,8 @@ void GuiMenu::openUIOptions()
|
|||
});
|
||||
|
||||
// Open menu effect.
|
||||
auto menuOpeningEffect = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("MENU OPENING ANIMATION"), false);
|
||||
auto menuOpeningEffect =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("MENU OPENING ANIMATION"), false);
|
||||
std::string selectedMenuEffect {Settings::getInstance()->getString("MenuOpeningEffect")};
|
||||
menuOpeningEffect->add(_("SCALE-UP"), "scale-up", selectedMenuEffect == "scale-up");
|
||||
menuOpeningEffect->add(_("NONE"), "none", selectedMenuEffect == "none");
|
||||
|
@ -789,12 +801,13 @@ void GuiMenu::openUIOptions()
|
|||
});
|
||||
|
||||
// Launch screen duration.
|
||||
auto launchScreenDuration = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("LAUNCH SCREEN DURATION"), false);
|
||||
auto launchScreenDuration =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("LAUNCH SCREEN DURATION"), false);
|
||||
std::string selectedDuration {Settings::getInstance()->getString("LaunchScreenDuration")};
|
||||
launchScreenDuration->add(_("NORMAL"), "normal", selectedDuration == "normal");
|
||||
launchScreenDuration->add(_("BRIEF"), "brief", selectedDuration == "brief");
|
||||
launchScreenDuration->add(_("LONG"), "long", selectedDuration == "long");
|
||||
launchScreenDuration->add(_("POPUP"), "popup", selectedDuration == "popup");
|
||||
launchScreenDuration->add(_("DISABLED"), "disabled", selectedDuration == "disabled");
|
||||
// If there are no objects returned, then there must be a manually modified entry in the
|
||||
// configuration file. Simply set the duration to "normal" in this case.
|
||||
|
@ -811,8 +824,7 @@ void GuiMenu::openUIOptions()
|
|||
});
|
||||
|
||||
// UI mode.
|
||||
auto uiMode =
|
||||
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(), _("UI MODE"), false);
|
||||
auto uiMode = std::make_shared<OptionListComponent<std::string>>(_("UI MODE"), false);
|
||||
std::string setMode;
|
||||
if (Settings::getInstance()->getBool("ForceKiosk"))
|
||||
setMode = "kiosk";
|
||||
|
@ -857,7 +869,7 @@ void GuiMenu::openUIOptions()
|
|||
UIModeController::getInstance()->getFormattedPassKeyStr().c_str());
|
||||
}
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
this->getHelpStyle(), msg, _("YES"),
|
||||
msg, _("YES"),
|
||||
[this, selectedMode] {
|
||||
LOG(LogDebug) << "GuiMenu::openUISettings(): Setting UI mode to '"
|
||||
<< selectedMode << "'.";
|
||||
|
@ -905,8 +917,8 @@ void GuiMenu::openUIOptions()
|
|||
});
|
||||
|
||||
// Random entry button.
|
||||
auto randomEntryButton = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("RANDOM ENTRY BUTTON"), false);
|
||||
auto randomEntryButton =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("RANDOM ENTRY BUTTON"), false);
|
||||
const std::string selectedRandomEntryButton {
|
||||
Settings::getInstance()->getString("RandomEntryButton")};
|
||||
randomEntryButton->add(_("GAMES ONLY"), "games", selectedRandomEntryButton == "games");
|
||||
|
@ -927,6 +939,19 @@ void GuiMenu::openUIOptions()
|
|||
}
|
||||
});
|
||||
|
||||
#if !defined(__FreeBSD__) && !defined(__HAIKU__)
|
||||
// System status.
|
||||
ComponentListRow systemStatusRow;
|
||||
systemStatusRow.elements.clear();
|
||||
systemStatusRow.addElement(std::make_shared<TextComponent>(_("SYSTEM STATUS SETTINGS"),
|
||||
Font::get(FONT_SIZE_MEDIUM),
|
||||
mMenuColorPrimary),
|
||||
true);
|
||||
systemStatusRow.addElement(mMenu.makeArrow(), false);
|
||||
systemStatusRow.makeAcceptInputHandler(std::bind(&GuiMenu::openSystemStatusOptions, this));
|
||||
s->addRow(systemStatusRow);
|
||||
#endif
|
||||
|
||||
// Media viewer.
|
||||
ComponentListRow mediaViewerRow;
|
||||
mediaViewerRow.elements.clear();
|
||||
|
@ -964,6 +989,17 @@ void GuiMenu::openUIOptions()
|
|||
}
|
||||
});
|
||||
|
||||
// Display clock.
|
||||
auto displayClock = std::make_shared<SwitchComponent>();
|
||||
displayClock->setState(Settings::getInstance()->getBool("DisplayClock"));
|
||||
s->addWithLabel(_("DISPLAY CLOCK"), displayClock);
|
||||
s->addSaveFunc([displayClock, s] {
|
||||
if (displayClock->getState() != Settings::getInstance()->getBool("DisplayClock")) {
|
||||
Settings::getInstance()->setBool("DisplayClock", displayClock->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
||||
// Blur background when the menu is open.
|
||||
auto menuBlurBackground = std::make_shared<SwitchComponent>();
|
||||
if (mRenderer->getScreenRotation() == 90 || mRenderer->getScreenRotation() == 270) {
|
||||
|
@ -1198,8 +1234,7 @@ void GuiMenu::openSoundOptions()
|
|||
|
||||
#if defined(__ANDROID__)
|
||||
// Audio driver.
|
||||
auto audioDriver = std::make_shared<OptionListComponent<std::string>>(getHelpStyle(),
|
||||
_("AUDIO DRIVER"), false);
|
||||
auto audioDriver = std::make_shared<OptionListComponent<std::string>>(_("AUDIO DRIVER"), false);
|
||||
std::string selectedDriver {Settings::getInstance()->getString("AudioDriver")};
|
||||
audioDriver->add("OPENSL ES", "openslES", selectedDriver == "openslES");
|
||||
audioDriver->add("AAUDIO", "AAudio", selectedDriver == "AAudio");
|
||||
|
@ -1327,8 +1362,8 @@ void GuiMenu::openInputDeviceOptions()
|
|||
auto s = new GuiSettings(_("INPUT DEVICE SETTINGS"));
|
||||
|
||||
// Controller type.
|
||||
auto inputControllerType = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("CONTROLLER TYPE"), false);
|
||||
auto inputControllerType =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("CONTROLLER TYPE"), false);
|
||||
std::string selectedPlayer {Settings::getInstance()->getString("InputControllerType")};
|
||||
inputControllerType->add("XBOX", "xbox", selectedPlayer == "xbox");
|
||||
inputControllerType->add("XBOX 360", "xbox360", selectedPlayer == "xbox360");
|
||||
|
@ -1348,13 +1383,14 @@ void GuiMenu::openInputDeviceOptions()
|
|||
Settings::getInstance()->setString("InputControllerType",
|
||||
inputControllerType->getSelected());
|
||||
s->setNeedsSaving();
|
||||
s->setNeedsClearHelpPromptsImageCache();
|
||||
}
|
||||
});
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
// Touch overlay size.
|
||||
auto touchOverlaySize = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("TOUCH OVERLAY SIZE"), false);
|
||||
auto touchOverlaySize =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("TOUCH OVERLAY SIZE"), false);
|
||||
std::string selectedOverlaySize {Settings::getInstance()->getString("InputTouchOverlaySize")};
|
||||
touchOverlaySize->add(_("MEDIUM"), "medium", selectedOverlaySize == "medium");
|
||||
touchOverlaySize->add(_("LARGE"), "large", selectedOverlaySize == "large");
|
||||
|
@ -1376,8 +1412,8 @@ void GuiMenu::openInputDeviceOptions()
|
|||
});
|
||||
|
||||
// Touch overlay opacity.
|
||||
auto touchOverlayOpacity = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("TOUCH OVERLAY OPACITY"), false);
|
||||
auto touchOverlayOpacity =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("TOUCH OVERLAY OPACITY"), false);
|
||||
std::string selectedOverlayOpacity {
|
||||
Settings::getInstance()->getString("InputTouchOverlayOpacity")};
|
||||
touchOverlayOpacity->add(_("NORMAL"), "normal", selectedOverlayOpacity == "normal");
|
||||
|
@ -1460,12 +1496,11 @@ void GuiMenu::openInputDeviceOptions()
|
|||
"CONFIGURATOR TO RUN ON NEXT STARTUP")};
|
||||
|
||||
Window* window {mWindow};
|
||||
window->pushGui(
|
||||
new GuiMsgBox(getHelpStyle(), message, _("OK"), nullptr, "", nullptr, "", nullptr,
|
||||
nullptr, true, true,
|
||||
(mRenderer->getIsVerticalOrientation() ?
|
||||
0.84f :
|
||||
0.54f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
||||
window->pushGui(new GuiMsgBox(
|
||||
message, _("OK"), nullptr, "", nullptr, "", nullptr, nullptr, true, true,
|
||||
(mRenderer->getIsVerticalOrientation() ?
|
||||
0.84f :
|
||||
0.54f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
||||
}
|
||||
|
||||
if (touchOverlaySize->getEnabled()) {
|
||||
|
@ -1580,7 +1615,7 @@ void GuiMenu::openConfigInput(GuiSettings* settings)
|
|||
|
||||
Window* window {mWindow};
|
||||
window->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(), message, _("PROCEED"),
|
||||
message, _("PROCEED"),
|
||||
[window] { window->pushGui(new GuiDetectDevice(false, false, nullptr)); }, _("CANCEL"),
|
||||
nullptr, "", nullptr, nullptr, false, true,
|
||||
(mRenderer->getIsVerticalOrientation() ?
|
||||
|
@ -1604,6 +1639,7 @@ void GuiMenu::openOtherOptions()
|
|||
std::bind([this] { mWindow->pushGui(new GuiAlternativeEmulators); }));
|
||||
s->addRow(alternativeEmulatorsRow);
|
||||
|
||||
#if !defined(__IOS__)
|
||||
// Game media directory.
|
||||
ComponentListRow rowMediaDir;
|
||||
auto mediaDirectory = std::make_shared<TextComponent>(
|
||||
|
@ -1632,19 +1668,20 @@ void GuiMenu::openOtherOptions()
|
|||
multiLineMediaDir] {
|
||||
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||
getHelpStyle(), s->getMenu().getPosition().y, titleMediaDir,
|
||||
s->getMenu().getPosition().y, titleMediaDir,
|
||||
Settings::getInstance()->getString("MediaDirectory"), updateValMediaDir,
|
||||
multiLineMediaDir, _("SAVE"), _("SAVE CHANGES?"), mediaDirectoryStaticText,
|
||||
defaultDirectoryText, _("load default directory")));
|
||||
}
|
||||
else {
|
||||
mWindow->pushGui(new GuiTextEditPopup(
|
||||
getHelpStyle(), titleMediaDir, Settings::getInstance()->getString("MediaDirectory"),
|
||||
titleMediaDir, Settings::getInstance()->getString("MediaDirectory"),
|
||||
updateValMediaDir, multiLineMediaDir, _("SAVE"), _("SAVE CHANGES?"),
|
||||
mediaDirectoryStaticText, defaultDirectoryText, _("load default directory")));
|
||||
}
|
||||
});
|
||||
s->addRow(rowMediaDir);
|
||||
#endif
|
||||
|
||||
// Maximum VRAM.
|
||||
auto maxVram = std::make_shared<SliderComponent>(128.0f, 2048.0f, 16.0f, "MiB");
|
||||
|
@ -1660,8 +1697,8 @@ void GuiMenu::openOtherOptions()
|
|||
|
||||
#if !defined(USE_OPENGLES)
|
||||
// Anti-aliasing (MSAA).
|
||||
auto antiAliasing = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("ANTI-ALIASING (MSAA)"), false);
|
||||
auto antiAliasing =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("ANTI-ALIASING (MSAA)"), false);
|
||||
const std::string& selectedAntiAliasing {
|
||||
std::to_string(Settings::getInstance()->getInt("AntiAliasing"))};
|
||||
antiAliasing->add(_("DISABLED"), "0", selectedAntiAliasing == "0");
|
||||
|
@ -1682,9 +1719,10 @@ void GuiMenu::openOtherOptions()
|
|||
});
|
||||
#endif
|
||||
|
||||
#if !defined(__IOS__)
|
||||
// Display/monitor.
|
||||
auto displayIndex = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("DISPLAY/MONITOR INDEX"), false);
|
||||
auto displayIndex =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("DISPLAY/MONITOR INDEX"), false);
|
||||
std::vector<std::string> displayIndexEntry;
|
||||
displayIndexEntry.push_back("1");
|
||||
displayIndexEntry.push_back("2");
|
||||
|
@ -1702,10 +1740,11 @@ void GuiMenu::openOtherOptions()
|
|||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
// Screen contents rotation.
|
||||
auto screenRotate = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("ROTATE SCREEN"), false);
|
||||
auto screenRotate =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("ROTATE SCREEN"), false);
|
||||
const std::string& selectedScreenRotate {
|
||||
std::to_string(Settings::getInstance()->getInt("ScreenRotate"))};
|
||||
screenRotate->add(_("DISABLED"), "0", selectedScreenRotate == "0");
|
||||
|
@ -1727,8 +1766,8 @@ void GuiMenu::openOtherOptions()
|
|||
});
|
||||
|
||||
// Keyboard quit shortcut.
|
||||
auto keyboardQuitShortcut = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("KEYBOARD QUIT SHORTCUT"), false);
|
||||
auto keyboardQuitShortcut =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("KEYBOARD QUIT SHORTCUT"), false);
|
||||
std::string selectedShortcut {Settings::getInstance()->getString("KeyboardQuitShortcut")};
|
||||
#if defined(_WIN64) || defined(__unix__) || defined(__HAIKU__)
|
||||
keyboardQuitShortcut->add("ALT + F4", "AltF4", selectedShortcut == "AltF4");
|
||||
|
@ -1757,7 +1796,7 @@ void GuiMenu::openOtherOptions()
|
|||
|
||||
// When to save game metadata.
|
||||
auto saveGamelistsMode = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _p("short", "WHEN TO SAVE GAME METADATA"), false);
|
||||
_p("short", "WHEN TO SAVE GAME METADATA"), false);
|
||||
saveGamelistsMode->add(_("ALWAYS"), "always",
|
||||
Settings::getInstance()->getString("SaveGamelistsMode") == "always");
|
||||
saveGamelistsMode->add(_("ON EXIT"), "on exit",
|
||||
|
@ -1787,8 +1826,8 @@ void GuiMenu::openOtherOptions()
|
|||
|
||||
#if defined(APPLICATION_UPDATER)
|
||||
// Application updater frequency.
|
||||
auto applicationUpdaterFrequency = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("APPLICATION UPDATES"), false);
|
||||
auto applicationUpdaterFrequency =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("APPLICATION UPDATES"), false);
|
||||
const std::string& selectedUpdaterFrequency {
|
||||
Settings::getInstance()->getString("ApplicationUpdaterFrequency")};
|
||||
applicationUpdaterFrequency->add(_("ALWAYS"), "always", selectedUpdaterFrequency == "always");
|
||||
|
@ -1937,6 +1976,7 @@ void GuiMenu::openOtherOptions()
|
|||
}
|
||||
});
|
||||
|
||||
#if !defined(__IOS__)
|
||||
// Custom event scripts, fired using Scripting::fireEvent().
|
||||
auto customEventScripts = std::make_shared<SwitchComponent>();
|
||||
customEventScripts->setState(Settings::getInstance()->getBool("CustomEventScripts"));
|
||||
|
@ -1949,6 +1989,30 @@ void GuiMenu::openOtherOptions()
|
|||
}
|
||||
});
|
||||
|
||||
// Custom event scripts when browsing games and systems, fired using Scripting::fireEvent().
|
||||
auto customEventScriptsBrowsing = std::make_shared<SwitchComponent>();
|
||||
customEventScriptsBrowsing->setState(
|
||||
Settings::getInstance()->getBool("CustomEventScriptsBrowsing"));
|
||||
s->addWithLabel(_("BROWSING CUSTOM EVENTS"), customEventScriptsBrowsing);
|
||||
s->addSaveFunc([customEventScriptsBrowsing, s] {
|
||||
if (customEventScriptsBrowsing->getState() !=
|
||||
Settings::getInstance()->getBool("CustomEventScriptsBrowsing")) {
|
||||
Settings::getInstance()->setBool("CustomEventScriptsBrowsing",
|
||||
customEventScriptsBrowsing->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
||||
// If custom event scripts are disabled, then gray out this option.
|
||||
if (!Settings::getInstance()->getBool("CustomEventScripts")) {
|
||||
customEventScriptsBrowsing->setEnabled(false);
|
||||
customEventScriptsBrowsing->setOpacity(DISABLED_OPACITY);
|
||||
customEventScriptsBrowsing->getParent()
|
||||
->getChild(customEventScriptsBrowsing->getChildIndex() - 1)
|
||||
->setOpacity(DISABLED_OPACITY);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Only show games included in the gamelist.xml files.
|
||||
auto parseGamelistOnly = std::make_shared<SwitchComponent>();
|
||||
parseGamelistOnly->setState(Settings::getInstance()->getBool("ParseGamelistOnly"));
|
||||
|
@ -2115,6 +2179,27 @@ void GuiMenu::openOtherOptions()
|
|||
applicationUpdaterFrequency->setCallback(applicationUpdaterFrequencyFunc);
|
||||
#endif
|
||||
|
||||
#if !defined(__IOS__)
|
||||
auto browsingEventsToggleFunc = [customEventScriptsBrowsing]() {
|
||||
if (customEventScriptsBrowsing->getEnabled()) {
|
||||
customEventScriptsBrowsing->setEnabled(false);
|
||||
customEventScriptsBrowsing->setOpacity(DISABLED_OPACITY);
|
||||
customEventScriptsBrowsing->getParent()
|
||||
->getChild(customEventScriptsBrowsing->getChildIndex() - 1)
|
||||
->setOpacity(DISABLED_OPACITY);
|
||||
}
|
||||
else {
|
||||
customEventScriptsBrowsing->setEnabled(true);
|
||||
customEventScriptsBrowsing->setOpacity(1.0f);
|
||||
customEventScriptsBrowsing->getParent()
|
||||
->getChild(customEventScriptsBrowsing->getChildIndex() - 1)
|
||||
->setOpacity(1.0f);
|
||||
}
|
||||
};
|
||||
|
||||
customEventScripts->setCallback(browsingEventsToggleFunc);
|
||||
#endif
|
||||
|
||||
s->setSize(mSize);
|
||||
mWindow->pushGui(s);
|
||||
}
|
||||
|
@ -2123,8 +2208,6 @@ void GuiMenu::openUtilities()
|
|||
{
|
||||
auto s = new GuiSettings(_("UTILITIES"));
|
||||
|
||||
HelpStyle style {getHelpStyle()};
|
||||
|
||||
ComponentListRow row;
|
||||
row.addElement(std::make_shared<TextComponent>(_("ORPHANED DATA CLEANUP"),
|
||||
Font::get(FONT_SIZE_MEDIUM), mMenuColorPrimary),
|
||||
|
@ -2146,7 +2229,6 @@ void GuiMenu::openUtilities()
|
|||
|
||||
row.makeAcceptInputHandler([this] {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
_("THIS WILL CREATE ALL GAME SYSTEM DIRECTORIES INSIDE YOUR ROM FOLDER AND IT WILL "
|
||||
"ALSO UPDATE ALL SYSTEMINFO.TXT FILES. THIS IS A SAFE OPERATION THAT WILL NOT DELETE "
|
||||
"OR MODIFY YOUR GAME FILES. TO DECREASE APPLICATION STARTUP TIMES IT'S RECOMMENDED "
|
||||
|
@ -2155,8 +2237,7 @@ void GuiMenu::openUtilities()
|
|||
[this] {
|
||||
if (!SystemData::createSystemDirectories()) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(), _("THE SYSTEM DIRECTORIES WERE SUCCESSFULLY CREATED"),
|
||||
_("OK"),
|
||||
_("THE SYSTEM DIRECTORIES WERE SUCCESSFULLY CREATED"), _("OK"),
|
||||
[this] {
|
||||
if (CollectionSystemsManager::getInstance()->isEditing())
|
||||
CollectionSystemsManager::getInstance()->exitEditMode();
|
||||
|
@ -2174,7 +2255,6 @@ void GuiMenu::openUtilities()
|
|||
}
|
||||
else {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
_("ERROR CREATING SYSTEM DIRECTORIES, PERMISSION PROBLEMS OR "
|
||||
"DISK FULL? SEE THE LOG FILE FOR MORE DETAILS"),
|
||||
_("OK"), nullptr, "", nullptr, "", nullptr, nullptr, true, true,
|
||||
|
@ -2201,7 +2281,6 @@ void GuiMenu::openUtilities()
|
|||
|
||||
row.makeAcceptInputHandler([this] {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
_("THIS WILL RESCAN YOUR ROM DIRECTORY FOR CHANGES SUCH AS ADDED OR REMOVED GAMES AND "
|
||||
"SYSTEMS"),
|
||||
_("PROCEED"),
|
||||
|
@ -2306,7 +2385,7 @@ void GuiMenu::openQuitMenu()
|
|||
if (!Settings::getInstance()->getBool("ShowQuitMenu")) {
|
||||
#endif
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
this->getHelpStyle(), _("REALLY QUIT?"), _("YES"),
|
||||
_("REALLY QUIT?"), _("YES"),
|
||||
[this] {
|
||||
close(true);
|
||||
Utils::Platform::quitES();
|
||||
|
@ -2317,13 +2396,12 @@ void GuiMenu::openQuitMenu()
|
|||
auto s = new GuiSettings(_("QUIT"));
|
||||
|
||||
Window* window {mWindow};
|
||||
HelpStyle style {getHelpStyle()};
|
||||
|
||||
ComponentListRow row;
|
||||
|
||||
row.makeAcceptInputHandler([window, this] {
|
||||
window->pushGui(new GuiMsgBox(
|
||||
this->getHelpStyle(), _("REALLY QUIT?"), _("YES"),
|
||||
_("REALLY QUIT?"), _("YES"),
|
||||
[this] {
|
||||
close(true);
|
||||
Utils::Platform::quitES();
|
||||
|
@ -2341,9 +2419,9 @@ void GuiMenu::openQuitMenu()
|
|||
s->addRow(row);
|
||||
|
||||
row.elements.clear();
|
||||
row.makeAcceptInputHandler([window, this] {
|
||||
row.makeAcceptInputHandler([window] {
|
||||
window->pushGui(new GuiMsgBox(
|
||||
this->getHelpStyle(), _("REALLY REBOOT?"), _("YES"),
|
||||
_("REALLY REBOOT?"), _("YES"),
|
||||
[] {
|
||||
if (Utils::Platform::quitES(Utils::Platform::QuitMode::REBOOT) != 0) {
|
||||
LOG(LogWarning) << "Reboot terminated with non-zero result!";
|
||||
|
@ -2358,9 +2436,9 @@ void GuiMenu::openQuitMenu()
|
|||
s->addRow(row);
|
||||
|
||||
row.elements.clear();
|
||||
row.makeAcceptInputHandler([window, this] {
|
||||
row.makeAcceptInputHandler([window] {
|
||||
window->pushGui(new GuiMsgBox(
|
||||
this->getHelpStyle(), _("REALLY POWER OFF?"), _("YES"),
|
||||
_("REALLY POWER OFF?"), _("YES"),
|
||||
[] {
|
||||
if (Utils::Platform::quitES(Utils::Platform::QuitMode::POWEROFF) != 0) {
|
||||
LOG(LogWarning) << "Power off terminated with non-zero result!";
|
||||
|
@ -2437,6 +2515,7 @@ void GuiMenu::openThemeDownloader(GuiSettings* settings)
|
|||
}
|
||||
else {
|
||||
openUIOptions();
|
||||
mWindow->clearHelpPromptsImageCache();
|
||||
mWindow->invalidateCachedBackground();
|
||||
}
|
||||
};
|
||||
|
@ -2444,6 +2523,11 @@ void GuiMenu::openThemeDownloader(GuiSettings* settings)
|
|||
mWindow->pushGui(new GuiThemeDownloader(updateFunc));
|
||||
}
|
||||
|
||||
void GuiMenu::openSystemStatusOptions()
|
||||
{
|
||||
mWindow->pushGui(new GuiSystemStatusOptions(_p("short", "SYSTEM STATUS SETTINGS")));
|
||||
}
|
||||
|
||||
void GuiMenu::openMediaViewerOptions()
|
||||
{
|
||||
mWindow->pushGui(new GuiMediaViewerOptions(_p("short", "MEDIA VIEWER SETTINGS")));
|
||||
|
|
|
@ -24,7 +24,6 @@ public:
|
|||
bool input(InputConfig* config, Input input) override;
|
||||
void onSizeChanged() override;
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); }
|
||||
|
||||
private:
|
||||
void close(bool closeAllWindows);
|
||||
|
@ -37,6 +36,7 @@ private:
|
|||
void openScraperOptions();
|
||||
void openUIOptions();
|
||||
void openThemeDownloader(GuiSettings* settings);
|
||||
void openSystemStatusOptions();
|
||||
void openMediaViewerOptions();
|
||||
void openScreensaverOptions();
|
||||
void openSoundOptions();
|
||||
|
|
|
@ -44,7 +44,6 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
std::function<void()> clearGameFunc,
|
||||
std::function<void()> deleteGameFunc)
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mBackground {":/graphics/frame.svg"}
|
||||
, mGrid {glm::ivec2 {2, 6}}
|
||||
, mScraperParams {scraperParams}
|
||||
, mControllerBadges {BadgeComponent::getGameControllers()}
|
||||
|
@ -626,14 +625,14 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
const float verticalPosition {
|
||||
mRenderer->getIsVerticalOrientation() ? mPosition.y : 0.0f};
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||
getHelpStyle(), verticalPosition, title, ed->getValue(), updateVal,
|
||||
multiLine, _("APPLY"), _("APPLY CHANGES?"), "", ""));
|
||||
verticalPosition, title, ed->getValue(), updateVal, multiLine,
|
||||
_("APPLY"), _("APPLY CHANGES?"), "", ""));
|
||||
});
|
||||
}
|
||||
else {
|
||||
row.makeAcceptInputHandler([this, title, ed, updateVal, multiLine] {
|
||||
mWindow->pushGui(new GuiTextEditPopup(getHelpStyle(), title, ed->getValue(),
|
||||
updateVal, multiLine, _("APPLY"),
|
||||
mWindow->pushGui(new GuiTextEditPopup(title, ed->getValue(), updateVal,
|
||||
multiLine, _("APPLY"),
|
||||
_("APPLY CHANGES?")));
|
||||
});
|
||||
}
|
||||
|
@ -689,7 +688,6 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
};
|
||||
auto clearSelfBtnFunc = [this, clearSelf] {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
_("THIS WILL DELETE ANY MEDIA FILES AND "
|
||||
"THE GAMELIST.XML ENTRY FOR THIS FOLDER, "
|
||||
"BUT NEITHER THE DIRECTORY ITSELF OR ANY "
|
||||
|
@ -711,7 +709,6 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
};
|
||||
auto clearSelfBtnFunc = [this, clearSelf] {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
_("THIS WILL DELETE ANY MEDIA FILES "
|
||||
"AND THE GAMELIST.XML ENTRY FOR "
|
||||
"THIS GAME, BUT THE GAME FILE "
|
||||
|
@ -734,8 +731,7 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
};
|
||||
auto deleteGameBtnFunc = [this, deleteFilesAndSelf] {
|
||||
mWindow->pushGui(
|
||||
new GuiMsgBox(getHelpStyle(),
|
||||
_("THIS WILL DELETE THE GAME "
|
||||
new GuiMsgBox(_("THIS WILL DELETE THE GAME "
|
||||
"FILE, ANY MEDIA FILES AND "
|
||||
"THE GAMELIST.XML ENTRY\nARE YOU SURE?"),
|
||||
_("YES"), deleteFilesAndSelf, _("NO"), nullptr, "", nullptr,
|
||||
|
@ -1039,7 +1035,7 @@ void GuiMetaDataEd::close()
|
|||
if (metadataUpdated) {
|
||||
// Changes were made, ask if the user wants to save them.
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(), _("SAVE CHANGES?"), _("YES"),
|
||||
_("SAVE CHANGES?"), _("YES"),
|
||||
[this, closeFunc] {
|
||||
save();
|
||||
closeFunc();
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
|
||||
#include "GuiComponent.h"
|
||||
#include "MetaData.h"
|
||||
#include "components/BackgroundComponent.h"
|
||||
#include "components/BadgeComponent.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
#include "components/NinePatchComponent.h"
|
||||
#include "components/ScrollIndicatorComponent.h"
|
||||
#include "guis/GuiSettings.h"
|
||||
#include "scrapers/Scraper.h"
|
||||
|
@ -38,7 +38,6 @@ public:
|
|||
void onSizeChanged() override;
|
||||
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); }
|
||||
|
||||
private:
|
||||
void save();
|
||||
|
@ -47,7 +46,7 @@ private:
|
|||
void close();
|
||||
|
||||
Renderer* mRenderer;
|
||||
NinePatchComponent mBackground;
|
||||
BackgroundComponent mBackground;
|
||||
ComponentGrid mGrid;
|
||||
|
||||
std::shared_ptr<TextComponent> mTitle;
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
GuiOfflineGenerator::GuiOfflineGenerator(const std::queue<FileData*>& gameQueue)
|
||||
: mGameQueue {gameQueue}
|
||||
, mRenderer {Renderer::getInstance()}
|
||||
, mBackground {":/graphics/frame.svg"}
|
||||
, mGrid {glm::ivec2 {6, 13}}
|
||||
{
|
||||
addChild(&mBackground);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "GuiComponent.h"
|
||||
#include "MiximageGenerator.h"
|
||||
#include "components/BackgroundComponent.h"
|
||||
#include "components/ButtonComponent.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
#include "views/ViewController.h"
|
||||
|
@ -31,7 +32,6 @@ private:
|
|||
void update(int deltaTime) override;
|
||||
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); }
|
||||
|
||||
std::queue<FileData*> mGameQueue;
|
||||
|
||||
|
@ -55,7 +55,7 @@ private:
|
|||
unsigned int mGamesFailed;
|
||||
|
||||
Renderer* mRenderer;
|
||||
NinePatchComponent mBackground;
|
||||
BackgroundComponent mBackground;
|
||||
ComponentGrid mGrid;
|
||||
|
||||
std::shared_ptr<TextComponent> mTitle;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
GuiOrphanedDataCleanup::GuiOrphanedDataCleanup(std::function<void()> reloadCallback)
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mBackground {":/graphics/frame.svg"}
|
||||
, mGrid {glm::ivec2 {4, 11}}
|
||||
, mReloadCallback {reloadCallback}
|
||||
, mCursorPos {0}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define ES_APP_GUIS_GUI_ORPHANED_DATA_CLEANUP_H
|
||||
|
||||
#include "GuiComponent.h"
|
||||
#include "components/BackgroundComponent.h"
|
||||
#include "components/BusyComponent.h"
|
||||
#include "guis/GuiSettings.h"
|
||||
#include "views/ViewController.h"
|
||||
|
@ -36,10 +37,9 @@ private:
|
|||
bool input(InputConfig* config, Input input) override;
|
||||
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); }
|
||||
|
||||
Renderer* mRenderer;
|
||||
NinePatchComponent mBackground;
|
||||
BackgroundComponent mBackground;
|
||||
ComponentGrid mGrid;
|
||||
BusyComponent mBusyAnim;
|
||||
std::function<void()> mReloadCallback;
|
||||
|
|
|
@ -25,8 +25,7 @@ GuiScraperMenu::GuiScraperMenu(std::string title)
|
|||
, mMenu {title}
|
||||
{
|
||||
// Scraper service.
|
||||
mScraper =
|
||||
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(), _("SCRAPE FROM"), false);
|
||||
mScraper = std::make_shared<OptionListComponent<std::string>>(_("SCRAPE FROM"), false);
|
||||
std::vector<std::string> scrapers = getScraperList();
|
||||
// Select either the first entry or the one read from the settings,
|
||||
// just in case the scraper from settings has vanished.
|
||||
|
@ -42,8 +41,8 @@ GuiScraperMenu::GuiScraperMenu(std::string title)
|
|||
|
||||
// Search filters, getSearches() will generate a queue of games to scrape
|
||||
// based on the outcome of the checks below.
|
||||
mFilters = std::make_shared<OptionListComponent<GameFilterFunc>>(
|
||||
getHelpStyle(), _("SCRAPE THESE GAMES"), false);
|
||||
mFilters =
|
||||
std::make_shared<OptionListComponent<GameFilterFunc>>(_("SCRAPE THESE GAMES"), false);
|
||||
mFilters->add(
|
||||
_("ALL GAMES"),
|
||||
[](SystemData*, FileData*) -> bool {
|
||||
|
@ -103,8 +102,7 @@ GuiScraperMenu::GuiScraperMenu(std::string title)
|
|||
});
|
||||
|
||||
// Add systems (all systems with an existing platform ID are listed).
|
||||
mSystems = std::make_shared<OptionListComponent<SystemData*>>(getHelpStyle(),
|
||||
_("SCRAPE THESE SYSTEMS"), true);
|
||||
mSystems = std::make_shared<OptionListComponent<SystemData*>>(_("SCRAPE THESE SYSTEMS"), true);
|
||||
for (unsigned int i {0}; i < SystemData::sSystemVector.size(); ++i) {
|
||||
if (!SystemData::sSystemVector[i]->hasPlatformId(PlatformIds::PLATFORM_IGNORE)) {
|
||||
mSystems->add(Utils::String::toUpper(SystemData::sSystemVector[i]->getFullName()),
|
||||
|
@ -462,8 +460,8 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
auto s = new GuiSettings(_("MIXIMAGE SETTINGS"));
|
||||
|
||||
// Miximage resolution.
|
||||
auto miximageResolution = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("MIXIMAGE RESOLUTION"), false);
|
||||
auto miximageResolution =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("MIXIMAGE RESOLUTION"), false);
|
||||
std::string selectedResolution {Settings::getInstance()->getString("MiximageResolution")};
|
||||
miximageResolution->add("1280X960", "1280x960", selectedResolution == "1280x960");
|
||||
miximageResolution->add("1920X1440", "1920x1440", selectedResolution == "1920x1440");
|
||||
|
@ -484,7 +482,7 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
|
||||
// Horizontally oriented screenshots fit.
|
||||
auto miximageHorizontalFit = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _p("short", "HORIZONTAL SCREENSHOT FIT"), false);
|
||||
_p("short", "HORIZONTAL SCREENSHOT FIT"), false);
|
||||
const std::string selectedHorizontalFit {
|
||||
Settings::getInstance()->getString("MiximageScreenshotHorizontalFit")};
|
||||
miximageHorizontalFit->add(_("CONTAIN"), "contain", selectedHorizontalFit == "contain");
|
||||
|
@ -506,7 +504,7 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
|
||||
// Vertically oriented screenshots fit.
|
||||
auto miximageVerticalFit = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _p("short", "VERTICAL SCREENSHOT FIT"), false);
|
||||
_p("short", "VERTICAL SCREENSHOT FIT"), false);
|
||||
const std::string selectedVerticalFit {
|
||||
Settings::getInstance()->getString("MiximageScreenshotVerticalFit")};
|
||||
miximageVerticalFit->add(_("CONTAIN"), "contain", selectedVerticalFit == "contain");
|
||||
|
@ -528,7 +526,7 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
|
||||
// Screenshots aspect ratio threshold.
|
||||
auto miximageAspectThreshold = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _p("short", "SCREENSHOT ASPECT RATIO THRESHOLD"), false);
|
||||
_p("short", "SCREENSHOT ASPECT RATIO THRESHOLD"), false);
|
||||
const std::string selectedAspectThreshold {
|
||||
Settings::getInstance()->getString("MiximageScreenshotAspectThreshold")};
|
||||
miximageAspectThreshold->add(_("HIGH"), "high", selectedAspectThreshold == "high");
|
||||
|
@ -548,8 +546,8 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
});
|
||||
|
||||
// Blank areas fill color.
|
||||
auto miximageBlankAreasColor = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("BLANK AREAS FILL COLOR"), false);
|
||||
auto miximageBlankAreasColor =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("BLANK AREAS FILL COLOR"), false);
|
||||
const std::string selectedBlankAreasColor {
|
||||
Settings::getInstance()->getString("MiximageScreenshotBlankAreasColor")};
|
||||
miximageBlankAreasColor->add(_("BLACK"), "black", selectedBlankAreasColor == "black");
|
||||
|
@ -570,7 +568,7 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
|
||||
// Screenshot scaling method.
|
||||
auto miximageScaling = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _p("short", "SCREENSHOT SCALING METHOD"), false);
|
||||
_p("short", "SCREENSHOT SCALING METHOD"), false);
|
||||
std::string selectedScaling {Settings::getInstance()->getString("MiximageScreenshotScaling")};
|
||||
miximageScaling->add(_("SHARP"), "sharp", selectedScaling == "sharp");
|
||||
miximageScaling->add(_("SMOOTH"), "smooth", selectedScaling == "smooth");
|
||||
|
@ -589,8 +587,7 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
});
|
||||
|
||||
// Box/cover size.
|
||||
auto miximageBoxSize =
|
||||
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(), _("BOX SIZE"), false);
|
||||
auto miximageBoxSize = std::make_shared<OptionListComponent<std::string>>(_("BOX SIZE"), false);
|
||||
std::string selectedBoxSize {Settings::getInstance()->getString("MiximageBoxSize")};
|
||||
miximageBoxSize->add(_("SMALL"), "small", selectedBoxSize == "small");
|
||||
miximageBoxSize->add(_("MEDIUM"), "medium", selectedBoxSize == "medium");
|
||||
|
@ -609,8 +606,8 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
});
|
||||
|
||||
// Physical media size.
|
||||
auto miximagePhysicalMediaSize = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("PHYSICAL MEDIA SIZE"), false);
|
||||
auto miximagePhysicalMediaSize =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("PHYSICAL MEDIA SIZE"), false);
|
||||
std::string selectedPhysicalMediaSize {
|
||||
Settings::getInstance()->getString("MiximagePhysicalMediaSize")};
|
||||
miximagePhysicalMediaSize->add(_("SMALL"), "small", selectedPhysicalMediaSize == "small");
|
||||
|
@ -765,8 +762,7 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
void GuiScraperMenu::openOfflineGenerator(GuiSettings* settings)
|
||||
{
|
||||
if (mSystems->getSelectedObjects().empty()) {
|
||||
mWindow->pushGui(new GuiMsgBox(getHelpStyle(),
|
||||
_("THE OFFLINE GENERATOR USES THE SAME SYSTEM "
|
||||
mWindow->pushGui(new GuiMsgBox(_("THE OFFLINE GENERATOR USES THE SAME SYSTEM "
|
||||
"SELECTIONS AS THE SCRAPER, SO PLEASE SELECT "
|
||||
"AT LEAST ONE SYSTEM TO GENERATE IMAGES FOR"),
|
||||
_("OK"), nullptr, "", nullptr, "", nullptr, nullptr, false,
|
||||
|
@ -807,8 +803,7 @@ void GuiScraperMenu::openOtherOptions()
|
|||
auto s = new GuiSettings(_("OTHER SETTINGS"));
|
||||
|
||||
// Scraper region.
|
||||
auto scraperRegion =
|
||||
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(), _("REGION"), false);
|
||||
auto scraperRegion = std::make_shared<OptionListComponent<std::string>>(_("REGION"), false);
|
||||
std::string selectedScraperRegion {Settings::getInstance()->getString("ScraperRegion")};
|
||||
// clang-format off
|
||||
scraperRegion->add(_("EUROPE"), "eu", selectedScraperRegion == "eu");
|
||||
|
@ -838,8 +833,8 @@ void GuiScraperMenu::openOtherOptions()
|
|||
}
|
||||
|
||||
// Scraper language.
|
||||
auto scraperLanguage = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("PREFERRED LANGUAGE"), false);
|
||||
auto scraperLanguage =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("PREFERRED LANGUAGE"), false);
|
||||
std::string selectedScraperLanguage {Settings::getInstance()->getString("ScraperLanguage")};
|
||||
// clang-format off
|
||||
scraperLanguage->add("ENGLISH", "en", selectedScraperLanguage == "en");
|
||||
|
@ -1242,7 +1237,7 @@ void GuiScraperMenu::pressedStart()
|
|||
"SET, RESULTS MAY BE INACCURATE");
|
||||
}
|
||||
mWindow->pushGui(
|
||||
new GuiMsgBox(getHelpStyle(), Utils::String::toUpper(warningString), _("PROCEED"),
|
||||
new GuiMsgBox(Utils::String::toUpper(warningString), _("PROCEED"),
|
||||
std::bind(&GuiScraperMenu::start, this), _("CANCEL"), nullptr, "",
|
||||
nullptr, nullptr, false, true,
|
||||
(mRenderer->getIsVerticalOrientation() ?
|
||||
|
@ -1257,8 +1252,7 @@ void GuiScraperMenu::pressedStart()
|
|||
void GuiScraperMenu::start()
|
||||
{
|
||||
if (mSystems->getSelectedObjects().empty()) {
|
||||
mWindow->pushGui(
|
||||
new GuiMsgBox(getHelpStyle(), _("PLEASE SELECT AT LEAST ONE SYSTEM TO SCRAPE")));
|
||||
mWindow->pushGui(new GuiMsgBox(_("PLEASE SELECT AT LEAST ONE SYSTEM TO SCRAPE")));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1332,16 +1326,14 @@ void GuiScraperMenu::start()
|
|||
} while (0);
|
||||
|
||||
if (!contentToScrape) {
|
||||
mWindow->pushGui(
|
||||
new GuiMsgBox(getHelpStyle(), _("PLEASE SELECT AT LEAST ONE CONTENT TYPE TO SCRAPE")));
|
||||
mWindow->pushGui(new GuiMsgBox(_("PLEASE SELECT AT LEAST ONE CONTENT TYPE TO SCRAPE")));
|
||||
return;
|
||||
}
|
||||
|
||||
auto searches = getSearches(mSystems->getSelectedObjects(), mFilters->getSelected());
|
||||
|
||||
if (searches.first.empty()) {
|
||||
mWindow->pushGui(
|
||||
new GuiMsgBox(getHelpStyle(), _("ALL GAMES WERE FILTERED, NOTHING TO SCRAPE")));
|
||||
mWindow->pushGui(new GuiMsgBox(_("ALL GAMES WERE FILTERED, NOTHING TO SCRAPE")));
|
||||
}
|
||||
else {
|
||||
GuiScraperMulti* gsm {
|
||||
|
|
|
@ -33,7 +33,6 @@ public:
|
|||
bool input(InputConfig* config, Input input) override;
|
||||
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); }
|
||||
|
||||
private:
|
||||
void pressedStart();
|
||||
|
|
|
@ -28,7 +28,6 @@ GuiScraperMulti::GuiScraperMulti(
|
|||
const std::pair<std::queue<ScraperSearchParams>, std::map<SystemData*, int>>& searches,
|
||||
bool approveResults)
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mBackground {":/graphics/frame.svg"}
|
||||
, mGrid {glm::ivec2 {2, 6}}
|
||||
, mSearchQueue {searches.first}
|
||||
, mApproveResults {approveResults}
|
||||
|
@ -327,7 +326,7 @@ void GuiScraperMulti::finish()
|
|||
|
||||
// Pressing either OK or using the back button should delete us.
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(), ss.str(), _("OK"),
|
||||
ss.str(), _("OK"),
|
||||
[&] {
|
||||
mIsProcessing = false;
|
||||
delete this;
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
#include "GuiComponent.h"
|
||||
#include "MetaData.h"
|
||||
#include "components/BackgroundComponent.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
#include "components/NinePatchComponent.h"
|
||||
#include "components/ScrollIndicatorComponent.h"
|
||||
#include "scrapers/Scraper.h"
|
||||
#include "views/ViewController.h"
|
||||
|
@ -35,7 +35,6 @@ public:
|
|||
void onSizeChanged() override;
|
||||
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); }
|
||||
|
||||
private:
|
||||
void acceptResult(const ScraperSearchResult& result);
|
||||
|
@ -44,7 +43,7 @@ private:
|
|||
void finish();
|
||||
|
||||
Renderer* mRenderer;
|
||||
NinePatchComponent mBackground;
|
||||
BackgroundComponent mBackground;
|
||||
ComponentGrid mGrid;
|
||||
|
||||
std::shared_ptr<TextComponent> mTitle;
|
||||
|
|
|
@ -370,7 +370,7 @@ void GuiScraperSearch::search(ScraperSearchParams& params)
|
|||
|
||||
mMD5Hash = "";
|
||||
params.md5Hash = "";
|
||||
if (!Utils::FileSystem::isDirectory(params.game->getPath()))
|
||||
if (!Utils::FileSystem::isDirectory(params.game->getPath()) && mSearchType != MANUAL_MODE)
|
||||
params.fileSize = Utils::FileSystem::getFileSize(params.game->getPath());
|
||||
|
||||
// Only use MD5 file hash searching when in automatic mode.
|
||||
|
@ -419,7 +419,6 @@ void GuiScraperSearch::onSearchDone(std::vector<ScraperSearchResult>& results)
|
|||
// Check if the scraper used is still valid.
|
||||
if (!isValidConfiguredScraper()) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
Utils::String::toUpper("Configured scraper is no longer available.\n"
|
||||
"Please change the scraping source in the settings."),
|
||||
"FINISH", mSkipCallback));
|
||||
|
@ -559,8 +558,8 @@ void GuiScraperSearch::onSearchError(const std::string& error,
|
|||
{
|
||||
if (fatalError) {
|
||||
LOG(LogWarning) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", "");
|
||||
mWindow->pushGui(new GuiMsgBox(getHelpStyle(), Utils::String::toUpper(error), _("OK"),
|
||||
mCancelCallback, "", nullptr, "", nullptr, nullptr, true));
|
||||
mWindow->pushGui(new GuiMsgBox(Utils::String::toUpper(error), _("OK"), mCancelCallback, "",
|
||||
nullptr, "", nullptr, nullptr, true));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -580,14 +579,14 @@ void GuiScraperSearch::onSearchError(const std::string& error,
|
|||
|
||||
if (mScrapeCount > 1) {
|
||||
LOG(LogError) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", "");
|
||||
mWindow->pushGui(new GuiMsgBox(getHelpStyle(), Utils::String::toUpper(error), _("RETRY"),
|
||||
mWindow->pushGui(new GuiMsgBox(Utils::String::toUpper(error), _("RETRY"),
|
||||
std::bind(&GuiScraperSearch::search, this, mLastSearch),
|
||||
_("SKIP"), mSkipCallback, _("CANCEL"), mCancelCallback,
|
||||
nullptr, true));
|
||||
}
|
||||
else {
|
||||
LOG(LogError) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", "");
|
||||
mWindow->pushGui(new GuiMsgBox(getHelpStyle(), Utils::String::toUpper(error), _("RETRY"),
|
||||
mWindow->pushGui(new GuiMsgBox(Utils::String::toUpper(error), _("RETRY"),
|
||||
std::bind(&GuiScraperSearch::search, this, mLastSearch),
|
||||
_("CANCEL"), mCancelCallback, "", nullptr, nullptr, true));
|
||||
}
|
||||
|
@ -1049,14 +1048,13 @@ void GuiScraperSearch::openInputScreen(ScraperSearchParams& params)
|
|||
searchString = Utils::String::replace(searchString, "_", " ");
|
||||
|
||||
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||
getHelpStyle(), 0.0f, _("REFINE SEARCH"), searchString, searchForFunc, false,
|
||||
_("SEARCH"), _("SEARCH USING REFINED NAME?")));
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(0.0f, _("REFINE SEARCH"), searchString,
|
||||
searchForFunc, false, _("SEARCH"),
|
||||
_("SEARCH USING REFINED NAME?")));
|
||||
}
|
||||
else {
|
||||
mWindow->pushGui(new GuiTextEditPopup(getHelpStyle(), _("REFINE SEARCH"), searchString,
|
||||
searchForFunc, false, _("SEARCH"),
|
||||
_("SEARCH USING REFINED NAME?")));
|
||||
mWindow->pushGui(new GuiTextEditPopup(_("REFINE SEARCH"), searchString, searchForFunc,
|
||||
false, _("SEARCH"), _("SEARCH USING REFINED NAME?")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ public:
|
|||
void update(int deltaTime) override;
|
||||
void render(const glm::mat4& parentTrans) override;
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); }
|
||||
|
||||
void onSizeChanged() override;
|
||||
|
||||
void decreaseScrapeCount()
|
||||
|
|
|
@ -23,7 +23,6 @@ GuiScraperSingle::GuiScraperSingle(ScraperSearchParams& params,
|
|||
bool& savedMediaAndAborted)
|
||||
: mClose {false}
|
||||
, mRenderer {Renderer::getInstance()}
|
||||
, mBackground {":/graphics/frame.svg"}
|
||||
, mGrid {glm::ivec2 {2, 6}}
|
||||
, mSearchParams {params}
|
||||
, mSavedMediaAndAborted {savedMediaAndAborted}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#define ES_APP_GUIS_GUI_SCRAPER_SINGLE_H
|
||||
|
||||
#include "GuiComponent.h"
|
||||
#include "components/NinePatchComponent.h"
|
||||
#include "components/BackgroundComponent.h"
|
||||
#include "components/ScrollIndicatorComponent.h"
|
||||
#include "guis/GuiScraperSearch.h"
|
||||
#include "views/ViewController.h"
|
||||
|
@ -30,14 +30,13 @@ public:
|
|||
void update(int deltaTime) override;
|
||||
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); }
|
||||
|
||||
private:
|
||||
bool mClose;
|
||||
void close();
|
||||
|
||||
Renderer* mRenderer;
|
||||
NinePatchComponent mBackground;
|
||||
BackgroundComponent mBackground;
|
||||
ComponentGrid mGrid;
|
||||
|
||||
std::shared_ptr<TextComponent> mGameName;
|
||||
|
|
|
@ -38,8 +38,8 @@ GuiScreensaverOptions::GuiScreensaverOptions(const std::string& title)
|
|||
});
|
||||
|
||||
// Screensaver type.
|
||||
auto screensaverType = std::make_shared<OptionListComponent<std::string>>(
|
||||
getHelpStyle(), _("SCREENSAVER TYPE"), false);
|
||||
auto screensaverType =
|
||||
std::make_shared<OptionListComponent<std::string>>(_("SCREENSAVER TYPE"), false);
|
||||
std::string selectedScreensaver {Settings::getInstance()->getString("ScreensaverType")};
|
||||
screensaverType->add(_("DIM"), "dim", selectedScreensaver == "dim");
|
||||
screensaverType->add(_("BLACK"), "black", selectedScreensaver == "black");
|
||||
|
@ -224,14 +224,14 @@ void GuiScreensaverOptions::openSlideshowScreensaverOptions()
|
|||
initValueMediaDir, updateValMediaDir] {
|
||||
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||
getHelpStyle(), s->getMenu().getPosition().y, titleCustomImageDir,
|
||||
s->getMenu().getPosition().y, titleCustomImageDir,
|
||||
Settings::getInstance()->getString("ScreensaverSlideshowCustomDir"),
|
||||
updateValMediaDir, false, _("SAVE"), _("SAVE CHANGES?"), defaultImageDirStaticText,
|
||||
defaultImageDirText, _("load default directory")));
|
||||
}
|
||||
else {
|
||||
mWindow->pushGui(new GuiTextEditPopup(
|
||||
getHelpStyle(), titleCustomImageDir,
|
||||
titleCustomImageDir,
|
||||
Settings::getInstance()->getString("ScreensaverSlideshowCustomDir"),
|
||||
updateValMediaDir, false, _("SAVE"), _("SAVE CHANGES?"), defaultImageDirStaticText,
|
||||
defaultImageDirText, _("load default directory")));
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "FileFilterIndex.h"
|
||||
#include "Settings.h"
|
||||
#include "SystemData.h"
|
||||
#include "SystemStatus.h"
|
||||
#include "Window.h"
|
||||
#include "components/HelpComponent.h"
|
||||
#include "guis/GuiTextEditKeyboardPopup.h"
|
||||
|
@ -36,6 +37,8 @@ GuiSettings::GuiSettings(std::string title)
|
|||
, mNeedsGoToStart {false}
|
||||
, mNeedsGoToSystem {false}
|
||||
, mNeedsGoToGroupedCollections {false}
|
||||
, mNeedsUpdateStatusComponents {false}
|
||||
, mNeedsClearHelpPromptsImageCache {false}
|
||||
, mInvalidateCachedBackground {false}
|
||||
{
|
||||
addChild(&mMenu);
|
||||
|
@ -143,6 +146,18 @@ void GuiSettings::save()
|
|||
ViewController::getInstance()->goToSystem(SystemData::sSystemVector.front(), false);
|
||||
}
|
||||
|
||||
if (mNeedsUpdateStatusComponents) {
|
||||
SystemStatus::getInstance().setCheckFlags();
|
||||
SystemStatus::getInstance().setPollImmediately(true);
|
||||
// If we're not done within this time window it's not the end of the world,
|
||||
// the indicators will still get updated shortly.
|
||||
SDL_Delay(100);
|
||||
mWindow->updateSystemStatusComponents();
|
||||
}
|
||||
|
||||
if (mNeedsClearHelpPromptsImageCache)
|
||||
mWindow->clearHelpPromptsImageCache();
|
||||
|
||||
if (mNeedsCollectionsUpdate) {
|
||||
auto state = ViewController::getInstance()->getState();
|
||||
// If we're in any view other than the grouped custom collections, always jump to the
|
||||
|
@ -241,24 +256,23 @@ void GuiSettings::addEditableTextComponent(const std::string label,
|
|||
row.makeAcceptInputHandler([this, label, ed, updateVal, isPassword] {
|
||||
// Never display the value if it's a password, instead set it to blank.
|
||||
if (isPassword)
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||
getHelpStyle(), getMenu().getPosition().y, label, "", updateVal, false,
|
||||
_("SAVE"), _("SAVE CHANGES?")));
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(getMenu().getPosition().y, label, "",
|
||||
updateVal, false, _("SAVE"),
|
||||
_("SAVE CHANGES?")));
|
||||
else
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||
getHelpStyle(), getMenu().getPosition().y, label, ed->getValue(), updateVal,
|
||||
false, _("SAVE"), _("SAVE CHANGES?")));
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(getMenu().getPosition().y, label,
|
||||
ed->getValue(), updateVal, false,
|
||||
_("SAVE"), _("SAVE CHANGES?")));
|
||||
});
|
||||
}
|
||||
else {
|
||||
row.makeAcceptInputHandler([this, label, ed, updateVal, isPassword] {
|
||||
if (isPassword)
|
||||
mWindow->pushGui(new GuiTextEditPopup(getHelpStyle(), label, "", updateVal, false,
|
||||
_("SAVE"), _("SAVE CHANGES?")));
|
||||
else
|
||||
mWindow->pushGui(new GuiTextEditPopup(getHelpStyle(), label, ed->getValue(),
|
||||
updateVal, false, _("SAVE"),
|
||||
mWindow->pushGui(new GuiTextEditPopup(label, "", updateVal, false, _("SAVE"),
|
||||
_("SAVE CHANGES?")));
|
||||
else
|
||||
mWindow->pushGui(new GuiTextEditPopup(label, ed->getValue(), updateVal, false,
|
||||
_("SAVE"), _("SAVE CHANGES?")));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,8 @@ public:
|
|||
mGoToSystem = goToSystem;
|
||||
};
|
||||
void setNeedsGoToGroupedCollections() { mNeedsGoToGroupedCollections = true; }
|
||||
void setNeedsUpdateStatusComponents() { mNeedsUpdateStatusComponents = true; }
|
||||
void setNeedsClearHelpPromptsImageCache() { mNeedsClearHelpPromptsImageCache = true; }
|
||||
void setNeedsCloseMenu(std::function<void()> closeFunction)
|
||||
{
|
||||
mCloseMenuFunction = closeFunction;
|
||||
|
@ -66,7 +68,6 @@ public:
|
|||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); }
|
||||
|
||||
private:
|
||||
Renderer* mRenderer;
|
||||
|
@ -85,6 +86,8 @@ private:
|
|||
bool mNeedsGoToStart;
|
||||
bool mNeedsGoToSystem;
|
||||
bool mNeedsGoToGroupedCollections;
|
||||
bool mNeedsUpdateStatusComponents;
|
||||
bool mNeedsClearHelpPromptsImageCache;
|
||||
bool mInvalidateCachedBackground;
|
||||
};
|
||||
|
||||
|
|
117
es-app/src/guis/GuiSystemStatusOptions.cpp
Normal file
117
es-app/src/guis/GuiSystemStatusOptions.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// ES-DE Frontend
|
||||
// GuiSystemStatusOptions.cpp
|
||||
//
|
||||
// User interface for the system status options.
|
||||
// Submenu to the GuiMenu main menu.
|
||||
//
|
||||
#include "guis/GuiSystemStatusOptions.h"
|
||||
|
||||
#include "Settings.h"
|
||||
#include "components/OptionListComponent.h"
|
||||
#include "components/SwitchComponent.h"
|
||||
#include "utils/LocalizationUtil.h"
|
||||
|
||||
GuiSystemStatusOptions::GuiSystemStatusOptions(const std::string& title)
|
||||
: GuiSettings {title}
|
||||
{
|
||||
// Display Bluetooth indicator.
|
||||
auto systemStatusBluetooth = std::make_shared<SwitchComponent>();
|
||||
systemStatusBluetooth->setState(Settings::getInstance()->getBool("SystemStatusBluetooth"));
|
||||
addWithLabel(_("DISPLAY BLUETOOTH STATUS INDICATOR"), systemStatusBluetooth);
|
||||
addSaveFunc([systemStatusBluetooth, this] {
|
||||
if (systemStatusBluetooth->getState() !=
|
||||
Settings::getInstance()->getBool("SystemStatusBluetooth")) {
|
||||
Settings::getInstance()->setBool("SystemStatusBluetooth",
|
||||
systemStatusBluetooth->getState());
|
||||
setNeedsSaving();
|
||||
setNeedsUpdateStatusComponents();
|
||||
}
|
||||
});
|
||||
|
||||
// Display WiFi indicator.
|
||||
auto systemStatusWifi = std::make_shared<SwitchComponent>();
|
||||
systemStatusWifi->setState(Settings::getInstance()->getBool("SystemStatusWifi"));
|
||||
addWithLabel(_("DISPLAY WI-FI STATUS INDICATOR"), systemStatusWifi);
|
||||
addSaveFunc([systemStatusWifi, this] {
|
||||
if (systemStatusWifi->getState() != Settings::getInstance()->getBool("SystemStatusWifi")) {
|
||||
Settings::getInstance()->setBool("SystemStatusWifi", systemStatusWifi->getState());
|
||||
setNeedsSaving();
|
||||
setNeedsUpdateStatusComponents();
|
||||
}
|
||||
});
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// Display cellular indicator.
|
||||
auto systemStatusCellular = std::make_shared<SwitchComponent>();
|
||||
systemStatusCellular->setState(Settings::getInstance()->getBool("SystemStatusCellular"));
|
||||
addWithLabel(_("DISPLAY CELLULAR STATUS INDICATOR"), systemStatusCellular);
|
||||
addSaveFunc([systemStatusCellular, this] {
|
||||
if (systemStatusCellular->getState() !=
|
||||
Settings::getInstance()->getBool("SystemStatusCellular")) {
|
||||
Settings::getInstance()->setBool("SystemStatusCellular",
|
||||
systemStatusCellular->getState());
|
||||
setNeedsSaving();
|
||||
setNeedsUpdateStatusComponents();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
// Display battery indicator.
|
||||
auto systemStatusBattery = std::make_shared<SwitchComponent>();
|
||||
systemStatusBattery->setState(Settings::getInstance()->getBool("SystemStatusBattery"));
|
||||
addWithLabel(_("DISPLAY BATTERY STATUS INDICATOR"), systemStatusBattery);
|
||||
addSaveFunc([systemStatusBattery, this] {
|
||||
if (systemStatusBattery->getState() !=
|
||||
Settings::getInstance()->getBool("SystemStatusBattery")) {
|
||||
Settings::getInstance()->setBool("SystemStatusBattery",
|
||||
systemStatusBattery->getState());
|
||||
setNeedsSaving();
|
||||
setNeedsUpdateStatusComponents();
|
||||
}
|
||||
});
|
||||
|
||||
// Display battery charge percentage.
|
||||
auto systemStatusBatteryPercentage = std::make_shared<SwitchComponent>();
|
||||
systemStatusBatteryPercentage->setState(
|
||||
Settings::getInstance()->getBool("SystemStatusBatteryPercentage"));
|
||||
addWithLabel(_("DISPLAY BATTERY CHARGE PERCENTAGE"), systemStatusBatteryPercentage);
|
||||
addSaveFunc([systemStatusBatteryPercentage, this] {
|
||||
if (systemStatusBatteryPercentage->getState() !=
|
||||
Settings::getInstance()->getBool("SystemStatusBatteryPercentage")) {
|
||||
Settings::getInstance()->setBool("SystemStatusBatteryPercentage",
|
||||
systemStatusBatteryPercentage->getState());
|
||||
setNeedsSaving();
|
||||
setNeedsUpdateStatusComponents();
|
||||
}
|
||||
});
|
||||
|
||||
// Gray out the battery charge percentage option if the battery setting has been disabled.
|
||||
if (!Settings::getInstance()->getBool("SystemStatusBattery")) {
|
||||
systemStatusBatteryPercentage->setEnabled(false);
|
||||
systemStatusBatteryPercentage->setOpacity(DISABLED_OPACITY);
|
||||
systemStatusBatteryPercentage->getParent()
|
||||
->getChild(systemStatusBatteryPercentage->getChildIndex() - 1)
|
||||
->setOpacity(DISABLED_OPACITY);
|
||||
}
|
||||
|
||||
auto batteryToggleFunc = [systemStatusBatteryPercentage]() {
|
||||
if (systemStatusBatteryPercentage->getEnabled()) {
|
||||
systemStatusBatteryPercentage->setEnabled(false);
|
||||
systemStatusBatteryPercentage->setOpacity(DISABLED_OPACITY);
|
||||
systemStatusBatteryPercentage->getParent()
|
||||
->getChild(systemStatusBatteryPercentage->getChildIndex() - 1)
|
||||
->setOpacity(DISABLED_OPACITY);
|
||||
}
|
||||
else {
|
||||
systemStatusBatteryPercentage->setEnabled(true);
|
||||
systemStatusBatteryPercentage->setOpacity(1.0f);
|
||||
systemStatusBatteryPercentage->getParent()
|
||||
->getChild(systemStatusBatteryPercentage->getChildIndex() - 1)
|
||||
->setOpacity(1.0f);
|
||||
}
|
||||
};
|
||||
|
||||
systemStatusBattery->setCallback(batteryToggleFunc);
|
||||
}
|
21
es-app/src/guis/GuiSystemStatusOptions.h
Normal file
21
es-app/src/guis/GuiSystemStatusOptions.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// ES-DE Frontend
|
||||
// GuiSystemStatusOptions.h
|
||||
//
|
||||
// User interface for the system status options.
|
||||
// Submenu to the GuiMenu main menu.
|
||||
//
|
||||
|
||||
#ifndef ES_APP_GUIS_GUI_SYSTEM_STATUS_OPTIONS_H
|
||||
#define ES_APP_GUIS_GUI_SYSTEM_STATUS_OPTIONS_H
|
||||
|
||||
#include "guis/GuiSettings.h"
|
||||
|
||||
class GuiSystemStatusOptions : public GuiSettings
|
||||
{
|
||||
public:
|
||||
GuiSystemStatusOptions(const std::string& title);
|
||||
};
|
||||
|
||||
#endif // ES_APP_GUIS_GUI_SYSTEM_STATUS_OPTIONS_H
|
|
@ -20,9 +20,14 @@
|
|||
#define LOCAL_TESTING_FILE false
|
||||
#define DEBUG_CLONING false
|
||||
|
||||
// Someone obviously thought it was a bright idea to change the version macros in libgit2 v1.9.0.
|
||||
#if defined(LIBGIT2_VERSION_MAJOR)
|
||||
#define LIBGIT2_VER_MAJOR LIBGIT2_VERSION_MAJOR
|
||||
#define LIBGIT2_VER_MINOR LIBGIT2_VERSION_MINOR
|
||||
#endif
|
||||
|
||||
GuiThemeDownloader::GuiThemeDownloader(std::function<void()> updateCallback)
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mBackground {":/graphics/frame.svg"}
|
||||
, mGrid {glm::ivec2 {2, 4}}
|
||||
, mUpdateCallback(updateCallback)
|
||||
, mRepositoryError {RepositoryError::NO_REPO_ERROR}
|
||||
|
@ -166,7 +171,7 @@ GuiThemeDownloader::GuiThemeDownloader(std::function<void()> updateCallback)
|
|||
|
||||
git_libgit2_init();
|
||||
|
||||
#if defined(__ANDROID__) && defined(USE_BUNDLED_CERTIFICATES)
|
||||
#if (defined(__ANDROID__) || defined(__IOS__)) && defined(USE_BUNDLED_CERTIFICATES)
|
||||
git_libgit2_opts(
|
||||
GIT_OPT_SET_SSL_CERT_LOCATIONS,
|
||||
ResourceManager::getInstance().getResourcePath(":/certificates/curl-ca-bundle.crt").c_str(),
|
||||
|
@ -180,6 +185,8 @@ GuiThemeDownloader::GuiThemeDownloader(std::function<void()> updateCallback)
|
|||
|
||||
#if defined(__ANDROID__)
|
||||
mThemeDirectory = Utils::FileSystem::getInternalAppDataDirectory() + "/themes";
|
||||
#elif defined(__IOS__)
|
||||
mThemeDirectory = Utils::FileSystem::getAppDataDirectory() + "/themes";
|
||||
#else
|
||||
const std::string defaultUserThemeDir {Utils::FileSystem::getAppDataDirectory() + "/themes"};
|
||||
const std::string userThemeDirSetting {Utils::FileSystem::expandHomePath(
|
||||
|
@ -601,7 +608,6 @@ bool GuiThemeDownloader::renameDirectory(const std::string& path, const std::str
|
|||
|
||||
if (renameStatus) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
Utils::String::format(_("COULDN'T RENAME DIRECTORY \"%s\"\nPERMISSION PROBLEMS?"),
|
||||
path.c_str()),
|
||||
_("OK"), [] { return; }, "", nullptr, "", nullptr, nullptr, true));
|
||||
|
@ -625,8 +631,8 @@ void GuiThemeDownloader::parseThemesList()
|
|||
if (!Utils::FileSystem::exists(themesFile)) {
|
||||
LOG(LogError) << "GuiThemeDownloader: No themes.json file found";
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(), _("COULDN'T FIND THE THEMES LIST CONFIGURATION FILE"), _("OK"),
|
||||
[] { return; }, "", nullptr, "", nullptr, nullptr, true));
|
||||
_("COULDN'T FIND THE THEMES LIST CONFIGURATION FILE"), _("OK"), [] { return; }, "",
|
||||
nullptr, "", nullptr, nullptr, true));
|
||||
mGrid.removeEntry(mCenterGrid);
|
||||
mGrid.setCursorTo(mButtons);
|
||||
return;
|
||||
|
@ -639,7 +645,6 @@ void GuiThemeDownloader::parseThemesList()
|
|||
if (doc.HasParseError()) {
|
||||
LOG(LogError) << "GuiThemeDownloader: Couldn't parse the themes.json file";
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
_("COULDN'T PARSE THE THEMES LIST CONFIGURATION FILE, MAYBE THE LOCAL REPOSITORY IS "
|
||||
"CORRUPT?"),
|
||||
_("OK"), [] { return; }, "", nullptr, "", nullptr, nullptr, true));
|
||||
|
@ -663,7 +668,6 @@ void GuiThemeDownloader::parseThemesList()
|
|||
#else
|
||||
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
_("IT SEEMS AS IF YOU'RE NOT RUNNING THE LATEST ES-DE RELEASE, PLEASE UPGRADE "
|
||||
"BEFORE PROCEEDING AS THESE THEMES MAY NOT BE COMPATIBLE WITH YOUR VERSION"),
|
||||
_("OK"), [] { return; }, "", nullptr, "", nullptr, nullptr, true));
|
||||
|
@ -806,7 +810,6 @@ void GuiThemeDownloader::populateGUI()
|
|||
std::promise<bool>().swap(mPromise);
|
||||
if (theme.manuallyDownloaded || theme.invalidRepository) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
Utils::String::format(
|
||||
_("IT SEEMS AS IF THIS THEME HAS BEEN MANUALLY DOWNLOADED INSTEAD OF VIA "
|
||||
"THIS THEME DOWNLOADER. A FRESH DOWNLOAD IS REQUIRED AND THE OLD THEME "
|
||||
|
@ -834,7 +837,6 @@ void GuiThemeDownloader::populateGUI()
|
|||
}
|
||||
else if (theme.corruptRepository) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
Utils::String::format(
|
||||
_("IT SEEMS AS IF THIS THEME REPOSITORY IS CORRUPT, WHICH COULD HAVE BEEN "
|
||||
"CAUSED BY AN INTERRUPTION OF A PREVIOUS DOWNLOAD OR UPDATE, FOR EXAMPLE "
|
||||
|
@ -863,7 +865,6 @@ void GuiThemeDownloader::populateGUI()
|
|||
}
|
||||
else if (theme.shallowRepository) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
Utils::String::format(
|
||||
_("IT SEEMS AS IF THIS IS A SHALLOW REPOSITORY WHICH MEANS THAT IT HAS "
|
||||
"BEEN DOWNLOADED USING SOME OTHER TOOL THAN THIS THEME DOWNLOADER. A "
|
||||
|
@ -892,7 +893,6 @@ void GuiThemeDownloader::populateGUI()
|
|||
}
|
||||
else if (theme.wrongUrl) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
Utils::String::format(
|
||||
_("THE LOCALLY CLONED REPOSITORY CONTAINS THE WRONG URL WHICH NORMALLY "
|
||||
"MEANS THE THEME HAS BEEN MOVED TO A NEW GIT SITE. A FRESH DOWNLOAD IS "
|
||||
|
@ -921,7 +921,6 @@ void GuiThemeDownloader::populateGUI()
|
|||
}
|
||||
else if (theme.hasLocalChanges) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
Utils::String::format(
|
||||
_("THEME REPOSITORY \"%s\" CONTAINS LOCAL CHANGES. PROCEED TO OVERWRITE "
|
||||
"YOUR CHANGES OR CANCEL TO SKIP ALL UPDATES FOR THIS THEME"),
|
||||
|
@ -1137,8 +1136,8 @@ void GuiThemeDownloader::update(int deltaTime)
|
|||
}
|
||||
errorMessage.append(" ").append(Utils::String::toUpper(mMessage));
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(), errorMessage, _("OK"), [] { return; }, "", nullptr, "",
|
||||
nullptr, nullptr, true));
|
||||
errorMessage, _("OK"), [] { return; }, "", nullptr, "", nullptr, nullptr,
|
||||
true));
|
||||
mRepositoryError = RepositoryError::NO_REPO_ERROR;
|
||||
mMessage = "";
|
||||
getHelpPrompts();
|
||||
|
@ -1324,7 +1323,6 @@ bool GuiThemeDownloader::input(InputConfig* config, Input input)
|
|||
if (config->isMappedTo("y", input) && input.value &&
|
||||
mGrid.getSelectedComponent() == mCenterGrid && mThemes[mList->getCursorId()].isCloned) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
#if defined(__ANDROID__)
|
||||
_("THIS WILL COMPLETELY DELETE THE THEME"),
|
||||
#else
|
||||
|
@ -1343,8 +1341,8 @@ bool GuiThemeDownloader::input(InputConfig* config, Input input)
|
|||
LOG(LogInfo) << "Deleting theme directory \"" << themeDirectory << "\"";
|
||||
if (!Utils::FileSystem::removeDirectory(themeDirectory, true)) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(), _("COULDN'T DELETE THEME, PERMISSION PROBLEMS?"), _("OK"),
|
||||
[] { return; }, "", nullptr, "", nullptr, nullptr, true));
|
||||
_("COULDN'T DELETE THEME, PERMISSION PROBLEMS?"), _("OK"), [] { return; },
|
||||
"", nullptr, "", nullptr, nullptr, true));
|
||||
}
|
||||
else {
|
||||
mMessage = _("THEME WAS DELETED");
|
||||
|
@ -1428,7 +1426,6 @@ bool GuiThemeDownloader::fetchThemesList()
|
|||
|
||||
if (errorCode != 0 || checkCorruptRepository(repository)) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
_("IT SEEMS AS IF THE THEMES LIST REPOSITORY IS CORRUPT, WHICH COULD HAVE BEEN "
|
||||
"CAUSED BY AN INTERRUPTION OF A PREVIOUS DOWNLOAD OR UPDATE, FOR EXAMPLE IF THE "
|
||||
"ES-DE PROCESS WAS KILLED. A FRESH DOWNLOAD IS REQUIRED AND THE OLD DIRECTORY "
|
||||
|
@ -1471,7 +1468,6 @@ bool GuiThemeDownloader::fetchThemesList()
|
|||
}
|
||||
else {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(),
|
||||
_("IT SEEMS AS IF YOU'RE USING THE THEME DOWNLOADER FOR THE FIRST TIME. "
|
||||
"AS SUCH THE THEMES LIST REPOSITORY WILL BE DOWNLOADED WHICH WILL TAKE A LITTLE "
|
||||
"WHILE. SUBSEQUENT RUNS WILL HOWEVER BE MUCH FASTER AS ONLY NEW OR MODIFIED FILES "
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
#define ES_APP_GUIS_GUI_THEME_DOWNLOADER_H
|
||||
|
||||
#include "GuiComponent.h"
|
||||
#include "components/BackgroundComponent.h"
|
||||
#include "components/BusyComponent.h"
|
||||
#include "components/ButtonComponent.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
#include "components/ComponentList.h"
|
||||
#include "components/ImageComponent.h"
|
||||
#include "components/NinePatchComponent.h"
|
||||
#include "components/ScrollIndicatorComponent.h"
|
||||
#include "components/TextComponent.h"
|
||||
#include "renderers/Renderer.h"
|
||||
|
@ -47,7 +47,6 @@ public:
|
|||
bool input(InputConfig* config, Input input) override;
|
||||
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); }
|
||||
|
||||
private:
|
||||
struct Screenshot {
|
||||
|
@ -108,7 +107,7 @@ private:
|
|||
void setupFullscreenViewer();
|
||||
|
||||
Renderer* mRenderer;
|
||||
NinePatchComponent mBackground;
|
||||
BackgroundComponent mBackground;
|
||||
ComponentGrid mGrid;
|
||||
std::shared_ptr<ComponentGrid> mCenterGrid;
|
||||
std::shared_ptr<ComponentList> mList;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "Settings.h"
|
||||
#include "Sound.h"
|
||||
#include "SystemData.h"
|
||||
#include "SystemStatus.h"
|
||||
#include "guis/GuiDetectDevice.h"
|
||||
#include "guis/GuiLaunchScreen.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
|
@ -35,9 +36,13 @@
|
|||
#include "views/ViewController.h"
|
||||
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <SDL2/SDL_main.h>
|
||||
#include <SDL2/SDL_timer.h>
|
||||
|
||||
// TODO: Not needed after moving to SDL3.
|
||||
#if !defined(__IOS__)
|
||||
#include <SDL2/SDL_main.h>
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include "utils/PlatformUtilAndroid.h"
|
||||
#endif
|
||||
|
@ -570,7 +575,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
SDL_SetHint(SDL_HINT_APP_NAME, "ES-DE");
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#if defined(__APPLE__) && !defined(__IOS__)
|
||||
// This is a workaround to disable the incredibly annoying save state functionality in
|
||||
// macOS which forces a restore of the previous window state. The problem is that this
|
||||
// removes the splash screen on startup and it may have other adverse effects as well.
|
||||
|
@ -598,7 +603,7 @@ int main(int argc, char* argv[])
|
|||
outputToConsole();
|
||||
#endif
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
#if !defined(__ANDROID__) && !defined(__IOS__)
|
||||
{
|
||||
std::vector<std::string> arguments;
|
||||
for (int i {0}; i < argc; ++i)
|
||||
|
@ -873,7 +878,7 @@ const std::string applicationName = "ES-DE";
|
|||
}
|
||||
|
||||
{
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
const std::string themeDir {Utils::FileSystem::getAppDataDirectory() + "/themes"};
|
||||
if (!Utils::FileSystem::exists(themeDir)) {
|
||||
LOG(LogInfo) << "Creating themes directory \"" << themeDir << "\"...";
|
||||
|
@ -883,6 +888,7 @@ const std::string applicationName = "ES-DE";
|
|||
LOG(LogWarning) << "Couldn't create directory, permission problems?";
|
||||
}
|
||||
}
|
||||
#if defined(__ANDROID__)
|
||||
if (!Utils::FileSystem::exists(themeDir + "/.nomedia")) {
|
||||
LOG(LogInfo) << "Creating \"no media\" file \"" << themeDir + "/.nomedia" << "\"...";
|
||||
Utils::FileSystem::createEmptyFile(themeDir + "/.nomedia");
|
||||
|
@ -890,6 +896,7 @@ const std::string applicationName = "ES-DE";
|
|||
LOG(LogWarning) << "Couldn't create file, permission problems?";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
// Create the themes folder in the application data directory (or elsewhere if the
|
||||
// UserThemeDirectory setting has been defined).
|
||||
|
@ -934,6 +941,7 @@ const std::string applicationName = "ES-DE";
|
|||
#endif
|
||||
}
|
||||
|
||||
#if !defined(__IOS__)
|
||||
{
|
||||
// Create the scripts folder in the application data directory. This is only required
|
||||
// for custom event scripts so it's also created as a convenience.
|
||||
|
@ -951,6 +959,7 @@ const std::string applicationName = "ES-DE";
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
// Create the screensavers and screensavers/custom_slideshow directories.
|
||||
|
@ -1066,9 +1075,11 @@ const std::string applicationName = "ES-DE";
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
InputOverlay::getInstance().init();
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
LOG(LogDebug) << "Android API level: " << SDL_GetAndroidSDKVersion();
|
||||
Utils::Platform::Android::printDeviceInfo();
|
||||
int storageState {SDL_AndroidGetExternalStorageState()};
|
||||
|
@ -1157,6 +1168,7 @@ const std::string applicationName = "ES-DE";
|
|||
}
|
||||
#endif
|
||||
|
||||
SystemStatus::getInstance();
|
||||
MameNames::getInstance();
|
||||
ThemeData::populateThemes();
|
||||
loadSystemsReturnCode loadSystemsStatus {loadSystemConfigFile()};
|
||||
|
@ -1315,5 +1327,9 @@ const std::string applicationName = "ES-DE";
|
|||
FreeConsole();
|
||||
#endif
|
||||
|
||||
#if defined(__IOS__)
|
||||
exit(0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ namespace
|
|||
{LCD_GAMES, 75},
|
||||
{MICROSOFT_XBOX, 32},
|
||||
{MICROSOFT_XBOX_360, 33},
|
||||
{MICROSOFT_XBOX_ONE, 34},
|
||||
{MSX, 113},
|
||||
{MSX2, 116},
|
||||
{MSX_TURBO_R, 118},
|
||||
|
@ -162,6 +163,7 @@ namespace
|
|||
{THOMSON_MOTO, 141},
|
||||
{UZEBOX, 216},
|
||||
{FUTURE_PINBALL, 199},
|
||||
{VIRCON32, 272},
|
||||
{VISUAL_PINBALL, 198},
|
||||
{WATARA_SUPERVISION, 207},
|
||||
{SPECTRAVIDEO, 218},
|
||||
|
|
|
@ -67,6 +67,8 @@ public:
|
|||
const std::string platformIdentifier {" P"};
|
||||
#elif defined(__linux__)
|
||||
const std::string platformIdentifier {" L"};
|
||||
#elif defined(__IOS__)
|
||||
const std::string platformIdentifier {" I"};
|
||||
#elif defined(__APPLE__)
|
||||
const std::string platformIdentifier {" M"};
|
||||
#elif defined(_WIN64)
|
||||
|
|
|
@ -500,6 +500,7 @@ bool GamelistBase::input(InputConfig* config, Input input)
|
|||
stopListScrolling();
|
||||
pauseViewVideos();
|
||||
stopGamelistFadeAnimations();
|
||||
ViewController::getInstance()->setHelpComponentsVisibility(false);
|
||||
mWindow->setAllowTextScrolling(false);
|
||||
mWindow->setAllowFileAnimation(false);
|
||||
mWindow->pushGui(new GuiGamelistOptions(this->mRoot->getSystem()));
|
||||
|
@ -512,6 +513,7 @@ bool GamelistBase::input(InputConfig* config, Input input)
|
|||
(SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL)) && input.id == SDLK_r &&
|
||||
input.value != 0) {
|
||||
LOG(LogDebug) << "GamelistView::input(): Reloading view";
|
||||
mWindow->clearHelpPromptsImageCache();
|
||||
ViewController::getInstance()->reloadGamelistView(this->mRoot->getSystem(), true);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "components/LottieAnimComponent.h"
|
||||
#include "components/RatingComponent.h"
|
||||
#include "components/ScrollableContainer.h"
|
||||
#include "components/SystemStatusComponent.h"
|
||||
#include "components/TextComponent.h"
|
||||
#include "components/VideoFFmpegComponent.h"
|
||||
#include "components/primary/CarouselComponent.h"
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "views/GamelistView.h"
|
||||
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "Scripting.h"
|
||||
#include "UIModeController.h"
|
||||
#include "animations/LambdaAnimation.h"
|
||||
#include "utils/LocalizationUtil.h"
|
||||
|
@ -20,6 +21,8 @@ GamelistView::GamelistView(FileData* root)
|
|||
: GamelistBase {root}
|
||||
, mRenderer {Renderer::getInstance()}
|
||||
, mStaticVideoAudio {false}
|
||||
, mTriggerEvent {false}
|
||||
, mTriggeredEventFastScroll {false}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -88,6 +91,15 @@ void GamelistView::onShow()
|
|||
for (auto& video : mStaticVideoComponents)
|
||||
video->stopVideoPlayer();
|
||||
|
||||
mWindow->passClockComponents(&mClockComponents);
|
||||
mWindow->passSystemStatusComponents(&mSystemStatusComponents);
|
||||
|
||||
for (auto& clock : mClockComponents)
|
||||
clock->update(500);
|
||||
|
||||
for (auto& systemstatus : mSystemStatusComponents)
|
||||
systemstatus->update(SystemStatus::updateTime);
|
||||
|
||||
mLastUpdated = nullptr;
|
||||
GuiComponent::onShow();
|
||||
|
||||
|
@ -349,9 +361,35 @@ void GamelistView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
mRatingComponents.back()->setOpacity(mRatingComponents.back()->getOpacity());
|
||||
addChild(mRatingComponents.back().get());
|
||||
}
|
||||
else if (element.second.type == "helpsystem") {
|
||||
mHelpComponents.emplace_back(std::make_unique<HelpComponent>());
|
||||
mHelpComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
||||
}
|
||||
else if (element.second.type == "clock") {
|
||||
mClockComponents.emplace_back(std::make_unique<DateTimeComponent>());
|
||||
mClockComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
||||
}
|
||||
else if (element.second.type == "systemstatus") {
|
||||
mSystemStatusComponents.emplace_back(std::make_unique<SystemStatusComponent>());
|
||||
mSystemStatusComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
||||
mSystemStatusComponents.back()->updateGrid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mHelpStyle.applyTheme(mTheme, "gamelist");
|
||||
if (mClockComponents.empty()) {
|
||||
// Apply a default clock if the theme does not contain any configuration for it.
|
||||
mClockComponents.emplace_back(std::make_unique<DateTimeComponent>());
|
||||
mClockComponents.back()->applyTheme(theme, "gamelist", "clock_default", ThemeFlags::ALL);
|
||||
mClockComponents.back()->update(1000);
|
||||
}
|
||||
|
||||
if (mSystemStatusComponents.empty()) {
|
||||
// Apply a default systemstatus if the theme does not contain any configuration for it.
|
||||
mSystemStatusComponents.emplace_back(std::make_unique<SystemStatusComponent>());
|
||||
mSystemStatusComponents.back()->applyTheme(theme, "gamelist", "systemstatus_default",
|
||||
ThemeFlags::ALL);
|
||||
mSystemStatusComponents.back()->updateGrid();
|
||||
}
|
||||
|
||||
if (mPrimary == nullptr) {
|
||||
|
@ -406,6 +444,17 @@ void GamelistView::update(int deltaTime)
|
|||
anim->advanceAnimation(0, deltaTime);
|
||||
}
|
||||
|
||||
if (mTriggerEvent) {
|
||||
mTriggerEvent = false;
|
||||
FileData* file {mPrimary->size() > 0 ? mPrimary->getSelected() : nullptr};
|
||||
if (file) {
|
||||
Scripting::fireEvent("game-select", file->getPath(),
|
||||
file->getSourceFileData()->metadata.get("name"),
|
||||
file->getSourceFileData()->getSystem()->getName(),
|
||||
file->getSourceFileData()->getSystem()->getFullName());
|
||||
}
|
||||
}
|
||||
|
||||
updateChildren(deltaTime);
|
||||
}
|
||||
|
||||
|
@ -512,6 +561,11 @@ void GamelistView::render(const glm::mat4& parentTrans)
|
|||
|
||||
std::vector<HelpPrompt> GamelistView::getHelpPrompts()
|
||||
{
|
||||
if (mHelpComponents.empty())
|
||||
mWindow->passHelpComponents(nullptr);
|
||||
else
|
||||
mWindow->passHelpComponents(&mHelpComponents);
|
||||
|
||||
std::vector<HelpPrompt> prompts;
|
||||
|
||||
if (Settings::getInstance()->getString("QuickSystemSelect") != "disabled") {
|
||||
|
@ -572,6 +626,7 @@ std::vector<HelpPrompt> GamelistView::getHelpPrompts()
|
|||
void GamelistView::updateView(const CursorState& state)
|
||||
{
|
||||
bool loadedTexture {false};
|
||||
mTriggerEvent = false;
|
||||
|
||||
if (mPrimary->isScrolling()) {
|
||||
onDemandTextureLoad();
|
||||
|
@ -584,8 +639,21 @@ void GamelistView::updateView(const CursorState& state)
|
|||
|
||||
// If the game data has already been rendered to the view, then skip it this time.
|
||||
// This also happens when fast-scrolling.
|
||||
if (file == mLastUpdated)
|
||||
if (file == mLastUpdated) {
|
||||
if (!mTriggeredEventFastScroll && state == CursorState::CURSOR_SCROLLING &&
|
||||
Settings::getInstance()->getBool("CustomEventScripts") &&
|
||||
Settings::getInstance()->getBool("CustomEventScriptsBrowsing")) {
|
||||
mTriggeredEventFastScroll = true;
|
||||
Scripting::fireEvent("game-select");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (Settings::getInstance()->getBool("CustomEventScripts") &&
|
||||
Settings::getInstance()->getBool("CustomEventScriptsBrowsing")) {
|
||||
mTriggerEvent = true;
|
||||
mTriggeredEventFastScroll = false;
|
||||
}
|
||||
|
||||
if (!loadedTexture)
|
||||
onDemandTextureLoad();
|
||||
|
|
|
@ -101,10 +101,15 @@ public:
|
|||
}
|
||||
void onThemeChanged(const std::shared_ptr<ThemeData>& theme);
|
||||
|
||||
void setHelpComponentsVisibility(const bool state) override
|
||||
{
|
||||
for (auto& helpComponent : mHelpComponents)
|
||||
helpComponent->setVisible(state);
|
||||
}
|
||||
|
||||
void update(int deltaTime) override;
|
||||
void render(const glm::mat4& parentTrans) override;
|
||||
|
||||
HelpStyle getHelpStyle() override { return mHelpStyle; }
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
|
||||
private:
|
||||
|
@ -112,8 +117,9 @@ private:
|
|||
void setGameImage(FileData* file, GuiComponent* comp);
|
||||
|
||||
Renderer* mRenderer;
|
||||
HelpStyle mHelpStyle;
|
||||
bool mStaticVideoAudio;
|
||||
bool mTriggerEvent;
|
||||
bool mTriggeredEventFastScroll;
|
||||
|
||||
std::shared_ptr<ThemeData> mTheme;
|
||||
std::vector<GuiComponent*> mThemeExtras;
|
||||
|
@ -130,6 +136,9 @@ private:
|
|||
std::vector<std::unique_ptr<ScrollableContainer>> mContainerComponents;
|
||||
std::vector<std::unique_ptr<TextComponent>> mContainerTextComponents;
|
||||
std::vector<std::unique_ptr<TextComponent>> mGamelistInfoComponents;
|
||||
std::vector<std::unique_ptr<HelpComponent>> mHelpComponents;
|
||||
std::vector<std::unique_ptr<DateTimeComponent>> mClockComponents;
|
||||
std::vector<std::unique_ptr<SystemStatusComponent>> mSystemStatusComponents;
|
||||
};
|
||||
|
||||
#endif // ES_APP_VIEWS_GAMELIST_VIEW_H
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "views/SystemView.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "Scripting.h"
|
||||
#include "Settings.h"
|
||||
#include "Sound.h"
|
||||
#include "UIModeController.h"
|
||||
|
@ -111,6 +112,7 @@ bool SystemView::input(InputConfig* config, Input input)
|
|||
if (config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_r &&
|
||||
SDL_GetModState() & KMOD_LCTRL && Settings::getInstance()->getBool("Debug")) {
|
||||
LOG(LogDebug) << "SystemView::input(): Reloading all";
|
||||
mWindow->clearHelpPromptsImageCache();
|
||||
TextureResource::manualUnloadAll();
|
||||
ViewController::getInstance()->reloadAll();
|
||||
return true;
|
||||
|
@ -211,7 +213,13 @@ void SystemView::onThemeChanged(const std::shared_ptr<ThemeData>& /*theme*/)
|
|||
|
||||
std::vector<HelpPrompt> SystemView::getHelpPrompts()
|
||||
{
|
||||
if (mSystemElements[mPrimary->getCursor()].helpComponents.empty())
|
||||
mWindow->passHelpComponents(nullptr);
|
||||
else
|
||||
mWindow->passHelpComponents(&mSystemElements[mPrimary->getCursor()].helpComponents);
|
||||
|
||||
std::vector<HelpPrompt> prompts;
|
||||
|
||||
if (mCarousel != nullptr) {
|
||||
if (mCarousel->getType() == CarouselComponent<SystemData*>::CarouselType::VERTICAL ||
|
||||
mCarousel->getType() == CarouselComponent<SystemData*>::CarouselType::VERTICAL_WHEEL)
|
||||
|
@ -239,6 +247,25 @@ std::vector<HelpPrompt> SystemView::getHelpPrompts()
|
|||
|
||||
void SystemView::onCursorChanged(const CursorState& state)
|
||||
{
|
||||
mWindow->passHelpComponents(nullptr);
|
||||
mWindow->passClockComponents(&mSystemElements[mPrimary->getCursor()].clockComponents);
|
||||
mWindow->passSystemStatusComponents(
|
||||
&mSystemElements[mPrimary->getCursor()].systemStatusComponents);
|
||||
|
||||
if (Settings::getInstance()->getBool("CustomEventScripts") &&
|
||||
Settings::getInstance()->getBool("CustomEventScriptsBrowsing")) {
|
||||
Scripting::fireEvent(
|
||||
"system-select", mSystemElements[mPrimary->getCursor()].system->getName(),
|
||||
mSystemElements[mPrimary->getCursor()].system->getFullName(),
|
||||
mSystemElements[mPrimary->getCursor()].system->getRootFolder()->getFullPath());
|
||||
}
|
||||
|
||||
for (auto& clock : mSystemElements[mPrimary->getCursor()].clockComponents)
|
||||
clock->update(1000);
|
||||
|
||||
for (auto& systemstatus : mSystemElements[mPrimary->getCursor()].systemStatusComponents)
|
||||
systemstatus->update(SystemStatus::updateTime);
|
||||
|
||||
// Reset horizontally scrolling text.
|
||||
for (auto& text : mSystemElements[mPrimary->getCursor()].gameCountComponents)
|
||||
text->resetComponent();
|
||||
|
@ -714,9 +741,42 @@ void SystemView::populate()
|
|||
elements.ratingComponents.back()->getOpacity());
|
||||
elements.children.emplace_back(elements.ratingComponents.back().get());
|
||||
}
|
||||
else if (element.second.type == "helpsystem") {
|
||||
elements.helpComponents.emplace_back(std::make_unique<HelpComponent>());
|
||||
elements.helpComponents.back()->applyTheme(theme, "system", element.first,
|
||||
ThemeFlags::ALL);
|
||||
}
|
||||
else if (element.second.type == "clock") {
|
||||
elements.clockComponents.emplace_back(std::make_unique<DateTimeComponent>());
|
||||
elements.clockComponents.back()->applyTheme(theme, "system", element.first,
|
||||
ThemeFlags::ALL);
|
||||
}
|
||||
else if (element.second.type == "systemstatus") {
|
||||
elements.systemStatusComponents.emplace_back(
|
||||
std::make_unique<SystemStatusComponent>());
|
||||
elements.systemStatusComponents.back()->applyTheme(
|
||||
theme, "system", element.first, ThemeFlags::ALL);
|
||||
elements.systemStatusComponents.back()->updateGrid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (elements.clockComponents.empty()) {
|
||||
// Apply a default clock if the theme does not contain any configuration for it.
|
||||
elements.clockComponents.emplace_back(std::make_unique<DateTimeComponent>());
|
||||
elements.clockComponents.back()->applyTheme(theme, "system", "clock_default",
|
||||
ThemeFlags::ALL);
|
||||
elements.clockComponents.back()->update(1000);
|
||||
}
|
||||
|
||||
if (elements.systemStatusComponents.empty()) {
|
||||
// Apply a default systemstatus if the theme does not contain any configuration for it.
|
||||
elements.systemStatusComponents.emplace_back(std::make_unique<SystemStatusComponent>());
|
||||
elements.systemStatusComponents.back()->applyTheme(
|
||||
theme, "system", "systemstatus_default", ThemeFlags::ALL);
|
||||
elements.systemStatusComponents.back()->updateGrid();
|
||||
}
|
||||
|
||||
std::stable_sort(
|
||||
elements.children.begin(), elements.children.end(),
|
||||
[](GuiComponent* a, GuiComponent* b) { return b->getZIndex() > a->getZIndex(); });
|
||||
|
@ -737,7 +797,6 @@ void SystemView::populate()
|
|||
return b->getZIndex() > a->getZIndex();
|
||||
});
|
||||
mSystemElements.emplace_back(std::move(elements));
|
||||
mSystemElements.back().helpStyle.applyTheme(theme, "system");
|
||||
|
||||
if (mPrimary == nullptr) {
|
||||
mCarousel = std::make_unique<CarouselComponent<SystemData*>>();
|
||||
|
@ -877,6 +936,15 @@ void SystemView::populate()
|
|||
}
|
||||
}
|
||||
|
||||
if (mSystemElements[mPrimary->getCursor()].helpComponents.empty())
|
||||
mWindow->passHelpComponents(nullptr);
|
||||
else
|
||||
mWindow->passHelpComponents(&mSystemElements[mPrimary->getCursor()].helpComponents);
|
||||
|
||||
mWindow->passClockComponents(&mSystemElements[mPrimary->getCursor()].clockComponents);
|
||||
mWindow->passSystemStatusComponents(
|
||||
&mSystemElements[mPrimary->getCursor()].systemStatusComponents);
|
||||
|
||||
mFadeTransitions = (static_cast<ViewTransitionAnimation>(Settings::getInstance()->getInt(
|
||||
"TransitionsSystemToSystem")) == ViewTransitionAnimation::FADE);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "components/LottieAnimComponent.h"
|
||||
#include "components/RatingComponent.h"
|
||||
#include "components/ScrollableContainer.h"
|
||||
#include "components/SystemStatusComponent.h"
|
||||
#include "components/TextComponent.h"
|
||||
#include "components/VideoFFmpegComponent.h"
|
||||
#include "components/primary/CarouselComponent.h"
|
||||
|
@ -103,8 +104,13 @@ public:
|
|||
|
||||
void onThemeChanged(const std::shared_ptr<ThemeData>& theme);
|
||||
|
||||
void setHelpComponentsVisibility(const bool state) override
|
||||
{
|
||||
for (auto& helpComponent : mSystemElements[mPrimary->getCursor()].helpComponents)
|
||||
helpComponent->setVisible(state);
|
||||
}
|
||||
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override { return mSystemElements[mPrimary->getCursor()].helpStyle; }
|
||||
|
||||
protected:
|
||||
void onCursorChanged(const CursorState& state);
|
||||
|
@ -117,7 +123,6 @@ private:
|
|||
|
||||
struct SystemViewElements {
|
||||
SystemData* system;
|
||||
HelpStyle helpStyle;
|
||||
std::string name;
|
||||
std::string fullName;
|
||||
std::vector<std::unique_ptr<GameSelectorComponent>> gameSelectors;
|
||||
|
@ -133,6 +138,9 @@ private:
|
|||
std::vector<std::unique_ptr<TextComponent>> textComponents;
|
||||
std::vector<std::unique_ptr<DateTimeComponent>> dateTimeComponents;
|
||||
std::vector<std::unique_ptr<RatingComponent>> ratingComponents;
|
||||
std::vector<std::unique_ptr<HelpComponent>> helpComponents;
|
||||
std::vector<std::unique_ptr<DateTimeComponent>> clockComponents;
|
||||
std::vector<std::unique_ptr<SystemStatusComponent>> systemStatusComponents;
|
||||
};
|
||||
|
||||
Renderer* mRenderer;
|
||||
|
|
|
@ -72,7 +72,7 @@ void ViewController::setMenuColors()
|
|||
if (Settings::getInstance()->getString("MenuColorScheme") == "light") {
|
||||
mMenuColorFrame = 0xEFEFEFFF;
|
||||
mMenuColorFrameLaunchScreen = 0xDFDFDFFF;
|
||||
mMenuColorFrameBusyComponent = 0xFFFFFFFF;
|
||||
mMenuColorFrameBusyComponent = 0xF5F5F5FF;
|
||||
mMenuColorPanelDimmed = 0x00000009;
|
||||
|
||||
mMenuColorTitle = 0x555555FF;
|
||||
|
@ -109,7 +109,7 @@ void ViewController::setMenuColors()
|
|||
else if (Settings::getInstance()->getString("MenuColorScheme") == "darkred") {
|
||||
mMenuColorFrame = 0x191919FF;
|
||||
mMenuColorFrameLaunchScreen = 0x121212FF;
|
||||
mMenuColorFrameBusyComponent = 0x090909FF;
|
||||
mMenuColorFrameBusyComponent = 0x000000FF;
|
||||
mMenuColorPanelDimmed = 0x00000024;
|
||||
|
||||
mMenuColorTitle = 0x909090FF;
|
||||
|
@ -146,7 +146,7 @@ void ViewController::setMenuColors()
|
|||
else {
|
||||
mMenuColorFrame = 0x191919FF;
|
||||
mMenuColorFrameLaunchScreen = 0x121212FF;
|
||||
mMenuColorFrameBusyComponent = 0x090909FF;
|
||||
mMenuColorFrameBusyComponent = 0x000000FF;
|
||||
mMenuColorPanelDimmed = 0x00000024;
|
||||
|
||||
mMenuColorTitle = 0x909090FF;
|
||||
|
@ -199,8 +199,7 @@ void ViewController::legacyAppDataDialog()
|
|||
#endif
|
||||
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
HelpStyle(), upgradeMessage.c_str(), _("OK"), [] {}, "", nullptr, "", nullptr, nullptr,
|
||||
true, true,
|
||||
upgradeMessage.c_str(), _("OK"), [] {}, "", nullptr, "", nullptr, nullptr, true, true,
|
||||
(mRenderer->getIsVerticalOrientation() ?
|
||||
0.85f :
|
||||
0.55f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
||||
|
@ -213,7 +212,7 @@ void ViewController::migratedAppDataFilesDialog()
|
|||
"THE CONFIGURATION"};
|
||||
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
HelpStyle(), message.c_str(), "QUIT",
|
||||
message.c_str(), "QUIT",
|
||||
[] {
|
||||
SDL_Event quit {};
|
||||
quit.type = SDL_QUIT;
|
||||
|
@ -235,8 +234,7 @@ void ViewController::unsafeUpgradeDialog()
|
|||
"README.TXT FILE THAT CAN BE FOUND IN THE ES-DE DIRECTORY.")};
|
||||
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
HelpStyle(), upgradeMessage.c_str(), _("OK"), [] {}, "", nullptr, "", nullptr, nullptr,
|
||||
true, true,
|
||||
upgradeMessage.c_str(), _("OK"), [] {}, "", nullptr, "", nullptr, nullptr, true, true,
|
||||
(mRenderer->getIsVerticalOrientation() ?
|
||||
0.85f :
|
||||
0.55f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
||||
|
@ -252,7 +250,7 @@ void ViewController::invalidSystemsFileDialog()
|
|||
"LOG FILE es_log.txt FOR ADDITIONAL INFO")};
|
||||
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
HelpStyle(), errorMessage.c_str(), _("QUIT"),
|
||||
errorMessage.c_str(), _("QUIT"),
|
||||
[] {
|
||||
SDL_Event quit {};
|
||||
quit.type = SDL_QUIT;
|
||||
|
@ -269,7 +267,7 @@ void ViewController::noGamesDialog()
|
|||
#if defined(RETRODECK)
|
||||
mNoGamesErrorMessage = _("NO GAME WERE FOUND. PLEASE PLACE YOUR GAMES IN "
|
||||
"THE RETRODECK ROM DIRECTORY LOCATED IN:\n");
|
||||
#elif defined(__ANDROID__)
|
||||
#elif defined(__ANDROID__) || defined(__IOS__)
|
||||
mNoGamesErrorMessage = _("NO GAME FILES WERE FOUND, PLEASE PLACE YOUR GAMES IN "
|
||||
"THE CONFIGURED ROM DIRECTORY. OPTIONALLY THE ROM "
|
||||
"DIRECTORY STRUCTURE CAN BE GENERATED WHICH WILL "
|
||||
|
@ -306,12 +304,12 @@ void ViewController::noGamesDialog()
|
|||
);
|
||||
#else
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
mNoGamesMessageBox = new GuiMsgBox(
|
||||
HelpStyle(), mNoGamesErrorMessage + mRomDirectory,
|
||||
mNoGamesErrorMessage + mRomDirectory,
|
||||
#else
|
||||
mNoGamesMessageBox = new GuiMsgBox(
|
||||
HelpStyle(), mNoGamesErrorMessage + mRomDirectory, _("CHANGE ROM DIRECTORY"),
|
||||
mNoGamesErrorMessage + mRomDirectory, _("CHANGE ROM DIRECTORY"),
|
||||
[this] {
|
||||
std::string currentROMDirectory;
|
||||
#if defined(_WIN64)
|
||||
|
@ -321,7 +319,7 @@ void ViewController::noGamesDialog()
|
|||
#endif
|
||||
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
||||
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
||||
HelpStyle(), 0.0f, _("ENTER ROM DIRECTORY PATH"), currentROMDirectory,
|
||||
0.0f, _("ENTER ROM DIRECTORY PATH"), currentROMDirectory,
|
||||
[this, currentROMDirectory](const std::string& newROMDirectory) {
|
||||
if (currentROMDirectory != newROMDirectory) {
|
||||
Settings::getInstance()->setString(
|
||||
|
@ -335,7 +333,6 @@ void ViewController::noGamesDialog()
|
|||
#endif
|
||||
mNoGamesMessageBox->changeText(mNoGamesErrorMessage + mRomDirectory);
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
HelpStyle(),
|
||||
_("ROM DIRECTORY SETTING SAVED, RESTART "
|
||||
"THE APPLICATION TO RESCAN THE SYSTEMS"),
|
||||
_("OK"), nullptr, "", nullptr, "", nullptr, nullptr, true, true,
|
||||
|
@ -350,7 +347,7 @@ void ViewController::noGamesDialog()
|
|||
}
|
||||
else {
|
||||
mWindow->pushGui(new GuiTextEditPopup(
|
||||
HelpStyle(), _("ENTER ROM DIRECTORY PATH"), currentROMDirectory,
|
||||
_("ENTER ROM DIRECTORY PATH"), currentROMDirectory,
|
||||
[this](const std::string& newROMDirectory) {
|
||||
Settings::getInstance()->setString("ROMDirectory",
|
||||
Utils::String::trim(newROMDirectory));
|
||||
|
@ -363,7 +360,6 @@ void ViewController::noGamesDialog()
|
|||
#endif
|
||||
mNoGamesMessageBox->changeText(mNoGamesErrorMessage + mRomDirectory);
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
HelpStyle(),
|
||||
_("ROM DIRECTORY SETTING SAVED, RESTART "
|
||||
"THE APPLICATION TO RESCAN THE SYSTEMS"),
|
||||
_("OK"), nullptr, "", nullptr, "", nullptr, nullptr, true, true,
|
||||
|
@ -380,7 +376,6 @@ void ViewController::noGamesDialog()
|
|||
_("CREATE DIRECTORIES"),
|
||||
[this] {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
HelpStyle(),
|
||||
_("THIS WILL CREATE DIRECTORIES FOR ALL THE "
|
||||
"GAME SYSTEMS DEFINED IN es_systems.xml\n\n"
|
||||
"THIS MAY CREATE A LOT OF FOLDERS SO IT'S "
|
||||
|
@ -389,7 +384,6 @@ void ViewController::noGamesDialog()
|
|||
[this] {
|
||||
if (!SystemData::createSystemDirectories()) {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
HelpStyle(),
|
||||
_("THE SYSTEM DIRECTORIES WERE SUCCESSFULLY "
|
||||
"GENERATED, EXIT THE APPLICATION AND PLACE "
|
||||
"YOUR GAMES IN THE NEW FOLDERS"),
|
||||
|
@ -400,7 +394,6 @@ void ViewController::noGamesDialog()
|
|||
}
|
||||
else {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
HelpStyle(),
|
||||
_("ERROR CREATING THE SYSTEM DIRECTORIES, "
|
||||
"PERMISSION PROBLEMS OR DISK FULL?\n\n"
|
||||
"SEE THE LOG FILE FOR MORE DETAILS"),
|
||||
|
@ -421,7 +414,7 @@ void ViewController::noGamesDialog()
|
|||
quit.type = SDL_QUIT;
|
||||
SDL_PushEvent(&quit);
|
||||
},
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
"", nullptr, nullptr, true, false,
|
||||
(mRenderer->getIsVerticalOrientation() ?
|
||||
0.90f :
|
||||
|
@ -440,8 +433,7 @@ void ViewController::noGamesDialog()
|
|||
void ViewController::invalidAlternativeEmulatorDialog()
|
||||
{
|
||||
cancelViewTransitions();
|
||||
mWindow->pushGui(new GuiMsgBox(getHelpStyle(),
|
||||
_("AT LEAST ONE OF YOUR SYSTEMS HAS AN "
|
||||
mWindow->pushGui(new GuiMsgBox(_("AT LEAST ONE OF YOUR SYSTEMS HAS AN "
|
||||
"INVALID ALTERNATIVE EMULATOR CONFIGURED "
|
||||
"WITH NO MATCHING ENTRY IN THE SYSTEMS "
|
||||
"CONFIGURATION FILE, PLEASE REVIEW YOUR "
|
||||
|
@ -469,7 +461,7 @@ void ViewController::updateAvailableDialog()
|
|||
<< "\"";
|
||||
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(), results, _("UPDATE"),
|
||||
results, _("UPDATE"),
|
||||
[this, package] {
|
||||
mWindow->pushGui(new GuiApplicationUpdater());
|
||||
|
||||
|
@ -499,8 +491,8 @@ void ViewController::updateAvailableDialog()
|
|||
"THE UPGRADE.");
|
||||
}
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
getHelpStyle(), upgradeMessage.c_str(), _("OK"), [] {}, "", nullptr, "",
|
||||
nullptr, nullptr, true, true,
|
||||
upgradeMessage.c_str(), _("OK"), [] {}, "", nullptr, "", nullptr, nullptr,
|
||||
true, true,
|
||||
(mRenderer->getIsVerticalOrientation() ?
|
||||
0.85f :
|
||||
0.535f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
||||
|
@ -517,8 +509,8 @@ void ViewController::updateAvailableDialog()
|
|||
0.45f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
||||
}
|
||||
else {
|
||||
mWindow->pushGui(new GuiMsgBox(getHelpStyle(), results, _("OK"), nullptr, "", nullptr, "",
|
||||
nullptr, nullptr, true, true,
|
||||
mWindow->pushGui(new GuiMsgBox(results, _("OK"), nullptr, "", nullptr, "", nullptr, nullptr,
|
||||
true, true,
|
||||
(mRenderer->getIsVerticalOrientation() ?
|
||||
0.70f :
|
||||
0.45f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
||||
|
@ -1048,11 +1040,10 @@ void ViewController::launch(FileData* game)
|
|||
mWindow->stopInfoPopup(); // Make sure we disable any existing info popup.
|
||||
|
||||
int duration {0};
|
||||
std::string durationString {Settings::getInstance()->getString("LaunchScreenDuration")};
|
||||
const std::string durationString {Settings::getInstance()->getString("LaunchScreenDuration")};
|
||||
|
||||
if (durationString == "disabled") {
|
||||
// If the game launch screen has been set as disabled, show a simple info popup
|
||||
// notification instead.
|
||||
if (durationString == "popup") {
|
||||
// Show a simple info popup notification instead of the launch screen.
|
||||
mWindow->queueInfoPopup(
|
||||
Utils::String::format(_("LAUNCHING GAME '%s'"),
|
||||
Utils::String::toUpper(game->metadata.get("name")).c_str()),
|
||||
|
@ -1065,21 +1056,35 @@ void ViewController::launch(FileData* game)
|
|||
else if (durationString == "long") {
|
||||
duration = 4500;
|
||||
}
|
||||
else if (durationString == "disabled") {
|
||||
duration = 0;
|
||||
}
|
||||
else {
|
||||
// Normal duration.
|
||||
duration = 3000;
|
||||
}
|
||||
|
||||
if (durationString != "disabled")
|
||||
if (durationString != "disabled" && durationString != "popup")
|
||||
mWindow->displayLaunchScreen(game->getSourceFileData());
|
||||
|
||||
#if defined(__ANDROID__) || defined(DEINIT_ON_LAUNCH)
|
||||
if (durationString != "disabled")
|
||||
NavigationSounds::getInstance().playThemeNavigationSound(LAUNCHSOUND);
|
||||
#else
|
||||
NavigationSounds::getInstance().playThemeNavigationSound(LAUNCHSOUND);
|
||||
#endif
|
||||
|
||||
// This is just a dummy animation in order for the launch screen or notification popup
|
||||
// to be displayed briefly, and for the navigation sound playing to be able to complete.
|
||||
// During this time period, all user input is blocked.
|
||||
setAnimation(new LambdaAnimation([](float t) {}, duration), 0, [this, game] {
|
||||
game->launchGame();
|
||||
#if defined(__ANDROID__)
|
||||
AudioManager::getInstance().stop();
|
||||
#else
|
||||
if (!Settings::getInstance()->getBool("RunInBackground"))
|
||||
AudioManager::getInstance().stop();
|
||||
#endif
|
||||
// If the launch screen is disabled then this will do nothing.
|
||||
mWindow->closeLaunchScreen();
|
||||
onFileChanged(game, true);
|
||||
|
@ -1248,6 +1253,7 @@ bool ViewController::input(InputConfig* config, Input input)
|
|||
mWindow->setAllowTextScrolling(true);
|
||||
mWindow->setAllowFileAnimation(true);
|
||||
mWindow->setLaunchedGame(false);
|
||||
resetViewVideosTimer();
|
||||
// Filter out the "a" button so the game is not restarted if there was such a button press
|
||||
// queued when leaving the game.
|
||||
if (config->isMappedTo("a", input) && input.value != 0)
|
||||
|
@ -1266,6 +1272,9 @@ bool ViewController::input(InputConfig* config, Input input)
|
|||
if (!(UIModeController::getInstance()->isUIModeKid() &&
|
||||
!Settings::getInstance()->getBool("EnableMenuKidMode")) &&
|
||||
config->isMappedTo("start", input) && input.value != 0 && mCurrentView != nullptr) {
|
||||
|
||||
setHelpComponentsVisibility(false);
|
||||
|
||||
// If we don't stop the scrolling here, it will continue to
|
||||
// run after closing the menu.
|
||||
if (mSystemListView->isScrolling())
|
||||
|
@ -1679,6 +1688,9 @@ void ViewController::rescanROMDirectory()
|
|||
// It's possible that there are no longer any games.
|
||||
mWindow->setBlockInput(false);
|
||||
mWindow->invalidateCachedBackground();
|
||||
mWindow->passHelpComponents(nullptr);
|
||||
mWindow->passClockComponents(nullptr);
|
||||
mWindow->passSystemStatusComponents(nullptr);
|
||||
noGamesDialog();
|
||||
}
|
||||
else {
|
||||
|
@ -1706,19 +1718,3 @@ std::vector<HelpPrompt> ViewController::getHelpPrompts()
|
|||
prompts.push_back(HelpPrompt("start", _("menu")));
|
||||
return prompts;
|
||||
}
|
||||
|
||||
HelpStyle ViewController::getHelpStyle()
|
||||
{
|
||||
if (!mCurrentView)
|
||||
return GuiComponent::getHelpStyle();
|
||||
|
||||
return mCurrentView->getHelpStyle();
|
||||
}
|
||||
|
||||
HelpStyle ViewController::getViewHelpStyle()
|
||||
{
|
||||
if (mState.viewing == ViewMode::GAMELIST)
|
||||
return getGamelistView(mState.getSystem())->getHelpStyle();
|
||||
else
|
||||
return getSystemListView()->getHelpStyle();
|
||||
}
|
||||
|
|
|
@ -89,7 +89,6 @@ public:
|
|||
void stopViewVideos() override { mCurrentView->stopViewVideos(); }
|
||||
void pauseViewVideos() override { mCurrentView->pauseViewVideos(); }
|
||||
void muteViewVideos() override { mCurrentView->muteViewVideos(); }
|
||||
// Needed on Android to reset the static image delay timer on activity resume.
|
||||
void resetViewVideosTimer() override
|
||||
{
|
||||
if (mCurrentView != nullptr)
|
||||
|
@ -132,8 +131,12 @@ public:
|
|||
const State& getState() const { return mState; }
|
||||
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override;
|
||||
HelpStyle getViewHelpStyle();
|
||||
|
||||
void setHelpComponentsVisibility(const bool state) override
|
||||
{
|
||||
if (mCurrentView != nullptr)
|
||||
mCurrentView->setHelpComponentsVisibility(state);
|
||||
}
|
||||
|
||||
std::shared_ptr<GamelistView> getGamelistView(SystemData* system);
|
||||
std::shared_ptr<SystemView> getSystemListView();
|
||||
|
|
|
@ -14,7 +14,6 @@ set(CORE_HEADERS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioManager.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/CECInput.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/GuiComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/HelpStyle.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/HttpReq.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/ImageIO.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/InputConfig.h
|
||||
|
@ -23,6 +22,7 @@ set(CORE_HEADERS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/MameNames.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Settings.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Sound.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemStatus.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeData.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.h
|
||||
|
||||
|
@ -40,6 +40,7 @@ set(CORE_HEADERS
|
|||
|
||||
# Secondary GUI components
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimatedImageComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/BackgroundComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/BadgeComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/BusyComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ButtonComponent.h
|
||||
|
@ -62,6 +63,7 @@ set(CORE_HEADERS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ScrollIndicatorComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SliderComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SystemStatusComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextEditComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoComponent.h
|
||||
|
@ -101,7 +103,6 @@ set(CORE_SOURCES
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioManager.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/CECInput.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/GuiComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/HelpStyle.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/HttpReq.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/ImageIO.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/InputConfig.cpp
|
||||
|
@ -111,6 +112,7 @@ set(CORE_SOURCES
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/Scripting.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Settings.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Sound.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemStatus.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeData.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.cpp
|
||||
|
||||
|
@ -119,6 +121,7 @@ set(CORE_SOURCES
|
|||
|
||||
# Secondary GUI components
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimatedImageComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/BackgroundComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/BadgeComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/BusyComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ButtonComponent.cpp
|
||||
|
@ -137,6 +140,7 @@ set(CORE_SOURCES
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ScrollableContainer.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SliderComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SystemStatusComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextEditComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoComponent.cpp
|
||||
|
@ -179,6 +183,17 @@ if(ANDROID)
|
|||
set(CORE_SOURCES ${CORE_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/PlatformUtilAndroid.cpp)
|
||||
endif()
|
||||
|
||||
if(APPLE AND NOT IOS)
|
||||
set(CORE_HEADERS ${CORE_HEADERS} ${CMAKE_CURRENT_SOURCE_DIR}/src/BluetoothStatusApple.m)
|
||||
endif()
|
||||
|
||||
if(IOS)
|
||||
set(CORE_HEADERS ${CORE_HEADERS} ${CMAKE_CURRENT_SOURCE_DIR}/src/InputOverlay.h)
|
||||
set(CORE_HEADERS ${CORE_HEADERS} ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/PlatformUtilIOS.h)
|
||||
set(CORE_HEADERS ${CORE_HEADERS} ${CMAKE_CURRENT_SOURCE_DIR}/src/InputOverlay.cpp)
|
||||
set(CORE_SOURCES ${CORE_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/PlatformUtilIOS.cpp)
|
||||
endif()
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
# Miscellaneous configuration.
|
||||
|
||||
|
|
|
@ -11,15 +11,15 @@
|
|||
// Do this version number update as the very last commit for the new release version.
|
||||
// clang-format off
|
||||
#define PROGRAM_VERSION_MAJOR 3
|
||||
#define PROGRAM_VERSION_MINOR 1
|
||||
#define PROGRAM_VERSION_MAINTENANCE 1
|
||||
#define PROGRAM_RELEASE_NUMBER 46
|
||||
#define PROGRAM_VERSION_MINOR 2
|
||||
#define PROGRAM_VERSION_MAINTENANCE 0
|
||||
#define PROGRAM_RELEASE_NUMBER 48
|
||||
// clang-format on
|
||||
#define PROGRAM_VERSION_STRING "3.1.1"
|
||||
#define PROGRAM_VERSION_STRING "3.2.0"
|
||||
|
||||
#define PROGRAM_BUILT_STRING __DATE__ " - " __TIME__
|
||||
|
||||
#define RESOURCE_VERSION_STRING "3,1,1\0"
|
||||
#define RESOURCE_VERSION_STRING "3,2,0\0"
|
||||
#define RESOURCE_VERSION PROGRAM_VERSION_MAJOR, PROGRAM_VERSION_MINOR, PROGRAM_VERSION_MAINTENANCE
|
||||
|
||||
#endif // ES_CORE_APPLICATION_VERSION_H
|
||||
|
|
18
es-core/src/BluetoothStatusApple.h
Normal file
18
es-core/src/BluetoothStatusApple.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// ES-DE Frontend
|
||||
// BluetoothStatusApple.h
|
||||
//
|
||||
// Gets the Bluetooth adapter status on macOS.
|
||||
//
|
||||
|
||||
#ifndef ES_CORE_BLUETOOTH_STATUS_APPLE_H
|
||||
#define ES_CORE_BLUETOOTH_STATUS_APPLE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
int getBluetoothStatus();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ES_CORE_BLUETOOTH_STATUS_APPLE_H
|
21
es-core/src/BluetoothStatusApple.m
Normal file
21
es-core/src/BluetoothStatusApple.m
Normal file
|
@ -0,0 +1,21 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// ES-DE Frontend
|
||||
// BluetoothStatusApple.m
|
||||
//
|
||||
// Gets the Bluetooth adapter status on macOS.
|
||||
//
|
||||
|
||||
#import "BluetoothStatusApple.h"
|
||||
|
||||
#import <IOBluetooth/IOBluetooth.h>
|
||||
|
||||
int getBluetoothStatus()
|
||||
{
|
||||
IOBluetoothHostController* hciController = [IOBluetoothHostController defaultController];
|
||||
|
||||
if (hciController != NULL && hciController.powerState)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
|
@ -31,6 +31,7 @@ GuiComponent::GuiComponent()
|
|||
, mRotationOrigin {0.5f, 0.5f}
|
||||
, mSize {0.0f, 0.0f}
|
||||
, mStationary {Stationary::NEVER}
|
||||
, mComponentScope {ComponentScope::SHARED}
|
||||
, mRenderDuringTransitions {true}
|
||||
, mBrightness {0.0f}
|
||||
, mOpacity {1.0f}
|
||||
|
@ -420,7 +421,7 @@ void GuiComponent::updateHelpPrompts()
|
|||
std::vector<HelpPrompt> prompts {getHelpPrompts()};
|
||||
|
||||
if (mWindow->peekGui() == this)
|
||||
mWindow->setHelpPrompts(prompts, getHelpStyle());
|
||||
mWindow->setHelpPrompts(prompts);
|
||||
}
|
||||
|
||||
void GuiComponent::updateSelf(int deltaTime)
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
#define ES_CORE_GUI_COMPONENT_H
|
||||
|
||||
#include "HelpPrompt.h"
|
||||
#include "HelpStyle.h"
|
||||
#include "InputConfig.h"
|
||||
#include "animations/AnimationController.h"
|
||||
#include "utils/MathUtil.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
@ -65,6 +65,13 @@ enum class Stationary {
|
|||
BETWEEN_VIEWS
|
||||
};
|
||||
|
||||
enum class ComponentScope {
|
||||
SHARED,
|
||||
VIEW,
|
||||
MENU,
|
||||
NONE
|
||||
};
|
||||
|
||||
class GuiComponent
|
||||
{
|
||||
public:
|
||||
|
@ -118,6 +125,7 @@ public:
|
|||
void setRotationOrigin(glm::vec2 origin) { setRotationOrigin(origin.x, origin.y); }
|
||||
|
||||
const Stationary getStationary() const { return mStationary; }
|
||||
const ComponentScope getComponentScope() const { return mComponentScope; }
|
||||
const bool getRenderDuringTransitions() const { return mRenderDuringTransitions; }
|
||||
|
||||
virtual glm::vec2 getSize() const { return mSize; }
|
||||
|
@ -321,8 +329,8 @@ public:
|
|||
// Used by TextComponent.
|
||||
virtual void setHorizontalScrolling(bool state) {}
|
||||
|
||||
// Default implementation just handles <pos> and <size> tags as normalized float pairs.
|
||||
// You probably want to keep this behavior for any derived classes as well as add your own.
|
||||
// Applies basic theme configuration, element-specific configuration is applied by
|
||||
// each component's applyTheme() function.
|
||||
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||
const std::string& view,
|
||||
const std::string& element,
|
||||
|
@ -334,12 +342,12 @@ public:
|
|||
// Called whenever help prompts change.
|
||||
void updateHelpPrompts();
|
||||
|
||||
virtual HelpStyle getHelpStyle() { return HelpStyle(); }
|
||||
virtual void setHelpComponentsVisibility(const bool state) {};
|
||||
|
||||
// Returns true if the component is busy doing background processing (e.g. HTTP downloads).
|
||||
const bool isProcessing() const { return mIsProcessing; }
|
||||
|
||||
const static unsigned char MAX_ANIMATIONS = 4;
|
||||
const static unsigned char MAX_ANIMATIONS {4};
|
||||
|
||||
protected:
|
||||
void updateSelf(int deltaTime); // Updates animations.
|
||||
|
@ -367,7 +375,7 @@ protected:
|
|||
// Default values are for the "light" color scheme.
|
||||
static inline unsigned int mMenuColorFrame {0xEFEFEFFF};
|
||||
static inline unsigned int mMenuColorFrameLaunchScreen {0xDFDFDFFF};
|
||||
static inline unsigned int mMenuColorFrameBusyComponent {0xFFFFFFFF};
|
||||
static inline unsigned int mMenuColorFrameBusyComponent {0xF5F5F5FF};
|
||||
static inline unsigned int mMenuColorPanelDimmed {0x00000009};
|
||||
|
||||
static inline unsigned int mMenuColorTitle {0x555555FF};
|
||||
|
@ -406,6 +414,7 @@ protected:
|
|||
glm::vec2 mRotationOrigin;
|
||||
glm::vec2 mSize;
|
||||
Stationary mStationary;
|
||||
ComponentScope mComponentScope;
|
||||
bool mRenderDuringTransitions;
|
||||
|
||||
float mBrightness;
|
||||
|
|
|
@ -1,210 +0,0 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// ES-DE Frontend
|
||||
// HelpStyle.cpp
|
||||
//
|
||||
// Style (colors, position, icons etc.) for the help system.
|
||||
//
|
||||
|
||||
#include "HelpStyle.h"
|
||||
|
||||
#include "resources/Font.h"
|
||||
|
||||
#define PREFIX "button_"
|
||||
|
||||
HelpStyle::HelpStyle()
|
||||
: position {Renderer::getScreenWidth() * 0.012f,
|
||||
Renderer::getScreenHeight() *
|
||||
(Renderer::getIsVerticalOrientation() ? 0.975f : 0.9515f)}
|
||||
, positionDimmed {position}
|
||||
, origin {glm::vec2 {0.0f, 0.0f}}
|
||||
, originDimmed {origin}
|
||||
, textColor {0x777777FF}
|
||||
, textColorDimmed {0x777777FF}
|
||||
, iconColor {0x777777FF}
|
||||
, iconColorDimmed {0x777777FF}
|
||||
, font {Renderer::getIsVerticalOrientation() ? Font::get(0.025f * Renderer::getScreenWidth()) :
|
||||
Font::get(FONT_SIZE_SMALL)}
|
||||
, fontDimmed {Renderer::getIsVerticalOrientation() ?
|
||||
Font::get(0.025f * Renderer::getScreenWidth()) :
|
||||
Font::get(FONT_SIZE_SMALL)}
|
||||
, entrySpacing {0.00833f}
|
||||
, entrySpacingDimmed {entrySpacing}
|
||||
, iconTextSpacing {0.00416f}
|
||||
, iconTextSpacingDimmed {iconTextSpacing}
|
||||
, opacity {1.0f}
|
||||
, opacityDimmed {opacity}
|
||||
, letterCase {"uppercase"}
|
||||
{
|
||||
}
|
||||
|
||||
void HelpStyle::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view)
|
||||
{
|
||||
auto elem = theme->getElement(view, "helpsystem_help", "helpsystem");
|
||||
if (!elem)
|
||||
return;
|
||||
|
||||
if (elem->has("pos"))
|
||||
position = elem->get<glm::vec2>("pos") *
|
||||
glm::vec2 {Renderer::getScreenWidth(), Renderer::getScreenHeight()};
|
||||
|
||||
if (elem->has("posDimmed"))
|
||||
positionDimmed = elem->get<glm::vec2>("posDimmed") *
|
||||
glm::vec2 {Renderer::getScreenWidth(), Renderer::getScreenHeight()};
|
||||
else
|
||||
positionDimmed = position;
|
||||
|
||||
if (elem->has("origin"))
|
||||
origin = elem->get<glm::vec2>("origin");
|
||||
|
||||
if (elem->has("originDimmed"))
|
||||
originDimmed = elem->get<glm::vec2>("originDimmed");
|
||||
else
|
||||
originDimmed = origin;
|
||||
|
||||
if (elem->has("textColor"))
|
||||
textColor = elem->get<unsigned int>("textColor");
|
||||
|
||||
if (elem->has("textColorDimmed"))
|
||||
textColorDimmed = elem->get<unsigned int>("textColorDimmed");
|
||||
else
|
||||
textColorDimmed = textColor;
|
||||
|
||||
if (elem->has("iconColor"))
|
||||
iconColor = elem->get<unsigned int>("iconColor");
|
||||
|
||||
if (elem->has("iconColorDimmed"))
|
||||
iconColorDimmed = elem->get<unsigned int>("iconColorDimmed");
|
||||
else
|
||||
iconColorDimmed = iconColor;
|
||||
|
||||
if (elem->has("fontPath") || elem->has("fontSize")) {
|
||||
font = Font::getFromTheme(elem, ThemeFlags::ALL, font);
|
||||
if (!elem->has("fontSizeDimmed"))
|
||||
fontDimmed = Font::getFromTheme(elem, ThemeFlags::ALL, font);
|
||||
}
|
||||
|
||||
if (elem->has("fontSizeDimmed"))
|
||||
fontDimmed = Font::getFromTheme(elem, ThemeFlags::ALL, font, 0.0f, 1.0f, true);
|
||||
|
||||
if (elem->has("entrySpacing"))
|
||||
entrySpacing = glm::clamp(elem->get<float>("entrySpacing"), 0.0f, 0.04f);
|
||||
|
||||
if (elem->has("entrySpacingDimmed"))
|
||||
entrySpacingDimmed = glm::clamp(elem->get<float>("entrySpacingDimmed"), 0.0f, 0.04f);
|
||||
else
|
||||
entrySpacingDimmed = entrySpacing;
|
||||
|
||||
if (elem->has("iconTextSpacing"))
|
||||
iconTextSpacing = glm::clamp(elem->get<float>("iconTextSpacing"), 0.0f, 0.04f);
|
||||
|
||||
if (elem->has("iconTextSpacingDimmed"))
|
||||
iconTextSpacingDimmed = glm::clamp(elem->get<float>("iconTextSpacingDimmed"), 0.0f, 0.04f);
|
||||
else
|
||||
iconTextSpacingDimmed = iconTextSpacing;
|
||||
|
||||
if (elem->has("letterCase"))
|
||||
letterCase = elem->get<std::string>("letterCase");
|
||||
|
||||
if (elem->has("opacity"))
|
||||
opacity = glm::clamp(elem->get<float>("opacity"), 0.2f, 1.0f);
|
||||
|
||||
if (elem->has("opacityDimmed"))
|
||||
opacityDimmed = glm::clamp(elem->get<float>("opacityDimmed"), 0.2f, 1.0f);
|
||||
else
|
||||
opacityDimmed = opacity;
|
||||
|
||||
// Load custom button icons.
|
||||
// The names may look a bit strange when combined with the PREFIX string "button_" but it's
|
||||
// because ThemeData adds this prefix to avoid name collisions when using XML attributes.
|
||||
|
||||
// General.
|
||||
if (elem->has(PREFIX "dpad_updown"))
|
||||
mCustomButtons.dpad_updown = elem->get<std::string>(PREFIX "dpad_updown");
|
||||
if (elem->has(PREFIX "dpad_leftright"))
|
||||
mCustomButtons.dpad_leftright = elem->get<std::string>(PREFIX "dpad_leftright");
|
||||
if (elem->has(PREFIX "dpad_all"))
|
||||
mCustomButtons.dpad_all = elem->get<std::string>(PREFIX "dpad_all");
|
||||
if (elem->has(PREFIX "thumbstick_click"))
|
||||
mCustomButtons.thumbstick_click = elem->get<std::string>(PREFIX "thumbstick_click");
|
||||
if (elem->has(PREFIX "button_l"))
|
||||
mCustomButtons.button_l = elem->get<std::string>(PREFIX "button_l");
|
||||
if (elem->has(PREFIX "button_r"))
|
||||
mCustomButtons.button_r = elem->get<std::string>(PREFIX "button_r");
|
||||
if (elem->has(PREFIX "button_lr"))
|
||||
mCustomButtons.button_lr = elem->get<std::string>(PREFIX "button_lr");
|
||||
if (elem->has(PREFIX "button_lt"))
|
||||
mCustomButtons.button_lt = elem->get<std::string>(PREFIX "button_lt");
|
||||
if (elem->has(PREFIX "button_rt"))
|
||||
mCustomButtons.button_rt = elem->get<std::string>(PREFIX "button_rt");
|
||||
if (elem->has(PREFIX "button_ltrt"))
|
||||
mCustomButtons.button_ltrt = elem->get<std::string>(PREFIX "button_ltrt");
|
||||
|
||||
// SNES.
|
||||
if (elem->has(PREFIX "button_a_SNES"))
|
||||
mCustomButtons.button_a_SNES = elem->get<std::string>(PREFIX "button_a_SNES");
|
||||
if (elem->has(PREFIX "button_b_SNES"))
|
||||
mCustomButtons.button_b_SNES = elem->get<std::string>(PREFIX "button_b_SNES");
|
||||
if (elem->has(PREFIX "button_x_SNES"))
|
||||
mCustomButtons.button_x_SNES = elem->get<std::string>(PREFIX "button_x_SNES");
|
||||
if (elem->has(PREFIX "button_y_SNES"))
|
||||
mCustomButtons.button_y_SNES = elem->get<std::string>(PREFIX "button_y_SNES");
|
||||
if (elem->has(PREFIX "button_back_SNES"))
|
||||
mCustomButtons.button_back_SNES = elem->get<std::string>(PREFIX "button_back_SNES");
|
||||
if (elem->has(PREFIX "button_start_SNES"))
|
||||
mCustomButtons.button_start_SNES = elem->get<std::string>(PREFIX "button_start_SNES");
|
||||
|
||||
// Switch Pro.
|
||||
if (elem->has(PREFIX "button_a_switch"))
|
||||
mCustomButtons.button_a_switch = elem->get<std::string>(PREFIX "button_a_switch");
|
||||
if (elem->has(PREFIX "button_b_switch"))
|
||||
mCustomButtons.button_b_switch = elem->get<std::string>(PREFIX "button_b_switch");
|
||||
if (elem->has(PREFIX "button_x_switch"))
|
||||
mCustomButtons.button_x_switch = elem->get<std::string>(PREFIX "button_x_switch");
|
||||
if (elem->has(PREFIX "button_y_switch"))
|
||||
mCustomButtons.button_y_switch = elem->get<std::string>(PREFIX "button_y_switch");
|
||||
if (elem->has(PREFIX "button_back_switch"))
|
||||
mCustomButtons.button_back_switch = elem->get<std::string>(PREFIX "button_back_switch");
|
||||
if (elem->has(PREFIX "button_start_switch"))
|
||||
mCustomButtons.button_start_switch = elem->get<std::string>(PREFIX "button_start_switch");
|
||||
|
||||
// PlayStation.
|
||||
if (elem->has(PREFIX "button_a_PS"))
|
||||
mCustomButtons.button_a_PS = elem->get<std::string>(PREFIX "button_a_PS");
|
||||
if (elem->has(PREFIX "button_b_PS"))
|
||||
mCustomButtons.button_b_PS = elem->get<std::string>(PREFIX "button_b_PS");
|
||||
if (elem->has(PREFIX "button_x_PS"))
|
||||
mCustomButtons.button_x_PS = elem->get<std::string>(PREFIX "button_x_PS");
|
||||
if (elem->has(PREFIX "button_y_PS"))
|
||||
mCustomButtons.button_y_PS = elem->get<std::string>(PREFIX "button_y_PS");
|
||||
if (elem->has(PREFIX "button_back_PS123"))
|
||||
mCustomButtons.button_back_PS123 = elem->get<std::string>(PREFIX "button_back_PS123");
|
||||
if (elem->has(PREFIX "button_start_PS123"))
|
||||
mCustomButtons.button_start_PS123 = elem->get<std::string>(PREFIX "button_start_PS123");
|
||||
if (elem->has(PREFIX "button_back_PS4"))
|
||||
mCustomButtons.button_back_PS4 = elem->get<std::string>(PREFIX "button_back_PS4");
|
||||
if (elem->has(PREFIX "button_start_PS4"))
|
||||
mCustomButtons.button_start_PS4 = elem->get<std::string>(PREFIX "button_start_PS4");
|
||||
if (elem->has(PREFIX "button_back_PS5"))
|
||||
mCustomButtons.button_back_PS5 = elem->get<std::string>(PREFIX "button_back_PS5");
|
||||
if (elem->has(PREFIX "button_start_PS5"))
|
||||
mCustomButtons.button_start_PS5 = elem->get<std::string>(PREFIX "button_start_PS5");
|
||||
|
||||
// XBOX.
|
||||
if (elem->has(PREFIX "button_a_XBOX"))
|
||||
mCustomButtons.button_a_XBOX = elem->get<std::string>(PREFIX "button_a_XBOX");
|
||||
if (elem->has(PREFIX "button_b_XBOX"))
|
||||
mCustomButtons.button_b_XBOX = elem->get<std::string>(PREFIX "button_b_XBOX");
|
||||
if (elem->has(PREFIX "button_x_XBOX"))
|
||||
mCustomButtons.button_x_XBOX = elem->get<std::string>(PREFIX "button_x_XBOX");
|
||||
if (elem->has(PREFIX "button_y_XBOX"))
|
||||
mCustomButtons.button_y_XBOX = elem->get<std::string>(PREFIX "button_y_XBOX");
|
||||
if (elem->has(PREFIX "button_back_XBOX"))
|
||||
mCustomButtons.button_back_XBOX = elem->get<std::string>(PREFIX "button_back_XBOX");
|
||||
if (elem->has(PREFIX "button_start_XBOX"))
|
||||
mCustomButtons.button_start_XBOX = elem->get<std::string>(PREFIX "button_start_XBOX");
|
||||
if (elem->has(PREFIX "button_back_XBOX360"))
|
||||
mCustomButtons.button_back_XBOX360 = elem->get<std::string>(PREFIX "button_back_XBOX360");
|
||||
if (elem->has(PREFIX "button_start_XBOX360"))
|
||||
mCustomButtons.button_start_XBOX360 = elem->get<std::string>(PREFIX "button_start_XBOX360");
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// ES-DE Frontend
|
||||
// HelpStyle.h
|
||||
//
|
||||
// Style (colors, position, icons etc.) for the help system.
|
||||
//
|
||||
|
||||
#ifndef ES_CORE_HELP_STYLE_H
|
||||
#define ES_CORE_HELP_STYLE_H
|
||||
|
||||
#include "utils/MathUtil.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class Font;
|
||||
class ThemeData;
|
||||
|
||||
struct HelpStyle {
|
||||
glm::vec2 position;
|
||||
glm::vec2 positionDimmed;
|
||||
glm::vec2 origin;
|
||||
glm::vec2 originDimmed;
|
||||
unsigned int textColor;
|
||||
unsigned int textColorDimmed;
|
||||
unsigned int iconColor;
|
||||
unsigned int iconColorDimmed;
|
||||
std::shared_ptr<Font> font;
|
||||
std::shared_ptr<Font> fontDimmed;
|
||||
float entrySpacing;
|
||||
float entrySpacingDimmed;
|
||||
float iconTextSpacing;
|
||||
float iconTextSpacingDimmed;
|
||||
float opacity;
|
||||
float opacityDimmed;
|
||||
std::string letterCase;
|
||||
|
||||
struct CustomButtonIcons {
|
||||
// Generic
|
||||
std::string dpad_updown;
|
||||
std::string dpad_up;
|
||||
std::string dpad_down;
|
||||
std::string dpad_leftright;
|
||||
std::string dpad_all;
|
||||
std::string thumbstick_click;
|
||||
std::string button_l;
|
||||
std::string button_r;
|
||||
std::string button_lr;
|
||||
std::string button_lt;
|
||||
std::string button_rt;
|
||||
std::string button_ltrt;
|
||||
|
||||
// SNES
|
||||
std::string button_a_SNES;
|
||||
std::string button_b_SNES;
|
||||
std::string button_x_SNES;
|
||||
std::string button_y_SNES;
|
||||
std::string button_back_SNES;
|
||||
std::string button_start_SNES;
|
||||
|
||||
// Switch Pro
|
||||
std::string button_a_switch;
|
||||
std::string button_b_switch;
|
||||
std::string button_x_switch;
|
||||
std::string button_y_switch;
|
||||
std::string button_back_switch;
|
||||
std::string button_start_switch;
|
||||
|
||||
// PlayStation
|
||||
std::string button_a_PS;
|
||||
std::string button_b_PS;
|
||||
std::string button_x_PS;
|
||||
std::string button_y_PS;
|
||||
std::string button_back_PS123;
|
||||
std::string button_start_PS123;
|
||||
std::string button_back_PS4;
|
||||
std::string button_start_PS4;
|
||||
std::string button_back_PS5;
|
||||
std::string button_start_PS5;
|
||||
|
||||
// XBOX
|
||||
std::string button_a_XBOX;
|
||||
std::string button_b_XBOX;
|
||||
std::string button_x_XBOX;
|
||||
std::string button_y_XBOX;
|
||||
std::string button_back_XBOX;
|
||||
std::string button_start_XBOX;
|
||||
std::string button_back_XBOX360;
|
||||
std::string button_start_XBOX360;
|
||||
};
|
||||
|
||||
CustomButtonIcons mCustomButtons;
|
||||
|
||||
HelpStyle();
|
||||
void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view);
|
||||
};
|
||||
|
||||
#endif // ES_CORE_HELP_STYLE_H
|
|
@ -30,6 +30,10 @@
|
|||
#include "utils/PlatformUtilAndroid.h"
|
||||
#endif
|
||||
|
||||
#if defined(__IOS__)
|
||||
#define TOUCH_GUID_STRING "-3"
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
int SDL_USER_CECBUTTONDOWN {-1};
|
||||
|
@ -38,7 +42,7 @@ namespace
|
|||
|
||||
InputManager::InputManager() noexcept
|
||||
: mWindow {Window::getInstance()}
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
, mInputOverlay {InputOverlay::getInstance()}
|
||||
#endif
|
||||
, mKeyboardInputConfig {nullptr}
|
||||
|
@ -92,7 +96,7 @@ void InputManager::init()
|
|||
LOG(LogInfo) << "Added keyboard with default configuration";
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
mTouchInputConfig = std::make_unique<InputConfig>(DEVICE_TOUCH, "Touch", TOUCH_GUID_STRING);
|
||||
loadTouchConfig();
|
||||
#endif
|
||||
|
@ -301,7 +305,7 @@ int InputManager::getNumConfiguredDevices()
|
|||
if (mKeyboardInputConfig->isConfigured())
|
||||
++num;
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
if (mTouchInputConfig->isConfigured())
|
||||
++num;
|
||||
#endif
|
||||
|
@ -335,7 +339,7 @@ std::string InputManager::getDeviceGUIDString(int deviceId)
|
|||
{
|
||||
if (deviceId == DEVICE_KEYBOARD)
|
||||
return KEYBOARD_GUID_STRING;
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
else if (deviceId == DEVICE_TOUCH)
|
||||
return TOUCH_GUID_STRING;
|
||||
#endif
|
||||
|
@ -358,7 +362,7 @@ InputConfig* InputManager::getInputConfigByDevice(int device)
|
|||
{
|
||||
if (device == DEVICE_KEYBOARD)
|
||||
return mKeyboardInputConfig.get();
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
else if (device == DEVICE_TOUCH)
|
||||
return mTouchInputConfig.get();
|
||||
#endif
|
||||
|
@ -542,7 +546,7 @@ bool InputManager::parseEvent(const SDL_Event& event)
|
|||
Input(DEVICE_KEYBOARD, TYPE_KEY, event.key.keysym.sym, 0, false));
|
||||
return true;
|
||||
}
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
case SDL_FINGERDOWN: {
|
||||
if (!Settings::getInstance()->getBool("InputTouchOverlay"))
|
||||
return false;
|
||||
|
@ -736,7 +740,7 @@ void InputManager::loadDefaultControllerConfig(SDL_JoystickID deviceIndex)
|
|||
|
||||
void InputManager::loadTouchConfig()
|
||||
{
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
InputConfig* cfg {mTouchInputConfig.get()};
|
||||
|
||||
if (cfg->isConfigured())
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include "CECInput.h"
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
#include "InputOverlay.h"
|
||||
#endif
|
||||
|
||||
|
@ -68,7 +68,7 @@ private:
|
|||
|
||||
Window* mWindow;
|
||||
CECInput mCECInput;
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
InputOverlay& mInputOverlay;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -30,6 +30,9 @@ namespace Scripting
|
|||
const std::string& arg3,
|
||||
const std::string& arg4)
|
||||
{
|
||||
#if defined(__IOS__)
|
||||
return;
|
||||
#endif
|
||||
if (!Settings::getInstance()->getBool("CustomEventScripts"))
|
||||
return;
|
||||
|
||||
|
|
|
@ -181,6 +181,13 @@ void Settings::setDefaults()
|
|||
mStringMap["UIMode"] = {"full", "full"};
|
||||
mStringMap["RandomEntryButton"] = {"games", "games"};
|
||||
|
||||
// UI settings -> system status settings.
|
||||
mBoolMap["SystemStatusBluetooth"] = {true, true};
|
||||
mBoolMap["SystemStatusWifi"] = {true, true};
|
||||
mBoolMap["SystemStatusCellular"] = {true, true};
|
||||
mBoolMap["SystemStatusBattery"] = {true, true};
|
||||
mBoolMap["SystemStatusBatteryPercentage"] = {true, true};
|
||||
|
||||
// UI settings -> media viewer settings.
|
||||
mStringMap["MediaViewerHelpPrompts"] = {"top", "top"};
|
||||
mBoolMap["MediaViewerShowTypes"] = {false, false};
|
||||
|
@ -222,6 +229,7 @@ void Settings::setDefaults()
|
|||
mBoolMap["ScreensaverVideoBlur"] = {false, false};
|
||||
|
||||
mBoolMap["ThemeVariantTriggers"] = {true, true};
|
||||
mBoolMap["DisplayClock"] = {false, false};
|
||||
mBoolMap["MenuBlurBackground"] = {true, true};
|
||||
mBoolMap["FoldersOnTop"] = {true, true};
|
||||
mBoolMap["FavoritesFirst"] = {true, true};
|
||||
|
@ -245,7 +253,7 @@ void Settings::setDefaults()
|
|||
|
||||
// Input device settings.
|
||||
mStringMap["InputControllerType"] = {"xbox", "xbox"};
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
mStringMap["InputTouchOverlaySize"] = {"medium", "medium"};
|
||||
mStringMap["InputTouchOverlayOpacity"] = {"normal", "normal"};
|
||||
mIntMap["InputTouchOverlayFadeTime"] = {6, 6};
|
||||
|
@ -263,7 +271,9 @@ void Settings::setDefaults()
|
|||
mBoolMap["FavStarCustom"] = {false, false};
|
||||
|
||||
// Other settings.
|
||||
#if !defined(__IOS__)
|
||||
mStringMap["MediaDirectory"] = {"", ""};
|
||||
#endif
|
||||
#if defined(STEAM_DECK) || defined(RETRODECK)
|
||||
mIntMap["MaxVRAM"] = {512, 512};
|
||||
#elif defined(RASPBERRY_PI)
|
||||
|
@ -274,7 +284,9 @@ void Settings::setDefaults()
|
|||
#if !defined(USE_OPENGLES)
|
||||
mIntMap["AntiAliasing"] = {0, 0};
|
||||
#endif
|
||||
#if !defined(__IOS__)
|
||||
mIntMap["DisplayIndex"] = {1, 1};
|
||||
#endif
|
||||
mIntMap["ScreenRotate"] = {0, 0};
|
||||
#if defined(__APPLE__)
|
||||
mStringMap["KeyboardQuitShortcut"] = {"CmdQ", "CmdQ"};
|
||||
|
@ -304,7 +316,10 @@ void Settings::setDefaults()
|
|||
mBoolMap["AlternativeEmulatorPerGame"] = {true, true};
|
||||
mBoolMap["ShowHiddenFiles"] = {true, true};
|
||||
mBoolMap["ShowHiddenGames"] = {true, true};
|
||||
#if !defined(__IOS__)
|
||||
mBoolMap["CustomEventScripts"] = {false, false};
|
||||
mBoolMap["CustomEventScriptsBrowsing"] = {false, false};
|
||||
#endif
|
||||
mBoolMap["ParseGamelistOnly"] = {false, false};
|
||||
mBoolMap["MAMENameStripExtraInfo"] = {true, true};
|
||||
#if defined(__unix__) && !defined(__ANDROID__)
|
||||
|
@ -350,12 +365,13 @@ void Settings::setDefaults()
|
|||
mBoolMap["DebugSkipMissingThemeFilesCustomCollections"] = {true, true};
|
||||
mBoolMap["LegacyGamelistFileLocation"] = {false, false};
|
||||
mBoolMap["CreatePlaceholderSystemDirectories"] = {false, false};
|
||||
mBoolMap["SystemStatusDisplayAll"] = {false, false};
|
||||
mStringMap["OpenGLVersion"] = {"", ""};
|
||||
#if !defined(__ANDROID__)
|
||||
#if !defined(__ANDROID__) && !defined(__IOS__)
|
||||
mStringMap["ROMDirectory"] = {"", ""};
|
||||
#endif
|
||||
mStringMap["UIMode_passkey"] = {"uuddlrlrba", "uuddlrlrba"};
|
||||
#if !defined(__ANDROID__)
|
||||
#if !defined(__ANDROID__) && !defined(__IOS__)
|
||||
mStringMap["UserThemeDirectory"] = {"", ""};
|
||||
#endif
|
||||
mIntMap["LottieMaxFileCache"] = {150, 150};
|
||||
|
|
492
es-core/src/SystemStatus.cpp
Normal file
492
es-core/src/SystemStatus.cpp
Normal file
|
@ -0,0 +1,492 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// ES-DE Frontend
|
||||
// SystemStatus.cpp
|
||||
//
|
||||
// Queries system status information from the operating system.
|
||||
// This includes Bluetooth, Wi-Fi, cellular and battery.
|
||||
//
|
||||
|
||||
#include "SystemStatus.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "Settings.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
|
||||
#include <SDL2/SDL_timer.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/hci.h>
|
||||
#include <bluetooth/hci_lib.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && !defined(__IOS__)
|
||||
#include "BluetoothStatusApple.h"
|
||||
#include <IOKit/ps/IOPSKeys.h>
|
||||
#include <IOKit/ps/IOPowerSources.h>
|
||||
#include <SystemConfiguration/SCNetworkConfiguration.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
// clang-format off
|
||||
// Because of course building fails if the files are included in the "wrong" order.
|
||||
#include <windows.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <bluetoothapis.h>
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include "utils/PlatformUtilAndroid.h"
|
||||
#endif
|
||||
|
||||
#define DEBUG_SYSTEM_STATUS false
|
||||
|
||||
SystemStatus::SystemStatus() noexcept
|
||||
: mExitPolling {false}
|
||||
, mPollImmediately {false}
|
||||
, mHasBluetooth {false}
|
||||
, mHasWifi {false}
|
||||
, mHasCellular {false}
|
||||
, mHasBattery {false}
|
||||
, mBatteryCharging {false}
|
||||
, mBatteryCapacity {0}
|
||||
{
|
||||
setCheckFlags();
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// Polling the device status is very fast on Android and it's quite problematic to run
|
||||
// these calls in a separate thread anyway.
|
||||
getStatusBluetooth();
|
||||
getStatusWifi();
|
||||
getStatusCellular();
|
||||
getStatusBattery();
|
||||
#elif !defined(__FreeBSD__) && !defined(__HAIKU__)
|
||||
mPollThread = std::make_unique<std::thread>(&SystemStatus::pollStatus, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
SystemStatus::~SystemStatus()
|
||||
{
|
||||
#if !defined(__ANDROID__) && !defined(__FreeBSD__) && !defined(__HAIKU__)
|
||||
mExitPolling = true;
|
||||
|
||||
if (mPollThread != nullptr && mPollThread->joinable()) {
|
||||
mPollThread->join();
|
||||
mPollThread.reset();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SystemStatus& SystemStatus::getInstance()
|
||||
{
|
||||
static SystemStatus instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void SystemStatus::setCheckFlags()
|
||||
{
|
||||
std::unique_lock<std::mutex> statusLock {mStatusMutex};
|
||||
mCheckBluetooth = Settings::getInstance()->getBool("SystemStatusBluetooth");
|
||||
mCheckWifi = Settings::getInstance()->getBool("SystemStatusWifi");
|
||||
mCheckCellular = Settings::getInstance()->getBool("SystemStatusCellular");
|
||||
mCheckBattery = Settings::getInstance()->getBool("SystemStatusBattery");
|
||||
|
||||
if (!mCheckBluetooth)
|
||||
mHasBluetooth = false;
|
||||
if (!mCheckWifi)
|
||||
mHasWifi = false;
|
||||
if (!mCheckCellular)
|
||||
mHasCellular = false;
|
||||
if (!mCheckBattery)
|
||||
mHasBattery = false;
|
||||
}
|
||||
|
||||
void SystemStatus::setPolling(const bool state)
|
||||
{
|
||||
#if defined(__ANDROID__)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (state == false) {
|
||||
mExitPolling = true;
|
||||
if (mPollThread != nullptr && mPollThread->joinable()) {
|
||||
mPollThread->join();
|
||||
mPollThread.reset();
|
||||
}
|
||||
}
|
||||
else if (mPollThread == nullptr) {
|
||||
mExitPolling = false;
|
||||
mPollThread = std::make_unique<std::thread>(&SystemStatus::pollStatus, this);
|
||||
}
|
||||
}
|
||||
|
||||
SystemStatus::Status SystemStatus::getStatus(const bool update)
|
||||
{
|
||||
#if defined(__ANDROID__)
|
||||
if (update) {
|
||||
getStatusBluetooth();
|
||||
getStatusWifi();
|
||||
getStatusCellular();
|
||||
getStatusBattery();
|
||||
#if (DEBUG_SYSTEM_STATUS)
|
||||
std::string status {"Bluetooth "};
|
||||
status.append(mHasBluetooth ? "enabled" : "disabled")
|
||||
.append(", Wi-Fi ")
|
||||
.append(mHasWifi ? "enabled" : "disabled")
|
||||
.append(", cellular ")
|
||||
.append(mHasCellular ? "enabled" : "disabled")
|
||||
.append(", battery ")
|
||||
.append(mHasBattery ? "enabled" : "disabled");
|
||||
if (mHasBattery) {
|
||||
status.append(" (")
|
||||
.append(mBatteryCharging ? "charging" : "not charging")
|
||||
.append(" and at ")
|
||||
.append(std::to_string(mBatteryCapacity))
|
||||
.append("% capacity)");
|
||||
}
|
||||
LOG(LogDebug) << "SystemStatus::getStatus(): " << status;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
mStatus.hasBluetooth = mHasBluetooth;
|
||||
mStatus.hasWifi = mHasWifi;
|
||||
mStatus.hasCellular = mHasCellular;
|
||||
mStatus.hasBattery = mHasBattery;
|
||||
mStatus.batteryCharging = mBatteryCharging;
|
||||
mStatus.batteryCapacity = mBatteryCapacity;
|
||||
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
void SystemStatus::pollStatus()
|
||||
{
|
||||
while (!mExitPolling) {
|
||||
std::unique_lock<std::mutex> statusLock {mStatusMutex};
|
||||
|
||||
getStatusBluetooth();
|
||||
getStatusWifi();
|
||||
getStatusCellular();
|
||||
getStatusBattery();
|
||||
statusLock.unlock();
|
||||
|
||||
#if (DEBUG_SYSTEM_STATUS)
|
||||
std::string status {"Bluetooth "};
|
||||
status.append(mHasBluetooth ? "enabled" : "disabled")
|
||||
.append(", Wi-Fi ")
|
||||
.append(mHasWifi ? "enabled" : "disabled")
|
||||
.append(", cellular ")
|
||||
.append(mHasCellular ? "enabled" : "disabled")
|
||||
.append(", battery ")
|
||||
.append(mHasBattery ? "enabled" : "disabled");
|
||||
if (mHasBattery) {
|
||||
status.append(" (")
|
||||
.append(mBatteryCharging ? "charging" : "not charging")
|
||||
.append(" and at ")
|
||||
.append(std::to_string(mBatteryCapacity))
|
||||
.append("% capacity)");
|
||||
}
|
||||
LOG(LogDebug) << "SystemStatus::pollStatus(): " << status;
|
||||
#endif
|
||||
|
||||
int delayValue {0};
|
||||
while (!mPollImmediately && !mExitPolling && delayValue < pollingTime) {
|
||||
delayValue += 100;
|
||||
SDL_Delay(100);
|
||||
}
|
||||
|
||||
mPollImmediately = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SystemStatus::getStatusBluetooth()
|
||||
{
|
||||
if (!mCheckBluetooth)
|
||||
return;
|
||||
|
||||
bool hasBluetooth {false};
|
||||
|
||||
#if defined(__APPLE__) && !defined(__IOS__)
|
||||
if (getBluetoothStatus() == 1)
|
||||
hasBluetooth = true;
|
||||
|
||||
#elif defined(_WIN64)
|
||||
BLUETOOTH_FIND_RADIO_PARAMS btFindRadio {sizeof(BLUETOOTH_FIND_RADIO_PARAMS)};
|
||||
HANDLE btRadio {nullptr};
|
||||
BLUETOOTH_RADIO_INFO btInfo {sizeof(BLUETOOTH_RADIO_INFO), 0};
|
||||
|
||||
if (BluetoothFindFirstRadio(&btFindRadio, &btRadio) != nullptr) {
|
||||
if (BluetoothGetRadioInfo(btRadio, &btInfo) == ERROR_SUCCESS)
|
||||
hasBluetooth = true;
|
||||
}
|
||||
|
||||
#elif defined(__ANDROID__)
|
||||
if (Utils::Platform::Android::getBluetoothStatus())
|
||||
hasBluetooth = true;
|
||||
|
||||
#elif defined(__linux__)
|
||||
if (hci_get_route(nullptr) != -1)
|
||||
hasBluetooth = true;
|
||||
#endif
|
||||
|
||||
mHasBluetooth = hasBluetooth;
|
||||
}
|
||||
|
||||
void SystemStatus::getStatusWifi()
|
||||
{
|
||||
if (!mCheckWifi)
|
||||
return;
|
||||
|
||||
bool hasWifi {false};
|
||||
|
||||
#if defined(__APPLE__) && !defined(__IOS__)
|
||||
const CFArrayRef interfaces {SCNetworkInterfaceCopyAll()};
|
||||
|
||||
if (interfaces != nullptr) {
|
||||
for (CFIndex i {0}; i < CFArrayGetCount(interfaces); ++i) {
|
||||
SCNetworkInterfaceRef interface {
|
||||
static_cast<SCNetworkInterfaceRef>(CFArrayGetValueAtIndex(interfaces, i))};
|
||||
|
||||
if (SCNetworkInterfaceGetInterfaceType(interface) == kSCNetworkInterfaceTypeIEEE80211) {
|
||||
const CFStringRef bsdName {SCNetworkInterfaceGetBSDName(interface)};
|
||||
|
||||
const SCDynamicStoreRef session {
|
||||
SCDynamicStoreCreate(nullptr, CFSTR("Custom"), nullptr, nullptr)};
|
||||
|
||||
const CFStringRef resolvedQuery {CFStringCreateWithFormat(
|
||||
nullptr, nullptr, CFSTR("State:/Network/Interface/%@/IPv4"), bsdName)};
|
||||
|
||||
const CFDictionaryRef dict {
|
||||
static_cast<CFDictionaryRef>(SCDynamicStoreCopyValue(session, resolvedQuery))};
|
||||
|
||||
if (dict != nullptr) {
|
||||
hasWifi = true;
|
||||
CFRelease(dict);
|
||||
CFRelease(resolvedQuery);
|
||||
CFRelease(session);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
CFRelease(resolvedQuery);
|
||||
CFRelease(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(interfaces);
|
||||
}
|
||||
|
||||
#elif defined(_WIN64)
|
||||
PIP_ADAPTER_INFO pAdapterInfo {nullptr};
|
||||
PIP_ADAPTER_INFO pAdapter {nullptr};
|
||||
ULONG ulOutBufLen {sizeof(IP_ADAPTER_INFO)};
|
||||
pAdapterInfo = reinterpret_cast<IP_ADAPTER_INFO*>(malloc(sizeof(IP_ADAPTER_INFO)));
|
||||
|
||||
if (pAdapterInfo != nullptr) {
|
||||
// Make an initial call to GetAdaptersInfo to get the necessary size into the
|
||||
// ulOutBufLen variable, which may or may not be big enough.
|
||||
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
|
||||
free(pAdapterInfo);
|
||||
pAdapterInfo = reinterpret_cast<IP_ADAPTER_INFO*>(malloc(ulOutBufLen));
|
||||
}
|
||||
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == NO_ERROR) {
|
||||
pAdapter = pAdapterInfo;
|
||||
while (pAdapter) {
|
||||
if (pAdapter->Type == IF_TYPE_IEEE80211) {
|
||||
// Checking whether the interface has an IP address is crude but
|
||||
// it seems to get the job done. And there is no other obvious
|
||||
// way to query the interface status without using additional
|
||||
// convoluted API calls.
|
||||
if (const std::string {pAdapter->IpAddressList.IpAddress.String} != "0.0.0.0") {
|
||||
hasWifi = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pAdapter = pAdapter->Next;
|
||||
}
|
||||
}
|
||||
|
||||
if (pAdapterInfo)
|
||||
free(pAdapterInfo);
|
||||
}
|
||||
|
||||
#elif defined(__ANDROID__)
|
||||
if (Utils::Platform::Android::getWifiStatus() == 1)
|
||||
hasWifi = true;
|
||||
|
||||
#elif defined(__linux__)
|
||||
const std::string sysEntry {"/sys/class/net"};
|
||||
auto entries {Utils::FileSystem::getDirContent(sysEntry, false)};
|
||||
for (auto& entry : entries) {
|
||||
if (Utils::FileSystem::exists(entry + "/wireless") &&
|
||||
Utils::FileSystem::exists(entry + "/operstate")) {
|
||||
std::string wifiState;
|
||||
std::ifstream fileStream;
|
||||
fileStream.open(entry + "/operstate");
|
||||
getline(fileStream, wifiState);
|
||||
fileStream.close();
|
||||
if (Utils::String::toLower(wifiState) == "up")
|
||||
hasWifi = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
mHasWifi = hasWifi;
|
||||
}
|
||||
|
||||
void SystemStatus::getStatusCellular()
|
||||
{
|
||||
if (!mCheckCellular)
|
||||
return;
|
||||
|
||||
bool hasCellular {false};
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
if (Utils::Platform::Android::getCellularStatus() >= 1)
|
||||
hasCellular = true;
|
||||
#endif
|
||||
|
||||
mHasCellular = hasCellular;
|
||||
}
|
||||
|
||||
void SystemStatus::getStatusBattery()
|
||||
{
|
||||
if (!mCheckBattery)
|
||||
return;
|
||||
|
||||
bool hasBattery {false};
|
||||
bool batteryCharging {false};
|
||||
int batteryCapacity {0};
|
||||
|
||||
#if defined(__APPLE__) && !defined(__IOS__)
|
||||
CFTypeRef sourceInfo {IOPSCopyPowerSourcesInfo()};
|
||||
CFArrayRef sourceList {IOPSCopyPowerSourcesList(sourceInfo)};
|
||||
|
||||
if (sourceList != nullptr && CFArrayGetCount(sourceList) > 0) {
|
||||
CFDictionaryRef source {nullptr};
|
||||
|
||||
for (CFIndex i {0}; i < CFArrayGetCount(sourceList); ++i) {
|
||||
source =
|
||||
IOPSGetPowerSourceDescription(sourceInfo, CFArrayGetValueAtIndex(sourceList, i));
|
||||
// Check if this is a battery.
|
||||
const CFStringRef type {static_cast<CFStringRef>(
|
||||
CFDictionaryGetValue(source, CFSTR(kIOPSTransportTypeKey)))};
|
||||
if (kCFCompareEqualTo == CFStringCompare(type, CFSTR(kIOPSInternalType), 0))
|
||||
break;
|
||||
else
|
||||
source = nullptr;
|
||||
}
|
||||
|
||||
if (source != nullptr) {
|
||||
hasBattery = true;
|
||||
|
||||
if (CFDictionaryGetValue(source, CFSTR(kIOPSIsChargingKey)) != nullptr) {
|
||||
batteryCharging = CFBooleanGetValue(static_cast<CFBooleanRef>(
|
||||
CFDictionaryGetValue(source, CFSTR(kIOPSIsChargingKey))));
|
||||
}
|
||||
|
||||
int curCapacity {0};
|
||||
const CFNumberRef curCapacityNum {static_cast<CFNumberRef>(
|
||||
CFDictionaryGetValue(source, CFSTR(kIOPSCurrentCapacityKey)))};
|
||||
CFNumberGetValue(curCapacityNum, kCFNumberIntType, &curCapacity);
|
||||
|
||||
int maxCapacity {0};
|
||||
const CFNumberRef maxCapacityNum {
|
||||
static_cast<CFNumberRef>(CFDictionaryGetValue(source, CFSTR(kIOPSMaxCapacityKey)))};
|
||||
CFNumberGetValue(maxCapacityNum, kCFNumberIntType, &maxCapacity);
|
||||
|
||||
if (maxCapacity > 0) {
|
||||
batteryCapacity =
|
||||
static_cast<float>(curCapacity) / static_cast<float>(maxCapacity) * 100.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceInfo != nullptr)
|
||||
CFRelease(sourceInfo);
|
||||
if (sourceList != nullptr)
|
||||
CFRelease(sourceList);
|
||||
|
||||
#elif defined(_WIN64)
|
||||
SYSTEM_POWER_STATUS powerStatus;
|
||||
|
||||
if (GetSystemPowerStatus(&powerStatus)) {
|
||||
if (powerStatus.BatteryFlag != 128 && powerStatus.BatteryFlag != 255) {
|
||||
hasBattery = true;
|
||||
|
||||
if (powerStatus.ACLineStatus == 1)
|
||||
batteryCharging = true;
|
||||
|
||||
batteryCapacity = powerStatus.BatteryLifePercent;
|
||||
}
|
||||
else {
|
||||
hasBattery = false;
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__ANDROID__)
|
||||
std::pair<int, int> batteryStatus {Utils::Platform::Android::getBatteryStatus()};
|
||||
hasBattery = static_cast<bool>(batteryStatus.first);
|
||||
|
||||
if (batteryStatus.first == -1 && batteryStatus.second == -1) {
|
||||
hasBattery = false;
|
||||
}
|
||||
else {
|
||||
hasBattery = true;
|
||||
if (batteryStatus.first == 1)
|
||||
batteryCharging = true;
|
||||
}
|
||||
|
||||
batteryCapacity = batteryStatus.second;
|
||||
|
||||
#elif defined(__linux__)
|
||||
const std::string sysEntry {"/sys/class/power_supply"};
|
||||
std::string batteryDir;
|
||||
auto entries {Utils::FileSystem::getDirContent(sysEntry, false)};
|
||||
if (std::find(entries.cbegin(), entries.cend(), sysEntry + "/BAT0") != entries.cend())
|
||||
batteryDir = sysEntry + "/BAT0";
|
||||
else if (std::find(entries.cbegin(), entries.cend(), sysEntry + "/BAT1") != entries.cend())
|
||||
batteryDir = sysEntry + "/BAT1";
|
||||
else if (std::find(entries.cbegin(), entries.cend(), sysEntry + "/battery") != entries.cend())
|
||||
batteryDir = sysEntry + "/battery";
|
||||
|
||||
hasBattery = true;
|
||||
|
||||
if (!Utils::FileSystem::exists(batteryDir + "/status"))
|
||||
hasBattery = false;
|
||||
if (!Utils::FileSystem::exists(batteryDir + "/capacity"))
|
||||
hasBattery = false;
|
||||
|
||||
if (hasBattery) {
|
||||
std::string batteryStatusValue;
|
||||
std::string batteryCapacityValue;
|
||||
std::ifstream fileStream;
|
||||
fileStream.open(batteryDir + "/status");
|
||||
getline(fileStream, batteryStatusValue);
|
||||
batteryStatusValue = Utils::String::toLower(batteryStatusValue);
|
||||
fileStream.close();
|
||||
|
||||
if (batteryStatusValue != "discharging")
|
||||
batteryCharging = true;
|
||||
|
||||
fileStream.open(batteryDir + "/capacity");
|
||||
getline(fileStream, batteryCapacityValue);
|
||||
fileStream.close();
|
||||
|
||||
batteryCapacity = std::stoi(batteryCapacityValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (batteryCapacity < 0)
|
||||
batteryCapacity = 0;
|
||||
if (batteryCapacity > 100)
|
||||
batteryCapacity = 100;
|
||||
|
||||
mHasBattery = hasBattery;
|
||||
mBatteryCharging = batteryCharging;
|
||||
mBatteryCapacity = batteryCapacity;
|
||||
}
|
81
es-core/src/SystemStatus.h
Normal file
81
es-core/src/SystemStatus.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// ES-DE Frontend
|
||||
// SystemStatus.h
|
||||
//
|
||||
// Queries system status information from the operating system.
|
||||
// This includes Bluetooth, Wi-Fi, cellular and battery.
|
||||
//
|
||||
|
||||
#ifndef ES_CORE_SYSTEM_STATUS_H
|
||||
#define ES_CORE_SYSTEM_STATUS_H
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
class SystemStatus
|
||||
{
|
||||
public:
|
||||
~SystemStatus();
|
||||
static SystemStatus& getInstance();
|
||||
|
||||
void setCheckFlags();
|
||||
void setPolling(const bool state);
|
||||
void setPollImmediately(const bool state) { mPollImmediately = state; }
|
||||
const bool getPollImmediately() { return mPollImmediately; }
|
||||
|
||||
struct Status {
|
||||
bool hasBluetooth;
|
||||
bool hasWifi;
|
||||
bool hasCellular;
|
||||
bool hasBattery;
|
||||
bool batteryCharging;
|
||||
int batteryCapacity;
|
||||
Status()
|
||||
: hasBluetooth {false}
|
||||
, hasWifi {false}
|
||||
, hasCellular {false}
|
||||
, hasBattery {false}
|
||||
, batteryCharging {false}
|
||||
, batteryCapacity {0}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
Status getStatus(const bool update = true);
|
||||
|
||||
static constexpr int updateTime {300};
|
||||
static constexpr int pollingTime {2500};
|
||||
|
||||
private:
|
||||
SystemStatus() noexcept;
|
||||
|
||||
void pollStatus();
|
||||
|
||||
void getStatusBluetooth();
|
||||
void getStatusWifi();
|
||||
void getStatusCellular();
|
||||
void getStatusBattery();
|
||||
|
||||
bool mCheckBluetooth;
|
||||
bool mCheckWifi;
|
||||
bool mCheckCellular;
|
||||
bool mCheckBattery;
|
||||
|
||||
std::unique_ptr<std::thread> mPollThread;
|
||||
Status mStatus;
|
||||
std::mutex mStatusMutex;
|
||||
|
||||
std::atomic<bool> mExitPolling;
|
||||
std::atomic<bool> mPollImmediately;
|
||||
|
||||
std::atomic<bool> mHasBluetooth;
|
||||
std::atomic<bool> mHasWifi;
|
||||
std::atomic<bool> mHasCellular;
|
||||
std::atomic<bool> mHasBattery;
|
||||
std::atomic<bool> mBatteryCharging;
|
||||
std::atomic<int> mBatteryCapacity;
|
||||
};
|
||||
|
||||
#endif // ES_CORE_SYSTEM_STATUS_H
|
|
@ -21,6 +21,10 @@
|
|||
#include <algorithm>
|
||||
#include <pugixml.hpp>
|
||||
|
||||
#if defined(__IOS__)
|
||||
#include "utils/PlatformUtilIOS.h"
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
std::vector<std::string> ThemeData::sSupportedViews {
|
||||
{"all"},
|
||||
|
@ -71,6 +75,8 @@ std::vector<std::pair<std::string, std::string>> ThemeData::sSupportedAspectRati
|
|||
{"4:3_vertical", "4:3 vertical"},
|
||||
{"5:4", "5:4"},
|
||||
{"5:4_vertical", "5:4 vertical"},
|
||||
{"8:7", "8:7"},
|
||||
{"8:7_vertical", "8:7 vertical"},
|
||||
{"19.5:9", "19.5:9"},
|
||||
{"19.5:9_vertical", "19.5:9 vertical"},
|
||||
{"20:9", "20:9"},
|
||||
|
@ -92,6 +98,8 @@ std::map<std::string, float> ThemeData::sAspectRatioMap {
|
|||
{"4:3_vertical", 0.75f},
|
||||
{"5:4", 1.25f},
|
||||
{"5:4_vertical", 0.8f},
|
||||
{"8:7", 1.1429f},
|
||||
{"8:7_vertical", 0.875f},
|
||||
{"19.5:9", 2.1667f},
|
||||
{"19.5:9_vertical", 0.4615f},
|
||||
{"20:9", 2.2222f},
|
||||
|
@ -119,7 +127,8 @@ std::vector<std::pair<std::string, std::string>> ThemeData::sSupportedLanguages
|
|||
{"sv_SE", "SVENSKA"},
|
||||
{"ja_JP", "日本語"},
|
||||
{"ko_KR", "한국어"},
|
||||
{"zh_CN", "简体中文"}};
|
||||
{"zh_CN", "简体中文"},
|
||||
{"zh_TW", "繁體中文"}};
|
||||
|
||||
std::map<std::string, std::map<std::string, std::string>> ThemeData::sPropertyAttributeMap
|
||||
// The data type is defined by the parent property.
|
||||
|
@ -129,6 +138,8 @@ std::map<std::string, std::map<std::string, std::string>> ThemeData::sPropertyAt
|
|||
{"customControllerIcon", "controller"}}},
|
||||
{"helpsystem",
|
||||
{{"customButtonIcon", "button"}}},
|
||||
{"systemstatus",
|
||||
{{"customIcon", "icon"}}},
|
||||
};
|
||||
|
||||
std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
||||
|
@ -350,6 +361,10 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
|||
{"maxSize", NORMALIZED_PAIR},
|
||||
{"cropSize", NORMALIZED_PAIR},
|
||||
{"cropPos", NORMALIZED_PAIR},
|
||||
{"imageSize", NORMALIZED_PAIR},
|
||||
{"imageMaxSize", NORMALIZED_PAIR},
|
||||
{"imageCropSize", NORMALIZED_PAIR},
|
||||
{"imageCropPos", NORMALIZED_PAIR},
|
||||
{"origin", NORMALIZED_PAIR},
|
||||
{"rotation", FLOAT},
|
||||
{"rotationOrigin", NORMALIZED_PAIR},
|
||||
|
@ -374,6 +389,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
|||
{"pillarboxThreshold", NORMALIZED_PAIR},
|
||||
{"scanlines", BOOLEAN},
|
||||
{"delay", FLOAT},
|
||||
{"fadeInType", STRING},
|
||||
{"fadeInTime", FLOAT},
|
||||
{"scrollFadeIn", BOOLEAN},
|
||||
{"brightness", FLOAT},
|
||||
|
@ -542,6 +558,8 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
|||
{"posDimmed", NORMALIZED_PAIR},
|
||||
{"origin", NORMALIZED_PAIR},
|
||||
{"originDimmed", NORMALIZED_PAIR},
|
||||
{"rotation", FLOAT},
|
||||
{"rotationOrigin", NORMALIZED_PAIR},
|
||||
{"textColor", COLOR},
|
||||
{"textColorDimmed", COLOR},
|
||||
{"iconColor", COLOR},
|
||||
|
@ -549,14 +567,64 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
|||
{"fontPath", PATH},
|
||||
{"fontSize", FLOAT},
|
||||
{"fontSizeDimmed", FLOAT},
|
||||
{"scope", STRING},
|
||||
{"entries", STRING},
|
||||
{"entryLayout", STRING},
|
||||
{"entryRelativeScale", FLOAT},
|
||||
{"entrySpacing", FLOAT},
|
||||
{"entrySpacingDimmed", FLOAT},
|
||||
{"iconTextSpacing", FLOAT},
|
||||
{"iconTextSpacingDimmed", FLOAT},
|
||||
{"letterCase", STRING},
|
||||
{"backgroundColor", COLOR},
|
||||
{"backgroundColorEnd", COLOR},
|
||||
{"backgroundGradientType", STRING},
|
||||
{"backgroundHorizontalPadding", NORMALIZED_PAIR},
|
||||
{"backgroundVerticalPadding", NORMALIZED_PAIR},
|
||||
{"backgroundCornerRadius", FLOAT},
|
||||
{"opacity", FLOAT},
|
||||
{"opacityDimmed", FLOAT},
|
||||
{"customButtonIcon", PATH}}},
|
||||
{"systemstatus",
|
||||
{{"pos", NORMALIZED_PAIR},
|
||||
{"height", FLOAT},
|
||||
{"origin", NORMALIZED_PAIR},
|
||||
{"rotation", FLOAT},
|
||||
{"rotationOrigin", NORMALIZED_PAIR},
|
||||
{"scope", STRING},
|
||||
{"fontPath", PATH},
|
||||
{"textRelativeScale", FLOAT},
|
||||
{"color", COLOR},
|
||||
{"backgroundColor", COLOR},
|
||||
{"backgroundColorEnd", COLOR},
|
||||
{"backgroundGradientType", STRING},
|
||||
{"backgroundHorizontalPadding", NORMALIZED_PAIR},
|
||||
{"backgroundVerticalPadding", NORMALIZED_PAIR},
|
||||
{"backgroundCornerRadius", FLOAT},
|
||||
{"entries", STRING},
|
||||
{"entrySpacing", FLOAT},
|
||||
{"customIcon", PATH},
|
||||
{"opacity", FLOAT}}},
|
||||
{"clock",
|
||||
{{"pos", NORMALIZED_PAIR},
|
||||
{"size", NORMALIZED_PAIR},
|
||||
{"origin", NORMALIZED_PAIR},
|
||||
{"rotation", FLOAT},
|
||||
{"rotationOrigin", NORMALIZED_PAIR},
|
||||
{"scope", STRING},
|
||||
{"fontPath", PATH},
|
||||
{"fontSize", FLOAT},
|
||||
{"horizontalAlignment", STRING},
|
||||
{"verticalAlignment", STRING},
|
||||
{"color", COLOR},
|
||||
{"backgroundColor", COLOR},
|
||||
{"backgroundColorEnd", COLOR},
|
||||
{"backgroundGradientType", STRING},
|
||||
{"backgroundHorizontalPadding", NORMALIZED_PAIR},
|
||||
{"backgroundVerticalPadding", NORMALIZED_PAIR},
|
||||
{"backgroundCornerRadius", FLOAT},
|
||||
{"format", STRING},
|
||||
{"opacity", FLOAT}}},
|
||||
{"sound",
|
||||
{{"path", PATH}}}};
|
||||
// clang-format on
|
||||
|
@ -769,6 +837,8 @@ void ThemeData::populateThemes()
|
|||
#if defined(__ANDROID__)
|
||||
const std::string userThemeDirectory {Utils::FileSystem::getInternalAppDataDirectory() +
|
||||
"/themes"};
|
||||
#elif defined(__IOS__)
|
||||
const std::string userThemeDirectory;
|
||||
#else
|
||||
const std::string defaultUserThemeDir {Utils::FileSystem::getAppDataDirectory() + "/themes"};
|
||||
const std::string userThemeDirSetting {Utils::FileSystem::expandHomePath(
|
||||
|
@ -800,6 +870,10 @@ void ThemeData::populateThemes()
|
|||
const std::vector<std::string> themePaths {Utils::FileSystem::getProgramDataPath() + "/themes",
|
||||
Utils::FileSystem::getAppDataDirectory() + "/themes",
|
||||
userThemeDirectory};
|
||||
#elif defined(__IOS__)
|
||||
const std::vector<std::string> themePaths {Utils::Platform::iOS::getPackagePath() + "themes",
|
||||
Utils::FileSystem::getAppDataDirectory() +
|
||||
"/themes"};
|
||||
#elif defined(__APPLE__)
|
||||
const std::vector<std::string> themePaths {
|
||||
Utils::FileSystem::getExePath() + "/themes",
|
||||
|
@ -2341,6 +2415,7 @@ void ThemeData::gettextMessageCatalogEntries()
|
|||
_("3:2 vertical");
|
||||
_("4:3 vertical");
|
||||
_("5:4 vertical");
|
||||
_("8:7 vertical");
|
||||
_("19.5:9 vertical");
|
||||
_("20:9 vertical");
|
||||
_("21:9 vertical");
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "resources/Font.h"
|
||||
#include "utils/LocalizationUtil.h"
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
#include "InputOverlay.h"
|
||||
#endif
|
||||
|
||||
|
@ -30,6 +30,9 @@
|
|||
|
||||
Window::Window() noexcept
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mHelpComponents {nullptr}
|
||||
, mClockComponents {nullptr}
|
||||
, mSystemStatusComponents {nullptr}
|
||||
, mSplashTextPositions {0.0f, 0.0f, 0.0f, 0.0f}
|
||||
, mBackgroundOverlayOpacity {1.0f}
|
||||
, mScreensaver {nullptr}
|
||||
|
@ -57,6 +60,7 @@ Window::Window() noexcept
|
|||
, mInvalidateCacheTimer {0}
|
||||
, mVideoPlayerCount {0}
|
||||
, mTopScale {0.5f}
|
||||
, mScaleAccumulator {0}
|
||||
, mRenderedHelpPrompts {false}
|
||||
, mChangedTheme {false}
|
||||
{
|
||||
|
@ -181,11 +185,22 @@ bool Window::init(bool resized)
|
|||
#endif
|
||||
mProgressBarRectangles.emplace_back(progressBarRect);
|
||||
|
||||
mBackgroundOverlay->setImage(":/graphics/frame.png");
|
||||
mBackgroundOverlay->setResize(mRenderer->getScreenWidth(), mRenderer->getScreenHeight());
|
||||
|
||||
mPostprocessedBackground = TextureResource::get("", false, false, false, false, false);
|
||||
|
||||
// This doesn't really do anything useful per se, but initializing the texture takes a bit
|
||||
// longer the first time so doing it here even with null data avoids some potential stutter
|
||||
// the first time the menu is opened.
|
||||
const std::vector<unsigned char> processedTexture(
|
||||
static_cast<size_t>(mRenderer->getScreenWidth()) *
|
||||
static_cast<size_t>(mRenderer->getScreenHeight()) * 4,
|
||||
0);
|
||||
mPostprocessedBackground->initFromPixels(&processedTexture[0],
|
||||
static_cast<size_t>(mRenderer->getScreenWidth()),
|
||||
static_cast<size_t>(mRenderer->getScreenHeight()));
|
||||
|
||||
mScaleAccumulator = 0;
|
||||
|
||||
mListScrollText = std::make_unique<TextComponent>("", Font::get(FONT_SIZE_LARGE));
|
||||
mGPUStatisticsText = std::make_unique<TextComponent>(
|
||||
"", Font::get(FONT_SIZE_SMALL), 0xFF00FFFF, ALIGN_LEFT, ALIGN_CENTER, glm::vec2 {1, 1},
|
||||
|
@ -206,6 +221,20 @@ void Window::deinit()
|
|||
(*it)->onHide();
|
||||
|
||||
mPostprocessedBackground.reset();
|
||||
sHelpPromptsImageCache.clear();
|
||||
mHelp.reset();
|
||||
if (mHelpComponents != nullptr) {
|
||||
mHelpComponents->clear();
|
||||
mHelpComponents = nullptr;
|
||||
}
|
||||
if (mClockComponents != nullptr) {
|
||||
mClockComponents->clear();
|
||||
mClockComponents = nullptr;
|
||||
}
|
||||
if (mSystemStatusComponents != nullptr) {
|
||||
mSystemStatusComponents->clear();
|
||||
mSystemStatusComponents = nullptr;
|
||||
}
|
||||
|
||||
InputManager::getInstance().deinit();
|
||||
ResourceManager::getInstance().unloadAll();
|
||||
|
@ -297,6 +326,7 @@ void Window::input(InputConfig* config, Input input)
|
|||
// up. So scale it to full size so it won't be stuck at a smaller size when returning
|
||||
// from the submenu.
|
||||
mTopScale = 1.0f;
|
||||
mScaleAccumulator = 0;
|
||||
GuiComponent* menu {mGuiStack.back()};
|
||||
glm::vec2 menuCenter {menu->getCenter()};
|
||||
menu->setOrigin(0.5f, 0.5f);
|
||||
|
@ -351,8 +381,13 @@ void Window::logInput(InputConfig* config, Input input)
|
|||
|
||||
void Window::update(int deltaTime)
|
||||
{
|
||||
if (mInvalidateCacheTimer > 0)
|
||||
if (mInvalidateCacheTimer > 0) {
|
||||
mInvalidateCacheTimer = glm::clamp(mInvalidateCacheTimer - deltaTime, 0, 500);
|
||||
if (mHelpComponents != nullptr) {
|
||||
for (auto& helpComponent : *mHelpComponents)
|
||||
helpComponent->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (mNormalizeNextUpdate) {
|
||||
mNormalizeNextUpdate = false;
|
||||
|
@ -361,6 +396,10 @@ void Window::update(int deltaTime)
|
|||
deltaTime = mAverageDeltaTime;
|
||||
}
|
||||
|
||||
if (mGuiStack.size() > 1 && mTopScale < 1.0f &&
|
||||
Settings::getInstance()->getString("MenuOpeningEffect") == "scale-up")
|
||||
mScaleAccumulator += deltaTime;
|
||||
|
||||
mFrameTimeElapsed += deltaTime;
|
||||
++mFrameCountElapsed;
|
||||
if (mFrameTimeElapsed > 500) {
|
||||
|
@ -440,7 +479,17 @@ void Window::update(int deltaTime)
|
|||
if (mScreensaver && mRenderScreensaver)
|
||||
mScreensaver->update(deltaTime);
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
if (mClockComponents != nullptr) {
|
||||
for (auto& clockComponent : *mClockComponents)
|
||||
clockComponent->update(deltaTime);
|
||||
}
|
||||
|
||||
if (mSystemStatusComponents != nullptr) {
|
||||
for (auto& systemStatusComponent : *mSystemStatusComponents)
|
||||
systemStatusComponent->update(deltaTime);
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
if (Settings::getInstance()->getBool("InputTouchOverlay"))
|
||||
InputOverlay::getInstance().update(deltaTime);
|
||||
#endif
|
||||
|
@ -463,6 +512,7 @@ void Window::render()
|
|||
glm::mat4 trans {mRenderer->getIdentity()};
|
||||
|
||||
mRenderedHelpPrompts = false;
|
||||
bool menuIsOpen {false};
|
||||
|
||||
// Draw only bottom and top of GuiStack (if they are different).
|
||||
if (!mGuiStack.empty()) {
|
||||
|
@ -503,6 +553,8 @@ void Window::render()
|
|||
bottom->render(trans);
|
||||
|
||||
if (bottom != top || mRenderLaunchScreen) {
|
||||
if (!mRenderLaunchScreen)
|
||||
menuIsOpen = true;
|
||||
if (!mCachedBackground && mInvalidateCacheTimer == 0) {
|
||||
// Generate a cache texture of the shaded background when opening the menu, which
|
||||
// will remain valid until the menu is closed. This is way faster than having to
|
||||
|
@ -525,7 +577,7 @@ void Window::render()
|
|||
|
||||
// We run two passes to make the blur smoother.
|
||||
backgroundParameters.blurPasses = 2;
|
||||
backgroundParameters.blurStrength = 1.35f;
|
||||
backgroundParameters.blurStrength = 1.75f;
|
||||
|
||||
// Also dim the background slightly.
|
||||
if (Settings::getInstance()->getString("MenuColorScheme") == "light")
|
||||
|
@ -593,18 +645,34 @@ void Window::render()
|
|||
mBackgroundOverlay->render(trans);
|
||||
|
||||
// Scale-up menu opening effect.
|
||||
if (Settings::getInstance()->getString("MenuOpeningEffect") == "scale-up") {
|
||||
if (mTopScale < 1.0f) {
|
||||
mTopScale = glm::clamp(mTopScale + 0.07f, 0.0f, 1.0f);
|
||||
glm::vec2 topCenter {top->getCenter()};
|
||||
top->setOrigin(0.5f, 0.5f);
|
||||
top->setPosition(topCenter.x, topCenter.y, 0.0f);
|
||||
top->setScale(mTopScale);
|
||||
}
|
||||
if (Settings::getInstance()->getString("MenuOpeningEffect") == "scale-up" &&
|
||||
mTopScale < 1.0f) {
|
||||
mTopScale =
|
||||
glm::clamp(glm::mix(0.5f, 1.0f, static_cast<float>(mScaleAccumulator) / 110.0f),
|
||||
0.5f, 1.0f);
|
||||
glm::vec2 topCenter {top->getCenter()};
|
||||
top->setOrigin(0.5f, 0.5f);
|
||||
top->setPosition(topCenter.x, topCenter.y, 0.0f);
|
||||
top->setScale(mTopScale);
|
||||
if (mTopScale == 1.0f)
|
||||
mScaleAccumulator = 0;
|
||||
}
|
||||
|
||||
if (!mRenderedHelpPrompts)
|
||||
mHelp->render(trans);
|
||||
if (!mRenderedHelpPrompts) {
|
||||
if (mHelpComponents != nullptr) {
|
||||
for (auto& helpComponent : *mHelpComponents) {
|
||||
if (helpComponent->getComponentScope() == ComponentScope::NONE)
|
||||
continue;
|
||||
if (helpComponent->getComponentScope() != ComponentScope::VIEW) {
|
||||
helpComponent->setVisible(true);
|
||||
helpComponent->render(trans);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mHelp->render(trans);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mRenderLaunchScreen)
|
||||
top->render(trans);
|
||||
|
@ -646,6 +714,30 @@ void Window::render()
|
|||
startScreensaver(true);
|
||||
}
|
||||
|
||||
if (mClockComponents != nullptr) {
|
||||
for (auto& clockComponent : *mClockComponents) {
|
||||
if (clockComponent->getComponentScope() == ComponentScope::NONE)
|
||||
continue;
|
||||
if (menuIsOpen && clockComponent->getComponentScope() == ComponentScope::VIEW)
|
||||
continue;
|
||||
if (!menuIsOpen && clockComponent->getComponentScope() == ComponentScope::MENU)
|
||||
continue;
|
||||
clockComponent->render(trans);
|
||||
}
|
||||
}
|
||||
|
||||
if (mSystemStatusComponents != nullptr) {
|
||||
for (auto& systemStatusComponent : *mSystemStatusComponents) {
|
||||
if (systemStatusComponent->getComponentScope() == ComponentScope::NONE)
|
||||
continue;
|
||||
if (menuIsOpen && systemStatusComponent->getComponentScope() == ComponentScope::VIEW)
|
||||
continue;
|
||||
if (!menuIsOpen && systemStatusComponent->getComponentScope() == ComponentScope::MENU)
|
||||
continue;
|
||||
systemStatusComponent->render(trans);
|
||||
}
|
||||
}
|
||||
|
||||
if (mInfoPopup)
|
||||
mInfoPopup->render(trans);
|
||||
|
||||
|
@ -661,7 +753,7 @@ void Window::render()
|
|||
if (mRenderScreensaver)
|
||||
mScreensaver->renderScreensaver();
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
if (Settings::getInstance()->getBool("InputTouchOverlay"))
|
||||
InputOverlay::getInstance().render(mRenderer->getIdentity());
|
||||
#endif
|
||||
|
@ -758,15 +850,24 @@ void Window::renderListScrollOverlay(const float opacity, const std::string& tex
|
|||
|
||||
void Window::renderHelpPromptsEarly()
|
||||
{
|
||||
mHelp->render(mRenderer->getIdentity());
|
||||
if (mHelpComponents != nullptr) {
|
||||
for (auto& helpComponent : *mHelpComponents) {
|
||||
if (helpComponent->getComponentScope() == ComponentScope::NONE)
|
||||
continue;
|
||||
if (helpComponent->getComponentScope() != ComponentScope::MENU) {
|
||||
helpComponent->setVisible(true);
|
||||
helpComponent->render(mRenderer->getIdentity());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mHelp->render(mRenderer->getIdentity());
|
||||
}
|
||||
mRenderedHelpPrompts = true;
|
||||
}
|
||||
|
||||
void Window::setHelpPrompts(const std::vector<HelpPrompt>& prompts, const HelpStyle& style)
|
||||
void Window::setHelpPrompts(const std::vector<HelpPrompt>& prompts)
|
||||
{
|
||||
mHelp->clearPrompts();
|
||||
mHelp->setStyle(style);
|
||||
|
||||
std::vector<HelpPrompt> addPrompts;
|
||||
|
||||
std::map<std::string, bool> inputSeenMap;
|
||||
|
@ -798,10 +899,13 @@ void Window::setHelpPrompts(const std::vector<HelpPrompt>& prompts, const HelpSt
|
|||
}
|
||||
}
|
||||
|
||||
// Sort prompts so it goes [dpad_all] [dpad_u/d] [dpad_l/r] [a/b/x/y/l/r] [start/back].
|
||||
// Sort the prompts so that they are always displayed in the same order on screen.
|
||||
std::sort(addPrompts.begin(), addPrompts.end(),
|
||||
[](const HelpPrompt& a, const HelpPrompt& b) -> bool {
|
||||
static const std::vector<std::string> map {"up/down/left/right",
|
||||
static const std::vector<std::string> map {"thumbstickclick",
|
||||
"lr",
|
||||
"ltrt",
|
||||
"up/down/left/right",
|
||||
"up/down",
|
||||
"up",
|
||||
"down",
|
||||
|
@ -830,7 +934,21 @@ void Window::setHelpPrompts(const std::vector<HelpPrompt>& prompts, const HelpSt
|
|||
return aVal > bVal;
|
||||
});
|
||||
|
||||
mHelp->setPrompts(addPrompts);
|
||||
if (mHelpComponents != nullptr) {
|
||||
for (auto& helpComponent : *mHelpComponents) {
|
||||
if (helpComponent->getComponentScope() == ComponentScope::NONE)
|
||||
continue;
|
||||
if (mGuiStack.size() == 1 && helpComponent->getComponentScope() == ComponentScope::MENU)
|
||||
continue;
|
||||
if (mGuiStack.size() > 1 && helpComponent->getComponentScope() == ComponentScope::VIEW)
|
||||
continue;
|
||||
helpComponent->clearPrompts();
|
||||
helpComponent->setPrompts(addPrompts);
|
||||
}
|
||||
}
|
||||
else if (mHelp != nullptr) {
|
||||
mHelp->setPrompts(addPrompts);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::stopInfoPopup()
|
||||
|
|
|
@ -12,11 +12,13 @@
|
|||
|
||||
#include "GuiComponent.h"
|
||||
#include "HelpPrompt.h"
|
||||
#include "HelpStyle.h"
|
||||
#include "InputConfig.h"
|
||||
#include "Settings.h"
|
||||
#include "SystemStatus.h"
|
||||
#include "components/DateTimeComponent.h"
|
||||
#include "components/HelpComponent.h"
|
||||
#include "components/ImageComponent.h"
|
||||
#include "components/SystemStatusComponent.h"
|
||||
#include "components/TextComponent.h"
|
||||
#include "guis/GuiInfoPopup.h"
|
||||
#include "resources/Font.h"
|
||||
|
@ -119,7 +121,13 @@ public:
|
|||
void renderListScrollOverlay(const float opacity, const std::string& text);
|
||||
|
||||
void renderHelpPromptsEarly(); // Used to render HelpPrompts before a fade.
|
||||
void setHelpPrompts(const std::vector<HelpPrompt>& prompts, const HelpStyle& style);
|
||||
void setHelpPrompts(const std::vector<HelpPrompt>& prompts);
|
||||
|
||||
std::map<std::string, std::shared_ptr<ImageComponent>>& getHelpPromptsImageCache()
|
||||
{
|
||||
return sHelpPromptsImageCache;
|
||||
}
|
||||
void clearHelpPromptsImageCache() { sHelpPromptsImageCache.clear(); }
|
||||
|
||||
// GuiInfoPopup notifications.
|
||||
void queueInfoPopup(const std::string& message, const int& duration)
|
||||
|
@ -169,6 +177,30 @@ public:
|
|||
void setChangedTheme() { mChangedTheme = true; }
|
||||
bool getChangedTheme() { return mChangedTheme; }
|
||||
|
||||
void passHelpComponents(std::vector<std::unique_ptr<HelpComponent>>* helpComponents)
|
||||
{
|
||||
mHelpComponents = helpComponents;
|
||||
}
|
||||
|
||||
void passClockComponents(std::vector<std::unique_ptr<DateTimeComponent>>* clockComponents)
|
||||
{
|
||||
mClockComponents = clockComponents;
|
||||
}
|
||||
|
||||
void passSystemStatusComponents(
|
||||
std::vector<std::unique_ptr<SystemStatusComponent>>* systemstatusComponents)
|
||||
{
|
||||
mSystemStatusComponents = systemstatusComponents;
|
||||
}
|
||||
|
||||
void updateSystemStatusComponents()
|
||||
{
|
||||
if (mSystemStatusComponents != nullptr) {
|
||||
for (auto& systemStatusComponent : *mSystemStatusComponents)
|
||||
systemStatusComponent->update(SystemStatus::pollingTime);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Window() noexcept;
|
||||
~Window();
|
||||
|
@ -184,8 +216,13 @@ private:
|
|||
unsigned int color;
|
||||
};
|
||||
|
||||
static inline std::map<std::string, std::shared_ptr<ImageComponent>> sHelpPromptsImageCache;
|
||||
|
||||
Renderer* mRenderer;
|
||||
std::vector<std::unique_ptr<HelpComponent>>* mHelpComponents;
|
||||
std::unique_ptr<HelpComponent> mHelp;
|
||||
std::vector<std::unique_ptr<DateTimeComponent>>* mClockComponents;
|
||||
std::vector<std::unique_ptr<SystemStatusComponent>>* mSystemStatusComponents;
|
||||
std::unique_ptr<ImageComponent> mBackgroundOverlay;
|
||||
std::unique_ptr<ImageComponent> mSplash;
|
||||
std::unique_ptr<TextComponent> mSplashTextScanning;
|
||||
|
@ -238,6 +275,7 @@ private:
|
|||
std::atomic<int> mVideoPlayerCount;
|
||||
|
||||
float mTopScale;
|
||||
int mScaleAccumulator;
|
||||
bool mRenderedHelpPrompts;
|
||||
bool mChangedTheme;
|
||||
};
|
||||
|
|
43
es-core/src/components/BackgroundComponent.cpp
Normal file
43
es-core/src/components/BackgroundComponent.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// ES-DE Frontend
|
||||
// BackgroundComponent.cpp
|
||||
//
|
||||
// Displays a background frame with rounded corners.
|
||||
// Used by menus, popups etc.
|
||||
//
|
||||
|
||||
#include "components/BackgroundComponent.h"
|
||||
|
||||
BackgroundComponent::BackgroundComponent(const glm::vec2 cornerSize)
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mCornerSize {cornerSize}
|
||||
, mFrameColor {mMenuColorFrame}
|
||||
{
|
||||
}
|
||||
|
||||
void BackgroundComponent::fitTo(glm::vec2 size, glm::vec3 position, glm::vec2 padding)
|
||||
{
|
||||
if (padding != glm::vec2 {0.0f, 0.0f}) {
|
||||
size += padding;
|
||||
position.x -= padding.x / 2.0f;
|
||||
position.y -= padding.y / 2.0f;
|
||||
}
|
||||
|
||||
setSize(size);
|
||||
setPosition(position);
|
||||
}
|
||||
|
||||
void BackgroundComponent::render(const glm::mat4& parentTrans)
|
||||
{
|
||||
if (!isVisible())
|
||||
return;
|
||||
|
||||
glm::mat4 trans {parentTrans * getTransform()};
|
||||
|
||||
mRenderer->setMatrix(trans);
|
||||
mRenderer->drawRect(0.0f, 0.0f, mSize.x, mSize.y, mFrameColor, mFrameColor, false, mOpacity,
|
||||
1.0f, Renderer::BlendFactor::SRC_ALPHA,
|
||||
Renderer::BlendFactor::ONE_MINUS_SRC_ALPHA,
|
||||
mCornerSize.x * mRenderer->getScreenResolutionModifier());
|
||||
}
|
34
es-core/src/components/BackgroundComponent.h
Normal file
34
es-core/src/components/BackgroundComponent.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// ES-DE Frontend
|
||||
// BackgroundComponent.h
|
||||
//
|
||||
// Displays a background frame with rounded corners.
|
||||
// Used by menus, popups etc.
|
||||
//
|
||||
|
||||
#ifndef ES_CORE_COMPONENTS_BACKGROUND_COMPONENT_H
|
||||
#define ES_CORE_COMPONENTS_BACKGROUND_COMPONENT_H
|
||||
|
||||
#include "GuiComponent.h"
|
||||
#include "renderers/Renderer.h"
|
||||
|
||||
class BackgroundComponent : public GuiComponent
|
||||
{
|
||||
public:
|
||||
BackgroundComponent(const glm::vec2 cornerSize = glm::vec2 {30.0f, 30.0f});
|
||||
|
||||
void fitTo(glm::vec2 size,
|
||||
glm::vec3 position = {0.0f, 0.0f, 0.0f},
|
||||
glm::vec2 padding = {0.0f, 0.0f});
|
||||
void setFrameColor(unsigned int frameColor) { mFrameColor = frameColor; }
|
||||
|
||||
void render(const glm::mat4& parentTrans) override;
|
||||
|
||||
private:
|
||||
Renderer* mRenderer;
|
||||
glm::vec2 mCornerSize;
|
||||
unsigned int mFrameColor;
|
||||
};
|
||||
|
||||
#endif // ES_CORE_COMPONENTS_BACKGROUND_COMPONENT_H
|
|
@ -13,7 +13,8 @@
|
|||
#include "utils/LocalizationUtil.h"
|
||||
|
||||
BusyComponent::BusyComponent()
|
||||
: mBackground {":/graphics/frame.png"}
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mBackground {glm::vec2 {16.0f, 16.0f}}
|
||||
, mGrid {glm::ivec2 {5, 3}}
|
||||
{
|
||||
mAnimation = std::make_shared<AnimatedImageComponent>();
|
||||
|
@ -36,10 +37,10 @@ void BusyComponent::onSizeChanged()
|
|||
if (mSize.x == 0.0f || mSize.y == 0.0f)
|
||||
return;
|
||||
|
||||
const float middleSpacerWidth {0.01f * Renderer::getScreenWidth()};
|
||||
const float middleSpacerWidth {0.01f * mRenderer->getScreenWidth()};
|
||||
const float textHeight {mText->getFont()->getLetterHeight()};
|
||||
mText->setSize(0.0f, textHeight);
|
||||
const float textWidth {mText->getSize().x + (4.0f * Renderer::getScreenWidthModifier())};
|
||||
const float textWidth {mText->getSize().x + (4.0f * mRenderer->getScreenWidthModifier())};
|
||||
|
||||
mGrid.setColWidthPerc(1, textHeight / mSize.x); // Animation is square.
|
||||
mGrid.setColWidthPerc(2, middleSpacerWidth / mSize.x);
|
||||
|
@ -47,11 +48,11 @@ void BusyComponent::onSizeChanged()
|
|||
|
||||
mGrid.setRowHeightPerc(1, mText->getFont()->getLetterHeight() / mSize.y);
|
||||
|
||||
mBackground.setCornerSize({16.0f * Renderer::getScreenResolutionModifier(),
|
||||
16.0f * Renderer::getScreenResolutionModifier()});
|
||||
mBackground.fitTo(glm::vec2 {mGrid.getColWidth(1) + mGrid.getColWidth(2) + mGrid.getColWidth(3),
|
||||
textHeight + (2.0f * Renderer::getScreenResolutionModifier())},
|
||||
mAnimation->getPosition(), glm::vec2 {0.0f, 0.0f});
|
||||
textHeight + (2.0f * mRenderer->getScreenResolutionModifier())},
|
||||
mAnimation->getPosition(),
|
||||
glm::vec2 {32.0f * mRenderer->getScreenResolutionModifier(),
|
||||
32.0f * mRenderer->getScreenResolutionModifier()});
|
||||
mBackground.setFrameColor(mMenuColorFrameBusyComponent);
|
||||
|
||||
AnimationFrame BUSY_ANIMATION_FRAMES[] {
|
||||
|
@ -64,8 +65,3 @@ void BusyComponent::onSizeChanged()
|
|||
const AnimationDef animationDef {BUSY_ANIMATION_FRAMES, 4, mMenuColorBusyComponent, true};
|
||||
mAnimation->load(&animationDef);
|
||||
}
|
||||
|
||||
void BusyComponent::reset()
|
||||
{
|
||||
// mAnimation->reset();
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
#define ES_CORE_COMPONENTS_BUSY_COMPONENT_H
|
||||
|
||||
#include "GuiComponent.h"
|
||||
#include "components/BackgroundComponent.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
#include "components/NinePatchComponent.h"
|
||||
#include "components/TextComponent.h"
|
||||
|
||||
class AnimatedImageComponent;
|
||||
|
@ -25,10 +25,9 @@ public:
|
|||
void setText(const std::string& text) { mText->setText(text, true); }
|
||||
void onSizeChanged() override;
|
||||
|
||||
void reset(); // Reset to frame 0.
|
||||
|
||||
private:
|
||||
NinePatchComponent mBackground;
|
||||
Renderer* mRenderer;
|
||||
BackgroundComponent mBackground;
|
||||
ComponentGrid mGrid;
|
||||
|
||||
std::shared_ptr<AnimatedImageComponent> mAnimation;
|
||||
|
|
|
@ -106,7 +106,6 @@ void ComponentGrid::setEntry(const std::shared_ptr<GuiComponent>& comp,
|
|||
{
|
||||
assert(pos.x >= 0 && pos.x < mGridSize.x && pos.y >= 0 && pos.y < mGridSize.y);
|
||||
assert(comp != nullptr);
|
||||
assert(comp->getParent() == nullptr);
|
||||
comp->setAutoCalcExtent(autoCalcExtent);
|
||||
|
||||
GridEntry entry {pos, size, comp, canFocus, resize, updateType, border};
|
||||
|
|
|
@ -239,9 +239,10 @@ void ComponentList::render(const glm::mat4& parentTrans)
|
|||
return;
|
||||
|
||||
glm::mat4 trans {parentTrans * getTransform()};
|
||||
int overflow {(static_cast<int>(std::round(mSize.y)) % static_cast<int>(mRowHeight))};
|
||||
|
||||
// Clip everything to be inside our bounds.
|
||||
glm::vec3 dim {mSize.x, mSize.y, 0.0f};
|
||||
glm::vec3 dim {mSize.x, mSize.y - overflow, 0.0f};
|
||||
dim.x = (trans[0].x * dim.x + trans[3].x) - trans[3].x;
|
||||
dim.y = (trans[1].y * dim.y + trans[3].y) - trans[3].y;
|
||||
|
||||
|
|
|
@ -16,7 +16,15 @@
|
|||
#include "utils/StringUtil.h"
|
||||
|
||||
DateTimeComponent::DateTimeComponent()
|
||||
: mDisplayRelative {false}
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mClockAccumulator {0}
|
||||
, mClockMode {false}
|
||||
, mDisplayRelative {false}
|
||||
, mBackgroundHorizontalPadding {0.0f, 0.0f}
|
||||
, mBackgroundVerticalPadding {0.0f, 0.0f}
|
||||
, mClockBgColor {0x00000000}
|
||||
, mClockBgColorEnd {0x00000000}
|
||||
, mClockColorGradientHorizontal {true}
|
||||
{
|
||||
// ISO 8601 date format.
|
||||
setFormat("%Y-%m-%d");
|
||||
|
@ -32,7 +40,14 @@ DateTimeComponent::DateTimeComponent(const std::string& text,
|
|||
: TextComponent {text, font, color, horizontalAlignment, ALIGN_CENTER, glm::vec2 {1, 0},
|
||||
pos, size, bgcolor}
|
||||
, mRenderer {Renderer::getInstance()}
|
||||
, mClockAccumulator {0}
|
||||
, mClockMode {false}
|
||||
, mDisplayRelative {false}
|
||||
, mBackgroundHorizontalPadding {0.0f, 0.0f}
|
||||
, mBackgroundVerticalPadding {0.0f, 0.0f}
|
||||
, mClockBgColor {0x00000000}
|
||||
, mClockBgColorEnd {0x00000000}
|
||||
, mClockColorGradientHorizontal {true}
|
||||
{
|
||||
// ISO 8601 date format.
|
||||
setFormat("%Y-%m-%d");
|
||||
|
@ -70,6 +85,10 @@ void DateTimeComponent::onTextChanged()
|
|||
|
||||
std::string DateTimeComponent::getDisplayString() const
|
||||
{
|
||||
if (mClockMode)
|
||||
return (Utils::Time::timeToString(Utils::Time::DateTime {Utils::Time::now()}.getTime(),
|
||||
mFormat));
|
||||
|
||||
if (mDisplayRelative) {
|
||||
// Workaround to handle Unix epoch for different time zones.
|
||||
if (mTime.getTime() < 82800) {
|
||||
|
@ -116,8 +135,45 @@ std::string DateTimeComponent::getDisplayString() const
|
|||
return Utils::Time::timeToString(mTime.getTime(), mFormat);
|
||||
}
|
||||
|
||||
void DateTimeComponent::update(int deltaTime)
|
||||
{
|
||||
updateSelf(deltaTime);
|
||||
|
||||
if (!mClockMode || (mClockMode && !Settings::getInstance()->getBool("DisplayClock")))
|
||||
return;
|
||||
|
||||
mClockAccumulator += deltaTime;
|
||||
|
||||
if (mClockAccumulator >= 500) {
|
||||
mClockAccumulator = 0;
|
||||
mTime = Utils::Time::now();
|
||||
const std::string newTime {Utils::Time::timeToString(mTime, mFormat)};
|
||||
// The setValue() function with its text cache rebuild is an expensive operation so we only
|
||||
// call this when the actual date/time string needs updating.
|
||||
if (newTime != mText)
|
||||
setValue(newTime);
|
||||
}
|
||||
}
|
||||
|
||||
void DateTimeComponent::render(const glm::mat4& parentTrans)
|
||||
{
|
||||
if (mClockMode && !Settings::getInstance()->getBool("DisplayClock"))
|
||||
return;
|
||||
|
||||
if (mClockMode && mClockBgColor != 0x00000000) {
|
||||
glm::mat4 trans {parentTrans * getTransform()};
|
||||
trans = glm::translate(trans, glm::vec3 {-mBackgroundHorizontalPadding.x,
|
||||
-mBackgroundVerticalPadding.x, 0.0f});
|
||||
mRenderer->setMatrix(trans);
|
||||
|
||||
mRenderer->drawRect(
|
||||
0.0f, 0.0f, mSize.x + mBackgroundHorizontalPadding.x + mBackgroundHorizontalPadding.y,
|
||||
mSize.y + mBackgroundVerticalPadding.x + mBackgroundVerticalPadding.y, mClockBgColor,
|
||||
mClockBgColorEnd, mClockColorGradientHorizontal, mThemeOpacity, 1.0f,
|
||||
Renderer::BlendFactor::SRC_ALPHA, Renderer::BlendFactor::ONE_MINUS_SRC_ALPHA,
|
||||
mBackgroundCornerRadius);
|
||||
}
|
||||
|
||||
// Render the component.
|
||||
TextComponent::render(parentTrans);
|
||||
}
|
||||
|
@ -128,12 +184,54 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
unsigned int properties)
|
||||
{
|
||||
using namespace ThemeFlags;
|
||||
|
||||
std::string elementType {"datetime"};
|
||||
std::string componentName {"DateTimeComponent"};
|
||||
|
||||
if (element.substr(0, 6) == "clock_") {
|
||||
mClockMode = true;
|
||||
elementType = "clock";
|
||||
componentName = "ClockComponent";
|
||||
// Apply default clock settings as the theme may not define any configuration for it.
|
||||
setFont(Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT));
|
||||
setLineSpacing(1.0f);
|
||||
const glm::vec2 scale {
|
||||
getParent() ? getParent()->getSize() :
|
||||
glm::vec2 {mRenderer->getScreenWidth(), mRenderer->getScreenHeight()}};
|
||||
setPosition(0.018f * scale.x, 0.016f * scale.y);
|
||||
mSize.y = mFont->getLetterHeight();
|
||||
setColor(0xFFFFFFFF);
|
||||
setFormat("%H:%M");
|
||||
}
|
||||
|
||||
GuiComponent::applyTheme(theme, view, element, properties);
|
||||
|
||||
const ThemeData::ThemeElement* elem {theme->getElement(view, element, "datetime")};
|
||||
const ThemeData::ThemeElement* elem {theme->getElement(view, element, elementType)};
|
||||
if (!elem)
|
||||
return;
|
||||
|
||||
if (mClockMode && elem->has("scope")) {
|
||||
const std::string& scope {elem->get<std::string>("scope")};
|
||||
if (scope == "shared") {
|
||||
mComponentScope = ComponentScope::SHARED;
|
||||
}
|
||||
else if (scope == "view") {
|
||||
mComponentScope = ComponentScope::VIEW;
|
||||
}
|
||||
else if (scope == "menu") {
|
||||
mComponentScope = ComponentScope::MENU;
|
||||
}
|
||||
else if (scope == "none") {
|
||||
mComponentScope = ComponentScope::NONE;
|
||||
}
|
||||
else {
|
||||
LOG(LogWarning) << componentName
|
||||
<< ": Invalid theme configuration, property "
|
||||
"\"scope\" for element \""
|
||||
<< element.substr(6) << "\" defined as \"" << scope << "\"";
|
||||
}
|
||||
}
|
||||
|
||||
if (properties & ThemeFlags::POSITION && elem->has("stationary")) {
|
||||
const std::string& stationary {elem->get<std::string>("stationary")};
|
||||
if (stationary == "never")
|
||||
|
@ -150,23 +248,65 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
<< element.substr(9) << "\" defined as \"" << stationary << "\"";
|
||||
}
|
||||
|
||||
if (elem->has("format"))
|
||||
setFormat(elem->get<std::string>("format"));
|
||||
|
||||
if (properties & COLOR && elem->has("color"))
|
||||
setColor(elem->get<unsigned int>("color"));
|
||||
|
||||
setRenderBackground(false);
|
||||
if (properties & COLOR && elem->has("backgroundColor")) {
|
||||
setBackgroundColor(elem->get<unsigned int>("backgroundColor"));
|
||||
setRenderBackground(true);
|
||||
if (mClockMode) {
|
||||
mClockBgColor = elem->get<unsigned int>("backgroundColor");
|
||||
|
||||
if (elem->has("backgroundColorEnd"))
|
||||
mClockBgColorEnd = elem->get<unsigned int>("backgroundColorEnd");
|
||||
else
|
||||
mClockBgColorEnd = mClockBgColor;
|
||||
|
||||
if (elem->has("backgroundGradientType")) {
|
||||
const std::string& backgroundGradientType {
|
||||
elem->get<std::string>("backgroundGradientType")};
|
||||
if (backgroundGradientType == "horizontal") {
|
||||
mClockColorGradientHorizontal = true;
|
||||
}
|
||||
else if (backgroundGradientType == "vertical") {
|
||||
mClockColorGradientHorizontal = false;
|
||||
}
|
||||
else {
|
||||
mClockColorGradientHorizontal = true;
|
||||
LOG(LogWarning) << componentName
|
||||
<< ": Invalid theme configuration, property "
|
||||
"\"backgroundGradientType\" for element \""
|
||||
<< element.substr(6) << "\" defined as \""
|
||||
<< backgroundGradientType << "\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
setBackgroundColor(elem->get<unsigned int>("backgroundColor"));
|
||||
setRenderBackground(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (elem->has("backgroundMargins")) {
|
||||
if (!mClockMode && elem->has("backgroundMargins")) {
|
||||
setBackgroundMargins(glm::clamp(elem->get<glm::vec2>("backgroundMargins"), 0.0f, 0.5f) *
|
||||
mRenderer->getScreenWidth());
|
||||
}
|
||||
|
||||
if (mClockMode && elem->has("backgroundHorizontalPadding")) {
|
||||
const glm::vec2 backgroundHorizontalPadding {
|
||||
glm::clamp(elem->get<glm::vec2>("backgroundHorizontalPadding"), 0.0f, 0.2f)};
|
||||
mBackgroundHorizontalPadding.x =
|
||||
backgroundHorizontalPadding.x * mRenderer->getScreenWidth();
|
||||
mBackgroundHorizontalPadding.y =
|
||||
backgroundHorizontalPadding.y * mRenderer->getScreenWidth();
|
||||
}
|
||||
|
||||
if (mClockMode && elem->has("backgroundVerticalPadding")) {
|
||||
const glm::vec2 backgroundVerticalPadding {
|
||||
glm::clamp(elem->get<glm::vec2>("backgroundVerticalPadding"), 0.0f, 0.2f)};
|
||||
mBackgroundVerticalPadding.x = backgroundVerticalPadding.x * mRenderer->getScreenHeight();
|
||||
mBackgroundVerticalPadding.y = backgroundVerticalPadding.y * mRenderer->getScreenHeight();
|
||||
}
|
||||
|
||||
if (elem->has("backgroundCornerRadius")) {
|
||||
setBackgroundCornerRadius(
|
||||
glm::clamp(elem->get<float>("backgroundCornerRadius"), 0.0f, 0.5f) *
|
||||
|
@ -182,10 +322,11 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
else if (horizontalAlignment == "right")
|
||||
setHorizontalAlignment(ALIGN_RIGHT);
|
||||
else
|
||||
LOG(LogWarning) << "DateTimeComponent: Invalid theme configuration, property "
|
||||
LOG(LogWarning) << componentName
|
||||
<< ": Invalid theme configuration, property "
|
||||
"\"horizontalAlignment\" for element \""
|
||||
<< element.substr(9) << "\" defined as \"" << horizontalAlignment
|
||||
<< "\"";
|
||||
<< element.substr(elementType == "clock" ? 6 : 9) << "\" defined as \""
|
||||
<< horizontalAlignment << "\"";
|
||||
}
|
||||
|
||||
if (properties & ALIGNMENT && elem->has("verticalAlignment")) {
|
||||
|
@ -197,9 +338,11 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
else if (verticalAlignment == "bottom")
|
||||
setVerticalAlignment(ALIGN_BOTTOM);
|
||||
else
|
||||
LOG(LogWarning) << "DateTimeComponent: Invalid theme configuration, property "
|
||||
LOG(LogWarning) << componentName
|
||||
<< ": Invalid theme configuration, property "
|
||||
"\"verticalAlignment\" for element \""
|
||||
<< element.substr(9) << "\" defined as \"" << verticalAlignment << "\"";
|
||||
<< element.substr(elementType == "clock" ? 6 : 9) << "\" defined as \""
|
||||
<< verticalAlignment << "\"";
|
||||
}
|
||||
|
||||
if (properties & METADATA && elem->has("metadata")) {
|
||||
|
@ -240,7 +383,8 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
setCapitalize(true);
|
||||
}
|
||||
else if (letterCase != "none") {
|
||||
LOG(LogWarning) << "DateTimeComponent: Invalid theme configuration, property "
|
||||
LOG(LogWarning) << componentName
|
||||
<< ": Invalid theme configuration, property "
|
||||
"\"letterCase\" for element \""
|
||||
<< element.substr(9) << "\" defined as \"" << letterCase << "\"";
|
||||
}
|
||||
|
@ -265,4 +409,9 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
|
||||
setFont(Font::getFromTheme(elem, properties, mFont, maxHeight));
|
||||
mSize = glm::round(mSize);
|
||||
|
||||
if (elem->has("format"))
|
||||
setFormat(elem->get<std::string>("format"));
|
||||
else if (mClockMode)
|
||||
setFormat("%H:%M");
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
glm::vec2 size = {0.0f, 0.0f},
|
||||
unsigned int bgcolor = 0x00000000);
|
||||
|
||||
void update(int deltaTime) override;
|
||||
void render(const glm::mat4& parentTrans) override;
|
||||
|
||||
void setValue(const std::string& val) override;
|
||||
|
@ -49,10 +50,17 @@ private:
|
|||
std::string getDisplayString() const;
|
||||
|
||||
Renderer* mRenderer;
|
||||
int mClockAccumulator;
|
||||
std::string mDefaultValue;
|
||||
Utils::Time::DateTime mTime;
|
||||
std::string mFormat;
|
||||
bool mClockMode;
|
||||
bool mDisplayRelative;
|
||||
glm::vec2 mBackgroundHorizontalPadding;
|
||||
glm::vec2 mBackgroundVerticalPadding;
|
||||
unsigned int mClockBgColor;
|
||||
unsigned int mClockBgColorEnd;
|
||||
bool mClockColorGradientHorizontal;
|
||||
};
|
||||
|
||||
#endif // ES_CORE_COMPONENTS_DATE_TIME_COMPONENT_H
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue