WiiUPluginLoaderBackend/source/utils/config/ConfigRenderer.cpp

305 lines
11 KiB
C++
Raw Normal View History

#include "ConfigRenderer.h"
2024-11-27 20:44:36 +01:00
#include "globals.h"
#include "plugin/PluginLoadWrapper.h"
2024-11-27 20:44:36 +01:00
#include "utils/DrawUtils.h"
#include "utils/StringTools.h"
2024-11-27 20:44:36 +01:00
#include "utils/logger.h"
#include "utils/utils.h"
#include <coreinit/title.h>
2024-11-27 20:44:36 +01:00
ConfigRenderer::ConfigRenderer(std::vector<ConfigDisplayItem> &&vec) : mConfigs(std::move(vec)) {
std::copy(mConfigs.begin(), mConfigs.end(),
std::back_inserter(mAllConfigs));
std::copy_if(mConfigs.begin(), mConfigs.end(),
std::back_inserter(mActiveConfigs),
[&](const auto &value) {
return value.isActivePlugin();
});
2024-11-27 20:44:36 +01:00
}
2024-11-27 20:44:36 +01:00
ConfigRenderer::~ConfigRenderer() = default;
2024-11-27 20:44:36 +01:00
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) {
2024-11-27 20:44:36 +01:00
mNeedRedraw = true;
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;
}
}
}
2024-11-27 20:44:36 +01:00
return SUB_STATE_ERROR;
}
2024-11-27 20:44:36 +01:00
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;
}
}
}
2024-11-27 20:44:36 +01:00
bool ConfigRenderer::NeedsRedraw() const {
if (mNeedRedraw) {
return true;
} else if (mCategoryRenderer) {
2024-11-27 20:44:36 +01:00
return mCategoryRenderer->NeedsRedraw();
}
2024-11-27 20:44:36 +01:00
return false;
}
2024-11-27 20:44:36 +01:00
void ConfigRenderer::ResetNeedsRedraw() {
mNeedRedraw = false;
if (mCategoryRenderer) {
mCategoryRenderer->ResetNeedsRedraw();
}
}
ConfigSubState ConfigRenderer::UpdateStateMain(const Input &input) {
auto &configs = GetConfigList();
auto prevSelectedItem = mCursorPos;
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_PLUS) {
if (mSetActivePluginsMode) {
mNeedRedraw = true;
mCategoryRenderer.reset();
return SUB_STATE_RETURN_WITH_PLUGIN_RELOAD;
}
} else if (input.data.buttons_d & Input::eButtons::BUTTON_X) {
if (!mSetActivePluginsMode && !mAllConfigs.empty()) {
mSetActivePluginsMode = true;
mNeedRedraw = true;
return SUB_STATE_RUNNING;
}
} else if (input.data.buttons_d & Input::eButtons::BUTTON_A) {
if (mSetActivePluginsMode) {
mActivePluginsDirty = true;
mNeedRedraw = true;
configs[mCursorPos].get().toggleIsActivePlugin();
return SUB_STATE_RUNNING;
} else if (!configs.empty()) {
if (mCursorPos != mCurrentOpen) {
mCategoryRenderer.reset();
mCategoryRenderer = make_unique_nothrow<CategoryRenderer>(&(configs[mCursorPos].get().getConfigInformation()), &(configs[mCursorPos].get().getConfig()), true);
}
mNeedRedraw = true;
mCurrentOpen = mCursorPos;
mState = STATE_SUB;
return SUB_STATE_RUNNING;
}
} else if (input.data.buttons_d & (Input::eButtons::BUTTON_B | Input::eButtons::BUTTON_HOME)) {
if (mSetActivePluginsMode) {
for (auto &cur : mConfigs) {
cur.resetIsActivePlugin();
}
mNeedRedraw = true;
mSetActivePluginsMode = false;
return SUB_STATE_RUNNING;
} else {
mNeedRedraw = true;
mCategoryRenderer.reset();
for (const auto &element : configs) {
CallOnCloseCallback(element.get().getConfigInformation(), element.get().getConfig());
}
return SUB_STATE_RETURN;
}
}
auto totalElementSize = (int32_t) configs.size();
if (mCursorPos < 0) {
mCursorPos = totalElementSize - 1;
} else if (mCursorPos > (totalElementSize - 1)) {
mCursorPos = 0;
}
if (mCursorPos < 0) {
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;
}
if (prevSelectedItem != mCursorPos) {
mNeedRedraw = true;
}
return SUB_STATE_RUNNING;
}
2024-11-27 20:44:36 +01:00
void ConfigRenderer::RenderStateMain() const {
auto &configs = GetConfigList();
DrawUtils::beginDraw();
DrawUtils::clear(COLOR_BACKGROUND);
auto totalElementSize = (int32_t) configs.size();
2024-11-27 20:44:36 +01:00
// Calculate the range of items to display
int start = std::max(0, mRenderOffset);
int end = std::min(start + MAX_BUTTONS_ON_SCREEN, totalElementSize);
if (mActiveConfigs.empty() && !mSetActivePluginsMode) {
DrawUtils::setFontSize(24);
std::string noConfigText = "No active plugins";
uint32_t szNoConfig = DrawUtils::getTextWidth(noConfigText.data());
if (!mAllConfigs.empty()) {
std::string activateHint = "Press \ue002 to activate inactive plugins";
auto szHint = DrawUtils::getTextWidth(activateHint.c_str());
2024-11-27 20:44:36 +01:00
DrawUtils::print((SCREEN_WIDTH / 2) - (szNoConfig / 2), (SCREEN_HEIGHT / 2) - 16, noConfigText.data());
DrawUtils::print((SCREEN_WIDTH / 2) - (szHint / 2), (SCREEN_HEIGHT / 2) + 16, activateHint.data());
} else {
DrawUtils::print((SCREEN_WIDTH / 2) - (szNoConfig / 2), (SCREEN_HEIGHT / 2), noConfigText.data());
}
} else {
uint32_t yOffset = 8 + 24 + 8 + 4;
for (int32_t i = start; i < end; i++) {
DrawConfigEntry(yOffset, configs[i].get().getConfigInformation(), i == mCursorPos, configs[i].get().isActivePlugin());
yOffset += 42 + 8;
}
}
2024-11-27 20:44:36 +01:00
DrawUtils::setFontColor(COLOR_TEXT);
// draw top bar
DrawUtils::setFontSize(24);
if (mSetActivePluginsMode) {
DrawUtils::print(16, 6 + 24, "Please select the plugin that should be active");
} else {
DrawUtils::print(16, 6 + 24, "Wii U Plugin System Config Menu");
auto countInactivePlugins = mAllConfigs.size() - mActiveConfigs.size();
if (countInactivePlugins > 0) {
DrawUtils::setFontSize(14);
std::string plugin_unloaded = string_format("Found %d inactive plugins", countInactivePlugins);
DrawUtils::print(SCREEN_WIDTH - 16 - DrawUtils::getTextWidth(MODULE_VERSION_FULL) - 32, 8 + 24, plugin_unloaded.c_str(), true);
}
}
2024-11-27 20:44:36 +01:00
DrawUtils::setFontSize(18);
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, MODULE_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 ");
if (mSetActivePluginsMode) {
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Activate | \uE045 Apply", true);
} else if (totalElementSize > 0) {
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true);
}
2024-11-27 20:44:36 +01:00
// draw scroll indicator
DrawUtils::setFontSize(24);
if (end < totalElementSize) {
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
}
2024-11-27 20:44:36 +01:00
if (start > 0) {
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
}
// draw home button
DrawUtils::setFontSize(18);
const char *exitHint = "\ue044 Exit";
if (mSetActivePluginsMode) {
exitHint = "\ue001 Abort";
}
2024-11-27 20:44:36 +01:00
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, bool isActive) const {
2024-11-27 20:44:36 +01:00
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);
}
2024-11-27 20:44:36 +01:00
int textXOffset = 16 * 2;
if (mSetActivePluginsMode) {
DrawUtils::setFontSize(24);
if (isActive) {
2024-08-04 17:56:26 +02:00
DrawUtils::print(textXOffset, yOffset + 8 + 24, "\u25C9");
} else {
DrawUtils::print(textXOffset, yOffset + 8 + 24, "\u25CE");
}
textXOffset += 32;
}
2024-11-27 20:44:36 +01:00
DrawUtils::setFontSize(24);
DrawUtils::print(textXOffset, yOffset + 8 + 24, configInformation.name.c_str());
uint32_t sz = DrawUtils::getTextWidth(configInformation.name.c_str());
2024-11-27 20:44:36 +01:00
DrawUtils::setFontSize(12);
DrawUtils::print(textXOffset + sz + 4, yOffset + 8 + 24, configInformation.author.c_str());
2024-11-27 20:44:36 +01:00
DrawUtils::print(SCREEN_WIDTH - 16 * 2, yOffset + 8 + 24, configInformation.version.c_str(), true);
}
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();
}
}
}
bool ConfigRenderer::GetActivePluginsIfChanged(std::vector<PluginLoadWrapper> &result) {
if (mActivePluginsDirty) {
std::vector<std::string> inactive_plugins;
result.clear();
for (const auto &cur : mConfigs) {
result.emplace_back(cur.getConfigInformation().pluginData, cur.isActivePlugin());
}
return true;
}
return false;
}
void ConfigRenderer::CallOnCloseCallback(const GeneralConfigInformation &info, const WUPSConfigAPIBackend::WUPSConfig &config) {
CallOnCloseCallback(info, config.getCategories());
for (const auto &item : config.getItems()) {
item->onCloseCallback();
}
}
const std::vector<std::reference_wrapper<ConfigDisplayItem>> &ConfigRenderer::GetConfigList() const {
if (mSetActivePluginsMode) {
return mAllConfigs;
}
return mActiveConfigs;
}