feat(menustyling) remove other styling before applying

This commit is contained in:
Lillith Rose 2026-01-07 16:43:34 -05:00
parent 1bf6887bf0
commit a49d2d74e6
2 changed files with 51 additions and 14 deletions

View file

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.RegularExpressions;
using gay.lilyy.MenuStyling; using gay.lilyy.MenuStyling;
using nadena.dev.ndmf; using nadena.dev.ndmf;
using nadena.dev.ndmf.vrchat; using nadena.dev.ndmf.vrchat;
@ -22,17 +23,26 @@ namespace gay.lilyy.MenuStyling
if (obj != null) if (obj != null)
{ {
var descriptor = ctx.VRChatAvatarDescriptor(); var descriptor = ctx.VRChatAvatarDescriptor();
descriptor.expressionsMenu = DuplicateMenu(descriptor.expressionsMenu); var processedMenus = new HashSet<VRCExpressionsMenu>();
WalkMenu(obj, descriptor.expressionsMenu); descriptor.expressionsMenu = DuplicateMenu(descriptor.expressionsMenu, processedMenus);
var walkProcessedMenus = new HashSet<VRCExpressionsMenu>();
WalkMenu(obj, descriptor.expressionsMenu, walkProcessedMenus);
Object.DestroyImmediate(obj); Object.DestroyImmediate(obj);
} }
}); });
} }
private VRCExpressionsMenu DuplicateMenu(VRCExpressionsMenu menu) private VRCExpressionsMenu DuplicateMenu(VRCExpressionsMenu menu, HashSet<VRCExpressionsMenu> processedMenus)
{ {
if (menu == null) return null; if (menu == null) return null;
// Prevent circular references - if we've already processed this menu, return null to break the cycle
if (processedMenus.Contains(menu))
{
return null;
}
processedMenus.Add(menu);
var newMenu = ScriptableObject.CreateInstance<VRCExpressionsMenu>(); var newMenu = ScriptableObject.CreateInstance<VRCExpressionsMenu>();
newMenu.controls = new List<Control>(); newMenu.controls = new List<Control>();
@ -44,7 +54,7 @@ namespace gay.lilyy.MenuStyling
type = control.type, type = control.type,
icon = control.icon, icon = control.icon,
parameter = control.parameter, parameter = control.parameter,
subMenu = DuplicateMenu(control.subMenu), subMenu = DuplicateMenu(control.subMenu, processedMenus),
value = control.value, value = control.value,
style = control.style, style = control.style,
labels = control.labels, labels = control.labels,
@ -56,24 +66,50 @@ namespace gay.lilyy.MenuStyling
return newMenu; return newMenu;
} }
private void WalkMenu(MenuStylingConfig config, VRCExpressionsMenu menu) private string StripTextMeshProTags(string text)
{ {
if (string.IsNullOrEmpty(text)) return text;
// Remove all TextMeshPro/rich text tags
// Pattern matches: <tag>, </tag>, <tag=value>, <tag="value">, <tag='value'>
text = Regex.Replace(text, @"<[^>]+>", "");
return text;
}
private void WalkMenu(MenuStylingConfig config, VRCExpressionsMenu menu, HashSet<VRCExpressionsMenu> processedMenus)
{
if (menu == null) return;
// Prevent circular references
if (processedMenus.Contains(menu))
{
return;
}
processedMenus.Add(menu);
foreach (var child in menu.controls) foreach (var child in menu.controls)
{ {
if (child.name != " " && child.name != "" && child.name != null) { if (child.name != " " && child.name != "" && child.name != null) {
if (!child.name.StartsWith(config.Prefix)) // Strip all TextMeshPro styling tags first if enabled
{ if (config.RemovePreexistingStyling)
child.name = config.Prefix + child.name; {
} child.name = StripTextMeshProTags(child.name);
if (!child.name.EndsWith(config.Suffix)) }
{
child.name += config.Suffix; if (!child.name.StartsWith(config.Prefix))
} {
child.name = config.Prefix + child.name;
}
if (!child.name.EndsWith(config.Suffix))
{
child.name += config.Suffix;
}
} }
if (child.type == Control.ControlType.SubMenu && child.subMenu != null) if (child.type == Control.ControlType.SubMenu && child.subMenu != null)
{ {
WalkMenu(config, child.subMenu); WalkMenu(config, child.subMenu, processedMenus);
} }
} }
} }

View file

@ -8,5 +8,6 @@ namespace gay.lilyy.MenuStyling
{ {
public string Prefix = "<b><color=#c481d6>"; public string Prefix = "<b><color=#c481d6>";
public string Suffix = ""; public string Suffix = "";
public bool RemovePreexistingStyling = true;
} }
} }