Skip to content
This repository was archived by the owner on Jan 24, 2023. It is now read-only.

Commit cd034ba

Browse files
committed
Reworked ReRadioTogglePage.cs entirely, no longer uses VRChat components at all. Added ReRadioToggle.cs. Removed SetTitle extension for RadioSelectorToggleGroup.
1 parent c51c3f3 commit cd034ba

4 files changed

Lines changed: 131 additions & 46 deletions

File tree

ReMod.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
<Compile Include="Notification\NotificationObject.cs" />
131131
<Compile Include="Notification\NotificationSystem.cs" />
132132
<Compile Include="UI\QuickMenu\IButtonPage.cs" />
133+
<Compile Include="UI\QuickMenu\ReRadioToggle.cs" />
133134
<Compile Include="UI\QuickMenu\ReRadioTogglePage.cs" />
134135
<Compile Include="UI\Wings\ReMirroredWingButton.cs" />
135136
<Compile Include="UI\Wings\ReMirroredWingMenu.cs" />

UI/QuickMenu/ReRadioToggle.cs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using System;
2+
using ReMod.Core.VRChat;
3+
using TMPro;
4+
using UnityEngine;
5+
using UnityEngine.UI;
6+
using VRC.DataModel.Core;
7+
using VRC.UI.Core.Styles;
8+
using VRC.UI.Elements;
9+
using VRC.UI.Elements.Controls;
10+
using Object = UnityEngine.Object;
11+
12+
namespace ReMod.Core.UI.QuickMenu
13+
{
14+
public class ReRadioToggle : UiElement
15+
{
16+
17+
private static GameObject _togglePrefab;
18+
19+
private static GameObject TogglePrefab
20+
{
21+
get
22+
{
23+
if (_togglePrefab == null)
24+
{
25+
var audioMenuSource = QuickMenuEx.Instance.field_Public_Transform_0.Find("Window/QMParent/Menu_ChangeAudioInputDevice").gameObject;
26+
var deviceMenu = audioMenuSource.GetComponent<AudioInputDeviceMenu>();
27+
_togglePrefab = deviceMenu.field_Public_GameObject_0;
28+
}
29+
return _togglePrefab;
30+
}
31+
}
32+
33+
public bool IsOn;
34+
public Action<ReRadioToggle, bool> ToggleStateUpdated;
35+
public System.Object ToggleData;
36+
37+
private Button _button;
38+
private Toggle _toggle;
39+
private Graphic _checkmark;
40+
private TMP_Text _text;
41+
private StyleElement _style;
42+
43+
public ReRadioToggle(Transform parent, string name, string text, System.Object obj, bool defaultState = false) : base(TogglePrefab, parent, $"ReRadioToggle_{GetCleanName(name)}")
44+
{
45+
Object.DestroyImmediate(RectTransform.GetComponent<AudioDeviceButton>());
46+
Object.DestroyImmediate(RectTransform.GetComponent<RadioButtonSelector>());
47+
Object.DestroyImmediate(RectTransform.GetComponent<DataContext>());
48+
Object.DestroyImmediate(RectTransform.GetComponentInChildren<ListCountBinding>());
49+
50+
_button = RectTransform.GetComponent<Button>();
51+
_toggle = RectTransform.GetComponentInChildren<Toggle>(true);
52+
_checkmark = _toggle.graphic;
53+
_text = RectTransform.GetComponentInChildren<TMP_Text>(true);
54+
_style = RectTransform.GetComponent<StyleElement>();
55+
56+
_text.text = text;
57+
ToggleData = obj;
58+
59+
SetToggle(defaultState);
60+
61+
_button.onClick.AddListener(new Action(ToggleOn));
62+
}
63+
64+
public void SetToggle(bool state)
65+
{
66+
IsOn = state;
67+
_checkmark.gameObject.active = IsOn;
68+
_toggle.Set(IsOn);
69+
}
70+
71+
private void ToggleOn()
72+
{
73+
if(IsOn) return;
74+
75+
IsOn = true;
76+
_checkmark.gameObject.active = IsOn;
77+
_toggle.Set(IsOn);
78+
ToggleStateUpdated?.Invoke(this, IsOn);
79+
}
80+
}
81+
}

