From e6e488a453a113b7363a09269df2e27ae4ed83b4 Mon Sep 17 00:00:00 2001 From: Maschell Date: Tue, 17 Jul 2018 15:26:52 +0200 Subject: [PATCH] Add the possibility of configurations to the plugins! Adds the configuration menu. --- loader/languages/english.lang | 31 +- loader/src/common/common.h | 1 + loader/src/main.cpp | 6 +- loader/src/myutils/ConfigInformation.cpp | 113 ++++++ loader/src/myutils/ConfigInformation.h | 61 +++ loader/src/myutils/ConfigUtils.cpp | 354 ++++++++++++++++++ loader/src/myutils/ConfigUtils.h | 81 ++++ loader/src/myutils/ScreenUtils.cpp | 69 ++++ loader/src/myutils/ScreenUtils.h | 50 +++ loader/src/patcher/hooks_patcher.cpp | 51 +++ loader/src/settings/ConfigSettings.cpp | 262 +++++++++++++ loader/src/settings/ConfigSettings.h | 240 ++++++++++++ wups_include/wups/config.h | 30 ++ wups_include/wups/config/WUPSConfig.h | 87 +++++ wups_include/wups/config/WUPSConfigCategory.h | 72 ++++ wups_include/wups/config/WUPSConfigItem.h | 131 +++++++ wups_include/wups/hooks.h | 3 +- 17 files changed, 1635 insertions(+), 7 deletions(-) create mode 100644 loader/src/myutils/ConfigInformation.cpp create mode 100644 loader/src/myutils/ConfigInformation.h create mode 100644 loader/src/myutils/ConfigUtils.cpp create mode 100644 loader/src/myutils/ConfigUtils.h create mode 100644 loader/src/myutils/ScreenUtils.cpp create mode 100644 loader/src/myutils/ScreenUtils.h create mode 100644 loader/src/settings/ConfigSettings.cpp create mode 100644 loader/src/settings/ConfigSettings.h create mode 100644 wups_include/wups/config.h create mode 100644 wups_include/wups/config/WUPSConfig.h create mode 100644 wups_include/wups/config/WUPSConfigCategory.h create mode 100644 wups_include/wups/config/WUPSConfigItem.h diff --git a/loader/languages/english.lang b/loader/languages/english.lang index f462b11..551040a 100644 --- a/loader/languages/english.lang +++ b/loader/languages/english.lang @@ -1,6 +1,12 @@ +msgid "Press HOME to return." +msgstr "" + msgid "Language" msgstr "" +msgid "Press B to return to the plugin overview." +msgstr "" + # English translations for Wii U Plugin System loader # This file is distributed under the same license as the PACKAGE package. msgid "" @@ -16,14 +22,33 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\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" msgstr "" -#: src/menu/content/ContentHome.cpp:32 +#: src/menu/content/ContentHome.cpp:33 msgid "Exit to HBL " msgstr "" -#: src/menu/content/ContentHome.cpp:35 +#: src/menu/content/ContentHome.cpp:36 msgid "Apply Patches" 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 "" diff --git a/loader/src/common/common.h b/loader/src/common/common.h index a04e83b..cf2f903 100644 --- a/loader/src/common/common.h +++ b/loader/src/common/common.h @@ -28,6 +28,7 @@ extern "C" { #define DEFAULT_WUPSLOADER_PATH SD_PATH WIIU_PATH "/apps/wiiupluginsystem" #define DEFAULT_LANG_PATH DEFAULT_WUPSLOADER_PATH "/languages" #define LANGUAGE_FILE_EXT ".lang" +#define PLUGIN_CONFIG_FILE_EXT ".cfg" #define PLUGIN_FILE_EXT ".mod" #define WUPS_PLUGIN_PATH SD_PATH WIIU_PATH "/plugins" diff --git a/loader/src/main.cpp b/loader/src/main.cpp index b7f68dd..ae84d06 100644 --- a/loader/src/main.cpp +++ b/loader/src/main.cpp @@ -57,6 +57,7 @@ #include "myutils/libntfs.h" #include "myutils/libfat.h" #include "myutils/overlay_helper.h" +#include "myutils/ConfigUtils.h" #include "version.h" #include "settings/CSettings.h" @@ -65,7 +66,6 @@ static void RestorePatches(); int32_t isInMiiMakerHBL(); void readAndPrintSegmentRegister(CThread *thread, void *arg); - extern "C" int32_t Menu_Main(int32_t argc, char **argv) { if(gAppStatus == 2) { //"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 relocations = DynamicLinkingHelper::getInstance()->getAllValidDynamicLinkingRelocations(); 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."); } if(!isInMiiMakerHBL()) { DEBUG_FUNCTION_LINE("Apply patches.\n"); ApplyPatchesAndCallHookStartingApp(); - + ConfigUtils::loadConfigFromSD(); if(MemoryMapping::isMemoryMapped()) { DEBUG_FUNCTION_LINE("Mapping was already done. Running %016llX\n",gGameTitleID); diff --git a/loader/src/myutils/ConfigInformation.cpp b/loader/src/myutils/ConfigInformation.cpp new file mode 100644 index 0000000..6d51bd0 --- /dev/null +++ b/loader/src/myutils/ConfigInformation.cpp @@ -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 . + ****************************************************************************/ + +#include +#include +#include +#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 defaultValues; + std::map 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; +} diff --git a/loader/src/myutils/ConfigInformation.h b/loader/src/myutils/ConfigInformation.h new file mode 100644 index 0000000..7100028 --- /dev/null +++ b/loader/src/myutils/ConfigInformation.h @@ -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 . + ****************************************************************************/ + +#ifndef _CONFIG_INFORMATION_H_ +#define _CONFIG_INFORMATION_H_ + +#include +#include "settings/ConfigSettings.h" +#include +#include + +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 diff --git a/loader/src/myutils/ConfigUtils.cpp b/loader/src/myutils/ConfigUtils.cpp new file mode 100644 index 0000000..3473bb9 --- /dev/null +++ b/loader/src/myutils/ConfigUtils.cpp @@ -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 . + ****************************************************************************/ +#include +#include +#include +#include +#include + +#include "common/common.h" +#include "common/retain_vars.h" + +#include "overlay_helper.h" +#include "ScreenUtils.h" +#include "ConfigUtils.h" +#include + +#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 * configList = (std::vector *) 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 configs) { + overlay_helper(WUPS_OVERLAY_DRC_AND_TV_WITH_DRC_PRIO, configMenuOpenedCallback, (void*) &configs); +} + +std::vector ConfigUtils::getConfigInformation() { + std::vector configs; + for(int32_t plugin_index=0; plugin_indexnumber_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 configs) { + for (auto & curConfig : configs) { + delete curConfig; + } +} + +void ConfigUtils::loadConfigFromSD() { + deleteConfigInformation(getConfigInformation()); +} + +void ConfigUtils::openConfigMenu() { + std::vector configInfos = getConfigInformation(); + + std::vector 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); +} diff --git a/loader/src/myutils/ConfigUtils.h b/loader/src/myutils/ConfigUtils.h new file mode 100644 index 0000000..b16c2b6 --- /dev/null +++ b/loader/src/myutils/ConfigUtils.h @@ -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 . + ****************************************************************************/ +#ifndef __CONFIG_UTILS_H_ +#define __CONFIG_UTILS_H_ + +#include +#include +#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 configs); + + /** + The callback that renders the configuration menu. + The args parameter expects a "std::vector *". + 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 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 configs); + +}; + +#endif diff --git a/loader/src/myutils/ScreenUtils.cpp b/loader/src/myutils/ScreenUtils.cpp new file mode 100644 index 0000000..e75dfc1 --- /dev/null +++ b/loader/src/myutils/ScreenUtils.cpp @@ -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 . + ****************************************************************************/ +#include +#include +#include +#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); + } +} diff --git a/loader/src/myutils/ScreenUtils.h b/loader/src/myutils/ScreenUtils.h new file mode 100644 index 0000000..b6fc82b --- /dev/null +++ b/loader/src/myutils/ScreenUtils.h @@ -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 . + ****************************************************************************/ +#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 diff --git a/loader/src/patcher/hooks_patcher.cpp b/loader/src/patcher/hooks_patcher.cpp index 1ff1966..b38d81f 100644 --- a/loader/src/patcher/hooks_patcher.cpp +++ b/loader/src/patcher/hooks_patcher.cpp @@ -4,6 +4,7 @@ #include "common/retain_vars.h" #include "hooks_patcher.h" #include "myutils/overlay_helper.h" +#include "myutils/ConfigUtils.h" #include "main.h" #include "utils.h" #include "mymemory/memory_mapping.h" @@ -61,6 +62,48 @@ DECL(void, GX2WaitForVsync, void) { } 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) { 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; } + + 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) { vpadPressCooldown--; } diff --git a/loader/src/settings/ConfigSettings.cpp b/loader/src/settings/ConfigSettings.cpp new file mode 100644 index 0000000..34f7250 --- /dev/null +++ b/loader/src/settings/ConfigSettings.cpp @@ -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 . + ****************************************************************************/ +#include +#include +#include + +#include "common/common.h" +#include "ConfigSettings.h" +#include +#include +#include +#include +#include + +#define VERSION_LINE "# WiiUPluginSystem - plugin settings file v" +#define VALID_VERSION 1 + +ConfigSettings::ConfigSettings(std::string configPath, std::string filename, std::map defaultValues, std::map 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 lines = StringTools::stringSplit(strBuffer, "\n"); + + if(lines.empty() || !ValidVersion(lines[0])) { + return false; + } + + for(uint32_t i = 0; i < lines.size(); ++i) { + std::vector 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; +} diff --git a/loader/src/settings/ConfigSettings.h b/loader/src/settings/ConfigSettings.h new file mode 100644 index 0000000..b1a9774 --- /dev/null +++ b/loader/src/settings/ConfigSettings.h @@ -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 . + ****************************************************************************/ +#ifndef _CONFIG_SETTINGS_H_ +#define _CONFIG_SETTINGS_H_ + +#include +#include +#include +#include +#include + +class ConfigSettings { +public: + //!Constructor + ConfigSettings(std::string configPath, std::string filename, std::map defaultValues, std::map 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 settingsValues; + + std::map defaultValues; + std::map settingsNames; + + + bool bChanged; +}; + +#endif diff --git a/wups_include/wups/config.h b/wups_include/wups/config.h new file mode 100644 index 0000000..72eedb1 --- /dev/null +++ b/wups_include/wups/config.h @@ -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 . + ****************************************************************************/ + +#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_ */ diff --git a/wups_include/wups/config/WUPSConfig.h b/wups_include/wups/config/WUPSConfig.h new file mode 100644 index 0000000..1c9538b --- /dev/null +++ b/wups_include/wups/config/WUPSConfig.h @@ -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 . + ****************************************************************************/ + +#ifndef _WUPS_CONFIG_H_ +#define _WUPS_CONFIG_H_ + +#include +#include +#include + +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 getCategories(){ + return this->categories; + } + +private: + std::string name; + std::vector categories; +}; + +#endif diff --git a/wups_include/wups/config/WUPSConfigCategory.h b/wups_include/wups/config/WUPSConfigCategory.h new file mode 100644 index 0000000..9e84337 --- /dev/null +++ b/wups_include/wups/config/WUPSConfigCategory.h @@ -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 . + ****************************************************************************/ + +#ifndef _WUPS_CONFIG_CATEGORY_H_ +#define _WUPS_CONFIG_CATEGORY_H_ + +#include +#include +#include + +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 getItems(){ + return this->items; + } + +private: + std::string name; + std::vector items; +}; + +#endif diff --git a/wups_include/wups/config/WUPSConfigItem.h b/wups_include/wups/config/WUPSConfigItem.h new file mode 100644 index 0000000..fbfd663 --- /dev/null +++ b/wups_include/wups/config/WUPSConfigItem.h @@ -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 . + ****************************************************************************/ + +#ifndef _WUPS_CONFIG_ITEM_H_ +#define _WUPS_CONFIG_ITEM_H_ + +#include +#include + +#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 diff --git a/wups_include/wups/hooks.h b/wups_include/wups/hooks.h index 6c0c0c7..dc2b597 100644 --- a/wups_include/wups/hooks.h +++ b/wups_include/wups/hooks.h @@ -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_INIT_KERNEL, /* Only for internal usage */ + WUPS_LOADER_HOOK_GET_CONFIG, /* Called when the config-menu will be loaded */ } wups_loader_hook_type_t; typedef struct wups_loader_hook_t { @@ -85,7 +86,7 @@ typedef struct wups_loader_app_started_args_t { void init_kernel(wups_loader_init_kernel_args_t args){ \ WUPS_InitKernel(args);\ } - + #define INITIALIZE_PLUGIN() \ void init_plugin(void);\ WUPS_HOOK_EX(WUPS_LOADER_HOOK_INIT_PLUGIN,init_plugin); \