Add the possibility of configurations to the plugins!

Adds the configuration menu.
This commit is contained in:
Maschell 2018-07-17 15:26:52 +02:00
parent 97536e1ee3
commit e6e488a453
17 changed files with 1635 additions and 7 deletions

View File

@ -1,6 +1,12 @@
msgid "Press HOME to return."
msgstr ""
msgid "Language" msgid "Language"
msgstr "" msgstr ""
msgid "Press B to return to the plugin overview."
msgstr ""
# English translations for Wii U Plugin System loader # English translations for Wii U Plugin System loader
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
msgid "" msgid ""
@ -16,14 +22,33 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: src/menu/content/ContentHome.cpp:23 msgid "Press B to return to the plugin overview, HOME to return to the running application."
msgstr ""
#: src/menu/content/ContentHome.cpp:24
msgid "Welcome to the Wii U plugin loader" msgid "Welcome to the Wii U plugin loader"
msgstr "" msgstr ""
#: src/menu/content/ContentHome.cpp:32 #: src/menu/content/ContentHome.cpp:33
msgid "Exit to HBL " msgid "Exit to HBL "
msgstr "" msgstr ""
#: src/menu/content/ContentHome.cpp:35 #: src/menu/content/ContentHome.cpp:36
msgid "Apply Patches" msgid "Apply Patches"
msgstr "" msgstr ""
#: src/myutils/ConfigUtils.cpp:113
msgid "Press HOME to return to the running application."
msgstr ""
#: src/myutils/ConfigUtils.cpp:114
msgid "Configurable running plugins:"
msgstr ""
#: src/myutils/ConfigUtils.cpp:118
msgid "No configurable running plugins found."
msgstr ""
#: src/myutils/ConfigUtils.cpp:243
msgid "B = plugin overview, HOME = back to running application."
msgstr ""

View File

