diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp
index fe16ba51..3a3d9ddb 100644
--- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp
+++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.hpp
@@ -21,7 +21,7 @@
#pragma once
#define CUST_REV 3
-#define KIP_VERSION 230
+#define KIP_VERSION 231
#include "oc_common.hpp"
#include "pcv/pcv_common.hpp"
diff --git a/Source/hoc-clk/overlay/Makefile b/Source/hoc-clk/overlay/Makefile
index 43ce6b94..8ea269b1 100644
--- a/Source/hoc-clk/overlay/Makefile
+++ b/Source/hoc-clk/overlay/Makefile
@@ -39,7 +39,7 @@ include ${TOPDIR}/lib/libultrahand/ultrahand.mk
# version control constants
#---------------------------------------------------------------------------------
#TARGET_VERSION := $(shell git describe --dirty --always --tags)
-APP_VERSION := 2.3.0 # ensure to set KIP_VERSION and CUST_REV in sysmodule Makefile when updating this
+APP_VERSION := 2.3.1 # ensure to set KIP_VERSION and CUST_REV in sysmodule Makefile when updating this
TARGET_VERSION := $(APP_VERSION)
#---------------------------------------------------------------------------------
diff --git a/Source/hoc-clk/overlay/src/ui/gui/config_info_strings.cpp b/Source/hoc-clk/overlay/src/ui/gui/config_info_strings.cpp
new file mode 100644
index 00000000..793d7e75
--- /dev/null
+++ b/Source/hoc-clk/overlay/src/ui/gui/config_info_strings.cpp
@@ -0,0 +1,570 @@
+/*
+ *
+ * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include "config_info_strings.h"
+
+std::vector ConfigInfoStrings(HocClkConfigValue val, bool isMariko, bool isHoag)
+{
+ switch (val)
+ {
+ case HocClkConfigValue_PollingIntervalMs:
+ return {
+ "The interval (in miliseconds) where clocks are applied, tempratures and voltages are polled and logs are written (if enabled).",
+ "Higher values may cause more delay between changing a setting and it taking effect, and lower values may increase sysmodule memory usage",
+ "Default: 300ms"
+ };
+
+ case HocClkConfigValue_RamDisplayUnit:
+ return {
+ "The unit used when displaying RAM frequency values.",
+ "Options:",
+ "- MHz: Megahertz (e.g. 1600 MHz)",
+ "- MT/s: MegaTransfers per second (e.g. 3200 MT/s)",
+ "Default: MHz"
+ };
+
+ case HocClkConfigValue_RAMVoltDisplayMode:
+ return {
+ "The method used to display RAM voltage values.",
+ "Options:",
+ "- VDD2 - Display VDD2 voltage",
+ "- VDDQ - Display VDDQ voltage",
+ "Default: VDD2"
+ };
+
+ case HocClkConfigValue_EnableExperimentalSettings:
+ return {
+ "When enabled, shows settings that are still being tested and may be unstable or not work at all.",
+ "Use with caution and report any issues to the developers."
+ };
+
+ case HocClkConfigValue_MarikoMiddleFreqs:
+ return {
+ "Allows usage of frequencies stepped by 38.4MHz instead of 76.8MHz below 1228MHz GPU clock",
+ "Default: OFF"
+ };
+
+ case HocClkConfigValue_LiveCpuUv:
+ return {
+ "Allows changing CPU undervolt settings without a reboot",
+ "Default: OFF"
+ };
+
+ case HocClkConfigValue_GPUSchedulingMethod:
+ return {
+ "Method used for GPU scheduling override",
+ "Options:",
+ "- INI: override via system_settings.ini",
+ "- NV Service: override via nvservices sysmodule (experimental)",
+ "Default: INI"
+ };
+
+ case HocClkConfigValue_MemoryFrequencyMeasurementMode:
+ return {
+ "How the RAM real frequency is measured",
+ "Options:",
+ "- PLL: Measure from PLLMB and PLLM (more accurate)",
+ "- Actmon: Measure from Actmon (less accurate)",
+ "Default: PLL"
+ };
+
+ case HocClkConfigValue_BatteryChargeCurrent:
+ return {
+ "Overrides the charge current to the battery. Use with caution!",
+ isHoag ? "Default: 1664 mA" : "2048 mA"
+ };
+
+ case HocClkConfigValue_AulaDisplayColorPreset:
+ return {
+ "Current display color preset. Default is Basic",
+ "Options:",
+ "- Saturated: Based on Vivid but over-saturated.",
+ "- Washed: Washed out colors.",
+ "- Basic: Real natural profile.",
+ "- Natural: Not actually natural.. Extra saturation.",
+ "- Vivid: Saturated.",
+ "Default: Do not override"
+ };
+
+ case HocClkConfigValue_CpuGovernorMinimumFreq:
+ return {
+ "The minimum frequency that the CPU governor will allow.",
+ "Default: 612MHz"
+ };
+
+ case HocClkConfigValue_OverwriteRefreshRate:
+ return {
+ "Conrols the avaiability of display refresh rate features.",
+ "When enabled, allows changing the display refresh rate and using display refresh rate related features."
+ };
+
+ case HocClkConfigValue_MaxDisplayClockH:
+ return {
+ "The maximum display clock frequency in handheld mode (in Hz).",
+ "Warning: Changing this value may cause instability or display damage.",
+ "Default: 60 Hz"
+ };
+
+ case HocClkConfigValue_DisplayVoltage:
+ return {
+ "The voltage supplied to the display panel (in mV).",
+ "Warning: Changing this value may cause instability.",
+ "Default: 1200mV"
+ };
+
+ case HocClkConfigValue_UncappedClocks:
+ if(isMariko) {
+ return {
+ "When enabled, disables clock cappings",
+ "Warning: Enabling this may cause damage to your device without a proper undervolt. Use with caution!",
+ "Clock cappings:",
+ "- Handheld:",
+ " - GPU (HiOPT): 614 MHz",
+ " - GPU (HiOPT - 15mV): 691 MHz",
+ " - GPU (High UV): 768 MHz",
+ "- USB Charger",
+ " - GPU (HiOPT): 844 MHz",
+ " - GPU (HiOPT - 15mV): 921 MHz",
+ " - GPU (High UV): 998 MHz",
+ "- PD Charger / Docked:",
+ " - No capping applied",
+ "Default: OFF"
+ };
+ } else {
+ return {
+ "When enabled, disables clock cappings",
+ "Warning: Enabling this may cause damage to your device without a proper undervolt. Use with caution!",
+ "Clock cappings:",
+ "- Handheld:",
+ " - GPU: 460 MHz",
+ " - CPU: 1581 MHz",
+ "- USB Charger",
+ " - GPU: 768 MHz",
+ "- PD Charger / Docked:",
+ " - No capping applied",
+ "Default: OFF"
+ };
+ }
+
+ case HocClkConfigValue_ThermalThrottle:
+ return {
+ "If enabled, Resets to stock clocks after the threshold is applied",
+ "Default: ON",
+ };
+
+ case HocClkConfigValue_HandheldTDP:
+ return {
+ "If enabled, Resets to stock clocks when power consumption is above the threshold in handheld mode",
+ "Default: ON",
+ };
+
+ case HocClkConfigValue_HandheldTDPLimit:
+ case HocClkConfigValue_LiteTDPLimit:
+ return {
+ "The power consumption threshold (in mW) for resetting to stock clocks in handheld mode when Handheld TDP is enabled.",
+ isHoag ? "Default: 6400mW" : "Default: 9600mW"
+ };
+
+ case HocClkConfigValue_ThermalThrottleThreshold:
+ return {
+ "The temperature threshold (in °C) for resetting to stock clocks when Thermal Throttle is enabled.",
+ "Default: 70°C"
+ };
+
+ case KipConfigValue_emcDvbShift:
+ return {
+ "Each level adds/removes 25mV from the SOC Voltage table",
+ "Consoles are bracketed by SoC Speedo. The brackets are as follows:",
+ " - Speedo 1487-1598: Bracket 0",
+ " - Speedo 1598-1709: Bracket 1",
+ " - Speedo 1709-1820: Bracket 2",
+ "SOC Volt Table:",
+ " - 1331/1600MHz tables are not modified",
+ " - 1633-1866MHz:",
+ " - Bracket 0: 700mV",
+ " - Bracket 1: 675mV",
+ " - Bracket 2: 650mV",
+ " - 1900-2133MHz:",
+ " - Bracket 0: 725mV",
+ " - Bracket 1: 700mV",
+ " - Bracket 2: 675mV",
+ " - 2166-2400MHz:",
+ " - Bracket 0: 750mV",
+ " - Bracket 1: 725mV",
+ " - Bracket 2: 700mV",
+ " - 2433-2666MHz:",
+ " - Bracket 0: 850mV",
+ " - Bracket 1: 825mV",
+ " - Bracket 2: 800mV",
+ " - 2700-2933MHz:",
+ " - Bracket 0: 950mV",
+ " - Bracket 1: 925mV",
+ " - Bracket 2: 900mV",
+ " - 2966-3200MHz:",
+ " - Bracket 0: 1050mV",
+ " - Bracket 1: 1025mV",
+ " - Bracket 2: 1000mV",
+ "Default: 0"
+ };
+
+ case KipConfigValue_marikoSocVmax:
+ return {
+ "The maximum available SOC Voltage that the DVB-adjusted table can use",
+ "Default: Do not override"
+ };
+
+ case KipConfigValue_hpMode:
+ return {
+ "When enabled, disables RAM powerdown. Helps with latency significantly",
+ "Default: OFF"
+ };
+
+ case KipConfigValue_commonEmcMemVolt:
+ return {
+ "RAM VDD2 voltage",
+ "Increasing this WILL NOT increase your maximum frequency, but may help with timing reduction.",
+ "Undervolting RAM is pointless and may hurt performance and stability",
+ "Default: 1175 mV"
+ };
+
+ case KipConfigValue_marikoEmcVddqVolt:
+ return {
+ "RAM VDDQ voltage",
+ "Increasing this may help, but the default value is usually good enough.",
+ "Undervolting RAM is pointless and may hurt performance and stability",
+ "Default: 600 mV"
+ };
+
+ case KipConfigValue_stepMode:
+ return {
+ "The step that RAM clocks take.",
+ "Options (with examples):",
+ " - 66MHz - 66 MHz step (ex. 1600, 1666, 1733, etc.)",
+ " - 100MHz - 100 MHz step (ex. 1600, 1700, 1800, etc.)",
+ " - 133MHz - 66 MHz step (ex. 1600, 1733, 1866, etc.)",
+ " - JEDEC:",
+ " - 1600, 1866, 1996, 2133, 2400, 2666, 2933 and 3200 MHz are used",
+ "The RAM max clock will always be available regardless of the step mode, but the intermediate frequencies will be limited by the selected step mode.",
+ "This setting does not affect performance and the option you choose mostly is based on your personal taste",
+ "33 MHz step mode is not possible due to certian limitations of Horizon OS",
+ "Default: 66 MHz",
+ };
+
+ case KipConfigValue_marikoEmcMaxClock:
+ return {
+ "The maximum RAM frequency available.",
+ "Higher frequencies may cause instability, so increase this gradually and test for stability.",
+ "Default: 2133 MHz"
+ };
+
+ case KipConfigValue_eristaEmcMaxClock:
+ case KipConfigValue_eristaEmcMaxClock1:
+ case KipConfigValue_eristaEmcMaxClock2:
+ return {
+ "The RAM frequency used in the particular slot. Higher frequencies may cause instability, so increase this gradually and test for stability.",
+ "Default: Disabled (1600 MHz)"
+ };
+
+ case KipConfigValue_t1_tRCD:
+ return {
+ "RAS-to-CAS delay",
+ "Default: 0"
+ };
+
+ case KipConfigValue_t2_tRP:
+ return {
+ "Row precharge time",
+ "Default: 0"
+ };
+
+ case KipConfigValue_t3_tRAS:
+ return {
+ "Row active time",
+ "Default: 0"
+ };
+
+ case KipConfigValue_t4_tRRD:
+ return {
+ "Row refresh time",
+ "Default: 0"
+ };
+
+ case KipConfigValue_t5_tRFC:
+ return {
+ "Refresh Cycle Time",
+ "Default: 0"
+ };
+
+ case KipConfigValue_t6_tRTW:
+ return {
+ "Read To Write (High bracket)",
+ "Default: 0"
+ };
+
+ case KipConfigValue_t7_tWTR:
+ return {
+ "Write To Read (High bracket)",
+ "Default: 0"
+ };
+
+ case KipConfigValue_t8_tREFI:
+ return {
+ "Refresh command interval",
+ "Default: 0"
+ };
+
+ case KipConfigValue_timingEmcTbreak:
+ return {
+ "Frequency where t6 and t7 break between the low and high brackets",
+ "Example:",
+ "Tbreak is set to 1866 MHz, and t6Low is set to 4 and t6High is set to 2. At frequencies below 1866 MHz, t6 will be 4, and at frequencies above 1866 MHz, t6 will be 2.",
+ "Default: Disabled"
+ };
+
+ case KipConfigValue_low_t6_tRTW:
+ return {
+ "Read To Write (Low bracket)",
+ "Default: 0"
+ };
+
+ case KipConfigValue_low_t7_tWTR:
+ return {
+ "Write To Read (Low bracket)",
+ "Default: 0"
+ };
+ case KipConfigValue_t2_tRP_cap:
+ return {
+ "Cap for t2 when 1333WL is used.",
+ "The default value is sufficient for most RAMs but some may need a lower value",
+ "Default: 2"
+ };
+
+ case KipConfigValue_t6_tRTW_fine_tune:
+ return {
+ "Finetunes the raw calculation of t6",
+ "Default: 0"
+ };
+
+ case KipConfigValue_t7_tWTR_fine_tune:
+ return {
+ "Finetunes the raw calculation of t6",
+ "Default: 0"
+ };
+
+ case KipConfigValue_write_latency_1333:
+ case KipConfigValue_write_latency_1600:
+ case KipConfigValue_write_latency_1866:
+ case KipConfigValue_write_latency_2133:
+ case KipConfigValue_read_latency_1333:
+ case KipConfigValue_read_latency_1600:
+ case KipConfigValue_read_latency_1866:
+ case KipConfigValue_read_latency_2133:
+ return {
+ "Latency bracket settings",
+ "Example:",
+ "If 1333 is set to 2000 MHz, 1600 set to 2500 MHz, 1866 set to 2766 MHz and 2133 set to 2933 MHz:",
+ "Frequencies below 2000 MHz use 1333, 2033-2500 MHz use 1600, 2533-2766 MHz use 1866 and 2800-2933 MHz use 2133. ",
+ "Either of these can be ommited and it will work (say you set 1333 to -, then <2000 MHz will use 1600 latency)",
+ "If all of these parameters are ommited the latency will automatically be calculated as follows:",
+ "1633-1866 MHz - 1866 WRL",
+ "1900+ MHz - 2133 WRL",
+ "These properties apply for both write and read latencies, and you can mix-and-match the brackets if nessesary",
+ "Default: -"
+ };
+
+ case KipConfigValue_mem_burst_read_latency:
+ return {
+ "The read latency for the ram",
+ "Default: 1600 RL"
+ };
+
+ case KipConfigValue_mem_burst_write_latency:
+ return {
+ "The write latency for the ram",
+ "Default: 1600 WL"
+ };
+
+ case KipConfigValue_marikoCpuUVLow:
+ return {
+ "The CPU UV level used before tBreak",
+ "Default: 0"
+ };
+
+ case KipConfigValue_marikoCpuUVHigh:
+ return {
+ "The CPU UV level used after tBreak",
+ "Default: 0"
+ };
+
+ case KipConfigValue_tableConf:
+ return {
+ "The current UV table used. The tbreaks are as follows:",
+ "1581 MHz tBreak and 1683 MHz tBreak use their respective tBreaks",
+ "The other tables use 1581 MHz as tBreak",
+ "The \"Default\" table does not contain frequencies past 1963 MHz and may not undervolt correctly"
+ };
+
+ case KipConfigValue_marikoCpuLowVmin:
+ return {
+ "The CPU vmin used before tBreak",
+ "Default: 620 mV"
+ };
+
+ case KipConfigValue_marikoCpuHighVmin:
+ return {
+ "The CPU vmin used after tBreak",
+ "Default: 750 mV"
+ };
+
+
+ case KipConfigValue_marikoCpuMaxVolt:
+ return {
+ "The maximum voltage that the CPU can use",
+ "Change this setting with caution!",
+ "Default: 1120 mV"
+ };
+
+ case KipConfigValue_marikoCpuMaxClock:
+ return {
+ "The maximum available CPU clock",
+ "Default: 1963 MHz"
+ };
+
+ case KipConfigValue_marikoCpuBoostClock:
+ return {
+ "The clock used for the CPU in \"boost mode\"",
+ "Default: 1963 MHz"
+ };
+
+ case KipConfigValue_eristaCpuUV:
+ return {
+ "CPU undervolt level",
+ "Default: 0"
+ };
+
+ case KipConfigValue_eristaCpuUnlock:
+ return {
+ "Unlock unsafe CPU clocks",
+ "Default: OFF"
+ };
+
+ case KipConfigValue_eristaCpuVmin:
+ return {
+ "Minimum CPU voltage",
+ "Default: 825 mV"
+ };
+
+ case KipConfigValue_eristaCpuMaxVolt:
+ return {
+ "Maximum CPU voltage",
+ "Default: 1235 mV"
+ };
+
+ case HocClkConfigValue_EristaMaxCpuClock:
+ return {
+ "The maximum available CPU clock",
+ "Default: 1785 MHz"
+ };
+
+ case KipConfigValue_eristaCpuBoostClock:
+ return {
+ "The clock used for the CPU in \"boost mode\"",
+ "Default: 1785 MHz"
+ };
+
+ case HocClkConfigValue_OverwriteBoostMode:
+ return {
+ "If enabled, profiles can override the boost mode setting",
+ "Default: OFF"
+ };
+
+ case KipConfigValue_marikoGpuUV:
+ return {
+ "GPU undervolt level",
+ "Options:",
+ " - HiOPT: L4T Custom HiOPT table",
+ " - HiOPT - 15mV: L4T Custom HiOPT table with a 15mV offset",
+ " - High UV: The highest undervolt table, reccomended",
+ "Default: HiOPT"
+ };
+
+ case KipConfigValue_marikoGpuVmin:
+ return {
+ "Minimum GPU voltage",
+ "Note: DVFS may change this value when the RAM clock is changed if the DVFS mode is set to PCV Hijack",
+ "Default: 610 mV"
+ };
+
+ case KipConfigValue_marikoGpuVmax:
+ return {
+ "Maximum GPU voltage",
+ "Default: 800 mV"
+ };
+
+ case HocClkConfigValue_DVFSMode:
+ return {
+ "The mode used for GPU DVFS",
+ "Adjusts GPU vmin when RAM clock is changed due to a higher requirement",
+ "Options:",
+ "- Disabled: disabled...",
+ "- PCV Hijack: hijack PCV for override",
+ "Default: PCV Hijack"
+ };
+
+ case HocClkConfigValue_DVFSOffset:
+ return {
+ "The offset added/subtracted to the GPU vmin when the RAM clock is changed due to a higher requirement in PCV Hijack mode",
+ "Default: 0 mV (Disabled)"
+ };
+
+ case KipConfigValue_eristaGpuUV:
+ return {
+ "GPU undervolt level",
+ "Options:",
+ " - HiOPT: L4T Custom HiOPT table",
+ " - HiOPT - 15mV: L4T Custom HiOPT table with a 15mV offset",
+ " - High UV: The highest undervolt table, reccomended",
+ "Default: HiOPT"
+ };
+
+ case KipConfigValue_eristaGpuVmin:
+ return {
+ "Minimum GPU voltage",
+ "Default: 810 mV (812mV as erista is stepped my 6.5mV instead of 5mV)"
+ };
+
+ case KipConfigValue_commonGpuVoltOffset:
+ return {
+ "The offset added/subtracted to all AUTO GPU voltages",
+ "Default: 0 mV (Disabled)"
+ };
+
+ case HocClkConfigValue_GPUScheduling:
+ return {
+ "The scheduling method used for GPU clocks",
+ "Options:",
+ "- Do Not Override: Do not override existing scheduling mode",
+ "- Disabled: Disables GPU scheduling, 99.7% GPU max load",
+ "- Enabled: Enables GPU scheduling, 96.5% GPU max load",
+ "Default: Do not override"
+ };
+
+ default:
+ return {};
+ }
+}
diff --git a/Source/hoc-clk/overlay/src/ui/gui/config_info_strings.h b/Source/hoc-clk/overlay/src/ui/gui/config_info_strings.h
new file mode 100644
index 00000000..595abbee
--- /dev/null
+++ b/Source/hoc-clk/overlay/src/ui/gui/config_info_strings.h
@@ -0,0 +1,23 @@
+/*
+ *
+ * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#pragma once
+#include "misc_gui.h"
+#include
+#include
+
+std::vector ConfigInfoStrings(HocClkConfigValue val, bool isMariko, bool isHoag);
diff --git a/Source/hoc-clk/overlay/src/ui/gui/info_gui.cpp b/Source/hoc-clk/overlay/src/ui/gui/info_gui.cpp
new file mode 100644
index 00000000..aa4e4869
--- /dev/null
+++ b/Source/hoc-clk/overlay/src/ui/gui/info_gui.cpp
@@ -0,0 +1,88 @@
+/*
+ *
+ * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include "info_gui.h"
+#include "ult_ext.h"
+#include
+
+InfoGui::InfoGui(std::string title, std::vector strings)
+ : m_title(std::move(title)), m_strings(std::move(strings)) {}
+
+static constexpr s32 TEXT_SIZE = 16;
+static constexpr s32 LINE_H = 22;
+static constexpr s32 PARA_GAP = 10;
+static constexpr s32 MARGIN_L = 20;
+static constexpr s32 MARGIN_R = 35;
+
+static std::vector wrapText(const std::string& text, s32 maxWidth)
+{
+ constexpr float CHAR_W = 10.0f;
+
+ // Preserve leading whitespace as an indent prefix for wrapped continuation lines.
+ std::string indent;
+ for (char c : text) {
+ if (c == ' ') indent += ' ';
+ else break;
+ }
+
+ std::vector lines;
+ std::istringstream ss(text);
+ std::string word, line = indent; // seed with indent so first word inherits it
+ bool first = true;
+ while (ss >> word) {
+ std::string candidate = (first && !indent.empty()) ? indent + word
+ : line.empty() ? word
+ : line + " " + word;
+ first = false;
+ if (static_cast(candidate.size() * CHAR_W) <= maxWidth)
+ line = std::move(candidate);
+ else {
+ if (!line.empty() && line != indent) lines.push_back(line);
+ line = indent + word;
+ }
+ }
+ if (!line.empty() && line != indent) lines.push_back(line);
+ if (lines.empty()) lines.emplace_back("");
+ return lines;
+}
+
+void InfoGui::listUI()
+{
+ this->listElement->addItem(new tsl::elm::CategoryHeader(m_title));
+
+ const s32 maxWidth = tsl::cfg::FramebufferWidth - MARGIN_L - MARGIN_R;
+
+ for (const auto& para : m_strings) {
+ for (const auto& lineText : wrapText(para, maxWidth)) {
+ auto* d = new FocusableDrawer(
+ [lineText](tsl::gfx::Renderer* r, s32 x, s32 y, s32 w, s32 h) {
+ r->drawString((lineText + "\n").c_str(), false,
+ x + MARGIN_L, y + LINE_H - 5,
+ TEXT_SIZE, tsl::style::color::ColorText);
+ });
+ d->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, LINE_H);
+ this->listElement->addItem(d, LINE_H);
+ }
+
+ // paragraph gap
+ auto* gap = new tsl::elm::CustomDrawer(
+ [](tsl::gfx::Renderer*, s32, s32, s32, s32) {});
+ gap->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, PARA_GAP);
+ this->listElement->addItem(gap, PARA_GAP);
+ }
+}
diff --git a/Source/hoc-clk/overlay/src/ui/gui/info_gui.h b/Source/hoc-clk/overlay/src/ui/gui/info_gui.h
new file mode 100644
index 00000000..8e5bf437
--- /dev/null
+++ b/Source/hoc-clk/overlay/src/ui/gui/info_gui.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#pragma once
+#include "base_menu_gui.h"
+#include
+#include
+
+class InfoGui : public BaseMenuGui
+{
+public:
+ InfoGui(std::string title, std::vector strings);
+ ~InfoGui() = default;
+ void listUI() override;
+
+private:
+ std::string m_title;
+ std::vector m_strings;
+};
diff --git a/Source/hoc-clk/overlay/src/ui/gui/misc_gui.cpp b/Source/hoc-clk/overlay/src/ui/gui/misc_gui.cpp
index 33bd5fcf..e4f32636 100644
--- a/Source/hoc-clk/overlay/src/ui/gui/misc_gui.cpp
+++ b/Source/hoc-clk/overlay/src/ui/gui/misc_gui.cpp
@@ -18,6 +18,7 @@
#include "misc_gui.h"
#include "fatal_gui.h"
+#include "config_info_strings.h"
#include "../format.h"
#include
#include
@@ -88,7 +89,24 @@ MiscGui::~MiscGui()
void MiscGui::addConfigToggle(HocClkConfigValue configVal, const char* altName, bool kip) {
const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true);
- tsl::elm::ToggleListItem* toggle = new tsl::elm::ToggleListItem(configName, this->configList->values[configVal]);
+ auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
+
+ struct YAwareToggle : tsl::elm::ToggleListItem {
+ std::vector m_info;
+ std::string m_title;
+ YAwareToggle(const char* text, bool state, std::string title, std::vector info)
+ : tsl::elm::ToggleListItem(text, state), m_info(std::move(info)), m_title(std::move(title)) {}
+ bool onClick(u64 keys) override {
+ if (!m_info.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
+ tsl::changeTo(m_title, m_info);
+ return true;
+ }
+ return tsl::elm::ToggleListItem::onClick(keys);
+ }
+ };
+
+ auto* toggle = new YAwareToggle(configName, this->configList->values[configVal],
+ configName, std::move(infoStrings));
if (!kip)
toggle->setTextColor(tsl::Color(120, 235, 255, 255));
toggle->setStateChangedListener([this, configVal, kip](bool state) {
@@ -106,9 +124,13 @@ void MiscGui::addConfigToggle(HocClkConfigValue configVal, const char* altName,
}
void MiscGui::addConfigTrackbar(HocClkConfigValue configVal, const char* altName, const ValueRange& range, bool kip) {
+ auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
struct IndexedBar : tsl::elm::NamedStepTrackBar {
- IndexedBar(const char* label, const ValueRange& r)
- : tsl::elm::NamedStepTrackBar("", {""}, true, label) {
+ std::vector m_info;
+ std::string m_title;
+ IndexedBar(const char* label, const ValueRange& r, std::string title, std::vector info)
+ : tsl::elm::NamedStepTrackBar("", {""}, true, label),
+ m_info(std::move(info)), m_title(std::move(title)) {
m_stepDescriptions.clear();
u32 numSteps = (r.max - r.min) / r.step + 1;
for (u32 i = 0; i < numSteps; i++) {
@@ -120,9 +142,17 @@ void MiscGui::addConfigTrackbar(HocClkConfigValue configVal, const char* altName
m_numSteps = (u8)m_stepDescriptions.size();
m_selection = m_stepDescriptions[0];
}
+ bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState& touchPos,
+ HidAnalogStickState leftJoyStick, HidAnalogStickState rightJoyStick) override {
+ if (!m_info.empty() && (keysDown & HidNpadButton_Y) && !(keysDown & ~HidNpadButton_Y)) {
+ tsl::changeTo(m_title, m_info);
+ return true;
+ }
+ return tsl::elm::NamedStepTrackBar::handleInput(keysDown, keysHeld, touchPos, leftJoyStick, rightJoyStick);
+ }
};
const char* name = altName ? altName : hocclkFormatConfigValue(configVal, true);
- auto* bar = new IndexedBar(name, range);
+ auto* bar = new IndexedBar(name, range, name, std::move(infoStrings));
u32 cur = (u32)this->configList->values[configVal];
u16 curStep = 0;
if (cur >= range.min && cur <= range.max && range.step > 0 && (cur - range.min) % range.step == 0)
@@ -141,7 +171,25 @@ void MiscGui::addMappedConfigTrackbar(HocClkConfigValue configVal, const char* a
std::vector vals,
std::initializer_list names, bool kip) {
const char* name = altName ? altName : hocclkFormatConfigValue(configVal, true);
- auto* bar = new tsl::elm::NamedStepTrackBar("", names, true, name);
+ auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
+
+ struct YAwareTrackBar : tsl::elm::NamedStepTrackBar {
+ std::vector m_info;
+ std::string m_title;
+ YAwareTrackBar(const char* label, std::initializer_list steps, std::string title, std::vector info)
+ : tsl::elm::NamedStepTrackBar("", steps, true, label),
+ m_info(std::move(info)), m_title(std::move(title)) {}
+ bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState& touchPos,
+ HidAnalogStickState leftJoyStick, HidAnalogStickState rightJoyStick) override {
+ if (!m_info.empty() && (keysDown & HidNpadButton_Y) && !(keysDown & ~HidNpadButton_Y)) {
+ tsl::changeTo(m_title, m_info);
+ return true;
+ }
+ return tsl::elm::NamedStepTrackBar::handleInput(keysDown, keysHeld, touchPos, leftJoyStick, rightJoyStick);
+ }
+ };
+
+ auto* bar = new YAwareTrackBar(name, names, name, std::move(infoStrings));
u32 cur = (u32)this->configList->values[configVal];
u16 curIdx = 0;
for (u16 i = 0; i < (u16)vals.size(); i++) {
@@ -170,6 +218,7 @@ void MiscGui::addConfigButton(HocClkConfigValue configVal,
bool kip)
{
const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true);
+ auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
tsl::elm::ListItem* listItem = new tsl::elm::ListItem(configName);
if (!kip)
@@ -203,8 +252,14 @@ void MiscGui::addConfigButton(HocClkConfigValue configVal,
ValueThresholds thresholdsCopy = (thresholds ? *thresholds : ValueThresholds{});
listItem->setClickListener(
- [this, configVal, range, categoryName, thresholdsCopy, labels, showDefaultValue, kip](u64 keys)
+ [this, configVal, range, categoryName, thresholdsCopy, labels, showDefaultValue, kip,
+ infoStrings = std::move(infoStrings), configName = std::string(configName)](u64 keys)
{
+ if (!infoStrings.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
+ tsl::changeTo(configName, infoStrings);
+ return true;
+ }
+
if ((keys & HidNpadButton_A) == 0)
return false;
@@ -287,6 +342,8 @@ void MiscGui::addConfigButtonS(HocClkConfigValue configVal,
const char* subText,
bool kip)
{
+ const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true);
+ auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
tsl::elm::ListItem* listItem = new tsl::elm::ListItem("");
if (!kip)
listItem->setTextColor(tsl::Color(120, 235, 255, 255));
@@ -321,8 +378,14 @@ void MiscGui::addConfigButtonS(HocClkConfigValue configVal,
ValueThresholds thresholdsCopy = (thresholds ? *thresholds : ValueThresholds{});
listItem->setClickListener(
- [this, configVal, range, categoryName, thresholdsCopy, labels, showDefaultValue, kip](u64 keys)
+ [this, configVal, range, categoryName, thresholdsCopy, labels, showDefaultValue, kip,
+ infoStrings = std::move(infoStrings), configName = std::string(configName)](u64 keys)
{
+ if (!infoStrings.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
+ tsl::changeTo(configName, infoStrings);
+ return true;
+ }
+
if ((keys & HidNpadButton_A) == 0)
return false;
@@ -410,6 +473,7 @@ void MiscGui::addFreqButton(HocClkConfigValue configVal,
const std::map& labels)
{
const char* configName = altName ? altName : hocclkFormatConfigValue(configVal, true);
+ auto infoStrings = ConfigInfoStrings(configVal, IsMariko(), IsHoag());
tsl::elm::ListItem* listItem = new tsl::elm::ListItem(configName);
@@ -419,8 +483,14 @@ void MiscGui::addFreqButton(HocClkConfigValue configVal,
listItem->setValue(valueText);
listItem->setClickListener(
- [this, configVal, module, labels](u64 keys)
+ [this, configVal, module, labels,
+ infoStrings = std::move(infoStrings), configName = std::string(configName)](u64 keys)
{
+ if (!infoStrings.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
+ tsl::changeTo(configName, infoStrings);
+ return true;
+ }
+
if ((keys & HidNpadButton_A) == 0)
return false;
@@ -1350,7 +1420,12 @@ protected:
tsl::elm::ListItem* item = new tsl::elm::ListItem(label);
item->setValue(makeValueText(currentVal));
- item->setClickListener([this, tierIdx, thisKey, keysArr](u64 keys) -> bool {
+ item->setClickListener([this, tierIdx, thisKey, keysArr, label](u64 keys) -> bool {
+ auto infoStrings = ConfigInfoStrings(thisKey, IsMariko(), IsHoag());
+ if (!infoStrings.empty() && (keys & HidNpadButton_Y) && !(keys & ~HidNpadButton_Y)) {
+ tsl::changeTo(std::string(label), infoStrings);
+ return true;
+ }
if ((keys & HidNpadButton_A) == 0)
return false;
diff --git a/Source/hoc-clk/overlay/src/ui/gui/misc_gui.h b/Source/hoc-clk/overlay/src/ui/gui/misc_gui.h
index bf0c5045..43c5e2db 100644
--- a/Source/hoc-clk/overlay/src/ui/gui/misc_gui.h
+++ b/Source/hoc-clk/overlay/src/ui/gui/misc_gui.h
@@ -25,6 +25,7 @@
#include
#include "freq_choice_gui.h"
#include "value_choice_gui.h"
+#include "info_gui.h"
class MiscGui : public BaseMenuGui
{
public:
@@ -32,7 +33,7 @@ public:
~MiscGui();
void listUI() override;
void refresh() override;
-
+
protected:
HocClkConfigValueList* configList;
std::map configButtons;
@@ -43,7 +44,7 @@ protected:
std::set configButtonSKeys;
std::map configButtonSSubtext;
std::set emcClockConfigs;
-
+
void addConfigToggle(HocClkConfigValue configVal, const char* altName, bool kip = false);
void addConfigTrackbar(HocClkConfigValue configVal, const char* altName, const ValueRange& range, bool kip = true);
void addMappedConfigTrackbar(HocClkConfigValue configVal, const char* altName,
@@ -74,8 +75,8 @@ protected:
HocClkModule module,
const std::map& labels = {});
void updateConfigToggles();
-
+
tsl::elm::ToggleListItem* enabledToggle;
u8 frameCounter = 60;
bool shouldSaveKip = false;
-};
\ No newline at end of file
+};
diff --git a/Source/hoc-clk/overlay/src/ui/gui/ult_ext.h b/Source/hoc-clk/overlay/src/ui/gui/ult_ext.h
index 82267fd9..e0b1fd4a 100644
--- a/Source/hoc-clk/overlay/src/ui/gui/ult_ext.h
+++ b/Source/hoc-clk/overlay/src/ui/gui/ult_ext.h
@@ -95,6 +95,18 @@ public:
}
};
+class FocusableDrawer : public tsl::elm::CustomDrawer {
+public:
+ template
+ FocusableDrawer(Args&&... args) : tsl::elm::CustomDrawer(std::forward(args)...) {
+ m_isItem = true;
+ }
+ Element* requestFocus(Element*, tsl::FocusDirection) override {
+ return this;
+ }
+ void drawHighlight(tsl::gfx::Renderer*) override {}
+};
+
class HideableCustomDrawer : public tsl::elm::Element {
private:
bool visible;
diff --git a/Source/hoc-clk/sysmodule/Makefile b/Source/hoc-clk/sysmodule/Makefile
index 2afc24aa..aea82a5f 100644
--- a/Source/hoc-clk/sysmodule/Makefile
+++ b/Source/hoc-clk/sysmodule/Makefile
@@ -28,8 +28,8 @@ INCLUDES := ../common/include src/hos src/soc src/i2c src/util src/pwr src/ipc
EXEFS_SRC := exefs_src
LIBNAMES := minIni
# major minor patch
-TARGET_VERSION := 2.3.0
-KIP_VERSION := 230
+TARGET_VERSION := 2.3.1
+KIP_VERSION := 231
CUST_REV := 3
#---------------------------------------------------------------------------------