Compare commits
5 Commits
617265f004
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30e89fee71 | ||
|
|
b5296d6686 | ||
|
|
b5ba2d71df | ||
|
|
a61fa67dca | ||
|
|
90b3902311 |
41
.github/workflows/build.yml
vendored
Normal file
41
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
name: Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, master]
|
||||||
|
pull_request:
|
||||||
|
branches: [main, master]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
switch:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
# Switch homebrew uses devkitA64 + libnx (not devkitARM)
|
||||||
|
image: devkitpro/devkita64:latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# actions/checkout needs Node; devkitPro images omit it by default
|
||||||
|
- name: Install dependencies
|
||||||
|
run: apt-get update && apt-get install -y nodejs
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
clean: true
|
||||||
|
|
||||||
|
- name: Compile (Switch .nro)
|
||||||
|
env:
|
||||||
|
DEVKITPRO: /opt/devkitpro
|
||||||
|
run: make -j$(nproc)
|
||||||
|
|
||||||
|
# v3: GHES does not support upload-artifact v4+ (artifact v2 backend)
|
||||||
|
- name: Upload .nro artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: swr-ini-tool
|
||||||
|
path: swr-ini-tool.nro
|
||||||
|
if-no-files-found: error
|
||||||
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# devkitPro / Switch build outputs
|
||||||
|
build.nx/
|
||||||
|
*.elf
|
||||||
|
*.nro
|
||||||
|
*.nacp
|
||||||
|
*.nso
|
||||||
|
*.npdm
|
||||||
|
*.nsp
|
||||||
|
*.lst
|
||||||
|
*.map
|
||||||
|
|
||||||
|
# editor / OS
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*~
|
||||||
|
*.bak
|
||||||
|
.DS_Store
|
||||||
6
Makefile
6
Makefile
@@ -33,7 +33,7 @@ APP_RESOURCES := romfs:/
|
|||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# version control constants
|
# version control constants
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
TARGET_VERSION := 0.1.0
|
TARGET_VERSION := 1.0.0
|
||||||
APP_VERSION := $(TARGET_VERSION)
|
APP_VERSION := $(TARGET_VERSION)
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
@@ -159,8 +159,8 @@ all: $(BUILD)
|
|||||||
$(ROMFS):
|
$(ROMFS):
|
||||||
@[ -d $@ ] || mkdir -p $@
|
@[ -d $@ ] || mkdir -p $@
|
||||||
@echo Merging ROMFS...
|
@echo Merging ROMFS...
|
||||||
@cp -ruf $(CURDIR)/$(BOREALIS_PATH)/resources/. $(CURDIR)/$(ROMFS)/borealis/
|
@cp -rf $(CURDIR)/$(BOREALIS_PATH)/resources/. $(CURDIR)/$(ROMFS)/borealis/
|
||||||
@cp -ruf $(CURDIR)/$(RESOURCES)/. $(CURDIR)/$(ROMFS)/
|
@cp -rf $(CURDIR)/$(RESOURCES)/. $(CURDIR)/$(ROMFS)/
|
||||||
|
|
||||||
$(BUILD): $(ROMFS)
|
$(BUILD): $(ROMFS)
|
||||||
@[ -d $@ ] || mkdir -p $@
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
|||||||
BIN
resources/gui_icon.png
Normal file
BIN
resources/gui_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
@@ -4,18 +4,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "about_tab.h"
|
#include "about_tab.h"
|
||||||
|
#include "i18n.h"
|
||||||
#include "logo.h"
|
#include "logo.h"
|
||||||
|
|
||||||
AboutTab::AboutTab()
|
AboutTab::AboutTab()
|
||||||
{
|
{
|
||||||
// Logo
|
// Logo
|
||||||
this->addView(new Logo(LogoStyle::ABOUT));
|
this->addView(new Logo());
|
||||||
|
|
||||||
// Subtitle
|
// Subtitle
|
||||||
brls::Label *subTitle = new brls::Label(
|
brls::Label *subTitle = new brls::Label(
|
||||||
brls::LabelStyle::REGULAR,
|
brls::LabelStyle::REGULAR,
|
||||||
"Switchroot INI Configuration Editor\n"
|
I18n::aboutSubtitle(),
|
||||||
"Edit your Linux, Android and Lakka OC settings without a PC!",
|
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
subTitle->setHorizontalAlign(NVG_ALIGN_CENTER);
|
subTitle->setHorizontalAlign(NVG_ALIGN_CENTER);
|
||||||
@@ -24,22 +24,17 @@ AboutTab::AboutTab()
|
|||||||
// Copyright
|
// Copyright
|
||||||
brls::Label *copyright = new brls::Label(
|
brls::Label *copyright = new brls::Label(
|
||||||
brls::LabelStyle::DESCRIPTION,
|
brls::LabelStyle::DESCRIPTION,
|
||||||
"Licensed under GPL-3.0\n"
|
I18n::aboutCopyright(),
|
||||||
"Powered by Borealis UI framework\n"
|
|
||||||
"Based on the work of Switchroot\n"
|
|
||||||
"\u00A9 2026 NiklasCFW",
|
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
copyright->setHorizontalAlign(NVG_ALIGN_CENTER);
|
copyright->setHorizontalAlign(NVG_ALIGN_CENTER);
|
||||||
this->addView(copyright);
|
this->addView(copyright);
|
||||||
|
|
||||||
// Links
|
// Links
|
||||||
this->addView(new brls::Header("Links and Resources"));
|
this->addView(new brls::Header(I18n::headerLinksAndResources()));
|
||||||
brls::Label *links = new brls::Label(
|
brls::Label *links = new brls::Label(
|
||||||
brls::LabelStyle::SMALL,
|
brls::LabelStyle::SMALL,
|
||||||
"\uE016 NiklasCFW Docs for setup guides and documentation\n"
|
I18n::aboutLinks(),
|
||||||
"\uE016 NiklasCFW's Discord server for support and community\n"
|
|
||||||
"\uE016 Source code available on the OmniNX GitHub",
|
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
this->addView(links);
|
this->addView(links);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "file_browser.h"
|
#include "file_browser.h"
|
||||||
|
#include "i18n.h"
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -78,7 +79,7 @@ std::vector<FileBrowser::DirEntry> FileBrowser::listDirectory(const std::string&
|
|||||||
void FileBrowser::navigate(const std::string& dir)
|
void FileBrowser::navigate(const std::string& dir)
|
||||||
{
|
{
|
||||||
this->currentDir = dir;
|
this->currentDir = dir;
|
||||||
this->setTitle("Select INI \u2014 " + dir);
|
this->setTitle(std::string(I18n::fileBrowserTitlePrefix()) + dir);
|
||||||
|
|
||||||
// Create a fresh list (setContentView frees the old one)
|
// Create a fresh list (setContentView frees the old one)
|
||||||
this->list = new brls::List();
|
this->list = new brls::List();
|
||||||
@@ -89,7 +90,7 @@ void FileBrowser::navigate(const std::string& dir)
|
|||||||
|
|
||||||
if (entries.empty())
|
if (entries.empty())
|
||||||
{
|
{
|
||||||
brls::ListItem* emptyItem = new brls::ListItem("No .ini files found in " + dir);
|
brls::ListItem* emptyItem = new brls::ListItem(I18n::fileBrowserNoIni(dir));
|
||||||
this->list->addView(emptyItem);
|
this->list->addView(emptyItem);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
264
src/i18n.cpp
Normal file
264
src/i18n.cpp
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
SWR INI Tool - Switchroot INI Configuration Editor
|
||||||
|
Copyright (C) 2026 Switchroot
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "i18n.h"
|
||||||
|
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
#include <switch.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
bool gGerman = false;
|
||||||
|
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
void detectSystemLanguage()
|
||||||
|
{
|
||||||
|
gGerman = false;
|
||||||
|
Result rc = setInitialize();
|
||||||
|
if (!R_SUCCEEDED(rc))
|
||||||
|
return;
|
||||||
|
|
||||||
|
u64 code = 0;
|
||||||
|
SetLanguage lang = SetLanguage_ENUS;
|
||||||
|
if (R_SUCCEEDED(setGetSystemLanguage(&code)) && R_SUCCEEDED(setMakeLanguage(code, &lang)))
|
||||||
|
{
|
||||||
|
if (lang == SetLanguage_DE)
|
||||||
|
gGerman = true;
|
||||||
|
}
|
||||||
|
setExit();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Triple
|
||||||
|
{
|
||||||
|
const char* key;
|
||||||
|
const char* en;
|
||||||
|
const char* de;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Triple OC_BOOL_LABEL[] = {
|
||||||
|
{"oc", "Overclocking", "Übertaktung"},
|
||||||
|
{"dvfsb", "CPU DVFS Boost", "CPU-DVFS-Boost"},
|
||||||
|
{"gpu_dvfsc", "GPU DVFS Scaling", "GPU-DVFS-Skalierung"},
|
||||||
|
{"usb3force", "Force USB 3.0", "USB 3.0 erzwingen"},
|
||||||
|
{"ddr200_enable", "DDR200 Enable", "DDR200 aktivieren"},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Triple OC_FREQ_LABEL[] = {
|
||||||
|
{"max_cpu_freq", "Max CPU Frequency", "Max. CPU-Taktfrequenz"},
|
||||||
|
{"max_gpu_freq", "Max GPU Frequency", "Max. GPU-Taktfrequenz"},
|
||||||
|
{"ram_oc", "RAM Frequency", "RAM-Taktfrequenz"},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Triple OC_VOLT_LABEL[] = {
|
||||||
|
{"ram_oc_vdd2", "RAM VDD2 Voltage", "RAM VDD2-Spannung"},
|
||||||
|
{"ram_oc_vddq", "RAM VDDQ Voltage", "RAM VDDQ-Spannung"},
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* lookup(const Triple* table, size_t n, const std::string& key, const char* fallback)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
if (key == table[i].key)
|
||||||
|
return gGerman ? table[i].de : table[i].en;
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace I18n
|
||||||
|
{
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
detectSystemLanguage();
|
||||||
|
#else
|
||||||
|
gGerman = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isGerman()
|
||||||
|
{
|
||||||
|
return gGerman;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* appTitle()
|
||||||
|
{
|
||||||
|
return gGerman ? "SWR INI-Tool" : "SWR INI Tool";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* tabSettings()
|
||||||
|
{
|
||||||
|
return gGerman ? "Einstellungen" : "Settings";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* tabAbout()
|
||||||
|
{
|
||||||
|
return gGerman ? "Über" : "About";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* wordOn()
|
||||||
|
{
|
||||||
|
return gGerman ? "Ein" : "ON";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* wordOff()
|
||||||
|
{
|
||||||
|
return gGerman ? "Aus" : "OFF";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sectionEditLine(const std::string& section, const std::string& path)
|
||||||
|
{
|
||||||
|
if (gGerman)
|
||||||
|
return "Abschnitt [" + section + "] aus " + path;
|
||||||
|
return "Editing section [" + section + "] from " + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* headerToggleOptions()
|
||||||
|
{
|
||||||
|
return gGerman ? "Schalter" : "Toggle Options";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* headerFrequencySettings()
|
||||||
|
{
|
||||||
|
return gGerman ? "Frequenz" : "Frequency Settings";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* headerVoltageSettings()
|
||||||
|
{
|
||||||
|
return gGerman ? "Spannung" : "Voltage Settings";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* headerOther()
|
||||||
|
{
|
||||||
|
return gGerman ? "Sonstiges" : "Other";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* headerIniFilePaths()
|
||||||
|
{
|
||||||
|
return gGerman ? "INI-Dateipfade" : "INI File Paths";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* headerLinksAndResources()
|
||||||
|
{
|
||||||
|
return gGerman ? "Links und Infos" : "Links and Resources";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* errorListItemTitleIni()
|
||||||
|
{
|
||||||
|
return gGerman ? "\uE150 INI-Problem" : "\uE150 INI file not found";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string iniLoadErrorBody(const std::string& path)
|
||||||
|
{
|
||||||
|
if (gGerman)
|
||||||
|
return "Die Datei konnte nicht geladen werden:\n" + path + "\n\n"
|
||||||
|
"Prüfen Sie den Pfad in den Einstellungen.";
|
||||||
|
return "Could not load " + path + "\n\n"
|
||||||
|
"Make sure the INI file exists at the expected path.\n"
|
||||||
|
"You can configure paths in the Settings tab.";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string iniSectionErrorBody(const std::string& path, const std::string& osName)
|
||||||
|
{
|
||||||
|
if (gGerman)
|
||||||
|
return "Kein OS-Abschnitt in " + path + "\n\n"
|
||||||
|
"Die INI sollte z. B. einen Abschnitt ["
|
||||||
|
+ osName + " OC] enthalten.";
|
||||||
|
return "No OS section found in " + path + "\n\n"
|
||||||
|
"The INI file should contain a section like\n"
|
||||||
|
"[" + osName + " OC] with your configuration.";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* notifyConfigSaved()
|
||||||
|
{
|
||||||
|
return gGerman ? "\uE14B Konfiguration gespeichert" : "\uE14B Configuration saved";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* notifyConfigSaveError()
|
||||||
|
{
|
||||||
|
return gGerman ? "\uE150 Fehler beim Speichern!" : "\uE150 Error saving configuration!";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* notifyPathUpdated()
|
||||||
|
{
|
||||||
|
return gGerman ? "\uE14B Pfad aktualisiert" : "\uE14B Path updated";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* settingsIntro()
|
||||||
|
{
|
||||||
|
return gGerman ? "Wählen Sie, welche INI-Datei jeder Reiter liest und schreibt.\n"
|
||||||
|
"Änderungen gelten sofort."
|
||||||
|
: "Select which INI file each OS tab reads and writes.\n"
|
||||||
|
"Changes take effect immediately.";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* pathListDescriptionLakka()
|
||||||
|
{
|
||||||
|
return gGerman ? "Tippen, um eine INI-Datei zu wählen" : "Tap to browse for an INI file";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* fileBrowserTitlePrefix()
|
||||||
|
{
|
||||||
|
return gGerman ? "INI wählen \u2014 " : "Select INI \u2014 ";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string fileBrowserNoIni(const std::string& dir)
|
||||||
|
{
|
||||||
|
if (gGerman)
|
||||||
|
return "Keine .ini-Dateien in " + dir;
|
||||||
|
return "No .ini files found in " + dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* aboutSubtitle()
|
||||||
|
{
|
||||||
|
return gGerman ? "Switchroot INI-Konfiguration\n"
|
||||||
|
"Linux-, Android- und Lakka-OC ohne PC bearbeiten!"
|
||||||
|
: "Switchroot INI Configuration Editor\n"
|
||||||
|
"Edit your Linux, Android and Lakka OC settings without a PC!";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* aboutCopyright()
|
||||||
|
{
|
||||||
|
return gGerman ? "Lizenziert unter GPL-3.0\n"
|
||||||
|
"UI: Borealis\n"
|
||||||
|
"Basierend auf der Arbeit von Switchroot\n"
|
||||||
|
"\u00A9 2026 NiklasCFW"
|
||||||
|
: "Licensed under GPL-3.0\n"
|
||||||
|
"Powered by Borealis UI framework\n"
|
||||||
|
"Based on the work of Switchroot\n"
|
||||||
|
"\u00A9 2026 NiklasCFW";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* aboutLinks()
|
||||||
|
{
|
||||||
|
return gGerman ? "\uE016 NiklasCFW-Dokumentation: Anleitungen und Infos\n"
|
||||||
|
"\uE016 NiklasCFW-Discord: Fragen und Community\n"
|
||||||
|
"\uE016 Quellcode auf GitHub (OmniNX)"
|
||||||
|
: "\uE016 NiklasCFW Docs for setup guides and documentation\n"
|
||||||
|
"\uE016 NiklasCFW's Discord server for support and community\n"
|
||||||
|
"\uE016 Source code available on the OmniNX GitHub";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ocBoolLabel(const std::string& key)
|
||||||
|
{
|
||||||
|
return lookup(OC_BOOL_LABEL, sizeof(OC_BOOL_LABEL) / sizeof(OC_BOOL_LABEL[0]), key, key.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ocFreqLabel(const std::string& key)
|
||||||
|
{
|
||||||
|
return lookup(OC_FREQ_LABEL, sizeof(OC_FREQ_LABEL) / sizeof(OC_FREQ_LABEL[0]), key, key.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ocVoltageLabel(const std::string& key)
|
||||||
|
{
|
||||||
|
return lookup(OC_VOLT_LABEL, sizeof(OC_VOLT_LABEL) / sizeof(OC_VOLT_LABEL[0]), key, key.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace I18n
|
||||||
57
src/i18n.h
Normal file
57
src/i18n.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
SWR INI Tool - Switchroot INI Configuration Editor
|
||||||
|
Copyright (C) 2026 Switchroot
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace I18n
|
||||||
|
{
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
bool isGerman();
|
||||||
|
|
||||||
|
const char* appTitle();
|
||||||
|
|
||||||
|
const char* tabSettings();
|
||||||
|
const char* tabAbout();
|
||||||
|
|
||||||
|
const char* wordOn();
|
||||||
|
const char* wordOff();
|
||||||
|
|
||||||
|
std::string sectionEditLine(const std::string& section, const std::string& path);
|
||||||
|
|
||||||
|
const char* headerToggleOptions();
|
||||||
|
const char* headerFrequencySettings();
|
||||||
|
const char* headerVoltageSettings();
|
||||||
|
const char* headerOther();
|
||||||
|
const char* headerIniFilePaths();
|
||||||
|
const char* headerLinksAndResources();
|
||||||
|
|
||||||
|
const char* errorListItemTitleIni();
|
||||||
|
std::string iniLoadErrorBody(const std::string& path);
|
||||||
|
std::string iniSectionErrorBody(const std::string& path, const std::string& osName);
|
||||||
|
|
||||||
|
const char* notifyConfigSaved();
|
||||||
|
const char* notifyConfigSaveError();
|
||||||
|
const char* notifyPathUpdated();
|
||||||
|
|
||||||
|
const char* settingsIntro();
|
||||||
|
|
||||||
|
const char* pathListDescriptionLakka();
|
||||||
|
|
||||||
|
const char* fileBrowserTitlePrefix();
|
||||||
|
std::string fileBrowserNoIni(const std::string& dir);
|
||||||
|
|
||||||
|
const char* aboutSubtitle();
|
||||||
|
const char* aboutCopyright();
|
||||||
|
const char* aboutLinks();
|
||||||
|
|
||||||
|
const char* ocBoolLabel(const std::string& key);
|
||||||
|
const char* ocFreqLabel(const std::string& key);
|
||||||
|
const char* ocVoltageLabel(const std::string& key);
|
||||||
|
|
||||||
|
} // namespace I18n
|
||||||
35
src/logo.cpp
35
src/logo.cpp
@@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
#include "logo.h"
|
#include "logo.h"
|
||||||
|
|
||||||
Logo::Logo(LogoStyle style)
|
Logo::Logo()
|
||||||
{
|
{
|
||||||
this->logoLabel = new brls::Label(brls::LabelStyle::LIST_ITEM, "SWR", style == LogoStyle::ABOUT);
|
this->logoLabel = new brls::Label(brls::LabelStyle::LIST_ITEM, "SWR", true);
|
||||||
this->logoLabel->setParent(this);
|
this->logoLabel->setParent(this);
|
||||||
|
|
||||||
int logoFont = brls::Application::findFont(LOGO_FONT_NAME);
|
int logoFont = brls::Application::findFont(LOGO_FONT_NAME);
|
||||||
@@ -16,35 +16,18 @@ Logo::Logo(LogoStyle style)
|
|||||||
this->logoLabel->setFont(logoFont);
|
this->logoLabel->setFont(logoFont);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (style == LogoStyle::ABOUT)
|
this->logoLabel->setFontSize(LOGO_ABOUT_FONT_SIZE);
|
||||||
{
|
this->logoLabel->setHorizontalAlign(NVG_ALIGN_CENTER);
|
||||||
this->logoLabel->setFontSize(LOGO_ABOUT_FONT_SIZE);
|
|
||||||
this->logoLabel->setHorizontalAlign(NVG_ALIGN_CENTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style == LogoStyle::HEADER)
|
|
||||||
{
|
|
||||||
this->logoLabel->setFontSize(LOGO_HEADER_FONT_SIZE);
|
|
||||||
this->descLabel = new brls::Label(brls::LabelStyle::LIST_ITEM, "INI Tool");
|
|
||||||
this->descLabel->setParent(this);
|
|
||||||
this->descLabel->setFontSize(LOGO_DESC_FONT_SIZE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logo::~Logo()
|
Logo::~Logo()
|
||||||
{
|
{
|
||||||
delete this->logoLabel;
|
delete this->logoLabel;
|
||||||
|
|
||||||
if (this->descLabel)
|
|
||||||
delete this->descLabel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logo::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx)
|
void Logo::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx)
|
||||||
{
|
{
|
||||||
this->logoLabel->frame(ctx);
|
this->logoLabel->frame(ctx);
|
||||||
|
|
||||||
if (this->descLabel)
|
|
||||||
this->descLabel->frame(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logo::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash)
|
void Logo::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash)
|
||||||
@@ -52,14 +35,4 @@ void Logo::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash)
|
|||||||
this->logoLabel->setBoundaries(this->x, this->y + LOGO_OFFSET, this->width, this->height);
|
this->logoLabel->setBoundaries(this->x, this->y + LOGO_OFFSET, this->width, this->height);
|
||||||
this->logoLabel->layout(vg, style, stash);
|
this->logoLabel->layout(vg, style, stash);
|
||||||
this->height = this->logoLabel->getHeight();
|
this->height = this->logoLabel->getHeight();
|
||||||
|
|
||||||
if (this->descLabel)
|
|
||||||
{
|
|
||||||
this->descLabel->layout(vg, style, stash);
|
|
||||||
this->descLabel->setBoundaries(
|
|
||||||
this->x + LOGO_HEADER_SPACING + this->logoLabel->getWidth(),
|
|
||||||
this->y + style->AppletFrame.titleOffset - 1,
|
|
||||||
this->descLabel->getWidth(),
|
|
||||||
height);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/logo.h
12
src/logo.h
@@ -9,30 +9,20 @@
|
|||||||
|
|
||||||
#define APP_ASSET(p) APP_RESOURCES p
|
#define APP_ASSET(p) APP_RESOURCES p
|
||||||
|
|
||||||
enum class LogoStyle
|
|
||||||
{
|
|
||||||
HEADER = 0,
|
|
||||||
ABOUT
|
|
||||||
};
|
|
||||||
|
|
||||||
#define LOGO_FONT_NAME "logo"
|
#define LOGO_FONT_NAME "logo"
|
||||||
#define LOGO_FONT_PATH APP_ASSET("fira/FiraSans-Medium-rnx.ttf")
|
#define LOGO_FONT_PATH APP_ASSET("fira/FiraSans-Medium-rnx.ttf")
|
||||||
|
|
||||||
#define LOGO_HEADER_FONT_SIZE 45
|
|
||||||
#define LOGO_HEADER_SPACING 12
|
|
||||||
#define LOGO_ABOUT_FONT_SIZE 55
|
#define LOGO_ABOUT_FONT_SIZE 55
|
||||||
#define LOGO_DESC_FONT_SIZE 28
|
|
||||||
#define LOGO_OFFSET 2
|
#define LOGO_OFFSET 2
|
||||||
|
|
||||||
class Logo : public brls::View
|
class Logo : public brls::View
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
brls::Label* logoLabel = nullptr;
|
brls::Label* logoLabel = nullptr;
|
||||||
brls::Label* descLabel = nullptr;
|
|
||||||
void layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash);
|
void layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash);
|
||||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) override;
|
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Logo(LogoStyle style);
|
Logo();
|
||||||
virtual ~Logo();
|
virtual ~Logo();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,11 +17,14 @@
|
|||||||
#include "main_frame.h"
|
#include "main_frame.h"
|
||||||
#include "logo.h"
|
#include "logo.h"
|
||||||
#include "app_config.h"
|
#include "app_config.h"
|
||||||
|
#include "i18n.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
I18n::init();
|
||||||
|
|
||||||
// Init the app
|
// Init the app
|
||||||
if (!brls::Application::init("SWR INI Tool"))
|
if (!brls::Application::init(I18n::appTitle()))
|
||||||
{
|
{
|
||||||
brls::Logger::error("Unable to init Borealis application");
|
brls::Logger::error("Unable to init Borealis application");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|||||||
@@ -8,8 +8,9 @@
|
|||||||
#include "os_config_tab.h"
|
#include "os_config_tab.h"
|
||||||
#include "settings_tab.h"
|
#include "settings_tab.h"
|
||||||
#include "about_tab.h"
|
#include "about_tab.h"
|
||||||
#include "logo.h"
|
|
||||||
#include "app_config.h"
|
#include "app_config.h"
|
||||||
|
#include "i18n.h"
|
||||||
|
#include "logo.h"
|
||||||
|
|
||||||
OsConfigTab* MainFrame::osTabs[(int)OsTarget::COUNT] = {};
|
OsConfigTab* MainFrame::osTabs[(int)OsTarget::COUNT] = {};
|
||||||
|
|
||||||
@@ -17,8 +18,10 @@ MainFrame::MainFrame() : TabFrame()
|
|||||||
{
|
{
|
||||||
AppConfig& cfg = AppConfig::get();
|
AppConfig& cfg = AppConfig::get();
|
||||||
|
|
||||||
// Header logo
|
this->setTitle(I18n::appTitle());
|
||||||
this->setIcon(new Logo(LogoStyle::HEADER));
|
brls::Image* headerIcon = new brls::Image(APP_ASSET("gui_icon.png"));
|
||||||
|
headerIcon->setScaleType(brls::ImageScaleType::FIT);
|
||||||
|
this->setIcon(headerIcon);
|
||||||
|
|
||||||
// OS configuration tabs — paths from config
|
// OS configuration tabs — paths from config
|
||||||
osTabs[(int)OsTarget::ANDROID] = new OsConfigTab("Android", cfg.getPath(OsTarget::ANDROID));
|
osTabs[(int)OsTarget::ANDROID] = new OsConfigTab("Android", cfg.getPath(OsTarget::ANDROID));
|
||||||
@@ -28,11 +31,11 @@ MainFrame::MainFrame() : TabFrame()
|
|||||||
this->addTab("Android", osTabs[(int)OsTarget::ANDROID]);
|
this->addTab("Android", osTabs[(int)OsTarget::ANDROID]);
|
||||||
this->addTab("Linux", osTabs[(int)OsTarget::LINUX]);
|
this->addTab("Linux", osTabs[(int)OsTarget::LINUX]);
|
||||||
this->addTab("Lakka", osTabs[(int)OsTarget::LAKKA]);
|
this->addTab("Lakka", osTabs[(int)OsTarget::LAKKA]);
|
||||||
this->addTab("Settings", new SettingsTab());
|
this->addTab(I18n::tabSettings(), new SettingsTab());
|
||||||
|
|
||||||
this->addSeparator();
|
this->addSeparator();
|
||||||
|
|
||||||
this->addTab("About", new AboutTab());
|
this->addTab(I18n::tabAbout(), new AboutTab());
|
||||||
}
|
}
|
||||||
|
|
||||||
MainFrame::~MainFrame()
|
MainFrame::~MainFrame()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "os_config_tab.h"
|
#include "os_config_tab.h"
|
||||||
|
#include "i18n.h"
|
||||||
#include "oc_defs.h"
|
#include "oc_defs.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -13,18 +14,14 @@ OsConfigTab::OsConfigTab(const std::string& osName, const std::string& iniPath)
|
|||||||
{
|
{
|
||||||
if (!this->ini.load(iniPath))
|
if (!this->ini.load(iniPath))
|
||||||
{
|
{
|
||||||
buildErrorUI("Could not load " + iniPath + "\n\n"
|
buildErrorUI(I18n::errorListItemTitleIni(), I18n::iniLoadErrorBody(iniPath));
|
||||||
"Make sure the INI file exists at the expected path.\n"
|
|
||||||
"You can configure paths in the Settings tab.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->osSection = this->ini.findOsSection();
|
this->osSection = this->ini.findOsSection();
|
||||||
if (this->osSection.empty())
|
if (this->osSection.empty())
|
||||||
{
|
{
|
||||||
buildErrorUI("No OS section found in " + iniPath + "\n\n"
|
buildErrorUI(I18n::errorListItemTitleIni(), I18n::iniSectionErrorBody(iniPath, osName));
|
||||||
"The INI file should contain a section like\n"
|
|
||||||
"[" + osName + " OC] with your configuration.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,30 +38,26 @@ void OsConfigTab::reload(const std::string& newIniPath)
|
|||||||
|
|
||||||
if (!this->ini.load(iniPath))
|
if (!this->ini.load(iniPath))
|
||||||
{
|
{
|
||||||
buildErrorUI("Could not load " + iniPath + "\n\n"
|
buildErrorUI(I18n::errorListItemTitleIni(), I18n::iniLoadErrorBody(iniPath));
|
||||||
"Make sure the INI file exists at the expected path.\n"
|
|
||||||
"You can configure paths in the Settings tab.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->osSection = this->ini.findOsSection();
|
this->osSection = this->ini.findOsSection();
|
||||||
if (this->osSection.empty())
|
if (this->osSection.empty())
|
||||||
{
|
{
|
||||||
buildErrorUI("No OS section found in " + iniPath + "\n\n"
|
buildErrorUI(I18n::errorListItemTitleIni(), I18n::iniSectionErrorBody(iniPath, osName));
|
||||||
"The INI file should contain a section like\n"
|
|
||||||
"[" + osName + " OC] with your configuration.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buildUI();
|
buildUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OsConfigTab::buildErrorUI(const std::string& message)
|
void OsConfigTab::buildErrorUI(const std::string& title, const std::string& message)
|
||||||
{
|
{
|
||||||
this->setSpacing(15);
|
this->setSpacing(15);
|
||||||
|
|
||||||
// Use a ListItem (focusable) so borealis doesn't crash on controller nav
|
// Use a ListItem (focusable) so borealis doesn't crash on controller nav
|
||||||
brls::ListItem *errorItem = new brls::ListItem("\uE150 INI file not found", message);
|
brls::ListItem *errorItem = new brls::ListItem(title, message);
|
||||||
this->addView(errorItem);
|
this->addView(errorItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,51 +69,44 @@ void OsConfigTab::buildUI()
|
|||||||
// Section name info
|
// Section name info
|
||||||
brls::Label *sectionInfo = new brls::Label(
|
brls::Label *sectionInfo = new brls::Label(
|
||||||
brls::LabelStyle::DESCRIPTION,
|
brls::LabelStyle::DESCRIPTION,
|
||||||
"Editing section [" + this->osSection + "] from " + this->iniPath,
|
I18n::sectionEditLine(this->osSection, this->iniPath),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
this->addView(sectionInfo);
|
this->addView(sectionInfo);
|
||||||
|
|
||||||
// ── Toggle Options ──
|
// ── Toggle Options ──
|
||||||
this->addView(new brls::Header("Toggle Options"));
|
this->addView(new brls::Header(I18n::headerToggleOptions()));
|
||||||
|
|
||||||
for (const auto& def : OC_BOOL_KEYS)
|
for (const auto& def : OC_BOOL_KEYS)
|
||||||
{
|
{
|
||||||
if (this->ini.hasKey(this->osSection, def.key))
|
bool val = this->ini.getBool(this->osSection, def.key, false);
|
||||||
{
|
addBooleanToggle(I18n::ocBoolLabel(def.key), "", def.key, val);
|
||||||
bool val = this->ini.getBool(this->osSection, def.key);
|
|
||||||
addBooleanToggle(def.label, "", def.key, val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Frequency Settings ──
|
// ── Frequency Settings ──
|
||||||
brls::Rectangle* spacer1 = new brls::Rectangle(nvgRGBA(0, 0, 0, 0));
|
brls::Rectangle* spacer1 = new brls::Rectangle(nvgRGBA(0, 0, 0, 0));
|
||||||
spacer1->setHeight(30);
|
spacer1->setHeight(30);
|
||||||
this->addView(spacer1);
|
this->addView(spacer1);
|
||||||
this->addView(new brls::Header("Frequency Settings"));
|
this->addView(new brls::Header(I18n::headerFrequencySettings()));
|
||||||
|
|
||||||
for (const auto& def : OC_FREQ_KEYS)
|
for (const auto& def : OC_FREQ_KEYS)
|
||||||
{
|
{
|
||||||
if (this->ini.hasKey(this->osSection, def.key))
|
int defVal = def.options.empty() ? 0 : (int)def.options.front();
|
||||||
{
|
uint32_t val = (uint32_t)this->ini.getInt(this->osSection, def.key, defVal);
|
||||||
uint32_t val = (uint32_t)this->ini.getInt(this->osSection, def.key, 0);
|
addFreqDropdown(I18n::ocFreqLabel(def.key), "", def.key, val, def.options);
|
||||||
addFreqDropdown(def.label, "", def.key, val, def.options);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Voltage Settings ──
|
// ── Voltage Settings ──
|
||||||
brls::Rectangle* spacer2 = new brls::Rectangle(nvgRGBA(0, 0, 0, 0));
|
brls::Rectangle* spacer2 = new brls::Rectangle(nvgRGBA(0, 0, 0, 0));
|
||||||
spacer2->setHeight(30);
|
spacer2->setHeight(30);
|
||||||
this->addView(spacer2);
|
this->addView(spacer2);
|
||||||
this->addView(new brls::Header("Voltage Settings"));
|
this->addView(new brls::Header(I18n::headerVoltageSettings()));
|
||||||
|
|
||||||
for (const auto& def : OC_VOLTAGE_KEYS)
|
for (const auto& def : OC_VOLTAGE_KEYS)
|
||||||
{
|
{
|
||||||
if (this->ini.hasKey(this->osSection, def.key))
|
int defVal = def.options.empty() ? 0 : (int)def.options.front();
|
||||||
{
|
uint32_t val = (uint32_t)this->ini.getInt(this->osSection, def.key, defVal);
|
||||||
uint32_t val = (uint32_t)this->ini.getInt(this->osSection, def.key, 0);
|
addVoltageDropdown(I18n::ocVoltageLabel(def.key), "", def.key, val, def.options);
|
||||||
addVoltageDropdown(def.label, "", def.key, val, def.options);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Other Keys (read-only info) ──
|
// ── Other Keys (read-only info) ──
|
||||||
@@ -148,7 +134,7 @@ void OsConfigTab::buildUI()
|
|||||||
brls::Rectangle* spacerOther = new brls::Rectangle(nvgRGBA(0, 0, 0, 0));
|
brls::Rectangle* spacerOther = new brls::Rectangle(nvgRGBA(0, 0, 0, 0));
|
||||||
spacerOther->setHeight(30);
|
spacerOther->setHeight(30);
|
||||||
this->addView(spacerOther);
|
this->addView(spacerOther);
|
||||||
this->addView(new brls::Header("Other"));
|
this->addView(new brls::Header(I18n::headerOther()));
|
||||||
hasOtherKeys = true;
|
hasOtherKeys = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,11 +149,11 @@ void OsConfigTab::saveAndNotify()
|
|||||||
{
|
{
|
||||||
if (this->ini.save())
|
if (this->ini.save())
|
||||||
{
|
{
|
||||||
brls::Application::notify("\uE14B Configuration saved");
|
brls::Application::notify(I18n::notifyConfigSaved());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
brls::Application::notify("\uE150 Error saving configuration!");
|
brls::Application::notify(I18n::notifyConfigSaveError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +161,7 @@ void OsConfigTab::addBooleanToggle(const std::string& label, const std::string&
|
|||||||
const std::string& key, bool currentValue)
|
const std::string& key, bool currentValue)
|
||||||
{
|
{
|
||||||
brls::ToggleListItem *toggle = new brls::ToggleListItem(
|
brls::ToggleListItem *toggle = new brls::ToggleListItem(
|
||||||
label, currentValue, description, "ON", "OFF"
|
label, currentValue, description, I18n::wordOn(), I18n::wordOff()
|
||||||
);
|
);
|
||||||
|
|
||||||
std::string keyCopy = key;
|
std::string keyCopy = key;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ private:
|
|||||||
std::string osSection;
|
std::string osSection;
|
||||||
|
|
||||||
void buildUI();
|
void buildUI();
|
||||||
void buildErrorUI(const std::string& message);
|
void buildErrorUI(const std::string& title, const std::string& message);
|
||||||
void saveAndNotify();
|
void saveAndNotify();
|
||||||
|
|
||||||
// Create a toggle for a boolean key
|
// Create a toggle for a boolean key
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "settings_tab.h"
|
#include "settings_tab.h"
|
||||||
#include "file_browser.h"
|
#include "file_browser.h"
|
||||||
|
#include "i18n.h"
|
||||||
#include "main_frame.h"
|
#include "main_frame.h"
|
||||||
#include "os_config_tab.h"
|
#include "os_config_tab.h"
|
||||||
|
|
||||||
@@ -15,14 +16,13 @@ SettingsTab::SettingsTab()
|
|||||||
|
|
||||||
brls::Label *info = new brls::Label(
|
brls::Label *info = new brls::Label(
|
||||||
brls::LabelStyle::DESCRIPTION,
|
brls::LabelStyle::DESCRIPTION,
|
||||||
"Select which INI file each OS tab reads and writes.\n"
|
I18n::settingsIntro(),
|
||||||
"Changes take effect immediately.",
|
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
this->addView(info);
|
this->addView(info);
|
||||||
|
|
||||||
// ── INI File Paths ──
|
// ── INI File Paths ──
|
||||||
this->addView(new brls::Header("INI File Paths"));
|
this->addView(new brls::Header(I18n::headerIniFilePaths()));
|
||||||
|
|
||||||
addPathItem(OsTarget::ANDROID);
|
addPathItem(OsTarget::ANDROID);
|
||||||
addPathItem(OsTarget::LINUX);
|
addPathItem(OsTarget::LINUX);
|
||||||
@@ -35,7 +35,7 @@ void SettingsTab::addPathItem(OsTarget target)
|
|||||||
std::string currentPath = cfg.getPath(target);
|
std::string currentPath = cfg.getPath(target);
|
||||||
std::string label = std::string(AppConfig::getLabel(target)) + " INI";
|
std::string label = std::string(AppConfig::getLabel(target)) + " INI";
|
||||||
|
|
||||||
std::string description = (target == OsTarget::LAKKA) ? "Tap to browse for an INI file" : "";
|
std::string description = (target == OsTarget::LAKKA) ? I18n::pathListDescriptionLakka() : "";
|
||||||
brls::ListItem* item = new brls::ListItem(label, description);
|
brls::ListItem* item = new brls::ListItem(label, description);
|
||||||
item->setValue(currentPath);
|
item->setValue(currentPath);
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ void SettingsTab::addPathItem(OsTarget target)
|
|||||||
if (tab)
|
if (tab)
|
||||||
tab->reload(selectedPath);
|
tab->reload(selectedPath);
|
||||||
|
|
||||||
brls::Application::notify("\uE14B Path updated");
|
brls::Application::notify(I18n::notifyPathUpdated());
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user