@ -28,6 +28,7 @@ extern "C" {
#define DEFAULT_WUPSLOADER_PATH SD_PATH WIIU_PATH "/apps/wiiupluginsystem" #define DEFAULT_WUPSLOADER_PATH SD_PATH WIIU_PATH "/apps/wiiupluginsystem"
#define DEFAULT_LANG_PATH DEFAULT_WUPSLOADER_PATH "/languages" #define DEFAULT_LANG_PATH DEFAULT_WUPSLOADER_PATH "/languages"
#define LANGUAGE_FILE_EXT ".lang" #define LANGUAGE_FILE_EXT ".lang"
#define PLUGIN_CONFIG_FILE_EXT ".cfg"
#define PLUGIN_FILE_EXT ".mod" #define PLUGIN_FILE_EXT ".mod"
#define WUPS_PLUGIN_PATH SD_PATH WIIU_PATH "/plugins" #define WUPS_PLUGIN_PATH SD_PATH WIIU_PATH "/plugins"

View File

@ -57,6 +57,7 @@
#include "myutils/libntfs.h" #include "myutils/libntfs.h"
#include "myutils/libfat.h" #include "myutils/libfat.h"
#include "myutils/overlay_helper.h" #include "myutils/overlay_helper.h"
#include "myutils/ConfigUtils.h"
#include "version.h" #include "version.h"
#include "settings/CSettings.h" #include "settings/CSettings.h"
@ -65,7 +66,6 @@ static void RestorePatches();
int32_t isInMiiMakerHBL(); int32_t isInMiiMakerHBL();
void readAndPrintSegmentRegister(CThread *thread, void *arg); void readAndPrintSegmentRegister(CThread *thread, void *arg);
extern "C" int32_t Menu_Main(int32_t argc, char **argv) { extern "C" int32_t Menu_Main(int32_t argc, char **argv) {
if(gAppStatus == 2) { if(gAppStatus == 2) {
//"No, we don't want to patch stuff again."); //"No, we don't want to patch stuff again.");
@ -142,14 +142,14 @@ extern "C" int32_t Menu_Main(int32_t argc, char **argv) {
std::vector<dyn_linking_relocation_entry_t *> relocations = DynamicLinkingHelper::getInstance()->getAllValidDynamicLinkingRelocations(); std::vector<dyn_linking_relocation_entry_t *> relocations = DynamicLinkingHelper::getInstance()->getAllValidDynamicLinkingRelocations();
DEBUG_FUNCTION_LINE("Found relocation information for %d functions\n",relocations.size()); DEBUG_FUNCTION_LINE("Found relocation information for %d functions\n",relocations.size());
if(!DynamicLinkingHelper::getInstance()->fillRelocations(relocations)){ if(!DynamicLinkingHelper::getInstance()->fillRelocations(relocations)) {
OSFatal("fillRelocations failed."); OSFatal("fillRelocations failed.");
} }
if(!isInMiiMakerHBL()) { if(!isInMiiMakerHBL()) {
DEBUG_FUNCTION_LINE("Apply patches.\n"); DEBUG_FUNCTION_LINE("Apply patches.\n");
ApplyPatchesAndCallHookStartingApp(); ApplyPatchesAndCallHookStartingApp();
ConfigUtils::loadConfigFromSD();
if(MemoryMapping::isMemoryMapped()) { if(MemoryMapping::isMemoryMapped()) {
DEBUG_FUNCTION_LINE("Mapping was already done. Running %016llX\n",gGameTitleID); DEBUG_FUNCTION_LINE("Mapping was already done. Running %016llX\n",gGameTitleID);

View File

@ -0,0 +1,113 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <map>
#include <string>
#include <wups/config/WUPSConfig.h>
#include "ConfigInformation.h"
ConfigInformation::ConfigInformation(WUPSConfig * config, std::string persistPath, std::string persistFileName) {
this->config = config;
this->persistPath = persistPath;
this->persistFileName = persistFileName;
createConfigSettings();
loadValuesFromSD();
}
ConfigInformation::~ConfigInformation() {
if(configSettings != NULL) {
updateAndSaveSettings();
delete configSettings;
configSettings = NULL;
}
if(config != NULL) {
delete config;
config = NULL;
}
}
bool ConfigInformation::createConfigSettings() {
if(this->config == NULL) {
return false;
}
if(this->configSettings != NULL) {
delete this->configSettings;
}
std::map<int32_t,std::string> defaultValues;
std::map<int32_t,std::string> settingsNames;
int32_t index = 0;
for (auto & curCat : this->config->getCategories()) {
for (auto & curItem : curCat->getItems()) {
std::string configID = curItem->getConfigID();
std::string defaultValue = curItem->persistValue();
defaultValues[index] = defaultValue;
settingsNames[index] = configID;
index++;
}
}
configSettings = new ConfigSettings(persistPath, persistFileName, defaultValues, settingsNames);
return (configSettings != NULL);
}
bool ConfigInformation::loadValuesFromSD() {
if(this->config == NULL || this->configSettings == NULL) {
return false;
}
for (auto & curCat : this->config->getCategories()) {
for (auto & curItem : curCat->getItems()) {
std::string configID = curItem->getConfigID();
std::string prevValue = curItem->persistValue();
std::string loadedValue = this->configSettings->getValueAsString(this->configSettings->getIdByName(configID));
//DEBUG_FUNCTION_LINE("Loaded %s(%d) to %s. Previous value was %s \n",configID.c_str(),this->configSettings->getIdByName(configID), loadedValue.c_str(), prevValue.c_str());
if(prevValue.compare(loadedValue) != 0) {
//DEBUG_FUNCTION_LINE("Call loadValue\n");
curItem->loadValue(loadedValue);
}
}
}
return true;
}
void ConfigInformation::updateAndSaveSettings() {
if(this->config == NULL || this->configSettings == NULL) {
return;
}
updateConfigSettings();
configSettings->Save();
}
bool ConfigInformation::updateConfigSettings() {
if(this->config == NULL || this->configSettings == NULL) {
return false;
}
for (auto & curCat : this->config->getCategories()) {
for (auto & curItem : curCat->getItems()) {
std::string configID = curItem->getConfigID();
std::string newValue = curItem->persistValue();
this->configSettings->setValueAsString(this->configSettings->getIdByName(configID), newValue);
//DEBUG_FUNCTION_LINE("Set %s(%d) to %s\n",configID.c_str(),this->configSettings->getIdByName(configID), newValue.c_str());
}
}
return true;
}

View File

@ -0,0 +1,61 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef _CONFIG_INFORMATION_H_
#define _CONFIG_INFORMATION_H_
#include <wups/config/WUPSConfig.h>
#include "settings/ConfigSettings.h"
#include <string>
#include <utils/logger.h>
class ConfigInformation {
public:
/**
Creates a ConfigInformation object for a given WUPSConfig.
This also is responsible for persisting/loading the configurations to/from the SDCard.
The configuration will be loaded created/loaded at "[persistPath]/[persistFileName]"
**/
ConfigInformation(WUPSConfig * config, std::string persistPath, std::string persistFileName);
/**
Deletes the given WUPSConfig
Calls updateAndSaveSettings
Deletes the created ConfigSettings
**/
~ConfigInformation();
void updateAndSaveSettings();
WUPSConfig * getConfig() {
return config;
}
private:
bool createConfigSettings();
bool loadValuesFromSD();
bool updateConfigSettings();
WUPSConfig * config = NULL;
ConfigSettings * configSettings = NULL;
std::string persistPath;
std::string persistFileName;
};
#endif

View File

@ -0,0 +1,354 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <vector>
#include <map>
#include <wups/config/WUPSConfig.h>
#include <dynamic_libs/vpad_functions.h>
#include <utils/logger.h>
#include "common/common.h"
#include "common/retain_vars.h"
#include "overlay_helper.h"
#include "ScreenUtils.h"
#include "ConfigUtils.h"
#include <language/gettext.h>
#include "ConfigInformation.h"
void ConfigUtils::configMenuOpenedCallback(wups_overlay_options_type_t screen, void * args) {
// We close the configuration menu with the home button, but this would also
// trigger the home menu.
// To avoid this (and restore the GX2 buffers properly) we disable the home menu button
// as long we're in the configuration menu.
OSEnableHomeButtonMenu(false);
std::vector<WUPSConfig*> * configList = (std::vector<WUPSConfig*> *) args;
if(configList == NULL) {
DEBUG_FUNCTION_LINE("configList was NULL.\n");
// Re-enable home button. TODO: Only enable when it was enabled before.
OSEnableHomeButtonMenu(true);
return;
}
int32_t i = 0;
int32_t x = 0;
int32_t screen_y_pos = 0;
int32_t visible_rows_start = 2;
int32_t visible_rows_end = 16;
int32_t visible_rows_range = visible_rows_end - visible_rows_start;
WUPSConfig* curConfig = NULL;
VPADData vpad_data;
int32_t error;
int32_t maxSelect = 0;
int32_t curSelect = 0;
int32_t curScreenOffset = 0;
bool firstRun = true;
while(true) {
VPADRead(0, &vpad_data, 1, &error);
if(vpad_data.btns_d == VPAD_BUTTON_HOME) {
break;
}
int32_t newSelect = curSelect;
bool changed = false;
if(curConfig == NULL) {
maxSelect = configList->size();
if(maxSelect > 0) {
maxSelect--;
}
bool selected = false;
if(vpad_data.btns_r & VPAD_BUTTON_DOWN) {
newSelect++;
}
if(vpad_data.btns_r & VPAD_BUTTON_UP) {
newSelect--;
}
if(vpad_data.btns_r & VPAD_BUTTON_A) {
selected = true;
changed = true;
}
if(newSelect < 0) {
newSelect = maxSelect;
} else if(newSelect > maxSelect) {
newSelect = 0;
}
if(newSelect != curSelect) {
curSelect = newSelect;
changed = true;
}
if(!firstRun) {
if(!changed) {
continue;
}
}
firstRun = false;
ScreenUtils::OSScreenClear(screen);
screen_y_pos = 0;
ScreenUtils::printTextOnScreen(screen, 0, visible_rows_end + 1, gettext("Press HOME to return to the running application."));
ScreenUtils::printTextOnScreen(screen, x, screen_y_pos++,gettext("Configurable running plugins:"));
ScreenUtils::printTextOnScreen(screen, x, screen_y_pos++,"==========================");
if(configList->size() == 0) {
ScreenUtils::printTextOnScreen(screen, x, screen_y_pos++,gettext("No configurable running plugins found."));
ScreenUtils::flipBuffers(screen);
continue;
}
int32_t index = 0;
for (auto & curConfig_ : *configList) {
if(index == curSelect) {
ScreenUtils::printTextOnScreen(screen, x, screen_y_pos++,"> %s",curConfig_->getName().c_str());
if(selected) {
curConfig = curConfig_;
curSelect = 0;
curScreenOffset = 0;
firstRun = true;
maxSelect = 0;
for (auto & curCat : curConfig_->getCategories()) {
maxSelect += curCat->getItems().size();
}
if(maxSelect > 0) {
maxSelect--;
}
}
} else {
ScreenUtils::printTextOnScreen(screen, x, screen_y_pos++," %s",curConfig_->getName().c_str());
}
index++;
}
ScreenUtils::flipBuffers(screen);
continue;
}
WUPSConfigButtons pressedButtons = WUPS_CONFIG_BUTTON_NONE;
/*
if(vpad_data.btns_r & VPAD_BUTTON_DOWN) {
pressedButtons |= WUPS_CONFIG_BUTTON_DOWN;
}
if(vpad_data.btns_r & VPAD_BUTTON_UP) {
pressedButtons |= WUPS_CONFIG_BUTTON_UP;
}*/
if(vpad_data.btns_d & VPAD_BUTTON_A) {
pressedButtons |= WUPS_CONFIG_BUTTON_A;
}
if(vpad_data.btns_d & VPAD_BUTTON_B) {
pressedButtons |= WUPS_CONFIG_BUTTON_B;
}
if(vpad_data.btns_d & VPAD_BUTTON_LEFT) {
pressedButtons |= WUPS_CONFIG_BUTTON_LEFT;
}
if(vpad_data.btns_d & VPAD_BUTTON_RIGHT) {
pressedButtons |= WUPS_CONFIG_BUTTON_RIGHT;
}
if(vpad_data.btns_r & VPAD_BUTTON_DOWN) {
newSelect++;
}
if(vpad_data.btns_r & VPAD_BUTTON_UP) {
newSelect--;
}
if(vpad_data.btns_d & VPAD_BUTTON_B) {
curConfig = NULL;
curSelect = 0;
curScreenOffset = 0;
firstRun = true;
continue;
}
if(newSelect < 0) {
newSelect = maxSelect;
} else if(newSelect > maxSelect) {
newSelect = 0;
}
if(newSelect != curSelect) {
curSelect = newSelect;
changed = true;
}
if(pressedButtons != WUPS_CONFIG_BUTTON_NONE) {
changed = true;
}
int32_t cur_visible_rows = 0;
if(!firstRun) {
if(!changed) {
continue;
}
}
firstRun = false;
ScreenUtils::OSScreenClear(screen);
int32_t inSelect = 0;
bool ignore = false;
for (auto & curCat : curConfig->getCategories()) {
cur_visible_rows += 2;
for (auto & curItem : curCat->getItems()) {
cur_visible_rows++;
if(!ignore && curSelect == inSelect) {
if(curSelect == 0) {
curScreenOffset = 0;
}else if(cur_visible_rows + curScreenOffset >= visible_rows_range) {
curScreenOffset -= (cur_visible_rows + curScreenOffset) - visible_rows_range;
}else if(cur_visible_rows + curScreenOffset < visible_rows_range/2 && cur_visible_rows >= visible_rows_range/2) {
curScreenOffset -= (cur_visible_rows + curScreenOffset) - visible_rows_range/2;
}
ignore = true;
}
inSelect++;
}
}
ScreenUtils::printTextOnScreen(screen, 0, 0, "Configuration for %s:", curConfig->getName().c_str());
int32_t arrow_x_offset = 60;
if(curScreenOffset < 0) {
ScreenUtils::printTextOnScreen(screen, arrow_x_offset, visible_rows_start + 1, " ^");
ScreenUtils::printTextOnScreen(screen, arrow_x_offset, visible_rows_start + 2, " |");
}
if(curScreenOffset + cur_visible_rows > visible_rows_range) {
ScreenUtils::printTextOnScreen(screen, arrow_x_offset, visible_rows_end - 2, " | ");
ScreenUtils::printTextOnScreen(screen, arrow_x_offset, visible_rows_end - 1, " v");
}
ScreenUtils::printTextOnScreen(screen, 0, visible_rows_end + 1, gettext("B = plugin overview, HOME = back to running application."));
screen_y_pos = curScreenOffset + visible_rows_start;
inSelect = 0;
for (auto & curCat : curConfig->getCategories()) {
if((screen_y_pos + 2) >= visible_rows_end) {
break;
}
if((screen_y_pos - visible_rows_start) < -1) {
screen_y_pos += 2;
} else if((screen_y_pos - visible_rows_start) < 0) {
screen_y_pos++;
ScreenUtils::printTextOnScreen(screen, x, screen_y_pos++,"==========================");
} else {
ScreenUtils::printTextOnScreen(screen, x, screen_y_pos++,"%s",curCat->getName().c_str());
ScreenUtils::printTextOnScreen(screen, x, screen_y_pos++,"==========================");
}
for (auto & curItem : curCat->getItems()) {
if(screen_y_pos >= visible_rows_end) {
break;
}
if(curSelect == inSelect) {
if(pressedButtons != WUPS_CONFIG_BUTTON_NONE) {
curItem->onButtonPressed(pressedButtons);
}
ScreenUtils::printTextOnScreen(screen, x, screen_y_pos++,"> %-40s %s\n",curItem->getDisplayName().c_str(),curItem->getCurrentValueSelectedDisplay().c_str());
} else if((screen_y_pos - visible_rows_start) >= 0) {
ScreenUtils::printTextOnScreen(screen, x, screen_y_pos++," %-40s %s\n",curItem->getDisplayName().c_str(),curItem->getCurrentValueDisplay().c_str());
} else {
screen_y_pos++;
}
inSelect++;
}
}
ScreenUtils::flipBuffers(screen);
i++;
}
// Re-enable home button. TODO: Only enable when it was enabled before.
// Currently we can be sure it was enabled, because it's an requirement to enter the configuration menu.
// This might change in the future.
OSEnableHomeButtonMenu(true);
}
void ConfigUtils::openConfigMenu(std::vector<WUPSConfig*> configs) {
overlay_helper(WUPS_OVERLAY_DRC_AND_TV_WITH_DRC_PRIO, configMenuOpenedCallback, (void*) &configs);
}
std::vector<ConfigInformation *> ConfigUtils::getConfigInformation() {
std::vector<ConfigInformation *> configs;
for(int32_t plugin_index=0; plugin_index<gbl_replacement_data.number_used_plugins; plugin_index++) {
replacement_data_plugin_t * plugin_data = &gbl_replacement_data.plugin_data[plugin_index];
if(plugin_data == NULL) {
continue;
}
for(int32_t j=0; j<plugin_data->number_used_hooks; j++) {
replacement_data_hook_t * hook_data = &plugin_data->hooks[j];
if(hook_data->type == WUPS_LOADER_HOOK_GET_CONFIG) {
if(hook_data->func_pointer == NULL) {
break;
}
void * func_ptr = hook_data->func_pointer;
WUPSConfig * cur_config = ((WUPSConfig* (*)(void))((uint32_t*)func_ptr) )();
DCFlushRange(cur_config, sizeof(WUPSConfig));
if(cur_config != NULL) {
std::string fullPath(plugin_data->path);
std::string path = fullPath.substr(0, fullPath.find_last_of("/"));
size_t filenamePos = fullPath.find_last_of("/")+1;
std::string filename = fullPath.substr(filenamePos, fullPath.find_last_of(".") - filenamePos);
ConfigInformation * configInfo = new ConfigInformation(cur_config, path, filename.append(PLUGIN_CONFIG_FILE_EXT));
configs.push_back(configInfo);
}
}
}
}
return configs;
}
void ConfigUtils::deleteConfigInformation(std::vector<ConfigInformation *> configs) {
for (auto & curConfig : configs) {
delete curConfig;
}
}
void ConfigUtils::loadConfigFromSD() {
deleteConfigInformation(getConfigInformation());
}
void ConfigUtils::openConfigMenu() {
std::vector<ConfigInformation *> configInfos = getConfigInformation();
std::vector<WUPSConfig *> configs;
for (auto & curConfig : configInfos) {
configs.push_back(curConfig->getConfig());
}
for (auto & curConfig : configs) {
DCFlushRange(curConfig, sizeof(WUPSConfig));
}
ConfigUtils::openConfigMenu(configs);
for (auto & curConfig : configs) {
DCFlushRange(curConfig, sizeof(WUPSConfig));
}
deleteConfigInformation(configInfos);
}

View File

@ -0,0 +1,81 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef __CONFIG_UTILS_H_
#define __CONFIG_UTILS_H_
#include <wups.h>
#include <wups/config/WUPSConfig.h>
#include "ConfigInformation.h"
class ConfigUtils {
public:
/**
Loads the configuration files of all loaded plugins from the SDCard
and triggers the "loadValue" if they differ the default value.
**/
static void loadConfigFromSD();
/**
Opens the configuration menu where plugins can be configured.
Plugins need to implement the WUPS_GET_CONFIG() hook to show up in the menu.
The menu will be rendered on the TV and DRC screen, with optimization for the DRC.
If the menu is low, the menu may be only rendered to the DRC.
**/
static void openConfigMenu();
private:
ConfigUtils() {}
~ConfigUtils() {}
/**
Opens the configuration menu for a list of WUPSConfig.
If a configuration menu context could be created successfully, "configMenuOpenedCallback"
will be called, with the configs as an argument.
**/
static void openConfigMenu(std::vector<WUPSConfig*> configs);
/**
The callback that renders the configuration menu.
The args parameter expects a "std::vector<WUPSConfig*> *".
Depending on the screen
**/
static void configMenuOpenedCallback(wups_overlay_options_type_t screen, void * args);
/**
Gets the ConfigInformation for all loaded plugin that have implemented
the WUPS_GET_CONFIG() hook.
This triggers creating ConfigInformation objects.
ConfigInformation objects load the corresponding configuration file for a plugin
from the sd card. It also calls the "loadValue" function if a loaded value differs from the
default value. This behaviour may change in the future.
See the ConfigInformation class for more information.
**/
static std::vector<ConfigInformation *> getConfigInformation();
/**
Delete a list of ConfigInformation.
The destructor of "ConfigInformation" causes the configuration files for the plugin
to be written to the sd card (if the value have changed). This behaviour may change
in the future. See the ConfigInformation class for more information.
**/
static void deleteConfigInformation(std::vector<ConfigInformation *> configs);
};
#endif

View File

@ -0,0 +1,69 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <utils/logger.h>
#include <wups.h>
#include <stdarg.h>
#include "dynamic_libs/os_functions.h"
#include "ScreenUtils.h"
void ScreenUtils::printTextOnScreen(wups_overlay_options_type_t screen, int x,int y, const char * msg, ...) {
if(screen == WUPS_OVERLAY_NONE) {
return;
}
char * tmp = NULL;
va_list va;
va_start(va, msg);
if((vasprintf(&tmp, msg, va) >= 0) && tmp) {
if(screen != WUPS_OVERLAY_DRC_ONLY) { // Draw TV if it's not DRC exclusive.
OSScreenPutFontEx(0, x, y, tmp);
}
if(screen != WUPS_OVERLAY_TV_ONLY) { // Draw DRC if it's not TV exclusive.
OSScreenPutFontEx(1, x, y, tmp);
}
}
va_end(va);
if(tmp) {
free(tmp);
}
}
void ScreenUtils::OSScreenClear(wups_overlay_options_type_t screen) {
if(screen == WUPS_OVERLAY_NONE) {
return;
}
if(screen != WUPS_OVERLAY_DRC_ONLY) { // Clear TV if it's not DRC exclusive.
OSScreenClearBufferEx(0, 0);
}
if(screen != WUPS_OVERLAY_TV_ONLY) { // Clear DRC if it's not TV exclusive.
OSScreenClearBufferEx(1, 0);
}
}
void ScreenUtils::flipBuffers(wups_overlay_options_type_t screen) {
if(screen == WUPS_OVERLAY_NONE) {
return;
}
if(screen != WUPS_OVERLAY_DRC_ONLY) { // Flip TV buffer if it's not DRC exclusive.
OSScreenFlipBuffersEx(0);
}
if(screen != WUPS_OVERLAY_TV_ONLY) { // Flip DRC buffer if it's not TV exclusive.
OSScreenFlipBuffersEx(1);
}
}

View File

@ -0,0 +1,50 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef __SCREEN_UTILS_H_
#define __SCREEN_UTILS_H_
class ScreenUtils {
public:
/**
Clears the screen for the given screens
\param screen defines on which screens should be printed
\param x defines the x position (character position) where the text should be printed
\param y defines on which line the text should be printed
\param msg C string that contains the text to be printed.
It can optionally contain embedded format specifiers that are replaced by the values specified in subsequent additional arguments and formatted as requested.
See printf for more information
\param ... Depending on the format string, the function may expect a sequence of additional arguments, each containing a value to be used to replace a format specifier in the format string
**/
static void printTextOnScreen(wups_overlay_options_type_t screen, int x,int y, const char * msg, ...);
/**
Clears the screen for the given screens
\param screen defines which screens should be cleared
**/
static void OSScreenClear(wups_overlay_options_type_t screen);
/**
Flips the buffer for the given screens
\param screen defines which screens should be flipped.
**/
static void flipBuffers(wups_overlay_options_type_t screen);
private:
ScreenUtils() {}
~ScreenUtils() {}
};
#endif

View File

@ -4,6 +4,7 @@
#include "common/retain_vars.h" #include "common/retain_vars.h"
#include "hooks_patcher.h" #include "hooks_patcher.h"
#include "myutils/overlay_helper.h" #include "myutils/overlay_helper.h"
#include "myutils/ConfigUtils.h"
#include "main.h" #include "main.h"
#include "utils.h" #include "utils.h"
#include "mymemory/memory_mapping.h" #include "mymemory/memory_mapping.h"
@ -61,6 +62,48 @@ DECL(void, GX2WaitForVsync, void) {
} }
uint8_t vpadPressCooldown = 0xFF; uint8_t vpadPressCooldown = 0xFF;
uint8_t angleX_counter = 0;
float angleX_delta = 0.0f;
float angleX_last = 0.0f;
uint8_t angleX_frameCounter = 0;
bool checkMagic(VPADData *buffer) {
// buffer->angle stores the rotations per axis since the app started.
// Each full rotation add/subtracts 1.0f (depending on the direction).
// Check for rotation every only 5 frames.
angleX_frameCounter++;
if(angleX_frameCounter >= 5) {
// Get how much the gamepad rotated within the last 5 frames.
float diff_angle = -(buffer->angle.x - angleX_last);
// We want the gamepad to make (on average) at least 0.16% (1/6) of a full rotation per 5 frames (for 6 times in a row).
float target_diff = (0.16f);
// Calculate if rotated enough in this step (including the delta from the last step).
float total_diff = (diff_angle + angleX_delta) - target_diff;
if(total_diff > 0.0f) {
// The rotation in this step was enough.
angleX_counter++;
// When the gamepad rotated ~0.16% for 6 times in a row we made a full rotation!
if(angleX_counter > 5) {
ConfigUtils::openConfigMenu();
// reset stuff.
angleX_counter = 0;
angleX_delta = 0.0f;
} else {
// Save difference as it will be added on the next check.
angleX_delta = total_diff;
}
} else {
// reset counter if it stopped rotating.
angleX_counter = 0;
}
angleX_frameCounter = 0;
angleX_last = buffer->angle.x;
}
}
DECL(int32_t, VPADRead, int32_t chan, VPADData *buffer, uint32_t buffer_size, int32_t *error) { DECL(int32_t, VPADRead, int32_t chan, VPADData *buffer, uint32_t buffer_size, int32_t *error) {
int32_t result = real_VPADRead(chan, buffer, buffer_size, error); int32_t result = real_VPADRead(chan, buffer, buffer_size, error);
@ -72,6 +115,14 @@ DECL(int32_t, VPADRead, int32_t chan, VPADData *buffer, uint32_t buffer_size, in
} }
vpadPressCooldown = 0x3C; vpadPressCooldown = 0x3C;
} }
if(result > 0 && (buffer[0].btns_h == (VPAD_BUTTON_L | VPAD_BUTTON_DOWN | VPAD_BUTTON_MINUS)) && vpadPressCooldown == 0 && OSIsHomeButtonMenuEnabled()) {
ConfigUtils::openConfigMenu();
vpadPressCooldown = 0x3C;
} else if(result > 0 && OSIsHomeButtonMenuEnabled()) {
checkMagic(buffer);
}
if(vpadPressCooldown > 0) { if(vpadPressCooldown > 0) {
vpadPressCooldown--; vpadPressCooldown--;
} }

View File

@ -0,0 +1,262 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
* Modified by Maschell, 2018 for WiiU plugin system loader
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common/common.h"
#include "ConfigSettings.h"
#include <fs/CFile.hpp>
#include <fs/FSUtils.h>
#include <utils/StringTools.h>
#include <utils/logger.h>
#include <language/gettext.h>
#define VERSION_LINE "# WiiUPluginSystem - plugin settings file v"
#define VALID_VERSION 1
ConfigSettings::ConfigSettings(std::string configPath, std::string filename, std::map<int32_t, std::string> defaultValues, std::map<int32_t, std::string> settingsNames) {
bChanged = false;
memset(&nullValue, 0, sizeof(nullValue));
nullValue.strValue = new std::string();
this->configPath = configPath;
this->fileName = filename;
this->defaultValues = defaultValues;
this->settingsNames = settingsNames;
this->Load();
}
ConfigSettings::~ConfigSettings() {
for(uint32_t i = 0; i < settingsValues.size(); i++) {
if(settingsValues[i].dataType == TypeString)
delete settingsValues[i].strValue;
}
delete nullValue.strValue;
}
void ConfigSettings::SetDefault() {
for(uint32_t i = 0; i < settingsValues.size(); i++) {
if(settingsValues[i].dataType == TypeString) {
delete settingsValues[i].strValue;
}
}
for (auto & kv : settingsNames) {
settingsNames[kv.first] = kv.second;
}
for (auto & kv : defaultValues) {
SettingValue value;
value.dataType = TypeString;
value.strValue = new std::string(kv.second);
settingsValues[kv.first] = value;
}
}
bool ConfigSettings::Load() {
//! Reset default path variables to the right device
SetDefault();
std::string filepath = configPath + "/";
filepath += fileName;
DEBUG_FUNCTION_LINE("Loading Configuration from %s\n",filepath.c_str());
CFile file(filepath, CFile::ReadOnly);
if (!file.isOpen()) {
DEBUG_FUNCTION_LINE("Failed to open file\n");
bChanged = true;
return false;
}
std::string strBuffer;
strBuffer.resize(file.size());
file.read((uint8_t *) &strBuffer[0], strBuffer.size());
file.close();
//! remove all windows crap signs
size_t position;
while(1 && !strBuffer.empty()) {
position = strBuffer.find('\r');
if(position == std::string::npos)
break;
strBuffer.erase(position, 1);
}
std::vector<std::string> lines = StringTools::stringSplit(strBuffer, "\n");
if(lines.empty() || !ValidVersion(lines[0])) {
return false;
}
for(uint32_t i = 0; i < lines.size(); ++i) {
std::vector<std::string> valueSplit = StringTools::stringSplit(lines[i], "=");
if(valueSplit.size() != 2) {
continue;
}
while((valueSplit[0].size() > 0) && valueSplit[0][0] == ' ') {
valueSplit[0].erase(0, 1);
}
while((valueSplit[1].size() > 0) && valueSplit[1][ valueSplit[1].size() - 1 ] == ' ') {
valueSplit[1].resize(valueSplit[1].size() - 1);
}
for(uint32_t n = 0; n < settingsNames.size(); n++) {
if(settingsNames.empty()) {
continue;
}
if(valueSplit[0] == settingsNames[n]) {
switch(settingsValues[n].dataType) {
case TypeBool:
settingsValues[n].bValue = atoi(valueSplit[1].c_str());
break;
case TypeS8:
settingsValues[n].cValue = atoi(valueSplit[1].c_str());
break;
case TypeU8:
settingsValues[n].ucValue = atoi(valueSplit[1].c_str());
break;
case TypeS16:
settingsValues[n].sValue = atoi(valueSplit[1].c_str());
break;
case TypeU16:
settingsValues[n].usValue = atoi(valueSplit[1].c_str());
break;
case TypeS32:
settingsValues[n].iValue = atoi(valueSplit[1].c_str());
break;
case TypeU32:
settingsValues[n].uiValue = strtoul(valueSplit[1].c_str(), 0, 10);
break;
case TypeF32:
settingsValues[n].fValue = atof(valueSplit[1].c_str());
break;
case TypeString:
if(settingsValues[n].strValue == NULL)
settingsValues[n].strValue = new std::string();
*settingsValues[n].strValue = valueSplit[1];
break;
default:
break;
}
}
}
}
return true;
}
bool ConfigSettings::ValidVersion(const std::string & versionString) {
int32_t version = 0;
if(versionString.find(VERSION_LINE) != 0) {
return false;
}
version = atoi(versionString.c_str() + strlen(VERSION_LINE));
return version == VALID_VERSION;
}
bool ConfigSettings::Reset() {
this->SetDefault();
bChanged = true;
if (this->Save()) {
return true;
}
return false;
}
int32_t ConfigSettings::getIdByName(std::string configID) {
for (auto & kv : settingsNames) {
if(configID.compare(kv.second) == 0) {
return kv.first;
}
}
return -1;
}
bool ConfigSettings::Save() {
if(!bChanged) {
DEBUG_FUNCTION_LINE("Nothing has changed, we can skip\n");
return true;
}
FSUtils::CreateSubfolder(configPath.c_str());
std::string filepath = configPath + "/";
filepath += fileName;
s32 res = open(filepath.c_str(), O_CREAT | O_TRUNC | O_WRONLY);
close(res);
CFile file(filepath, CFile::WriteOnly);
if (!file.isOpen()) {
DEBUG_FUNCTION_LINE("failed to open %s\n",filepath.c_str());
return false;
}
file.fwrite("%s%i\n", VERSION_LINE, VALID_VERSION);
for(uint32_t i = 0; i < settingsValues.size(); i++) {
switch(settingsValues[i].dataType) {
case TypeBool:
file.fwrite("%s=%i\n", settingsNames[i], settingsValues[i].bValue);
break;
case TypeS8:
file.fwrite("%s=%i\n", settingsNames[i], settingsValues[i].cValue);
break;
case TypeU8:
file.fwrite("%s=%i\n", settingsNames[i], settingsValues[i].ucValue);
break;
case TypeS16:
file.fwrite("%s=%i\n", settingsNames[i], settingsValues[i].sValue);
break;
case TypeU16:
file.fwrite("%s=%i\n", settingsNames[i], settingsValues[i].usValue);
break;
case TypeS32:
file.fwrite("%s=%i\n", settingsNames[i], settingsValues[i].iValue);
break;
case TypeU32:
file.fwrite("%s=%u\n", settingsNames[i], settingsValues[i].uiValue);
break;
case TypeF32:
file.fwrite("%s=%f\n", settingsNames[i], settingsValues[i].fValue);
break;
case TypeString:
if(settingsValues[i].strValue != NULL)
file.fwrite("%s=%s\n", settingsNames[i].c_str(), settingsValues[i].strValue->c_str());
break;
default:
break;
}
}
file.close();
bChanged = false;
return true;
}

View File

@ -0,0 +1,240 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* Modified by Maschell, 2018 for WiiU plugin system loader
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef _CONFIG_SETTINGS_H_
#define _CONFIG_SETTINGS_H_
#include <string>
#include <stdio.h>
#include <dynamic_libs/os_types.h>
#include <vector>
#include <map>
class ConfigSettings {
public:
//!Constructor
ConfigSettings(std::string configPath, std::string filename, std::map<int32_t, std::string> defaultValues, std::map<int32_t, std::string> settingsNames);
//!Destructor
~ConfigSettings();
//!Set Default Settings
void SetDefault();
//!Load Settings
bool Load();
//!Save Settings
bool Save();
//!Reset Settings
bool Reset();
enum DataTypes {
TypeNone,
TypeBool,
TypeS8,
TypeU8,
TypeS16,
TypeU16,
TypeS32,
TypeU32,
TypeF32,
TypeString
};
const uint8_t & getDataType(int32_t idx) {
if(isValidId(idx)) {
return settingsValues[idx].dataType;
}
return nullValue.dataType;
}
const bool & getValueAsBool(int32_t idx) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeBool) {
return settingsValues[idx].bValue;
}
return nullValue.bValue;
}
const int8_t & getValueAsS8(int32_t idx) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeS8) {
return settingsValues[idx].cValue;
}
return nullValue.cValue;
}
const uint8_t & getValueAsU8(int32_t idx) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeU8) {
return settingsValues[idx].ucValue;
}
return nullValue.ucValue;
}
const int16_t & getValueAsS16(int32_t idx) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeS16) {
return settingsValues[idx].sValue;
}
return nullValue.sValue;
}
const uint16_t & getValueAsU16(int32_t idx) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeU16) {
return settingsValues[idx].usValue;
}
return nullValue.usValue;
}
const int32_t & getValueAsS32(int32_t idx) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeS32) {
return settingsValues[idx].iValue;
}
return nullValue.iValue;
}
const uint32_t & getValueAsU32(int32_t idx) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeU32) {
return settingsValues[idx].uiValue;
}
return nullValue.uiValue;
}
const float & getValueAsF32(int32_t idx) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeF32) {
return settingsValues[idx].fValue;
}
return nullValue.fValue;
}
const std::string & getValueAsString(int32_t idx) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeString && settingsValues[idx].strValue) {
return *(settingsValues[idx].strValue);
}
return *(nullValue.strValue);
}
void setValueAsBool(int32_t idx, const bool & val) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeBool) {
if(settingsValues[idx].bValue != val) {
settingsValues[idx].bValue = val;
bChanged = true;
}
}
}
void setValueAsS8(int32_t idx, const int8_t & val) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeS8) {
if(settingsValues[idx].cValue != val) {
settingsValues[idx].cValue = val;
bChanged = true;
}
}
}
void setValueAsU8(int32_t idx, const uint8_t & val) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeU8) {
if(settingsValues[idx].ucValue != val) {
settingsValues[idx].ucValue = val;
bChanged = true;
}
}
}
void setValueAsS16(int32_t idx, const int16_t & val) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeS16) {
if(settingsValues[idx].sValue != val) {
settingsValues[idx].sValue = val;
bChanged = true;
}
}
}
void setValueAsU16(int32_t idx, const uint16_t & val) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeU16) {
if(settingsValues[idx].usValue != val) {
settingsValues[idx].usValue = val;
bChanged = true;
}
}
}
void setValueAsS32(int32_t idx, const int32_t & val) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeS32) {
if(settingsValues[idx].iValue != val) {
settingsValues[idx].iValue = val;
bChanged = true;
}
}
}
void setValueAsU32(int32_t idx, const uint32_t & val) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeU32) {
if(settingsValues[idx].uiValue != val) {
settingsValues[idx].uiValue = val;
bChanged = true;
}
}
}
void setValueAsF32(int32_t idx, const float & val) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeF32) {
if(settingsValues[idx].fValue != val) {
settingsValues[idx].fValue = val;
bChanged = true;
}
}
}
void setValueAsString(int32_t idx, const std::string & val) {
if(isValidId(idx) && settingsValues[idx].dataType == TypeString && settingsValues[idx].strValue) {
if(val.compare(*(settingsValues[idx].strValue)) != 0) { // Only update if the value changed.
*(settingsValues[idx].strValue) = val;
bChanged = true;
}
}
}
int32_t getIdByName(std::string configID);
protected:
bool ValidVersion(const std::string & versionString);
bool isValidId(int32_t idx) {
return (settingsValues.count(idx) > 0);
}
typedef struct {
uint8_t dataType;
union {
bool bValue;
int8_t cValue;
uint8_t ucValue;
int16_t sValue;
uint16_t usValue;
int32_t iValue;
uint32_t uiValue;
float fValue;
std::string *strValue;
};
} SettingValue;
SettingValue nullValue;
std::string configPath;
std::string fileName;
std::map<int32_t, SettingValue> settingsValues;
std::map<int32_t, std::string> defaultValues;
std::map<int32_t, std::string> settingsNames;
bool bChanged;
};
#endif

