hocclk: improve ui

yes i did vibecode this, no i don't care
This commit is contained in:
souldbminersmwc
2026-05-26 19:05:53 -04:00
parent 13f422fa29
commit 6b26aa5574
14 changed files with 101 additions and 40 deletions

View File

@@ -1,10 +0,0 @@
{
"permissions": {
"allow": [
"PowerShell(\\(Get-Item \"c:\\\\Users\\\\sould\\\\Documents\\\\GitHub\\\\Horizon-OC\\\\Source\\\\hoc-clk\\\\assets\\\\hoc.rgba\"\\).Length)",
"PowerShell(python --version)",
"PowerShell(magick --version 2>$null)",
"PowerShell(convert --version 2>$null)"
]
}
}

View File

@@ -28,20 +28,21 @@
#pragma once #pragma once
#include <tesla.hpp> #include <tesla.hpp>
#include "../gui/base_gui.h"
class BaseGui;
static constexpr u16 HOC_HEADER_HEIGHT = 287;
// Bottom edge of the drawn box: 106 + TOP_Y_OFFSET(15) + 156 = 277
static constexpr u16 HOC_BOX_BOTTOM = 277;
class BaseFrame : public tsl::elm::HeaderOverlayFrame class BaseFrame : public tsl::elm::HeaderOverlayFrame
{ {
public: public:
BaseFrame(BaseGui* gui) : tsl::elm::HeaderOverlayFrame(234) { BaseFrame(BaseGui* gui, u16 headerHeight = HOC_HEADER_HEIGHT) : tsl::elm::HeaderOverlayFrame(headerHeight) {
this->gui = gui; this->gui = gui;
} }
void draw(tsl::gfx::Renderer* renderer) override void draw(tsl::gfx::Renderer* renderer) override;
{
tsl::elm::HeaderOverlayFrame::draw(renderer);
this->gui->preDraw(renderer);
}
protected: protected:
BaseGui* gui; BaseGui* gui;

View File

@@ -25,6 +25,7 @@
*/ */
#include "ult_ext.h"
#include "app_profile_gui.h" #include "app_profile_gui.h"
#include "../format.h" #include "../format.h"

View File

@@ -25,9 +25,13 @@
*/ */
#include "base_gui.h" #include "base_gui.h"
#include "../elements/base_frame.h" #include "../elements/base_frame.h"
void BaseFrame::draw(tsl::gfx::Renderer* renderer) {
tsl::elm::HeaderOverlayFrame::draw(renderer);
this->gui->preDraw(renderer);
}
#include <tesla.hpp> #include <tesla.hpp>
#include <math.h> #include <math.h>
@@ -142,11 +146,27 @@ void BaseGui::preDraw(tsl::gfx::Renderer* renderer) {
STATIC_TEAL, STATIC_TEAL,
false false
); );
static const std::string versionStr = "Version " + getVersionString();
static constexpr tsl::Color versionColor(9, 9, 9, 15);
static constexpr s32 vx = LOGO_TEXT_X + 15;
static constexpr s32 vy = TEXT_Y + 18;
static constexpr s32 fs = 15;
static constexpr s32 skew = 3;
static constexpr s32 passes = 10;
for (s32 i = 0; i < passes; i++) {
s32 sliceY = (vy - fs) + i * fs / passes;
s32 sliceH = fs / passes + 1;
s32 xOff = skew - (skew * i / (passes - 1));
renderer->enableScissoring(0, sliceY, tsl::cfg::FramebufferWidth, sliceH);
renderer->drawString(versionStr.c_str(), false, vx + xOff, vy, fs, versionColor);
renderer->disableScissoring();
}
} }
tsl::elm::Element* BaseGui::createUI() tsl::elm::Element* BaseGui::createUI()
{ {
BaseFrame* rootFrame = new BaseFrame(this); BaseFrame* rootFrame = new BaseFrame(this, this->headerHeight());
rootFrame->setContent(this->baseUI()); rootFrame->setContent(this->baseUI());
return rootFrame; return rootFrame;
} }

View File

@@ -28,6 +28,7 @@
#pragma once #pragma once
#include <tesla.hpp> #include <tesla.hpp>
#include "../elements/base_frame.h"
#include <fstream> #include <fstream>
#include <vector> #include <vector>
#include <string> #include <string>
@@ -46,6 +47,7 @@ class BaseGui : public tsl::Gui
tsl::elm::Element* createUI() override; tsl::elm::Element* createUI() override;
virtual tsl::elm::Element* baseUI() = 0; virtual tsl::elm::Element* baseUI() = 0;
virtual void refresh() {} virtual void refresh() {}
virtual u16 headerHeight() const { return HOC_HEADER_HEIGHT; }
private: private:
}; };

