A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections.Generic; 3 4using UnityEditor; 5using UnityEngine; 6 7using PlasticGui; 8 9namespace Unity.PlasticSCM.Editor.UI 10{ 11 internal abstract class PlasticDialog : EditorWindow, IPlasticDialogCloser 12 { 13 internal enum SizeToContent 14 { 15 Manual = 0, 16 Automatic = 1 17 } 18 19 protected virtual Rect DefaultRect 20 { 21 get 22 { 23 int pixelWidth = Screen.currentResolution.width; 24 float x = (pixelWidth - DEFAULT_WIDTH) / 2; 25 return new Rect(x, 200, DEFAULT_WIDTH, DEFAULT_HEIGHT); 26 } 27 } 28 29 protected virtual bool IsResizable { get; set; } 30 31 internal void SetSizeToContent(SizeToContent sizeToContent) 32 { 33 mSizeToContent = sizeToContent; 34 } 35 36 internal void OkButtonAction() 37 { 38 CompleteModal(ResponseType.Ok); 39 } 40 41 internal void CancelButtonAction() 42 { 43 CompleteModal(ResponseType.Cancel); 44 } 45 46 internal void CloseButtonAction() 47 { 48 CompleteModal(ResponseType.None); 49 } 50 51 internal void ApplyButtonAction() 52 { 53 CompleteModal(ResponseType.Apply); 54 } 55 56 internal void AddControlConsumingEnterKey(string controlName) 57 { 58 mControlsConsumingEnterKey.Add(controlName); 59 } 60 61 internal void RunUtility(EditorWindow parentWindow) 62 { 63 InitializeVars(parentWindow); 64 65 if (!IsResizable) 66 MakeNonResizable(); 67 68 ShowUtility(); 69 } 70 71 internal ResponseType RunModal(EditorWindow parentWindow) 72 { 73 InitializeVars(parentWindow); 74 75 if (!IsResizable) 76 MakeNonResizable(); 77 78 if (UI.RunModal.IsAvailable()) 79 { 80 UI.RunModal.Dialog(this); 81 return mAnswer; 82 } 83 84 EditorUtility.DisplayDialog( 85 PlasticLocalization.GetString(PlasticLocalization.Name.UnityVersionControl), 86 PlasticLocalization.GetString(PlasticLocalization.Name.PluginModalInformation), 87 PlasticLocalization.GetString(PlasticLocalization.Name.CloseButton)); 88 return ResponseType.None; 89 } 90 91 protected void OnGUI() 92 { 93 try 94 { 95 // If the Dialog has been saved into the Unity editor layout and persisted between restarts, the methods 96 // to configure the dialogs will be skipped. Simple fix here is to close it when this state is detected. 97 // Fixes a NPE loop when the state mentioned above is occurring. 98 if (!mIsConfigured) 99 { 100 mIsClosed = true; 101 Close(); 102 return; 103 } 104 105 if (!mFocusedOnce) 106 { 107 // Somehow the prevents the dialog from jumping when dragged 108 // NOTE(rafa): We cannot do every frame because the modal kidnaps focus for all processes (in mac at least) 109 Focus(); 110 mFocusedOnce = true; 111 } 112 113 ProcessKeyActions(); 114 115 if (mIsClosed) 116 return; 117 118 GUI.Box(new Rect(0, 0, position.width, position.height), GUIContent.none, EditorStyles.label); 119 120 float margin = 25; 121 float marginTop = 25; 122 using (new EditorGUILayout.HorizontalScope(GUILayout.Height(position.height))) 123 { 124 GUILayout.Space(margin); 125 using (new EditorGUILayout.VerticalScope(GUILayout.Height(position.height))) 126 { 127 GUILayout.Space(marginTop); 128 OnModalGUI(); 129 GUILayout.Space(margin); 130 } 131 GUILayout.Space(margin); 132 } 133 134 if (!IsResizable && mSizeToContent == SizeToContent.Automatic) 135 { 136 var lastRect = GUILayoutUtility.GetLastRect(); 137 float desiredHeight = lastRect.yMax; 138 139 if (position.height < desiredHeight) 140 { 141 Rect newPos = position; 142 newPos.height = desiredHeight; 143 144 position = newPos; 145 } 146 147 maxSize = position.size; 148 minSize = maxSize; 149 } 150 151 if (Event.current.type == EventType.Repaint) 152 { 153 if (mIsCompleted) 154 { 155 mIsClosed = true; 156 Close(); 157 } 158 } 159 } 160 finally 161 { 162 if (mIsClosed) 163 EditorGUIUtility.ExitGUI(); 164 } 165 } 166 167 void OnDestroy() 168 { 169 if (!mIsConfigured) 170 return; 171 172 SaveSettings(); 173 174 if (mParentWindow == null) 175 return; 176 177 mParentWindow.Focus(); 178 } 179 180 protected virtual void SaveSettings() { } 181 protected abstract void OnModalGUI(); 182 protected abstract string GetTitle(); 183 184 protected void Paragraph(string text) 185 { 186 GUILayout.Label(text, UnityStyles.Paragraph); 187 GUILayout.Space(DEFAULT_PARAGRAPH_SPACING); 188 } 189 190 protected void TextBlockWithEndLink( 191 string url, string formattedExplanation, GUIStyle textblockStyle) 192 { 193 ExternalLink externalLink = new ExternalLink 194 { 195 Label = url, 196 Url = url 197 }; 198 199 DrawTextBlockWithLink.ForExternalLink( 200 externalLink, formattedExplanation, textblockStyle); 201 } 202 203 protected static void Title(string text) 204 { 205 GUILayout.Label(text, UnityStyles.Dialog.Toggle); 206 } 207 208 protected static bool TitleToggle(string text, bool isOn) 209 { 210 return EditorGUILayout.ToggleLeft(text, isOn, UnityStyles.Dialog.Toggle); 211 } 212 213 protected static bool TitleToggle(string text, bool isOn, GUIStyle style) 214 { 215 return EditorGUILayout.ToggleLeft(text, isOn, style); 216 } 217 218 protected static string TextEntry( 219 string label, 220 string value, 221 float width, 222 float x) 223 { 224 return TextEntry( 225 label, 226 value, 227 null, 228 width, 229 x); 230 } 231 232 protected static string TextEntry( 233 string label, string value, string controlName, float width, float x) 234 { 235 using (new EditorGUILayout.HorizontalScope()) 236 { 237 EntryLabel(label); 238 239 GUILayout.FlexibleSpace(); 240 241 var rt = GUILayoutUtility.GetRect( 242 new GUIContent(value), UnityStyles.Dialog.EntryLabel); 243 rt.width = width; 244 rt.x = x; 245 246 if (!string.IsNullOrEmpty(controlName)) 247 GUI.SetNextControlName(controlName); 248 249 return GUI.TextField(rt, value); 250 } 251 } 252 253 protected static string ComboBox( 254 string label, 255 string value, 256 List<string> dropDownOptions, 257 GenericMenu.MenuFunction2 optionSelected, 258 float width, 259 float x) 260 { 261 using (new EditorGUILayout.HorizontalScope()) 262 { 263 EntryLabel(label); 264 265 GUILayout.FlexibleSpace(); 266 267 var rt = GUILayoutUtility.GetRect( 268 new GUIContent(value), UnityStyles.Dialog.EntryLabel); 269 rt.width = width; 270 rt.x = x; 271 272 return DropDownTextField.DoDropDownTextField( 273 value, 274 label, 275 dropDownOptions, 276 optionSelected, 277 rt); 278 } 279 } 280 281 protected static string PasswordEntry( 282 string label, string value, float width, float x) 283 { 284 using (new EditorGUILayout.HorizontalScope()) 285 { 286 EntryLabel(label); 287 288 GUILayout.FlexibleSpace(); 289 290 var rt = GUILayoutUtility.GetRect( 291 new GUIContent(value), UnityStyles.Dialog.EntryLabel); 292 rt.width = width; 293 rt.x = x; 294 295 return GUI.PasswordField(rt, value, '*'); 296 } 297 } 298 299 static void EntryLabel(string labelText) 300 { 301 GUIContent labelContent = new GUIContent(labelText); 302 GUIStyle labelStyle = UnityStyles.Dialog.EntryLabel; 303 304 Rect rt = GUILayoutUtility.GetRect(labelContent, labelStyle); 305 306 GUI.Label(rt, labelText, EditorStyles.label); 307 } 308 309 protected static bool ToggleEntry( 310 string label, bool value, float width, float x) 311 { 312 var rt = GUILayoutUtility.GetRect( 313 new GUIContent(label), UnityStyles.Dialog.EntryLabel); 314 rt.width = width; 315 rt.x = x; 316 317 return GUI.Toggle(rt, value, label); 318 } 319 320 protected static bool ToggleEntry(string label, bool value) 321 { 322 var rt = GUILayoutUtility.GetRect( 323 new GUIContent(label), UnityStyles.Dialog.EntryLabel); 324 325 return GUI.Toggle(rt, value, label); 326 } 327 328 protected static bool NormalButton(string text) 329 { 330 return GUILayout.Button( 331 text, UnityStyles.Dialog.NormalButton, 332 GUILayout.MinWidth(80), 333 GUILayout.Height(25)); 334 } 335 336 protected static bool AcceptButton(string text, int extraWidth = 10) 337 { 338 GUI.color = new Color(0.098f, 0.502f, 0.965f, .8f); 339 340 int textWidth = (int)((GUIStyle)UnityStyles.Dialog.AcceptButtonText) 341 .CalcSize(new GUIContent(text)).x; 342 343 bool pressed = GUILayout.Button( 344 string.Empty, GetEditorSkin().button, 345 GUILayout.MinWidth(Math.Max(80, textWidth + extraWidth)), 346 GUILayout.Height(25)); 347 348 GUI.color = Color.white; 349 350 Rect buttonRect = GUILayoutUtility.GetLastRect(); 351 GUI.Label(buttonRect, text, UnityStyles.Dialog.AcceptButtonText); 352 353 return pressed; 354 } 355 356 void IPlasticDialogCloser.CloseDialog() 357 { 358 OkButtonAction(); 359 } 360 361 void ProcessKeyActions() 362 { 363 Event e = Event.current; 364 365 string focusedControlName = GUI.GetNameOfFocusedControl(); 366 367 if (mEnterKeyAction != null && 368 Keyboard.IsReturnOrEnterKeyPressed(e) && 369 !ControlConsumesKey(mControlsConsumingEnterKey, focusedControlName)) 370 { 371 mEnterKeyAction.Invoke(); 372 e.Use(); 373 return; 374 } 375 376 if (mEscapeKeyAction != null && 377 Keyboard.IsKeyPressed(e, KeyCode.Escape)) 378 { 379 mEscapeKeyAction.Invoke(); 380 e.Use(); 381 return; 382 } 383 } 384 385 void CompleteModal(ResponseType answer) 386 { 387 mIsCompleted = true; 388 mAnswer = answer; 389 390 Repaint(); 391 } 392 393 void InitializeVars(EditorWindow parentWindow) 394 { 395 mIsConfigured = true; 396 mIsCompleted = false; 397 mIsClosed = false; 398 mAnswer = ResponseType.Cancel; 399 400 titleContent = new GUIContent(GetTitle()); 401 402 mFocusedOnce = false; 403 404 position = DefaultRect; 405 mParentWindow = parentWindow; 406 } 407 408 void MakeNonResizable() 409 { 410 maxSize = DefaultRect.size; 411 minSize = maxSize; 412 } 413 414 static bool ControlConsumesKey( 415 List<string> controlsConsumingKey, 416 string focusedControlName) 417 { 418 if (string.IsNullOrEmpty(focusedControlName)) 419 return false; 420 421 foreach (string controlName in controlsConsumingKey) 422 { 423 if (focusedControlName.Equals(controlName)) 424 return true; 425 } 426 427 return false; 428 } 429 430 static GUISkin GetEditorSkin() 431 { 432 return EditorGUIUtility.isProSkin ? 433 EditorGUIUtility.GetBuiltinSkin(EditorSkin.Scene) : 434 EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector); 435 } 436 437 bool mFocusedOnce; 438 bool mIsConfigured; 439 bool mIsCompleted; 440 bool mIsClosed; 441 ResponseType mAnswer; 442 443 protected Action mEnterKeyAction = null; 444 protected Action mEscapeKeyAction = null; 445 446 EditorWindow mParentWindow; 447 SizeToContent mSizeToContent = SizeToContent.Automatic; 448 449 List<string> mControlsConsumingEnterKey = new List<string>(); 450 451 const float DEFAULT_WIDTH = 500f; 452 const float DEFAULT_HEIGHT = 180f; 453 const float DEFAULT_PARAGRAPH_SPACING = 10f; 454 } 455}