View File

@ -0,0 +1,30 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef WUPS_CONFIG_HOOKS_DEF_H_
#define WUPS_CONFIG_HOOKS_DEF_H_
#include "hooks.h"
#include "config/WUPSConfig.h"
#define WUPS_GET_CONFIG() \
WUPSConfig* get_config();\
WUPS_HOOK_EX(WUPS_LOADER_HOOK_GET_CONFIG,get_config); \
WUPSConfig* get_config()
#endif /* WUPS_CONFIG_HOOKS_DEF_H_ */

View File

@ -0,0 +1,87 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef _WUPS_CONFIG_H_
#define _WUPS_CONFIG_H_
#include <string>
#include <vector>
#include <wups/config/WUPSConfigCategory.h>
class WUPSConfig {
public:
WUPSConfig(std::string name) {
this->name = name;
}
~WUPSConfig() {
for (auto & element : categories) {
delete element;
}
}
/**
\return Returns the name of this WUPSConfig
**/
std::string getName(){
return this->name;
}
/**
\brief Creates a new WUPSCategory add its to this WUPSConfig.
The category will be added to the end of the list.
This class holds responsibility for deleting the created instance.
\param categoryName: The name of the category that will be created.
\return On success, the created and inserted category will be returned.
**/
WUPSConfigCategory * addCategory(std::string categoryName){
WUPSConfigCategory * curCat = new WUPSConfigCategory(categoryName);
categories.push_back(curCat);
return curCat;
}
/**
\brief Adds a given WUPSConfigCategory to this WUPSConfig.
The category will be added to the end of the list.
This class holds responsibility for deleting the created instance.
\param category: The category that will be added to this config.
\return On success, the inserted category will be returned.
On error NULL will be returned. In this case the caller still has the responsibility
for deleting the WUPSConfigCategory instance.
**/
WUPSConfigCategory * addCategory(WUPSConfigCategory * category){
categories.push_back(category);
return category;
}
/**
\return Returns a vector with all categories.
**/
std::vector<WUPSConfigCategory *> getCategories(){
return this->categories;
}
private:
std::string name;
std::vector<WUPSConfigCategory *> categories;
};
#endif

