|
|
@@ -1,5 +1,7 @@
|
|
|
using LightGlue.Unity.Game;
|
|
|
+using LightGlue.Unity.Config;
|
|
|
using System.Collections.Generic;
|
|
|
+using TMPro;
|
|
|
using UnityEngine;
|
|
|
using UnityEngine.SceneManagement;
|
|
|
using UnityEngine.UI;
|
|
|
@@ -110,6 +112,17 @@ namespace LightGlue.Unity.UI
|
|
|
|
|
|
private GameObject _cursorSettingsInstance;
|
|
|
|
|
|
+ [Header("Reference Resize (统一与 Python --resize 一致)")]
|
|
|
+ [Tooltip("参考图像 resize 下拉框。若不绑定,将在运行时尝试克隆一个现有 TMP_Dropdown 作为样式,并生成到 UIRoot 下。")]
|
|
|
+ [SerializeField]
|
|
|
+ private TMP_Dropdown resizeDropdown;
|
|
|
+
|
|
|
+ [Tooltip("resize 预设列表(格式:\"320x240\")。")]
|
|
|
+ [SerializeField]
|
|
|
+ private List<string> resizePresets = new List<string> { "320x240", "640x480" };
|
|
|
+
|
|
|
+ private bool _resizeDropdownInitialized;
|
|
|
+
|
|
|
#region 生成RomaUI管理插件部分
|
|
|
public static void Create(UIType uiType = UIType.Plugin, GameObject parentObj = null)
|
|
|
{
|
|
|
@@ -257,6 +270,135 @@ namespace LightGlue.Unity.UI
|
|
|
|
|
|
ApplyUITypeVisibility();
|
|
|
ApplySceneVisibilityNodes(SceneManager.GetActiveScene().name);
|
|
|
+
|
|
|
+ EnsureResizeDropdown();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void EnsureResizeDropdown()
|
|
|
+ {
|
|
|
+ if (_resizeDropdownInitialized) return;
|
|
|
+ _resizeDropdownInitialized = true;
|
|
|
+
|
|
|
+ ReferenceImageResizeService.EnsureInitialized();
|
|
|
+
|
|
|
+ if (resizeDropdown == null)
|
|
|
+ {
|
|
|
+ resizeDropdown = TryCloneAnyTmpDropdown();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (resizeDropdown == null)
|
|
|
+ {
|
|
|
+ Debug.LogWarning("[LightGlueUI] 未找到/未生成 resizeDropdown(TMP_Dropdown)。请在 LightGlueUIManager Inspector 绑定一个 TMP_Dropdown,或确保 UI 中存在可克隆的 TMP_Dropdown。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var options = new List<TMP_Dropdown.OptionData>();
|
|
|
+ for (int i = 0; i < resizePresets.Count; i++)
|
|
|
+ {
|
|
|
+ string s = resizePresets[i];
|
|
|
+ if (string.IsNullOrWhiteSpace(s)) continue;
|
|
|
+ options.Add(new TMP_Dropdown.OptionData(s.Trim()));
|
|
|
+ }
|
|
|
+ if (options.Count == 0)
|
|
|
+ {
|
|
|
+ options.Add(new TMP_Dropdown.OptionData("320x240"));
|
|
|
+ }
|
|
|
+
|
|
|
+ resizeDropdown.onValueChanged.RemoveListener(OnResizeDropdownChanged);
|
|
|
+ resizeDropdown.ClearOptions();
|
|
|
+ resizeDropdown.AddOptions(options);
|
|
|
+
|
|
|
+ int currentIndex = FindPresetIndex(ReferenceImageResizeService.Width, ReferenceImageResizeService.Height, resizePresets);
|
|
|
+ if (currentIndex < 0) currentIndex = 0;
|
|
|
+ resizeDropdown.SetValueWithoutNotify(currentIndex);
|
|
|
+ resizeDropdown.onValueChanged.AddListener(OnResizeDropdownChanged);
|
|
|
+ }
|
|
|
+
|
|
|
+ private TMP_Dropdown TryCloneAnyTmpDropdown()
|
|
|
+ {
|
|
|
+ if (uiRoot == null) uiRoot = gameObject;
|
|
|
+ Transform parent = uiRoot.transform;
|
|
|
+
|
|
|
+ TMP_Dropdown sample = null;
|
|
|
+ var dropdowns = uiRoot.GetComponentsInChildren<TMP_Dropdown>(true);
|
|
|
+ if (dropdowns != null && dropdowns.Length > 0)
|
|
|
+ {
|
|
|
+ // 优先找名字含 "resolution" 的下拉框(现有UI里通常有)
|
|
|
+ for (int i = 0; i < dropdowns.Length; i++)
|
|
|
+ {
|
|
|
+ var d = dropdowns[i];
|
|
|
+ if (d != null && d.name.ToLowerInvariant().Contains("resolution"))
|
|
|
+ {
|
|
|
+ sample = d;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (sample == null)
|
|
|
+ sample = dropdowns[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sample == null) return null;
|
|
|
+
|
|
|
+ var inst = Instantiate(sample.gameObject, sample.transform.parent != null ? sample.transform.parent : parent);
|
|
|
+ inst.name = "ResizeDropdown";
|
|
|
+
|
|
|
+ // 尽量让它在 sample 旁边,避免遮挡
|
|
|
+ var rt = inst.GetComponent<RectTransform>();
|
|
|
+ var sampleRt = sample.GetComponent<RectTransform>();
|
|
|
+ if (rt != null && sampleRt != null)
|
|
|
+ {
|
|
|
+ rt.anchorMin = sampleRt.anchorMin;
|
|
|
+ rt.anchorMax = sampleRt.anchorMax;
|
|
|
+ rt.pivot = sampleRt.pivot;
|
|
|
+ rt.sizeDelta = sampleRt.sizeDelta;
|
|
|
+ rt.anchoredPosition = sampleRt.anchoredPosition + new Vector2(0, - (sampleRt.sizeDelta.y + 10f));
|
|
|
+ rt.localScale = sampleRt.localScale;
|
|
|
+ }
|
|
|
+
|
|
|
+ var dd = inst.GetComponent<TMP_Dropdown>();
|
|
|
+ if (dd == null) return null;
|
|
|
+
|
|
|
+ // 尝试改一下 label,方便辨识(不保证所有模板都有 captionText)
|
|
|
+ if (dd.captionText != null)
|
|
|
+ dd.captionText.text = "Resize";
|
|
|
+
|
|
|
+ return dd;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static int FindPresetIndex(int w, int h, List<string> presets)
|
|
|
+ {
|
|
|
+ if (presets == null) return -1;
|
|
|
+ string target = $"{w}x{h}";
|
|
|
+ for (int i = 0; i < presets.Count; i++)
|
|
|
+ {
|
|
|
+ string s = presets[i];
|
|
|
+ if (string.IsNullOrWhiteSpace(s)) continue;
|
|
|
+ if (NormalizePreset(s) == target) return i;
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static string NormalizePreset(string s)
|
|
|
+ {
|
|
|
+ s = s.Trim().ToLowerInvariant().Replace(" ", "");
|
|
|
+ s = s.Replace("*", "x").Replace("×", "x");
|
|
|
+ return s;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OnResizeDropdownChanged(int index)
|
|
|
+ {
|
|
|
+ if (resizePresets == null || resizePresets.Count == 0) return;
|
|
|
+ if (index < 0 || index >= resizePresets.Count) return;
|
|
|
+ string preset = resizePresets[index];
|
|
|
+ if (string.IsNullOrWhiteSpace(preset)) return;
|
|
|
+
|
|
|
+ preset = NormalizePreset(preset);
|
|
|
+ var parts = preset.Split('x');
|
|
|
+ if (parts.Length != 2) return;
|
|
|
+ if (!int.TryParse(parts[0], out int w)) return;
|
|
|
+ if (!int.TryParse(parts[1], out int h)) return;
|
|
|
+
|
|
|
+ ReferenceImageResizeService.Set(w, h, persistToNetworkConfig: true);
|
|
|
}
|
|
|
|
|
|
private void OnDestroy()
|