DropdownHelper.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. using System;
  2. using UnityEngine;
  3. namespace MeidoPhotoStudio.Plugin;
  4. public static class DropdownHelper
  5. {
  6. public static Rect DropdownWindow;
  7. private static int dropdownID = 100;
  8. private static GUIStyle defaultDropdownStyle;
  9. private static bool onScrollBar;
  10. private static Rect dropdownScrollRect;
  11. private static Rect dropdownRect;
  12. private static GUIStyle dropdownStyle;
  13. private static GUIStyle windowStyle;
  14. private static Rect buttonRect;
  15. private static string[] dropdownList;
  16. private static Vector2 scrollPos;
  17. private static int currentDropdownID;
  18. private static int selectedItemIndex;
  19. private static bool initialized;
  20. public static event EventHandler<DropdownSelectArgs> SelectionChange;
  21. public static event EventHandler<DropdownCloseArgs> DropdownClose;
  22. public static int DropdownID =>
  23. dropdownID++;
  24. public static GUIStyle DefaultDropdownStyle
  25. {
  26. get
  27. {
  28. if (!initialized)
  29. InitializeStyle();
  30. return defaultDropdownStyle;
  31. }
  32. }
  33. public static bool Visible { get; set; }
  34. public static bool DropdownOpen { get; private set; }
  35. public static Vector2 CalculateElementSize(string item, GUIStyle style = null)
  36. {
  37. if (!initialized)
  38. InitializeStyle();
  39. style ??= DefaultDropdownStyle;
  40. return style.CalcSize(new(item));
  41. }
  42. public static Vector2 CalculateElementSize(string[] list, GUIStyle style = null)
  43. {
  44. if (!initialized)
  45. InitializeStyle();
  46. style ??= DefaultDropdownStyle;
  47. var content = new GUIContent(list[0]);
  48. var calculatedSize = style.CalcSize(content);
  49. for (var i = 1; i < list.Length; i++)
  50. {
  51. content.text = list[i];
  52. var calcSize = style.CalcSize(content);
  53. if (calcSize.x > calculatedSize.x)
  54. calculatedSize = calcSize;
  55. }
  56. return calculatedSize;
  57. }
  58. public static void Set(Dropdown dropdown, GUIStyle style = null)
  59. {
  60. dropdownStyle = style ?? DefaultDropdownStyle;
  61. currentDropdownID = dropdown.DropdownID;
  62. dropdownList = dropdown.DropdownList;
  63. scrollPos = dropdown.ScrollPos;
  64. selectedItemIndex = dropdown.SelectedItemIndex;
  65. scrollPos = dropdown.ScrollPos;
  66. buttonRect = dropdown.ButtonRect;
  67. var calculatedSize = dropdown.ElementSize;
  68. var calculatedListHeight = calculatedSize.y * dropdownList.Length;
  69. var heightAbove = buttonRect.y;
  70. var heightBelow = Screen.height - heightAbove - buttonRect.height;
  71. var rectWidth = Mathf.Max(calculatedSize.x + 5, buttonRect.width);
  72. var rectHeight = Mathf.Min(calculatedListHeight, Mathf.Max(heightAbove, heightBelow));
  73. if (calculatedListHeight > heightBelow && heightAbove > heightBelow)
  74. {
  75. DropdownWindow = new(buttonRect.x, buttonRect.y - rectHeight, rectWidth + 18, rectHeight);
  76. }
  77. else
  78. {
  79. if (calculatedListHeight > heightBelow)
  80. rectHeight -= calculatedSize.y;
  81. DropdownWindow = new(buttonRect.x, buttonRect.y + buttonRect.height, rectWidth + 18, rectHeight);
  82. }
  83. DropdownWindow.x = Mathf.Clamp(DropdownWindow.x, 0, Screen.width - rectWidth - 18);
  84. dropdownScrollRect = new(0, 0, DropdownWindow.width, DropdownWindow.height);
  85. dropdownRect = new(0, 0, DropdownWindow.width - 18, calculatedListHeight);
  86. DropdownOpen = true;
  87. Visible = true;
  88. }
  89. public static void HandleDropdown()
  90. {
  91. DropdownWindow = GUI.Window(Constants.DropdownWindowID, DropdownWindow, GUIFunc, string.Empty, windowStyle);
  92. if (Input.mouseScrollDelta.y is not 0f && Visible && DropdownWindow.Contains(Event.current.mousePosition))
  93. Input.ResetInputAxes();
  94. }
  95. private static void GUIFunc(int id)
  96. {
  97. var clicked = false;
  98. if (Event.current.type is EventType.MouseUp)
  99. clicked = true;
  100. scrollPos = GUI.BeginScrollView(dropdownScrollRect, scrollPos, dropdownRect);
  101. var selection = GUI.SelectionGrid(dropdownRect, selectedItemIndex, dropdownList, 1, dropdownStyle);
  102. GUI.EndScrollView();
  103. var clickedYou = false;
  104. if (Utility.AnyMouseDown())
  105. {
  106. var mousePos = GUIUtility.GUIToScreenPoint(Event.current.mousePosition);
  107. var clickedMe = DropdownWindow.Contains(mousePos);
  108. onScrollBar = mousePos.x > DropdownWindow.x + DropdownWindow.width - 12f;
  109. if (buttonRect.Contains(mousePos))
  110. clickedYou = true;
  111. if (!clickedMe)
  112. DropdownOpen = false;
  113. }
  114. if (selection != selectedItemIndex || clicked && !onScrollBar)
  115. {
  116. SelectionChange?.Invoke(null, new(currentDropdownID, selection));
  117. DropdownOpen = false;
  118. }
  119. if (!DropdownOpen)
  120. {
  121. Visible = false;
  122. DropdownClose?.Invoke(null, new(currentDropdownID, scrollPos, clickedYou));
  123. }
  124. }
  125. private static void InitializeStyle()
  126. {
  127. defaultDropdownStyle = new(GUI.skin.button)
  128. {
  129. alignment = TextAnchor.MiddleLeft,
  130. margin = new(0, 0, 0, 0),
  131. };
  132. defaultDropdownStyle.padding.top = defaultDropdownStyle.padding.bottom = 2;
  133. defaultDropdownStyle.normal.background = Utility.MakeTex(2, 2, new(0f, 0f, 0f, 0.5f));
  134. var whiteBackground = new Texture2D(2, 2);
  135. defaultDropdownStyle.onHover.background
  136. = defaultDropdownStyle.hover.background
  137. = defaultDropdownStyle.onNormal.background
  138. = whiteBackground;
  139. defaultDropdownStyle.onHover.textColor
  140. = defaultDropdownStyle.onNormal.textColor
  141. = defaultDropdownStyle.hover.textColor
  142. = Color.black;
  143. windowStyle = new(GUI.skin.box)
  144. {
  145. padding = new(0, 0, 0, 0),
  146. alignment = TextAnchor.UpperRight,
  147. };
  148. initialized = true;
  149. }
  150. public class DropdownEventArgs : EventArgs
  151. {
  152. public DropdownEventArgs(int dropdownID) =>
  153. DropdownID = dropdownID;
  154. public int DropdownID { get; }
  155. }
  156. public class DropdownSelectArgs : DropdownEventArgs
  157. {
  158. public DropdownSelectArgs(int dropdownID, int selection)
  159. : base(dropdownID) =>
  160. SelectedItemIndex = selection;
  161. public int SelectedItemIndex { get; }
  162. }
  163. public class DropdownCloseArgs : DropdownEventArgs
  164. {
  165. public DropdownCloseArgs(int dropdownID, Vector2 scrollPos, bool clickedYou = false)
  166. : base(dropdownID)
  167. {
  168. ScrollPos = scrollPos;
  169. ClickedYou = clickedYou;
  170. }
  171. public Vector2 ScrollPos { get; }
  172. public bool ClickedYou { get; }
  173. }
  174. }