Skip to content

Commit 58f8de3

Browse files
d3nd3cursoragent
andcommitted
Release v7.4: themed Buddy settings shell and loading options
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent a9ef6eb commit 58f8de3

52 files changed

Lines changed: 480 additions & 491 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
# Changelog
22

3+
## v7.4
4+
5+
### Internal menus — themed SoF Buddy settings shell
6+
7+
- **Menu themes:** Added `_sofbuddy_menu_theme` with 31 editor-inspired color presets; RMF files now use `{theme_tints}` so theme colors are injected at load time.
8+
- **Buddy settings page:** New **Buddy** tab (`sofbuddy.rmf` / `sofbuddy_content.rmf`) for menu theme, tooltip duration, hotkey display, loading-screen options, startup update check, and restore defaults.
9+
- **Tab layout:** SoF Buddy tabs moved into `sof_buddy/tabs/*.rmf`, with fixed-width three-column rows and a shared `{tabs_row_prefix}` placeholder. Old standalone `*_content.rmf` pages for Input / Profiles / Video were removed where the tab content is now folded into the unified layout.
10+
- **Layout cvars:** Default tab content width is now 384px for both rows; row prefix calculation uses the full 640px center panel with a small left nudge for balanced tab rows.
11+
12+
### Loading screen options
13+
14+
- **`_sofbuddy_loading_show_mapname`** and **`_sofbuddy_loading_show_download`** let users hide the map name or download status rows independently.
15+
- **`loading_network_map.rmf`** and **`loading_network_download.rmf`** split the loading header rows so the new cvars can gate each row.
16+
- Loading map display strips leading `maps/` from paths before writing `_sofbuddy_loading_current`.
17+
18+
### Internal menu plumbing
19+
20+
- `FS_LoadFile` placeholder substitution now supports `{tabs_row_prefix}` and `{theme_tints}`.
21+
- `tools/generate_menu_embed.py` now embeds nested menu folders (for example `sof_buddy/tabs/*.rmf`) using the full relative menu path.
22+
- `fx_maxdebrisonscreen` is registered with `CVAR_ARCHIVE` so CPU/profile menu changes persist.
23+
324
## v7.3
425

526
### Internal menus — deathmatch-only loading rule

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
7.3
1+
7.4

hdr/version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
Increment version using: ./increment_version.sh
88
*/
99

10-
#define SOFBUDDY_VERSION "7.3"
10+
#define SOFBUDDY_VERSION "7.4"