View File

@ -0,0 +1,72 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef _WUPS_CONFIG_CATEGORY_H_
#define _WUPS_CONFIG_CATEGORY_H_
#include <string>
#include <vector>
#include <wups/config/WUPSConfigItem.h>
class WUPSConfigCategory {
public:
WUPSConfigCategory(std::string name) {
this->name = name;
}
~WUPSConfigCategory() {
for (auto & element : items) {
delete element;
}
}
/**
\return Returns the name of this WUPSConfigCategory
**/
std::string getName(){
return this->name;
}
/**
\brief Adds a given WUPSConfigItem to this WUPSConfigCategory.
The item will be added to the end of the list.
This class holds responsibility for deleting the created instance.
\param item: The item that will be added to this config.
\return On success, the inserted item will be returned.
On error NULL will be returned. In this case the caller still has the responsibility
for deleting the WUPSConfigItem instance.
**/
WUPSConfigItem * addItem(WUPSConfigItem * item){
items.push_back(item);
return item;
}
/**
\return Returns a vector with all items.
**/
std::vector<WUPSConfigItem *> getItems(){
return this->items;
}
private:
std::string name;
std::vector<WUPSConfigItem *> items;
};
#endif

View File

@ -0,0 +1,131 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef _WUPS_CONFIG_ITEM_H_
#define _WUPS_CONFIG_ITEM_H_
#include <string>
#include <vector>
#define WUPS_CONFIG_BUTTON_NONE 0
#define WUPS_CONFIG_BUTTON_LEFT (1<<0)
#define WUPS_CONFIG_BUTTON_RIGHT (1<<1)
#define WUPS_CONFIG_BUTTON_UP (1<<2)
#define WUPS_CONFIG_BUTTON_DOWN (1<<3)
#define WUPS_CONFIG_BUTTON_A (1<<4)
#define WUPS_CONFIG_BUTTON_B (1<<5)
#define WUPS_CONFIG_BUTTON_ZL (1<<6)
#define WUPS_CONFIG_BUTTON_ZR (1<<7)
typedef int32_t WUPSConfigButtons;
class WUPSConfigItem {
public:
/**
Sets the display name of this WUPSConfigItem
This is the value which will be shown in the configuration menu.
**/
virtual void setDisplayName(std::string displayName) {
this->displayName = displayName;
}
/**
\return Returns the display name of this WUPSConfigItem
**/
virtual std::string getDisplayName() {
return this->displayName;
}
/**
Sets the config ID name of this WUPSConfigItem.
This config ID is used to persist the configuration values and needs
to be unique in the context of this WUPSConfig.
Items in different categories are NOT allowed to have the config ID.
**/
virtual void setConfigID(std::string configID) {
this->configID = configID;
}
/**
\return Returns the configID of this WUPSConfigItem.
**/
virtual std::string getConfigID() {
return this->configID;
}
/**
Returns a string that displays the current value.
This string is shown next to the display name when the cursor is NOT on this item
**/
virtual std::string getCurrentValueDisplay() = 0;
/**
Returns a string that displays the current value when selected.
This string is shown next to the display name when the cursor IS on this item
**/
virtual std::string getCurrentValueSelectedDisplay() = 0;
/**
Is called when the cursor enters or leaves the item.
When the cursor enters the item, "isSelected" will be true.
When the cursor leaves the item, "isSelected" will be false.
**/
virtual void onSelected(bool isSelected) = 0;
/**
Is called when a button is pressed while the cursor on this item.
See the WUPSConfigButtons enum for possible values.
**/
virtual void onButtonPressed(WUPSConfigButtons buttons) = 0;
/**
When the cursor is on this item, the configuration menu asks this item
if it's allowed to leave it.
If it returns true, the item can be leaved.
It it returns false, leaves is not allowed.
**/
virtual bool isMovementAllowed() = 0;
/**
Returns a string that represents the value of this item.
**/
virtual std::string persistValue() = 0;
/**
Loads a value for a given string that contains the persisted value.
\param persistedValue A valued that the result of the persistValue function
**/
virtual void loadValue(std::string persistedValue) = 0;
/**
Restores the default value
**/
virtual void restoreDefault() = 0;
WUPSConfigItem(std::string configID, std::string displayName){
this->configID = configID;
this->displayName = displayName;
}
virtual ~WUPSConfigItem(){
}
private:
std::string displayName;
std::string configID;
};
#endif

View File

@ -45,6 +45,7 @@ typedef enum wups_loader_hook_type_t {
WUPS_LOADER_HOOK_APP_STATUS_CHANGED, /* Called when the app status changes (foreground, background, closing) */ WUPS_LOADER_HOOK_APP_STATUS_CHANGED, /* Called when the app status changes (foreground, background, closing) */
WUPS_LOADER_HOOK_INIT_KERNEL, /* Only for internal usage */ WUPS_LOADER_HOOK_INIT_KERNEL, /* Only for internal usage */
WUPS_LOADER_HOOK_GET_CONFIG, /* Called when the config-menu will be loaded */
} wups_loader_hook_type_t; } wups_loader_hook_type_t;
typedef struct wups_loader_hook_t { typedef struct wups_loader_hook_t {