Initial commit

This commit is contained in:
Niklas080208
2026-02-11 20:33:01 +01:00
commit 617265f004
145 changed files with 45252 additions and 0 deletions

279
src/os_config_tab.cpp Normal file
View File

@@ -0,0 +1,279 @@
/*
SWR INI Tool - Switchroot INI Configuration Editor
Copyright (C) 2026 Switchroot
*/
#include "os_config_tab.h"
#include "oc_defs.h"
#include <algorithm>
OsConfigTab::OsConfigTab(const std::string& osName, const std::string& iniPath)
: osName(osName), iniPath(iniPath)
{
if (!this->ini.load(iniPath))
{
buildErrorUI("Could not load " + iniPath + "\n\n"
"Make sure the INI file exists at the expected path.\n"
"You can configure paths in the Settings tab.");
return;
}
this->osSection = this->ini.findOsSection();
if (this->osSection.empty())
{
buildErrorUI("No OS section found in " + iniPath + "\n\n"
"The INI file should contain a section like\n"
"[" + osName + " OC] with your configuration.");
return;
}
buildUI();
}
void OsConfigTab::reload(const std::string& newIniPath)
{
this->iniPath = newIniPath;
this->osSection.clear();
// Remove all child views
this->clear();
if (!this->ini.load(iniPath))
{
buildErrorUI("Could not load " + iniPath + "\n\n"
"Make sure the INI file exists at the expected path.\n"
"You can configure paths in the Settings tab.");
return;
}
this->osSection = this->ini.findOsSection();
if (this->osSection.empty())
{
buildErrorUI("No OS section found in " + iniPath + "\n\n"
"The INI file should contain a section like\n"
"[" + osName + " OC] with your configuration.");
return;
}
buildUI();
}
void OsConfigTab::buildErrorUI(const std::string& message)
{
this->setSpacing(15);
// Use a ListItem (focusable) so borealis doesn't crash on controller nav
brls::ListItem *errorItem = new brls::ListItem("\uE150 INI file not found", message);
this->addView(errorItem);
}
void OsConfigTab::buildUI()
{
this->setSpacing(2);
this->setMarginBottom(20);
// Section name info
brls::Label *sectionInfo = new brls::Label(
brls::LabelStyle::DESCRIPTION,
"Editing section [" + this->osSection + "] from " + this->iniPath,
true
);
this->addView(sectionInfo);
// ── Toggle Options ──
this->addView(new brls::Header("Toggle Options"));
for (const auto& def : OC_BOOL_KEYS)
{
if (this->ini.hasKey(this->osSection, def.key))
{
bool val = this->ini.getBool(this->osSection, def.key);
addBooleanToggle(def.label, "", def.key, val);
}
}
// ── Frequency Settings ──
brls::Rectangle* spacer1 = new brls::Rectangle(nvgRGBA(0, 0, 0, 0));
spacer1->setHeight(30);
this->addView(spacer1);
this->addView(new brls::Header("Frequency Settings"));
for (const auto& def : OC_FREQ_KEYS)
{
if (this->ini.hasKey(this->osSection, def.key))
{
uint32_t val = (uint32_t)this->ini.getInt(this->osSection, def.key, 0);
addFreqDropdown(def.label, "", def.key, val, def.options);
}
}
// ── Voltage Settings ──
brls::Rectangle* spacer2 = new brls::Rectangle(nvgRGBA(0, 0, 0, 0));
spacer2->setHeight(30);
this->addView(spacer2);
this->addView(new brls::Header("Voltage Settings"));
for (const auto& def : OC_VOLTAGE_KEYS)
{
if (this->ini.hasKey(this->osSection, def.key))
{
uint32_t val = (uint32_t)this->ini.getInt(this->osSection, def.key, 0);
addVoltageDropdown(def.label, "", def.key, val, def.options);
}
}
// ── Other Keys (read-only info) ──
// Show any keys that aren't covered by the known definitions above
auto allKeys = this->ini.getKeys(this->osSection);
bool hasOtherKeys = false;
for (const auto& kv : allKeys)
{
bool isKnown = false;
for (const auto& def : OC_BOOL_KEYS)
if (def.key == kv.first) { isKnown = true; break; }
if (!isKnown)
for (const auto& def : OC_FREQ_KEYS)
if (def.key == kv.first) { isKnown = true; break; }
if (!isKnown)
for (const auto& def : OC_VOLTAGE_KEYS)
if (def.key == kv.first) { isKnown = true; break; }
if (!isKnown)
{
if (!hasOtherKeys)
{
brls::Rectangle* spacerOther = new brls::Rectangle(nvgRGBA(0, 0, 0, 0));
spacerOther->setHeight(30);
this->addView(spacerOther);
this->addView(new brls::Header("Other"));
hasOtherKeys = true;
}
brls::ListItem *item = new brls::ListItem(kv.first);
item->setValue(kv.second);
this->addView(item);
}
}
}
void OsConfigTab::saveAndNotify()
{
if (this->ini.save())
{
brls::Application::notify("\uE14B Configuration saved");
}
else
{
brls::Application::notify("\uE150 Error saving configuration!");
}
}
void OsConfigTab::addBooleanToggle(const std::string& label, const std::string& description,
const std::string& key, bool currentValue)
{
brls::ToggleListItem *toggle = new brls::ToggleListItem(
label, currentValue, description, "ON", "OFF"
);
std::string keyCopy = key;
toggle->getClickEvent()->subscribe([this, toggle, keyCopy](brls::View* view) {
bool newVal = toggle->getToggleState();
this->ini.setBool(this->osSection, keyCopy, newVal);
this->saveAndNotify();
});
this->addView(toggle);
}
void OsConfigTab::addFreqDropdown(const std::string& label, const std::string& description,
const std::string& key, uint32_t currentValue,
const std::vector<uint32_t>& options)
{
// Build option list, including the current value if not in the predefined list
std::vector<uint32_t> allOptions = options;
bool currentFound = false;
for (uint32_t opt : allOptions)
{
if (opt == currentValue) { currentFound = true; break; }
}
if (!currentFound && currentValue > 0)
{
allOptions.push_back(currentValue);
std::sort(allOptions.begin(), allOptions.end());
}
// Build display strings
std::vector<std::string> displayOptions;
size_t selectedIdx = 0;
for (size_t i = 0; i < allOptions.size(); i++)
{
displayOptions.push_back(formatFreqKHz(allOptions[i]));
if (allOptions[i] == currentValue)
selectedIdx = i;
}
brls::SelectListItem *item = new brls::SelectListItem(label, displayOptions, selectedIdx);
std::string keyCopy = key;
std::vector<uint32_t> optionsCopy = allOptions;
item->getValueSelectedEvent()->subscribe([this, keyCopy, optionsCopy](int result) {
if (result >= 0 && result < (int)optionsCopy.size())
{
this->ini.setInt(this->osSection, keyCopy, (int)optionsCopy[result]);
this->saveAndNotify();
}
});
this->addView(item);
}
void OsConfigTab::addVoltageDropdown(const std::string& label, const std::string& description,
const std::string& key, uint32_t currentValue,
const std::vector<uint32_t>& options)
{
// Build option list, including the current value if not in the predefined list
std::vector<uint32_t> allOptions = options;
bool currentFound = false;
for (uint32_t opt : allOptions)
{
if (opt == currentValue) { currentFound = true; break; }
}
if (!currentFound && currentValue > 0)
{
allOptions.push_back(currentValue);
std::sort(allOptions.begin(), allOptions.end());
}
// Build display strings
std::vector<std::string> displayOptions;
size_t selectedIdx = 0;
for (size_t i = 0; i < allOptions.size(); i++)
{
displayOptions.push_back(formatVoltageMv(allOptions[i]));
if (allOptions[i] == currentValue)
selectedIdx = i;
}
brls::SelectListItem *item = new brls::SelectListItem(label, displayOptions, selectedIdx);
std::string keyCopy = key;
std::vector<uint32_t> optionsCopy = allOptions;
item->getValueSelectedEvent()->subscribe([this, keyCopy, optionsCopy](int result) {
if (result >= 0 && result < (int)optionsCopy.size())
{
this->ini.setInt(this->osSection, keyCopy, (int)optionsCopy[result]);
this->saveAndNotify();
}
});
this->addView(item);
}