No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PlasticDialog.cs 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEditor;
  4. using UnityEngine;
  5. using PlasticGui;
  6. namespace Unity.PlasticSCM.Editor.UI
  7. {
  8. internal abstract class PlasticDialog : EditorWindow, IPlasticDialogCloser
  9. {
  10. protected virtual Rect DefaultRect
  11. {
  12. get
  13. {
  14. int pixelWidth = Screen.currentResolution.width;
  15. float x = (pixelWidth - DEFAULT_WIDTH) / 2;
  16. return new Rect(x, 200, DEFAULT_WIDTH, DEFAULT_HEIGHT);
  17. }
  18. }
  19. protected virtual bool IsResizable { get; set; }
  20. internal void OkButtonAction()
  21. {
  22. CompleteModal(ResponseType.Ok);
  23. }
  24. internal void CancelButtonAction()
  25. {
  26. CompleteModal(ResponseType.Cancel);
  27. }
  28. internal void CloseButtonAction()
  29. {
  30. CompleteModal(ResponseType.None);
  31. }
  32. internal void ApplyButtonAction()
  33. {
  34. CompleteModal(ResponseType.Apply);
  35. }
  36. internal ResponseType RunModal(EditorWindow parentWindow)
  37. {
  38. InitializeVars(parentWindow);
  39. if (!IsResizable)
  40. MakeNonResizable();
  41. if (UI.RunModal.IsAvailable())
  42. {
  43. UI.RunModal.Dialog(this);
  44. return mAnswer;
  45. }
  46. EditorUtility.DisplayDialog(
  47. PlasticLocalization.GetString(PlasticLocalization.Name.UnityVersionControl),
  48. PlasticLocalization.GetString(PlasticLocalization.Name.PluginModalInformation),
  49. PlasticLocalization.GetString(PlasticLocalization.Name.CloseButton));
  50. return ResponseType.None;
  51. }
  52. protected void OnGUI()
  53. {
  54. try
  55. {
  56. // If the Dialog has been saved into the Unity editor layout and persisted between restarts, the methods
  57. // to configure the dialogs will be skipped. Simple fix here is to close it when this state is detected.
  58. // Fixes a NPE loop when the state mentioned above is occurring.
  59. if (!mIsConfigured)
  60. {
  61. mIsClosed = true;
  62. Close();
  63. return;
  64. }
  65. if (Event.current.type == EventType.Layout)
  66. {
  67. EditorDispatcher.Update();
  68. }
  69. if (!mFocusedOnce)
  70. {
  71. // Somehow the prevents the dialog from jumping when dragged
  72. // NOTE(rafa): We cannot do every frame because the modal kidnaps focus for all processes (in mac at least)
  73. Focus();
  74. mFocusedOnce = true;
  75. }
  76. ProcessKeyActions();
  77. if (mIsClosed)
  78. return;
  79. GUI.Box(new Rect(0, 0, position.width, position.height), GUIContent.none, EditorStyles.label);
  80. float margin = 25;
  81. float marginTop = 25;
  82. using (new EditorGUILayout.HorizontalScope(GUILayout.Height(position.height)))
  83. {
  84. GUILayout.Space(margin);
  85. using (new EditorGUILayout.VerticalScope(GUILayout.Height(position.height)))
  86. {
  87. GUILayout.Space(marginTop);
  88. OnModalGUI();
  89. GUILayout.Space(margin);
  90. }
  91. GUILayout.Space(margin);
  92. }
  93. var lastRect = GUILayoutUtility.GetLastRect();
  94. float desiredHeight = lastRect.yMax;
  95. Rect newPos = position;
  96. newPos.height = desiredHeight;
  97. if (position.height < desiredHeight)
  98. position = newPos;
  99. if (Event.current.type == EventType.Repaint)
  100. {
  101. if (mIsCompleted)
  102. {
  103. mIsClosed = true;
  104. Close();
  105. }
  106. }
  107. }
  108. finally
  109. {
  110. if (mIsClosed)
  111. EditorGUIUtility.ExitGUI();
  112. }
  113. }
  114. void OnDestroy()
  115. {
  116. if (!mIsConfigured)
  117. return;
  118. SaveSettings();
  119. if (mParentWindow == null)
  120. return;
  121. mParentWindow.Focus();
  122. }
  123. protected virtual void SaveSettings() { }
  124. protected abstract void OnModalGUI();
  125. protected abstract string GetTitle();
  126. protected void Paragraph(string text)
  127. {
  128. GUILayout.Label(text, UnityStyles.Paragraph);
  129. GUILayout.Space(DEFAULT_PARAGRAPH_SPACING);
  130. }
  131. protected void TextBlockWithEndLink(
  132. string url, string formattedExplanation,
  133. GUIStyle textblockStyle)
  134. {
  135. DrawTextBlockWithEndLink.For(url, formattedExplanation, textblockStyle);
  136. }
  137. protected static void Title(string text)
  138. {
  139. GUILayout.Label(text, UnityStyles.Dialog.Toggle);
  140. }
  141. protected static bool TitleToggle(string text, bool isOn)
  142. {
  143. return EditorGUILayout.ToggleLeft(text, isOn, UnityStyles.Dialog.Toggle);
  144. }
  145. protected static bool TitleToggle(string text, bool isOn, GUIStyle style)
  146. {
  147. return EditorGUILayout.ToggleLeft(text, isOn, style);
  148. }
  149. protected static string TextEntry(
  150. string label,
  151. string value,
  152. float width,
  153. float x)
  154. {
  155. return TextEntry(
  156. label,
  157. value,
  158. null,
  159. width,
  160. x);
  161. }
  162. protected static string TextEntry(
  163. string label, string value, string controlName, float width, float x)
  164. {
  165. using (new EditorGUILayout.HorizontalScope())
  166. {
  167. EntryLabel(label);
  168. GUILayout.FlexibleSpace();
  169. var rt = GUILayoutUtility.GetRect(
  170. new GUIContent(value), UnityStyles.Dialog.EntryLabel);
  171. rt.width = width;
  172. rt.x = x;
  173. if (!string.IsNullOrEmpty(controlName))
  174. GUI.SetNextControlName(controlName);
  175. return GUI.TextField(rt, value);
  176. }
  177. }
  178. protected static string ComboBox(
  179. string label,
  180. string value,
  181. string controlName,
  182. List<string> dropDownOptions,
  183. GenericMenu.MenuFunction2 optionSelected,
  184. float width,
  185. float x)
  186. {
  187. using (new EditorGUILayout.HorizontalScope())
  188. {
  189. EntryLabel(label);
  190. GUILayout.FlexibleSpace();
  191. var rt = GUILayoutUtility.GetRect(
  192. new GUIContent(value), UnityStyles.Dialog.EntryLabel);
  193. rt.width = width;
  194. rt.x = x;
  195. return DropDownTextField.DoDropDownTextField(
  196. value,
  197. label,
  198. dropDownOptions,
  199. optionSelected,
  200. rt);
  201. }
  202. }
  203. protected static string PasswordEntry(
  204. string label, string value, float width, float x)
  205. {
  206. using (new EditorGUILayout.HorizontalScope())
  207. {
  208. EntryLabel(label);
  209. GUILayout.FlexibleSpace();
  210. var rt = GUILayoutUtility.GetRect(
  211. new GUIContent(value), UnityStyles.Dialog.EntryLabel);
  212. rt.width = width;
  213. rt.x = x;
  214. return GUI.PasswordField(rt, value, '*');
  215. }
  216. }
  217. protected static bool ToggleEntry(
  218. string label, bool value, float width, float x)
  219. {
  220. var rt = GUILayoutUtility.GetRect(
  221. new GUIContent(label), UnityStyles.Dialog.EntryLabel);
  222. rt.width = width;
  223. rt.x = x;
  224. return GUI.Toggle(rt, value, label);
  225. }
  226. protected static bool NormalButton(string text)
  227. {
  228. return GUILayout.Button(
  229. text, UnityStyles.Dialog.NormalButton,
  230. GUILayout.MinWidth(80),
  231. GUILayout.Height(25));
  232. }
  233. void IPlasticDialogCloser.CloseDialog()
  234. {
  235. OkButtonAction();
  236. }
  237. void ProcessKeyActions()
  238. {
  239. Event e = Event.current;
  240. if (mEnterKeyAction != null &&
  241. Keyboard.IsReturnOrEnterKeyPressed(e))
  242. {
  243. mEnterKeyAction.Invoke();
  244. e.Use();
  245. return;
  246. }
  247. if (mEscapeKeyAction != null &&
  248. Keyboard.IsKeyPressed(e, KeyCode.Escape))
  249. {
  250. mEscapeKeyAction.Invoke();
  251. e.Use();
  252. return;
  253. }
  254. }
  255. protected static bool AcceptButton(string text, int extraWidth = 10)
  256. {
  257. GUI.color = new Color(0.098f, 0.502f, 0.965f, .8f);
  258. int textWidth = (int)((GUIStyle)UnityStyles.Dialog.AcceptButtonText)
  259. .CalcSize(new GUIContent(text)).x;
  260. bool pressed = GUILayout.Button(
  261. string.Empty, GetEditorSkin().button,
  262. GUILayout.MinWidth(Math.Max(80, textWidth + extraWidth)),
  263. GUILayout.Height(25));
  264. GUI.color = Color.white;
  265. Rect buttonRect = GUILayoutUtility.GetLastRect();
  266. GUI.Label(buttonRect, text, UnityStyles.Dialog.AcceptButtonText);
  267. return pressed;
  268. }
  269. void CompleteModal(ResponseType answer)
  270. {
  271. mIsCompleted = true;
  272. mAnswer = answer;
  273. }
  274. void InitializeVars(EditorWindow parentWindow)
  275. {
  276. mIsConfigured = true;
  277. mIsCompleted = false;
  278. mIsClosed = false;
  279. mAnswer = ResponseType.Cancel;
  280. titleContent = new GUIContent(GetTitle());
  281. mFocusedOnce = false;
  282. position = DefaultRect;
  283. mParentWindow = parentWindow;
  284. }
  285. void MakeNonResizable()
  286. {
  287. maxSize = DefaultRect.size;
  288. minSize = maxSize;
  289. }
  290. static void EntryLabel(string labelText)
  291. {
  292. GUIContent labelContent = new GUIContent(labelText);
  293. GUIStyle labelStyle = UnityStyles.Dialog.EntryLabel;
  294. Rect rt = GUILayoutUtility.GetRect(labelContent, labelStyle);
  295. GUI.Label(rt, labelText, EditorStyles.label);
  296. }
  297. static GUISkin GetEditorSkin()
  298. {
  299. return EditorGUIUtility.isProSkin ?
  300. EditorGUIUtility.GetBuiltinSkin(EditorSkin.Scene) :
  301. EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector);
  302. }
  303. bool mIsConfigured;
  304. bool mIsCompleted;
  305. bool mIsClosed;
  306. ResponseType mAnswer;
  307. protected Action mEnterKeyAction = null;
  308. protected Action mEscapeKeyAction = null;
  309. bool mFocusedOnce;
  310. Dictionary<string, string[]> mWrappedTextLines =
  311. new Dictionary<string, string[]>();
  312. EditorWindow mParentWindow;
  313. protected const float DEFAULT_LINE_SPACING = -5f;
  314. const float DEFAULT_WIDTH = 500f;
  315. const float DEFAULT_HEIGHT = 180f;
  316. const float DEFAULT_PARAGRAPH_SPACING = 10f;
  317. static class BuildLine
  318. {
  319. internal static string ForIndex(string text, int index)
  320. {
  321. if (index < 0 || index > text.Length)
  322. return string.Empty;
  323. return text.Substring(index).Trim();
  324. }
  325. internal static string ForIndexAndLenght(string text, int index, int lenght)
  326. {
  327. if (index < 0 || index > text.Length)
  328. return string.Empty;
  329. return text.Substring(index, lenght);
  330. }
  331. }
  332. }
  333. }