UI/QuickMenu/ReRadioTogglePage.cs

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
using System;
22
using System.Collections.Generic;
3+
using MelonLoader;
34
using ReMod.Core.Unity;
45
using ReMod.Core.VRChat;
56
using TMPro;
67
using UnityEngine;
78
using UnityEngine.UI;
89
using VRC.UI.Elements;
910
using VRC.UI.Elements.Controls;
10-
using Object = Il2CppSystem.Object;
11+
using Object = System.Object;
1112

1213
namespace ReMod.Core.UI.QuickMenu
1314
{
@@ -39,10 +40,9 @@ public string TitleText
3940
}
4041

4142
private TextMeshProUGUI _titleText;
42-
private ListBinding ListBinding;
43-
private GameObject RadioButtonPrefab;
44-
private RadioButtonSelectorGroup RadioButtonSelectorGroup;
45-
private Dictionary<string, Tuple<string, Object, Action>> _radioElementSource = new();
43+
private GameObject _toggleGroupRoot;
44+
private List<Tuple<String, Object>> _radioElementSource = new();
45+
private List<ReRadioToggle> _radioElements = new();
4646
private bool _isUpdated;
4747

4848
private readonly bool _isRoot;
@@ -62,11 +62,11 @@ public ReRadioTogglePage(string name) : base(MenuPrefab, QuickMenuEx.MenuParent,
6262
_container = RectTransform.GetComponentInChildren<ScrollRect>().content;
6363

6464
var inputMenu = RectTransform.GetComponent<AudioInputDeviceMenu>();
65-
RadioButtonPrefab = inputMenu.field_Public_GameObject_0;
66-
ListBinding = inputMenu.field_Public_ListBinding_0;
67-
RadioButtonSelectorGroup = ListBinding.gameObject.GetComponent<RadioButtonSelectorGroup>();
6865

69-
ListBinding.field_Protected_Dictionary_2_Object_GameObject_0 = new Il2CppSystem.Collections.Generic.Dictionary<Object, GameObject>();
66+
_toggleGroupRoot = inputMenu.field_Public_ListBinding_0.gameObject;
67+
68+
UnityEngine.Object.DestroyImmediate(_toggleGroupRoot.gameObject.GetComponent<ListBinding>());
69+
UnityEngine.Object.DestroyImmediate(_toggleGroupRoot.gameObject.GetComponent<RadioButtonSelectorGroup>());
7070

7171
//Get rid of the AudioInputDeviceMenu component
7272
UnityEngine.Object.DestroyImmediate(inputMenu);
@@ -87,46 +87,62 @@ public ReRadioTogglePage(string name) : base(MenuPrefab, QuickMenuEx.MenuParent,
8787
listener.OnDisableEvent += () => OnClose?.Invoke();
8888
}
8989

90-
public void Open()
90+
/// <summary>
91+
/// Opens and configures the ReRadioTogglePage, optionally with default object to set toggles active
92+
/// </summary>
93+
/// <param name="selected">Default object matching ones on toggle elements</param>
94+
public void Open(Object selected = null)
9195
{
9296
QuickMenuEx.MenuStateCtrl.PushPage(UiPage.field_Public_String_0);
9397

94-
if (!_isUpdated)
95-
return;
98+
if (_isUpdated)
99+
{
100+
_isUpdated = false;
101+
102+
foreach (var element in _radioElements)
103+
UnityEngine.Object.DestroyImmediate(element.GameObject);
104+
_radioElements.Clear();
96105

97-
_isUpdated = false;
106+
foreach (var newElement in _radioElementSource)
107+
{
108+
var toggle = new ReRadioToggle(_toggleGroupRoot.transform, newElement.Item1, newElement.Item1, newElement.Item2);
109+
toggle.ToggleStateUpdated += OnToggleSelect;
110+
_radioElements.Add(toggle);
111+
}
112+
}
98113

99-
foreach(var element in ListBinding.field_Protected_Dictionary_2_Object_GameObject_0)
100-
UnityEngine.Object.DestroyImmediate(element.value);
101-
ListBinding.field_Protected_Dictionary_2_Object_GameObject_0.Clear();
114+
if(selected == null)
115+
return;
116+
117+
//Update the toggles to display the current active state
118+
foreach (var element in _radioElements)
119+
{
120+
if(element.ToggleData == selected)
121+
element.SetToggle(true);
122+
}
123+
}
102124

103-
foreach (var newElement in _radioElementSource)
125+
private void OnToggleSelect(ReRadioToggle toggle, bool state)
126+
{
127+
foreach (var element in _radioElements)
104128
{
105-
var radioButton = UnityEngine.Object.Instantiate(RadioButtonPrefab, ListBinding.gameObject.transform);
106-
radioButton.active = true;
107-
var radioButtonSelector = radioButton.GetComponent<RadioButtonSelector>();
108-
radioButtonSelector.field_Public_TextMeshProUGUI_0 = radioButtonSelector.GetComponentInChildren<TextMeshProUGUI>();
109-
radioButtonSelector.field_Private_Button_0 = radioButtonSelector.GetComponent<Button>();
110-
UnityEngine.Object.DestroyImmediate(radioButtonSelector.GetComponent<AudioDeviceButton>());
111-
radioButtonSelector.field_Private_Button_0.onClick.AddListener(new Action(() => OnSelect?.Invoke(newElement.Value.Item2)));
112-
if(newElement.Value.Item3 != null)
113-
radioButtonSelector.field_Private_Button_0.onClick.AddListener(newElement.Value.Item3);
114-
radioButtonSelector.field_Public_String_0 = newElement.Value.Item1;
115-
radioButtonSelector.SetTitle(newElement.Key, newElement.Value.Item1);
116-
radioButtonSelector.prop_RadioButtonSelectorGroup_0 = RadioButtonSelectorGroup;
117-
ListBinding.field_Protected_Dictionary_2_Object_GameObject_0.Add(newElement.Key, radioButton);
129+
if(element == toggle)
130+
continue;
131+
132+
element.SetToggle(false);
118133
}
134+
135+
OnSelect?.Invoke(toggle.ToggleData);
119136
}
120137

121138
/// <summary>
122139
/// Adds a item to the radio element source
123140
/// </summary>
124141
/// <param name="name">Name that will appear on radio toggle</param>
125142
/// <param name="obj">Object to be send in OnSelect event</param>
126-
/// <param name="onClick">OnClick when the toggle is selected in menu</param>
127-
public void AddItem(string name, Object obj, Action onClick = null)
143+
public void AddItem(string name, Object obj)
128144
{
129-
_radioElementSource.Add($"{_radioElementSource.Count}_{name}", new Tuple<string, Object, Action>(name, obj, onClick));
145+
_radioElementSource.Add(new Tuple<string, Object>(name, obj));
130146
_isUpdated = true;
131147
}
132148

VRChat/VrcUiExtensions.cs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -122,19 +122,6 @@ public static Transform GetScreen(this VRCUiManager uiManager, QuickMenu.MainMen
122122
return uiManager.MenuContent().transform.Find($"Screens/{BigMenuIndexToNameTable[menuIndex]}");
123123
}
124124

125-
private static MethodInfo[] _radioSetTitleMethods;
126-
127-
public static void SetTitle(this RadioButtonSelector selector, string key, string displayName)
128-
{
129-
_radioSetTitleMethods ??= typeof(RadioButtonSelector).GetMethods(BindingFlags.Public | BindingFlags.Instance)
130-
.Where(x => x.Name.Contains("Method_Public_Void_String_String_PDM") && XrefScanner.UsedBy(x).Any()).ToArray();
131-
132-
foreach (var method in _radioSetTitleMethods)
133-
{
134-
method.Invoke(selector, new object[] {key, displayName});
135-
}
136-
}
137-
138125
private static readonly Dictionary<QuickMenu.MainMenuScreenIndex, string> BigMenuIndexToPathTable = new Dictionary<QuickMenu.MainMenuScreenIndex, string>()
139126
{
140127
{ QuickMenu.MainMenuScreenIndex.Unknown, "" },

0 commit comments

Comments
 (0)