From 4534540786648214e9f066d940ae1935cdd51cf5 Mon Sep 17 00:00:00 2001 From: Soar Qin Date: Wed, 25 Sep 2024 20:40:46 +0800 Subject: [PATCH] Work in progress for UXAssist 1.2.5 --- UXAssist/CHANGELOG.md | 4 + UXAssist/Common/WinApi.cs | 14 +- UXAssist/Functions/WindowFunctions.cs | 54 ++++++- UXAssist/README.md | 4 + UXAssist/UI/MyCheckbox.cs | 151 +++++++++++++------- UXAssist/UI/MyComboBox.cs | 194 ++++++++++++++++++++------ UXAssist/UI/MySlider.cs | 102 ++++++++------ UXAssist/UI/MyWindow.cs | 105 ++++++++------ UXAssist/UIConfigWindow.cs | 46 ++++-- UXAssist/UXAssist.cs | 10 ++ UXAssist/UXAssist.csproj | 2 +- UXAssist/package/manifest.json | 2 +- 12 files changed, 503 insertions(+), 185 deletions(-) diff --git a/UXAssist/CHANGELOG.md b/UXAssist/CHANGELOG.md index f6b559f..705c82d 100644 --- a/UXAssist/CHANGELOG.md +++ b/UXAssist/CHANGELOG.md @@ -1,6 +1,8 @@ ## Changlog * 1.2.5 + + New feature: `Set process priority` + + New feature: `Set enabled CPU threads` + `Drag building power poles in maximum connection range`: Add a new config option `Build Tesla Tower and Wireless Power Tower alternately` * 1.2.4 + `Sunlight at night`: @@ -201,6 +203,8 @@ ## 更新日志 * 1.2.5 + + 新功能:`设置进程优先级` + + 新功能:`设置使用的CPU线程` + `拖动建造电线杆时自动使用最大连接距离间隔`:添加一个新的设置项`交替建造电力感应塔和无线输电塔` * 1.2.4 + `夜间日光灯`: diff --git a/UXAssist/Common/WinApi.cs b/UXAssist/Common/WinApi.cs index c11bb27..2fd181e 100644 --- a/UXAssist/Common/WinApi.cs +++ b/UXAssist/Common/WinApi.cs @@ -52,6 +52,16 @@ public static class WinApi #endregion + #region Priorities + + public const int HIGH_PRIORITY_CLASS = 0x00000080; + public const int ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000; + public const int NORMAL_PRIORITY_CLASS = 0x00000020; + public const int BELOW_NORMAL_PRIORITY_CLASS = 0x00004000; + public const int IDLE_PRIORITY_CLASS = 0x00000040; + + #endregion + #region Messages public const int WM_CREATE = 0x0001; @@ -113,13 +123,13 @@ public static class WinApi public static extern bool MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool bRepaint); [DllImport("kernel32", ExactSpelling = true, SetLastError = true)] - public static extern bool GetProcessAffinityMask(IntPtr hProcess, out IntPtr lpProcessAffinityMask, out IntPtr lpSystemAffinityMask); + public static extern bool GetProcessAffinityMask(IntPtr hProcess, out ulong lpProcessAffinityMask, out ulong lpSystemAffinityMask); [DllImport("kernel32", ExactSpelling = true, SetLastError = true)] public static extern IntPtr GetCurrentProcess(); [DllImport("kernel32", ExactSpelling = true, SetLastError = true)] - public static extern bool SetProcessAffinityMask(IntPtr hProcess, IntPtr dwProcessAffinityMask); + public static extern bool SetProcessAffinityMask(IntPtr hProcess, ulong dwProcessAffinityMask); // GetPriorityClass and SetPriorityClass [DllImport("kernel32", ExactSpelling = true, SetLastError = true)] diff --git a/UXAssist/Functions/WindowFunctions.cs b/UXAssist/Functions/WindowFunctions.cs index ca4cd9a..1b63d01 100644 --- a/UXAssist/Functions/WindowFunctions.cs +++ b/UXAssist/Functions/WindowFunctions.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices; +using BepInEx.Configuration; using UnityEngine; using UXAssist.Common; @@ -17,6 +18,23 @@ public static class WindowFunctions private static IntPtr _gameWindowHandle = IntPtr.Zero; private static bool _gameLoaded; + public static WinApi.LogicalProcessorDetails ProcessorDetails { get; private set; } + + public static ConfigEntry ProcessPriority; + public static ConfigEntry ProcessAffinity; + + private static readonly int[] ProrityFlags = [ + WinApi.HIGH_PRIORITY_CLASS, + WinApi.ABOVE_NORMAL_PRIORITY_CLASS, + WinApi.NORMAL_PRIORITY_CLASS, + WinApi.BELOW_NORMAL_PRIORITY_CLASS, + WinApi.IDLE_PRIORITY_CLASS + ]; + + public static void Init() + { + ProcessorDetails = WinApi.GetLogicalProcessorDetails(); + } public static void Start() { @@ -28,6 +46,39 @@ public static class WindowFunctions _oldWndProc = WinApi.SetWindowLongPtr(gameWnd, WinApi.GWLP_WNDPROC, Marshal.GetFunctionPointerForDelegate(wndProc)); } Patches.GamePatch.LoadLastWindowRect.MoveWindowPosition(true); + + ProcessPriority.SettingChanged += (_, _) => WinApi.SetPriorityClass(WinApi.GetCurrentProcess(), ProrityFlags[ProcessPriority.Value]); + WinApi.SetPriorityClass(WinApi.GetCurrentProcess(), ProrityFlags[ProcessPriority.Value]); + ProcessAffinity.SettingChanged += (_, _) => UpdateAffinity(); + UpdateAffinity(); + return; + + void UpdateAffinity() + { + var process = WinApi.GetCurrentProcess(); + if (!WinApi.GetProcessAffinityMask(process, out _, out var systemMask)) + { + systemMask = ulong.MaxValue; + } + switch (ProcessAffinity.Value) + { + case 0: + WinApi.SetProcessAffinityMask(process, systemMask); + break; + case 1: + WinApi.SetProcessAffinityMask(process, systemMask & ((1UL << (ProcessorDetails.ThreadCount / 2)) - 1UL)); + break; + case 2: + WinApi.SetProcessAffinityMask(process, systemMask & (ProcessorDetails.ThreadCount > 16 ? 0xFFUL : 1UL)); + break; + case 3: + WinApi.SetProcessAffinityMask(process, systemMask & ProcessorDetails.PerformanceCoreMask); + break; + case 4: + WinApi.SetProcessAffinityMask(process, systemMask & ProcessorDetails.EfficiencyCoreMask); + break; + } + } } private static IntPtr GameWndProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam) @@ -35,8 +86,7 @@ public static class WindowFunctions switch (uMsg) { case WinApi.WM_ACTIVATE: - // UXAssist.Logger.LogDebug($"Activate: {wParam.ToInt32()}, {lParam.ToInt32()}"); - // TODO: Set Priority like: WinApi.SetPriorityClass(WinApi.GetCurrentProcess(), 0x00000080); + WinApi.SetPriorityClass(WinApi.GetCurrentProcess(), ProrityFlags[ProcessPriority.Value]); break; case WinApi.WM_DESTROY: if (_oldWndProc != IntPtr.Zero && _gameWindowHandle != IntPtr.Zero) diff --git a/UXAssist/README.md b/UXAssist/README.md index 05ad0ce..c8b251a 100644 --- a/UXAssist/README.md +++ b/UXAssist/README.md @@ -34,6 +34,8 @@ - This will not affect some game animations. - When set game speed in mod `Auxilaryfunction`, this feature will be disabled. - When mod `BulletTime` is installed, this feature will be hidden, but patch `BulletTime`'s speed control, to make its maximum speed 10x. + - Set process priority + - Set enabled CPU threads - Increase maximum count of Metadata Instantiations to 20000 (from 2000) - Increase capacity of player order queue to 128 (from 16) + Planet/Factory @@ -147,6 +149,8 @@ - 这不会影响一些游戏动画 - 当在`Auxilaryfunction`mod中设置游戏速度时,此功能将被禁用 - 当安装了`BulletTime`mod时,此功能将被隐藏,但会对`BulletTime`的速度控制打补丁,使其最大速度变为10倍 + - 设置进程优先级 + - 设置使用的CPU线程 - 将元数据提取的最大数量增加到20000(原来为2000) - 将玩家指令队列的容量增加到128(原来为16) + 行星/工厂 diff --git a/UXAssist/UI/MyCheckbox.cs b/UXAssist/UI/MyCheckbox.cs index b272062..124fdc4 100644 --- a/UXAssist/UI/MyCheckbox.cs +++ b/UXAssist/UI/MyCheckbox.cs @@ -14,16 +14,78 @@ public class MyCheckBox : MonoBehaviour public Image checkImage; public Text labelText; public event Action OnChecked; - protected event Action OnFree; private bool _checked; + private static GameObject _baseObject; + private static readonly Color BoxColor = new Color(1f, 1f, 1f, 100f / 255f); private static readonly Color CheckColor = new Color(1f, 1f, 1f, 1f); private static readonly Color TextColor = new Color(178f / 255f, 178f / 255f, 178f / 255f, 168f / 255f); + public static void InitBaseObject() + { + if (_baseObject) return; + var go = Instantiate(UIRoot.instance.uiGame.buildMenu.uxFacilityCheck.gameObject); + go.name = "my-checkbox"; + go.SetActive(false); + var comp = go.transform.Find("text"); + if (comp) + { + var txt = comp.GetComponent(); + if (txt) txt.text = ""; + var localizer = comp.GetComponent(); + if (localizer) DestroyImmediate(localizer); + } + _baseObject = go; + } + protected void OnDestroy() { - OnFree?.Invoke(); + _config.SettingChanged -= _configChanged; + } + + public static MyCheckBox CreateCheckBox(float x, float y, RectTransform parent, ConfigEntry config, string label = "", int fontSize = 15) + { + return CreateCheckBox(x, y, parent, config.Value, label, fontSize).WithConfigEntry(config); + } + + public static MyCheckBox CreateCheckBox(float x, float y, RectTransform parent, bool check, string label = "", int fontSize = 15) + { + return CreateCheckBox(x, y, parent, fontSize).WithCheck(check).WithLabelText(label); + } + + public static MyCheckBox CreateCheckBox(float x, float y, RectTransform parent, int fontSize = 15) + { + var go = Instantiate(_baseObject); + go.name = "my-checkbox"; + go.SetActive(true); + var cb = go.AddComponent(); + var rect = Util.NormalizeRectWithTopLeft(cb, x, y, parent); + + cb.rectTrans = rect; + cb.uiButton = go.GetComponent(); + cb.boxImage = go.transform.GetComponent(); + cb.checkImage = go.transform.Find("checked")?.GetComponent(); + + var child = go.transform.Find("text"); + if (child != null) + { + cb.labelText = child.GetComponent(); + if (cb.labelText) + { + cb.labelText.text = ""; + cb.labelText.fontSize = fontSize; + cb.UpdateLabelTextWidth(); + } + } + + cb.uiButton.onClick += cb.OnClick; + return cb; + } + + private void UpdateLabelTextWidth() + { + if (labelText) labelText.rectTransform.sizeDelta = new Vector2(labelText.preferredWidth, labelText.rectTransform.sizeDelta.y); } public bool Checked @@ -36,6 +98,15 @@ public class MyCheckBox : MonoBehaviour } } + public void SetLabelText(string val) + { + if (labelText != null) + { + labelText.text = val.Translate(); + UpdateLabelTextWidth(); + } + } + public void SetEnable(bool on) { if (uiButton) uiButton.enabled = on; @@ -53,59 +124,43 @@ public class MyCheckBox : MonoBehaviour } } - public static MyCheckBox CreateCheckBox(float x, float y, RectTransform parent, ConfigEntry config, string label = "", int fontSize = 15) + private EventHandler _configChanged; + private Action _checkedChanged; + private ConfigEntry _config; + public void SetConfigEntry(ConfigEntry config) { - var cb = CreateCheckBox(x, y, parent, config.Value, label, fontSize); - cb.OnChecked += () => config.Value = !config.Value; - EventHandler func = (_, _) => cb.Checked = config.Value; - config.SettingChanged += func; - cb.OnFree += () => config.SettingChanged -= func; - return cb; + if (_checkedChanged != null) OnChecked -= _checkedChanged; + if (_configChanged != null) config.SettingChanged -= _configChanged; + + _config = config; + _checkedChanged = () => config.Value = !config.Value; + OnChecked += _checkedChanged; + _configChanged = (_, _) => Checked = config.Value; + config.SettingChanged += _configChanged; } - public static MyCheckBox CreateCheckBox(float x, float y, RectTransform parent, bool check, string label = "", int fontSize = 15) + public MyCheckBox WithLabelText(string val) { - var buildMenu = UIRoot.instance.uiGame.buildMenu; - var src = buildMenu.uxFacilityCheck; - - var go = Instantiate(src.gameObject); - go.name = "my-checkbox"; - var cb = go.AddComponent(); - cb._checked = check; - var rect = Util.NormalizeRectWithTopLeft(cb, x, y, parent); - - cb.rectTrans = rect; - cb.uiButton = go.GetComponent(); - cb.boxImage = go.transform.GetComponent(); - cb.checkImage = go.transform.Find("checked")?.GetComponent(); - - var child = go.transform.Find("text"); - if (child != null) - { - DestroyImmediate(child.GetComponent()); - cb.labelText = child.GetComponent(); - cb.labelText.fontSize = fontSize; - cb.SetLabelText(label); - var width = cb.labelText.preferredWidth; - cb.labelText.rectTransform.sizeDelta = new Vector2(width, cb.labelText.rectTransform.sizeDelta.y); - } - - //value - cb.uiButton.onClick += cb.OnClick; - if (cb.checkImage != null) - { - cb.checkImage.enabled = check; - } - - return cb; + SetLabelText(val); + return this; } - public void SetLabelText(string val) + public MyCheckBox WithCheck(bool check) { - if (labelText != null) - { - labelText.text = val.Translate(); - } + Checked = check; + return this; + } + + public MyCheckBox WithEnable(bool on) + { + SetEnable(on); + return this; + } + + public MyCheckBox WithConfigEntry(ConfigEntry config) + { + SetConfigEntry(config); + return this; } public void OnClick(int obj) diff --git a/UXAssist/UI/MyComboBox.cs b/UXAssist/UI/MyComboBox.cs index 81bcaea..935358d 100644 --- a/UXAssist/UI/MyComboBox.cs +++ b/UXAssist/UI/MyComboBox.cs @@ -1,6 +1,9 @@ using System; using System.Linq; +using System.Security.Cryptography; +using BepInEx.Configuration; using UnityEngine; +using UnityEngine.UI; namespace UXAssist.UI; @@ -8,69 +11,180 @@ public class MyComboBox : MonoBehaviour { private RectTransform _rectTrans; private UIComboBox _comboBox; - private Action _onSelChanged; + private Text _text; + public Action OnSelChanged; private static GameObject _baseObject; + public static void InitBaseObject() + { + if (_baseObject) return; + var fontSource = UIRoot.instance.uiGame.buildMenu.uxFacilityCheck.transform.Find("text")?.GetComponent(); + var go = Instantiate(UIRoot.instance.optionWindow.resolutionComp.transform.parent.gameObject); + go.name = "my-combobox"; + go.SetActive(false); + + var txt = go.GetComponent(); + if (txt) txt.text = ""; + if (txt && fontSource) + { + txt.font = fontSource.font; + txt.fontSize = fontSource.fontSize; + txt.fontStyle = fontSource.fontStyle; + txt.color = new Color(1f, 1f, 1f, 0.6f); + } + var localizer = go.GetComponent(); + if (localizer) DestroyImmediate(localizer); + + var rect = (RectTransform)go.transform; + var cbctrl = rect.transform.Find("ComboBox").GetComponent(); + foreach (var button in cbctrl.ItemButtons) + { + Destroy(button.gameObject); + } + cbctrl.Items.Clear(); + cbctrl.ItemButtons.Clear(); + if (fontSource) + { + var txtComp = cbctrl.m_ListItemRes.GetComponentInChildren(); + if (txtComp) + { + txtComp.font = fontSource.font; + txtComp.fontSize = fontSource.fontSize; + txtComp.fontStyle = fontSource.fontStyle; + } + txtComp = cbctrl.transform.Find("Main Button")?.GetComponentInChildren(); + if (txtComp) + { + txtComp.font = fontSource.font; + txtComp.fontSize = fontSource.fontSize; + txtComp.fontStyle = fontSource.fontStyle; + } + } + cbctrl.onSubmit.RemoveAllListeners(); + cbctrl.onItemIndexChange.RemoveAllListeners(); + _baseObject = go; + } + public static MyComboBox CreateComboBox(float x, float y, RectTransform parent) { - if (!_baseObject) - { - var go = Instantiate(UIRoot.instance.optionWindow.resolutionComp.transform.parent.gameObject); - go.name = "my-combobox"; - var rect = (RectTransform)go.transform; - var cbctrl = rect.transform.Find("ComboBox"); - var content = cbctrl.Find("Dropdown List ScrollBox")?.Find("Mask")?.Find("Content Panel"); - if (content != null) - { - for (var i = content.childCount - 1; i >= 0; i--) - { - var theTrans = content.GetChild(i); - if (theTrans.name == "Item Button(Clone)") - { - Destroy(theTrans.gameObject); - } - } - } - var comboBox = cbctrl.GetComponent(); - comboBox.onSubmit.RemoveAllListeners(); - comboBox.onItemIndexChange.RemoveAllListeners(); - _baseObject = go; - } var gameObject = Instantiate(_baseObject); gameObject.name = "my-combobox"; + gameObject.SetActive(true); var cb = gameObject.AddComponent(); var rtrans = Util.NormalizeRectWithTopLeft(cb, x, y, parent); cb._rectTrans = rtrans; - - var box = rtrans.transform.Find("ComboBox").GetComponent(); + cb._text = gameObject.GetComponent(); + var box = rtrans.Find("ComboBox").GetComponent(); cb._comboBox = box; - box.onItemIndexChange.AddListener(() => { cb._onSelChanged?.Invoke(box.itemIndex); }); + box.onItemIndexChange.AddListener(() => { cb.OnSelChanged?.Invoke(box.itemIndex); }); + cb.UpdateComboBoxPosition(); return cb; } - - public MyComboBox SetItems(string[] items) + + protected void OnDestroy() { - _comboBox.Items = items.ToList(); + _config.SettingChanged -= _configChanged; + } + + private void UpdateComboBoxPosition() + { + var rtrans = (RectTransform)_comboBox.transform; + var oldPosition = rtrans.localPosition; + var pwidth = _text.preferredWidth; + rtrans.localPosition = new Vector3(pwidth + 5f, oldPosition.y, oldPosition.z); + _rectTrans.sizeDelta = new Vector2(rtrans.localPosition.x + rtrans.sizeDelta.x, _rectTrans.sizeDelta.y); + } + + public void SetPrompt(string prompt) + { + _text.text = prompt.Translate(); + UpdateComboBoxPosition(); + } + + public void SetFontSize(int size) + { + _text.fontSize = size; + _comboBox.ItemButtons.ForEach(b => b.GetComponentInChildren().fontSize = size); + _comboBox.m_ListItemRes.GetComponentInChildren().fontSize = size; + var txtComp = _comboBox.transform.Find("Main Button")?.GetComponentInChildren(); + if (txtComp) txtComp.fontSize = size; + UpdateComboBoxPosition(); + } + + public void SetItems(params string[] items) => _comboBox.Items = items.Select(s => s.Translate()).ToList(); + + public void SetIndex(int index) => _comboBox.itemIndex = index; + + public void SetSize(float width, float height) + { + var rtrans = (RectTransform)_comboBox.transform; + rtrans.sizeDelta = new Vector2(width > 0f ? width : rtrans.sizeDelta.x, height > 0f ? height : rtrans.sizeDelta.y); + _rectTrans.sizeDelta = new Vector2(rtrans.localPosition.x + rtrans.sizeDelta.x, _rectTrans.sizeDelta.y); + } + + public void AddOnSelChanged(Action action) => OnSelChanged += action; + + private EventHandler _configChanged; + private Action _selChanged; + private ConfigEntry _config; + public void SetConfigEntry(ConfigEntry config) + { + if (_selChanged != null) OnSelChanged -= _selChanged; + if (_configChanged != null) config.SettingChanged -= _configChanged; + + _comboBox.itemIndex = config.Value; + _config = config; + _selChanged = value => config.Value = value; + OnSelChanged += _selChanged; + _configChanged = (_, _) => SetIndex(config.Value); + config.SettingChanged += _configChanged; + } + + public MyComboBox WithPrompt(string prompt) + { + SetPrompt(prompt); return this; } - public MyComboBox SetIndex(int index) + public MyComboBox WithFontSize(int size) { - _comboBox.itemIndex = index; - return this; - } - - public MyComboBox AddOnSelChanged(Action action) - { - _onSelChanged += action; + SetFontSize(size); return this; } - public MyComboBox SetSize(float width, float height) + public MyComboBox WithItems(params string[] items) { - _rectTrans.sizeDelta = new Vector2(width, height); + SetItems(items); return this; } + + public MyComboBox WithIndex(int index) + { + SetIndex(index); + return this; + } + + public MyComboBox WithSize(float width, float height) + { + SetSize(width, height); + return this; + } + + public MyComboBox WithOnSelChanged(params Action[] action) + { + foreach (var act in action) + AddOnSelChanged(act); + return this; + } + + public MyComboBox WithConfigEntry(ConfigEntry config) + { + SetConfigEntry(config); + return this; + } + + public float Width => _rectTrans.sizeDelta.x; + public float Height => _rectTrans.sizeDelta.y; } \ No newline at end of file diff --git a/UXAssist/UI/MySlider.cs b/UXAssist/UI/MySlider.cs index 6ea7179..373e871 100644 --- a/UXAssist/UI/MySlider.cs +++ b/UXAssist/UI/MySlider.cs @@ -14,36 +14,13 @@ public class MySlider : MonoBehaviour public Text labelText; public string labelFormat; public event Action OnValueChanged; - private float _value; - - public void SetEnable(bool on) - { - lock (this) - { - if (slider) slider.interactable = on; - } - } - - public MySlider MakeHandleSmaller(float deltaX = 10f, float deltaY = 0f) - { - var oldSize = slider.handleRect.sizeDelta; - slider.handleRect.sizeDelta = new Vector2(oldSize.x - deltaX, oldSize.y - deltaY); - handleSlideArea.offsetMin = new Vector2(handleSlideArea.offsetMin.x - deltaX / 2, handleSlideArea.offsetMin.y); - handleSlideArea.offsetMax = new Vector2(handleSlideArea.offsetMax.x + deltaX / 2, handleSlideArea.offsetMax.y); - return this; - } - - public float Value - { - get => _value; - set - { - _value = value; - OnValueSet(); - } - } public static MySlider CreateSlider(float x, float y, RectTransform parent, float value, float minValue, float maxValue, string format = "G", float width = 0f) + { + return CreateSlider(x, y, parent, width).WithLabelFormat(format).WithMinMaxValue(minValue, maxValue).WithValue(value); + } + + public static MySlider CreateSlider(float x, float y, RectTransform parent, float width = 0f) { var optionWindow = UIRoot.instance.optionWindow; var src = optionWindow.audioVolumeComp; @@ -53,7 +30,6 @@ public class MySlider : MonoBehaviour go.name = "my-slider"; go.SetActive(true); var sl = go.AddComponent(); - sl._value = value; var rect = Util.NormalizeRectWithTopLeft(sl, x, y, parent); sl.rectTrans = rect; if (width > 0) @@ -62,10 +38,11 @@ public class MySlider : MonoBehaviour } sl.slider = go.GetComponent(); - sl.slider.minValue = minValue; - sl.slider.maxValue = maxValue; + sl.slider.minValue = 0f; + sl.slider.maxValue = 100f; sl.slider.onValueChanged.RemoveAllListeners(); sl.slider.onValueChanged.AddListener(sl.SliderChanged); + sl.Value = 0f; sl.labelText = sl.slider.handleRect.Find("Text")?.GetComponent(); if (sl.labelText) { @@ -75,7 +52,7 @@ public class MySlider : MonoBehaviour rectTrans.sizeDelta = new Vector2(22f, 22f); } } - sl.labelFormat = format; + sl.labelFormat = "G"; sl.handleSlideArea = sl.transform.Find("Handle Slide Area")?.GetComponent(); @@ -89,35 +66,72 @@ public class MySlider : MonoBehaviour { fill.color = new Color(1f, 1f, 1f, 0.28f); } - sl.OnValueSet(); sl.UpdateLabel(); return sl; } - public void OnValueSet() + + public void SetEnable(bool on) { lock (this) { - var sliderVal = _value; + if (slider) slider.interactable = on; + } + } + + public float Value + { + get => slider.value; + set + { + var sliderVal = value; if (sliderVal.Equals(slider.value)) return; if (sliderVal > slider.maxValue) { - _value = sliderVal = slider.maxValue; + sliderVal = slider.maxValue; } else if (sliderVal < slider.minValue) { - _value = sliderVal = slider.minValue; + sliderVal = slider.minValue; } slider.value = sliderVal; UpdateLabel(); } } + + public MySlider WithValue(float value) + { + Value = value; + return this; + } + + public MySlider WithMinMaxValue(float min, float max) + { + slider.minValue = min; + slider.maxValue = max; + return this; + } + + public MySlider WithLabelFormat(string format) + { + if (format == labelFormat) return this; + labelFormat = format; + UpdateLabel(); + return this; + } + + public MySlider WithEnable(bool on) + { + SetEnable(on); + return this; + } + public void UpdateLabel() { if (labelText != null) { - labelText.text = _value.ToString(labelFormat); + labelText.text = slider.value.ToString(labelFormat); } } @@ -129,13 +143,19 @@ public class MySlider : MonoBehaviour } } + public MySlider WithSmallerHandle(float deltaX = 10f, float deltaY = 0f) + { + var oldSize = slider.handleRect.sizeDelta; + slider.handleRect.sizeDelta = new Vector2(oldSize.x - deltaX, oldSize.y - deltaY); + handleSlideArea.offsetMin = new Vector2(handleSlideArea.offsetMin.x - deltaX / 2, handleSlideArea.offsetMin.y); + handleSlideArea.offsetMax = new Vector2(handleSlideArea.offsetMax.x + deltaX / 2, handleSlideArea.offsetMax.y); + return this; + } + public void SliderChanged(float val) { lock (this) { - var newVal = Mathf.Round(slider.value); - if (_value.Equals(newVal)) return; - _value = newVal; UpdateLabel(); OnValueChanged?.Invoke(); } diff --git a/UXAssist/UI/MyWindow.cs b/UXAssist/UI/MyWindow.cs index 0cf1419..ed95241 100644 --- a/UXAssist/UI/MyWindow.cs +++ b/UXAssist/UI/MyWindow.cs @@ -7,7 +7,6 @@ using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using UXAssist.Common; -using Object = UnityEngine.Object; namespace UXAssist.UI; @@ -23,6 +22,46 @@ public class MyWindow : ManualBehaviour protected const float Margin = 30f; protected const float Spacing = 10f; public event Action OnFree; + private static GameObject _baseObject; + + public static void InitBaseObject() + { + if (_baseObject) return; + var go = Instantiate(UIRoot.instance.uiGame.tankWindow.gameObject); + go.SetActive(false); + go.name = "my-window"; + Destroy(go.GetComponent()); + for (var i = 0; i < go.transform.childCount; i++) + { + var child = go.transform.GetChild(i).gameObject; + if (child.name != "panel-bg" && child.name != "shadow" && child.name != "panel-bg") + { + Destroy(child); + } + } + + _baseObject = go; + } + + public static T Create(string name, string title = "") where T : MyWindow + { + var go = Instantiate(_baseObject, UIRoot.instance.uiGame.transform.parent); + go.name = name; + go.SetActive(false); + MyWindow win = go.AddComponent(); + if (!win) return null; + + var btn = go.transform.Find("panel-bg")?.gameObject.GetComponentInChildren