WizardPage.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using UnityEditor;
  6. using UnityEngine;
  7. namespace TheraBytes.BetterUi.Editor
  8. {
  9. public abstract class WizardPage
  10. {
  11. public abstract string NameId { get; }
  12. protected List<WizardPageElementBase> elements = new List<WizardPageElementBase>();
  13. Vector2 scrollPosition;
  14. protected virtual string NextButtonText { get { return "Next"; } }
  15. protected IWizard wizard;
  16. public WizardPage(IWizard wizard)
  17. {
  18. this.wizard = wizard;
  19. }
  20. public void Initialize()
  21. {
  22. OnInitialize();
  23. Load();
  24. }
  25. protected abstract void OnInitialize();
  26. public void Add(WizardPageElementBase element)
  27. {
  28. elements.Add(element);
  29. if(elements.Count == 1)
  30. {
  31. element.Activate();
  32. }
  33. }
  34. public void DrawGui()
  35. {
  36. BeforeGui();
  37. this.scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
  38. bool disableNext = false;
  39. for (int i = 0; i < elements.Count; i++)
  40. {
  41. var element = elements[i];
  42. switch (element.State)
  43. {
  44. case WizardElementState.Complete:
  45. element.DrawGui();
  46. ActivateIfPending(i + 1);
  47. break;
  48. case WizardElementState.WaitForInput:
  49. element.DrawGui();
  50. disableNext = true;
  51. break;
  52. case WizardElementState.Pending:
  53. disableNext = true;
  54. break;
  55. default: throw new NotImplementedException(); ;
  56. }
  57. }
  58. EditorGUILayout.EndScrollView();
  59. EditorGUI.BeginDisabledGroup(disableNext);
  60. if(GUILayout.Button(NextButtonText, GUILayout.Height(40)))
  61. {
  62. NextButtonClicked();
  63. }
  64. EditorGUI.EndDisabledGroup();
  65. AfterGui();
  66. }
  67. protected virtual void NextButtonClicked()
  68. {
  69. Save();
  70. wizard.PageFinished(this);
  71. }
  72. protected virtual void BeforeGui() { }
  73. protected virtual void AfterGui()
  74. {
  75. string page = string.Format("Page {0} / {1} ", wizard.CurrentPageNumber + 1, wizard.TotalPageCount);
  76. for(int i = 0; i < wizard.TotalPageCount; i++)
  77. {
  78. page += (i == wizard.CurrentPageNumber) ? "♠ " : "○ ";
  79. }
  80. EditorGUILayout.LabelField(page);
  81. }
  82. void ActivateIfPending(int index)
  83. {
  84. if (index >= elements.Count)
  85. return;
  86. if (elements[index].State != WizardElementState.Pending)
  87. return;
  88. elements[index].Activate();
  89. }
  90. void Save()
  91. {
  92. foreach(var element in elements)
  93. {
  94. var dataElement = element as IWizardDataElement;
  95. if (dataElement != null)
  96. {
  97. string key = dataElement.SerializationKey;
  98. string value = dataElement.GetValueAsString();
  99. wizard.PersistentData.RegisterValue(key, value);
  100. }
  101. }
  102. wizard.PersistentData.Save();
  103. }
  104. private void Load()
  105. {
  106. // apply saved data to elements until there is data missing
  107. int lastCompleteIndex = -1;
  108. for(int i = 0; i < elements.Count; i++)
  109. {
  110. var dataElement = elements[i] as IWizardDataElement;
  111. if (dataElement != null)
  112. {
  113. string stringValue;
  114. if(wizard.PersistentData.TryGetValue(dataElement.SerializationKey, out stringValue))
  115. {
  116. dataElement.TrySetValue(stringValue);
  117. lastCompleteIndex = i;
  118. }
  119. else
  120. {
  121. break;
  122. }
  123. }
  124. }
  125. // mark all elements complete until the last one which could be loaded successfully
  126. for(int i = 0; i <= lastCompleteIndex; i++)
  127. {
  128. elements[i].MarkComplete();
  129. }
  130. // activate all upcoming elements until user interaction is required.
  131. for(int i = lastCompleteIndex + 1; i < elements.Count; i++)
  132. {
  133. elements[i].Activate();
  134. if (elements[i].State == WizardElementState.WaitForInput)
  135. break;
  136. }
  137. }
  138. }
  139. }