mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2024-11-21 12:19:18 +01:00
Implement new ConfigAPI and new Config Menu
This commit is contained in:
parent
b991d6e329
commit
921b5ce157
@ -1,7 +1,7 @@
|
||||
FROM ghcr.io/wiiu-env/devkitppc:20230621
|
||||
|
||||
COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20230719 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:0.7.2-dev-20231105-45d17c5 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:0.3.2-dev-20231203-2e5832b /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:0.8.0-dev-20231216-104fdc3 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/libmappedmemory:20230621 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/libwupsbackend:20230621 /artifacts $DEVKITPRO
|
||||
|
8
Makefile
8
Makefile
@ -29,7 +29,9 @@ SOURCES := source \
|
||||
source/patcher \
|
||||
source/plugin \
|
||||
source/utils \
|
||||
source/utils/storage
|
||||
source/utils/config \
|
||||
source/utils/storage \
|
||||
source/uitls/input
|
||||
DATA := data
|
||||
INCLUDES := source
|
||||
|
||||
@ -41,7 +43,7 @@ CFLAGS := -Wall -Wextra -Os -ffunction-sections -fdata-sections\
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -std=c++20 -fno-exceptions -fno-rtti
|
||||
CXXFLAGS := $(CFLAGS) -std=c++20 -fno-exceptions -fno-rtti
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libmappedmemory.ld $(WUMSSPECS)
|
||||
@ -56,7 +58,7 @@ CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
endif
|
||||
|
||||
LIBS := -lwums -lwut -lfunctionpatcher -lmappedmemory -lz -lnotifications
|
||||
LIBS := -lwums -lwups -lwut -lfunctionpatcher -lmappedmemory -lz -lnotifications
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level
|
||||
|
@ -181,6 +181,7 @@ bool PluginManagement::DoFunctionPatches(const std::vector<std::unique_ptr<Plugi
|
||||
}
|
||||
|
||||
void PluginManagement::callInitHooks(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
|
||||
CallHook(plugins, WUPS_LOADER_HOOK_INIT_CONFIG);
|
||||
CallHook(plugins, WUPS_LOADER_HOOK_INIT_STORAGE_DEPRECATED);
|
||||
CallHook(plugins, WUPS_LOADER_HOOK_INIT_STORAGE);
|
||||
CallHook(plugins, WUPS_LOADER_HOOK_INIT_PLUGIN);
|
||||
|
@ -18,73 +18,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "WUPSConfigCategory.h"
|
||||
#include "utils/logger.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wups/config.h>
|
||||
|
||||
class WUPSConfig {
|
||||
public:
|
||||
explicit WUPSConfig(std::string_view name) {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
~WUPSConfig() {
|
||||
for (const auto &element : categories) {
|
||||
delete element;
|
||||
namespace WUPSConfigAPIBackend {
|
||||
class WUPSConfig : public WUPSConfigCategory {
|
||||
public:
|
||||
explicit WUPSConfig(std::string_view name) : WUPSConfigCategory(name) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\return Returns the name of this WUPSConfig
|
||||
**/
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
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.
|
||||
**/
|
||||
std::optional<WUPSConfigCategory *> addCategory(std::string_view categoryName) {
|
||||
auto curCat = new (std::nothrow) WUPSConfigCategory(categoryName);
|
||||
if (curCat == nullptr) {
|
||||
return {};
|
||||
}
|
||||
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 nullptr 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.
|
||||
**/
|
||||
const std::vector<WUPSConfigCategory *> &getCategories() {
|
||||
return this->categories;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::vector<WUPSConfigCategory *> categories = {};
|
||||
};
|
||||
};
|
||||
} // namespace WUPSConfigAPIBackend
|
||||
|
324
source/config/WUPSConfigAPI.cpp
Normal file
324
source/config/WUPSConfigAPI.cpp
Normal file
@ -0,0 +1,324 @@
|
||||
#include "WUPSConfigAPI.h"
|
||||
#include "WUPSConfig.h"
|
||||
#include "WUPSConfigCategory.h"
|
||||
#include "WUPSConfigItem.h"
|
||||
#include "WUPSConfigItemV1.h"
|
||||
#include "WUPSConfigItemV2.h"
|
||||
#include "globals.h"
|
||||
#include "plugin/PluginConfigData.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/utils.h"
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <wums/exports.h>
|
||||
#include <wups/config.h>
|
||||
#include <wups/config_api.h>
|
||||
|
||||
namespace WUPSConfigAPIBackend {
|
||||
std::vector<std::unique_ptr<WUPSConfig>> sConfigs;
|
||||
std::mutex sConfigsMutex;
|
||||
|
||||
std::vector<std::unique_ptr<WUPSConfigCategory>> sConfigCategories;
|
||||
std::mutex sConfigCategoryMutex;
|
||||
|
||||
std::vector<std::unique_ptr<WUPSConfigItem>> sConfigItems;
|
||||
std::mutex sConfigItemsMutex;
|
||||
|
||||
namespace Intern {
|
||||
WUPSConfig *GetConfigByHandle(WUPSConfigHandle handle) {
|
||||
std::lock_guard lock(sConfigsMutex);
|
||||
auto itr = std::find_if(sConfigs.begin(), sConfigs.end(), [handle](auto &cur) { return handle == cur.get(); });
|
||||
if (itr == sConfigs.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return itr->get();
|
||||
}
|
||||
|
||||
std::unique_ptr<WUPSConfig> PopConfigByHandle(WUPSConfigHandle handle) {
|
||||
return pop_locked_first_if(sConfigsMutex, sConfigs, [handle](auto &cur) { return handle == cur.get(); });
|
||||
}
|
||||
|
||||
static WUPSConfigCategory *GetCategoryByHandleRecursive(WUPSConfigCategory *category, WUPSConfigCategoryHandle handle) {
|
||||
if (handle == category) {
|
||||
return category;
|
||||
}
|
||||
for (const auto &cat : category->getCategories()) {
|
||||
auto res = GetCategoryByHandleRecursive(cat.get(), handle);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WUPSConfigCategory *GetCategoryByHandle(WUPSConfigCategoryHandle handle, bool checkRecursive) {
|
||||
std::lock_guard lock(sConfigCategoryMutex);
|
||||
auto itr = std::find_if(sConfigCategories.begin(), sConfigCategories.end(), [handle](auto &cur) { return handle == cur.get(); });
|
||||
if (itr == sConfigCategories.end()) {
|
||||
if (checkRecursive) {
|
||||
std::lock_guard config_lock(sConfigsMutex);
|
||||
for (const auto &curConfig : sConfigs) {
|
||||
auto *category = Intern::GetCategoryByHandleRecursive(curConfig.get(), handle);
|
||||
if (category) {
|
||||
return category;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return itr->get();
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<WUPSConfigCategory> PopCategoryByHandle(WUPSConfigCategoryHandle handle) {
|
||||
return pop_locked_first_if(sConfigCategoryMutex, sConfigCategories, [handle](auto &cur) { return handle == cur.get(); });
|
||||
}
|
||||
|
||||
WUPSConfigItem *GetItemByHandle(WUPSConfigItemHandle handle) {
|
||||
std::lock_guard lock(sConfigItemsMutex);
|
||||
auto itr = std::find_if(sConfigItems.begin(), sConfigItems.end(), [handle](auto &cur) { return handle == cur.get(); });
|
||||
if (itr == sConfigItems.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return itr->get();
|
||||
}
|
||||
|
||||
std::unique_ptr<WUPSConfigItem> PopItemByHandle(WUPSConfigItemHandle handle) {
|
||||
return pop_locked_first_if(sConfigItemsMutex, sConfigItems, [handle](auto &cur) { return handle == cur.get(); });
|
||||
}
|
||||
|
||||
WUPSConfigAPIStatus CreateConfig(const char *name, WUPSConfigHandle *out) {
|
||||
if (out == nullptr || name == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"out\" or \"name\" was NULL");
|
||||
return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
auto config = make_unique_nothrow<WUPSConfig>(name);
|
||||
if (!config) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate WUPSConfig");
|
||||
return WUPSCONFIG_API_RESULT_OUT_OF_MEMORY;
|
||||
}
|
||||
std::lock_guard lock(sConfigsMutex);
|
||||
*out = WUPSConfigHandle(config.get());
|
||||
sConfigs.push_back(std::move(config));
|
||||
return WUPSCONFIG_API_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void CleanAllHandles() {
|
||||
std::lock_guard lock(sConfigsMutex);
|
||||
std::lock_guard lock1(sConfigCategoryMutex);
|
||||
std::lock_guard lock2(sConfigItemsMutex);
|
||||
sConfigs.clear();
|
||||
sConfigCategories.clear();
|
||||
sConfigItems.clear();
|
||||
}
|
||||
} // namespace Intern
|
||||
|
||||
/**
|
||||
* @brief Initialize the WUPSConfigAPI with extended functionality.
|
||||
*
|
||||
* This function initializes the WUPSConfigAPI with extended functionality by associating a plugin
|
||||
* identified by `pluginIdentifier` with the provided options and callback functions. The `options`
|
||||
* parameter specifies the configuration options for the plugin, while `openedCallback` and
|
||||
* `closedCallback` specify the callback functions to be invoked when the plugin menu is opened
|
||||
* and closed, respectively.
|
||||
*
|
||||
* @param pluginIdentifier The identifier of the plugin to be associated with the WUPSConfigAPI.
|
||||
* @param options The configuration options for the plugin.
|
||||
* @param openedCallback The callback function to be invoked when the plugin menu is opened.
|
||||
* @param closedCallback The callback function to be invoked when the plugin menu is closed.
|
||||
*
|
||||
* @return The status of the initialization process. Possible return values are:
|
||||
* - WUPSCONFIG_API_RESULT_SUCCESS: The initialization was successful.
|
||||
* - WUPSCONFIG_API_RESULT_INVALID_ARGUMENT: The `openedCallback` or `closedCallback` parameter is nullptr.
|
||||
* - WUPSCONFIG_API_RESULT_UNSUPPORTED_VERSION: The specified `options.version` is not supported.
|
||||
* - WUPSCONFIG_API_RESULT_NOT_FOUND: The plugin with the given identifier was not found.
|
||||
*/
|
||||
WUPSConfigAPIStatus InitEx(uint32_t pluginIdentifier, WUPSConfigAPIOptions options, WUPSConfigAPI_MenuOpenedCallback openedCallback, WUPSConfigAPI_MenuClosedCallback closedCallback) {
|
||||
if (openedCallback == nullptr || closedCallback == nullptr) {
|
||||
return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT;
|
||||
}
|
||||
for (auto &cur : gLoadedPlugins) {
|
||||
if (cur->getHandle() == pluginIdentifier) {
|
||||
if (options.version != 1) {
|
||||
return WUPSCONFIG_API_RESULT_UNSUPPORTED_VERSION;
|
||||
}
|
||||
auto configDat = PluginConfigData::create(options, openedCallback, closedCallback);
|
||||
if (!configDat) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to create config data for %08X", pluginIdentifier);
|
||||
return WUPSCONFIG_API_RESULT_UNSUPPORTED_VERSION;
|
||||
}
|
||||
cur->setConfigData(configDat.value());
|
||||
return WUPSCONFIG_API_RESULT_SUCCESS;
|
||||
}
|
||||
}
|
||||
return WUPSCONFIG_API_RESULT_NOT_FOUND;
|
||||
}
|
||||
|
||||
namespace Category {
|
||||
WUPSConfigAPIStatus Create(WUPSConfigAPICreateCategoryOptions options, WUPSConfigCategoryHandle *out) {
|
||||
if (out == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"out\" or \"name\" was NULL");
|
||||
return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT;
|
||||
}
|
||||
if (options.version != WUPS_API_CATEGORY_OPTION_VERSION_V1) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Invalid category option version: expected %08X but got %08X", WUPS_API_CATEGORY_OPTION_VERSION_V1, options.version);
|
||||
return WUPSCONFIG_API_RESULT_UNSUPPORTED_VERSION;
|
||||
}
|
||||
auto category = make_unique_nothrow<WUPSConfigCategory>(options.data.v1.name);
|
||||
if (!category) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate WUPSConfigCategory");
|
||||
return WUPSCONFIG_API_RESULT_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
std::lock_guard lock(sConfigCategoryMutex);
|
||||
*out = WUPSConfigCategoryHandle(category.get());
|
||||
sConfigCategories.push_back(std::move(category));
|
||||
return WUPSCONFIG_API_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
WUPSConfigAPIStatus Destroy(WUPSConfigCategoryHandle handle) {
|
||||
if (handle == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"handle\" was NULL");
|
||||
return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!remove_locked_first_if(sConfigCategoryMutex, sConfigCategories, [handle](auto &cur) { return handle == cur.get(); })) {
|
||||
{
|
||||
// Ignore any attempts to destroy to create root item.
|
||||
std::lock_guard lock(sConfigsMutex);
|
||||
if (std::any_of(sConfigs.begin(), sConfigs.end(), [handle](auto &cur) { return handle == cur.get(); })) {
|
||||
return WUPSCONFIG_API_RESULT_SUCCESS;
|
||||
}
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to destroy WUPSConfigCategory (for handle: \"%08X\")", handle.handle);
|
||||
return WUPSCONFIG_API_RESULT_NOT_FOUND;
|
||||
}
|
||||
return WUPSCONFIG_API_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
WUPSConfigAPIStatus AddCategory(WUPSConfigCategoryHandle parentHandle, WUPSConfigCategoryHandle categoryHandle) {
|
||||
if (parentHandle == nullptr || categoryHandle == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"parentHandle\" or \"categoryHandle\" was NULL");
|
||||
return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT;
|
||||
}
|
||||
std::lock_guard lockConfigs(sConfigsMutex);
|
||||
std::lock_guard lockCats(sConfigCategoryMutex);
|
||||
WUPSConfigCategory *parentCat = Intern::GetConfigByHandle(WUPSConfigHandle(parentHandle.handle));
|
||||
if (!parentCat) {
|
||||
parentCat = Intern::GetCategoryByHandle(parentHandle);
|
||||
if (!parentCat) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to find parent for handle %08X", parentHandle.handle);
|
||||
return WUPSCONFIG_API_RESULT_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
auto category = Intern::PopCategoryByHandle(categoryHandle);
|
||||
if (!category) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to find category. parentHandle: %08X categoryHandle: %08X", parentHandle.handle, categoryHandle.handle);
|
||||
return WUPSCONFIG_API_RESULT_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!parentCat->addCategory(category)) {
|
||||
sConfigCategories.push_back(std::move(category));
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to add category to parent. parentHandle: %08X categoryHandle: %08X", parentHandle.handle, categoryHandle.handle);
|
||||
return WUPSCONFIG_API_RESULT_UNKNOWN_ERROR; // TODO!!!
|
||||
}
|
||||
return WUPSCONFIG_API_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
WUPSConfigAPIStatus AddItem(WUPSConfigCategoryHandle parentHandle, WUPSConfigItemHandle itemHandle) {
|
||||
if (parentHandle == nullptr || itemHandle == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"handle\" or \"item_Handle\" was NULL");
|
||||
return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
std::lock_guard lockConfigs(sConfigsMutex);
|
||||
std::lock_guard lockCats(sConfigCategoryMutex);
|
||||
WUPSConfigCategory *parentCat = Intern::GetConfigByHandle(WUPSConfigHandle(parentHandle.handle));
|
||||
if (!parentCat) {
|
||||
parentCat = Intern::GetCategoryByHandle(parentHandle, true);
|
||||
if (!parentCat) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to find parent for handle %08X", parentHandle.handle);
|
||||
return WUPSCONFIG_API_RESULT_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
auto item = Intern::PopItemByHandle(itemHandle);
|
||||
if (!item) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get item for handle %08X", itemHandle.handle);
|
||||
return WUPSCONFIG_API_RESULT_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!parentCat->addItem(item)) {
|
||||
std::lock_guard lockItems(sConfigItemsMutex);
|
||||
sConfigItems.push_back(std::move(item));
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to add item %08X to category %08X", itemHandle.handle, parentHandle.handle);
|
||||
return WUPSCONFIG_API_RESULT_UNKNOWN_ERROR; // TODO
|
||||
}
|
||||
|
||||
return WUPSCONFIG_API_RESULT_SUCCESS;
|
||||
}
|
||||
} // namespace Category
|
||||
|
||||
namespace Item {
|
||||
WUPSConfigAPIStatus Create(WUPSConfigAPICreateItemOptions options, WUPSConfigItemHandle *out) {
|
||||
if (out == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"out\" was NULL");
|
||||
return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
std::unique_ptr<WUPSConfigItem> item = nullptr;
|
||||
if (options.version == WUPS_API_ITEM_OPTION_VERSION_V1) {
|
||||
item = make_unique_nothrow<WUPSConfigItemV1>(options.data.v1.configId, options.data.v1.displayName, options.data.v1.callbacks, options.data.v1.context);
|
||||
} else if (options.version == WUPS_API_ITEM_OPTION_VERSION_V2) {
|
||||
item = make_unique_nothrow<WUPSConfigItemV2>(options.data.v2.displayName, options.data.v2.callbacks, options.data.v2.context);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_WARN("Invalid item option version: expected %08X or %08X but got %08X", WUPS_API_ITEM_OPTION_VERSION_V1, WUPS_API_ITEM_OPTION_VERSION_V2, options.version);
|
||||
return WUPSCONFIG_API_RESULT_UNSUPPORTED_VERSION;
|
||||
}
|
||||
|
||||
if (!item) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate WUPSConfigItem");
|
||||
return WUPSCONFIG_API_RESULT_OUT_OF_MEMORY;
|
||||
}
|
||||
std::lock_guard lock(sConfigItemsMutex);
|
||||
*out = WUPSConfigItemHandle(item.get());
|
||||
sConfigItems.push_back(std::move(item));
|
||||
return WUPSCONFIG_API_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
WUPSConfigAPIStatus Destroy(WUPSConfigItemHandle handle) {
|
||||
if (handle == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"handle\" was NULL");
|
||||
return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!remove_locked_first_if(sConfigItemsMutex, sConfigItems, [handle](auto &cur) { return cur.get() == handle; })) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to destroy WUPSConfigItem (handle: \"%08X\")", handle);
|
||||
return WUPSCONFIG_API_RESULT_NOT_FOUND;
|
||||
}
|
||||
return WUPSCONFIG_API_RESULT_SUCCESS;
|
||||
}
|
||||
} // namespace Item
|
||||
|
||||
WUPSConfigAPIStatus WUPSConfigAPI_GetVersion(WUPSConfigAPIVersion *out) {
|
||||
if (out == nullptr) {
|
||||
return WUPSCONFIG_API_RESULT_INVALID_ARGUMENT;
|
||||
}
|
||||
*out = 1;
|
||||
return WUPSCONFIG_API_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigAPI_GetVersion);
|
||||
|
||||
WUMS_EXPORT_FUNCTION_EX(WUPSConfigAPIBackend::InitEx, WUPSConfigAPI_InitEx);
|
||||
WUMS_EXPORT_FUNCTION_EX(WUPSConfigAPIBackend::Category::Create, WUPSConfigAPI_Category_CreateEx);
|
||||
WUMS_EXPORT_FUNCTION_EX(WUPSConfigAPIBackend::Category::Destroy, WUPSConfigAPI_Category_Destroy);
|
||||
WUMS_EXPORT_FUNCTION_EX(WUPSConfigAPIBackend::Category::AddCategory, WUPSConfigAPI_Category_AddCategory);
|
||||
WUMS_EXPORT_FUNCTION_EX(WUPSConfigAPIBackend::Category::AddItem, WUPSConfigAPI_Category_AddItem);
|
||||
|
||||
WUMS_EXPORT_FUNCTION_EX(WUPSConfigAPIBackend::Item::Create, WUPSConfigAPI_Item_CreateEx);
|
||||
WUMS_EXPORT_FUNCTION_EX(WUPSConfigAPIBackend::Item::Destroy, WUPSConfigAPI_Item_Destroy);
|
||||
} // namespace WUPSConfigAPIBackend
|
231
source/config/WUPSConfigAPI.h
Normal file
231
source/config/WUPSConfigAPI.h
Normal file
@ -0,0 +1,231 @@
|
||||
#pragma once
|
||||
|
||||
#include "WUPSConfig.h"
|
||||
#include "WUPSConfigCategory.h"
|
||||
#include "WUPSConfigItem.h"
|
||||
#include <wups/config.h>
|
||||
|
||||
namespace WUPSConfigAPIBackend {
|
||||
namespace Intern {
|
||||
/**
|
||||
* @brief Retrieves a WUPSConfig pointer based on a given handle.
|
||||
*
|
||||
* This function searches for a WUPSConfig within a list of WUPSConfig objects based on a handle.
|
||||
* If a matching handle is found, a pointer to the WUPSConfig object is returned. Otherwise, nullptr is returned.
|
||||
*
|
||||
* @param handle The handle used to identify the desired WUPSConfig object.
|
||||
* @return A pointer to the WUPSConfig object with the matching handle, or nullptr if not found.
|
||||
*
|
||||
* @note This function locks the sConfigsMutex during the search operation to ensure thread safety.
|
||||
*/
|
||||
WUPSConfig *GetConfigByHandle(WUPSConfigHandle handle);
|
||||
|
||||
/**
|
||||
* @brief Pop a WUPSConfig object from the sConfigs vector based on the provided handle.
|
||||
*
|
||||
* This function retrieves a WUPSConfig object from the sConfigs vector based on the given handle.
|
||||
* It locks the sConfigsMutex to ensure thread safety during the operation.
|
||||
*
|
||||
* @param handle The handle of the WUPSConfig object to be retrieved.
|
||||
* @return A std::unique_ptr to the WUPSConfig object if found, nullptr otherwise.
|
||||
*/
|
||||
std::unique_ptr<WUPSConfig> PopConfigByHandle(WUPSConfigHandle handle);
|
||||
|
||||
/**
|
||||
* @brief Get a WUPSConfigCategory object by its handle
|
||||
*
|
||||
* This function searches for a WUPSConfigCategory object with the given handle.
|
||||
* If the 'checkRecursive' flag is set to true, the function also searches recursively
|
||||
* through all the WUPSConfig objects for the requested category.
|
||||
*
|
||||
* @param handle The handle of the desired WUPSConfigCategory
|
||||
* @param checkRecursive Flag to indicate whether recursive search is required
|
||||
* @return A pointer to the found WUPSConfigCategory object, or nullptr if not found
|
||||
*/
|
||||
WUPSConfigCategory *GetCategoryByHandle(WUPSConfigCategoryHandle handle, bool checkRecursive = false);
|
||||
|
||||
/**
|
||||
* @brief Pop a WUPSConfigCategory from the list of categories by its handle.
|
||||
*
|
||||
* This function searches for a WUPSConfigCategory in the list of categories using the given handle.
|
||||
* If a matching WUPSConfigCategory is found, it is removed from the list and returned as a unique_ptr.
|
||||
* If no matching category is found, nullptr is returned.
|
||||
*
|
||||
* @param handle The handle of the WUPSConfigCategory to pop.
|
||||
* @return std::unique_ptr<WUPSConfigCategory> The popped WUPSConfigCategory or nullptr if not found.
|
||||
*/
|
||||
std::unique_ptr<WUPSConfigCategory> PopCategoryByHandle(WUPSConfigCategoryHandle handle);
|
||||
|
||||
/**
|
||||
* @brief Retrieves a WUPSConfigItem object by its handle.
|
||||
*
|
||||
* This function searches for a WUPSConfigItem object in the sConfigItems vector
|
||||
* with a matching handle. It acquires a lock on the sConfigItemsMutex
|
||||
* to ensure thread safety during the search operation. If a matching object is found,
|
||||
* a pointer to the object is returned. Otherwise, nullptr is returned.
|
||||
*
|
||||
* @param handle The handle of the WUPSConfigItem to retrieve.
|
||||
* @return A pointer to the WUPSConfigItem object with the specified handle, or nullptr if not found.
|
||||
*/
|
||||
WUPSConfigItem *GetItemByHandle(WUPSConfigItemHandle handle);
|
||||
|
||||
/**
|
||||
* @brief Removes and returns an item from the configuration items list based on its handle.
|
||||
*
|
||||
* This function pops and returns an item from the `sConfigItems` vector based on its handle.
|
||||
* The handle is used to match the item in the vector using a predicate. If a matching item is found,
|
||||
* it is moved to the returned unique_ptr and removed from the vector.
|
||||
*
|
||||
* @param handle The handle of the item to be popped.
|
||||
* @return A unique_ptr to the popped item. If no matching item is found, returns a nullptr.
|
||||
*
|
||||
* @note The function locks the `sConfigItemsMutex` mutex to ensure thread safety while performing the operation.
|
||||
*
|
||||
* @see WUPSConfigItem
|
||||
* @see pop_locked_first_if
|
||||
* @see sConfigItemsMutex
|
||||
* @see sConfigItems
|
||||
*/
|
||||
std::unique_ptr<WUPSConfigItem> PopItemByHandle(WUPSConfigItemHandle handle);
|
||||
|
||||
/**
|
||||
* @brief Creates a new configuration with the given name.
|
||||
*
|
||||
* This function creates a new configuration with the specified name. The configuration is allocated dynamically
|
||||
* using `make_unique_nothrow` and added to the `sConfigs` vector.
|
||||
*
|
||||
* @param name The name of the configuration.
|
||||
* @param out A pointer to a `WUPSConfigHandle` where the created configuration will be stored.
|
||||
*
|
||||
* @return A `WUPSConfigAPIStatus` indicating the status of the operation.
|
||||
* - `WUPSCONFIG_API_RESULT_SUCCESS` if the configuration was created successfully.
|
||||
* - `WUPSCONFIG_API_RESULT_INVALID_ARGUMENT` if the `out` or `name` parameter is null.
|
||||
* - `WUPSCONFIG_API_RESULT_OUT_OF_MEMORY` if memory allocation fails.
|
||||
*
|
||||
* @note The caller is responsible for managing the lifetime of the created configuration and freeing the
|
||||
* associated resources when they are no longer needed.
|
||||
*/
|
||||
WUPSConfigAPIStatus CreateConfig(const char *name, WUPSConfigHandle *out);
|
||||
|
||||
/**
|
||||
* @brief Cleans all handles and clears the configuration data.
|
||||
*
|
||||
* This function acquires locks on three different mutexes: `sConfigsMutex`, `sConfigCategoryMutex`, and `sConfigItemsMutex`.
|
||||
* It then clears the vectors `sConfigs`, `sConfigCategories`, and `sConfigItems`, effectively cleaning all handles and
|
||||
* removing all configuration data.
|
||||
*
|
||||
* @note This function assumes that the mutexes and vectors are already defined and initialized.
|
||||
*
|
||||
* @see sConfigsMutex
|
||||
* @see sConfigCategoryMutex
|
||||
* @see sConfigItemsMutex
|
||||
* @see sConfigs
|
||||
* @see sConfigCategories
|
||||
* @see sConfigItems
|
||||
*/
|
||||
void CleanAllHandles();
|
||||
} // namespace Intern
|
||||
|
||||
namespace Category {
|
||||
/**
|
||||
* @brief Create a new WUPSConfigCategory.
|
||||
*
|
||||
* This function creates a new WUPSConfigCategory with the given options.
|
||||
* The created category will be added to the global config categories list and a handle to the category will be
|
||||
* returned.
|
||||
*
|
||||
* @param options The options to create the category.
|
||||
* @param out[out] Pointer to store the handle to the newly created category.
|
||||
* @return WUPSConfigAPIStatus The status of the operation.
|
||||
* - WUPSCONFIG_API_RESULT_SUCCESS: Success.
|
||||
* - WUPSCONFIG_API_RESULT_INVALID_ARGUMENT: Invalid parameter, `out` or `name` is NULL.
|
||||
* - WUPSCONFIG_API_RESULT_UNSUPPORTED_VERSION: Invalid category option version.
|
||||
* - WUPSCONFIG_API_RESULT_OUT_OF_MEMORY: Failed to allocate WUPSConfigCategory.
|
||||
*
|
||||
* @note The caller is responsible for deleting the WUPSConfigCategory instance unless it has been transferred to
|
||||
* another category
|
||||
*/
|
||||
WUPSConfigAPIStatus Create(WUPSConfigAPICreateCategoryOptions options, WUPSConfigCategoryHandle *out);
|
||||
|
||||
/**
|
||||
* @brief Destroy a WUPSConfigCategory.
|
||||
*
|
||||
* This function destroys a WUPSConfigCategory identified by the given handle.
|
||||
*
|
||||
* @param handle The handle of the WUPSConfigCategory to destroy.
|
||||
* @return WUPSConfigAPIStatus The status of the destroy operation.
|
||||
* - WUPSCONFIG_API_RESULT_SUCCESS: If the WUPSConfigCategory was successfully destroyed.
|
||||
* - WUPSCONFIG_API_RESULT_INVALID_ARGUMENT: If the handle was NULL.
|
||||
* - WUPSCONFIG_API_RESULT_NOT_FOUND: If the WUPSConfigCategory was not found.
|
||||
*/
|
||||
WUPSConfigAPIStatus Destroy(WUPSConfigCategoryHandle handle);
|
||||
|
||||
/**
|
||||
* @brief Adds a category to the WUPS configuration.
|
||||
*
|
||||
* This function adds a category to the WUPS configuration. The category is added as a child of
|
||||
* the specified parent category. On success the ownership will be passed to the parent.
|
||||
*
|
||||
* @param parentHandle The handle of the parent category.
|
||||
* @param categoryHandle The handle of the category to be added.
|
||||
* @return The status of the operation. Possible values are:
|
||||
* - WUPSCONFIG_API_RESULT_SUCCESS: The category was added successfully.
|
||||
* - WUPSCONFIG_API_RESULT_INVALID_ARGUMENT: One or both of the input handles were NULL.
|
||||
* - WUPSCONFIG_API_RESULT_NOT_FOUND: The parent category or the specified category was not found.
|
||||
* - WUPSCONFIG_API_RESULT_UNKNOWN_ERROR: Failed to add the category to the parent.
|
||||
*/
|
||||
WUPSConfigAPIStatus AddCategory(WUPSConfigCategoryHandle parentHandle, WUPSConfigCategoryHandle categoryHandle);
|
||||
|
||||
/**
|
||||
* @brief Adds an item to a WUPSConfigCategory.
|
||||
*
|
||||
* This function adds a WUPSConfigItem to a WUPSConfigCategory. The item will be added to the end of the list
|
||||
* of items in the category. This function also holds the responsibility for deleting the created item instance.
|
||||
*
|
||||
* @param parentHandle The handle of the parent category.
|
||||
* @param itemHandle The handle of the item to be added.
|
||||
* @return Returns the status of the operation.
|
||||
* - WUPSCONFIG_API_RESULT_SUCCESS: If the item was added successfully.
|
||||
* - WUPSCONFIG_API_RESULT_INVALID_ARGUMENT: If either the parentHandle or itemHandle is nullptr.
|
||||
* - WUPSCONFIG_API_RESULT_NOT_FOUND: If the parent category was not found.
|
||||
* - WUPSCONFIG_API_RESULT_UNKNOWN_ERROR: If an unknown error occurred while adding the item.
|
||||
*/
|
||||
WUPSConfigAPIStatus AddItem(WUPSConfigCategoryHandle parentHandle, WUPSConfigItemHandle itemHandle);
|
||||
} // namespace Category
|
||||
|
||||
namespace Item {
|
||||
/**
|
||||
* @brief Creates a new WUPSConfigItem and adds it to the list of config items.
|
||||
*
|
||||
* This function creates a new WUPSConfigItem object based on the provided options,
|
||||
* and returns a handle to the newly created item.
|
||||
*
|
||||
* @param options The options for creating the item.
|
||||
* @param out Pointer to store the handle to the newly created item.
|
||||
* @return The status of the API call.
|
||||
* - WUPSCONFIG_API_RESULT_SUCCESS if the item was created and added successfully.
|
||||
* - WUPSCONFIG_API_RESULT_INVALID_ARGUMENT if the 'out' parameter is nullptr.
|
||||
* - WUPSCONFIG_API_RESULT_UNSUPPORTED_VERSION if the options version is invalid.
|
||||
* - WUPSCONFIG_API_RESULT_OUT_OF_MEMORY if memory allocation failed.
|
||||
* @note The caller is responsible for deleting the WUPSConfigItem instance unless it has been transferred to
|
||||
* a category
|
||||
*/
|
||||
WUPSConfigAPIStatus Create(WUPSConfigAPICreateItemOptions options, WUPSConfigItemHandle *out);
|
||||
|
||||
/**
|
||||
* @brief Destroy a WUPSConfigItem.
|
||||
*
|
||||
* This function destroys a WUPSConfigItem identified by the given handle. It removes the memory allocated for the item.
|
||||
*
|
||||
* @param handle The handle of the WUPSConfigItem to destroy.
|
||||
* @return The status of the operation, which can be one of the following values:
|
||||
* - WUPSCONFIG_API_RESULT_SUCCESS: The WUPSConfigItem was destroyed successfully.
|
||||
* - WUPSCONFIG_API_RESULT_NOT_FOUND: The WUPSConfigItem with the given handle was not found.
|
||||
* - WUPSCONFIG_API_RESULT_INVALID_ARGUMENT: The handle parameter was NULL.
|
||||
*
|
||||
* @see WUPSConfigItemHandle, WUPSConfigAPIStatus
|
||||
*/
|
||||
WUPSConfigAPIStatus Destroy(WUPSConfigItemHandle handle);
|
||||
} // namespace Item
|
||||
|
||||
} // namespace WUPSConfigAPIBackend
|
231
source/config/WUPSConfigAPIDeprecated.cpp
Normal file
231
source/config/WUPSConfigAPIDeprecated.cpp
Normal file
@ -0,0 +1,231 @@
|
||||
#include "WUPSConfig.h"
|
||||
#include "WUPSConfigAPI.h"
|
||||
#include <wums.h>
|
||||
#include <wups/config.h>
|
||||
|
||||
int32_t WUPSConfig_Create(void **out, const char *name) {
|
||||
if (out == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
*out = nullptr;
|
||||
WUPSConfigHandle outConfig;
|
||||
if (WUPSConfigAPIBackend::Intern::CreateConfig(name, &outConfig) == WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
*out = outConfig.handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t WUPSConfig_Destroy(WUPSConfigHandle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfig_GetName(void *handle, char *out_buf, int32_t out_len) {
|
||||
if (out_buf == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"out_buf\" was NULL");
|
||||
return -1;
|
||||
}
|
||||
auto config = WUPSConfigAPIBackend::Intern::GetConfigByHandle(WUPSConfigHandle(handle));
|
||||
if (!config) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to find WUPSConfig by handle %08X", handle);
|
||||
return -1;
|
||||
}
|
||||
snprintf(out_buf, out_len, "%s", config->getName().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfig_AddCategory(void *configHandle, void *categoryHandle) {
|
||||
if (WUPSConfigAPIBackend::Category::AddCategory(WUPSConfigCategoryHandle(configHandle), WUPSConfigCategoryHandle(categoryHandle)) != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfig_AddCategoryByName(void *handle, const char *categoryName, void **out) {
|
||||
if (handle == nullptr || categoryName == nullptr || out == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"handle\" or \"categoryName\" or \"out\" was NULL");
|
||||
return -1;
|
||||
}
|
||||
*out = nullptr;
|
||||
WUPSConfigAPICreateCategoryOptions options = {
|
||||
.version = WUPS_API_CATEGORY_OPTION_VERSION_V1,
|
||||
.data = {
|
||||
.v1 = {
|
||||
.name = categoryName,
|
||||
},
|
||||
},
|
||||
};
|
||||
WUPSConfigCategoryHandle catHandle;
|
||||
if (WUPSConfigAPIBackend::Category::Create(options, &catHandle) != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to create category");
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (WUPSConfigAPIBackend::Category::AddCategory(WUPSConfigCategoryHandle(handle), catHandle) < 0) {
|
||||
WUPSConfigAPIBackend::Intern::PopCategoryByHandle(catHandle); // make sure to destroy created category.
|
||||
return -3;
|
||||
}
|
||||
*out = catHandle.handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_Create);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_Destroy);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_GetName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_AddCategoryByName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_AddCategory);
|
||||
|
||||
int32_t WUPSConfigCategory_Create(void **out, const char *name) {
|
||||
if (out == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
*out = nullptr;
|
||||
WUPSConfigAPICreateCategoryOptions options = {
|
||||
.version = WUPS_API_CATEGORY_OPTION_VERSION_V1,
|
||||
.data = {
|
||||
.v1 = {
|
||||
.name = name,
|
||||
},
|
||||
},
|
||||
};
|
||||
WUPSConfigCategoryHandle outCat;
|
||||
if (WUPSConfigAPIBackend::Category::Create(options, &outCat) != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
*out = outCat.handle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigCategory_Destroy(void *handle) {
|
||||
if (WUPSConfigAPIBackend::Category::Destroy(WUPSConfigCategoryHandle(handle)) != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigCategory_GetName(void *handle, char *out_buf, int32_t out_len) {
|
||||
if (handle == nullptr || out_buf == nullptr || out_len == 0) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"handle\" or \"out_buf\" was NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto *category = WUPSConfigAPIBackend::Intern::GetCategoryByHandle(WUPSConfigCategoryHandle(handle), true);
|
||||
if (!category) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to find existing category for handle %08X", handle);
|
||||
return -2;
|
||||
}
|
||||
snprintf(out_buf, out_len, "%s", category->getName().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigCategory_AddItem(void *handle, void *item_Handle) {
|
||||
if (WUPSConfigAPIBackend::Category::AddItem(WUPSConfigCategoryHandle(handle), WUPSConfigItemHandle(item_Handle)) != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_Create);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_Destroy);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_GetName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_AddItem);
|
||||
|
||||
int32_t WUPSConfigItem_Create(void **out, const char *configId, const char *displayName, WUPSConfigAPIItemCallbacksV1 callbacks, void *context) {
|
||||
if (out == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
*out = nullptr;
|
||||
WUPSConfigAPICreateItemOptions options = {
|
||||
.version = WUPS_API_ITEM_OPTION_VERSION_V1,
|
||||
.data = {
|
||||
.v1 = {
|
||||
.configId = configId,
|
||||
.displayName = displayName,
|
||||
.context = context,
|
||||
.callbacks = callbacks,
|
||||
},
|
||||
},
|
||||
};
|
||||
WUPSConfigItemHandle outItem;
|
||||
if (WUPSConfigAPIBackend::Item::Create(options, &outItem) != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
*out = outItem.handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigItem_Destroy(void *handle) {
|
||||
if (WUPSConfigAPIBackend::Item::Destroy(WUPSConfigItemHandle(handle)) != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigItem_SetDisplayName(void *handle, const char *displayName) {
|
||||
if (displayName == nullptr || handle == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"handle\" or \"displayName\" was NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto *config = WUPSConfigAPIBackend::Intern::GetItemByHandle(WUPSConfigItemHandle(handle));
|
||||
if (!config) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to find item for handle %08X", handle);
|
||||
return -2;
|
||||
}
|
||||
config->setDisplayName(displayName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigItem_GetDisplayName(void *handle, char *out_buf, int32_t out_len) {
|
||||
if (handle == nullptr || out_buf == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"handle\" or \"out_buf\" was NULL");
|
||||
return -1;
|
||||
}
|
||||
auto *config = WUPSConfigAPIBackend::Intern::GetItemByHandle(WUPSConfigItemHandle(handle));
|
||||
if (!config) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to find item for handle %08X", handle);
|
||||
return -2;
|
||||
}
|
||||
snprintf(out_buf, out_len, "%s", config->getDisplayName().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigItem_SetConfigID(void *handle, const char *configId) {
|
||||
if (handle == nullptr || configId == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"handle\" or \"configId\" was NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto *config = WUPSConfigAPIBackend::Intern::GetItemByHandle(WUPSConfigItemHandle(handle));
|
||||
if (!config) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to find item for handle %08X", handle);
|
||||
return -2;
|
||||
}
|
||||
config->setConfigId(configId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigItem_GetConfigID(void *handle, char *out_buf, int32_t out_len) {
|
||||
if (handle == nullptr || out_buf == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Invalid param: \"handle\" or \"out_buf\" was NULL");
|
||||
return -1;
|
||||
}
|
||||
auto *config = WUPSConfigAPIBackend::Intern::GetItemByHandle(WUPSConfigItemHandle(handle));
|
||||
if (!config) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to find item for handle %08X", handle);
|
||||
return -2;
|
||||
}
|
||||
snprintf(out_buf, out_len, "%s", config->getConfigId().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_Create);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_Destroy);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_SetDisplayName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_GetDisplayName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_SetConfigID);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_GetConfigID);
|
@ -1,73 +1,95 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2018-2021 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/>.
|
||||
****************************************************************************/
|
||||
* Copyright (C) 2018-2021 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/>.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "WUPSConfigItem.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wups/config.h>
|
||||
|
||||
class WUPSConfigCategory {
|
||||
public:
|
||||
explicit WUPSConfigCategory(std::string_view name) {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
~WUPSConfigCategory() {
|
||||
for (const auto &element : items) {
|
||||
delete element;
|
||||
namespace WUPSConfigAPIBackend {
|
||||
class WUPSConfigCategory {
|
||||
public:
|
||||
explicit WUPSConfigCategory(std::string_view name) : mName(name) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\return Returns the name of this WUPSConfigCategory
|
||||
virtual ~WUPSConfigCategory() = default;
|
||||
|
||||
/**
|
||||
\return Returns the name of this WUPSConfigCategory
|
||||
**/
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return this->name;
|
||||
}
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
\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.
|
||||
/**
|
||||
\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.
|
||||
\param item: The item that will be added to this config.
|
||||
|
||||
\return On success, true will be returned.
|
||||
On error false will be returned. In this case the caller still has the responsibility
|
||||
for deleting the WUPSConfigItem instance.
|
||||
\return On success, true will be returned.
|
||||
On error false will be returned. In this case the caller still has the responsibility
|
||||
for deleting the WUPSConfigItem instance.
|
||||
**/
|
||||
[[nodiscard]] bool addItem(std::unique_ptr<WUPSConfigItem> &item) {
|
||||
if (item != nullptr) {
|
||||
mItems.push_back(std::move(item));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\return Returns a vector with all items.
|
||||
**/
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<WUPSConfigItem>> &getItems() const {
|
||||
return mItems;
|
||||
}
|
||||
|
||||
/**
|
||||
\return Returns a vector with all categories.
|
||||
**/
|
||||
[[nodiscard]] bool addItem(WUPSConfigItem *item) {
|
||||
if (item != nullptr) {
|
||||
items.push_back(item);
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<WUPSConfigCategory>> &getCategories() const {
|
||||
return mCategories;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Adds a given WUPSConfigCategory to this WUPSConfigCategory.
|
||||
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, true will be returned.
|
||||
On error false will be returned. In this case the caller still has the responsibility
|
||||
for deleting the WUPSConfigCategory instance.
|
||||
**/
|
||||
[[nodiscard]] bool addCategory(std::unique_ptr<WUPSConfigCategory> &category) {
|
||||
mCategories.push_back(std::move(category));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\return Returns a vector with all items.
|
||||
**/
|
||||
[[nodiscard]] const std::vector<WUPSConfigItem *> &getItems() const {
|
||||
return this->items;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::vector<WUPSConfigItem *> items{};
|
||||
};
|
||||
private:
|
||||
std::string mName;
|
||||
std::vector<std::unique_ptr<WUPSConfigItem>> mItems;
|
||||
std::vector<std::unique_ptr<WUPSConfigCategory>> mCategories;
|
||||
};
|
||||
} // namespace WUPSConfigAPIBackend
|
@ -1,81 +0,0 @@
|
||||
#include "../utils/logger.h"
|
||||
#include "WUPSConfigCategory.h"
|
||||
#include <wums.h>
|
||||
#include <wups/config.h>
|
||||
|
||||
int32_t WUPSConfigCategory_Create(WUPSConfigCategoryHandle *out, const char *name) {
|
||||
if (name == nullptr || out == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out = (WUPSConfigCategoryHandle) new WUPSConfigCategory(name);
|
||||
if (*out != 0) {
|
||||
return 0;
|
||||
}
|
||||
return -2;
|
||||
};
|
||||
|
||||
int32_t WUPSConfigCategory_Destroy(WUPSConfigCategoryHandle handle) {
|
||||
if (handle == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto *config = reinterpret_cast<WUPSConfigCategory *>(handle);
|
||||
delete config;
|
||||
return 0;
|
||||
};
|
||||
|
||||
int32_t WUPSConfigCategory_GetName(WUPSConfigCategoryHandle handle, char *out_buf, int32_t out_len) {
|
||||
if (out_buf == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfigCategory *>(handle);
|
||||
snprintf(out_buf, out_len, "%s", config->getName().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigCategory_AddItem(WUPSConfigCategoryHandle handle, WUPSConfigItemHandle item_Handle) {
|
||||
if (handle == 0 || item_Handle == 0) {
|
||||
return -1;
|
||||
}
|
||||
auto *category = reinterpret_cast<WUPSConfigCategory *>(handle);
|
||||
auto *item = reinterpret_cast<WUPSConfigItem *>(item_Handle);
|
||||
if (category->addItem(item)) {
|
||||
return 0;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
/*
|
||||
int32_t WUPSConfigCategory_GetItemCount(WUPSConfigCategoryHandle handle, int32_t *item_count) {
|
||||
if (handle == 0 || item_count == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfigCategory *>(handle);
|
||||
*item_count = config->getItems().size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigCategory_GetItems(WUPSConfigCategoryHandle handle, WUPSConfigItemHandle *items_out, int32_t items_out_size) {
|
||||
if (handle == 0 || items_out == nullptr || items_out_size == 0) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfigCategory *>(handle);
|
||||
auto items = config->getItems();
|
||||
int32_t index = 0;
|
||||
for (auto const &item: items) {
|
||||
if (index >= items_out_size) {
|
||||
break;
|
||||
}
|
||||
items_out[index] = (WUPSConfigItemHandle) item;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_Create);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_Destroy);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_GetName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_AddItem);
|
||||
/*
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_GetItemCount);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_GetItems);*/
|
@ -1,96 +0,0 @@
|
||||
#include "../utils/logger.h"
|
||||
#include "WUPSConfig.h"
|
||||
#include <wums.h>
|
||||
#include <wups/config.h>
|
||||
|
||||
int32_t WUPSConfig_Create(WUPSConfigHandle *out, const char *name) {
|
||||
if (name == nullptr || out == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out = (WUPSConfigHandle) new WUPSConfig(name);
|
||||
if (*out != 0) {
|
||||
return 0;
|
||||
}
|
||||
return -2;
|
||||
};
|
||||
|
||||
int32_t WUPSConfig_Destroy(WUPSConfigHandle handle) {
|
||||
if (handle == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto *config = reinterpret_cast<WUPSConfig *>(handle);
|
||||
delete config;
|
||||
return 0;
|
||||
};
|
||||
|
||||
int32_t WUPSConfig_GetName(WUPSConfigHandle handle, char *out_buf, int32_t out_len) {
|
||||
if (out_buf == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfig *>(handle);
|
||||
snprintf(out_buf, out_len, "%s", config->getName().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfig_AddCategoryByName(WUPSConfigHandle handle, const char *categoryName, WUPSConfigCategoryHandle *out) {
|
||||
if (categoryName == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfig *>(handle);
|
||||
auto res = config->addCategory(std::string(categoryName));
|
||||
if (res.has_value()) {
|
||||
if (out != nullptr) {
|
||||
*out = reinterpret_cast<WUPSConfigCategoryHandle>(res.value());
|
||||
} else {
|
||||
return -3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
int32_t WUPSConfig_AddCategory(WUPSConfigHandle handle, WUPSConfigCategoryHandle category) {
|
||||
auto *config = reinterpret_cast<WUPSConfig *>(handle);
|
||||
auto res = config->addCategory(reinterpret_cast<WUPSConfigCategory *>(category));
|
||||
if (res == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
int32_t WUPSConfig_GetCategoryCount(WUPSConfigHandle handle, int32_t *category_count) {
|
||||
if (category_count == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfig *>(handle);
|
||||
*category_count = config->getCategories().size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfig_GetCategories(WUPSConfigHandle handle, WUPSConfigCategoryHandle *categories_out, int32_t categories_out_size) {
|
||||
if (categories_out == nullptr || categories_out_size == 0) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfig *>(handle);
|
||||
auto cats = config->getCategories();
|
||||
int32_t index = 0;
|
||||
for (auto const &cat: cats) {
|
||||
if (index >= categories_out_size) {
|
||||
break;
|
||||
}
|
||||
categories_out[index] = (WUPSConfigCategoryHandle) cat;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_Create);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_Destroy);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_GetName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_AddCategoryByName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_AddCategory);
|
||||
/*
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_GetCategoryCount);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_GetCategories);*/
|
@ -18,170 +18,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/StringTools.h"
|
||||
#include "utils/logger.h"
|
||||
#include <wups/config.h>
|
||||
|
||||
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_view _displayName) {
|
||||
this->displayName = _displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
\return Returns the display name of this WUPSConfigItem
|
||||
**/
|
||||
virtual const 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_view _configID) {
|
||||
this->configID = _configID;
|
||||
}
|
||||
|
||||
/**
|
||||
\return Returns the configID of this WUPSConfigItem.
|
||||
**/
|
||||
[[nodiscard]] virtual const std::string &getConfigID() const {
|
||||
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
|
||||
**/
|
||||
[[nodiscard]] std::string getCurrentValueDisplay() const {
|
||||
if (this->callbacks.getCurrentValueDisplay != nullptr) {
|
||||
char buf[80];
|
||||
int res = this->callbacks.getCurrentValueDisplay(context, buf, sizeof(buf));
|
||||
if (res == 0) {
|
||||
return buf;
|
||||
} else {
|
||||
return string_format("[ERROR %d]", res);
|
||||
}
|
||||
namespace WUPSConfigAPIBackend {
|
||||
class WUPSConfigItem {
|
||||
public:
|
||||
explicit WUPSConfigItem(std::string displayName) : mDisplayName(std::move(displayName)) {
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||
return "NOT_IMPLEMENTED";
|
||||
}
|
||||
virtual ~WUPSConfigItem() = default;
|
||||
|
||||
/**
|
||||
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
|
||||
**/
|
||||
[[nodiscard]] std::string getCurrentValueSelectedDisplay() const {
|
||||
if (this->callbacks.getCurrentValueSelectedDisplay != nullptr) {
|
||||
char buf[80];
|
||||
int res = this->callbacks.getCurrentValueSelectedDisplay(context, buf, sizeof(buf));
|
||||
if (res == 0) {
|
||||
return buf;
|
||||
} else {
|
||||
return string_format("[ERROR %d]", res);
|
||||
}
|
||||
[[nodiscard]] virtual std::string getCurrentValueDisplay() const = 0;
|
||||
|
||||
[[nodiscard]] virtual std::string getCurrentValueSelectedDisplay() const = 0;
|
||||
|
||||
virtual void onSelected(bool isSelected) const = 0;
|
||||
|
||||
virtual void onButtonPressed(WUPSConfigButtons) const {}
|
||||
|
||||
[[nodiscard]] virtual bool isMovementAllowed() const = 0;
|
||||
|
||||
virtual void restoreDefault() const = 0;
|
||||
|
||||
virtual void onCloseCallback() = 0;
|
||||
|
||||
[[nodiscard]] const std::string &getDisplayName() const {
|
||||
return mDisplayName;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||
return "NOT_IMPLEMENTED";
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
**/
|
||||
void onSelected(bool isSelected) const {
|
||||
if (this->callbacks.onSelected != nullptr) {
|
||||
this->callbacks.onSelected(context, isSelected);
|
||||
return;
|
||||
virtual void setConfigId(const std::string &) {}
|
||||
|
||||
virtual const std::string &getConfigId() {
|
||||
return mStubConfigId;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
/**
|
||||
Is called when a button is pressed while the cursor on this item.
|
||||
See the WUPSConfigButtons enum for possible values.
|
||||
**/
|
||||
void onButtonPressed(WUPSConfigButtons buttons) const {
|
||||
if (this->callbacks.onButtonPressed != nullptr) {
|
||||
this->callbacks.onButtonPressed(context, buttons);
|
||||
return;
|
||||
void setDisplayName(std::string displayName) {
|
||||
mDisplayName = std::move(displayName);
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
**/
|
||||
[[nodiscard]] bool isMovementAllowed() const {
|
||||
if (this->callbacks.isMovementAllowed != nullptr) {
|
||||
return this->callbacks.isMovementAllowed(context);
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||
return false;
|
||||
}
|
||||
virtual void onInput(WUPSConfigSimplePadData) const {}
|
||||
|
||||
/**
|
||||
Restores the default value
|
||||
**/
|
||||
void restoreDefault() {
|
||||
if (this->callbacks.restoreDefault != nullptr) {
|
||||
this->callbacks.restoreDefault(context);
|
||||
return;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||
}
|
||||
virtual void onInputEx(WUPSConfigComplexPadData) const {}
|
||||
|
||||
/**
|
||||
Call callback with with current value.
|
||||
This function will be called whenever this item should call it's (optional) given
|
||||
callback with the current value.
|
||||
Returns true if a valid callback could be called
|
||||
Returns false if no callback was called (e.g. callback was nullptr)
|
||||
**/
|
||||
bool callCallback() {
|
||||
if (this->callbacks.callCallback != nullptr) {
|
||||
return this->callbacks.callCallback(context);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isDirty() {
|
||||
return defaultValue != getCurrentValueDisplay();
|
||||
}
|
||||
|
||||
WUPSConfigItem(std::string_view _configID, std::string_view _displayName, WUPSConfigCallbacks_t callbacks, void *_context) {
|
||||
this->configID = _configID;
|
||||
this->displayName = _displayName;
|
||||
this->context = _context;
|
||||
this->callbacks = callbacks;
|
||||
this->defaultValue = getCurrentValueDisplay();
|
||||
}
|
||||
|
||||
virtual ~WUPSConfigItem() {
|
||||
if (this->callbacks.onDelete != nullptr) {
|
||||
this->callbacks.onDelete(context);
|
||||
return;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||
protected:
|
||||
std::string mDisplayName;
|
||||
std::string mStubConfigId;
|
||||
};
|
||||
|
||||
private:
|
||||
void *context;
|
||||
std::string displayName;
|
||||
std::string configID;
|
||||
std::string defaultValue;
|
||||
WUPSConfigCallbacks_t callbacks{};
|
||||
};
|
||||
} // namespace WUPSConfigAPIBackend
|
||||
|
@ -1,72 +0,0 @@
|
||||
#include "WUPSConfigItem.h"
|
||||
#include <wums.h>
|
||||
#include <wups/config.h>
|
||||
|
||||
typedef uint32_t WUPSConfigItemHandle;
|
||||
|
||||
int32_t WUPSConfigItem_Create(WUPSConfigItemHandle *out, const char *configID, const char *displayName, WUPSConfigCallbacks_t callbacks, void *context) {
|
||||
if (out == nullptr || configID == nullptr || displayName == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out = (WUPSConfigItemHandle) new WUPSConfigItem(configID, displayName, callbacks, context);
|
||||
if (*out != 0) {
|
||||
return 0;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigItem_Destroy(WUPSConfigItemHandle handle) {
|
||||
if (handle == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto *config = reinterpret_cast<WUPSConfigItem *>(handle);
|
||||
delete config;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigItem_SetDisplayName(WUPSConfigItemHandle handle, const char *displayName) {
|
||||
if (displayName == nullptr || handle == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto *config = reinterpret_cast<WUPSConfigItem *>(handle);
|
||||
config->setDisplayName(displayName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigItem_GetDisplayName(WUPSConfigItemHandle handle, char *out_buf, int32_t out_len) {
|
||||
if (out_buf == nullptr || handle == 0) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfigItem *>(handle);
|
||||
snprintf(out_buf, out_len, "%s", config->getDisplayName().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigItem_SetConfigID(WUPSConfigItemHandle handle, const char *configID) {
|
||||
if (configID == nullptr || handle == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto *config = reinterpret_cast<WUPSConfigItem *>(handle);
|
||||
config->setConfigID(configID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigItem_GetConfigID(WUPSConfigItemHandle handle, char *out_buf, int32_t out_len) {
|
||||
if (out_buf == nullptr || handle == 0) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfigItem *>(handle);
|
||||
snprintf(out_buf, out_len, "%s", config->getConfigID().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_Create);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_Destroy);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_SetDisplayName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_GetDisplayName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_SetConfigID);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_GetConfigID);
|
97
source/config/WUPSConfigItemV1.cpp
Normal file
97
source/config/WUPSConfigItemV1.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#include "WUPSConfigItemV1.h"
|
||||
|
||||
namespace WUPSConfigAPIBackend {
|
||||
WUPSConfigItemV1::WUPSConfigItemV1(std::string_view configId, std::string_view _displayName, WUPSConfigAPIItemCallbacksV1 callbacks, void *context) : WUPSConfigItem(std::string(_displayName)) {
|
||||
this->mConfigId = configId;
|
||||
this->mContext = context;
|
||||
this->mCallbacks = callbacks;
|
||||
this->mDefaultValue = getCurrentValueDisplayImpl();
|
||||
}
|
||||
|
||||
WUPSConfigItemV1::~WUPSConfigItemV1() {
|
||||
if (this->mCallbacks.onDelete == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_WARN("onDelete callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return;
|
||||
}
|
||||
this->mCallbacks.onDelete(mContext);
|
||||
}
|
||||
|
||||
std::string WUPSConfigItemV1::getCurrentValueDisplayImpl() const {
|
||||
if (this->mCallbacks.getCurrentValueDisplay == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("getCurrentValueDisplay callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return "NOT_IMPLEMENTED";
|
||||
}
|
||||
char buf[80];
|
||||
int res = this->mCallbacks.getCurrentValueDisplay(mContext, buf, sizeof(buf));
|
||||
if (res != 0) {
|
||||
return string_format("[ERROR %d]", res);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string WUPSConfigItemV1::getCurrentValueDisplay() const {
|
||||
return getCurrentValueDisplayImpl();
|
||||
}
|
||||
|
||||
std::string WUPSConfigItemV1::getCurrentValueSelectedDisplay() const {
|
||||
if (this->mCallbacks.getCurrentValueSelectedDisplay == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("getCurrentValueSelectedDisplay callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return "NOT_IMPLEMENTED";
|
||||
}
|
||||
char buf[80];
|
||||
int res = this->mCallbacks.getCurrentValueSelectedDisplay(mContext, buf, sizeof(buf));
|
||||
if (res != 0) {
|
||||
return string_format("[ERROR %d]", res);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void WUPSConfigItemV1::onSelected(bool isSelected) const {
|
||||
if (this->mCallbacks.onSelected == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("onSelected callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return;
|
||||
}
|
||||
this->mCallbacks.onSelected(mContext, isSelected);
|
||||
}
|
||||
|
||||
void WUPSConfigItemV1::onButtonPressed(WUPSConfigButtons buttons) const {
|
||||
if (this->mCallbacks.onButtonPressed == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("onButtonPressed callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return;
|
||||
}
|
||||
this->mCallbacks.onButtonPressed(mContext, buttons);
|
||||
}
|
||||
|
||||
bool WUPSConfigItemV1::isMovementAllowed() const {
|
||||
if (this->mCallbacks.isMovementAllowed == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("isMovementAllowed callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return true;
|
||||
}
|
||||
return this->mCallbacks.isMovementAllowed(mContext);
|
||||
}
|
||||
|
||||
void WUPSConfigItemV1::restoreDefault() const {
|
||||
if (this->mCallbacks.restoreDefault == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("restoreDefault callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return;
|
||||
}
|
||||
this->mCallbacks.restoreDefault(mContext);
|
||||
}
|
||||
|
||||
void WUPSConfigItemV1::onCloseCallback() {
|
||||
if (this->mCallbacks.callCallback == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("callCallback callback not implemented. [%s]", mDisplayName.c_str());
|
||||
}
|
||||
if (mDefaultValue != getCurrentValueDisplay()) {
|
||||
this->mCallbacks.callCallback(mContext);
|
||||
}
|
||||
}
|
||||
|
||||
void WUPSConfigItemV1::setConfigId(const std::string &configId) {
|
||||
mConfigId = configId;
|
||||
}
|
||||
|
||||
const std::string &WUPSConfigItemV1::getConfigId() {
|
||||
return mConfigId;
|
||||
}
|
||||
} // namespace WUPSConfigAPIBackend
|
39
source/config/WUPSConfigItemV1.h
Normal file
39
source/config/WUPSConfigItemV1.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include "WUPSConfigItem.h"
|
||||
#include <string>
|
||||
#include <wups/config.h>
|
||||
|
||||
namespace WUPSConfigAPIBackend {
|
||||
class WUPSConfigItemV1 : public WUPSConfigItem {
|
||||
public:
|
||||
WUPSConfigItemV1(std::string_view configId, std::string_view _displayName, WUPSConfigAPIItemCallbacksV1 callbacks, void *context);
|
||||
|
||||
~WUPSConfigItemV1() override;
|
||||
|
||||
[[nodiscard]] std::string getCurrentValueDisplayImpl() const;
|
||||
|
||||
[[nodiscard]] std::string getCurrentValueDisplay() const override;
|
||||
|
||||
[[nodiscard]] std::string getCurrentValueSelectedDisplay() const override;
|
||||
|
||||
void onSelected(bool isSelected) const override;
|
||||
|
||||
void onButtonPressed(WUPSConfigButtons buttons) const override;
|
||||
|
||||
[[nodiscard]] bool isMovementAllowed() const override;
|
||||
|
||||
void restoreDefault() const override;
|
||||
|
||||
void onCloseCallback() override;
|
||||
|
||||
void setConfigId(const std::string &configId) override;
|
||||
|
||||
const std::string &getConfigId() override;
|
||||
|
||||
private:
|
||||
void *mContext;
|
||||
std::string mConfigId;
|
||||
std::string mDefaultValue;
|
||||
WUPSConfigAPIItemCallbacksV1 mCallbacks{};
|
||||
};
|
||||
} // namespace WUPSConfigAPIBackend
|
93
source/config/WUPSConfigItemV2.cpp
Normal file
93
source/config/WUPSConfigItemV2.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include "WUPSConfigItemV2.h"
|
||||
#include <string>
|
||||
#include <wups/config.h>
|
||||
namespace WUPSConfigAPIBackend {
|
||||
WUPSConfigItemV2::WUPSConfigItemV2(std::string_view displayName, WUPSConfigAPIItemCallbacksV2 callbacks, void *context) : WUPSConfigItem(std::string(displayName)) {
|
||||
this->mDisplayName = displayName;
|
||||
this->mContext = context;
|
||||
this->mCallbacks = callbacks;
|
||||
}
|
||||
|
||||
WUPSConfigItemV2::~WUPSConfigItemV2() {
|
||||
if (this->mCallbacks.onDelete == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_WARN("onDelete callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return;
|
||||
}
|
||||
this->mCallbacks.onDelete(mContext);
|
||||
}
|
||||
|
||||
void WUPSConfigItemV2::onSelected(bool isSelected) const {
|
||||
if (this->mCallbacks.onSelected == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("onSelected callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return;
|
||||
}
|
||||
this->mCallbacks.onSelected(mContext, isSelected);
|
||||
}
|
||||
|
||||
|
||||
std::string WUPSConfigItemV2::getCurrentValueDisplay() const {
|
||||
if (this->mCallbacks.getCurrentValueDisplay == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("getCurrentValueDisplay callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return "NOT_IMPLEMENTED";
|
||||
}
|
||||
char buf[80];
|
||||
int res = this->mCallbacks.getCurrentValueDisplay(mContext, buf, sizeof(buf));
|
||||
if (res != 0) {
|
||||
return string_format("[ERROR %d]", res);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string WUPSConfigItemV2::getCurrentValueSelectedDisplay() const {
|
||||
if (this->mCallbacks.getCurrentValueSelectedDisplay == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("getCurrentValueSelectedDisplay callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return "NOT_IMPLEMENTED";
|
||||
}
|
||||
char buf[80];
|
||||
int res = this->mCallbacks.getCurrentValueSelectedDisplay(mContext, buf, sizeof(buf));
|
||||
if (res != 0) {
|
||||
return string_format("[ERROR %d]", res);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void WUPSConfigItemV2::onInput(WUPSConfigSimplePadData input) const {
|
||||
if (this->mCallbacks.onInput == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("onInput callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return;
|
||||
}
|
||||
this->mCallbacks.onInput(mContext, input);
|
||||
}
|
||||
|
||||
void WUPSConfigItemV2::onInputEx(WUPSConfigComplexPadData input) const {
|
||||
if (this->mCallbacks.onInputEx == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("onInputEx callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return;
|
||||
}
|
||||
this->mCallbacks.onInputEx(mContext, input);
|
||||
}
|
||||
|
||||
bool WUPSConfigItemV2::isMovementAllowed() const {
|
||||
if (this->mCallbacks.isMovementAllowed == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("isMovementAllowed callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return true;
|
||||
}
|
||||
return this->mCallbacks.isMovementAllowed(mContext);
|
||||
}
|
||||
|
||||
void WUPSConfigItemV2::restoreDefault() const {
|
||||
if (this->mCallbacks.restoreDefault == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("restoreDefault callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return;
|
||||
}
|
||||
this->mCallbacks.restoreDefault(mContext);
|
||||
}
|
||||
|
||||
void WUPSConfigItemV2::onCloseCallback() {
|
||||
if (this->mCallbacks.onCloseCallback == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("onCloseCallback callback not implemented. [%s]", mDisplayName.c_str());
|
||||
return;
|
||||
}
|
||||
this->mCallbacks.onCloseCallback(mContext);
|
||||
}
|
||||
} // namespace WUPSConfigAPIBackend
|
35
source/config/WUPSConfigItemV2.h
Normal file
35
source/config/WUPSConfigItemV2.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include "WUPSConfigItem.h"
|
||||
#include <string>
|
||||
#include <wups/config.h>
|
||||
|
||||
namespace WUPSConfigAPIBackend {
|
||||
|
||||
class WUPSConfigItemV2 : public WUPSConfigItem {
|
||||
public:
|
||||
WUPSConfigItemV2(std::string_view displayName, WUPSConfigAPIItemCallbacksV2 callbacks, void *context);
|
||||
|
||||
~WUPSConfigItemV2() override;
|
||||
|
||||
[[nodiscard]] std::string getCurrentValueDisplay() const override;
|
||||
|
||||
[[nodiscard]] std::string getCurrentValueSelectedDisplay() const override;
|
||||
|
||||
void onSelected(bool isSelected) const override;
|
||||
|
||||
void onInput(WUPSConfigSimplePadData input) const override;
|
||||
|
||||
void onInputEx(WUPSConfigComplexPadData input) const override;
|
||||
|
||||
[[nodiscard]] bool isMovementAllowed() const override;
|
||||
|
||||
void restoreDefault() const override;
|
||||
|
||||
void onCloseCallback() override;
|
||||
|
||||
private:
|
||||
void *mContext;
|
||||
std::string mDefaultValue;
|
||||
WUPSConfigAPIItemCallbacksV2 mCallbacks{};
|
||||
};
|
||||
} // namespace WUPSConfigAPIBackend
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include "plugin/PluginContainer.h"
|
||||
#include "utils/ConfigUtils.h"
|
||||
#include "utils/config/ConfigUtils.h"
|
||||
#include "version.h"
|
||||
#include <coreinit/dynload.h>
|
||||
#include <forward_list>
|
||||
|
@ -20,8 +20,8 @@ static const char **hook_names = (const char *[]){
|
||||
"WUPS_LOADER_HOOK_INIT_WRAPPER",
|
||||
"WUPS_LOADER_HOOK_FINI_WRAPPER",
|
||||
|
||||
"WUPS_LOADER_HOOK_GET_CONFIG",
|
||||
"WUPS_LOADER_HOOK_CONFIG_CLOSED",
|
||||
"WUPS_LOADER_HOOK_GET_CONFIG_DEPRECATED",
|
||||
"WUPS_LOADER_HOOK_CONFIG_CLOSED_DEPRECATED",
|
||||
|
||||
"WUPS_LOADER_HOOK_INIT_STORAGE_DEPRECATED",
|
||||
|
||||
@ -32,7 +32,8 @@ static const char **hook_names = (const char *[]){
|
||||
"WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND",
|
||||
"WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT",
|
||||
"WUPS_LOADER_HOOK_APPLICATION_ENDS",
|
||||
"WUPS_LOADER_HOOK_INIT_STORAGE"};
|
||||
"WUPS_LOADER_HOOK_INIT_STORAGE",
|
||||
"WUPS_LOADER_HOOK_INIT_CONFIG"};
|
||||
|
||||
void CallHook(const std::vector<std::unique_ptr<PluginContainer>> &plugins, wups_loader_hook_type_t hook_type) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d]", hook_names[hook_type], hook_type);
|
||||
@ -60,8 +61,8 @@ void CallHook(const PluginContainer &plugin, wups_loader_hook_type_t hook_type)
|
||||
case WUPS_LOADER_HOOK_FINI_WUT_SOCKETS:
|
||||
case WUPS_LOADER_HOOK_INIT_WRAPPER:
|
||||
case WUPS_LOADER_HOOK_FINI_WRAPPER:
|
||||
case WUPS_LOADER_HOOK_GET_CONFIG:
|
||||
case WUPS_LOADER_HOOK_CONFIG_CLOSED:
|
||||
case WUPS_LOADER_HOOK_GET_CONFIG_DEPRECATED:
|
||||
case WUPS_LOADER_HOOK_CONFIG_CLOSED_DEPRECATED:
|
||||
case WUPS_LOADER_HOOK_INIT_PLUGIN:
|
||||
case WUPS_LOADER_HOOK_DEINIT_PLUGIN:
|
||||
case WUPS_LOADER_HOOK_APPLICATION_STARTS:
|
||||
@ -75,7 +76,7 @@ void CallHook(const PluginContainer &plugin, wups_loader_hook_type_t hook_type)
|
||||
break;
|
||||
case WUPS_LOADER_HOOK_INIT_STORAGE:
|
||||
case WUPS_LOADER_HOOK_INIT_STORAGE_DEPRECATED: {
|
||||
if (plugin.getMetaInformation().getWUPSVersion() < WUPSVersion(0, 7, 2)) {
|
||||
if (plugin.getMetaInformation().getWUPSVersion() <= WUPSVersion(0, 7, 1)) {
|
||||
WUPSStorageDeprecated::wups_loader_init_storage_args_t_ args{};
|
||||
args.open_storage_ptr = &WUPSStorageDeprecated::StorageUtils::OpenStorage;
|
||||
args.close_storage_ptr = &WUPSStorageDeprecated::StorageUtils::CloseStorage;
|
||||
@ -100,9 +101,19 @@ void CallHook(const PluginContainer &plugin, wups_loader_hook_type_t hook_type)
|
||||
// clang-format off
|
||||
auto res = ((WUPSStorageError(*)(wups_loader_init_storage_args_t_))((uint32_t *) func_ptr))(args);
|
||||
// clang-format on
|
||||
if (res == WUPS_STORAGE_ERROR_INVALID_VERSION) {
|
||||
if (res != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
// TODO: More error handling? Notification?
|
||||
DEBUG_FUNCTION_LINE_ERR("WUPS_LOADER_HOOK_INIT_STORAGE failed for plugin %s: WUPS_STORAGE_ERROR_INVALID_VERSION", plugin.getMetaInformation().getName().c_str());
|
||||
DEBUG_FUNCTION_LINE_ERR("WUPS_LOADER_HOOK_INIT_STORAGE failed for plugin %s: %s", plugin.getMetaInformation().getName().c_str(), WUPS_GetStorageStatusStr(res));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WUPS_LOADER_HOOK_INIT_CONFIG: {
|
||||
wups_loader_init_config_args_t args{.arg_version = 1, .plugin_identifier = plugin.getHandle()};
|
||||
auto res = ((WUPSConfigAPIStatus(*)(wups_loader_init_config_args_t))((uint32_t *) func_ptr))(args);
|
||||
// clang-format on
|
||||
if (res != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
// TODO: More error handling? Notification?
|
||||
DEBUG_FUNCTION_LINE_ERR("WUPS_LOADER_HOOK_INIT_CONFIG failed for plugin %s: %s", plugin.getMetaInformation().getName().c_str(), WUPSConfigAPI_GetStatusStr(res));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
56
source/plugin/PluginConfigData.h
Normal file
56
source/plugin/PluginConfigData.h
Normal file
@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "config/WUPSConfigAPI.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <wups/config_api.h>
|
||||
|
||||
class PluginConfigData {
|
||||
public:
|
||||
PluginConfigData(std::string_view name,
|
||||
WUPSConfigAPI_MenuOpenedCallback openedCallback,
|
||||
WUPSConfigAPI_MenuClosedCallback closedCallback) : mName(name),
|
||||
mOpenedCallback(openedCallback),
|
||||
mClosedCallback(closedCallback) {
|
||||
}
|
||||
|
||||
std::optional<WUPSConfigHandle> createConfig() {
|
||||
WUPSConfigHandle handle;
|
||||
if (WUPSConfigAPIBackend::Intern::CreateConfig(mName.c_str(), &handle) == WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
return handle;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
WUPSConfigAPIStatus CallMenuOpenendCallback(WUPSConfigHandle config) {
|
||||
if (mOpenedCallback == nullptr) {
|
||||
return WUPSCONFIG_API_RESULT_MISSING_CALLBACK;
|
||||
}
|
||||
if (mOpenedCallback(WUPSConfigCategoryHandle(config.handle)) != WUPSCONFIG_API_CALLBACK_RESULT_SUCCESS) {
|
||||
return WUPSCONFIG_API_RESULT_UNKNOWN_ERROR;
|
||||
}
|
||||
return WUPSCONFIG_API_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
WUPSConfigAPIStatus CallMenuClosedCallback() {
|
||||
if (mClosedCallback == nullptr) {
|
||||
return WUPSCONFIG_API_RESULT_MISSING_CALLBACK;
|
||||
}
|
||||
mClosedCallback();
|
||||
return WUPSCONFIG_API_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static std::optional<PluginConfigData> create(WUPSConfigAPIOptions options, WUPSConfigAPI_MenuOpenedCallback openedCallback, WUPSConfigAPI_MenuClosedCallback closedCallback) {
|
||||
if (options.version != 1) {
|
||||
return std::nullopt;
|
||||
}
|
||||
PluginConfigData result(options.data.v1.name, openedCallback, closedCallback);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
WUPSConfigAPI_MenuOpenedCallback mOpenedCallback;
|
||||
WUPSConfigAPI_MenuClosedCallback mClosedCallback;
|
||||
};
|
@ -17,11 +17,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PluginConfigData.h"
|
||||
#include "PluginData.h"
|
||||
#include "PluginInformation.h"
|
||||
#include "PluginMetaInformation.h"
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <wups/config_api.h>
|
||||
|
||||
class PluginContainer {
|
||||
public:
|
||||
@ -43,12 +45,21 @@ public:
|
||||
return mPluginData;
|
||||
}
|
||||
|
||||
uint32_t getHandle() {
|
||||
uint32_t getHandle() const {
|
||||
return (uint32_t) this;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::optional<PluginConfigData> &getConfigData() const {
|
||||
return mPluginConfigData;
|
||||
}
|
||||
|
||||
void setConfigData(const PluginConfigData &pluginConfigData) {
|
||||
mPluginConfigData = pluginConfigData;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::unique_ptr<PluginMetaInformation> mMetaInformation;
|
||||
const std::unique_ptr<PluginInformation> mPluginInformation;
|
||||
const std::shared_ptr<PluginData> mPluginData;
|
||||
std::optional<PluginConfigData> mPluginConfigData;
|
||||
};
|
||||
|
@ -105,8 +105,8 @@ std::unique_ptr<PluginMetaInformation> PluginMetaInformationFactory::loadPlugin(
|
||||
} else if (key == "wups") {
|
||||
if (value == "0.7.1") {
|
||||
pluginInfo->setWUPSVersion(0, 7, 1);
|
||||
} else if (value == "0.7.2") {
|
||||
pluginInfo->setWUPSVersion(0, 7, 2);
|
||||
} else if (value == "0.8.0") {
|
||||
pluginInfo->setWUPSVersion(0, 8, 0);
|
||||
} else {
|
||||
error = PLUGIN_PARSE_ERROR_INCOMPATIBLE_VERSION;
|
||||
DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring plugin - Unsupported WUPS version: %s.", value.c_str());
|
||||
|
@ -1,762 +0,0 @@
|
||||
#include "ConfigUtils.h"
|
||||
|
||||
#include "../config/WUPSConfig.h"
|
||||
#include "../globals.h"
|
||||
#include "DrawUtils.h"
|
||||
#include "hooks.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <coreinit/screen.h>
|
||||
#include <gx2/display.h>
|
||||
#include <memory/mappedmemory.h>
|
||||
#include <padscore/kpad.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <vpad/input.h>
|
||||
|
||||
#define COLOR_BACKGROUND Color(238, 238, 238, 255)
|
||||
#define COLOR_TEXT Color(51, 51, 51, 255)
|
||||
#define COLOR_TEXT2 Color(72, 72, 72, 255)
|
||||
#define COLOR_DISABLED Color(255, 0, 0, 255)
|
||||
#define COLOR_BORDER Color(204, 204, 204, 255)
|
||||
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4FF)
|
||||
#define COLOR_WHITE Color(0xFFFFFFFF)
|
||||
#define COLOR_BLACK Color(0, 0, 0, 255)
|
||||
|
||||
struct ConfigDisplayItem {
|
||||
WUPSConfig *config{};
|
||||
std::string name;
|
||||
std::string author;
|
||||
std::string version;
|
||||
};
|
||||
|
||||
#define MAX_BUTTONS_ON_SCREEN 8
|
||||
|
||||
static uint32_t remapWiiMoteButtons(uint32_t buttons) {
|
||||
uint32_t conv_buttons = 0;
|
||||
|
||||
if (buttons & WPAD_BUTTON_LEFT)
|
||||
conv_buttons |= VPAD_BUTTON_LEFT;
|
||||
|
||||
if (buttons & WPAD_BUTTON_RIGHT)
|
||||
conv_buttons |= VPAD_BUTTON_RIGHT;
|
||||
|
||||
if (buttons & WPAD_BUTTON_DOWN)
|
||||
conv_buttons |= VPAD_BUTTON_DOWN;
|
||||
|
||||
if (buttons & WPAD_BUTTON_UP)
|
||||
conv_buttons |= VPAD_BUTTON_UP;
|
||||
|
||||
if (buttons & WPAD_BUTTON_PLUS)
|
||||
conv_buttons |= VPAD_BUTTON_PLUS;
|
||||
|
||||
if (buttons & WPAD_BUTTON_B)
|
||||
conv_buttons |= VPAD_BUTTON_B;
|
||||
|
||||
if (buttons & WPAD_BUTTON_A)
|
||||
conv_buttons |= VPAD_BUTTON_A;
|
||||
|
||||
if (buttons & WPAD_BUTTON_MINUS)
|
||||
conv_buttons |= VPAD_BUTTON_MINUS;
|
||||
|
||||
if (buttons & WPAD_BUTTON_HOME)
|
||||
conv_buttons |= VPAD_BUTTON_HOME;
|
||||
|
||||
return conv_buttons;
|
||||
}
|
||||
|
||||
static uint32_t remapClassicButtons(uint32_t buttons) {
|
||||
uint32_t conv_buttons = 0;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_LEFT)
|
||||
conv_buttons |= VPAD_BUTTON_LEFT;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_RIGHT)
|
||||
conv_buttons |= VPAD_BUTTON_RIGHT;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_DOWN)
|
||||
conv_buttons |= VPAD_BUTTON_DOWN;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_UP)
|
||||
conv_buttons |= VPAD_BUTTON_UP;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_PLUS)
|
||||
conv_buttons |= VPAD_BUTTON_PLUS;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_X)
|
||||
conv_buttons |= VPAD_BUTTON_X;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_Y)
|
||||
conv_buttons |= VPAD_BUTTON_Y;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_B)
|
||||
conv_buttons |= VPAD_BUTTON_B;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_A)
|
||||
conv_buttons |= VPAD_BUTTON_A;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_MINUS)
|
||||
conv_buttons |= VPAD_BUTTON_MINUS;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_HOME)
|
||||
conv_buttons |= VPAD_BUTTON_HOME;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_ZR)
|
||||
conv_buttons |= VPAD_BUTTON_ZR;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_ZL)
|
||||
conv_buttons |= VPAD_BUTTON_ZL;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_R)
|
||||
conv_buttons |= VPAD_BUTTON_R;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_L)
|
||||
conv_buttons |= VPAD_BUTTON_L;
|
||||
|
||||
return conv_buttons;
|
||||
}
|
||||
|
||||
void ConfigUtils::displayMenu() {
|
||||
renderBasicScreen("Loading configs...");
|
||||
|
||||
std::vector<ConfigDisplayItem> configs;
|
||||
for (auto &plugin : gLoadedPlugins) {
|
||||
ConfigDisplayItem cfg;
|
||||
cfg.name = plugin->getMetaInformation().getName();
|
||||
cfg.author = plugin->getMetaInformation().getAuthor();
|
||||
cfg.version = plugin->getMetaInformation().getVersion();
|
||||
|
||||
for (const auto &hook : plugin->getPluginInformation().getHookDataList()) {
|
||||
if (hook->getType() == WUPS_LOADER_HOOK_GET_CONFIG /*WUPS_LOADER_HOOK_GET_CONFIG*/) {
|
||||
if (hook->getFunctionPointer() == nullptr) {
|
||||
break;
|
||||
}
|
||||
auto *cur_config = reinterpret_cast<WUPSConfig *>(((WUPSConfigHandle(*)())((uint32_t *) hook->getFunctionPointer()))());
|
||||
if (cur_config == nullptr) {
|
||||
break;
|
||||
}
|
||||
cfg.config = cur_config;
|
||||
configs.push_back(cfg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigDisplayItem *currentConfig = nullptr;
|
||||
WUPSConfigCategory *currentCategory = nullptr;
|
||||
|
||||
uint32_t selectedConfig = 0;
|
||||
uint32_t selectedCat = 0;
|
||||
uint32_t selectedItem = 0;
|
||||
uint32_t start = 0;
|
||||
uint32_t end = MAX_BUTTONS_ON_SCREEN;
|
||||
if (configs.size() < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = configs.size();
|
||||
}
|
||||
|
||||
bool redraw = true;
|
||||
uint32_t buttonsTriggered;
|
||||
uint32_t buttonsReleased;
|
||||
|
||||
VPADStatus vpad_data{};
|
||||
VPADReadError vpad_error;
|
||||
KPADStatus kpad_data{};
|
||||
KPADError kpad_error;
|
||||
|
||||
int32_t prevSelectedItem = -1;
|
||||
bool isItemMovementAllowed = true;
|
||||
|
||||
while (true) {
|
||||
buttonsTriggered = 0;
|
||||
buttonsReleased = 0;
|
||||
|
||||
VPADRead(VPAD_CHAN_0, &vpad_data, 1, &vpad_error);
|
||||
if (vpad_error == VPAD_READ_SUCCESS) {
|
||||
buttonsTriggered = vpad_data.trigger;
|
||||
buttonsReleased = vpad_data.release;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (KPADReadEx((KPADChan) i, &kpad_data, 1, &kpad_error) > 0) {
|
||||
if (kpad_error == KPAD_ERROR_OK && kpad_data.extensionType != 0xFF) {
|
||||
if (kpad_data.extensionType == WPAD_EXT_CORE || kpad_data.extensionType == WPAD_EXT_NUNCHUK) {
|
||||
buttonsTriggered |= remapWiiMoteButtons(kpad_data.trigger);
|
||||
buttonsReleased |= remapWiiMoteButtons(kpad_data.release);
|
||||
} else {
|
||||
buttonsTriggered |= remapClassicButtons(kpad_data.classic.trigger);
|
||||
buttonsReleased |= remapClassicButtons(kpad_data.classic.release);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonsReleased & VPAD_BUTTON_HOME) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (configs.empty()) {
|
||||
renderBasicScreen("No configurable plugins loaded");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!currentConfig || !currentConfig->config) {
|
||||
if (buttonsTriggered & VPAD_BUTTON_DOWN) {
|
||||
if (selectedConfig < configs.size() - 1) {
|
||||
selectedCat = 0;
|
||||
selectedConfig++;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (buttonsTriggered & VPAD_BUTTON_UP) {
|
||||
if (selectedConfig > 0) {
|
||||
selectedCat = 0;
|
||||
selectedConfig--;
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_A) {
|
||||
currentConfig = &configs[selectedConfig];
|
||||
if (currentConfig == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
selectedItem = 0;
|
||||
start = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
|
||||
auto cats = currentConfig->config->getCategories();
|
||||
if (cats.size() < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = cats.size();
|
||||
}
|
||||
|
||||
redraw = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selectedConfig >= end) {
|
||||
end = selectedConfig + 1;
|
||||
start = end - MAX_BUTTONS_ON_SCREEN;
|
||||
} else if (selectedConfig < start) {
|
||||
start = selectedConfig;
|
||||
end = start + MAX_BUTTONS_ON_SCREEN;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
// draw buttons
|
||||
uint32_t index = 8 + 24 + 8 + 4;
|
||||
for (uint32_t i = start; i < end; i++) {
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
if (i == selectedConfig) {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16 * 2, index + 8 + 24, configs[i].name.c_str());
|
||||
uint32_t sz = DrawUtils::getTextWidth(configs[i].name.c_str());
|
||||
DrawUtils::setFontSize(12);
|
||||
DrawUtils::print(16 * 2 + sz + 4, index + 8 + 24, configs[i].author.c_str());
|
||||
DrawUtils::print(SCREEN_WIDTH - 16 * 2, index + 8 + 24, configs[i].version.c_str(), true);
|
||||
index += 42 + 8;
|
||||
}
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, "Wii U Plugin System Config Menu");
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, VERSION_FULL, true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true);
|
||||
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
if (end < configs.size()) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
|
||||
}
|
||||
if (start > 0) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
|
||||
}
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue044 Exit";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
redraw = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!currentCategory) {
|
||||
auto cats = currentConfig->config->getCategories();
|
||||
if (buttonsTriggered & VPAD_BUTTON_DOWN) {
|
||||
if (selectedCat < cats.size() - 1) {
|
||||
selectedItem = 0;
|
||||
prevSelectedItem = 0;
|
||||
selectedCat++;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (buttonsTriggered & VPAD_BUTTON_UP) {
|
||||
if (selectedCat > 0) {
|
||||
selectedItem = 0;
|
||||
prevSelectedItem = 0;
|
||||
selectedCat--;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (buttonsTriggered & VPAD_BUTTON_A) {
|
||||
if (!cats.empty() && selectedCat > cats.size() - 1) {
|
||||
selectedCat = 0;
|
||||
}
|
||||
currentCategory = cats[selectedCat];
|
||||
if (currentCategory == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("currentCategory was NULL");
|
||||
break;
|
||||
}
|
||||
|
||||
start = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
prevSelectedItem = -1;
|
||||
|
||||
auto items = currentCategory->getItems();
|
||||
if (items.size() < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = items.size();
|
||||
}
|
||||
|
||||
redraw = true;
|
||||
continue;
|
||||
} else if (buttonsTriggered & VPAD_BUTTON_B) {
|
||||
currentConfig = nullptr;
|
||||
currentCategory = nullptr;
|
||||
start = 0;
|
||||
selectedItem = 0;
|
||||
prevSelectedItem = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
if (configs.size() < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = configs.size();
|
||||
}
|
||||
redraw = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selectedCat >= end) {
|
||||
end = selectedCat + 1;
|
||||
start = end - MAX_BUTTONS_ON_SCREEN;
|
||||
} else if (selectedCat < start) {
|
||||
start = selectedCat;
|
||||
end = start + MAX_BUTTONS_ON_SCREEN;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
// draw buttons
|
||||
uint32_t index = 8 + 24 + 8 + 4;
|
||||
for (uint32_t i = start; i < end; i++) {
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
if (i == selectedCat) {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16 * 2, index + 8 + 24, cats[i]->getName().c_str());
|
||||
index += 42 + 8;
|
||||
}
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, StringTools::truncate(currentConfig->config->getName(), 45).c_str());
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, currentConfig->version.c_str(), true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true);
|
||||
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
if (end < cats.size()) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
|
||||
}
|
||||
if (start > 0) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
|
||||
}
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue001 Back";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
redraw = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::vector<WUPSConfigItem *> config_items = currentCategory->getItems();
|
||||
if (config_items.empty()) {
|
||||
if (buttonsTriggered & VPAD_BUTTON_B) {
|
||||
currentCategory = nullptr;
|
||||
start = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
auto catSize = currentConfig->config->getCategories().size();
|
||||
if (catSize < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = catSize;
|
||||
}
|
||||
redraw = true;
|
||||
continue;
|
||||
}
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
uint32_t sz = DrawUtils::getTextWidth("This category has no items");
|
||||
|
||||
DrawUtils::print((SCREEN_WIDTH / 2) - (sz / 2), (SCREEN_HEIGHT / 2), "This category has no items");
|
||||
|
||||
|
||||
auto headline = string_format("%s - %s", currentConfig->config->getName().c_str(), currentCategory->getName().c_str());
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, StringTools::truncate(headline, 45).c_str());
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, currentConfig->version.c_str(), true);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue001 Back";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isItemMovementAllowed) {
|
||||
if (buttonsTriggered & VPAD_BUTTON_DOWN) {
|
||||
if (selectedItem < config_items.size() - 1) {
|
||||
selectedItem++;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (buttonsTriggered & VPAD_BUTTON_UP) {
|
||||
if (selectedItem > 0) {
|
||||
selectedItem--;
|
||||
redraw = true;
|
||||
}
|
||||
} else if (buttonsTriggered & VPAD_BUTTON_B) {
|
||||
currentCategory = nullptr;
|
||||
start = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
auto catSize = currentConfig->config->getCategories().size();
|
||||
if (catSize < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = catSize;
|
||||
}
|
||||
redraw = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
WUPSConfigButtons pressedButtons = WUPS_CONFIG_BUTTON_NONE;
|
||||
if (buttonsTriggered & VPAD_BUTTON_A) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_A;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_LEFT) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_LEFT;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_RIGHT) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_RIGHT;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_L) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_L;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_R) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_R;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_ZL) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_ZL;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_ZR) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_ZR;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_X) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_Y;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_Y) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_X;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_STICK_L) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_STICK_L;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_STICK_R) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_STICK_R;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_PLUS) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_PLUS;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_MINUS) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_MINUS;
|
||||
}
|
||||
|
||||
if (!isItemMovementAllowed) {
|
||||
if (buttonsTriggered & VPAD_BUTTON_B) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_B;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_UP) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_UP;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_DOWN) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_UP;
|
||||
}
|
||||
}
|
||||
|
||||
if (pressedButtons != WUPS_CONFIG_BUTTON_NONE) {
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if (selectedItem >= end) {
|
||||
end = selectedItem + 1;
|
||||
start = selectedItem - MAX_BUTTONS_ON_SCREEN;
|
||||
} else if (selectedItem < start) {
|
||||
start = selectedItem;
|
||||
end = start + MAX_BUTTONS_ON_SCREEN;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
if (prevSelectedItem != (int32_t) selectedItem) {
|
||||
if (prevSelectedItem >= 0) {
|
||||
config_items[prevSelectedItem]->onSelected(false);
|
||||
}
|
||||
config_items[selectedItem]->onSelected(true);
|
||||
prevSelectedItem = (int32_t) selectedItem;
|
||||
}
|
||||
|
||||
if (pressedButtons != WUPS_CONFIG_BUTTON_NONE) {
|
||||
config_items[selectedItem]->onButtonPressed(pressedButtons);
|
||||
}
|
||||
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
// draw buttons
|
||||
uint32_t index = 8 + 24 + 8 + 4;
|
||||
for (uint32_t i = start; i < end; i++) {
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
if (i == selectedItem) {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16 * 2, index + 8 + 24, config_items[i]->getDisplayName().c_str());
|
||||
if (i == selectedItem) {
|
||||
DrawUtils::print(SCREEN_WIDTH - 16 * 2, index + 8 + 24, config_items[i]->getCurrentValueSelectedDisplay().c_str(), true);
|
||||
} else {
|
||||
DrawUtils::print(SCREEN_WIDTH - 16 * 2, index + 8 + 24, config_items[i]->getCurrentValueDisplay().c_str(), true);
|
||||
}
|
||||
index += 42 + 8;
|
||||
}
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
auto headline = string_format("%s - %s", currentConfig->config->getName().c_str(), currentCategory->getName().c_str());
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, StringTools::truncate(headline, 45).c_str());
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, currentConfig->version.c_str(), true);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 / \ue07e Toggle", true);
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
if (end < config_items.size()) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
|
||||
}
|
||||
if (start > 0) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
|
||||
}
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue001 Back";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
redraw = pressedButtons != WUPS_CONFIG_BUTTON_NONE;
|
||||
|
||||
isItemMovementAllowed = config_items[selectedItem]->isMovementAllowed();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &element : configs) {
|
||||
for (const auto &cat : element.config->getCategories()) {
|
||||
for (const auto &item : cat->getItems()) {
|
||||
if (item->isDirty()) {
|
||||
item->callCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_CONFIG_CLOSED);
|
||||
|
||||
for (const auto &element : configs) {
|
||||
delete element.config;
|
||||
}
|
||||
}
|
||||
|
||||
#define __SetDCPitchReg ((void (*)(uint32_t, uint32_t))(0x101C400 + 0x1e714))
|
||||
|
||||
void ConfigUtils::openConfigMenu() {
|
||||
bool wasHomeButtonMenuEnabled = OSIsHomeButtonMenuEnabled();
|
||||
|
||||
OSScreenInit();
|
||||
|
||||
uint32_t screen_buf0_size = OSScreenGetBufferSizeEx(SCREEN_TV);
|
||||
uint32_t screen_buf1_size = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
||||
void *screenbuffer0 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf0_size, 0x100);
|
||||
void *screenbuffer1 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf1_size, 0x100);
|
||||
|
||||
// Fix the TV buffer pitch if a 1080p buffer is used.
|
||||
if (screen_buf0_size == 0x00FD2000) {
|
||||
__SetDCPitchReg(SCREEN_TV, 1920);
|
||||
}
|
||||
|
||||
bool skipScreen0Free = false;
|
||||
bool skipScreen1Free = false;
|
||||
|
||||
if (!screenbuffer0 || !screenbuffer1) {
|
||||
if (screenbuffer0 == nullptr) {
|
||||
if (gStoredTVBuffer.buffer_size >= screen_buf0_size) {
|
||||
screenbuffer0 = gStoredTVBuffer.buffer;
|
||||
skipScreen0Free = true;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Use storedTVBuffer");
|
||||
}
|
||||
}
|
||||
if (screenbuffer1 == nullptr) {
|
||||
if (gStoredDRCBuffer.buffer_size >= screen_buf1_size) {
|
||||
screenbuffer1 = gStoredDRCBuffer.buffer;
|
||||
skipScreen1Free = true;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Use storedDRCBuffer");
|
||||
}
|
||||
}
|
||||
if (!screenbuffer0 || !screenbuffer1) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc buffers");
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
|
||||
OSScreenSetBufferEx(SCREEN_TV, screenbuffer0);
|
||||
OSScreenSetBufferEx(SCREEN_DRC, screenbuffer1);
|
||||
|
||||
OSScreenEnableEx(SCREEN_TV, 1);
|
||||
OSScreenEnableEx(SCREEN_DRC, 1);
|
||||
|
||||
// Clear screens
|
||||
OSScreenClearBufferEx(SCREEN_TV, 0);
|
||||
OSScreenClearBufferEx(SCREEN_DRC, 0);
|
||||
|
||||
// Flip buffers
|
||||
OSScreenFlipBuffersEx(SCREEN_TV);
|
||||
OSScreenFlipBuffersEx(SCREEN_DRC);
|
||||
|
||||
DrawUtils::initBuffers(screenbuffer0, screen_buf0_size, screenbuffer1, screen_buf1_size);
|
||||
if (!DrawUtils::initFont()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to init Font");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// disable the home button menu to prevent opening it when exiting
|
||||
OSEnableHomeButtonMenu(false);
|
||||
|
||||
displayMenu();
|
||||
|
||||
OSEnableHomeButtonMenu(wasHomeButtonMenuEnabled);
|
||||
|
||||
DrawUtils::deinitFont();
|
||||
|
||||
error_exit:
|
||||
|
||||
if (gStoredTVBuffer.buffer != nullptr) {
|
||||
GX2SetTVBuffer(gStoredTVBuffer.buffer, gStoredTVBuffer.buffer_size, static_cast<GX2TVRenderMode>(gStoredTVBuffer.mode),
|
||||
gStoredTVBuffer.surface_format, gStoredTVBuffer.buffering_mode);
|
||||
}
|
||||
|
||||
if (gStoredDRCBuffer.buffer != nullptr) {
|
||||
GX2SetDRCBuffer(gStoredDRCBuffer.buffer, gStoredDRCBuffer.buffer_size, static_cast<GX2DrcRenderMode>(gStoredDRCBuffer.mode),
|
||||
gStoredDRCBuffer.surface_format, gStoredDRCBuffer.buffering_mode);
|
||||
}
|
||||
if (!skipScreen0Free && screenbuffer0) {
|
||||
MEMFreeToMappedMemory(screenbuffer0);
|
||||
}
|
||||
|
||||
if (!skipScreen1Free && screenbuffer1) {
|
||||
MEMFreeToMappedMemory(screenbuffer1);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigUtils::renderBasicScreen(std::string_view text) {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, "Wii U Plugin System Config Menu");
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, VERSION_FULL, true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true);
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
uint32_t sz = DrawUtils::getTextWidth(text.data());
|
||||
|
||||
DrawUtils::print((SCREEN_WIDTH / 2) - (sz / 2), (SCREEN_HEIGHT / 2), text.data());
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue044 Exit";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gx2/enum.h>
|
||||
#include <string>
|
||||
|
||||
struct StoredBuffer {
|
||||
void *buffer;
|
||||
uint32_t buffer_size;
|
||||
uint32_t mode;
|
||||
GX2SurfaceFormat surface_format;
|
||||
GX2BufferingMode buffering_mode;
|
||||
};
|
||||
|
||||
class ConfigUtils {
|
||||
public:
|
||||
static void openConfigMenu();
|
||||
|
||||
private:
|
||||
static void displayMenu();
|
||||
static void renderBasicScreen(std::string_view text);
|
||||
};
|
221
source/utils/config/CategoryRenderer.cpp
Normal file
221
source/utils/config/CategoryRenderer.cpp
Normal file
@ -0,0 +1,221 @@
|
||||
#include "CategoryRenderer.h"
|
||||
#include "ConfigDefines.h"
|
||||
#include "config/WUPSConfigCategory.h"
|
||||
#include "utils/input/Input.h"
|
||||
#include "utils/utils.h"
|
||||
#include <vector>
|
||||
#include <wups/config.h>
|
||||
|
||||
CategoryRenderer::CategoryRenderer(const GeneralConfigInformation *info, const WUPSConfigAPIBackend::WUPSConfigCategory *cat, bool isRoot)
|
||||
: mInfo(info), mCat(cat), mIsRoot(isRoot) {
|
||||
for (uint32_t i = 0; i < cat->getCategories().size() + cat->getItems().size(); i++) {
|
||||
if (i < cat->getCategories().size()) {
|
||||
auto item = make_unique_nothrow<ConfigRendererItemCategory>(cat->getCategories()[i].get());
|
||||
if (!item) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc ConfigRendererItemCategory");
|
||||
OSFatal("WiiUPluginBackend::CategoryRenderer::CategoryRenderer() Failed to alloc ConfigRendererItemCategory");
|
||||
}
|
||||
mItemRenderer.push_back(std::move(item));
|
||||
} else {
|
||||
auto itemIndex = (int32_t) (i - cat->getCategories().size());
|
||||
if (itemIndex < 0 || itemIndex >= (int32_t) cat->getItems().size()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("unexpected index");
|
||||
OSFatal("WiiUPluginBackend::CategoryRenderer::CategoryRenderer() unexpected index");
|
||||
}
|
||||
auto item = make_unique_nothrow<ConfigRendererItem>(cat->getItems()[itemIndex].get());
|
||||
if (!item) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc ConfigRendererItemCategory");
|
||||
OSFatal("WiiUPluginBackend::CategoryRenderer::CategoryRenderer() Failed to alloc ConfigRendererItem");
|
||||
}
|
||||
mItemRenderer.push_back(std::move(item));
|
||||
}
|
||||
}
|
||||
|
||||
mCursorPos = 0;
|
||||
if (!mItemRenderer.empty()) {
|
||||
mItemRenderer[mCursorPos]->SetIsSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
CategoryRenderer::~CategoryRenderer() {
|
||||
if (mCursorPos < (int32_t) mItemRenderer.size()) {
|
||||
mItemRenderer[mCursorPos]->SetIsSelected(false);
|
||||
}
|
||||
}
|
||||
|
||||
ConfigSubState CategoryRenderer::Update(Input &input, const WUPSConfigSimplePadData &simpleInputData, const WUPSConfigComplexPadData &complexInputData) {
|
||||
switch (mState) {
|
||||
case STATE_MAIN: {
|
||||
auto res = UpdateStateMain(input, simpleInputData, complexInputData);
|
||||
mFirstFrame = false;
|
||||
return res;
|
||||
}
|
||||
case STATE_SUB: {
|
||||
if (mSubCategoryRenderer) {
|
||||
auto subResult = mSubCategoryRenderer->Update(input, simpleInputData, complexInputData);
|
||||
if (subResult != SUB_STATE_RUNNING) {
|
||||
mState = STATE_MAIN;
|
||||
mFirstFrame = true;
|
||||
return SUB_STATE_RUNNING;
|
||||
}
|
||||
return SUB_STATE_RUNNING;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_WARN("State is RENDERER_STATE_CAT but mCategoryRenderer is null. Resetting state.");
|
||||
mState = STATE_MAIN;
|
||||
mCursorPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SUB_STATE_ERROR;
|
||||
}
|
||||
|
||||
ConfigSubState CategoryRenderer::UpdateStateMain(Input &input, const WUPSConfigSimplePadData &simpleInputData, const WUPSConfigComplexPadData &complexInputData) {
|
||||
if (mIsItemMovementAllowed && input.data.buttons_d & Input::eButtons::BUTTON_B) {
|
||||
return SUB_STATE_RETURN;
|
||||
}
|
||||
if (mItemRenderer.empty()) {
|
||||
return SUB_STATE_RUNNING;
|
||||
}
|
||||
|
||||
auto totalElementSize = mItemRenderer.size();
|
||||
int32_t prevSelectedItem = mCursorPos;
|
||||
|
||||
if (mIsItemMovementAllowed) {
|
||||
if (input.data.buttons_d & Input::eButtons::BUTTON_DOWN) {
|
||||
mCursorPos++;
|
||||
} else if (input.data.buttons_d & Input::eButtons::BUTTON_UP) {
|
||||
mCursorPos--;
|
||||
} else if (input.data.buttons_d & Input::eButtons::BUTTON_A) {
|
||||
if (mCursorPos < (int32_t) mCat->getCategories().size()) {
|
||||
if (mCurrentOpen != mCursorPos) {
|
||||
mSubCategoryRenderer.reset();
|
||||
mSubCategoryRenderer = make_unique_nothrow<CategoryRenderer>(mInfo, mCat->getCategories()[mCursorPos].get(), false);
|
||||
}
|
||||
mCurrentOpen = mCursorPos;
|
||||
mState = STATE_SUB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mCursorPos < 0) {
|
||||
mCursorPos = (int32_t) totalElementSize - 1;
|
||||
} else if (mCursorPos > (int32_t) (totalElementSize - 1)) {
|
||||
mCursorPos = 0;
|
||||
}
|
||||
|
||||
// Adjust the render offset when reaching the boundaries
|
||||
if (mCursorPos < mRenderOffset) {
|
||||
mRenderOffset = mCursorPos;
|
||||
} else if (mCursorPos >= mRenderOffset + MAX_BUTTONS_ON_SCREEN - 1) {
|
||||
mRenderOffset = mCursorPos - MAX_BUTTONS_ON_SCREEN + 1;
|
||||
}
|
||||
|
||||
bool posJustChanged = false;
|
||||
if (prevSelectedItem != mCursorPos) {
|
||||
mItemRenderer[prevSelectedItem]->SetIsSelected(false);
|
||||
mItemRenderer[mCursorPos]->SetIsSelected(true);
|
||||
posJustChanged = true;
|
||||
}
|
||||
|
||||
if (!posJustChanged && !mFirstFrame) {
|
||||
// WUPSConfigItemV2
|
||||
mItemRenderer[mCursorPos]->OnInput(simpleInputData);
|
||||
mItemRenderer[mCursorPos]->OnInputEx(complexInputData);
|
||||
|
||||
// WUPSConfigItemV1
|
||||
if (input.data.buttons_d != 0) {
|
||||
WUPSConfigButtons buttons = input.data.buttons_d;
|
||||
buttons = ConfigUtils::convertInputs(buttons);
|
||||
if (!mIsItemMovementAllowed) {
|
||||
buttons &= ~MOVE_ITEM_INPUT_MASK;
|
||||
}
|
||||
mItemRenderer[mCursorPos]->OnButtonPressed(buttons);
|
||||
}
|
||||
}
|
||||
|
||||
mIsItemMovementAllowed = mItemRenderer[mCursorPos]->IsMovementAllowed();
|
||||
|
||||
return SUB_STATE_RUNNING;
|
||||
}
|
||||
|
||||
void CategoryRenderer::Render() const {
|
||||
switch (mState) {
|
||||
case STATE_MAIN:
|
||||
RenderStateMain();
|
||||
break;
|
||||
case STATE_SUB: {
|
||||
if (mSubCategoryRenderer) {
|
||||
mSubCategoryRenderer->Render();
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_WARN("STATE_SUB but mSubCategoryRenderer is NULL");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CategoryRenderer::RenderStateMain() const {
|
||||
if (mItemRenderer.empty()) {
|
||||
DrawUtils::beginDraw();
|
||||
RenderMainLayout();
|
||||
|
||||
std::string text(mIsRoot ? "This plugin can not be configured" : "This category is empty");
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
uint32_t sz = DrawUtils::getTextWidth(text.c_str());
|
||||
DrawUtils::print((SCREEN_WIDTH / 2) - (sz / 2), (SCREEN_HEIGHT / 2), text.c_str());
|
||||
|
||||
DrawUtils::endDraw();
|
||||
return;
|
||||
}
|
||||
auto totalElementSize = static_cast<int>(mItemRenderer.size());
|
||||
|
||||
// Calculate the range of items to display
|
||||
int start = std::max(0, mRenderOffset);
|
||||
int end = std::min(start + MAX_BUTTONS_ON_SCREEN, totalElementSize);
|
||||
|
||||
DrawUtils::beginDraw();
|
||||
|
||||
RenderMainLayout();
|
||||
|
||||
uint32_t yOffset = 8 + 24 + 8 + 4;
|
||||
for (int32_t i = start; i < end; i++) {
|
||||
bool isHighlighted = (i == mCursorPos);
|
||||
mItemRenderer[i]->Draw(yOffset, isHighlighted);
|
||||
yOffset += 42 + 8;
|
||||
}
|
||||
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
if (end < totalElementSize) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
|
||||
}
|
||||
if (start > 0) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
|
||||
}
|
||||
|
||||
DrawUtils::endDraw();
|
||||
}
|
||||
|
||||
void CategoryRenderer::RenderMainLayout() const {
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, StringTools::truncate(mInfo->name, 45).c_str());
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, mInfo->version.c_str(), true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true);
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue001 Back";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
}
|
46
source/utils/config/CategoryRenderer.h
Normal file
46
source/utils/config/CategoryRenderer.h
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
#include "../DrawUtils.h"
|
||||
#include "ConfigRendererItem.h"
|
||||
#include "ConfigRendererItemCategory.h"
|
||||
#include "ConfigRendererItemGeneric.h"
|
||||
#include "ConfigUtils.h"
|
||||
#include "config/WUPSConfigCategory.h"
|
||||
#include "utils/input/Input.h"
|
||||
#include <memory>
|
||||
|
||||
class CategoryRenderer {
|
||||
|
||||
public:
|
||||
explicit CategoryRenderer(const GeneralConfigInformation *info, const WUPSConfigAPIBackend::WUPSConfigCategory *cat, bool isRoot);
|
||||
|
||||
~CategoryRenderer();
|
||||
|
||||
ConfigSubState Update(Input &input, const WUPSConfigSimplePadData &simpleInputData, const WUPSConfigComplexPadData &complexInputData);
|
||||
|
||||
void Render() const;
|
||||
|
||||
private:
|
||||
ConfigSubState UpdateStateMain(Input &input, const WUPSConfigSimplePadData &simpleInputData, const WUPSConfigComplexPadData &complexInputData);
|
||||
|
||||
void RenderStateMain() const;
|
||||
|
||||
void RenderMainLayout() const;
|
||||
|
||||
enum State {
|
||||
STATE_MAIN = 0,
|
||||
STATE_SUB = 1,
|
||||
};
|
||||
|
||||
State mState = STATE_MAIN;
|
||||
int32_t mCurrentOpen = -1;
|
||||
int32_t mCursorPos = 0;
|
||||
int32_t mRenderOffset = 0;
|
||||
std::unique_ptr<CategoryRenderer> mSubCategoryRenderer = {};
|
||||
const GeneralConfigInformation *mInfo = {};
|
||||
const WUPSConfigAPIBackend::WUPSConfigCategory *mCat = {};
|
||||
|
||||
std::vector<std::unique_ptr<ConfigRendererItemGeneric>> mItemRenderer = {};
|
||||
bool mIsItemMovementAllowed = true;
|
||||
bool mFirstFrame = true;
|
||||
bool mIsRoot = false;
|
||||
};
|
31
source/utils/config/ConfigDefines.h
Normal file
31
source/utils/config/ConfigDefines.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <gx2/surface.h>
|
||||
#include <string>
|
||||
|
||||
#define COLOR_BACKGROUND Color(238, 238, 238, 255)
|
||||
#define COLOR_TEXT Color(51, 51, 51, 255)
|
||||
#define COLOR_TEXT2 Color(72, 72, 72, 255)
|
||||
#define COLOR_DISABLED Color(255, 0, 0, 255)
|
||||
#define COLOR_BORDER Color(204, 204, 204, 255)
|
||||
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4FF)
|
||||
#define COLOR_WHITE Color(0xFFFFFFFF)
|
||||
#define COLOR_BLACK Color(0, 0, 0, 255)
|
||||
|
||||
#define MAX_BUTTONS_ON_SCREEN 8
|
||||
|
||||
struct StoredBuffer {
|
||||
void *buffer;
|
||||
uint32_t buffer_size;
|
||||
uint32_t mode;
|
||||
GX2SurfaceFormat surface_format;
|
||||
GX2BufferingMode buffering_mode;
|
||||
};
|
||||
|
||||
|
||||
enum ConfigSubState {
|
||||
SUB_STATE_RUNNING = 0,
|
||||
SUB_STATE_RETURN = 1,
|
||||
SUB_STATE_ERROR = 2,
|
||||
};
|
26
source/utils/config/ConfigDisplayItem.h
Normal file
26
source/utils/config/ConfigDisplayItem.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include "config/WUPSConfig.h"
|
||||
#include <memory>
|
||||
|
||||
struct GeneralConfigInformation {
|
||||
std::string name;
|
||||
std::string author;
|
||||
std::string version;
|
||||
};
|
||||
|
||||
class ConfigDisplayItem {
|
||||
public:
|
||||
ConfigDisplayItem(GeneralConfigInformation &info, std::unique_ptr<WUPSConfigAPIBackend::WUPSConfig> config) : mConfig(std::move(config)), mInfo(std::move(info)) {
|
||||
assert(mConfig);
|
||||
}
|
||||
[[nodiscard]] const GeneralConfigInformation &getConfigInformation() const {
|
||||
return mInfo;
|
||||
}
|
||||
[[nodiscard]] const WUPSConfigAPIBackend::WUPSConfig &getConfig() const {
|
||||
return *mConfig;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<WUPSConfigAPIBackend::WUPSConfig> mConfig;
|
||||
GeneralConfigInformation mInfo;
|
||||
};
|
154
source/utils/config/ConfigRenderer.cpp
Normal file
154
source/utils/config/ConfigRenderer.cpp
Normal file
@ -0,0 +1,154 @@
|
||||
#include "ConfigRenderer.h"
|
||||
|
||||
void ConfigRenderer::RenderStateMain() const {
|
||||
auto totalElementSize = (int32_t) mConfigs.size();
|
||||
// Calculate the range of items to display
|
||||
int start = std::max(0, mRenderOffset);
|
||||
int end = std::min(start + MAX_BUTTONS_ON_SCREEN, totalElementSize);
|
||||
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
uint32_t yOffset = 8 + 24 + 8 + 4;
|
||||
for (int32_t i = start; i < end; i++) {
|
||||
drawConfigEntry(yOffset, mConfigs[i].getConfigInformation(), i == mCursorPos);
|
||||
yOffset += 42 + 8;
|
||||
}
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, "Wii U Plugin System Config Menu");
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, VERSION_FULL, true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true);
|
||||
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
if (end < totalElementSize) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
|
||||
}
|
||||
if (start > 0) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
|
||||
}
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue044 Exit";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
}
|
||||
|
||||
void ConfigRenderer::drawConfigEntry(uint32_t yOffset, const GeneralConfigInformation &configInformation, bool isHighlighted) const {
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
if (isHighlighted) {
|
||||
DrawUtils::drawRect(16, yOffset, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, yOffset, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16 * 2, yOffset + 8 + 24, configInformation.name.c_str());
|
||||
uint32_t sz = DrawUtils::getTextWidth(configInformation.name.c_str());
|
||||
DrawUtils::setFontSize(12);
|
||||
DrawUtils::print(16 * 2 + sz + 4, yOffset + 8 + 24, configInformation.author.c_str());
|
||||
DrawUtils::print(SCREEN_WIDTH - 16 * 2, yOffset + 8 + 24, configInformation.version.c_str(), true);
|
||||
}
|
||||
|
||||
ConfigSubState ConfigRenderer::UpdateStateMain(const Input &input) {
|
||||
if (mConfigs.empty()) {
|
||||
return SUB_STATE_ERROR;
|
||||
}
|
||||
auto totalElementSize = mConfigs.size();
|
||||
if (input.data.buttons_d & Input::eButtons::BUTTON_DOWN) {
|
||||
mCursorPos++;
|
||||
} else if (input.data.buttons_d & Input::eButtons::BUTTON_UP) {
|
||||
mCursorPos--;
|
||||
} else if (input.data.buttons_d & Input::eButtons::BUTTON_A) {
|
||||
if (mCursorPos != mCurrentOpen) {
|
||||
mCategoryRenderer.reset();
|
||||
mCategoryRenderer = make_unique_nothrow<CategoryRenderer>(&(mConfigs[mCursorPos].getConfigInformation()), &(mConfigs[mCursorPos].getConfig()), true);
|
||||
}
|
||||
mCurrentOpen = mCursorPos;
|
||||
mState = STATE_SUB;
|
||||
return SUB_STATE_RUNNING;
|
||||
} else if (input.data.buttons_d & (Input::eButtons::BUTTON_B | Input::eButtons::BUTTON_HOME)) {
|
||||
mCategoryRenderer.reset();
|
||||
for (const auto &element : mConfigs) {
|
||||
CallOnCloseCallback(element.getConfigInformation(), element.getConfig().getCategories());
|
||||
}
|
||||
return SUB_STATE_RETURN;
|
||||
}
|
||||
|
||||
if (mCursorPos < 0) {
|
||||
mCursorPos = (int32_t) totalElementSize - 1;
|
||||
} else if (mCursorPos > (int32_t) (totalElementSize - 1)) {
|
||||
mCursorPos = 0;
|
||||
}
|
||||
|
||||
// Adjust the render offset when reaching the boundaries
|
||||
if (mCursorPos < mRenderOffset) {
|
||||
mRenderOffset = mCursorPos;
|
||||
} else if (mCursorPos >= mRenderOffset + MAX_BUTTONS_ON_SCREEN - 1) {
|
||||
mRenderOffset = mCursorPos - MAX_BUTTONS_ON_SCREEN + 1;
|
||||
}
|
||||
return SUB_STATE_RUNNING;
|
||||
}
|
||||
|
||||
void ConfigRenderer::Render() const {
|
||||
switch (mState) {
|
||||
case STATE_MAIN:
|
||||
RenderStateMain();
|
||||
break;
|
||||
case STATE_SUB: {
|
||||
if (mCategoryRenderer) {
|
||||
mCategoryRenderer->Render();
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_WARN("render failed: state was RENDERER_STATE_CAT but mCategoryRenderer is NULL");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigSubState ConfigRenderer::Update(Input &input, const WUPSConfigSimplePadData &simpleInputData, const WUPSConfigComplexPadData &complexInputData) {
|
||||
switch (mState) {
|
||||
case STATE_MAIN:
|
||||
return UpdateStateMain(input);
|
||||
case STATE_SUB: {
|
||||
if (mCategoryRenderer) {
|
||||
auto subResult = mCategoryRenderer->Update(input, simpleInputData, complexInputData);
|
||||
if (subResult != SUB_STATE_RUNNING) {
|
||||
mState = STATE_MAIN;
|
||||
return SUB_STATE_RUNNING;
|
||||
}
|
||||
return SUB_STATE_RUNNING;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_WARN("State is RENDERER_STATE_CAT but mCategoryRenderer is null. Resetting state.");
|
||||
mState = STATE_MAIN;
|
||||
mCursorPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SUB_STATE_ERROR;
|
||||
}
|
||||
|
||||
void ConfigRenderer::CallOnCloseCallback(const GeneralConfigInformation &info, const std::vector<std::unique_ptr<WUPSConfigAPIBackend::WUPSConfigCategory>> &categories) {
|
||||
for (const auto &cat : categories) {
|
||||
if (!cat->getCategories().empty()) {
|
||||
CallOnCloseCallback(info, cat->getCategories());
|
||||
}
|
||||
for (const auto &item : cat->getItems()) {
|
||||
item->onCloseCallback();
|
||||
}
|
||||
}
|
||||
}
|
42
source/utils/config/ConfigRenderer.h
Normal file
42
source/utils/config/ConfigRenderer.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include "../DrawUtils.h"
|
||||
#include "../input/Input.h"
|
||||
#include "../logger.h"
|
||||
#include "CategoryRenderer.h"
|
||||
#include "globals.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class ConfigRenderer {
|
||||
|
||||
public:
|
||||
explicit ConfigRenderer(std::vector<ConfigDisplayItem> &&vec) : mConfigs(std::move(vec)) {
|
||||
}
|
||||
~ConfigRenderer() = default;
|
||||
|
||||
ConfigSubState Update(Input &input, const WUPSConfigSimplePadData &simpleInputData, const WUPSConfigComplexPadData &complexInputData);
|
||||
|
||||
void Render() const;
|
||||
|
||||
private:
|
||||
ConfigSubState UpdateStateMain(const Input &input);
|
||||
|
||||
void RenderStateMain() const;
|
||||
|
||||
void drawConfigEntry(uint32_t yOffset, const GeneralConfigInformation &configInformation, bool isHighlighted) const;
|
||||
|
||||
enum State {
|
||||
STATE_MAIN = 0,
|
||||
STATE_SUB = 1,
|
||||
};
|
||||
|
||||
std::vector<ConfigDisplayItem> mConfigs;
|
||||
std::unique_ptr<CategoryRenderer> mCategoryRenderer = {};
|
||||
|
||||
State mState = STATE_MAIN;
|
||||
|
||||
int32_t mCursorPos = 0;
|
||||
int32_t mRenderOffset = 0;
|
||||
int32_t mCurrentOpen = -1;
|
||||
void CallOnCloseCallback(const GeneralConfigInformation &info, const std::vector<std::unique_ptr<WUPSConfigAPIBackend::WUPSConfigCategory>> &categories);
|
||||
};
|
43
source/utils/config/ConfigRendererItem.h
Normal file
43
source/utils/config/ConfigRendererItem.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include "ConfigRendererItemGeneric.h"
|
||||
#include "config/WUPSConfigItem.h"
|
||||
|
||||
class ConfigRendererItem : public ConfigRendererItemGeneric {
|
||||
public:
|
||||
explicit ConfigRendererItem(const WUPSConfigAPIBackend::WUPSConfigItem *item) : mItem(item) {
|
||||
assert(item);
|
||||
}
|
||||
|
||||
void Draw(uint32_t yOffset, bool isHighlighted) const override {
|
||||
assert(mItem);
|
||||
drawGenericBoxAndText(yOffset, mItem->getDisplayName(), isHighlighted);
|
||||
DrawUtils::setFontSize(24);
|
||||
if (isHighlighted) {
|
||||
DrawUtils::print(SCREEN_WIDTH - 16 * 2, yOffset + 8 + 24, mItem->getCurrentValueSelectedDisplay().c_str(), true);
|
||||
} else {
|
||||
DrawUtils::print(SCREEN_WIDTH - 16 * 2, yOffset + 8 + 24, mItem->getCurrentValueDisplay().c_str(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void SetIsSelected(bool isSelected) override {
|
||||
mItem->onSelected(isSelected);
|
||||
}
|
||||
|
||||
void OnButtonPressed(WUPSConfigButtons buttons) override {
|
||||
mItem->onButtonPressed(buttons);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsMovementAllowed() const override {
|
||||
return mItem->isMovementAllowed();
|
||||
}
|
||||
|
||||
void OnInput(WUPSConfigSimplePadData input) override {
|
||||
mItem->onInput(input);
|
||||
}
|
||||
void OnInputEx(WUPSConfigComplexPadData input) override {
|
||||
mItem->onInputEx(input);
|
||||
}
|
||||
|
||||
private:
|
||||
const WUPSConfigAPIBackend::WUPSConfigItem *mItem;
|
||||
};
|
17
source/utils/config/ConfigRendererItemCategory.h
Normal file
17
source/utils/config/ConfigRendererItemCategory.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "ConfigRendererItemGeneric.h"
|
||||
#include "config/WUPSConfigCategory.h"
|
||||
|
||||
class ConfigRendererItemCategory : public ConfigRendererItemGeneric {
|
||||
public:
|
||||
explicit ConfigRendererItemCategory(const WUPSConfigAPIBackend::WUPSConfigCategory *category) : mCategory(category) {
|
||||
assert(category);
|
||||
}
|
||||
|
||||
void Draw(uint32_t yOffset, bool isHighlighted) const override {
|
||||
drawGenericBoxAndText(yOffset, mCategory->getName(), isHighlighted);
|
||||
}
|
||||
|
||||
private:
|
||||
const WUPSConfigAPIBackend::WUPSConfigCategory *mCategory;
|
||||
};
|
36
source/utils/config/ConfigRendererItemGeneric.h
Normal file
36
source/utils/config/ConfigRendererItemGeneric.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include "../DrawUtils.h"
|
||||
#include "ConfigDefines.h"
|
||||
#include <wups/config.h>
|
||||
|
||||
class ConfigRendererItemGeneric {
|
||||
public:
|
||||
virtual ~ConfigRendererItemGeneric() = default;
|
||||
virtual void drawGenericBoxAndText(uint32_t yOffset, const std::string &displayName, bool isHighlighted) const {
|
||||
if (isHighlighted) {
|
||||
DrawUtils::drawRect(16, yOffset, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, yOffset, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
DrawUtils::print(16 * 2, yOffset + 8 + 24, displayName.c_str());
|
||||
}
|
||||
|
||||
virtual void Draw(uint32_t yOffset, bool isHighlighted) const = 0;
|
||||
|
||||
virtual void SetIsSelected(bool) {
|
||||
}
|
||||
|
||||
virtual void OnButtonPressed(WUPSConfigButtons) {
|
||||
}
|
||||
virtual void OnInput(WUPSConfigSimplePadData) {
|
||||
}
|
||||
virtual void OnInputEx(WUPSConfigComplexPadData) {
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual bool IsMovementAllowed() const {
|
||||
return true;
|
||||
}
|
||||
};
|
308
source/utils/config/ConfigUtils.cpp
Normal file
308
source/utils/config/ConfigUtils.cpp
Normal file
@ -0,0 +1,308 @@
|
||||
#include "ConfigUtils.h"
|
||||
#include "../../globals.h"
|
||||
#include "../DrawUtils.h"
|
||||
#include "../logger.h"
|
||||
#include "ConfigRenderer.h"
|
||||
#include "config/WUPSConfigAPI.h"
|
||||
#include "hooks.h"
|
||||
#include "utils/input/CombinedInput.h"
|
||||
#include "utils/input/VPADInput.h"
|
||||
#include "utils/input/WPADInput.h"
|
||||
|
||||
#include <coreinit/screen.h>
|
||||
#include <gx2/display.h>
|
||||
#include <memory/mappedmemory.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
WUPS_CONFIG_SIMPLE_INPUT ConfigUtils::convertInputs(uint32_t buttons) {
|
||||
WUPSConfigButtons pressedButtons = WUPS_CONFIG_BUTTON_NONE;
|
||||
if (buttons & Input::eButtons::BUTTON_A) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_A;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_LEFT) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_LEFT;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_RIGHT) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_RIGHT;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_L) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_L;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_R) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_R;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_ZL) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_ZL;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_ZR) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_ZR;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_X) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_X;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_Y) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_Y;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_STICK_L) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_STICK_L;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_STICK_R) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_STICK_R;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_PLUS) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_PLUS;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_MINUS) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_MINUS;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_B) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_B;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_UP) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_UP;
|
||||
}
|
||||
if (buttons & Input::eButtons::BUTTON_DOWN) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_DOWN;
|
||||
}
|
||||
return (WUPS_CONFIG_SIMPLE_INPUT) pressedButtons;
|
||||
}
|
||||
|
||||
void ConfigUtils::displayMenu() {
|
||||
renderBasicScreen("Loading configs...");
|
||||
|
||||
std::vector<ConfigDisplayItem> configs;
|
||||
for (auto &plugin : gLoadedPlugins) {
|
||||
GeneralConfigInformation info;
|
||||
info.name = plugin->getMetaInformation().getName();
|
||||
info.author = plugin->getMetaInformation().getAuthor();
|
||||
info.version = plugin->getMetaInformation().getVersion();
|
||||
|
||||
std::unique_ptr<WUPSConfigAPIBackend::WUPSConfig> config;
|
||||
auto configData = plugin->getConfigData();
|
||||
if (configData) {
|
||||
auto configHandleOpt = configData->createConfig();
|
||||
if (configHandleOpt) {
|
||||
WUPSConfigAPIStatus callbackResult = configData->CallMenuOpenendCallback(configHandleOpt.value());
|
||||
config = WUPSConfigAPIBackend::Intern::PopConfigByHandle(configHandleOpt.value());
|
||||
if (!config) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get config for handle: %08X", configHandleOpt.value().handle);
|
||||
} else if (callbackResult != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Callback failed for %s: %s", info.name.c_str(), WUPSConfigAPI_GetStatusStr(callbackResult));
|
||||
config.reset();
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to create config for plugin: \"%s\"", info.name.c_str());
|
||||
}
|
||||
} else {
|
||||
for (const auto &hook : plugin->getPluginInformation().getHookDataList()) {
|
||||
if (hook->getType() == WUPS_LOADER_HOOK_GET_CONFIG_DEPRECATED) {
|
||||
if (hook->getFunctionPointer() == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Hook had invalid ptr");
|
||||
break;
|
||||
}
|
||||
auto cur_config_handle = ((void *(*) ())((uint32_t *) hook->getFunctionPointer()))();
|
||||
if (cur_config_handle == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Hook returned empty handle");
|
||||
break;
|
||||
}
|
||||
config = WUPSConfigAPIBackend::Intern::PopConfigByHandle(WUPSConfigHandle(cur_config_handle));
|
||||
if (!config) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to find config for handle: %08X", cur_config_handle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!config) {
|
||||
config = make_unique_nothrow<WUPSConfigAPIBackend::WUPSConfig>("DUMMY");
|
||||
}
|
||||
|
||||
configs.emplace_back(info, std::move(config));
|
||||
}
|
||||
|
||||
ConfigRenderer renderer(std::move(configs));
|
||||
configs.clear();
|
||||
|
||||
CombinedInput baseInput;
|
||||
VPadInput vpadInput;
|
||||
WPADInput wpadInputs[4] = {
|
||||
WPAD_CHAN_0,
|
||||
WPAD_CHAN_1,
|
||||
WPAD_CHAN_2,
|
||||
WPAD_CHAN_3};
|
||||
|
||||
auto startTime = OSGetTime();
|
||||
while (true) {
|
||||
baseInput.reset();
|
||||
if (vpadInput.update(1280, 720)) {
|
||||
baseInput.combine(vpadInput);
|
||||
}
|
||||
for (auto &wpadInput : wpadInputs) {
|
||||
if (wpadInput.update(1280, 720)) {
|
||||
baseInput.combine(wpadInput);
|
||||
}
|
||||
}
|
||||
baseInput.process();
|
||||
|
||||
WUPSConfigSimplePadData simpleData;
|
||||
simpleData.buttons_d = convertInputs(baseInput.data.buttons_d);
|
||||
simpleData.buttons_r = convertInputs(baseInput.data.buttons_r);
|
||||
simpleData.buttons_h = convertInputs(baseInput.data.buttons_h);
|
||||
simpleData.x = baseInput.data.x;
|
||||
simpleData.y = baseInput.data.y;
|
||||
simpleData.touched = baseInput.data.touched;
|
||||
simpleData.validPointer = baseInput.data.validPointer;
|
||||
|
||||
WUPSConfigComplexPadData complexData;
|
||||
complexData.vpad.data = vpadInput.vpad;
|
||||
complexData.vpad.tpCalib = vpadInput.tpCalib;
|
||||
complexData.vpad.vpadError = vpadInput.vpadError;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
complexData.kpad.kpadError[i] = wpadInputs[i].kpadError;
|
||||
complexData.kpad.data[i] = wpadInputs[i].kpad;
|
||||
}
|
||||
|
||||
auto subState = renderer.Update(baseInput, simpleData, complexData);
|
||||
if (subState != SUB_STATE_RUNNING) {
|
||||
break;
|
||||
}
|
||||
renderer.Render();
|
||||
auto diffTime = OSTicksToMicroseconds(OSGetTime() - startTime);
|
||||
if (diffTime < 16000) {
|
||||
OSSleepTicks(OSMicrosecondsToTicks(16000 - diffTime));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &plugin : gLoadedPlugins) {
|
||||
auto configData = plugin->getConfigData();
|
||||
if (configData) {
|
||||
configData->CallMenuClosedCallback();
|
||||
} else {
|
||||
CallHook(*plugin, WUPS_LOADER_HOOK_CONFIG_CLOSED_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
WUPSConfigAPIBackend::Intern::CleanAllHandles();
|
||||
}
|
||||
|
||||
#define __SetDCPitchReg ((void (*)(uint32_t, uint32_t))(0x101C400 + 0x1e714))
|
||||
|
||||
void ConfigUtils::openConfigMenu() {
|
||||
bool wasHomeButtonMenuEnabled = OSIsHomeButtonMenuEnabled();
|
||||
|
||||
OSScreenInit();
|
||||
|
||||
uint32_t screen_buf0_size = OSScreenGetBufferSizeEx(SCREEN_TV);
|
||||
uint32_t screen_buf1_size = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
||||
void *screenbuffer0 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf0_size, 0x100);
|
||||
void *screenbuffer1 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf1_size, 0x100);
|
||||
|
||||
// Fix the TV buffer pitch if a 1080p buffer is used.
|
||||
if (screen_buf0_size == 0x00FD2000) {
|
||||
__SetDCPitchReg(SCREEN_TV, 1920);
|
||||
}
|
||||
|
||||
bool skipScreen0Free = false;
|
||||
bool skipScreen1Free = false;
|
||||
|
||||
if (!screenbuffer0 || !screenbuffer1) {
|
||||
if (screenbuffer0 == nullptr) {
|
||||
if (gStoredTVBuffer.buffer_size >= screen_buf0_size) {
|
||||
screenbuffer0 = gStoredTVBuffer.buffer;
|
||||
skipScreen0Free = true;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Use storedTVBuffer");
|
||||
}
|
||||
}
|
||||
if (screenbuffer1 == nullptr) {
|
||||
if (gStoredDRCBuffer.buffer_size >= screen_buf1_size) {
|
||||
screenbuffer1 = gStoredDRCBuffer.buffer;
|
||||
skipScreen1Free = true;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Use storedDRCBuffer");
|
||||
}
|
||||
}
|
||||
if (!screenbuffer0 || !screenbuffer1) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc buffers");
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
|
||||
OSScreenSetBufferEx(SCREEN_TV, screenbuffer0);
|
||||
OSScreenSetBufferEx(SCREEN_DRC, screenbuffer1);
|
||||
|
||||
OSScreenEnableEx(SCREEN_TV, 1);
|
||||
OSScreenEnableEx(SCREEN_DRC, 1);
|
||||
|
||||
// Clear screens
|
||||
OSScreenClearBufferEx(SCREEN_TV, 0);
|
||||
OSScreenClearBufferEx(SCREEN_DRC, 0);
|
||||
|
||||
// Flip buffers
|
||||
OSScreenFlipBuffersEx(SCREEN_TV);
|
||||
OSScreenFlipBuffersEx(SCREEN_DRC);
|
||||
|
||||
DrawUtils::initBuffers(screenbuffer0, screen_buf0_size, screenbuffer1, screen_buf1_size);
|
||||
if (!DrawUtils::initFont()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to init Font");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// disable the home button menu to prevent opening it when exiting
|
||||
OSEnableHomeButtonMenu(false);
|
||||
|
||||
displayMenu();
|
||||
|
||||
OSEnableHomeButtonMenu(wasHomeButtonMenuEnabled);
|
||||
|
||||
DrawUtils::deinitFont();
|
||||
|
||||
error_exit:
|
||||
|
||||
if (gStoredTVBuffer.buffer != nullptr) {
|
||||
GX2SetTVBuffer(gStoredTVBuffer.buffer, gStoredTVBuffer.buffer_size, static_cast<GX2TVRenderMode>(gStoredTVBuffer.mode),
|
||||
gStoredTVBuffer.surface_format, gStoredTVBuffer.buffering_mode);
|
||||
}
|
||||
|
||||
if (gStoredDRCBuffer.buffer != nullptr) {
|
||||
GX2SetDRCBuffer(gStoredDRCBuffer.buffer, gStoredDRCBuffer.buffer_size, static_cast<GX2DrcRenderMode>(gStoredDRCBuffer.mode),
|
||||
gStoredDRCBuffer.surface_format, gStoredDRCBuffer.buffering_mode);
|
||||
}
|
||||
if (!skipScreen0Free && screenbuffer0) {
|
||||
MEMFreeToMappedMemory(screenbuffer0);
|
||||
}
|
||||
|
||||
if (!skipScreen1Free && screenbuffer1) {
|
||||
MEMFreeToMappedMemory(screenbuffer1);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigUtils::renderBasicScreen(std::string_view text) {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, "Wii U Plugin System Config Menu");
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, VERSION_FULL, true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true);
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
uint32_t sz = DrawUtils::getTextWidth(text.data());
|
||||
|
||||
DrawUtils::print((SCREEN_WIDTH / 2) - (sz / 2), (SCREEN_HEIGHT / 2), text.data());
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char *exitHint = "\ue044 Exit";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 10, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
}
|
23
source/utils/config/ConfigUtils.h
Normal file
23
source/utils/config/ConfigUtils.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "ConfigDefines.h"
|
||||
#include "ConfigDisplayItem.h"
|
||||
#include "config/WUPSConfig.h"
|
||||
|
||||
#include "utils/input/Input.h"
|
||||
#include <gx2/enum.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#define MOVE_ITEM_INPUT_MASK (WUPS_CONFIG_BUTTON_B | WUPS_CONFIG_BUTTON_DOWN | WUPS_CONFIG_BUTTON_UP)
|
||||
|
||||
class ConfigUtils {
|
||||
public:
|
||||
static void openConfigMenu();
|
||||
|
||||
static WUPS_CONFIG_SIMPLE_INPUT convertInputs(uint32_t buttons);
|
||||
|
||||
private:
|
||||
static void displayMenu();
|
||||
static void renderBasicScreen(std::string_view text);
|
||||
};
|
27
source/utils/input/CombinedInput.h
Normal file
27
source/utils/input/CombinedInput.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include "Input.h"
|
||||
class CombinedInput : public Input {
|
||||
public:
|
||||
void combine(const Input &b) {
|
||||
data.buttons_h |= b.data.buttons_h;
|
||||
if (!data.touched) {
|
||||
data.touched = b.data.touched;
|
||||
}
|
||||
if (!data.validPointer) {
|
||||
data.validPointer = b.data.validPointer;
|
||||
data.pointerAngle = b.data.pointerAngle;
|
||||
data.x = b.data.x;
|
||||
data.y = b.data.y;
|
||||
}
|
||||
}
|
||||
|
||||
void process() {
|
||||
data.buttons_d |= (data.buttons_h & (~lastData.buttons_h));
|
||||
data.buttons_r |= (lastData.buttons_h & (~data.buttons_h));
|
||||
lastData.buttons_h = data.buttons_h;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
data = {};
|
||||
}
|
||||
};
|
62
source/utils/input/Input.h
Normal file
62
source/utils/input/Input.h
Normal file
@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
class Input {
|
||||
public:
|
||||
//!Constructor
|
||||
Input() = default;
|
||||
|
||||
//!Destructor
|
||||
virtual ~Input() = default;
|
||||
|
||||
enum eButtons {
|
||||
BUTTON_NONE = 0x0000,
|
||||
VPAD_TOUCH = 0x80000000,
|
||||
BUTTON_STICK_L = 0x80000,
|
||||
BUTTON_STICK_R = 0x40000,
|
||||
BUTTON_Z = 0x20000,
|
||||
BUTTON_C = 0x10000,
|
||||
BUTTON_A = 0x8000,
|
||||
BUTTON_B = 0x4000,
|
||||
BUTTON_X = 0x2000,
|
||||
BUTTON_Y = 0x1000,
|
||||
BUTTON_1 = BUTTON_Y,
|
||||
BUTTON_2 = BUTTON_X,
|
||||
BUTTON_LEFT = 0x0800,
|
||||
BUTTON_RIGHT = 0x0400,
|
||||
BUTTON_UP = 0x0200,
|
||||
BUTTON_DOWN = 0x0100,
|
||||
BUTTON_ZL = 0x0080,
|
||||
BUTTON_ZR = 0x0040,
|
||||
BUTTON_L = 0x0020,
|
||||
BUTTON_R = 0x0010,
|
||||
BUTTON_PLUS = 0x0008,
|
||||
BUTTON_MINUS = 0x0004,
|
||||
BUTTON_HOME = 0x0002,
|
||||
BUTTON_SYNC = 0x0001,
|
||||
STICK_R_LEFT = 0x04000000,
|
||||
STICK_R_RIGHT = 0x02000000,
|
||||
STICK_R_UP = 0x01000000,
|
||||
STICK_R_DOWN = 0x00800000,
|
||||
STICK_L_LEFT = 0x40000000,
|
||||
STICK_L_RIGHT = 0x20000000,
|
||||
STICK_L_UP = 0x10000000,
|
||||
STICK_L_DOWN = 0x08000000
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t buttons_h;
|
||||
uint32_t buttons_d;
|
||||
uint32_t buttons_r;
|
||||
bool validPointer;
|
||||
bool touched;
|
||||
float pointerAngle;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
} PadData;
|
||||
|
||||
PadData data{};
|
||||
PadData lastData{};
|
||||
};
|
57
source/utils/input/VPADInput.h
Normal file
57
source/utils/input/VPADInput.h
Normal file
@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* 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 "Input.h"
|
||||
#include <vpad/input.h>
|
||||
|
||||
class VPadInput : public Input {
|
||||
public:
|
||||
//!Constructor
|
||||
VPadInput() = default;
|
||||
|
||||
//!Destructor
|
||||
~VPadInput() override = default;
|
||||
|
||||
bool update(int32_t width, int32_t height) {
|
||||
lastData = data;
|
||||
|
||||
data = {};
|
||||
vpadError = VPAD_READ_NO_SAMPLES;
|
||||
|
||||
if (VPADRead(VPAD_CHAN_0, &vpad, 1, &vpadError) > 0 && vpadError == VPAD_READ_SUCCESS) {
|
||||
data.buttons_r = vpad.release;
|
||||
data.buttons_h = vpad.hold;
|
||||
data.buttons_d = vpad.trigger;
|
||||
data.validPointer = !vpad.tpNormal.validity;
|
||||
data.touched = vpad.tpNormal.touched;
|
||||
|
||||
VPADGetTPCalibratedPoint(VPAD_CHAN_0, &tpCalib, &vpad.tpFiltered1);
|
||||
|
||||
//! calculate the screen offsets
|
||||
data.x = -(width >> 1) + (int32_t) (((float) tpCalib.x / 1280.0f) * (float) width);
|
||||
data.y = -(height >> 1) + (int32_t) (float) height - (((float) tpCalib.y / 720.0f) * (float) height);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
VPADStatus vpad = {};
|
||||
VPADReadError vpadError = {};
|
||||
VPADTouchData tpCalib = {};
|
||||
};
|
187
source/utils/input/WPADInput.h
Normal file
187
source/utils/input/WPADInput.h
Normal file
@ -0,0 +1,187 @@
|
||||
#pragma once
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* 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 "Input.h"
|
||||
#include <padscore/kpad.h>
|
||||
#include <padscore/wpad.h>
|
||||
|
||||
class WPADInput : public Input {
|
||||
public:
|
||||
WPADInput(KPADChan channel) {
|
||||
this->channel = channel;
|
||||
}
|
||||
|
||||
~WPADInput() override {}
|
||||
|
||||
uint32_t remapWiiMoteButtons(uint32_t buttons) {
|
||||
uint32_t conv_buttons = 0;
|
||||
|
||||
if (buttons & WPAD_BUTTON_LEFT)
|
||||
conv_buttons |= Input::BUTTON_LEFT;
|
||||
|
||||
if (buttons & WPAD_BUTTON_RIGHT)
|
||||
conv_buttons |= Input::BUTTON_RIGHT;
|
||||
|
||||
if (buttons & WPAD_BUTTON_DOWN)
|
||||
conv_buttons |= Input::BUTTON_DOWN;
|
||||
|
||||
if (buttons & WPAD_BUTTON_UP)
|
||||
conv_buttons |= Input::BUTTON_UP;
|
||||
|
||||
if (buttons & WPAD_BUTTON_PLUS)
|
||||
conv_buttons |= Input::BUTTON_PLUS;
|
||||
|
||||
if (buttons & WPAD_BUTTON_2)
|
||||
conv_buttons |= Input::BUTTON_2;
|
||||
|
||||
if (buttons & WPAD_BUTTON_1)
|
||||
conv_buttons |= Input::BUTTON_1;
|
||||
|
||||
if (buttons & WPAD_BUTTON_B)
|
||||
conv_buttons |= Input::BUTTON_B;
|
||||
|
||||
if (buttons & WPAD_BUTTON_A)
|
||||
conv_buttons |= Input::BUTTON_A;
|
||||
|
||||
if (buttons & WPAD_BUTTON_MINUS)
|
||||
conv_buttons |= Input::BUTTON_MINUS;
|
||||
|
||||
if (buttons & WPAD_BUTTON_Z)
|
||||
conv_buttons |= Input::BUTTON_Z;
|
||||
|
||||
if (buttons & WPAD_BUTTON_C)
|
||||
conv_buttons |= Input::BUTTON_C;
|
||||
|
||||
if (buttons & WPAD_BUTTON_HOME)
|
||||
conv_buttons |= Input::BUTTON_HOME;
|
||||
|
||||
return conv_buttons;
|
||||
}
|
||||
|
||||
uint32_t remapClassicButtons(uint32_t buttons) {
|
||||
uint32_t conv_buttons = 0;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_LEFT)
|
||||
conv_buttons |= Input::BUTTON_LEFT;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_RIGHT)
|
||||
conv_buttons |= Input::BUTTON_RIGHT;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_DOWN)
|
||||
conv_buttons |= Input::BUTTON_DOWN;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_UP)
|
||||
conv_buttons |= Input::BUTTON_UP;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_PLUS)
|
||||
conv_buttons |= Input::BUTTON_PLUS;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_X)
|
||||
conv_buttons |= Input::BUTTON_X;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_Y)
|
||||
conv_buttons |= Input::BUTTON_Y;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_B)
|
||||
conv_buttons |= Input::BUTTON_B;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_A)
|
||||
conv_buttons |= Input::BUTTON_A;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_MINUS)
|
||||
conv_buttons |= Input::BUTTON_MINUS;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_HOME)
|
||||
conv_buttons |= Input::BUTTON_HOME;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_ZR)
|
||||
conv_buttons |= Input::BUTTON_ZR;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_ZL)
|
||||
conv_buttons |= Input::BUTTON_ZL;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_R)
|
||||
conv_buttons |= Input::BUTTON_R;
|
||||
|
||||
if (buttons & WPAD_CLASSIC_BUTTON_L)
|
||||
conv_buttons |= Input::BUTTON_L;
|
||||
|
||||
return conv_buttons;
|
||||
}
|
||||
|
||||
bool update(int32_t width, int32_t height) {
|
||||
lastData = data;
|
||||
|
||||
kpadError = KPAD_ERROR_UNINITIALIZED;
|
||||
data = {};
|
||||
|
||||
WPADExtensionType type;
|
||||
if (WPADProbe(channel, &type) != 0) {
|
||||
data.buttons_h = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (KPADReadEx(channel, &kpad, 1, &kpadError) <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (kpadError != KPAD_ERROR_OK || kpad.extensionType == 0xFF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (kpad.extensionType == WPAD_EXT_CORE || kpad.extensionType == WPAD_EXT_NUNCHUK) {
|
||||
data.buttons_r = remapWiiMoteButtons(kpad.release);
|
||||
data.buttons_h = remapWiiMoteButtons(kpad.hold);
|
||||
data.buttons_d = remapWiiMoteButtons(kpad.trigger);
|
||||
} else {
|
||||
data.buttons_r = remapClassicButtons(kpad.classic.release);
|
||||
data.buttons_h = remapClassicButtons(kpad.classic.hold);
|
||||
data.buttons_d = remapClassicButtons(kpad.classic.trigger);
|
||||
}
|
||||
|
||||
data.validPointer = (kpad.posValid == 1 || kpad.posValid == 2) &&
|
||||
(kpad.pos.x >= -1.0f && kpad.pos.x <= 1.0f) &&
|
||||
(kpad.pos.y >= -1.0f && kpad.pos.y <= 1.0f);
|
||||
|
||||
//! calculate the screen offsets if pointer is valid else leave old value
|
||||
if (data.validPointer) {
|
||||
data.x = (width >> 1) * kpad.pos.x;
|
||||
data.y = (height >> 1) * (-kpad.pos.y);
|
||||
|
||||
if (kpad.angle.y > 0.0f) {
|
||||
data.pointerAngle = (-kpad.angle.x + 1.0f) * 0.5f * 180.0f;
|
||||
} else {
|
||||
data.pointerAngle = (kpad.angle.x + 1.0f) * 0.5f * 180.0f - 180.0f;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void init() {
|
||||
KPADInit();
|
||||
WPADEnableURCC(1);
|
||||
}
|
||||
|
||||
static void close() {
|
||||
}
|
||||
|
||||
KPADStatus kpad = {};
|
||||
KPADError kpadError = KPAD_ERROR_UNINITIALIZED;
|
||||
KPADChan channel;
|
||||
};
|
@ -55,7 +55,7 @@ extern "C" {
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
|
||||
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##WARN ## ", "\n", FMT, ##ARGS)
|
||||
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) while (0)
|
||||
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##INFO ## ", "\n", FMT, ##ARGS)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS);
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -91,12 +92,44 @@ remove_first_if(Container &container, Predicate pred) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Container, typename Predicate>
|
||||
typename std::enable_if<std::is_same<Container, std::vector<typename Container::value_type>>::value, bool>::type
|
||||
remove_first_if(Container &container, Predicate pred) {
|
||||
auto it = container.begin();
|
||||
while (it != container.end()) {
|
||||
if (pred(*it)) {
|
||||
container.erase(it);
|
||||
return true;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Container, typename Predicate>
|
||||
bool remove_locked_first_if(std::mutex &mutex, Container &container, Predicate pred) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
return remove_first_if(container, pred);
|
||||
}
|
||||
|
||||
template<typename T, typename Predicate>
|
||||
T pop_locked_first_if(std::mutex &mutex, std::vector<T> &container, Predicate pred) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
T result;
|
||||
auto it = container.begin();
|
||||
while (it != container.end()) {
|
||||
if (pred(*it)) {
|
||||
result = std::move(*it);
|
||||
container.erase(it);
|
||||
return result;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string getPluginPath();
|
||||
|
||||
OSDynLoad_Error CustomDynLoadAlloc(int32_t size, int32_t align, void **outAddr);
|
||||
|
Loading…
Reference in New Issue
Block a user