Initial commit
This commit is contained in:
279
src/os_config_tab.cpp
Normal file
279
src/os_config_tab.cpp
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user