src/features/internal_menus/hooks/fs_loadfile_override.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,16 @@ int internal_menus_fs_loadfile_override_callback(char* path, void** buffer, bool
7171
content.erase(std::remove(content.begin(), content.end(), '\r'), content.end());
7272
const char* inset = internal_menus_get_content_inset_rmf();
7373
const char* inset_tall = internal_menus_get_content_inset_tall_rmf();
74+
const char* tabs_prefix = internal_menus_get_tabs_row_prefix_rmf();
75+
const char* theme_tints = internal_menus_get_theme_tints_rmf();
7476
for (std::string::size_type pos = 0; (pos = content.find("{content_inset_tall}", pos)) != std::string::npos; )
7577
content.replace(pos, 20, inset_tall), pos += std::strlen(inset_tall);
7678
for (std::string::size_type pos = 0; (pos = content.find("{content_inset}", pos)) != std::string::npos; )
7779
content.replace(pos, 15, inset), pos += std::strlen(inset);
80+
for (std::string::size_type pos = 0; (pos = content.find("{tabs_row_prefix}", pos)) != std::string::npos; )
81+
content.replace(pos, 17, tabs_prefix), pos += std::strlen(tabs_prefix);
82+
for (std::string::size_type pos = 0; (pos = content.find("{theme_tints}", pos)) != std::string::npos; )
83+
content.replace(pos, 13, theme_tints), pos += std::strlen(theme_tints);
7884
for (std::string::size_type pos = 0; (pos = content.find("tall}", pos)) != std::string::npos; )
7985
content.replace(pos, 5, "");
8086

src/features/internal_menus/internal_menus.cpp

Lines changed: 101 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ void create_loading_cvars() {
184184
detour_Cvar_Get::oCvar_Get("_sofbuddy_tab", "0", 0, nullptr);
185185
// User preference: keep loading menu input locked (default), or allow interaction.
186186
detour_Cvar_Get::oCvar_Get("_sofbuddy_loading_lock_input", "1", CVAR_SOFBUDDY_ARCHIVE, nullptr);
187+
detour_Cvar_Get::oCvar_Get("_sofbuddy_loading_show_mapname", "1", CVAR_SOFBUDDY_ARCHIVE, nullptr);
188+
detour_Cvar_Get::oCvar_Get("_sofbuddy_loading_show_download", "1", CVAR_SOFBUDDY_ARCHIVE, nullptr);
187189
// User preference: key used to open SoF Buddy menu.
188190
detour_Cvar_Get::oCvar_Get("_sofbuddy_menu_hotkey", "F12", CVAR_SOFBUDDY_ARCHIVE, nullptr);
189191
// Last SoF Buddy tab/page (e.g. sof_buddy/map_debug) restored when opening via F12 (sofbuddy_menu sof_buddy).
@@ -198,11 +200,16 @@ void create_loading_cvars() {
198200
cvar_t* perf = detour_Cvar_Get::oCvar_Get("_sofbuddy_perf_profile", "0", CVAR_SOFBUDDY_ARCHIVE, sofbuddy_perf_profile_change);
199201
sofbuddy_perf_profile_change(perf);
200202

203+
// FX_Init registers this with flags 0; OR CVAR_ARCHIVE so menu/config.cfg persist changes.
204+
detour_Cvar_Get::oCvar_Get("fx_maxdebrisonscreen", "16", CVAR_ARCHIVE, nullptr);
201205
}
202206

203207
constexpr int kSofBuddyCenterPanelVirtualWidth = 640;
204-
constexpr int kSofBuddyDefaultRow1ContentWidth = 400;
205-
constexpr int kSofBuddyDefaultRow2ContentWidth = 520;
208+
constexpr int kSofBuddyDefaultRow1ContentWidth = 384;
209+
constexpr int kSofBuddyDefaultRow2ContentWidth = 384;
210+
constexpr int kSofBuddyTabWidthPx = 120;
211+
constexpr int kSofBuddyTabGapPx = 12;
212+
constexpr int kSofBuddyTabLeftNudgePx = 32;
206213

207214
cvar_t* _sofbuddy_sb_tabs_row1_content_px = nullptr;
208215
cvar_t* _sofbuddy_sb_tabs_row2_content_px = nullptr;
@@ -223,12 +230,15 @@ void create_layout_cvars() {
223230
detour_Cvar_Get::oCvar_Get("_sofbuddy_sb_tabs_row2_prefix_rmf", "<blank 36 1>", kLayoutCvarFlags, nullptr);
224231
detour_Cvar_Get::oCvar_Get("_sofbuddy_sb_tabs_row1_suffix_rmf", "<blank 96 1>", kLayoutCvarFlags, nullptr);
225232
detour_Cvar_Get::oCvar_Get("_sofbuddy_sb_tabs_row2_suffix_rmf", "<blank 36 1>", kLayoutCvarFlags, nullptr);
226-
_sofbuddy_sb_tabs_row1_content_px = detour_Cvar_Get::oCvar_Get("_sofbuddy_sb_tabs_row1_content_px", "400", kLayoutCvarFlags, nullptr);
227-
_sofbuddy_sb_tabs_row2_content_px = detour_Cvar_Get::oCvar_Get("_sofbuddy_sb_tabs_row2_content_px", "520", kLayoutCvarFlags, nullptr);
233+
_sofbuddy_sb_tabs_row1_content_px = detour_Cvar_Get::oCvar_Get("_sofbuddy_sb_tabs_row1_content_px", "384", kLayoutCvarFlags, nullptr);
234+
_sofbuddy_sb_tabs_row2_content_px = detour_Cvar_Get::oCvar_Get("_sofbuddy_sb_tabs_row2_content_px", "384", kLayoutCvarFlags, nullptr);
228235
_sofbuddy_sb_tabs_center_bias_px = detour_Cvar_Get::oCvar_Get("_sofbuddy_sb_tabs_center_bias_px", "0", kLayoutCvarFlags, nullptr);
229236
_sofbuddy_sb_tabs_row1_bias_px = detour_Cvar_Get::oCvar_Get("_sofbuddy_sb_tabs_row1_bias_px", "0", kLayoutCvarFlags, nullptr);
230237
_sofbuddy_sb_tabs_row2_bias_px = detour_Cvar_Get::oCvar_Get("_sofbuddy_sb_tabs_row2_bias_px", "0", kLayoutCvarFlags, nullptr);
231238

239+
// Menu color theme preset index (see kMenuThemes).
240+
detour_Cvar_Get::oCvar_Get("_sofbuddy_menu_theme", "0", CVAR_SOFBUDDY_ARCHIVE, nullptr);
241+
232242
// SoF default for tip_duration is 2500ms; bump to 5000ms if untouched.
233243
cvar_t* tip_duration = detour_Cvar_Get::oCvar_Get("tip_duration", "2500", 0, nullptr);
234244
if (tip_duration && tip_duration->string && std::strcmp(tip_duration->string, "2500") == 0 && detour_Cvar_Set2::oCvar_Set2)
@@ -314,11 +324,11 @@ void update_layout_cvars(bool trigger_reloadall_if_changed) {
314324
const int row1_bias_px = _sofbuddy_sb_tabs_row1_bias_px ? static_cast<int>(_sofbuddy_sb_tabs_row1_bias_px->value + 0.5f) : 0;
315325
const int row2_bias_px = _sofbuddy_sb_tabs_row2_bias_px ? static_cast<int>(_sofbuddy_sb_tabs_row2_bias_px->value + 0.5f) : 0;
316326

317-
row1_content_px = std::max(64, std::min(center_panel_px, row1_content_px));
318-
row2_content_px = std::max(64, std::min(center_panel_px, row2_content_px));
327+
row1_content_px = std::max(64, std::min(kSofBuddyCenterPanelVirtualWidth, row1_content_px));
328+
row2_content_px = row1_content_px;
319329

320-
const int row1_prefix_px = std::max(0, ((center_panel_px - row1_content_px) / 2) + center_bias_px + row1_bias_px);
321-
const int row2_prefix_px = std::max(0, ((center_panel_px - row2_content_px) / 2) + center_bias_px + row2_bias_px);
330+
const int row1_prefix_px = std::max(0, ((kSofBuddyCenterPanelVirtualWidth - row1_content_px) / 2) + center_bias_px + row1_bias_px - kSofBuddyTabLeftNudgePx);
331+
const int row2_prefix_px = row1_prefix_px + row2_bias_px - row1_bias_px;
322332

323333
char row1_rmf[64];
324334
char row2_rmf[64];
@@ -419,6 +429,69 @@ const char* internal_menus_get_content_inset_tall_rmf(void) {
419429
std::snprintf(buf, sizeof(buf), "<blank %d %d>", internal_menus_content_inset_px(), internal_menus_menu_vid_h_px());
420430
return buf;
421431
}
432+
// Menu color themes: (bg, fg, secondary/accent, dim, panel) as ABGR (0xAABBGGRR).
433+
// Palettes sourced from popular editor themes (Dracula, Nord, One Dark, Tokyo Night, etc.).
434+
struct MenuTheme { unsigned bg, fg, sec, dim, panel; };
435+
static const MenuTheme kMenuThemes[] = {
436+
{0xff050913, 0xfff3f7ff, 0xff43ffd0, 0xff2b3b55, 0xff101b2b}, // 0 Dark
437+
{0xff000000, 0xffffffff, 0xff4ad5ff, 0xffa0a0a0, 0xff161616}, // 1 Hi Contrast
438+
{0xff00050a, 0xff00b0ff, 0xff7fd2ff, 0xff106aa0, 0xff000f1a}, // 2 Amber
439+
{0xff001100, 0xff66ff33, 0xffc4ff9e, 0xff4f8a2f, 0xff002600}, // 3 Green
440+
{0xff362b00, 0xffa1a193, 0xff98a12a, 0xff756e58, 0xff423607}, // 4 Solar Dark
441+
{0xffe3f6fd, 0xff423607, 0xffd28b26, 0xffa1a193, 0xffd5e8ee}, // 5 Solar Light
442+
{0xfff0f5f5, 0xff1a1a1a, 0xff875f00, 0xff707070, 0xffe0e6e6}, // 6 Paper
443+
{0xff000000, 0xff00ffff, 0xffffff00, 0xff00b0b0, 0xff101010}, // 7 Hi Yellow
444+
{0xff362a28, 0xfff2f8f8, 0xfffde98b, 0xffa47262, 0xff5a4744}, // 8 Dracula
445+
{0xff342c28, 0xffbfb2ab, 0xffefaf61, 0xff70635c, 0xff2b2521}, // 9 One Dark
446+
{0xff40342e, 0xfff4efec, 0xffd0c088, 0xff6a564c, 0xff52423b}, // 10 Nord
447+
{0xff222827, 0xfff2f8f8, 0xff2ee2a6, 0xff5e7175, 0xff1c1f1e}, // 11 Monokai
448+
{0xff261b1a, 0xfff5cac0, 0xfff7a27a, 0xff895f56, 0xff1e1616}, // 12 Tokyo Night
449+
{0xff2e1e1e, 0xfff4d6cd, 0xfffab489, 0xff86706c, 0xff251818}, // 13 Catppuccin
450+
{0xff282828, 0xffb2dbeb, 0xff98a583, 0xff748392, 0xff21201d}, // 14 Gruvbox
451+
{0xff3b352d, 0xffaac6d3, 0xff80c0a7, 0xff78847a, 0xff2e2a23}, // 15 Everforest
452+
{0xff17110d, 0xffd9d1c9, 0xffffa658, 0xff9e948b, 0xff221b16}, // 16 GitHub Dark
453+
{0xff140e0a, 0xffb6bdbf, 0xffe6ba39, 0xff736a62, 0xff1a130f}, // 17 Ayu Dark
454+
{0xff3e2d29, 0xffcdaca6, 0xffffaa82, 0xff956e67, 0xff33221f}, // 18 Palenight
455+
{0xff241719, 0xfff4dee0, 0xffe7a7c4, 0xff866a6e, 0xff2e1d1f}, // 19 Rose Pine
456+
{0xff271601, 0xffebded6, 0xffffaa82, 0xff777763, 0xff42290b}, // 20 Night Owl
457+
{0xff493519, 0xffffffff, 0xff00c6ff, 0xffff8800, 0xff382712}, // 21 Cobalt2
458+
{0xff3f3f3f, 0xffccdcdc, 0xff809070, 0xffafaf9f, 0xff333333}, // 22 Zenburn
459+
{0xff2f1b24, 0xfff1eff0, 0xffdb7eff, 0xffbd8b84, 0xff23141a}, // 23 Synthwave
460+
{0xff08020d, 0xff41ff00, 0xff33cc00, 0xff118f00, 0xff001a00}, // 24 Matrix
461+
{0xff000000, 0xffe0e0e0, 0xff76e600, 0xff888888, 0xff0a0a0a}, // 25 OLED
462+
{0xffffffff, 0xff2f2924, 0xffda6909, 0xff766d65, 0xfffaf8f6}, // 26 GitHub Light
463+
{0xfffafafa, 0xff423a38, 0xfff27840, 0xffa7a1a0, 0xfff0f0f0}, // 27 One Light
464+
{0xfff5f1ef, 0xff694f4c, 0xfff5661e, 0xffb0a09c, 0xffefe9e6}, // 28 Cat Latte
465+
{0xfff4efec, 0xff40342e, 0xffac815e, 0xff6a564c, 0xfff0e9e5}, // 29 Nord Snow
466+
{0xffd8ecf4, 0xff223443, 0xff13458b, 0xff556a7a, 0xffcfe3eb}, // 30 Sepia
467+
};
468+
const char* internal_menus_get_theme_tints_rmf(void) {
469+
static char buf[512];
470+
int idx = 0;
471+
if (detour_Cvar_Get::oCvar_Get) {
472+
cvar_t* c = detour_Cvar_Get::oCvar_Get("_sofbuddy_menu_theme", "0", CVAR_SOFBUDDY_ARCHIVE, nullptr);
473+
if (c) idx = static_cast<int>(c->value + 0.5f);
474+
}
475+
if (idx < 0 || idx >= static_cast<int>(sizeof(kMenuThemes) / sizeof(kMenuThemes[0]))) idx = 0;
476+
const MenuTheme& t = kMenuThemes[idx];
477+
std::snprintf(buf, sizeof(buf),
478+
"<tint normaltext 0x%08x><tint hilitetext 0x%08x>"
479+
"<tint sb_bg 0x%08x><tint sb_panel 0x%08x>"
480+
"<tint sb_accent 0x%08x><tint sb_subtle 0x%08x>"
481+
"<tint white 0x%08x><tint cyan 0x%08x>"
482+
"<tint gray 0x%08x><tint orange 0x%08x>",
483+
t.fg, t.bg, t.bg, t.panel,
484+
t.sec, t.dim, t.fg, t.sec,
485+
t.dim, t.fg);
486+
return buf;
487+
}
488+
const char* internal_menus_get_tabs_row_prefix_rmf(void) {
489+
if (detour_Cvar_Get::oCvar_Get) {
490+
cvar_t* c = detour_Cvar_Get::oCvar_Get("_sofbuddy_sb_tabs_row1_prefix_rmf", "<blank 124 1>", 0, nullptr);
491+
if (c && c->string && c->string[0]) return c->string;
492+
}
493+
return "<blank 124 1>";
494+
}
422495

423496
bool internal_menus_deathmatch_mode_active(void) {
424497
if (!detour_Cvar_Get::oCvar_Get) return false;
@@ -456,9 +529,28 @@ const char* internal_menus_loading_menu_name(void) {
456529
return internal_menus_should_lock_loading_input() ? "loading/loading" : "loading/loading_safe";
457530
}
458531

532+
static std::string loading_display_map_name(const char* map_name) {
533+
if (!map_name || !map_name[0]) return map_name ? map_name : "";
534+
std::string n(map_name);
535+
std::replace(n.begin(), n.end(), '\\', '/');
536+
while (n.rfind("./", 0) == 0) n.erase(0, 2);
537+
while (!n.empty() && n[0] == '/') n.erase(0, 1);
538+
if (n.size() >= 5 &&
539+
(n[0] == 'm' || n[0] == 'M') &&
540+
(n[1] == 'a' || n[1] == 'A') &&
541+
(n[2] == 'p' || n[2] == 'P') &&
542+
(n[3] == 's' || n[3] == 'S') &&
543+
n[4] == '/') {
544+
n.erase(0, 5);
545+
}
546+
return n;
547+
}
548+
459549
void loading_set_current(const char* map_name) {
460550
if (!map_name || !detour_Cvar_Set2::oCvar_Set2) return;
461-
detour_Cvar_Set2::oCvar_Set2(const_cast<char*>("_sofbuddy_loading_current"), const_cast<char*>(map_name), true);
551+
const std::string display = loading_display_map_name(map_name);
552+
detour_Cvar_Set2::oCvar_Set2(const_cast<char*>("_sofbuddy_loading_current"),
553+
const_cast<char*>(display.c_str()), true);
462554
}
463555

464556
void loading_reset_current_map_unknown(void) {

src/features/internal_menus/menu_library/loading/loading_network.rmf

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
<include tints>
44
<font type title tint lblue atint lblue>
55
<hbr>
6-
<ctext _sofbuddy_loading_current atext "Map: "><hbr>
7-
<hbr>
8-
<ctext _sofbuddy_loading_status atext "Download: "><hbr>
6+
<cinclude _sofbuddy_loading_show_mapname loading/loading_network_map>
7+
<cinclude _sofbuddy_loading_show_download loading/loading_network_download>
98
</stm>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<stm>
2+
<strings menu_generic>
3+
<include tints>
4+
<font type title tint lblue atint lblue>
5+
<ctext _sofbuddy_loading_status atext "Download: "><hbr>
6+
</stm>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<stm>
2+
<strings menu_generic>
3+
<include tints>
4+
<font type title tint lblue atint lblue>
5+
<ctext _sofbuddy_loading_current atext "Map: "><hbr>
6+
<hbr>
7+
</stm>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
<stm>
2+
<cinclude _sofbuddy_loading_show_mapname loading/loading_network_map>
3+
<cinclude _sofbuddy_loading_show_download loading/loading_network_download>
24
</stm>

src/features/internal_menus/menu_library/sof_buddy/cpu.rmf

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<stm nopush global>
22
<include tints>
3-
<tint normaltext 0xffffffff>
4-
<tint hilitetext 0xffffffff>
3+
{theme_tints}
54
<key escape "sofbuddy_menu sof_buddy">
65
<cursor 1>
76

0 commit comments

Comments
 (0)