using System; using BepInEx; using CharaCustom; using KKAPI.Utilities; using UniRx; using UniRx.Triggers; using UnityEngine; using UnityEngine.UI; using Object = UnityEngine.Object; namespace KKAPI.Maker.UI { /// /// Custom control that draws a slider and a text box (both are used to edit the same value) /// public class MakerSlider : BaseEditableGuiEntry { private static Transform _sliderCopy; private readonly string _settingName; private readonly float _maxValue; private readonly float _minValue; private readonly float _defaultValue; /// /// Create a new custom control. Create and register it in . /// /// Text displayed next to the slider /// Category the control will be created under /// Plugin that owns the control /// Lowest allowed value (inclusive) /// Highest allowed value (inclusive) /// Value the slider will be set to after creation public MakerSlider(MakerCategory category, string settingName, float minValue, float maxValue, float defaultValue, BaseUnityPlugin owner) : base(category, defaultValue, owner) { _settingName = settingName; _minValue = minValue; _maxValue = maxValue; _defaultValue = defaultValue; } /// /// Custom converter from text in the textbox to the slider value. /// If not set, float.Parse(txt) / 100f is used. /// public Func StringToValue { get; set; } /// /// Custom converter from the slider value to what's displayed in the textbox. /// If not set, Mathf.RoundToInt(f * 100).ToString() is used. /// public Func ValueToString { get; set; } private static Transform SliderCopy { get { if (_sliderCopy == null) MakeCopy(); return _sliderCopy; } } private static void MakeCopy() { var originalSlider = GameObject.FindObjectOfType().transform; _sliderCopy = Object.Instantiate(originalSlider, GuiCacheTransfrom, false); _sliderCopy.gameObject.SetActive(false); _sliderCopy.name = "sldTemp"; var slider = _sliderCopy.GetComponent(); slider.onChange = null; slider.onPointerUp = null; slider.onSetDefaultValue = null; foreach (var renderer in _sliderCopy.GetComponentsInChildren()) renderer.raycastTarget = true; RemoveLocalisation(_sliderCopy.gameObject); } /// protected internal override void Initialize() { if (_sliderCopy == null) MakeCopy(); } /// protected override GameObject OnCreateControl(Transform subCategoryList) { var tr = Object.Instantiate(SliderCopy, subCategoryList, false); tr.name = "SliderSet"; var sliderSet = tr.GetComponent(); sliderSet.onChange = null; sliderSet.onPointerUp = null; sliderSet.onSetDefaultValue = null; GameObject.Destroy(sliderSet); sliderSet.title.text = _settingName; sliderSet.title.color = TextColor; SetTextAutosize(sliderSet.title); var slider = sliderSet.slider; slider.minValue = _minValue; slider.maxValue = _maxValue; slider.onValueChanged.ActuallyRemoveAllListeners(); slider.onValueChanged.AddListener(SetValue); slider.GetComponent() .OnScrollAsObservable() .Subscribe( data => { var scrollDelta = data.scrollDelta.y; var valueChange = Mathf.Pow(10, Mathf.Round(Mathf.Log10(slider.maxValue / 100))); if (scrollDelta < 0f) slider.value += valueChange; else if (scrollDelta > 0f) slider.value -= valueChange; }); var inputField = sliderSet.input; inputField.onEndEdit.AddListener( txt => { try { var result = StringToValue?.Invoke(txt) ?? float.Parse(txt) / 100f; slider.value = Mathf.Clamp(result, slider.minValue, slider.maxValue); } catch { // Ignore parsing errors, lets user keep typing } }); slider.onValueChanged.AddListener( f => { if (ValueToString != null) inputField.text = ValueToString(f); else inputField.text = Mathf.RoundToInt(f * 100).ToString(); }); var resetButton = sliderSet.button; resetButton.onClick.ActuallyRemoveAllListeners(); resetButton.onClick.AddListener(() => slider.value = _defaultValue); BufferedValueChanged.Subscribe(f => slider.value = f); return tr.gameObject; } } }