View File

@@ -29,6 +29,8 @@
#include "fatal_gui.h" #include "fatal_gui.h"
#include "../format.h" #include "../format.h"
#define TOP_Y_OFFSET 15
// Cache hardware model to avoid repeated syscalls // Cache hardware model to avoid repeated syscalls
BaseMenuGui::BaseMenuGui() : tempColors{ tsl::Color(0), tsl::Color(0), tsl::Color(0), tsl::Color(0), tsl::Color(0), tsl::Color(0), tsl::Color(0), } BaseMenuGui::BaseMenuGui() : tempColors{ tsl::Color(0), tsl::Color(0), tsl::Color(0), tsl::Color(0), tsl::Color(0), tsl::Color(0), tsl::Color(0), }
@@ -77,10 +79,10 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
static u32 maxProfileValueWidth = renderer->getTextDimensions("USB Charger", false, SMALL_TEXT_SIZE).first; // longest word static u32 maxProfileValueWidth = renderer->getTextDimensions("USB Charger", false, SMALL_TEXT_SIZE).first; // longest word
u32 y = 91; u32 y = 91 + TOP_Y_OFFSET;
// === TOP SECTION === // === TOP SECTION ===
renderer->drawRoundedRect(14, 70-1, 420, 30+2, 12.0f, renderer->aWithOpacity(tsl::tableBGColor)); renderer->drawRoundedRect(14, 70-1 + TOP_Y_OFFSET, 420, 30+2, 12.0f, renderer->aWithOpacity(tsl::tableBGColor));
// App ID - use pre-formatted string // App ID - use pre-formatted string
renderer->drawString(labels[0], false, positions[0], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); renderer->drawString(labels[0], false, positions[0], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
@@ -93,7 +95,7 @@ void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
y += 38; // Direct assignment instead of += 38 y += 38; // Direct assignment instead of += 38
// === MAIN DATA SECTION === // === MAIN DATA SECTION ===
renderer->drawRoundedRect(14, 106, 420, 156, 10.0f, renderer->aWithOpacity(tsl::tableBGColor)); renderer->drawRoundedRect(14, 106 + TOP_Y_OFFSET, 420, 156, 10.0f, renderer->aWithOpacity(tsl::tableBGColor));
// === FREQUENCY SECTION === // === FREQUENCY SECTION ===
// Labels first (better cache locality) // Labels first (better cache locality)
@@ -348,7 +350,6 @@ void BaseMenuGui::refresh()
tsl::elm::Element* BaseMenuGui::baseUI() tsl::elm::Element* BaseMenuGui::baseUI()
{ {
auto* list = new tsl::elm::List(); auto* list = new tsl::elm::List();
list->addItem(new tsl::elm::CustomDrawer([](tsl::gfx::Renderer*, s32, s32, s32, s32) {}), 35); // add a bit of space
this->listElement = list; this->listElement = list;
this->listUI(); this->listUI();

View File

@@ -84,6 +84,7 @@ class BaseMenuGui : public BaseGui
tsl::elm::Element* baseUI() override; tsl::elm::Element* baseUI() override;
void refresh() override; void refresh() override;
virtual void listUI() = 0; virtual void listUI() = 0;
u16 headerHeight() const override { return HOC_BOX_BOTTOM + 9; }
private: private:
char displayStrings[48][32]; // Pre-formatted display strings char displayStrings[48][32]; // Pre-formatted display strings

View File

@@ -25,6 +25,7 @@
*/ */
#include "ult_ext.h"
#include "freq_choice_gui.h" #include "freq_choice_gui.h"
#include "../format.h" #include "../format.h"

View File

@@ -16,6 +16,7 @@
* *
*/ */
#include "ult_ext.h"
#include "../format.h" #include "../format.h"
#include "fatal_gui.h" #include "fatal_gui.h"
#include "global_override_gui.h" #include "global_override_gui.h"

View File

@@ -32,6 +32,14 @@
#include "global_override_gui.h" #include "global_override_gui.h"
#include "misc_gui.h" #include "misc_gui.h"
#include "about_gui.h" #include "about_gui.h"
#include "ult_ext.h"
tsl::elm::Element* MainGui::baseUI() {
auto* list = new BoxClippedList();
this->listElement = list;
this->listUI();
return list;
}
void MainGui::listUI() void MainGui::listUI()
{ {

View File

@@ -34,6 +34,8 @@ class MainGui : public BaseMenuGui
public: public:
MainGui() {} MainGui() {}
~MainGui() {} ~MainGui() {}
tsl::elm::Element* baseUI() override;
void listUI() override; void listUI() override;
void refresh() override; void refresh() override;
u16 headerHeight() const override { return HOC_HEADER_HEIGHT - 25; }
}; };

View File

@@ -17,6 +17,7 @@
*/ */
#include "misc_gui.h" #include "misc_gui.h"
#include "ult_ext.h"
#include "fatal_gui.h" #include "fatal_gui.h"
#include "config_info_strings.h" #include "config_info_strings.h"
#include "../format.h" #include "../format.h"
@@ -547,7 +548,7 @@ void MiscGui::listUI()
ValueThresholds thresholdsDisabled(0, 0); ValueThresholds thresholdsDisabled(0, 0);
std::vector<NamedValue> noNamedValues = {}; std::vector<NamedValue> noNamedValues = {};
this->listElement->addItem(new tsl::elm::CategoryHeader("Settings")); this->listElement->addItem(new CompactCategoryHeader("Settings"));
tsl::elm::CustomDrawer* rebootSetWarning = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) { tsl::elm::CustomDrawer* rebootSetWarning = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
renderer->drawString("\uE150 Settings marked in blue", false, x + 20, y + 30, 18, tsl::style::color::ColorText); renderer->drawString("\uE150 Settings marked in blue", false, x + 20, y + 30, 18, tsl::style::color::ColorText);
@@ -659,7 +660,7 @@ protected:
void listUI() override { void listUI() override {
Result rc = hocclkIpcGetConfigValues(this->configList); Result rc = hocclkIpcGetConfigValues(this->configList);
if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; } if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; }
this->listElement->addItem(new tsl::elm::CategoryHeader("General Settings")); this->listElement->addItem(new CompactCategoryHeader("General Settings"));
ValueThresholds thresholdsDisabled(0, 0); ValueThresholds thresholdsDisabled(0, 0);
std::vector<NamedValue> ramVoltDispModes = { std::vector<NamedValue> ramVoltDispModes = {
@@ -719,7 +720,7 @@ protected:
void listUI() override { void listUI() override {
Result rc = hocclkIpcGetConfigValues(this->configList); Result rc = hocclkIpcGetConfigValues(this->configList);
if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; } if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; }
this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental Settings")); this->listElement->addItem(new CompactCategoryHeader("Experimental Settings"));
ValueThresholds thresholdsDisabled(0, 0); ValueThresholds thresholdsDisabled(0, 0);
if(IsMariko()) { if(IsMariko()) {
addConfigToggle(HocClkConfigValue_MarikoMiddleFreqs, nullptr, true); addConfigToggle(HocClkConfigValue_MarikoMiddleFreqs, nullptr, true);
@@ -855,7 +856,7 @@ protected:
void listUI() override { void listUI() override {
Result rc = hocclkIpcGetConfigValues(this->configList); Result rc = hocclkIpcGetConfigValues(this->configList);
if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; } if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; }
this->listElement->addItem(new tsl::elm::CategoryHeader("Governor Settings")); this->listElement->addItem(new CompactCategoryHeader("Governor Settings"));
ValueThresholds thresholdsDisabled(0, 0); ValueThresholds thresholdsDisabled(0, 0);
std::vector<NamedValue> GovernorMinHz = { std::vector<NamedValue> GovernorMinHz = {
@@ -896,7 +897,7 @@ protected:
if(!this->context) if(!this->context)
return; return;
this->listElement->addItem(new tsl::elm::CategoryHeader("Display Settings")); this->listElement->addItem(new CompactCategoryHeader("Display Settings"));
addConfigToggle(HocClkConfigValue_OverwriteRefreshRate, nullptr); addConfigToggle(HocClkConfigValue_OverwriteRefreshRate, nullptr);
if(!this->context->isUsingRetroSuper) { if(!this->context->isUsingRetroSuper) {
tsl::elm::CustomDrawer* warningText = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) { tsl::elm::CustomDrawer* warningText = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
@@ -951,7 +952,7 @@ protected:
void listUI() override { void listUI() override {
Result rc = hocclkIpcGetConfigValues(this->configList); Result rc = hocclkIpcGetConfigValues(this->configList);
if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; } if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; }
this->listElement->addItem(new tsl::elm::CategoryHeader("Safety Settings")); this->listElement->addItem(new CompactCategoryHeader("Safety Settings"));
addConfigToggle(HocClkConfigValue_UncappedClocks, nullptr); addConfigToggle(HocClkConfigValue_UncappedClocks, nullptr);
addConfigToggle(HocClkConfigValue_ThermalThrottle, nullptr); addConfigToggle(HocClkConfigValue_ThermalThrottle, nullptr);
addConfigToggle(HocClkConfigValue_HandheldTDP, nullptr); addConfigToggle(HocClkConfigValue_HandheldTDP, nullptr);
@@ -1011,7 +1012,7 @@ protected:
this->listElement->addItem(new tsl::elm::CategoryHeader("RAM Settings")); this->listElement->addItem(new CompactCategoryHeader("RAM Settings"));
addMappedConfigTrackbar(KipConfigValue_emcDvbShift, "DVB Shift", addMappedConfigTrackbar(KipConfigValue_emcDvbShift, "DVB Shift",
{0xFFFFFFFCu, 0xFFFFFFFDu, 0xFFFFFFFEu, 0xFFFFFFFFu, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u}, {0xFFFFFFFCu, 0xFFFFFFFDu, 0xFFFFFFFEu, 0xFFFFFFFFu, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u},
@@ -1251,7 +1252,7 @@ protected:
void listUI() override { void listUI() override {
Result rc = hocclkIpcGetConfigValues(this->configList); Result rc = hocclkIpcGetConfigValues(this->configList);
if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; } if (R_FAILED(rc)) [[unlikely]] { FatalGui::openWithResultCode("hocclkIpcGetConfigValues", rc); return; }
this->listElement->addItem(new tsl::elm::CategoryHeader("Memory Timings")); this->listElement->addItem(new CompactCategoryHeader("Memory Timings"));
addConfigTrackbar(KipConfigValue_t1_tRCD, "t1 tRCD", ValueRange(0, 7, 1)); addConfigTrackbar(KipConfigValue_t1_tRCD, "t1 tRCD", ValueRange(0, 7, 1));
addConfigTrackbar(KipConfigValue_t2_tRP, "t2 tRP", ValueRange(0, 7, 1)); addConfigTrackbar(KipConfigValue_t2_tRP, "t2 tRP", ValueRange(0, 7, 1));
@@ -1332,7 +1333,7 @@ protected:
} }
ValueThresholds thresholdsDisabled(0, 0); ValueThresholds thresholdsDisabled(0, 0);
this->listElement->addItem(new tsl::elm::CategoryHeader("Advanced")); this->listElement->addItem(new CompactCategoryHeader("Advanced"));
if(IsMariko()) { if(IsMariko()) {
// tBreak / low-high timing graph (live, reads config each frame) // tBreak / low-high timing graph (live, reads config each frame)
{ {
@@ -1483,6 +1484,13 @@ class RamLatenciesSubmenuGui : public MiscGui {
public: public:
RamLatenciesSubmenuGui() { } RamLatenciesSubmenuGui() { }
tsl::elm::Element* baseUI() override {
auto* list = new TopAnchoredList();
this->listElement = list;
this->listUI();
return list;
}
protected: protected:
void normalizeLatencies(const HocClkConfigValue keysArr[4]) { void normalizeLatencies(const HocClkConfigValue keysArr[4]) {
@@ -1729,6 +1737,8 @@ protected:
this->configNamedValues[thisKey] = buildNamedValues(tierIdx); this->configNamedValues[thisKey] = buildNamedValues(tierIdx);
}; };
this->listElement->addItem(new CompactCategoryHeader("Latency Graph"));
{ {
HocClkConfigValueList* cfgPtr = this->configList; HocClkConfigValueList* cfgPtr = this->configList;
bool mariko = IsMariko(); bool mariko = IsMariko();
@@ -1764,7 +1774,7 @@ protected:
const s32 gx = x + 52; const s32 gx = x + 52;
const s32 gw = w - 64; const s32 gw = w - 64;
const s32 gy = y + 14; const s32 gy = y + 14;
const s32 gh = 72; const s32 gh = 54;
const s32 th = gh / 3; const s32 th = gh / 3;
const s32 axisY = gy + gh; const s32 axisY = gy + gh;
@@ -1916,7 +1926,7 @@ protected:
} }
} }
s32 ly = y + h - 14; const s32 ly = axisY + 46;
renderer->drawRect(gx, ly, 14, 3, cRead); renderer->drawRect(gx, ly, 14, 3, cRead);
renderer->drawString("Read", false, gx + 17, ly + 5, 12, cRead); renderer->drawString("Read", false, gx + 17, ly + 5, 12, cRead);
renderer->drawRect(gx + 60, ly, 14, 3, cWrite); renderer->drawRect(gx + 60, ly, 14, 3, cWrite);
@@ -1925,15 +1935,15 @@ protected:
renderer->drawString("Same", false, gx + 142, ly + 5, 12, cMerge); renderer->drawString("Same", false, gx + 142, ly + 5, 12, cMerge);
} }
); );
graph->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 165); graph->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, 150);
this->listElement->addItem(graph); this->listElement->addItem(graph);
} }
this->listElement->addItem(new tsl::elm::CategoryHeader("Read Latency")); this->listElement->addItem(new CompactCategoryHeader("Read Latency"));
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
addLatencyRow(kTierLabels[i], i, kLatencyRKeys); addLatencyRow(kTierLabels[i], i, kLatencyRKeys);
this->listElement->addItem(new tsl::elm::CategoryHeader("Write Latency")); this->listElement->addItem(new CompactCategoryHeader("Write Latency"));
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
addLatencyRow(kTierLabels[i], i, kLatencyWKeys); addLatencyRow(kTierLabels[i], i, kLatencyWKeys);
} }
@@ -1957,7 +1967,7 @@ protected:
ValueThresholds eCpuClockThresholds(1785000, 2091000); ValueThresholds eCpuClockThresholds(1785000, 2091000);
ValueThresholds eCpuClockThresholdsUV(2091000, 2193000); ValueThresholds eCpuClockThresholdsUV(2091000, 2193000);
this->listElement->addItem(new tsl::elm::CategoryHeader("CPU Settings")); this->listElement->addItem(new CompactCategoryHeader("CPU Settings"));
if(IsMariko()) { if(IsMariko()) {
addConfigTrackbar(KipConfigValue_marikoCpuUVLow, "CPU Low UV", ValueRange(0, 8, 1)); addConfigTrackbar(KipConfigValue_marikoCpuUVLow, "CPU Low UV", ValueRange(0, 8, 1));
addConfigTrackbar(KipConfigValue_marikoCpuUVHigh, "CPU High UV", ValueRange(0, 12, 1)); addConfigTrackbar(KipConfigValue_marikoCpuUVHigh, "CPU High UV", ValueRange(0, 12, 1));
@@ -2152,7 +2162,7 @@ protected:
ValueThresholds thresholdsDisabled(0, 0); ValueThresholds thresholdsDisabled(0, 0);
std::vector<NamedValue> noNamedValues = {}; std::vector<NamedValue> noNamedValues = {};
this->listElement->addItem(new tsl::elm::CategoryHeader("GPU Settings")); this->listElement->addItem(new CompactCategoryHeader("GPU Settings"));
std::vector<NamedValue> gpuUvConf = { std::vector<NamedValue> gpuUvConf = {
NamedValue("HiOPT", 0), NamedValue("HiOPT", 0),
@@ -2363,7 +2373,7 @@ protected:
return; return;
} }
this->listElement->addItem(new tsl::elm::CategoryHeader("GPU Custom Table (mV)")); this->listElement->addItem(new CompactCategoryHeader("GPU Custom Table (mV)"));
ValueThresholds MgpuVmaxThresholds(800, 850); ValueThresholds MgpuVmaxThresholds(800, 850);
ValueThresholds EgpuVmaxThresholds(950, 975); ValueThresholds EgpuVmaxThresholds(950, 975);

View File

@@ -17,6 +17,28 @@
#pragma once #pragma once
#include <tesla.hpp> #include <tesla.hpp>
#include "../elements/base_frame.h"
class TopAnchoredList : public tsl::elm::List {
public:
TopAnchoredList() { m_hasSetInitialFocusHack = true; }
};
class BoxClippedList : public tsl::elm::List {
public:
void draw(tsl::gfx::Renderer* renderer) override {
renderer->enableScissoring(0, HOC_BOX_BOTTOM, tsl::cfg::FramebufferWidth, tsl::cfg::FramebufferHeight - HOC_BOX_BOTTOM);
tsl::elm::List::draw(renderer);
renderer->disableScissoring();
}
};
class CompactCategoryHeader : public tsl::elm::CategoryHeader {
public:
CompactCategoryHeader(const std::string& text) : tsl::elm::CategoryHeader(text) {}
void layout(u16 parentX, u16 parentY, u16 parentWidth, u16 parentHeight) override {
this->setBoundaries(this->getX(), this->getY(), this->getWidth(), 33);
}
};
class ImageElement : public tsl::elm::ListItem { class ImageElement : public tsl::elm::ListItem {
private: private:

View File

@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
#include "ult_ext.h"
#include "value_choice_gui.h" #include "value_choice_gui.h"
#include "../format.h" #include "../format.h"
#include "fatal_gui.h" #include "fatal_gui.h"