Large code cleanup and code documentation update.

The initial code cleanup of es-app is now complete as of this commit.
This commit is contained in:
Leon Styhre 2020-06-23 20:07:00 +02:00
parent d29e16778d
commit 6b62065595
41 changed files with 2371 additions and 2289 deletions

View file

@ -18,14 +18,13 @@ Some key points:
* Comments should be proper sentences, starting with a capital letter and ending with a dot
* Use K&R placements of braces, read the Linux Kernel coding style document for clarifications
* Always use spaces between keywords and opening brackets, i.e. `if ()`, `for ()`, `while ()` etc.
* Use `std::string` instead of `char *` or `char []` unless there is a very specific reason requiring the latter
* Use `std::string` instead of `char *` or `char []` unless there is a specific reason requiring the latter
* If the arguments (and initializer list) for a function or class exceeds 4 items, arrange them vertically to make the code easier to read
* Always declare one variable per line, never combine multiple declarations of the same type
* Name local variables with the first word in small letters and the proceeding words starting with capital letters, e.g. myExampleVariable
* Name member variables starting with a small 'm', e.g. mMyMemberVariable
* Don't pad variable declarations with spaces to make them align in columns, I'm sure it's well intended but it looks terrible
* Use the same naming convention for functions as for local variables, e.g. someFunction()
* Inline functions can be used but don't overdo it by using them for functions that won't be called very frequently
* Inline functions makes perfect sense to use, but don't overdo it by using them for functions that won't be called very frequently
* Never put more than one statement on a single line, except for lambda expressions
* Avoid overoptimizations, especially if it sacrifices readability, makes the code hard to expand on or is error prone
* For the rest, check the code and have fun! :)
@ -34,7 +33,7 @@ Some key points:
Development Environment
=======================
EmulationStation-DE is developed and compiled using GCC and GDB. \
EmulationStation-DE is developed and compiled using GCC and GDB. Any code editor can be used of course, I use [VSCodium](https://vscodium.com). \
For debugging purposes, starting the application like this could make sense:
`emulationstation --windowed --debug --resolution 1280 720`

View file

@ -8,35 +8,35 @@ The code has a few dependencies. For building, you'll need CMake and development
**On Debian/Ubuntu:**
All of the required packages can be easily installed with `apt-get`:
```bash
sudo apt-get install libsdl2-dev libfreeimage-dev libfreetype6-dev libcurl4-openssl-dev rapidjson-dev \
libasound2-dev libgl1-mesa-dev build-essential cmake fonts-droid-fallback libvlc-dev \
```
sudo apt-get install libsdl2-dev libfreeimage-dev libfreetype6-dev libcurl4-openssl-dev rapidjson-dev
libasound2-dev libgl1-mesa-dev build-essential cmake fonts-droid-fallback libvlc-dev
libvlccore-dev vlc-bin
```
**On Fedora:**
For this operating system, use `dnf` (with rpmfusion activated) :
```bash
sudo dnf install SDL2-devel freeimage-devel freetype-devel curl-devel \
alsa-lib-devel mesa-libGL-devel cmake \
```
sudo dnf install SDL2-devel freeimage-devel freetype-devel curl-devel
alsa-lib-devel mesa-libGL-devel cmake
vlc-devel rapidjson-devel
```
To checkout the source, run the following:
```bash
```
git clone https://gitlab.com/leonstyhre/emulationstation-de
```
Then generate and build the Makefile using CMake:
Then generate the Makefile and build the software like this:
```bash
```
cd emulationstation-de
cmake -DOpenGL_GL_PREFERENCE=GLVND .
make
```
NOTE: to generate a `Debug` build on Unix/Linux, run this:
```bash
NOTE: to generate a `Debug` build on Unix/Linux, run this instead:
```
cmake -DOpenGL_GL_PREFERENCE=GLVND -DCMAKE_BUILD_TYPE=Debug .
make
```
@ -65,9 +65,9 @@ Configuring
**~/.emulationstation/es_systems.cfg:**
EmulationStation Desktop Edition ships with a comprehensive `es_systems.cfg` configuration file, and as the logic is to use a `%ROMPATH%` variable to locate the ROM files (with a corresponding setting in `es_settings.cfg`), normally you shouldn't need to modify this file to the same extent as previous versions of EmulationStation. Still, see below in this document on how to adjust es_systems.cfg file if required.
EmulationStation Desktop Edition ships with a comprehensive `es_systems.cfg` configuration file, and as the logic is to use a `%ROMPATH%` variable to locate the ROM files (with a corresponding setting in `es_settings.cfg`), normally you shouldn't need to modify this file to the same extent as previous versions of EmulationStation. Still, see below in this document on how to adjust the es_systems.cfg file if required.
Upon first startup of the application, if there is no es_systems.cfg file present, it will be copied from the template directory of the resources directory. This directory is located in the installation path of the application, for instance `/usr/local/share/emulationstation/resources/templates`.
Upon first startup of the application, if there is no es_systems.cfg file present, it will be copied from the template subdirectory inside the resources directory. This directory is located in the installation path of the application, for instance `/usr/local/share/emulationstation/resources/templates`.
The template file will be copied to `~/.emulationstation/es_systems.cfg`. `~` is `$HOME` on Linux, and `%HOMEPATH%` on Windows.
@ -80,7 +80,7 @@ The exception would be the ROMDirectory setting as ES won't start if no ROM file
**Setting the ROM directory:**
By default, ES looks in `~/ROMs` for the ROM files, where they are expected to be grouped into directories corresponding to the systems, for example:
By default, ES looks in `~/ROMs` for the ROM files, where they are expected to be grouped into directories corresponding to the game systems, for example:
```
user@computer:~ROMs$ ls -1
@ -99,6 +99,7 @@ Keep in mind though that you still need to group the ROMs into directories corre
**Keep in mind that you'll have to set up your emulator separately from EmulationStation!**
**~/.emulationstation/es_input.cfg:**
When you first start EmulationStation, you will be prompted to configure an input device. The process is thus:
1. Hold a button on the device you want to configure. This includes the keyboard.
@ -116,7 +117,10 @@ The new configuration will be added to the `~/.emulationstation/es_input.cfg` fi
**If your controller stops working, you can delete the `~/.emulationstation/es_input.cfg` file to make the input configuration screen re-appear on the next run.**
You can use `--help` or `-h` to view a list of command-line options. Briefly outlined here:
**Command line arguments:**
You can use `--help` or `-h` to view a list of command line options. Briefly outlined here:
```
--resolution [width] [height] Try to force a particular resolution
--gamelist-only Skip automatic game ROM search, only read from gamelist.xml
@ -147,16 +151,16 @@ As you can see above, you can override the home directory path using the `--home
Writing an es_systems.cfg
=========================
The `es_systems.cfg` file contains the system configuration data for EmulationStation, written in XML. \
The es_systems.cfg file contains the system configuration data for EmulationStation, written in XML format. \
This tells EmulationStation what systems you have, what platform they correspond to (for scraping), and where the games are located.
ES will only check in your home directory for an `es_systems.cfg` file, for example `~/.emulationstation/es_systems.cfg`.
ES will only check in your home directory for an es_systems.cfg file, for example `~/.emulationstation/es_systems.cfg`.
The order EmulationStation displays systems reflects the order you define them in. In the case of the default `es_systems.cfg` file, the systems are listed in alphabetical order.
The order EmulationStation displays systems reflects the order you define them in. In the case of the default es_systems.cfg file, the systems are listed in alphabetical order.
**NOTE:** A system *must* have at least one game present in its "path" directory, or ES will ignore it! If no valid systems are found, ES will report an error and quit!
Here's an overview of the `es_systems.cfg` file layout:
Here's an overview of the file layout:
```xml
<?xml version="1.0"?>
@ -194,23 +198,25 @@ Here's an overview of the `es_systems.cfg` file layout:
</systemList>
```
The following variables are replaced by ES in launch commands:
`%ROMPATH%` - Replaced with the path defined for the setting ROMDirectory in es_settings.cfg.
The following variables are expanded by ES for the `command` tag:
`%ROM%` - Replaced with absolute path to the selected ROM, with most Bash special characters escaped with a backslash.
`%BASENAME%` - Replaced with the "base" name of the path to the selected ROM. For example, a path of "/foo/bar.rom", this tag would be "bar". This tag is useful for setting up AdvanceMAME.
`%BASENAME%` - Replaced with the "base" name of the path to the selected ROM. For example, a path of `/foo/bar.rom`, this tag would be `bar`. This tag is useful for setting up AdvanceMAME.
`%ROM_RAW%` - 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.
For the `path` tag, the following variable is expanded by ES:
`%ROMPATH%` - Replaced with the path defined for the setting ROMDirectory in `es_settings.cfg`.
gamelist.xml
============
The gamelist.xml file for a system defines metadata for games, such as a name, description, release date, and rating.
As of the fork to EmulationStation Desktop Edition, game media information no longer needs to be defined in the `gamelist.xml` files. Instead the application will look for any media matching the ROM filename. The media path where to look for game art is configurable either manually in `es_settings.cfg` or via the GUI. If configured manually in `es_settings.cfg`, it looks something like this:
As of the fork to EmulationStation Desktop Edition, game media information no longer needs to be defined in the gamelist.xml files. Instead the application will look for any media matching the ROM filename. The media path where to look for game art is configurable either manually in `es_settings.cfg` or via the GUI. If configured manually in es_settings.cfg, it looks something like this:
`<string name="MediaDirectory" value="~/games/images/emulationstation" />`

View file

@ -3,7 +3,7 @@ EmulationStation Desktop Edition
EmulationStation Desktop Edition is a cross-platform graphical front-end for emulators with controller and keyboard navigation.
This is a fork intended for use primarily on desktop computers where EmulationStation is not the primary interface for the computer. As such, this software will not provide full control over emulator settings or emulator button mappings or provide system utility functions and similar. Instead it's assumed that the emulators and the overall environment has been properly configured upfront.
The difference to other versions of EmulationStation is that this fork is intended for use primarily on desktop computers where it's not the primary interface for the computer. As such, this version does not aim to provide full control over emulator settings or emulator button mappings, or include system administration functions and similar. Instead it's assumed that the emulators and the overall environment has been properly configured upfront.
The software comes preconfigured for use primarily with [RetroArch](https://www.retroarch.com), although this can certainly be changed as all emulator settings are fully configurable, even on a per-game basis.
@ -13,24 +13,25 @@ Apart from code commits, help is especially needed for thorough testing of the s
It's impossible for me to test every game system (RBSimple-DE has support for almost a 100 different systems!) so it would be especially useful to hear about any issues with starting games using the default es_systems.cfg configuration file and also if there are any issues regarding scraping for certain systems.
In general, a review of the [es_systems.cfg](resources/templates/es_systems.cfg_unix) file including the supported file extensions would be great.
In general, a review of the [es_systems.cfg](resources/templates/es_systems.cfg_unix) file including the supported file extensions would be great!
As for RBSimple-DE there are quite some missing graphic files and other customizations for a number of game systems. \
Check out [MISSING.md](themes/rbsimple-DE/MISSING.md) for more details of what needs to be added.
Check out [MISSING.md](themes/rbsimple-DE/MISSING.md) for more details of what needs to be added or updated.
Finally, if someone could make a proper port to the Macintosh Operating System, that would be great as then all of the three major desktop operating systems would be supported. There is some code present specifically for macOS but I've been unable to test it.
Finally, if someone could make a proper port to macOS, that would be great as then all of the three major desktop operating systems would be supported. There is some code present specifically for macOS but I've been unable to test it. And according to the code comments, some things seem to be missing altogether for this operating system, so it may take some effort.
General information
===================
[NEWS.md](NEWS.md) contains information about new functionality, improvements and bug fixes. An overview of all previous versions will be included here as well.
[NEWS.md](NEWS.md) contains information about new functionality, improvements and bug fixes. \
(An overview of all previous versions will be included here as well.)
[INSTALL.md](INSTALL.md) provides details on how to build and configure the application.
[DEVNOTES.md](DEVNOTES.md) is the place to go if you're interested in participating in the development of EmulationStation Desktop Edition.
What it can do
==============
Overview of the software
========================

View file

@ -285,8 +285,8 @@ Starting EmulationStation with the --debug flag will provide feedback on whether
providing an error message if any of the .wav sound files could not be loaded.
Example debug output: \
May 12 21:12:37 lvl2: Sound::getFromTheme() looking for [all.selectSound] \
May 12 21:12:37 lvl2: [selectSound] found, ready to play sound file
`May 12 21:12:37 lvl2: Sound::getFromTheme() looking for [all.selectSound]` \
`May 12 21:12:37 lvl2: [selectSound] found, ready to play sound file`
Example `navigationsounds.xml`, to be included from the main theme file:

View file

@ -75,8 +75,8 @@ CollectionSystemManager::CollectionSystemManager(Window* window) : mWindow(windo
mIsEditingCustom = false;
mEditingCollection = "Favorites";
mEditingCollectionSystemData = NULL;
mCustomCollectionsBundle = NULL;
mEditingCollectionSystemData = nullptr;
mCustomCollectionsBundle = nullptr;
}
CollectionSystemManager::~CollectionSystemManager()

View file

@ -304,7 +304,7 @@ FileData* FileData::getSourceFileData()
void FileData::addChild(FileData* file)
{
assert(mType == FOLDER);
assert(file->getParent() == NULL);
assert(file->getParent() == nullptr);
const std::string key = file->getKey();
if (mChildrenByFilename.find(key) == mChildrenByFilename.cend()) {
@ -321,7 +321,7 @@ void FileData::removeChild(FileData* file)
mChildrenByFilename.erase(file->getKey());
for (auto it = mChildren.cbegin(); it != mChildren.cend(); it++) {
if (*it == file) {
file->mParent = NULL;
file->mParent = nullptr;
mChildren.erase(it);
return;
}
@ -491,7 +491,7 @@ CollectionFileData::CollectionFileData(FileData* file, SystemData* system)
// We use this constructor to create a clone of the filedata, and change its system.
mSourceFileData = file->getSourceFileData();
refreshMetadata();
mParent = NULL;
mParent = nullptr;
metadata = mSourceFileData->metadata;
mSystemName = mSourceFileData->getSystem()->getName();
}
@ -501,7 +501,7 @@ CollectionFileData::~CollectionFileData()
// Need to remove collection file data at the collection object destructor.
if (mParent)
mParent->removeChild(this);
mParent = NULL;
mParent = nullptr;
}
std::string CollectionFileData::getKey() {

View file

@ -1,7 +1,7 @@
//
// PlatformId.h
//
// Index of all supported platforms.
// Index of all supported systems/platforms.
//
#include "PlatformId.h"
@ -89,7 +89,7 @@ namespace PlatformIds
PlatformId getPlatformId(const char* str)
{
if (str == NULL)
if (str == nullptr)
return PLATFORM_UNKNOWN;
for (unsigned int i = 1; i < PLATFORM_COUNT; i++) {

View file

@ -1,7 +1,7 @@
//
// PlatformId.h
//
// Index of all supported platforms.
// Index of all supported systems/platforms.
//
#pragma once

View file

@ -270,7 +270,7 @@ bool SystemData::loadConfig()
// If there appears to be an actual platform ID supplied
// but it didn't match the list, generate a warning.
if (str != NULL && str[0] != '\0' && platformId == PlatformIds::PLATFORM_UNKNOWN)
if (str != nullptr && str[0] != '\0' && platformId == PlatformIds::PLATFORM_UNKNOWN)
LOG(LogWarning) << " Unknown platform for system \"" << name << "\" (platform \""
<< str << "\" from list \"" << platformList << "\")";
else if (platformId != PlatformIds::PLATFORM_UNKNOWN)
@ -499,7 +499,7 @@ SystemData* SystemData::getRandomSystem()
}
// If we end up here, there is no valid system.
return NULL;
return nullptr;
}
FileData* SystemData::getRandomGame()
@ -510,7 +510,7 @@ FileData* SystemData::getRandomGame()
// Get a random number in range.
if (total == 0)
return NULL;
return nullptr;
target = (int)Math::round((std::rand() / (float)RAND_MAX) * (total - 1));
return list.at(target);

View file

@ -1,3 +1,10 @@
//
// SystemScreenSaver.cpp
//
// Screensaver, supporting the following modes:
// Dim, black, video, slideshow.
//
#include "SystemScreenSaver.h"
#ifdef _RPI_
@ -17,9 +24,10 @@
#include <time.h>
#define FADE_TIME 300
SystemScreenSaver::SystemScreenSaver(Window* window) :
mVideoScreensaver(NULL),
mImageScreensaver(NULL),
SystemScreenSaver::SystemScreenSaver(
Window* window)
: mVideoScreensaver(nullptr),
mImageScreensaver(nullptr),
mWindow(window),
mVideosCounted(false),
mVideoCount(0),
@ -30,30 +38,29 @@ SystemScreenSaver::SystemScreenSaver(Window* window) :
mTimer(0),
mSystemName(""),
mGameName(""),
mCurrentGame(NULL),
mCurrentGame(nullptr),
mStopBackgroundAudio(true)
{
mWindow->setScreenSaver(this);
std::string path = getTitleFolder();
if(!Utils::FileSystem::exists(path))
if (!Utils::FileSystem::exists(path))
Utils::FileSystem::createDirectory(path);
srand((unsigned int)time(NULL));
srand((unsigned int)time(nullptr));
mVideoChangeTime = 30000;
}
SystemScreenSaver::~SystemScreenSaver()
{
// Delete subtitle file, if existing
// Delete subtitle file, if it exists.
remove(getTitlePath().c_str());
mCurrentGame = NULL;
mCurrentGame = nullptr;
delete mVideoScreensaver;
delete mImageScreensaver;
}
bool SystemScreenSaver::allowSleep()
{
//return false;
return ((mVideoScreensaver == NULL) && (mImageScreensaver == NULL));
return ((mVideoScreensaver == nullptr) && (mImageScreensaver == nullptr));
}
bool SystemScreenSaver::isScreenSaverActive()
@ -64,50 +71,48 @@ bool SystemScreenSaver::isScreenSaverActive()
void SystemScreenSaver::startScreenSaver()
{
std::string screensaver_behavior = Settings::getInstance()->getString("ScreenSaverBehavior");
if (!mVideoScreensaver && (screensaver_behavior == "random video"))
{
// Configure to fade out the windows, Skip Fading if Instant mode
if (!mVideoScreensaver && (screensaver_behavior == "random video")) {
// Configure to fade out the windows, skip fading if mode is set to Instant.
mState = PowerSaver::getMode() == PowerSaver::INSTANT
? STATE_SCREENSAVER_ACTIVE
: STATE_FADE_OUT_WINDOW;
mVideoChangeTime = Settings::getInstance()->getInt("ScreenSaverSwapVideoTimeout");
mOpacity = 0.0f;
// Load a random video
// Load a random video.
std::string path = "";
pickRandomVideo(path);
int retry = 200;
while(retry > 0 && ((path.empty() || !Utils::FileSystem::exists(path)) || mCurrentGame == NULL))
{
while (retry > 0 && ((path.empty() || !Utils::FileSystem::exists(path)) ||
mCurrentGame == nullptr)) {
retry--;
pickRandomVideo(path);
}
if (!path.empty() && Utils::FileSystem::exists(path))
{
#ifdef _RPI_
if (!path.empty() && Utils::FileSystem::exists(path)) {
#ifdef _RPI_
// Create the correct type of video component
if (Settings::getInstance()->getBool("ScreenSaverOmxPlayer"))
mVideoScreensaver = new VideoPlayerComponent(mWindow, getTitlePath());
else
mVideoScreensaver = new VideoVlcComponent(mWindow, getTitlePath());
#else
#else
mVideoScreensaver = new VideoVlcComponent(mWindow, getTitlePath());
#endif
#endif
mVideoScreensaver->topWindow(true);
mVideoScreensaver->setOrigin(0.5f, 0.5f);
mVideoScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f);
mVideoScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f,
Renderer::getScreenHeight() / 2.0f);
if (Settings::getInstance()->getBool("StretchVideoOnScreenSaver"))
{
mVideoScreensaver->setResize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
}
mVideoScreensaver->setResize((float)Renderer::getScreenWidth(),
(float)Renderer::getScreenHeight());
else
{
mVideoScreensaver->setMaxSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
}
mVideoScreensaver->setMaxSize((float)Renderer::getScreenWidth(),
(float)Renderer::getScreenHeight());
mVideoScreensaver->setVideo(path);
mVideoScreensaver->setScreensaverMode(true);
mVideoScreensaver->onShow();
@ -116,54 +121,47 @@ void SystemScreenSaver::startScreenSaver()
return;
}
}
else if (screensaver_behavior == "slideshow")
{
// Configure to fade out the windows, Skip Fading if Instant mode
else if (screensaver_behavior == "slideshow") {
// Configure to fade out the windows, skip fading if mode is set to Instant.
mState = PowerSaver::getMode() == PowerSaver::INSTANT
? STATE_SCREENSAVER_ACTIVE
: STATE_FADE_OUT_WINDOW;
mVideoChangeTime = Settings::getInstance()->getInt("ScreenSaverSwapImageTimeout");
mOpacity = 0.0f;
// Load a random image
// Load a random image.
std::string path = "";
if (Settings::getInstance()->getBool("SlideshowScreenSaverCustomImageSource"))
{
if (Settings::getInstance()->getBool("SlideshowScreenSaverCustomImageSource")) {
pickRandomCustomImage(path);
// Custom images are not tied to the game list
mCurrentGame = NULL;
// Custom images are not tied to the game list.
mCurrentGame = nullptr;
}
else
{
else {
pickRandomGameListImage(path);
}
if (!mImageScreensaver)
{
mImageScreensaver = new ImageComponent(mWindow, false, false);
}
mTimer = 0;
mImageScreensaver->setImage(path);
mImageScreensaver->setOrigin(0.5f, 0.5f);
mImageScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f);
mImageScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f,
Renderer::getScreenHeight() / 2.0f);
if (Settings::getInstance()->getBool("SlideshowScreenSaverStretch"))
{
mImageScreensaver->setResize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
}
mImageScreensaver->setResize((float)Renderer::getScreenWidth(),
(float)Renderer::getScreenHeight());
else
{
mImageScreensaver->setMaxSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
}
mImageScreensaver->setMaxSize((float)Renderer::getScreenWidth(),
(float)Renderer::getScreenHeight());
std::string bg_audio_file = Settings::getInstance()->getString("SlideshowScreenSaverBackgroundAudioFile");
if ((!mBackgroundAudio) && (bg_audio_file != ""))
{
if (Utils::FileSystem::exists(bg_audio_file))
{
// paused PS so that the background audio keeps playing
std::string bg_audio_file = Settings::getInstance()->
getString("SlideshowScreenSaverBackgroundAudioFile");
if ((!mBackgroundAudio) && (bg_audio_file != "")) {
if (Utils::FileSystem::exists(bg_audio_file)) {
// Pause PowerSaver so that the background audio keeps playing.
PowerSaver::pause();
mBackgroundAudio = Sound::get(bg_audio_file);
mBackgroundAudio->play();
@ -174,30 +172,29 @@ void SystemScreenSaver::startScreenSaver()
mTimer = 0;
return;
}
// No videos. Just use a standard screensaver
// No videos. Just use a standard screensaver.
mState = STATE_SCREENSAVER_ACTIVE;
mCurrentGame = NULL;
mCurrentGame = nullptr;
}
void SystemScreenSaver::stopScreenSaver()
{
if ((mBackgroundAudio) && (mStopBackgroundAudio))
{
if ((mBackgroundAudio) && (mStopBackgroundAudio)) {
mBackgroundAudio->stop();
mBackgroundAudio.reset();
// if we were playing audio, we paused PS
// If we were playing audio, we paused PowerSaver.
PowerSaver::resume();
}
// so that we stop the background audio next time, unless we're restarting the screensaver
// So that we stop the background audio next time, unless we're restarting the screensaver.
mStopBackgroundAudio = true;
delete mVideoScreensaver;
mVideoScreensaver = NULL;
mVideoScreensaver = nullptr;
delete mImageScreensaver;
mImageScreensaver = NULL;
mImageScreensaver = nullptr;
// we need this to loop through different videos
// We need this to loop through different videos.
mState = STATE_INACTIVE;
PowerSaver::runningScreenSaver(false);
}
@ -205,30 +202,27 @@ void SystemScreenSaver::stopScreenSaver()
void SystemScreenSaver::renderScreenSaver()
{
std::string screensaver_behavior = Settings::getInstance()->getString("ScreenSaverBehavior");
if (mVideoScreensaver && screensaver_behavior == "random video")
{
// Render black background
if (mVideoScreensaver && screensaver_behavior == "random video") {
// Render black background.
Renderer::setMatrix(Transform4x4f::Identity());
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0x000000FF, 0x000000FF);
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
Renderer::getScreenHeight(), 0x000000FF, 0x000000FF);
// Only render the video if the state requires it
if ((int)mState >= STATE_FADE_IN_VIDEO)
{
// Only render the video if the state requires it.
if ((int)mState >= STATE_FADE_IN_VIDEO) {
Transform4x4f transform = Transform4x4f::Identity();
mVideoScreensaver->render(transform);
}
}
else if (mImageScreensaver && screensaver_behavior == "slideshow")
{
// Render black background
else if (mImageScreensaver && screensaver_behavior == "slideshow") {
// Render black background.
Renderer::setMatrix(Transform4x4f::Identity());
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0x000000FF, 0x000000FF);
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
Renderer::getScreenHeight(), 0x000000FF, 0x000000FF);
// Only render the video if the state requires it
if ((int)mState >= STATE_FADE_IN_VIDEO)
{
if (mImageScreensaver->hasImage())
{
// Only render the video if the state requires it.
if ((int)mState >= STATE_FADE_IN_VIDEO) {
if (mImageScreensaver->hasImage()) {
mImageScreensaver->setOpacity(255- (unsigned char) (mOpacity * 255));
Transform4x4f transform = Transform4x4f::Identity();
@ -236,20 +230,18 @@ void SystemScreenSaver::renderScreenSaver()
}
}
// Check if we need to restart the background audio
if ((mBackgroundAudio) && (Settings::getInstance()->getString("SlideshowScreenSaverBackgroundAudioFile") != ""))
{
// Check if we need to restart the background audio.
if ((mBackgroundAudio) && (Settings::getInstance()->
getString("SlideshowScreenSaverBackgroundAudioFile") != "")) {
if (!mBackgroundAudio->isPlaying())
{
mBackgroundAudio->play();
}
}
}
else if (mState != STATE_INACTIVE)
{
else if (mState != STATE_INACTIVE) {
Renderer::setMatrix(Transform4x4f::Identity());
unsigned char color = screensaver_behavior == "dim" ? 0x000000A0 : 0x000000FF;
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), color, color);
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
Renderer::getScreenHeight(), color, color);
}
}
@ -257,9 +249,9 @@ unsigned long SystemScreenSaver::countGameListNodes(const char *nodeName)
{
unsigned long nodeCount = 0;
std::vector<SystemData*>::const_iterator it;
for (it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend(); ++it)
{
// We only want nodes from game systems that are not collections
for (it = SystemData::sSystemVector.cbegin();
it != SystemData::sSystemVector.cend(); ++it) {
// We only want nodes from game systems that are not collections.
if (!(*it)->isGameSystem() || (*it)->isCollection())
continue;
@ -267,23 +259,20 @@ unsigned long SystemScreenSaver::countGameListNodes(const char *nodeName)
FileType type = GAME;
std::vector<FileData*> allFiles = rootFileData->getFilesRecursive(type, true);
std::vector<FileData*>::const_iterator itf; // declare an iterator to a vector of strings
std::vector<FileData*>::const_iterator itf; // Declare an iterator to a vector of strings.
for(itf=allFiles.cbegin() ; itf < allFiles.cend(); itf++) {
for (itf=allFiles.cbegin() ; itf < allFiles.cend(); itf++) {
if ((strcmp(nodeName, "video") == 0 && (*itf)->getVideoPath() != "") ||
(strcmp(nodeName, "image") == 0 && (*itf)->getImagePath() != ""))
{
nodeCount++;
}
}
}
return nodeCount;
}
void SystemScreenSaver::countVideos()
{
if (!mVideosCounted)
{
if (!mVideosCounted) {
mVideoCount = countGameListNodes("video");
mVideosCounted = true;
}
@ -291,19 +280,19 @@ void SystemScreenSaver::countVideos()
void SystemScreenSaver::countImages()
{
if (!mImagesCounted)
{
if (!mImagesCounted) {
mImageCount = countGameListNodes("image");
mImagesCounted = true;
}
}
void SystemScreenSaver::pickGameListNode(unsigned long index, const char *nodeName, std::string& path)
void SystemScreenSaver::pickGameListNode(unsigned long index,
const char *nodeName, std::string& path)
{
std::vector<SystemData*>::const_iterator it;
for (it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend(); ++it)
{
// We only want nodes from game systems that are not collections
for (it = SystemData::sSystemVector.cbegin();
it != SystemData::sSystemVector.cend(); ++it) {
// We only want nodes from game systems that are not collections.
if (!(*it)->isGameSystem() || (*it)->isCollection())
continue;
@ -311,15 +300,13 @@ void SystemScreenSaver::pickGameListNode(unsigned long index, const char *nodeNa
FileType type = GAME;
std::vector<FileData*> allFiles = rootFileData->getFilesRecursive(type, true);
std::vector<FileData*>::const_iterator itf; // declare an iterator to a vector of strings
std::vector<FileData*>::const_iterator itf; // Declare an iterator to a vector of strings.
for(itf=allFiles.cbegin() ; itf < allFiles.cend(); itf++) {
for (itf=allFiles.cbegin() ; itf < allFiles.cend(); itf++) {
if ((strcmp(nodeName, "video") == 0 && (*itf)->getVideoPath() != "") ||
(strcmp(nodeName, "image") == 0 && (*itf)->getImagePath() != ""))
{
if (index-- == 0)
{
// We have it
(strcmp(nodeName, "image") == 0 && (*itf)->getImagePath() != "")) {
if (index-- == 0) {
// We have it.
path = "";
if (strcmp(nodeName, "video") == 0)
path = (*itf)->getVideoPath();
@ -329,10 +316,11 @@ void SystemScreenSaver::pickGameListNode(unsigned long index, const char *nodeNa
mGameName = (*itf)->getName();
mCurrentGame = (*itf);
// end of getting FileData
// End of getting FileData.
if (Settings::getInstance()->getString("ScreenSaverGameInfo") != "never")
writeSubtitle(mGameName.c_str(), mSystemName.c_str(),
(Settings::getInstance()->getString("ScreenSaverGameInfo") == "always"));
(Settings::getInstance()->getString("ScreenSaverGameInfo") ==
"always"));
return;
}
}
@ -343,11 +331,10 @@ void SystemScreenSaver::pickGameListNode(unsigned long index, const char *nodeNa
void SystemScreenSaver::pickRandomVideo(std::string& path)
{
countVideos();
mCurrentGame = NULL;
if (mVideoCount > 0)
{
int video = (int)(((float)rand() / float(RAND_MAX)) * (float)mVideoCount);
mCurrentGame = nullptr;
if (mVideoCount > 0) {
int video = (int)(((float)rand() / float(RAND_MAX)) * (float)mVideoCount);
pickGameListNode(video, "video", path);
}
}
@ -355,11 +342,10 @@ void SystemScreenSaver::pickRandomVideo(std::string& path)
void SystemScreenSaver::pickRandomGameListImage(std::string& path)
{
countImages();
mCurrentGame = NULL;
if (mImageCount > 0)
{
int image = (int)(((float)rand() / float(RAND_MAX)) * (float)mImageCount);
mCurrentGame = nullptr;
if (mImageCount > 0) {
int image = (int)(((float)rand() / float(RAND_MAX)) * (float)mImageCount);
pickGameListNode(image, "image", path);
}
}
@ -367,79 +353,69 @@ void SystemScreenSaver::pickRandomGameListImage(std::string& path)
void SystemScreenSaver::pickRandomCustomImage(std::string& path)
{
std::string imageDir = Settings::getInstance()->getString("SlideshowScreenSaverImageDir");
if ((imageDir != "") && (Utils::FileSystem::exists(imageDir)))
{
std::string imageFilter = Settings::getInstance()->getString("SlideshowScreenSaverImageFilter");
std::vector<std::string> matchingFiles;
Utils::FileSystem::stringList dirContent = Utils::FileSystem::getDirContent(imageDir, Settings::getInstance()->getBool("SlideshowScreenSaverRecurse"));
for(Utils::FileSystem::stringList::const_iterator it = dirContent.cbegin(); it != dirContent.cend(); ++it)
{
if (Utils::FileSystem::isRegularFile(*it))
{
// If the image filter is empty, or the file extension is in the filter string,
// add it to the matching files list
if ((imageFilter.length() <= 0) ||
(imageFilter.find(Utils::FileSystem::getExtension(*it)) != std::string::npos))
{
if ((imageDir != "") && (Utils::FileSystem::exists(imageDir))) {
std::string imageFilter = Settings::getInstance()->
getString("SlideshowScreenSaverImageFilter");
std::vector<std::string> matchingFiles;
Utils::FileSystem::stringList dirContent = Utils::FileSystem::getDirContent(
imageDir, Settings::getInstance()->getBool("SlideshowScreenSaverRecurse"));
for (Utils::FileSystem::stringList::const_iterator it = dirContent.cbegin();
it != dirContent.cend(); ++it) {
if (Utils::FileSystem::isRegularFile(*it)) {
// If the image filter is empty, or the file extension is in the filter
// string, add it to the matching files list.
if ((imageFilter.length() <= 0) || (imageFilter.find(
Utils::FileSystem::getExtension(*it)) != std::string::npos))
matchingFiles.push_back(*it);
}
}
}
int fileCount = (int)matchingFiles.size();
if (fileCount > 0)
{
// get a random index in the range 0 to fileCount (exclusive)
if (fileCount > 0) {
// Get a random index in the range 0 to fileCount (exclusive).
int randomIndex = rand() % fileCount;
path = matchingFiles[randomIndex];
}
else
{
else {
LOG(LogError) << "Slideshow Screensaver - No image files found\n";
}
}
else
{
LOG(LogError) << "Slideshow Screensaver - Image directory does not exist: " << imageDir << "\n";
else {
LOG(LogError) << "Slideshow Screensaver - Image directory does not exist: " <<
imageDir << "\n";
}
}
void SystemScreenSaver::update(int deltaTime)
{
// Use this to update the fade value for the current fade stage
if (mState == STATE_FADE_OUT_WINDOW)
{
// Use this to update the fade value for the current fade stage.
if (mState == STATE_FADE_OUT_WINDOW) {
mOpacity += (float)deltaTime / FADE_TIME;
if (mOpacity >= 1.0f)
{
if (mOpacity >= 1.0f) {
mOpacity = 1.0f;
// Update to the next state
// Update to the next state.
mState = STATE_FADE_IN_VIDEO;
}
}
else if (mState == STATE_FADE_IN_VIDEO)
{
else if (mState == STATE_FADE_IN_VIDEO) {
mOpacity -= (float)deltaTime / FADE_TIME;
if (mOpacity <= 0.0f)
{
if (mOpacity <= 0.0f) {
mOpacity = 0.0f;
// Update to the next state
// Update to the next state.
mState = STATE_SCREENSAVER_ACTIVE;
}
}
else if (mState == STATE_SCREENSAVER_ACTIVE)
{
// Update the timer that swaps the videos
else if (mState == STATE_SCREENSAVER_ACTIVE) {
// Update the timer that swaps the videos.
mTimer += deltaTime;
if (mTimer > mVideoChangeTime)
{
nextVideo();
}
}
// If we have a loaded video then update it
// If we have a loaded video then update it.
if (mVideoScreensaver)
mVideoScreensaver->update(deltaTime);
if (mImageScreensaver)
@ -460,15 +436,13 @@ FileData* SystemScreenSaver::getCurrentGame()
void SystemScreenSaver::launchGame()
{
if (mCurrentGame != NULL)
{
// launching Game
if (mCurrentGame != nullptr) {
// Launching game
ViewController::get()->goToGameList(mCurrentGame->getSystem());
IGameListView* view = ViewController::get()->getGameListView(mCurrentGame->getSystem()).get();
IGameListView* view = ViewController::get()->
getGameListView(mCurrentGame->getSystem()).get();
view->setCursor(mCurrentGame);
if (Settings::getInstance()->getBool("ScreenSaverControls"))
{
view->launch(mCurrentGame);
}
}
}

View file

@ -1,3 +1,10 @@
//
// SystemScreenSaver.h
//
// Screensaver, supporting the following modes:
// Dim, black, video, slideshow.
//
#pragma once
#ifndef ES_APP_SYSTEM_SCREEN_SAVER_H
#define ES_APP_SYSTEM_SCREEN_SAVER_H
@ -8,7 +15,7 @@ class ImageComponent;
class Sound;
class VideoComponent;
// Screensaver implementation for main window
// Screensaver implementation for main window.
class SystemScreenSaver : public Window::ScreenSaver
{
public:

View file

@ -1,3 +1,9 @@
//
// VolumeControl.cpp
//
// Controls system audio volume.
//
#include "VolumeControl.h"
#include "math/Misc.h"
@ -8,59 +14,68 @@
#endif
#if defined(__linux__)
#if defined(_RPI_) || defined(_VERO4K_)
const char * VolumeControl::mixerName = "PCM";
#else
const char * VolumeControl::mixerName = "Master";
#endif
const char * VolumeControl::mixerCard = "default";
#if defined(_RPI_) || defined(_VERO4K_)
const char * VolumeControl::mixerName = "PCM";
#else
const char * VolumeControl::mixerName = "Master";
#endif
const char * VolumeControl::mixerCard = "default";
#endif
std::weak_ptr<VolumeControl> VolumeControl::sInstance;
VolumeControl::VolumeControl()
: originalVolume(0), internalVolume(0)
#if defined (__APPLE__)
: originalVolume(0),
internalVolume(0)
#if defined (__APPLE__)
#error TODO: Not implemented for MacOS yet!!!
#elif defined(__linux__)
, mixerIndex(0), mixerHandle(nullptr), mixerElem(nullptr), mixerSelemId(nullptr)
#elif defined(WIN32) || defined(_WIN32)
, mixerHandle(nullptr), endpointVolume(nullptr)
#endif
#elif defined(__linux__)
, mixerIndex(0),
mixerHandle(nullptr),
mixerElem(nullptr),
mixerSelemId(nullptr)
#elif defined(WIN32) || defined(_WIN32)
, mixerHandle(nullptr),
endpointVolume(nullptr)
#endif
{
init();
//get original volume levels for system
// Get original volume levels for system.
originalVolume = getVolume();
}
VolumeControl::VolumeControl(const VolumeControl & right):
originalVolume(0), internalVolume(0)
#if defined (__APPLE__)
VolumeControl::VolumeControl(
const VolumeControl & right):
originalVolume(0),
internalVolume(0)
#if defined (__APPLE__)
#error TODO: Not implemented for MacOS yet!!!
#elif defined(__linux__)
, mixerIndex(0), mixerHandle(nullptr), mixerElem(nullptr), mixerSelemId(nullptr)
#elif defined(WIN32) || defined(_WIN32)
, mixerHandle(nullptr), endpointVolume(nullptr)
#endif
#elif defined(__linux__)
, mixerIndex(0),
mixerHandle(nullptr),
mixerElem(nullptr),
mixerSelemId(nullptr)
#elif defined(WIN32) || defined(_WIN32)
, mixerHandle(nullptr),
endpointVolume(nullptr)
#endif
{
(void)right;
sInstance = right.sInstance;
}
VolumeControl & VolumeControl::operator=(const VolumeControl & right)
VolumeControl & VolumeControl::operator=(const VolumeControl& right)
{
if (this != &right) {
if (this != &right)
sInstance = right.sInstance;
}
return *this;
}
VolumeControl::~VolumeControl()
{
//set original volume levels for system
// Set original volume levels for system.
//setVolume(originalVolume);
deinit();
@ -68,7 +83,7 @@ VolumeControl::~VolumeControl()
std::shared_ptr<VolumeControl> & VolumeControl::getInstance()
{
//check if an VolumeControl instance is already created, if not create one
// Check if an VolumeControl instance is already created, if not create one.
static std::shared_ptr<VolumeControl> sharedInstance = sInstance.lock();
if (sharedInstance == nullptr) {
sharedInstance.reset(new VolumeControl);
@ -79,158 +94,144 @@ std::shared_ptr<VolumeControl> & VolumeControl::getInstance()
void VolumeControl::init()
{
//initialize audio mixer interface
#if defined (__APPLE__)
// Initialize audio mixer interface.
#if defined (__APPLE__)
#error TODO: Not implemented for MacOS yet!!!
#elif defined(__linux__)
//try to open mixer device
if (mixerHandle == nullptr)
{
// Allow users to override the AudioCard and MixerName in es_settings.cfg
#elif defined(__linux__)
// Try to open mixer device.
if (mixerHandle == nullptr) {
// Allow user to override the AudioCard and AudioDevice in es_settings.cfg.
mixerCard = Settings::getInstance()->getString("AudioCard").c_str();
mixerName = Settings::getInstance()->getString("AudioDevice").c_str();
snd_mixer_selem_id_alloca(&mixerSelemId);
//sets simple-mixer index and name
// Sets simple-mixer index and name.
snd_mixer_selem_id_set_index(mixerSelemId, mixerIndex);
snd_mixer_selem_id_set_name(mixerSelemId, mixerName);
//open mixer
if (snd_mixer_open(&mixerHandle, 0) >= 0)
{
// Open mixer.
if (snd_mixer_open(&mixerHandle, 0) >= 0) {
LOG(LogDebug) << "VolumeControl::init() - Opened ALSA mixer";
//ok. attach to defualt card
if (snd_mixer_attach(mixerHandle, mixerCard) >= 0)
{
// Ok, attach to defualt card.
if (snd_mixer_attach(mixerHandle, mixerCard) >= 0) {
LOG(LogDebug) << "VolumeControl::init() - Attached to default card";
//ok. register simple element class
if (snd_mixer_selem_register(mixerHandle, NULL, NULL) >= 0)
{
// Ok, register simple element class.
if (snd_mixer_selem_register(mixerHandle, nullptr, nullptr) >= 0) {
LOG(LogDebug) << "VolumeControl::init() - Registered simple element class";
//ok. load registered elements
if (snd_mixer_load(mixerHandle) >= 0)
{
// Ok, load registered elements.
if (snd_mixer_load(mixerHandle) >= 0) {
LOG(LogDebug) << "VolumeControl::init() - Loaded mixer elements";
//ok. find elements now
// Ok, find elements now.
mixerElem = snd_mixer_find_selem(mixerHandle, mixerSelemId);
if (mixerElem != nullptr)
{
//wohoo. good to go...
if (mixerElem != nullptr) {
// Wohoo. good to go...
LOG(LogDebug) << "VolumeControl::init() - Mixer initialized";
}
else
{
LOG(LogError) << "VolumeControl::init() - Failed to find mixer elements!";
else {
LOG(LogError) <<
"VolumeControl::init() - Failed to find mixer elements!";
snd_mixer_close(mixerHandle);
mixerHandle = nullptr;
}
}
else
{
else {
LOG(LogError) << "VolumeControl::init() - Failed to load mixer elements!";
snd_mixer_close(mixerHandle);
mixerHandle = nullptr;
}
}
else
{
LOG(LogError) << "VolumeControl::init() - Failed to register simple element class!";
else {
LOG(LogError) <<
"VolumeControl::init() - Failed to register simple element class!";
snd_mixer_close(mixerHandle);
mixerHandle = nullptr;
}
}
else
{
else {
LOG(LogError) << "VolumeControl::init() - Failed to attach to default card!";
snd_mixer_close(mixerHandle);
mixerHandle = nullptr;
}
}
else
{
else {
LOG(LogError) << "VolumeControl::init() - Failed to open ALSA mixer!";
}
}
#elif defined(WIN32) || defined(_WIN32)
//get windows version information
#elif defined(WIN32) || defined(_WIN32)
// Get windows version information.
OSVERSIONINFOEXA osVer = {sizeof(OSVERSIONINFO)};
::GetVersionExA(reinterpret_cast<LPOSVERSIONINFOA>(&osVer));
//check windows version
if(osVer.dwMajorVersion < 6)
{
//Windows older than Vista. use mixer API. open default mixer
if (mixerHandle == nullptr)
{
if (mixerOpen(&mixerHandle, 0, NULL, 0, 0) == MMSYSERR_NOERROR)
{
//retrieve info on the volume slider control for the "Speaker Out" line
// Check windows version.
if (osVer.dwMajorVersion < 6) {
// Windows older than Vista. use mixer API. open default mixer.
if (mixerHandle == nullptr) {
if (mixerOpen(&mixerHandle, 0, nullptr, 0, 0) == MMSYSERR_NOERROR) {
// Retrieve info on the volume slider control for the "Speaker Out" line.
MIXERLINECONTROLS mixerLineControls;
mixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
mixerLineControls.dwLineID = 0xFFFF0000; //Id of "Speaker Out" line
mixerLineControls.dwLineID = 0xFFFF0000; // Id of "Speaker Out" line.
mixerLineControls.cControls = 1;
//mixerLineControls.dwControlID = 0x00000000; //Id of "Speaker Out" line's volume slider
mixerLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; //Get volume control
// Id of "Speaker Out" line's volume slider.
//mixerLineControls.dwControlID = 0x00000000;
//Get volume control.
mixerLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mixerLineControls.pamxctrl = &mixerControl;
mixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
if (mixerGetLineControls((HMIXEROBJ)mixerHandle, &mixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR)
{
LOG(LogError) << "VolumeControl::getVolume() - Failed to get mixer volume control!";
if (mixerGetLineControls((HMIXEROBJ)mixerHandle, &mixerLineControls,
MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR) {
LOG(LogError) <<
"VolumeControl::getVolume() - Failed to get mixer volume control!";
mixerClose(mixerHandle);
mixerHandle = nullptr;
}
}
else
{
else {
LOG(LogError) << "VolumeControl::init() - Failed to open mixer!";
}
}
}
else
{
//Windows Vista or above. use EndpointVolume API. get device enumerator
if (endpointVolume == nullptr)
{
else {
// Windows Vista or above. use EndpointVolume API. get device enumerator.
if (endpointVolume == nullptr) {
CoInitialize(nullptr);
IMMDeviceEnumerator * deviceEnumerator = nullptr;
CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
if (deviceEnumerator != nullptr)
{
//get default endpoint
CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
if (deviceEnumerator != nullptr) {
// Get default endpoint.
IMMDevice * defaultDevice = nullptr;
deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
if (defaultDevice != nullptr)
{
//retrieve endpoint volume
defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, (LPVOID *)&endpointVolume);
if (defaultDevice != nullptr) {
// Retrieve endpoint volume.
defaultDevice->Activate(__uuidof(IAudioEndpointVolume),
CLSCTX_INPROC_SERVER, nullptr, (LPVOID *)&endpointVolume);
if (endpointVolume == nullptr)
{
LOG(LogError) << "VolumeControl::init() - Failed to get default audio endpoint volume!";
}
//release default device. we don't need it anymore
LOG(LogError) << "VolumeControl::init() - "
"Failed to get default audio endpoint volume!";
// Release default device. we don't need it anymore.
defaultDevice->Release();
}
else
{
LOG(LogError) << "VolumeControl::init() - Failed to get default audio endpoint!";
else {
LOG(LogError) <<
"VolumeControl::init() - Failed to get default audio endpoint!";
}
//release device enumerator. we don't need it anymore
// Release device enumerator. we don't need it anymore.
deviceEnumerator->Release();
}
else
{
else {
LOG(LogError) << "VolumeControl::init() - Failed to get audio endpoint enumerator!";
CoUninitialize();
}
}
}
#endif
#endif
}
void VolumeControl::deinit()
{
//deinitialize audio mixer interface
#if defined (__APPLE__)
// Deinitialize audio mixer interface.
#if defined (__APPLE__)
#error TODO: Not implemented for MacOS yet!!!
#elif defined(__linux__)
#elif defined(__linux__)
if (mixerHandle != nullptr) {
snd_mixer_detach(mixerHandle, mixerCard);
snd_mixer_free(mixerHandle);
@ -238,7 +239,7 @@ void VolumeControl::deinit()
mixerHandle = nullptr;
mixerElem = nullptr;
}
#elif defined(WIN32) || defined(_WIN32)
#elif defined(WIN32) || defined(_WIN32)
if (mixerHandle != nullptr) {
mixerClose(mixerHandle);
mixerHandle = nullptr;
@ -248,159 +249,137 @@ void VolumeControl::deinit()
endpointVolume = nullptr;
CoUninitialize();
}
#endif
#endif
}
int VolumeControl::getVolume() const
{
int volume = 0;
#if defined (__APPLE__)
#if defined (__APPLE__)
#error TODO: Not implemented for MacOS yet!!!
#elif defined(__linux__)
if (mixerElem != nullptr)
{
//get volume range
#elif defined(__linux__)
if (mixerElem != nullptr) {
// Get volume range.
long minVolume;
long maxVolume;
if (snd_mixer_selem_get_playback_volume_range(mixerElem, &minVolume, &maxVolume) == 0)
{
//ok. now get volume
if (snd_mixer_selem_get_playback_volume_range(mixerElem, &minVolume, &maxVolume) == 0) {
// Ok, now get volume.
long rawVolume;
if (snd_mixer_selem_get_playback_volume(mixerElem, SND_MIXER_SCHN_MONO, &rawVolume) == 0)
{
//worked. bring into range 0-100
if (snd_mixer_selem_get_playback_volume(mixerElem,
SND_MIXER_SCHN_MONO, &rawVolume) == 0) {
// Worked. bring into range 0-100.
rawVolume -= minVolume;
if (rawVolume > 0)
{
volume = (rawVolume * 100.0) / (maxVolume - minVolume) + 0.5;
//else
// volume = 0;
}
//else volume = 0;
}
else
{
else {
LOG(LogError) << "VolumeControl::getVolume() - Failed to get mixer volume!";
}
}
else
{
else {
LOG(LogError) << "VolumeControl::getVolume() - Failed to get volume range!";
}
}
#elif defined(WIN32) || defined(_WIN32)
if (mixerHandle != nullptr)
{
//Windows older than Vista. use mixer API. get volume from line control
#elif defined(WIN32) || defined(_WIN32)
if (mixerHandle != nullptr) {
// Windows older than Vista. use mixer API. get volume from line control.
MIXERCONTROLDETAILS_UNSIGNED value;
MIXERCONTROLDETAILS mixerControlDetails;
mixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
mixerControlDetails.dwControlID = mixerControl.dwControlID;
mixerControlDetails.cChannels = 1; //always 1 for a MIXERCONTROL_CONTROLF_UNIFORM control
mixerControlDetails.cMultipleItems = 0; //always 0 except for a MIXERCONTROL_CONTROLF_MULTIPLE control
// Always 1 for a MIXERCONTROL_CONTROLF_UNIFORM control.
mixerControlDetails.cChannels = 1;
// Always 0 except for a MIXERCONTROL_CONTROLF_MULTIPLE control.
mixerControlDetails.cMultipleItems = 0;
mixerControlDetails.paDetails = &value;
mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
if (mixerGetControlDetails((HMIXEROBJ)mixerHandle, &mixerControlDetails, MIXER_GETCONTROLDETAILSF_VALUE) == MMSYSERR_NOERROR)
{
if (mixerGetControlDetails((HMIXEROBJ)mixerHandle, &mixerControlDetails,
MIXER_GETCONTROLDETAILSF_VALUE) == MMSYSERR_NOERROR)
volume = (int)Math::round((value.dwValue * 100) / 65535.0f);
}
else
{
LOG(LogError) << "VolumeControl::getVolume() - Failed to get mixer volume!";
}
}
else if (endpointVolume != nullptr)
{
//Windows Vista or above. use EndpointVolume API
float floatVolume = 0.0f; //0-1
if (endpointVolume->GetMasterVolumeLevelScalar(&floatVolume) == S_OK)
{
else if (endpointVolume != nullptr) {
// Windows Vista or above. use EndpointVolume API.
float floatVolume = 0.0f; // 0-1
if (endpointVolume->GetMasterVolumeLevelScalar(&floatVolume) == S_OK) {
volume = (int)Math::round(floatVolume * 100.0f);
LOG(LogInfo) << " getting volume as " << volume << " ( from float " << floatVolume << ")";
LOG(LogInfo) << " getting volume as " << volume <<
" ( from float " << floatVolume << ")";
}
else
{
else {
LOG(LogError) << "VolumeControl::getVolume() - Failed to get master volume!";
}
}
#endif
}
#endif
//clamp to 0-100 range
// Clamp to 0-100 range.
if (volume < 0)
{
volume = 0;
}
if (volume > 100)
{
volume = 100;
}
return volume;
}
void VolumeControl::setVolume(int volume)
{
//clamp to 0-100 range
// Clamp to 0-100 range.
if (volume < 0)
{
volume = 0;
}
if (volume > 100)
{
volume = 100;
}
//store values in internal variables
// Store values in internal variables.
internalVolume = volume;
#if defined (__APPLE__)
#if defined (__APPLE__)
#error TODO: Not implemented for MacOS yet!!!
#elif defined(__linux__)
if (mixerElem != nullptr)
{
//get volume range
#elif defined(__linux__)
if (mixerElem != nullptr) {
// Get volume range.
long minVolume;
long maxVolume;
if (snd_mixer_selem_get_playback_volume_range(mixerElem, &minVolume, &maxVolume) == 0)
{
//ok. bring into minVolume-maxVolume range and set
if (snd_mixer_selem_get_playback_volume_range(mixerElem, &minVolume, &maxVolume) == 0) {
// Ok, bring into minVolume-maxVolume range and set.
long rawVolume = (volume * (maxVolume - minVolume) / 100) + minVolume;
if (snd_mixer_selem_set_playback_volume(mixerElem, SND_MIXER_SCHN_FRONT_LEFT, rawVolume) < 0
|| snd_mixer_selem_set_playback_volume(mixerElem, SND_MIXER_SCHN_FRONT_RIGHT, rawVolume) < 0)
{
if (snd_mixer_selem_set_playback_volume(mixerElem,
SND_MIXER_SCHN_FRONT_LEFT, rawVolume) < 0 ||
snd_mixer_selem_set_playback_volume(mixerElem,
SND_MIXER_SCHN_FRONT_RIGHT, rawVolume) < 0) {
LOG(LogError) << "VolumeControl::getVolume() - Failed to set mixer volume!";
}
}
else
{
else {
LOG(LogError) << "VolumeControl::getVolume() - Failed to get volume range!";
}
}
#elif defined(WIN32) || defined(_WIN32)
if (mixerHandle != nullptr)
{
//Windows older than Vista. use mixer API. get volume from line control
#elif defined(WIN32) || defined(_WIN32)
if (mixerHandle != nullptr) {
// Windows older than Vista. use mixer API. get volume from line control.
MIXERCONTROLDETAILS_UNSIGNED value;
value.dwValue = (volume * 65535) / 100;
MIXERCONTROLDETAILS mixerControlDetails;
mixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
mixerControlDetails.dwControlID = mixerControl.dwControlID;
mixerControlDetails.cChannels = 1; //always 1 for a MIXERCONTROL_CONTROLF_UNIFORM control
mixerControlDetails.cMultipleItems = 0; //always 0 except for a MIXERCONTROL_CONTROLF_MULTIPLE control
// Always 1 for a MIXERCONTROL_CONTROLF_UNIFORM control.
mixerControlDetails.cChannels = 1;
// Always 0 except for a MIXERCONTROL_CONTROLF_MULTIPLE control.
mixerControlDetails.cMultipleItems = 0;
mixerControlDetails.paDetails = &value;
mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
if (mixerSetControlDetails((HMIXEROBJ)mixerHandle, &mixerControlDetails, MIXER_SETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR)
{
if (mixerSetControlDetails((HMIXEROBJ)mixerHandle, &mixerControlDetails,
MIXER_SETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR)
LOG(LogError) << "VolumeControl::setVolume() - Failed to set mixer volume!";
}
}
else if (endpointVolume != nullptr)
{
//Windows Vista or above. use EndpointVolume API
float floatVolume = 0.0f; //0-1
if (volume > 0) {
else if (endpointVolume != nullptr) {
// Windows Vista or above. use EndpointVolume API.
float floatVolume = 0.0f; // 0-1
if (volume > 0)
floatVolume = (float)volume / 100.0f;
}
if (endpointVolume->SetMasterVolumeLevelScalar(floatVolume, nullptr) != S_OK)
{
LOG(LogError) << "VolumeControl::setVolume() - Failed to set master volume!";
}
}
#endif
#endif
}

View file

@ -1,3 +1,9 @@
//
// VolumeControl.h
//
// Controls system audio volume.
//
#pragma once
#ifndef ES_APP_VOLUME_CONTROL_H
#define ES_APP_VOLUME_CONTROL_H
@ -5,36 +11,34 @@
#include <memory>
#if defined (__APPLE__)
#error TODO: Not implemented for MacOS yet!!!
#error TODO: Not implemented for MacOS yet!!!
#elif defined(__linux__)
#include <unistd.h>
#include <fcntl.h>
#include <alsa/asoundlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <alsa/asoundlib.h>
#elif defined(WIN32) || defined(_WIN32)
#include <Windows.h>
#include <endpointvolume.h>
#include <mmeapi.h>
#include <Windows.h>
#include <endpointvolume.h>
#include <mmeapi.h>
#endif
/*!
Singleton pattern. Call getInstance() to get an object.
*/
// Singleton pattern. Call getInstance() to get an object.
class VolumeControl
{
#if defined (__APPLE__)
#if defined (__APPLE__)
#error TODO: Not implemented for MacOS yet!!!
#elif defined(__linux__)
#elif defined(__linux__)
static const char * mixerName;
static const char * mixerCard;
int mixerIndex;
snd_mixer_t* mixerHandle;
snd_mixer_elem_t* mixerElem;
snd_mixer_selem_id_t* mixerSelemId;
#elif defined(WIN32) || defined(_WIN32)
#elif defined(WIN32) || defined(_WIN32)
HMIXER mixerHandle;
MIXERCONTROL mixerControl;
IAudioEndpointVolume * endpointVolume;
#endif
#endif
int originalVolume;
int internalVolume;

View file

@ -238,7 +238,7 @@ void GuiGamelistOptions::openMetaDataEd()
std::function<void()> deleteBtnFunc;
if (file->getType() == FOLDER) {
deleteBtnFunc = NULL;
deleteBtnFunc = nullptr;
}
else {
deleteBtnFunc = [this, file] {

View file

@ -1,3 +1,9 @@
//
// GuiSettings.cpp
//
// User interface template for a settings GUI.
//
#include "guis/GuiSettings.h"
#include "views/ViewController.h"
@ -5,10 +11,10 @@
#include "SystemData.h"
#include "Window.h"
GuiSettings::GuiSettings(Window* window, const char* title) : GuiComponent(window), mMenu(window, title)
GuiSettings::GuiSettings(Window* window, const char* title)
: GuiComponent(window), mMenu(window, title)
{
addChild(&mMenu);
mMenu.addButton("BACK", "back", [this] { delete this; });
setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
@ -22,10 +28,10 @@ GuiSettings::~GuiSettings()
void GuiSettings::save()
{
if(!mSaveFuncs.size())
if (!mSaveFuncs.size())
return;
for(auto it = mSaveFuncs.cbegin(); it != mSaveFuncs.cend(); it++)
for (auto it = mSaveFuncs.cbegin(); it != mSaveFuncs.cend(); it++)
(*it)();
Settings::getInstance()->saveFile();
@ -33,18 +39,17 @@ void GuiSettings::save()
bool GuiSettings::input(InputConfig* config, Input input)
{
if(config->isMappedTo("b", input) && input.value != 0)
{
if (config->isMappedTo("b", input) && input.value != 0) {
delete this;
return true;
}
// Keep code for potential future use.
// if(config->isMappedTo("start", input) && input.value != 0)
// if (config->isMappedTo("start", input) && input.value != 0)
// {
// // close everything
// Window* window = mWindow;
// while(window->peekGui() && window->peekGui() != ViewController::get())
// while (window->peekGui() && window->peekGui() != ViewController::get())
// delete window->peekGui();
// return true;
// }

View file

@ -1,3 +1,9 @@
//
// GuiSettings.h
//
// User interface template for a settings GUI.
//
#pragma once
#ifndef ES_APP_GUIS_GUI_SETTINGS_H
#define ES_APP_GUIS_GUI_SETTINGS_H
@ -9,11 +15,12 @@ class GuiSettings : public GuiComponent
{
public:
GuiSettings(Window* window, const char* title);
virtual ~GuiSettings(); // just calls save();
virtual ~GuiSettings(); // Just calls save()
void save();
inline void addRow(const ComponentListRow& row) { mMenu.addRow(row); };
inline void addWithLabel(const std::string& label, const std::shared_ptr<GuiComponent>& comp) { mMenu.addWithLabel(label, comp); };
inline void addWithLabel(const std::string& label,
const std::shared_ptr<GuiComponent>& comp) { mMenu.addWithLabel(label, comp); };
inline void addSaveFunc(const std::function<void()>& func) { mSaveFuncs.push_back(func); };
bool input(InputConfig* config, Input input) override;

View file

@ -1,3 +1,10 @@
//
// GuiSlideshowScreensaverOptions.cpp
//
// User interface for the slideshow screensaver options.
// Submenu to GuiGeneralScreensaverOptions.
//
#include "guis/GuiSlideshowScreensaverOptions.h"
#include "components/SliderComponent.h"
@ -7,13 +14,15 @@
#include "Settings.h"
#include "Window.h"
GuiSlideshowScreensaverOptions::GuiSlideshowScreensaverOptions(Window* window, const char* title) : GuiScreensaverOptions(window, title)
GuiSlideshowScreensaverOptions::GuiSlideshowScreensaverOptions(Window* window, const char* title)
: GuiScreensaverOptions(window, title)
{
ComponentListRow row;
// image duration (seconds)
// Image duration (in seconds).
auto sss_image_sec = std::make_shared<SliderComponent>(mWindow, 1.f, 60.f, 1.f, "s");
sss_image_sec->setValue((float)(Settings::getInstance()->getInt("ScreenSaverSwapImageTimeout") / (1000)));
sss_image_sec->setValue((float)(Settings::getInstance()->
getInt("ScreenSaverSwapImageTimeout") / (1000)));
addWithLabel(row, "SWAP IMAGE AFTER (SECS)", sss_image_sec);
addSaveFunc([sss_image_sec] {
int playNextTimeout = (int)Math::round(sss_image_sec->getValue()) * (1000);
@ -21,7 +30,7 @@ GuiSlideshowScreensaverOptions::GuiSlideshowScreensaverOptions(Window* window, c
PowerSaver::updateTimeouts();
});
// stretch
// Stretch image.
auto sss_stretch = std::make_shared<SwitchComponent>(mWindow);
sss_stretch->setState(Settings::getInstance()->getBool("SlideshowScreenSaverStretch"));
addWithLabel(row, "STRETCH IMAGES", sss_stretch);
@ -29,27 +38,35 @@ GuiSlideshowScreensaverOptions::GuiSlideshowScreensaverOptions(Window* window, c
Settings::getInstance()->setBool("SlideshowScreenSaverStretch", sss_stretch->getState());
});
// background audio file
auto sss_bg_audio_file = std::make_shared<TextComponent>(mWindow, "", Font::get(FONT_SIZE_SMALL), 0x777777FF);
addEditableTextComponent(row, "BACKGROUND AUDIO", sss_bg_audio_file, Settings::getInstance()->getString("SlideshowScreenSaverBackgroundAudioFile"));
// Background audio file.
auto sss_bg_audio_file = std::make_shared<TextComponent>(mWindow, "",
Font::get(FONT_SIZE_SMALL), 0x777777FF);
addEditableTextComponent(row, "BACKGROUND AUDIO", sss_bg_audio_file,
Settings::getInstance()->getString("SlideshowScreenSaverBackgroundAudioFile"));
addSaveFunc([sss_bg_audio_file] {
Settings::getInstance()->setString("SlideshowScreenSaverBackgroundAudioFile", sss_bg_audio_file->getValue());
Settings::getInstance()->setString("SlideshowScreenSaverBackgroundAudioFile",
sss_bg_audio_file->getValue());
});
// image source
// Image source.
auto sss_custom_source = std::make_shared<SwitchComponent>(mWindow);
sss_custom_source->setState(Settings::getInstance()->getBool("SlideshowScreenSaverCustomImageSource"));
sss_custom_source->setState(Settings::getInstance()->
getBool("SlideshowScreenSaverCustomImageSource"));
addWithLabel(row, "USE CUSTOM IMAGES", sss_custom_source);
addSaveFunc([sss_custom_source] { Settings::getInstance()->setBool("SlideshowScreenSaverCustomImageSource", sss_custom_source->getState()); });
addSaveFunc([sss_custom_source] { Settings::getInstance()->
setBool("SlideshowScreenSaverCustomImageSource", sss_custom_source->getState()); });
// custom image directory
auto sss_image_dir = std::make_shared<TextComponent>(mWindow, "", Font::get(FONT_SIZE_SMALL), 0x777777FF);
addEditableTextComponent(row, "CUSTOM IMAGE DIR", sss_image_dir, Settings::getInstance()->getString("SlideshowScreenSaverImageDir"));
// Custom image directory.
auto sss_image_dir = std::make_shared<TextComponent>(mWindow, "",
Font::get(FONT_SIZE_SMALL), 0x777777FF);
addEditableTextComponent(row, "CUSTOM IMAGE DIR", sss_image_dir,
Settings::getInstance()->getString("SlideshowScreenSaverImageDir"));
addSaveFunc([sss_image_dir] {
Settings::getInstance()->setString("SlideshowScreenSaverImageDir", sss_image_dir->getValue());
Settings::getInstance()->setString("SlideshowScreenSaverImageDir",
sss_image_dir->getValue());
});
// recurse custom image directory
// Recurse custom image directory.
auto sss_recurse = std::make_shared<SwitchComponent>(mWindow);
sss_recurse->setState(Settings::getInstance()->getBool("SlideshowScreenSaverRecurse"));
addWithLabel(row, "CUSTOM IMAGE DIR RECURSIVE", sss_recurse);
@ -57,11 +74,14 @@ GuiSlideshowScreensaverOptions::GuiSlideshowScreensaverOptions(Window* window, c
Settings::getInstance()->setBool("SlideshowScreenSaverRecurse", sss_recurse->getState());
});
// custom image filter
auto sss_image_filter = std::make_shared<TextComponent>(mWindow, "", Font::get(FONT_SIZE_SMALL), 0x777777FF);
addEditableTextComponent(row, "CUSTOM IMAGE FILTER", sss_image_filter, Settings::getInstance()->getString("SlideshowScreenSaverImageFilter"));
// Custom image filter (file extensions).
auto sss_image_filter = std::make_shared<TextComponent>(mWindow, "",
Font::get(FONT_SIZE_SMALL), 0x777777FF);
addEditableTextComponent(row, "CUSTOM IMAGE FILTER", sss_image_filter,
Settings::getInstance()->getString("SlideshowScreenSaverImageFilter"));
addSaveFunc([sss_image_filter] {
Settings::getInstance()->setString("SlideshowScreenSaverImageFilter", sss_image_filter->getValue());
Settings::getInstance()->setString("SlideshowScreenSaverImageFilter",
sss_image_filter->getValue());
});
}
@ -69,14 +89,15 @@ GuiSlideshowScreensaverOptions::~GuiSlideshowScreensaverOptions()
{
}
void GuiSlideshowScreensaverOptions::addWithLabel(ComponentListRow row, const std::string label, std::shared_ptr<GuiComponent> component)
void GuiSlideshowScreensaverOptions::addWithLabel(ComponentListRow row,
const std::string label, std::shared_ptr<GuiComponent> component)
{
row.elements.clear();
auto lbl = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(label), Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
row.addElement(lbl, true); // label
auto lbl = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(label),
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
row.addElement(lbl, true); // Label.
row.addElement(component, false, true);
addRow(row);
}

View file

@ -1,3 +1,10 @@
//
// GuiSlideshowScreensaverOptions.h
//
// User interface for the slideshow screensaver options.
// Submenu to GuiGeneralScreensaverOptions.
//
#pragma once
#ifndef ES_APP_GUIS_GUI_SLIDESHOW_SCREENSAVER_OPTIONS_H
#define ES_APP_GUIS_GUI_SLIDESHOW_SCREENSAVER_OPTIONS_H
@ -11,7 +18,8 @@ public:
virtual ~GuiSlideshowScreensaverOptions();
private:
void addWithLabel(ComponentListRow row, const std::string label, std::shared_ptr<GuiComponent> component);
void addWithLabel(ComponentListRow row, const std::string label,
std::shared_ptr<GuiComponent> component);
};
#endif // ES_APP_GUIS_GUI_SLIDESHOW_SCREENSAVER_OPTIONS_H

View file

@ -1,3 +1,10 @@
//
// GuiVideoScreensaverOptions.cpp
//
// User interface for the video screensaver options.
// Submenu to GuiGeneralScreensaverOptions.
//
#include "guis/GuiVideoScreensaverOptions.h"
#include "components/OptionListComponent.h"
@ -6,11 +13,13 @@
#include "guis/GuiMsgBox.h"
#include "Settings.h"
GuiVideoScreensaverOptions::GuiVideoScreensaverOptions(Window* window, const char* title) : GuiScreensaverOptions(window, title)
GuiVideoScreensaverOptions::GuiVideoScreensaverOptions(Window* window, const char* title)
: GuiScreensaverOptions(window, title)
{
// timeout to swap videos
// Timer for swapping videos.
auto swap = std::make_shared<SliderComponent>(mWindow, 10.f, 1000.f, 1.f, "s");
swap->setValue((float)(Settings::getInstance()->getInt("ScreenSaverSwapVideoTimeout") / (1000)));
swap->setValue((float)(Settings::getInstance()->
getInt("ScreenSaverSwapVideoTimeout") / (1000)));
addWithLabel("SWAP VIDEO AFTER (SECS)", swap);
addSaveFunc([swap] {
int playNextTimeout = (int)Math::round(swap->getValue()) * (1000);
@ -21,17 +30,20 @@ GuiVideoScreensaverOptions::GuiVideoScreensaverOptions(Window* window, const cha
auto stretch_screensaver = std::make_shared<SwitchComponent>(mWindow);
stretch_screensaver->setState(Settings::getInstance()->getBool("StretchVideoOnScreenSaver"));
addWithLabel("STRETCH VIDEO ON SCREENSAVER", stretch_screensaver);
addSaveFunc([stretch_screensaver] { Settings::getInstance()->setBool("StretchVideoOnScreenSaver", stretch_screensaver->getState()); });
addSaveFunc([stretch_screensaver] { Settings::getInstance()->
setBool("StretchVideoOnScreenSaver", stretch_screensaver->getState()); });
#ifdef _RPI_
#ifdef _RPI_
auto ss_omx = std::make_shared<SwitchComponent>(mWindow);
ss_omx->setState(Settings::getInstance()->getBool("ScreenSaverOmxPlayer"));
addWithLabel("USE OMX PLAYER FOR SCREENSAVER", ss_omx);
addSaveFunc([ss_omx, this] { Settings::getInstance()->setBool("ScreenSaverOmxPlayer", ss_omx->getState()); });
#endif
addSaveFunc([ss_omx, this] { Settings::getInstance()->
setBool("ScreenSaverOmxPlayer", ss_omx->getState()); });
#endif
// Render Video Game Name as subtitles
auto ss_info = std::make_shared< OptionListComponent<std::string> >(mWindow, getHelpStyle(), "SHOW GAME INFO", false);
// Render video game name as subtitles.
auto ss_info = std::make_shared<OptionListComponent<std::string>>
(mWindow,getHelpStyle(), "SHOW GAME INFO", false);
std::vector<std::string> info_type;
info_type.push_back("always");
info_type.push_back("start & end");
@ -39,22 +51,26 @@ GuiVideoScreensaverOptions::GuiVideoScreensaverOptions(Window* window, const cha
for(auto it = info_type.cbegin(); it != info_type.cend(); it++)
ss_info->add(*it, *it, Settings::getInstance()->getString("ScreenSaverGameInfo") == *it);
addWithLabel("SHOW GAME INFO ON SCREENSAVER", ss_info);
addSaveFunc([ss_info, this] { Settings::getInstance()->setString("ScreenSaverGameInfo", ss_info->getSelected()); });
addSaveFunc([ss_info, this] { Settings::getInstance()->
setString("ScreenSaverGameInfo", ss_info->getSelected()); });
#ifdef _RPI_
#ifdef _RPI_
ComponentListRow row;
// Set subtitle position
auto ss_omx_subs_align = std::make_shared< OptionListComponent<std::string> >(mWindow, "GAME INFO ALIGNMENT", false);
// Set subtitle position.
auto ss_omx_subs_align = std::make_shared<OptionListComponent<std::string>>
(mWindow, "GAME INFO ALIGNMENT", false);
std::vector<std::string> align_mode;
align_mode.push_back("left");
align_mode.push_back("center");
for(auto it = align_mode.cbegin(); it != align_mode.cend(); it++)
ss_omx_subs_align->add(*it, *it, Settings::getInstance()->getString("SubtitleAlignment") == *it);
ss_omx_subs_align->add(*it, *it, Settings::getInstance()->
getString("SubtitleAlignment") == *it);
addWithLabel("GAME INFO ALIGNMENT", ss_omx_subs_align);
addSaveFunc([ss_omx_subs_align, this] { Settings::getInstance()->setString("SubtitleAlignment", ss_omx_subs_align->getSelected()); });
addSaveFunc([ss_omx_subs_align, this] { Settings::getInstance()->
setString("SubtitleAlignment", ss_omx_subs_align->getSelected()); });
// Set font size
// Set font size.
auto ss_omx_font_size = std::make_shared<SliderComponent>(mWindow, 1.f, 64.f, 1.f, "h");
ss_omx_font_size->setValue((float)(Settings::getInstance()->getInt("SubtitleSize")));
addWithLabel("GAME INFO FONT SIZE", ss_omx_font_size);
@ -66,29 +82,36 @@ GuiVideoScreensaverOptions::GuiVideoScreensaverOptions(Window* window, const cha
auto ss_video_mute = std::make_shared<SwitchComponent>(mWindow);
ss_video_mute->setState(Settings::getInstance()->getBool("ScreenSaverVideoMute"));
addWithLabel("MUTE SCREENSAVER AUDIO", ss_video_mute);
addSaveFunc([ss_video_mute] { Settings::getInstance()->setBool("ScreenSaverVideoMute", ss_video_mute->getState()); });
addSaveFunc([ss_video_mute] { Settings::getInstance()->
setBool("ScreenSaverVideoMute", ss_video_mute->getState()); });
// Define subtitle font
auto ss_omx_font_file = std::make_shared<TextComponent>(mWindow, "", Font::get(FONT_SIZE_SMALL), 0x777777FF);
addEditableTextComponent(row, "PATH TO FONT FILE", ss_omx_font_file, Settings::getInstance()->getString("SubtitleFont"));
// Define subtitle font.
auto ss_omx_font_file = std::make_shared<TextComponent>(mWindow, "",
Font::get(FONT_SIZE_SMALL), 0x777777FF);
addEditableTextComponent(row, "PATH TO FONT FILE", ss_omx_font_file,
Settings::getInstance()->getString("SubtitleFont"));
addSaveFunc([ss_omx_font_file] {
Settings::getInstance()->setString("SubtitleFont", ss_omx_font_file->getValue());
});
// Define subtitle italic font
auto ss_omx_italic_font_file = std::make_shared<TextComponent>(mWindow, "", Font::get(FONT_SIZE_SMALL), 0x777777FF);
addEditableTextComponent(row, "PATH TO ITALIC FONT FILE", ss_omx_italic_font_file, Settings::getInstance()->getString("SubtitleItalicFont"));
// Define subtitle italic font.
auto ss_omx_italic_font_file = std::make_shared<TextComponent>(mWindow, "",
Font::get(FONT_SIZE_SMALL), 0x777777FF);
addEditableTextComponent(row, "PATH TO ITALIC FONT FILE", ss_omx_italic_font_file,
Settings::getInstance()->getString("SubtitleItalicFont"));
addSaveFunc([ss_omx_italic_font_file] {
Settings::getInstance()->setString("SubtitleItalicFont", ss_omx_italic_font_file->getValue());
Settings::getInstance()->setString("SubtitleItalicFont",
ss_omx_italic_font_file->getValue());
});
#endif
#endif
#ifndef _RPI_
#ifndef _RPI_
auto captions_compatibility = std::make_shared<SwitchComponent>(mWindow);
captions_compatibility->setState(Settings::getInstance()->getBool("CaptionsCompatibility"));
addWithLabel("USE COMPATIBLE LOW RESOLUTION FOR CAPTIONS", captions_compatibility);
addSaveFunc([captions_compatibility] { Settings::getInstance()->setBool("CaptionsCompatibility", captions_compatibility->getState()); });
#endif
addSaveFunc([captions_compatibility] { Settings::getInstance()->
setBool("CaptionsCompatibility", captions_compatibility->getState()); });
#endif
}
GuiVideoScreensaverOptions::~GuiVideoScreensaverOptions()
@ -97,18 +120,25 @@ GuiVideoScreensaverOptions::~GuiVideoScreensaverOptions()
void GuiVideoScreensaverOptions::save()
{
#ifdef _RPI_
bool startingStatusNotRisky = (Settings::getInstance()->getString("ScreenSaverGameInfo") == "never" || !Settings::getInstance()->getBool("ScreenSaverOmxPlayer"));
#endif
#ifdef _RPI_
bool startingStatusNotRisky = (Settings::getInstance()->
getString("ScreenSaverGameInfo") == "never" ||
!Settings::getInstance()->getBool("ScreenSaverOmxPlayer"));
#endif
GuiScreensaverOptions::save();
#ifdef _RPI_
bool endStatusRisky = (Settings::getInstance()->getString("ScreenSaverGameInfo") != "never" && Settings::getInstance()->getBool("ScreenSaverOmxPlayer"));
#ifdef _RPI_
bool endStatusRisky = (Settings::getInstance()->getString("ScreenSaverGameInfo") !=
"never" && Settings::getInstance()->getBool("ScreenSaverOmxPlayer"));
if (startingStatusNotRisky && endStatusRisky) {
// if before it wasn't risky but now there's a risk of problems, show warning
// If before it wasn't risky but now there's a risk of problems, show warning.
mWindow->pushGui(new GuiMsgBox(mWindow,
"Using OMX Player and displaying Game Info may result in the video flickering in some TV modes. If that happens, consider:\n\n• Disabling the \"Show Game Info\" option;\n• Disabling \"Overscan\" on the Pi configuration menu might help:\nRetroPie > Raspi-Config > Advanced Options > Overscan > \"No\".\n• Disabling the use of OMX Player for the screensaver.",
"Using OMX Player and displaying Game Info may result in the video flickering in "
"some TV modes. If that happens, consider:\n\n• Disabling the \"Show Game Info\" "
"option;\n• Disabling \"Overscan\" on the Pi configuration menu might help:\nRetroPie > "
"Raspi-Config > Advanced Options > Overscan > \"No\".\n• Disabling the use of OMX Player "
"for the screensaver.",
"GOT IT!", [] { return; }));
}
#endif
#endif
}

View file

@ -1,3 +1,10 @@
//
// GuiVideoScreensaverOptions.h
//
// User interface for the video screensaver options.
// Submenu to GuiGeneralScreensaverOptions.
//
#pragma once
#ifndef ES_APP_GUIS_GUI_VIDEO_SCREENSAVER_OPTIONS_H
#define ES_APP_GUIS_GUI_VIDEO_SCREENSAVER_OPTIONS_H

View file

@ -30,6 +30,7 @@
#include "Settings.h"
#include "SystemData.h"
#include "SystemScreenSaver.h"
#include <FreeImage.h>
#include <SDL_events.h>
#include <SDL_main.h>
#include <SDL_timer.h>
@ -39,8 +40,6 @@
#include <Windows.h>
#endif
#include <FreeImage.h>
enum eErrorCodes {
NO_ERRORS,
NO_SYSTEMS_FILE,
@ -289,7 +288,7 @@ void onExit()
int main(int argc, char* argv[])
{
srand((unsigned int)time(NULL));
srand((unsigned int)time(nullptr));
std::locale::global(std::locale("C"));

View file

@ -360,7 +360,7 @@ bool resizeImage(const std::string& path, int maxWidth, int maxHeight)
return true;
FREE_IMAGE_FORMAT format = FIF_UNKNOWN;
FIBITMAP* image = NULL;
FIBITMAP* image = nullptr;
// Detect the filetype.
format = FreeImage_GetFileType(path.c_str(), 0);
@ -396,7 +396,7 @@ bool resizeImage(const std::string& path, int maxWidth, int maxHeight)
FIBITMAP* imageRescaled = FreeImage_Rescale(image, maxWidth, maxHeight, FILTER_BILINEAR);
FreeImage_Unload(image);
if (imageRescaled == NULL) {
if (imageRescaled == nullptr) {
LOG(LogError) << "Could not resize image! (not enough memory? invalid bitdepth?)";
return false;
}

View file

@ -122,7 +122,7 @@ pugi::xml_node find_child_by_attribute_list(const pugi::xml_node& node_parent,
}
}
return pugi::xml_node(NULL);
return pugi::xml_node(nullptr);
}
void screenscraper_generate_scraper_requests(const ScraperSearchParams& params,
@ -307,7 +307,7 @@ void ScreenScraperRequest::processMedia(
std::string& fileFormat,
std::string region)
{
pugi::xml_node art = pugi::xml_node(NULL);
pugi::xml_node art = pugi::xml_node(nullptr);
// Do an XPath query for media[type='$media_type'], then filter by region.
// We need to do this because any child of 'medias' has the form

View file

@ -12,11 +12,11 @@
#include "Log.h"
#include "Window.h"
UIModeController * UIModeController::sInstance = NULL;
UIModeController * UIModeController::sInstance = nullptr;
UIModeController * UIModeController::getInstance()
{
if (sInstance == NULL)
if (sInstance == nullptr)
sInstance = new UIModeController();
return sInstance;

View file

@ -232,7 +232,7 @@ void DetailedGameListView::initMDValues()
void DetailedGameListView::updateInfoPanel()
{
FileData* file = (mList.size() == 0 || mList.isScrolling()) ? NULL : mList.getSelected();
FileData* file = (mList.size() == 0 || mList.isScrolling()) ? nullptr : mList.getSelected();
bool fadingOut;
if (file == nullptr) {

View file

@ -264,7 +264,7 @@ void VideoGameListView::initMDValues()
void VideoGameListView::updateInfoPanel()
{
FileData* file = (mList.size() == 0 || mList.isScrolling()) ? NULL : mList.getSelected();
FileData* file = (mList.size() == 0 || mList.isScrolling()) ? nullptr : mList.getSelected();
Utils::FileSystem::removeFile(getTitlePath());

View file

@ -16,7 +16,7 @@
GuiComponent::GuiComponent(Window* window)
: mWindow(window),
mParent(NULL),
mParent(nullptr),
mOpacity(255),
mPosition(Vector3f::Zero()),
mOrigin(Vector2f::Zero()),
@ -27,7 +27,7 @@ GuiComponent::GuiComponent(Window* window)
mVisible(true)
{
for (unsigned char i = 0; i < MAX_ANIMATIONS; i++)
mAnimationMap[i] = NULL;
mAnimationMap[i] = nullptr;
}
GuiComponent::~GuiComponent()
@ -40,7 +40,7 @@ GuiComponent::~GuiComponent()
mParent->removeChild(this);
for (unsigned int i = 0; i < getChildCount(); i++)
getChild(i)->setParent(NULL);
getChild(i)->setParent(nullptr);
}
bool GuiComponent::input(InputConfig* config, Input input)
@ -203,7 +203,7 @@ void GuiComponent::removeChild(GuiComponent* cmp)
if (cmp->getParent() != this)
LOG(LogError) << "Tried to remove child from incorrect parent!";
cmp->setParent(NULL);
cmp->setParent(nullptr);
for (auto i = mChildren.cbegin(); i != mChildren.cend(); i++) {
if (*i == cmp) {
@ -334,7 +334,7 @@ bool GuiComponent::stopAnimation(unsigned char slot)
assert(slot < MAX_ANIMATIONS);
if (mAnimationMap[slot]) {
delete mAnimationMap[slot];
mAnimationMap[slot] = NULL;
mAnimationMap[slot] = nullptr;
return true;
}
else {
@ -348,7 +348,7 @@ bool GuiComponent::cancelAnimation(unsigned char slot)
if (mAnimationMap[slot]) {
mAnimationMap[slot]->removeFinishedCallback();
delete mAnimationMap[slot];
mAnimationMap[slot] = NULL;
mAnimationMap[slot] = nullptr;
return true;
}
else {
@ -366,7 +366,7 @@ bool GuiComponent::finishAnimation(unsigned char slot)
assert(done);
delete mAnimationMap[slot]; // Will also call finishedCallback
mAnimationMap[slot] = NULL;
mAnimationMap[slot] = nullptr;
return true;
}
else {
@ -381,7 +381,7 @@ bool GuiComponent::advanceAnimation(unsigned char slot, unsigned int time)
if (anim) {
bool done = anim->update(time);
if (done) {
mAnimationMap[slot] = NULL;
mAnimationMap[slot] = nullptr;
delete anim;
}
return true;
@ -405,18 +405,18 @@ void GuiComponent::cancelAllAnimations()
bool GuiComponent::isAnimationPlaying(unsigned char slot) const
{
return mAnimationMap[slot] != NULL;
return mAnimationMap[slot] != nullptr;
}
bool GuiComponent::isAnimationReversed(unsigned char slot) const
{
assert(mAnimationMap[slot] != NULL);
assert(mAnimationMap[slot] != nullptr);
return mAnimationMap[slot]->isReversed();
}
int GuiComponent::getAnimationTime(unsigned char slot) const
{
assert(mAnimationMap[slot] != NULL);
assert(mAnimationMap[slot] != nullptr);
return mAnimationMap[slot]->getTime();
}

View file

@ -1,13 +1,18 @@
//
// InputConfig.cpp
//
// Input device configuration functions.
//
#include "InputConfig.h"
#include "Log.h"
#include <pugixml/src/pugixml.hpp>
//some util functions
// Some utility functions.
std::string inputTypeToString(InputType type)
{
switch(type)
{
switch (type) {
case TYPE_AXIS:
return "axis";
case TYPE_BUTTON:
@ -25,32 +30,35 @@ std::string inputTypeToString(InputType type)
InputType stringToInputType(const std::string& type)
{
if(type == "axis")
if (type == "axis")
return TYPE_AXIS;
if(type == "button")
if (type == "button")
return TYPE_BUTTON;
if(type == "hat")
if (type == "hat")
return TYPE_HAT;
if(type == "key")
if (type == "key")
return TYPE_KEY;
if(type == "cec-button")
if (type == "cec-button")
return TYPE_CEC_BUTTON;
return TYPE_COUNT;
}
std::string toLower(std::string str)
{
for(unsigned int i = 0; i < str.length(); i++)
{
for (unsigned int i = 0; i < str.length(); i++)
str[i] = (char)tolower(str[i]);
}
return str;
}
//end util functions
// End of utility functions.
InputConfig::InputConfig(int deviceId, const std::string& deviceName, const std::string& deviceGUID) : mDeviceId(deviceId), mDeviceName(deviceName), mDeviceGUID(deviceGUID)
InputConfig::InputConfig(
int deviceId,
const std::string& deviceName,
const std::string& deviceGUID)
: mDeviceId(deviceId),
mDeviceName(deviceName),
mDeviceGUID(deviceGUID)
{
}
@ -72,63 +80,66 @@ void InputConfig::mapInput(const std::string& name, Input input)
void InputConfig::unmapInput(const std::string& name)
{
auto it = mNameMap.find(toLower(name));
if(it != mNameMap.cend())
if (it != mNameMap.cend())
mNameMap.erase(it);
}
bool InputConfig::getInputByName(const std::string& name, Input* result)
{
auto it = mNameMap.find(toLower(name));
if(it != mNameMap.cend())
{
if (it != mNameMap.cend()) {
*result = it->second;
return true;
}
return false;
}
bool InputConfig::isMappedTo(const std::string& name, Input input)
{
Input comp;
if(!getInputByName(name, &comp))
if (!getInputByName(name, &comp))
return false;
if(comp.configured && comp.type == input.type && comp.id == input.id)
{
if(comp.type == TYPE_HAT)
{
if (comp.configured && comp.type == input.type && comp.id == input.id) {
if (comp.type == TYPE_HAT)
return (input.value == 0 || input.value & comp.value);
}
if(comp.type == TYPE_AXIS)
{
if (comp.type == TYPE_AXIS)
return input.value == 0 || comp.value == input.value;
}else{
else
return true;
}
}
return false;
}
bool InputConfig::isMappedLike(const std::string& name, Input input)
{
if(name == "left")
{
return isMappedTo("left", input) || isMappedTo("leftanalogleft", input) || isMappedTo("rightanalogleft", input);
}else if(name == "right"){
return isMappedTo("right", input) || isMappedTo("leftanalogright", input) || isMappedTo("rightanalogright", input);
}else if(name == "up"){
return isMappedTo("up", input) || isMappedTo("leftanalogup", input) || isMappedTo("rightanalogup", input);
}else if(name == "down"){
return isMappedTo("down", input) || isMappedTo("leftanalogdown", input) || isMappedTo("rightanalogdown", input);
}else if(name == "leftshoulder"){
if (name == "left") {
return isMappedTo("left", input) || isMappedTo("leftanalogleft", input) ||
isMappedTo("rightanalogleft", input);
}
else if (name == "right") {
return isMappedTo("right", input) || isMappedTo("leftanalogright", input) ||
isMappedTo("rightanalogright", input);
}
else if (name == "up") {
return isMappedTo("up", input) || isMappedTo("leftanalogup", input) ||
isMappedTo("rightanalogup", input);
}
else if (name == "down") {
return isMappedTo("down", input) || isMappedTo("leftanalogdown", input) ||
isMappedTo("rightanalogdown", input);
}
else if (name == "leftshoulder") {
return isMappedTo("leftshoulder", input) || isMappedTo("pageup", input);
}else if(name == "rightshoulder"){
}
else if (name == "rightshoulder") {
return isMappedTo("rightshoulder", input) || isMappedTo("pagedown", input);
}else if(name == "lefttrigger"){
}
else if (name == "lefttrigger") {
return isMappedTo("lefttrigger", input) || isMappedTo("home", input);
}else if(name == "righttrigger"){
}
else if (name == "righttrigger") {
return isMappedTo("righttrigger", input) || isMappedTo("end", input);
}
return isMappedTo(name, input);
@ -139,34 +150,28 @@ std::vector<std::string> InputConfig::getMappedTo(Input input)
std::vector<std::string> maps;
typedef std::map<std::string, Input>::const_iterator it_type;
for(it_type iterator = mNameMap.cbegin(); iterator != mNameMap.cend(); iterator++)
{
for (it_type iterator = mNameMap.cbegin(); iterator != mNameMap.cend(); iterator++) {
Input chk = iterator->second;
if(!chk.configured)
if (!chk.configured)
continue;
if(chk.device == input.device && chk.type == input.type && chk.id == input.id)
{
if(chk.type == TYPE_HAT)
{
if(input.value == 0 || input.value & chk.value)
{
if (chk.device == input.device && chk.type == input.type && chk.id == input.id) {
if (chk.type == TYPE_HAT) {
if (input.value == 0 || input.value & chk.value)
maps.push_back(iterator->first);
}
continue;
}
if(input.type == TYPE_AXIS)
{
if(input.value == 0 || chk.value == input.value)
if (input.type == TYPE_AXIS) {
if (input.value == 0 || chk.value == input.value)
maps.push_back(iterator->first);
}else{
}
else {
maps.push_back(iterator->first);
}
}
}
return maps;
}
@ -174,23 +179,23 @@ void InputConfig::loadFromXML(pugi::xml_node& node)
{
clear();
for(pugi::xml_node input = node.child("input"); input; input = input.next_sibling("input"))
{
for (pugi::xml_node input = node.child("input"); input; input = input.next_sibling("input")) {
std::string name = input.attribute("name").as_string();
std::string type = input.attribute("type").as_string();
InputType typeEnum = stringToInputType(type);
if(typeEnum == TYPE_COUNT)
{
LOG(LogError) << "InputConfig load error - input of type \"" << type << "\" is invalid! Skipping input \"" << name << "\".\n";
if (typeEnum == TYPE_COUNT) {
LOG(LogError) << "InputConfig load error - input of type \"" << type <<
"\" is invalid! Skipping input \"" << name << "\".\n";
continue;
}
int id = input.attribute("id").as_int();
int value = input.attribute("value").as_int();
if(value == 0)
LOG(LogWarning) << "WARNING: InputConfig value is 0 for " << type << " " << id << "!\n";
if (value == 0)
LOG(LogWarning) << "WARNING: InputConfig value is 0 for " <<
type << " " << id << "!\n";
mNameMap[toLower(name)] = Input(mDeviceId, typeEnum, id, value, true);
}
@ -200,18 +205,15 @@ void InputConfig::writeToXML(pugi::xml_node& parent)
{
pugi::xml_node cfg = parent.append_child("inputConfig");
if(mDeviceId == DEVICE_KEYBOARD)
{
if (mDeviceId == DEVICE_KEYBOARD) {
cfg.append_attribute("type") = "keyboard";
cfg.append_attribute("deviceName") = "Keyboard";
}
else if(mDeviceId == DEVICE_CEC)
{
else if (mDeviceId == DEVICE_CEC) {
cfg.append_attribute("type") = "cec";
cfg.append_attribute("deviceName") = "CEC";
}
else
{
else {
cfg.append_attribute("type") = "joystick";
cfg.append_attribute("deviceName") = mDeviceName.c_str();
}
@ -219,9 +221,8 @@ void InputConfig::writeToXML(pugi::xml_node& parent)
cfg.append_attribute("deviceGUID") = mDeviceGUID.c_str();
typedef std::map<std::string, Input>::const_iterator it_type;
for(it_type iterator = mNameMap.cbegin(); iterator != mNameMap.cend(); iterator++)
{
if(!iterator->second.configured)
for (it_type iterator = mNameMap.cbegin(); iterator != mNameMap.cend(); iterator++) {
if (!iterator->second.configured)
continue;
pugi::xml_node input = cfg.append_child("input");

View file

@ -1,3 +1,9 @@
//
// InputConfig.h
//
// Input device configuration functions.
//
#pragma once
#ifndef ES_CORE_INPUT_CONFIG_H
#define ES_CORE_INPUT_CONFIG_H
@ -14,8 +20,7 @@ namespace pugi { class xml_node; }
#define DEVICE_KEYBOARD -1
#define DEVICE_CEC -2
enum InputType
{
enum InputType {
TYPE_AXIS,
TYPE_BUTTON,
TYPE_HAT,
@ -42,19 +47,28 @@ public:
type = TYPE_COUNT;
}
Input(int dev, InputType t, int i, int val, bool conf) : device(dev), type(t), id(i), value(val), configured(conf)
Input(
int dev,
InputType t,
int i,
int val,
bool conf)
: device(dev),
type(t),id(i),
value(val),
configured(conf)
{
}
std::string getHatDir(int val)
{
if(val & SDL_HAT_UP)
if (val & SDL_HAT_UP)
return "up";
else if(val & SDL_HAT_DOWN)
else if (val & SDL_HAT_DOWN)
return "down";
else if(val & SDL_HAT_LEFT)
else if (val & SDL_HAT_LEFT)
return "left";
else if(val & SDL_HAT_RIGHT)
else if (val & SDL_HAT_RIGHT)
return "right";
return "neutral?";
}
@ -67,8 +81,7 @@ public:
std::string string()
{
std::stringstream stream;
switch(type)
{
switch (type) {
case TYPE_BUTTON:
stream << "Button " << id;
break;
@ -100,17 +113,17 @@ public:
void clear();
void mapInput(const std::string& name, Input input);
void unmapInput(const std::string& name); // unmap all Inputs mapped to this name
void unmapInput(const std::string& name); // Unmap all Inputs mapped to this name.
inline int getDeviceId() const { return mDeviceId; };
inline const std::string& getDeviceName() { return mDeviceName; }
inline const std::string& getDeviceGUIDString() { return mDeviceGUID; }
//Returns true if Input is mapped to this name, false otherwise.
// Returns true if Input is mapped to this name, false otherwise.
bool isMappedTo(const std::string& name, Input input);
bool isMappedLike(const std::string& name, Input input);
//Returns a list of names this input is mapped to.
// Returns a list of names this input is mapped to.
std::vector<std::string> getMappedTo(Input input);
// Returns true if there is an Input mapped to this name, false otherwise.

View file

@ -455,7 +455,7 @@ std::string InputManager::getTemporaryConfigPath()
bool InputManager::initialized() const
{
return mKeyboardInputConfig != NULL;
return mKeyboardInputConfig != nullptr;
}
int InputManager::getNumConfiguredDevices()

View file

@ -1,3 +1,9 @@
//
// GuiDetectDevice.cpp
//
// Detect input devices (keyboards, joysticks and gamepads).
//
#include "guis/GuiDetectDevice.h"
#include "components/TextComponent.h"
@ -10,53 +16,65 @@
#define HOLD_TIME 1000
GuiDetectDevice::GuiDetectDevice(Window* window, bool firstRun, const std::function<void()>& doneCallback) : GuiComponent(window), mFirstRun(firstRun),
mBackground(window, ":/graphics/frame.png"), mGrid(window, Vector2i(1, 5))
GuiDetectDevice::GuiDetectDevice(
Window* window,
bool firstRun,
const std::function<void()>& doneCallback)
: GuiComponent(window),
mFirstRun(firstRun),
mBackground(window, ":/graphics/frame.png"),
mGrid(window, Vector2i(1, 5))
{
mHoldingConfig = NULL;
mHoldingConfig = nullptr;
mHoldTime = 0;
mDoneCallback = doneCallback;
addChild(&mBackground);
addChild(&mGrid);
// title
// Title.
mTitle = std::make_shared<TextComponent>(mWindow, firstRun ? "WELCOME" : "CONFIGURE INPUT",
Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
mGrid.setEntry(mTitle, Vector2i(0, 0), false, true, Vector2i(1, 1), GridFlags::BORDER_BOTTOM);
// device info
// Device info.
std::stringstream deviceInfo;
int numDevices = InputManager::getInstance()->getNumJoysticks();
if(numDevices > 0)
if (numDevices > 0)
deviceInfo << numDevices << " GAMEPAD" << (numDevices > 1 ? "S" : "") << " DETECTED";
else
deviceInfo << "NO GAMEPADS DETECTED";
mDeviceInfo = std::make_shared<TextComponent>(mWindow, deviceInfo.str(), Font::get(FONT_SIZE_SMALL), 0x999999FF, ALIGN_CENTER);
mDeviceInfo = std::make_shared<TextComponent>(mWindow, deviceInfo.str(),
Font::get(FONT_SIZE_SMALL), 0x999999FF, ALIGN_CENTER);
mGrid.setEntry(mDeviceInfo, Vector2i(0, 1), false, true);
// message
mMsg1 = std::make_shared<TextComponent>(mWindow, "HOLD A BUTTON ON YOUR DEVICE TO CONFIGURE IT.", Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_CENTER);
// Message.
mMsg1 = std::make_shared<TextComponent>(mWindow,
"HOLD A BUTTON ON YOUR DEVICE TO CONFIGURE IT.",
Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_CENTER);
mGrid.setEntry(mMsg1, Vector2i(0, 2), false, true);
const char* msg2str = firstRun ? "PRESS F4 TO QUIT AT ANY TIME." : "PRESS ESC TO CANCEL.";
mMsg2 = std::make_shared<TextComponent>(mWindow, msg2str, Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_CENTER);
mMsg2 = std::make_shared<TextComponent>(mWindow, msg2str,
Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_CENTER);
mGrid.setEntry(mMsg2, Vector2i(0, 3), false, true);
// currently held device
mDeviceHeld = std::make_shared<TextComponent>(mWindow, "", Font::get(FONT_SIZE_MEDIUM), 0xFFFFFFFF, ALIGN_CENTER);
// Currently held device.
mDeviceHeld = std::make_shared<TextComponent>(mWindow, "",
Font::get(FONT_SIZE_MEDIUM), 0xFFFFFFFF, ALIGN_CENTER);
mGrid.setEntry(mDeviceHeld, Vector2i(0, 4), false, true);
setSize(Renderer::getScreenWidth() * 0.6f, Renderer::getScreenHeight() * 0.5f);
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, (Renderer::getScreenHeight() - mSize.y()) / 2);
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2,
(Renderer::getScreenHeight() - mSize.y()) / 2);
}
void GuiDetectDevice::onSizeChanged()
{
mBackground.fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32));
// grid
// Grid.
mGrid.setSize(mSize);
mGrid.setRowHeightPerc(0, mTitle->getFont()->getHeight() / mSize.y());
//mGrid.setRowHeightPerc(1, mDeviceInfo->getFont()->getHeight() / mSize.y());
@ -69,54 +87,49 @@ bool GuiDetectDevice::input(InputConfig* config, Input input)
{
PowerSaver::pause();
if(!mFirstRun && input.device == DEVICE_KEYBOARD && input.type == TYPE_KEY && input.value && input.id == SDLK_ESCAPE)
{
// cancel configuring
if (!mFirstRun && input.device == DEVICE_KEYBOARD && input.type == TYPE_KEY &&
input.value && input.id == SDLK_ESCAPE) {
// Cancel the configuration.
PowerSaver::resume();
delete this;
return true;
}
if(input.type == TYPE_BUTTON || input.type == TYPE_KEY ||input.type == TYPE_CEC_BUTTON)
{
if(input.value && mHoldingConfig == NULL)
{
// started holding
if (input.type == TYPE_BUTTON || input.type == TYPE_KEY ||input.type == TYPE_CEC_BUTTON) {
if (input.value && mHoldingConfig == nullptr) {
// Started holding.
mHoldingConfig = config;
mHoldTime = HOLD_TIME;
mDeviceHeld->setText(Utils::String::toUpper(config->getDeviceName()));
}else if(!input.value && mHoldingConfig == config)
{
// cancel
mHoldingConfig = NULL;
}
else if (!input.value && mHoldingConfig == config) {
// Cancel.
mHoldingConfig = nullptr;
mDeviceHeld->setText("");
}
}
return true;
}
void GuiDetectDevice::update(int deltaTime)
{
if(mHoldingConfig)
{
// If ES starts and if a known device is connected after startup skip controller configuration
if(mFirstRun && Utils::FileSystem::exists(InputManager::getConfigPath()) && InputManager::getInstance()->getNumConfiguredDevices() > 0)
{
if(mDoneCallback)
if (mHoldingConfig) {
// If ES starts and if a known device is connected after startup
// skip controller configuration.
if (mFirstRun && Utils::FileSystem::exists(InputManager::getConfigPath()) &&
InputManager::getInstance()->getNumConfiguredDevices() > 0) {
if (mDoneCallback)
mDoneCallback();
PowerSaver::resume();
delete this; // delete GUI element
delete this; // Delete GUI element.
}
else
{
else {
mHoldTime -= deltaTime;
const float t = (float)mHoldTime / HOLD_TIME;
unsigned int c = (unsigned char)(t * 255);
mDeviceHeld->setColor((c << 24) | (c << 16) | (c << 8) | 0xFF);
if(mHoldTime <= 0)
{
// picked one!
if (mHoldTime <= 0) {
// Picked one!
mWindow->pushGui(new GuiInputConfig(mWindow, mHoldingConfig, true, mDoneCallback));
PowerSaver::resume();
delete this;

View file

@ -1,3 +1,9 @@
//
// GuiDetectDevice.h
//
// Detect input devices (keyboards, joysticks and gamepads).
//
#pragma once
#ifndef ES_CORE_GUIS_GUI_DETECT_DEVICE_H
#define ES_CORE_GUIS_GUI_DETECT_DEVICE_H

View file

@ -1,3 +1,9 @@
//
// GuiInputConfig.cpp
//
// Input device configuration GUI (for keyboards, joysticks and gamepads).
//
#include "guis/GuiInputConfig.h"
#include "components/ButtonComponent.h"
@ -7,8 +13,7 @@
#include "Log.h"
#include "Window.h"
struct InputConfigStructure
{
struct InputConfigStructure {
const char* name;
const bool skippable;
const char* dispName;
@ -16,6 +21,7 @@ struct InputConfigStructure
};
static const int inputCount = 22;
static const InputConfigStructure GUI_INPUT_CONFIG_LIST[inputCount] =
{
{ "Up", false, "D-PAD UP", ":/help/dpad_up.svg" },
@ -45,18 +51,27 @@ static const InputConfigStructure GUI_INPUT_CONFIG_LIST[inputCount] =
// { "HotKeyEnable", true, "HOTKEY ENABLE", ":/help/button_hotkey.svg" }
};
//MasterVolUp and MasterVolDown are also hooked up, but do not appear on this screen.
//If you want, you can manually add them to es_input.cfg.
// MasterVolUp and MasterVolDown are also hooked up, but do not appear on this screen.
// If you want, you can manually add them to es_input.cfg.
#define HOLD_TO_SKIP_MS 1000
GuiInputConfig::GuiInputConfig(Window* window, InputConfig* target, bool reconfigureAll, const std::function<void()>& okCallback) : GuiComponent(window),
mBackground(window, ":/graphics/frame.png"), mGrid(window, Vector2i(1, 7)),
mTargetConfig(target), mHoldingInput(false), mBusyAnim(window)
GuiInputConfig::GuiInputConfig(
Window* window,
InputConfig* target,
bool reconfigureAll,
const std::function<void()>& okCallback)
: GuiComponent(window),
mBackground(window, ":/graphics/frame.png"),
mGrid(window, Vector2i(1, 7)),
mTargetConfig(target),
mHoldingInput(false),
mBusyAnim(window)
{
LOG(LogInfo) << "Configuring device " << target->getDeviceId() << " (" << target->getDeviceName() << ").";
LOG(LogInfo) << "Configuring device " << target->getDeviceId() << " (" <<
target->getDeviceName() << ").";
if(reconfigureAll)
if (reconfigureAll)
target->clear();
mConfiguringAll = reconfigureAll;
@ -65,84 +80,83 @@ GuiInputConfig::GuiInputConfig(Window* window, InputConfig* target, bool reconfi
addChild(&mBackground);
addChild(&mGrid);
// 0 is a spacer row
// 0 is a spacer row.
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 0), false);
mTitle = std::make_shared<TextComponent>(mWindow, "CONFIGURING", Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
mTitle = std::make_shared<TextComponent>(mWindow, "CONFIGURING",
Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
mGrid.setEntry(mTitle, Vector2i(0, 1), false, true);
std::stringstream ss;
if(target->getDeviceId() == DEVICE_KEYBOARD)
if (target->getDeviceId() == DEVICE_KEYBOARD)
ss << "KEYBOARD";
else if(target->getDeviceId() == DEVICE_CEC)
else if (target->getDeviceId() == DEVICE_CEC)
ss << "CEC";
else
ss << "GAMEPAD " << (target->getDeviceId() + 1);
mSubtitle1 = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(ss.str()), Font::get(FONT_SIZE_MEDIUM), 0x555555FF, ALIGN_CENTER);
mSubtitle1 = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(ss.str()),
Font::get(FONT_SIZE_MEDIUM), 0x555555FF, ALIGN_CENTER);
mGrid.setEntry(mSubtitle1, Vector2i(0, 2), false, true);
mSubtitle2 = std::make_shared<TextComponent>(mWindow, "HOLD ANY BUTTON TO SKIP", Font::get(FONT_SIZE_SMALL), 0x999999FF, ALIGN_CENTER);
mSubtitle2 = std::make_shared<TextComponent>(mWindow, "HOLD ANY BUTTON TO SKIP",
Font::get(FONT_SIZE_SMALL), 0x999999FF, ALIGN_CENTER);
mGrid.setEntry(mSubtitle2, Vector2i(0, 3), false, true);
// 4 is a spacer row
// 4 is a spacer row.
mList = std::make_shared<ComponentList>(mWindow);
mGrid.setEntry(mList, Vector2i(0, 5), true, true);
for(int i = 0; i < inputCount; i++)
{
for (int i = 0; i < inputCount; i++) {
ComponentListRow row;
// icon
// Icon.
auto icon = std::make_shared<ImageComponent>(mWindow);
icon->setImage(GUI_INPUT_CONFIG_LIST[i].icon);
icon->setColorShift(0x777777FF);
icon->setResize(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() * 1.25f);
row.addElement(icon, false);
// spacer between icon and text
// Spacer between icon and text.
auto spacer = std::make_shared<GuiComponent>(mWindow);
spacer->setSize(16, 0);
row.addElement(spacer, false);
auto text = std::make_shared<TextComponent>(mWindow, GUI_INPUT_CONFIG_LIST[i].dispName, Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
auto text = std::make_shared<TextComponent>(mWindow,
GUI_INPUT_CONFIG_LIST[i].dispName, Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
row.addElement(text, true);
auto mapping = std::make_shared<TextComponent>(mWindow, "-NOT DEFINED-", Font::get(FONT_SIZE_MEDIUM, FONT_PATH_LIGHT), 0x999999FF, ALIGN_RIGHT);
setNotDefined(mapping); // overrides text and color set above
auto mapping = std::make_shared<TextComponent>(mWindow, "-NOT DEFINED-",
Font::get(FONT_SIZE_MEDIUM, FONT_PATH_LIGHT), 0x999999FF, ALIGN_RIGHT);
setNotDefined(mapping); // Overrides the text and color set above.
row.addElement(mapping, true);
mMappings.push_back(mapping);
row.input_handler = [this, i, mapping](InputConfig* config, Input input) -> bool
{
// ignore input not from our target device
if(config != mTargetConfig)
row.input_handler = [this, i, mapping](InputConfig* config, Input input) -> bool {
// Ignore input not from our target device.
if (config != mTargetConfig)
return false;
// if we're not configuring, start configuring when A is pressed
if(!mConfiguringRow)
{
if(config->isMappedTo("a", input) && input.value)
{
// If we're not configuring, start configuring when A is pressed.
if (!mConfiguringRow) {
if (config->isMappedTo("a", input) && input.value) {
mList->stopScrolling();
mConfiguringRow = true;
setPress(mapping);
return true;
}
// we're not configuring and they didn't press A to start, so ignore this
// We're not configuring and they didn't press A to start, so ignore this.
return false;
}
// apply filtering for quirks related to trigger mapping
if(filterTrigger(input, config, i))
// Apply filtering for quirks related to trigger mapping.
if (filterTrigger(input, config, i))
return false;
// we are configuring
if(input.value != 0)
{
// input down
// if we're already holding something, ignore this, otherwise plan to map this input
if(mHoldingInput)
// We are configuring.
if (input.value != 0) {
// Input down.
// If we're already holding something, ignore this,
// otherwise plan to map this input.
if (mHoldingInput)
return true;
mHoldingInput = true;
@ -151,50 +165,57 @@ GuiInputConfig::GuiInputConfig(Window* window, InputConfig* target, bool reconfi
mHeldInputId = i;
return true;
}else{
// input up
// make sure we were holding something and we let go of what we were previously holding
if(!mHoldingInput || mHeldInput.device != input.device || mHeldInput.id != input.id || mHeldInput.type != input.type)
}
else {
// Input up.
// Make sure we were holding something and we let go of what we
// were previously holding.
if (!mHoldingInput || mHeldInput.device != input.device || mHeldInput.id !=
input.id || mHeldInput.type != input.type)
return true;
mHoldingInput = false;
if(assign(mHeldInput, i))
rowDone(); // if successful, move cursor/stop configuring - if not, we'll just try again
if (assign(mHeldInput, i))
// If successful, move cursor/stop configuring - if not,
// we'll just try again.
rowDone();
return true;
}
};
mList->addRow(row);
}
// only show "HOLD TO SKIP" if this input is skippable
// Only show "HOLD TO SKIP" if this input is skippable.
mList->setCursorChangedCallback([this](CursorState /*state*/) {
bool skippable = GUI_INPUT_CONFIG_LIST[mList->getCursorId()].skippable;
mSubtitle2->setOpacity(skippable * 255);
});
// make the first one say "PRESS ANYTHING" if we're re-configuring everything
if(mConfiguringAll)
// Make the first one say "PRESS ANYTHING" if we're re-configuring everything.
if (mConfiguringAll)
setPress(mMappings.front());
// buttons
// Buttons.
std::vector< std::shared_ptr<ButtonComponent> > buttons;
std::function<void()> okFunction = [this, okCallback] {
InputManager::getInstance()->writeDeviceConfig(mTargetConfig); // save
if(okCallback)
if (okCallback)
okCallback();
delete this;
};
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "OK", "ok", [this, okFunction] {
// check if the hotkey enable button is set. if not prompt the user to use select or nothing.
// Check if the hotkey enable button is set. if not prompt the
// user to use select or nothing.
Input input;
okFunction();
// Temporary comments, needs to be properly cleaned up later.
// Temporarily commented out, needs to be properly cleaned up later.
// if (!mTargetConfig->getInputByName("HotKeyEnable", &input)) {
// mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
// "YOU DIDN'T CHOOSE A HOTKEY ENABLE BUTTON. THIS IS REQUIRED FOR EXITING GAMES WITH A CONTROLLER. DO YOU WANT TO USE THE SELECT BUTTON DEFAULT ? PLEASE ANSWER YES TO USE SELECT OR NO TO NOT SET A HOTKEY ENABLE BUTTON.",
// "YOU DIDN'T CHOOSE A HOTKEY ENABLE BUTTON. THIS IS REQUIRED FOR EXITING GAMES "
// "WITH A CONTROLLER. DO YOU WANT TO USE THE SELECT BUTTON DEFAULT ? PLEASE ANSWER "
// "YES TO USE SELECT OR NO TO NOT SET A HOTKEY ENABLE BUTTON.",
// "YES", [this, okFunction] {
// Input input;
// mTargetConfig->getInputByName("Select", &input);
@ -204,26 +225,30 @@ GuiInputConfig::GuiInputConfig(Window* window, InputConfig* target, bool reconfi
// "NO", [this, okFunction] {
// // for a disabled hotkey enable button, set to a key with id 0,
// // so the input configuration script can be backwards compatible.
// mTargetConfig->mapInput("HotKeyEnable", Input(DEVICE_KEYBOARD, TYPE_KEY, 0, 1, true));
// mTargetConfig->mapInput("HotKeyEnable", Input(DEVICE_KEYBOARD,
// TYPE_KEY, 0, 1, true));
// okFunction();
// }
// ));
// } else {
// }
// else {
// okFunction();
// }
}));
mButtonGrid = makeButtonGrid(mWindow, buttons);
mGrid.setEntry(mButtonGrid, Vector2i(0, 6), true, false);
setSize(Renderer::getScreenWidth() * 0.6f, Renderer::getScreenHeight() * 0.75f);
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, (Renderer::getScreenHeight() - mSize.y()) / 2);
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2,
(Renderer::getScreenHeight() - mSize.y()) / 2);
}
void GuiInputConfig::onSizeChanged()
{
mBackground.fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32));
// update grid
// Update grid.
mGrid.setSize(mSize);
//mGrid.setRowHeightPerc(0, 0.025f);
@ -239,22 +264,20 @@ void GuiInputConfig::onSizeChanged()
void GuiInputConfig::update(int deltaTime)
{
if(mConfiguringRow && mHoldingInput && GUI_INPUT_CONFIG_LIST[mHeldInputId].skippable)
{
if (mConfiguringRow && mHoldingInput && GUI_INPUT_CONFIG_LIST[mHeldInputId].skippable) {
int prevSec = mHeldTime / 1000;
mHeldTime += deltaTime;
int curSec = mHeldTime / 1000;
if(mHeldTime >= HOLD_TO_SKIP_MS)
{
if (mHeldTime >= HOLD_TO_SKIP_MS) {
setNotDefined(mMappings.at(mHeldInputId));
clearAssignment(mHeldInputId);
mHoldingInput = false;
rowDone();
}else{
if(prevSec != curSec)
{
// crossed the second boundary, update text
}
else {
if (prevSec != curSec) {
// Crossed the second boundary, update text.
const auto& text = mMappings.at(mHeldInputId);
std::stringstream ss;
ss << "HOLD FOR " << HOLD_TO_SKIP_MS/1000 - curSec << "S TO SKIP";
@ -265,24 +288,25 @@ void GuiInputConfig::update(int deltaTime)
}
}
// move cursor to the next thing if we're configuring all,
// or come out of "configure mode" if we were only configuring one row
// Move cursor to the next thing if we're configuring all,
// or come out of "configure mode" if we were only configuring one row.
void GuiInputConfig::rowDone()
{
if(mConfiguringAll)
{
if(!mList->moveCursor(1)) // try to move to the next one
{
// at bottom of list, done
if (mConfiguringAll) {
// Try to move to the next one.
if (!mList->moveCursor(1)) {
// At bottom of list, we're done.
mConfiguringAll = false;
mConfiguringRow = false;
mGrid.moveCursor(Vector2i(0, 1));
}else{
// on another one
}
else {
// On another one.
setPress(mMappings.at(mList->getCursorId()));
}
}else{
// only configuring one row, so stop
}
else {
// Only configuring one row, so stop.
mConfiguringRow = false;
}
}
@ -313,12 +337,14 @@ void GuiInputConfig::error(const std::shared_ptr<TextComponent>& text, const std
bool GuiInputConfig::assign(Input input, int inputId)
{
// input is from InputConfig* mTargetConfig
// Input is from InputConfig* mTargetConfig.
// if this input is mapped to something other than "nothing" or the current row, error
// (if it's the same as what it was before, allow it)
if(mTargetConfig->getMappedTo(input).size() > 0 && !mTargetConfig->isMappedTo(GUI_INPUT_CONFIG_LIST[inputId].name, input) && strcmp(GUI_INPUT_CONFIG_LIST[inputId].name, "HotKeyEnable") != 0)
{
// If this input is mapped to something other than "nothing" or the current row,
// generate an error.
// (If it's the same as what it was before, allow it.)
if (mTargetConfig->getMappedTo(input).size() > 0 &&
!mTargetConfig->isMappedTo(GUI_INPUT_CONFIG_LIST[inputId].name, input) &&
strcmp(GUI_INPUT_CONFIG_LIST[inputId].name, "HotKeyEnable") != 0) {
error(mMappings.at(inputId), "Already mapped!");
return false;
}
@ -328,7 +354,8 @@ bool GuiInputConfig::assign(Input input, int inputId)
input.configured = true;
mTargetConfig->mapInput(GUI_INPUT_CONFIG_LIST[inputId].name, input);
LOG(LogInfo) << " Mapping [" << input.string() << "] -> " << GUI_INPUT_CONFIG_LIST[inputId].name;
LOG(LogInfo) << " Mapping [" << input.string() << "] -> " <<
GUI_INPUT_CONFIG_LIST[inputId].name;
return true;
}
@ -340,48 +367,44 @@ void GuiInputConfig::clearAssignment(int inputId)
bool GuiInputConfig::filterTrigger(Input input, InputConfig* config, int inputId)
{
#if defined(__linux__)
// on Linux, some gamepads return both an analog axis and a digital button for the trigger;
// we want the analog axis only, so this function removes the button press event
#if defined(__linux__)
// On Linux, some gamepads return both an analog axis and a digital button for the trigger;
// we want the analog axis only, so this function removes the button press event.
if((
// match PlayStation joystick with 6 axes only
strstr(config->getDeviceName().c_str(), "PLAYSTATION") != NULL
|| strstr(config->getDeviceName().c_str(), "PS3 Ga") != NULL
|| strstr(config->getDeviceName().c_str(), "PS(R) Ga") != NULL
// BigBen kid's PS3 gamepad 146b:0902, matched on SDL GUID because its name "Bigben Interactive Bigben Game Pad" may be too generic
|| strcmp(config->getDeviceGUIDString().c_str(), "030000006b1400000209000011010000") == 0
) && InputManager::getInstance()->getAxisCountByDevice(config->getDeviceId()) == 6)
{
// digital triggers are unwanted
if(input.type == TYPE_BUTTON && (input.id == 6 || input.id == 7))
{
if ((
// Match PlayStation joystick with 6 axes only.
strstr(config->getDeviceName().c_str(), "PLAYSTATION") != nullptr ||
strstr(config->getDeviceName().c_str(), "PS3 Ga") != nullptr ||
strstr(config->getDeviceName().c_str(), "PS(R) Ga") != nullptr ||
// BigBen kid's PS3 gamepad 146b:0902, matched on SDL GUID because its name "Bigben
// Interactive Bigben Game Pad" may be too generic.
strcmp(config->getDeviceGUIDString().c_str(), "030000006b1400000209000011010000") == 0)
&& InputManager::getInstance()->getAxisCountByDevice(config->getDeviceId()) == 6) {
// Digital triggers are unwanted.
if (input.type == TYPE_BUTTON && (input.id == 6 || input.id == 7)) {
mHoldingInput = false;
return true;
}
}
// ignore negative pole for axes 2/5 only when triggers are being configured
if(input.type == TYPE_AXIS && (input.id == 2 || input.id == 5))
{
if(strstr(GUI_INPUT_CONFIG_LIST[inputId].name, "Trigger") != NULL)
{
if(input.value == 1)
// Ignore negative pole for axes 2/5 only when triggers are being configured.
if (input.type == TYPE_AXIS && (input.id == 2 || input.id == 5)) {
if (strstr(GUI_INPUT_CONFIG_LIST[inputId].name, "Trigger") != nullptr) {
if (input.value == 1)
mSkipAxis = true;
else if(input.value == -1)
else if (input.value == -1)
return true;
}
else if(mSkipAxis)
{
else if (mSkipAxis) {
mSkipAxis = false;
return true;
}
}
#else
#else
(void)input;
(void)config;
(void)inputId;
#endif
#endif
return false;
}

View file

@ -1,3 +1,9 @@
//
// GuiInputConfig.h
//
// Input device configuration GUI (for keyboards, joysticks and gamepads).
//
#pragma once
#ifndef ES_CORE_GUIS_GUI_INPUT_CONFIG_H
#define ES_CORE_GUIS_GUI_INPUT_CONFIG_H
@ -13,18 +19,22 @@ class TextComponent;
class GuiInputConfig : public GuiComponent
{
public:
GuiInputConfig(Window* window, InputConfig* target, bool reconfigureAll, const std::function<void()>& okCallback);
GuiInputConfig(Window* window, InputConfig* target, bool reconfigureAll,
const std::function<void()>& okCallback);
void update(int deltaTime) override;
void onSizeChanged() override;
private:
void error(const std::shared_ptr<TextComponent>& text, const std::string& msg); // set text to "msg" + not greyed out
// Set text to "msg" + not greyed out.
void error(const std::shared_ptr<TextComponent>& text, const std::string& msg);
void setPress(const std::shared_ptr<TextComponent>& text); // set text to "PRESS ANYTHING" + not greyed out
void setNotDefined(const std::shared_ptr<TextComponent>& text); // set text to -NOT DEFINED- + greyed out
void setAssignedTo(const std::shared_ptr<TextComponent>& text, Input input); // set text to "BUTTON 2"/"AXIS 2+", etc.
// Set text to "PRESS ANYTHING" + not greyed out.
void setPress(const std::shared_ptr<TextComponent>& text);
// Set text to -NOT DEFINED- + greyed out.
void setNotDefined(const std::shared_ptr<TextComponent>& text);
// Set text to "BUTTON 2"/"AXIS 2+", etc.
void setAssignedTo(const std::shared_ptr<TextComponent>& text, Input input);
bool assign(Input input, int inputId);
void clearAssignment(int inputId);
@ -43,8 +53,11 @@ private:
std::shared_ptr<ComponentGrid> mButtonGrid;
InputConfig* mTargetConfig;
bool mConfiguringRow; // next input captured by mList will be interpretted as a remap
bool mConfiguringAll; // move the cursor down after configuring a row and start configuring the next row until we reach the bottom
// Next input captured by mList will be interpretted as a remap.
bool mConfiguringRow;
// Move the cursor down after configuring a row and start configuring
// the next row until we reach the bottom.
bool mConfiguringAll;
bool mHoldingInput;
Input mHeldInput;

View file

@ -2,6 +2,8 @@
// FileSystemUtil.cpp
//
// Low-level filesystem functions.
// Resolve relative paths, resolve symlinks, create directories,
// remove files etc.
//
#define _FILE_OFFSET_BITS 64
@ -100,10 +102,10 @@ namespace Utils
#else
DIR* dir = opendir(path.c_str());
if (dir != NULL) {
if (dir != nullptr) {
struct dirent* entry;
// Loop over all files in the directory.
while ((entry = readdir(dir)) != NULL) {
while ((entry = readdir(dir)) != nullptr) {
std::string name(entry->d_name);
// Ignore "." and ".."

View file

@ -2,6 +2,8 @@
// FileSystemUtil.h
//
// Low-level filesystem functions.
// Resolve relative paths, resolve symlinks, create directories,
// remove files etc.
//
#pragma once

View file

@ -1,3 +1,10 @@
//
// StringUtil.cpp
//
// Low-level string functions.
// Convert characters to Unicode, upper-/lowercase conversion, string formatting etc.
//
#include "utils/StringUtil.h"
#include <algorithm>
@ -12,186 +19,172 @@ namespace Utils
const char& c = _string[_cursor];
unsigned int result = '?';
if((c & 0x80) == 0) // 0xxxxxxx, one byte character
{
// 0xxxxxxx, one byte character.
if ((c & 0x80) == 0) {
// 0xxxxxxx
result = ((_string[_cursor++] ) );
}
else if((c & 0xE0) == 0xC0) // 110xxxxx, two byte character
{
// 110xxxxx, two byte character.
else if ((c & 0xE0) == 0xC0) {
// 110xxxxx 10xxxxxx
result = ((_string[_cursor++] & 0x1F) << 6) |
((_string[_cursor++] & 0x3F) );
}
else if((c & 0xF0) == 0xE0) // 1110xxxx, three byte character
{
// 1110xxxx, three byte character.
else if ((c & 0xF0) == 0xE0) {
// 1110xxxx 10xxxxxx 10xxxxxx
result = ((_string[_cursor++] & 0x0F) << 12) |
((_string[_cursor++] & 0x3F) << 6) |
((_string[_cursor++] & 0x3F) );
}
else if((c & 0xF8) == 0xF0) // 11110xxx, four byte character
{
// 11110xxx, four byte character.
else if ((c & 0xF8) == 0xF0) {
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
result = ((_string[_cursor++] & 0x07) << 18) |
((_string[_cursor++] & 0x3F) << 12) |
((_string[_cursor++] & 0x3F) << 6) |
((_string[_cursor++] & 0x3F) );
}
else
{
// error, invalid unicode
else {
// Error, invalid unicode.
++_cursor;
}
return result;
} // chars2Unicode
}
std::string unicode2Chars(const unsigned int _unicode)
{
std::string result;
if(_unicode < 0x80) // one byte character
{
// One byte character.
if (_unicode < 0x80) {
result += ((_unicode ) & 0xFF);
}
else if(_unicode < 0x800) // two byte character
{
// Two byte character.
else if (_unicode < 0x800) {
result += ((_unicode >> 6) & 0xFF) | 0xC0;
result += ((_unicode ) & 0x3F) | 0x80;
}
else if(_unicode < 0xFFFF) // three byte character
{
// Three byte character.
else if (_unicode < 0xFFFF) {
result += ((_unicode >> 12) & 0xFF) | 0xE0;
result += ((_unicode >> 6) & 0x3F) | 0x80;
result += ((_unicode ) & 0x3F) | 0x80;
}
else if(_unicode <= 0x1fffff) // four byte character
{
// Four byte character.
else if (_unicode <= 0x1fffff) {
result += ((_unicode >> 18) & 0xFF) | 0xF0;
result += ((_unicode >> 12) & 0x3F) | 0x80;
result += ((_unicode >> 6) & 0x3F) | 0x80;
result += ((_unicode ) & 0x3F) | 0x80;
}
else
{
// error, invalid unicode
else {
// Error, invalid unicode.
result += '?';
}
return result;
} // unicode2Chars
}
size_t nextCursor(const std::string& _string, const size_t _cursor)
{
size_t result = _cursor;
while(result < _string.length())
{
while (result < _string.length()) {
++result;
if((_string[result] & 0xC0) != 0x80) // break if current character is not 10xxxxxx
// Break if current character is not 10xxxxxx
if ((_string[result] & 0xC0) != 0x80)
break;
}
return result;
} // nextCursor
}
size_t prevCursor(const std::string& _string, const size_t _cursor)
{
size_t result = _cursor;
while(result > 0)
{
while (result > 0) {
--result;
if((_string[result] & 0xC0) != 0x80) // break if current character is not 10xxxxxx
// Break if current character is not 10xxxxxx
if ((_string[result] & 0xC0) != 0x80)
break;
}
return result;
} // prevCursor
}
size_t moveCursor(const std::string& _string, const size_t _cursor, const int _amount)
{
size_t result = _cursor;
if(_amount > 0)
{
for(int i = 0; i < _amount; ++i)
if (_amount > 0) {
for (int i = 0; i < _amount; ++i)
result = nextCursor(_string, result);
}
else if(_amount < 0)
{
for(int i = _amount; i < 0; ++i)
else if (_amount < 0) {
for (int i = _amount; i < 0; ++i)
result = prevCursor(_string, result);
}
return result;
} // moveCursor
}
std::string toLower(const std::string& _string)
{
std::string string;
for(size_t i = 0; i < _string.length(); ++i)
for (size_t i = 0; i < _string.length(); ++i)
string += (char)tolower(_string[i]);
return string;
} // toLower
}
std::string toUpper(const std::string& _string)
{
std::string string;
for(size_t i = 0; i < _string.length(); ++i)
for (size_t i = 0; i < _string.length(); ++i)
string += (char)toupper(_string[i]);
return string;
} // toUpper
}
std::string trim(const std::string& _string)
{
const size_t strBegin = _string.find_first_not_of(" \t");
const size_t strEnd = _string.find_last_not_of(" \t");
if(strBegin == std::string::npos)
if (strBegin == std::string::npos)
return "";
return _string.substr(strBegin, strEnd - strBegin + 1);
}
} // trim
std::string replace(const std::string& _string, const std::string& _replace, const std::string& _with)
std::string replace(const std::string& _string, const std::string& _replace,
const std::string& _with)
{
std::string string = _string;
size_t pos;
while((pos = string.find(_replace)) != std::string::npos)
while ((pos = string.find(_replace)) != std::string::npos)
string = string.replace(pos, _replace.length(), _with.c_str(), _with.length());
return string;
} // replace
}
bool startsWith(const std::string& _string, const std::string& _start)
{
return (_string.find(_start) == 0);
} // startsWith
}
bool endsWith(const std::string& _string, const std::string& _end)
{
return (_string.find(_end) == (_string.size() - _end.size()));
} // endsWith
}
std::string removeParenthesis(const std::string& _string)
{
@ -201,17 +194,14 @@ namespace Utils
size_t end;
bool done = false;
while(!done)
{
while (!done) {
done = true;
for(size_t i = 0; i < sizeof(remove); i += 2)
{
for (size_t i = 0; i < sizeof(remove); i += 2) {
end = string.find_first_of(remove[i + 1]);
start = string.find_last_of( remove[i + 0], end);
if((start != std::string::npos) && (end != std::string::npos))
{
if ((start != std::string::npos) && (end != std::string::npos)) {
string.erase(start, end - start + 1);
done = false;
}
@ -219,17 +209,16 @@ namespace Utils
}
return trim(string);
}
} // removeParenthesis
stringVector delimitedStringToVector(const std::string& _string, const std::string& _delimiter, bool sort)
stringVector delimitedStringToVector(const std::string& _string,
const std::string& _delimiter, bool sort)
{
stringVector vector;
size_t start = 0;
size_t comma = _string.find(_delimiter);
while(comma != std::string::npos)
{
while (comma != std::string::npos) {
vector.push_back(_string.substr(start, comma - start));
start = comma + 1;
comma = _string.find(_delimiter, start);
@ -240,13 +229,12 @@ namespace Utils
std::sort(vector.begin(), vector.end());
return vector;
} // delimitedStringToVector
}
stringVector commaStringToVector(const std::string& _string, bool sort)
{
return delimitedStringToVector(_string, ",", sort);
} // commaStringToVector
}
std::string vectorToCommaString(stringVector _vector)
{
@ -254,12 +242,11 @@ namespace Utils
std::sort(_vector.begin(), _vector.end());
for(stringVector::const_iterator it = _vector.cbegin(); it != _vector.cend(); ++it)
for (stringVector::const_iterator it = _vector.cbegin(); it != _vector.cend(); ++it)
string += (string.length() ? "," : "") + (*it);
return string;
} // vectorToCommaString
}
std::string format(const char* _format, ...)
{
@ -283,21 +270,17 @@ namespace Utils
delete buffer;
return out;
} // format
}
std::string scramble(const std::string& _input, const std::string& _key)
{
std::string buffer = _input;
for(size_t i = 0; i < _input.size(); ++i)
{
for (size_t i = 0; i < _input.size(); ++i)
buffer[i] = _input[i] ^ _key[i];
}
return buffer;
} // scramble
}
} // String::

View file

@ -1,3 +1,10 @@
//
// StringUtil.h
//
// Low-level string functions.
// Convert characters to Unicode, upper-/lowercase conversion, string formatting etc.
//
#pragma once
#ifndef ES_CORE_UTILS_STRING_UTIL_H
#define ES_CORE_UTILS_STRING_UTIL_H
@ -11,23 +18,25 @@ namespace Utils
{
typedef std::vector<std::string> stringVector;
unsigned int chars2Unicode (const std::string& _string, size_t& _cursor);
std::string unicode2Chars (const unsigned int _unicode);
size_t nextCursor (const std::string& _string, const size_t _cursor);
size_t prevCursor (const std::string& _string, const size_t _cursor);
size_t moveCursor (const std::string& _string, const size_t _cursor, const int _amount);
std::string toLower (const std::string& _string);
std::string toUpper (const std::string& _string);
std::string trim (const std::string& _string);
std::string replace (const std::string& _string, const std::string& _replace, const std::string& _with);
bool startsWith (const std::string& _string, const std::string& _start);
bool endsWith (const std::string& _string, const std::string& _end);
std::string removeParenthesis (const std::string& _string);
stringVector delimitedStringToVector(const std::string& _string, const std::string& _delimiter, bool sort = false);
stringVector commaStringToVector (const std::string& _string, bool sort = false);
std::string vectorToCommaString (stringVector _vector);
std::string format (const char* _string, ...);
std::string scramble (const std::string& _input, const std::string& key);
unsigned int chars2Unicode(const std::string& _string, size_t& _cursor);
std::string unicode2Chars(const unsigned int _unicode);
size_t nextCursor(const std::string& _string, const size_t _cursor);
size_t prevCursor(const std::string& _string, const size_t _cursor);
size_t moveCursor(const std::string& _string, const size_t _cursor, const int _amount);
std::string toLower(const std::string& _string);
std::string toUpper(const std::string& _string);
std::string trim(const std::string& _string);
std::string replace(const std::string& _string, const std::string& _replace,
const std::string& _with);
bool startsWith(const std::string& _string, const std::string& _start);
bool endsWith(const std::string& _string, const std::string& _end);
std::string removeParenthesis(const std::string& _string);
stringVector delimitedStringToVector(const std::string& _string,
const std::string& _delimiter, bool sort = false);
stringVector commaStringToVector(const std::string& _string, bool sort = false);
std::string vectorToCommaString(stringVector _vector);
std::string format(const char* _string, ...);
std::string scramble(const std::string& _input, const std::string& key);
} // String::

View file

@ -1,3 +1,10 @@
//
// TimeUtil.cpp
//
// Low-level date and time functions.
// Set and get time, format to string formats, count days and months etc.
//
#include "utils/TimeUtil.h"
#include <time.h>
@ -11,51 +18,43 @@ namespace Utils
mTime = 0;
mTimeStruct = { 0, 0, 0, 1, 0, 0, 0, 0, -1 };
mIsoString = "00000000T000000";
} // DateTime::DateTime
}
DateTime::DateTime(const time_t& _time)
{
setTime(_time);
} // DateTime::DateTime
}
DateTime::DateTime(const tm& _timeStruct)
{
setTimeStruct(_timeStruct);
} // DateTime::DateTime
}
DateTime::DateTime(const std::string& _isoString)
{
setIsoString(_isoString);
} // DateTime::DateTime
}
DateTime::~DateTime()
{
} // DateTime::~DateTime
}
void DateTime::setTime(const time_t& _time)
{
mTime = (_time < 0) ? 0 : _time;
mTimeStruct = *localtime(&mTime);
mIsoString = timeToString(mTime);
} // DateTime::setTime
}
void DateTime::setTimeStruct(const tm& _timeStruct)
{
setTime(mktime((tm*)&_timeStruct));
} // DateTime::setTimeStruct
}
void DateTime::setIsoString(const std::string& _isoString)
{
setTime(stringToTime(_isoString));
} // DateTime::setIsoString
}
Duration::Duration(const time_t& _time)
{
@ -64,21 +63,18 @@ namespace Utils
mHours = ((mTotalSeconds % (60*60*24)) - (mTotalSeconds % (60*60))) / (60*60);
mMinutes = ((mTotalSeconds % (60*60)) - (mTotalSeconds % (60))) / 60;
mSeconds = mTotalSeconds % 60;
} // Duration::Duration
}
Duration::~Duration()
{
} // Duration::~Duration
}
time_t now()
{
time_t time;
::time(&time);
return time;
} // now
}
time_t stringToTime(const std::string& _string, const std::string& _format)
{
@ -87,106 +83,88 @@ namespace Utils
tm timeStruct = { 0, 0, 0, 1, 0, 0, 0, 0, -1 };
size_t parsedChars = 0;
if(_string == "not-a-date-time")
if (_string == "not-a-date-time")
return mktime(&timeStruct);
while(*f && (parsedChars < _string.length()))
{
if(*f == '%')
{
while (*f && (parsedChars < _string.length())) {
if (*f == '%') {
++f;
switch(*f++)
{
case 'Y': // The year [1970,xxxx]
{
if((parsedChars + 4) <= _string.length())
{
switch (*f++) {
// The year [1970,xxxx]
case 'Y': {
if ((parsedChars + 4) <= _string.length()) {
timeStruct.tm_year = (*s++ - '0') * 1000;
timeStruct.tm_year += (*s++ - '0') * 100;
timeStruct.tm_year += (*s++ - '0') * 10;
timeStruct.tm_year += (*s++ - '0');
if(timeStruct.tm_year >= 1900)
if (timeStruct.tm_year >= 1900)
timeStruct.tm_year -= 1900;
}
parsedChars += 4;
}
break;
case 'm': // The month number [01,12]
{
if((parsedChars + 2) <= _string.length())
{
// The month number [01,12]
case 'm': {
if ((parsedChars + 2) <= _string.length()) {
timeStruct.tm_mon = (*s++ - '0') * 10;
timeStruct.tm_mon += (*s++ - '0');
if(timeStruct.tm_mon >= 1)
if (timeStruct.tm_mon >= 1)
timeStruct.tm_mon -= 1;
}
parsedChars += 2;
}
break;
case 'd': // The day of the month [01,31]
{
if((parsedChars + 2) <= _string.length())
{
// The day of the month [01,31]
case 'd': {
if ((parsedChars + 2) <= _string.length()) {
timeStruct.tm_mday = (*s++ - '0') * 10;
timeStruct.tm_mday += (*s++ - '0');
}
parsedChars += 2;
}
break;
case 'H': // The hour (24-hour clock) [00,23]
{
if((parsedChars + 2) <= _string.length())
{
// The hour (24-hour clock) [00,23]
case 'H': {
if ((parsedChars + 2) <= _string.length()) {
timeStruct.tm_hour = (*s++ - '0') * 10;
timeStruct.tm_hour += (*s++ - '0');
}
parsedChars += 2;
}
break;
case 'M': // The minute [00,59]
{
if((parsedChars + 2) <= _string.length())
{
// The minute [00,59]
case 'M': {
if ((parsedChars + 2) <= _string.length()) {
timeStruct.tm_min = (*s++ - '0') * 10;
timeStruct.tm_min += (*s++ - '0');
}
parsedChars += 2;
}
break;
case 'S': // The second [00,59]
{
if((parsedChars + 2) <= _string.length())
{
// The second [00,59]
case 'S': {
if ((parsedChars + 2) <= _string.length()) {
timeStruct.tm_sec = (*s++ - '0') * 10;
timeStruct.tm_sec += (*s++ - '0');
}
parsedChars += 2;
}
break;
}
}
else
{
else {
++s;
++f;
}
}
return mktime(&timeStruct);
} // stringToTime
}
std::string timeToString(const time_t& _time, const std::string& _format)
{
@ -195,16 +173,13 @@ namespace Utils
char buf[256] = { '\0' };
char* s = buf;
while(*f)
{
if(*f == '%')
{
while (*f) {
if (*f == '%') {
++f;
switch(*f++)
{
case 'Y': // The year, including the century (1900)
{
switch (*f++) {
// The year, including the century (1900)
case 'Y': {
const int year = timeStruct.tm_year + 1900;
*s++ = (char)((year - (year % 1000)) / 1000) + '0';
*s++ = (char)(((year % 1000) - (year % 100)) / 100) + '0';
@ -213,54 +188,50 @@ namespace Utils
}
break;
case 'm': // The month number [00,11]
{
// The month number [00,11]
case 'm': {
const int mon = timeStruct.tm_mon + 1;
*s++ = (char)(mon / 10) + '0';
*s++ = (char)(mon % 10) + '0';
}
break;
case 'd': // The day of the month [01,31]
{
// The day of the month [01,31]
case 'd': {
*s++ = (char)(timeStruct.tm_mday / 10) + '0';
*s++ = (char)(timeStruct.tm_mday % 10) + '0';
}
break;
case 'H': // The hour (24-hour clock) [00,23]
{
// The hour (24-hour clock) [00,23]
case 'H': {
*s++ = (char)(timeStruct.tm_hour / 10) + '0';
*s++ = (char)(timeStruct.tm_hour % 10) + '0';
}
break;
case 'M': // The minute [00,59]
{
// The minute [00,59]
case 'M': {
*s++ = (char)(timeStruct.tm_min / 10) + '0';
*s++ = (char)(timeStruct.tm_min % 10) + '0';
}
break;
case 'S': // The second [00,59]
{
// The second [00,59]
case 'S': {
*s++ = (char)(timeStruct.tm_sec / 10) + '0';
*s++ = (char)(timeStruct.tm_sec % 10) + '0';
}
break;
}
}
else
{
else {
*s++ = *f++;
}
*s = '\0';
}
return std::string(buf);
} // timeToString
}
int daysInMonth(const int _year, const int _month)
{
@ -268,8 +239,7 @@ namespace Utils
mktime(&timeStruct);
return timeStruct.tm_mday;
} // daysInMonth
}
int daysInYear(const int _year)
{
@ -277,8 +247,7 @@ namespace Utils
mktime(&timeStruct);
return timeStruct.tm_yday + 1;
} // daysInYear
}
} // Time::

View file

@ -1,3 +1,10 @@
//
// TimeUtil.h
//
// Low-level date and time functions.
// Set and get time, format to string formats, count days and months etc.
//
#pragma once
#ifndef ES_CORE_UTILS_TIME_UTIL_H
#define ES_CORE_UTILS_TIME_UTIL_H
@ -13,66 +20,60 @@ namespace Utils
class DateTime
{
public:
DateTime();
DateTime(const time_t& _time);
DateTime(const tm& _timeStruct);
DateTime(const std::string& _isoString);
~DateTime();
const bool operator< (const DateTime& _other) const { return (mTime < _other.mTime); }
const bool operator<= (const DateTime& _other) const { return (mTime <= _other.mTime); }
const bool operator> (const DateTime& _other) const { return (mTime > _other.mTime); }
const bool operator>= (const DateTime& _other) const { return (mTime >= _other.mTime); }
operator time_t () const { return mTime; }
operator tm () const { return mTimeStruct; }
const bool operator<(const DateTime& _other) const { return (mTime < _other.mTime); }
const bool operator<=(const DateTime& _other) const { return (mTime <= _other.mTime); }
const bool operator>(const DateTime& _other) const { return (mTime > _other.mTime); }
const bool operator>=(const DateTime& _other) const { return (mTime >= _other.mTime); }
operator time_t() const { return mTime; }
operator tm() const { return mTimeStruct; }
operator std::string() const { return mIsoString; }
void setTime (const time_t& _time);
const time_t& getTime () const { return mTime; }
void setTime(const time_t& _time);
const time_t& getTime() const { return mTime; }
void setTimeStruct(const tm& _timeStruct);
const tm& getTimeStruct() const { return mTimeStruct; }
void setIsoString (const std::string& _isoString);
const std::string& getIsoString () const { return mIsoString; }
private:
time_t mTime;
tm mTimeStruct;
std::string mIsoString;
}; // DateTime
};
class Duration
{
public:
Duration(const time_t& _time);
~Duration();
unsigned int getDays () const { return mDays; }
unsigned int getHours () const { return mHours; }
unsigned int getDays() const { return mDays; }
unsigned int getHours() const { return mHours; }
unsigned int getMinutes() const { return mMinutes; }
unsigned int getSeconds() const { return mSeconds; }
private:
unsigned int mTotalSeconds;
unsigned int mDays;
unsigned int mHours;
unsigned int mMinutes;
unsigned int mSeconds;
};
}; // Duration
time_t now ();
time_t stringToTime(const std::string& _string, const std::string& _format = "%Y%m%dT%H%M%S");
std::string timeToString(const time_t& _time, const std::string& _format = "%Y%m%dT%H%M%S");
int daysInMonth (const int _year, const int _month);
int daysInYear (const int _year);
} // Time::
time_t now();
time_t stringToTime(const std::string& _string,
const std::string& _format = "%Y%m%dT%H%M%S");
std::string timeToString(const time_t& _time,
const std::string& _format = "%Y%m%dT%H%M%S");
int daysInMonth(const int _year, const int _month);
int daysInYear(const int _year);
}
} // Utils::
#endif // ES_CORE_UTILS_TIME_UTIL_H