UserSetting.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. using System;
  2. using UnityEngine;
  3. namespace UnityEditor.SettingsManagement
  4. {
  5. [Flags]
  6. enum SettingVisibility
  7. {
  8. None = 0 << 0,
  9. /// <value>
  10. /// Matches any static field implementing IUserSetting and tagged with [UserSettingAttribute(visibleInSettingsProvider = true)].
  11. /// </value>
  12. /// <summary>
  13. /// These fields are automatically scraped by the SettingsProvider and displayed.
  14. /// </summary>
  15. Visible = 1 << 0,
  16. /// <value>
  17. /// Matches any static field implementing IUserSetting and tagged with [UserSettingAttribute(visibleInSettingsProvider = false)].
  18. /// </value>
  19. /// <summary>
  20. /// These fields will be reset by the "Reset All" menu in SettingsProvider, but are not shown in the interface.
  21. /// Typically these fields require some conditional formatting or data handling, and are shown in the
  22. /// SettingsProvider UI with a [UserSettingBlockAttribute].
  23. /// </summary>
  24. Hidden = 1 << 1,
  25. /// <value>
  26. /// A static or instance field tagged with [SettingsKeyAttribute].
  27. /// </value>
  28. /// <summary>
  29. /// Unlisted settings are not shown in the SettingsProvider, but are reset to default values by the "Reset All"
  30. /// context menu.
  31. /// </summary>
  32. Unlisted = 1 << 2,
  33. /// <value>
  34. /// A static field implementing IUserSetting that is not marked with any setting attribute.
  35. /// </value>
  36. /// <summary>
  37. /// Unregistered IUserSetting fields are not affected by the SettingsProvider.
  38. /// </summary>
  39. Unregistered = 1 << 3,
  40. All = Visible | Hidden | Unlisted | Unregistered
  41. }
  42. /// <summary>
  43. /// Types implementing IUserSetting are eligible for use with <see cref="UserSettingAttribute"/>, which enables
  44. /// fields to automatically populate the <see cref="UserSettingsProvider"/> interface.
  45. /// </summary>
  46. public interface IUserSetting
  47. {
  48. /// <value>
  49. /// The key for this value.
  50. /// </value>
  51. string key { get; }
  52. /// <value>
  53. /// The type of the stored value.
  54. /// </value>
  55. Type type { get; }
  56. /// <value>
  57. /// At which scope this setting is saved.
  58. /// </value>
  59. SettingsScope scope { get; }
  60. /// <summary>
  61. /// The name of the <see cref="ISettingsRepository"/> that this setting should be associated with. If null, the
  62. /// first repository matching the <see cref="scope"/> will be used.
  63. /// </summary>
  64. string settingsRepositoryName { get; }
  65. /// <value>
  66. /// The <see cref="Settings"/> instance that this setting should be saved and loaded from.
  67. /// </value>
  68. Settings settings { get; }
  69. /// <summary>
  70. /// Get the stored value.
  71. /// If you are implementing IUserSetting it is recommended that you cache this value.
  72. /// </summary>
  73. /// <returns>
  74. /// The stored value.
  75. /// </returns>
  76. object GetValue();
  77. /// <summary>
  78. /// Get the default value for this setting.
  79. /// </summary>
  80. /// <returns>
  81. /// The default value for this setting.
  82. /// </returns>
  83. object GetDefaultValue();
  84. /// <summary>
  85. /// Set the value for this setting.
  86. /// </summary>
  87. /// <param name="value">The new value.</param>
  88. /// <param name="saveProjectSettingsImmediately">
  89. /// True to immediately serialize the ISettingsRepository that is backing this value, or false to postpone.
  90. /// If not serializing immediately, be sure to call <see cref="Settings.Save"/>.
  91. /// </param>
  92. void SetValue(object value, bool saveProjectSettingsImmediately = false);
  93. /// <summary>
  94. /// When the inspected type is a reference value, it is possible to change properties without affecting the
  95. /// backing setting. ApplyModifiedProperties provides a method to force serialize these changes.
  96. /// </summary>
  97. void ApplyModifiedProperties();
  98. /// <summary>
  99. /// Set the current value back to the default.
  100. /// </summary>
  101. /// <param name="saveProjectSettingsImmediately">True to immediately re-serialize project settings.</param>
  102. void Reset(bool saveProjectSettingsImmediately = false);
  103. /// <summary>
  104. /// Delete the saved setting. Does not clear the current value.
  105. /// </summary>
  106. /// <see cref="Reset"/>
  107. /// <param name="saveProjectSettingsImmediately">True to immediately re-serialize project settings.</param>
  108. void Delete(bool saveProjectSettingsImmediately = false);
  109. }
  110. /// <summary>
  111. /// A generic implementation of IUserSetting to be used with a <see cref="Settings"/> instance. This default
  112. /// implementation assumes the <see cref="Settings"/> instance contains two <see cref="ISettingsRepository"/>, one
  113. /// for <see cref="SettingsScope.Project"/> and one for <see cref="SettingsScope.User"/>.
  114. /// </summary>
  115. /// <typeparam name="T"></typeparam>
  116. /// <inheritdoc />
  117. public class UserSetting<T> : IUserSetting
  118. {
  119. bool m_Initialized;
  120. string m_Key;
  121. string m_Repository;
  122. T m_Value;
  123. T m_DefaultValue;
  124. SettingsScope m_Scope;
  125. Settings m_Settings;
  126. UserSetting() {}
  127. /// <summary>
  128. /// Constructor for UserSetting{T} type.
  129. /// </summary>
  130. /// <param name="settings">The <see cref="Settings"/> instance that this setting should be saved and loaded from.</param>
  131. /// <param name="key">The key for this value.</param>
  132. /// <param name="value">The default value for this key.</param>
  133. /// <param name="scope">The scope at which to save this setting.</param>
  134. public UserSetting(Settings settings, string key, T value, SettingsScope scope = SettingsScope.Project)
  135. {
  136. m_Key = key;
  137. m_Repository = null;
  138. m_Value = value;
  139. m_Scope = scope;
  140. m_Initialized = false;
  141. m_Settings = settings;
  142. }
  143. /// <summary>
  144. /// Constructor for UserSetting{T} type.
  145. /// </summary>
  146. /// <param name="settings">The <see cref="Settings"/> instance that this setting should be saved and loaded from.</param>
  147. /// <param name="repository">The <see cref="ISettingsRepository"/> name that this setting should be saved and loaded from. Pass null to save to first available instance.</param>
  148. /// <param name="key">The key for this value.</param>
  149. /// <param name="value">The default value for this key.</param>
  150. /// <param name="scope">The scope at which to save this setting.</param>
  151. public UserSetting(Settings settings, string repository, string key, T value, SettingsScope scope = SettingsScope.Project)
  152. {
  153. m_Key = key;
  154. m_Repository = repository;
  155. m_Value = value;
  156. m_Scope = scope;
  157. m_Initialized = false;
  158. m_Settings = settings;
  159. }
  160. /// <value>
  161. /// The key for this value.
  162. /// </value>
  163. /// <inheritdoc />
  164. public string key
  165. {
  166. get { return m_Key; }
  167. }
  168. /// <value>
  169. /// The name of the repository that this setting is saved in.
  170. /// </value>
  171. /// <inheritdoc />
  172. public string settingsRepositoryName
  173. {
  174. get { return m_Repository; }
  175. }
  176. /// <value>
  177. /// The type that this setting represents ({T}).
  178. /// </value>
  179. /// <inheritdoc />
  180. public Type type
  181. {
  182. get { return typeof(T); }
  183. }
  184. /// <summary>
  185. /// Get a copy of the default value.
  186. /// </summary>
  187. /// <returns>
  188. /// The default value.
  189. /// </returns>
  190. /// <inheritdoc />
  191. public object GetDefaultValue()
  192. {
  193. return defaultValue;
  194. }
  195. /// <summary>
  196. /// Get the currently stored value.
  197. /// </summary>
  198. /// <returns>
  199. /// The value that is currently set.
  200. /// </returns>
  201. /// <inheritdoc />
  202. public object GetValue()
  203. {
  204. return value;
  205. }
  206. /// <summary>
  207. /// The scope affects which <see cref="ISettingsRepository"/> the <see cref="settings"/> instance will save
  208. /// it's data to.
  209. /// </summary>
  210. /// <value>
  211. /// The scope at which to save this key and value.
  212. /// </value>
  213. /// <inheritdoc />
  214. public SettingsScope scope
  215. {
  216. get { return m_Scope; }
  217. }
  218. /// <value>
  219. /// The <see cref="Settings"/> instance that this setting will be read from and saved to.
  220. /// </value>
  221. /// <inheritdoc />
  222. public Settings settings
  223. {
  224. get { return m_Settings; }
  225. }
  226. /// <summary>
  227. /// Set the value for this setting.
  228. /// </summary>
  229. /// <param name="value">The new value.</param>
  230. /// <param name="saveProjectSettingsImmediately">
  231. /// True to immediately serialize the ISettingsRepository that is backing this value, or false to postpone.
  232. /// If not serializing immediately, be sure to call <see cref="Settings.Save"/>.
  233. /// </param>
  234. /// <inheritdoc />
  235. public void SetValue(object value, bool saveProjectSettingsImmediately = false)
  236. {
  237. // we do want to allow null values
  238. if (value != null && !(value is T))
  239. throw new ArgumentException("Value must be of type " + typeof(T) + "\n" + key + " expecting value of type " + type + ", received " + value.GetType());
  240. SetValue((T)value, saveProjectSettingsImmediately);
  241. }
  242. /// <summary>
  243. /// Set the value for this setting.
  244. /// </summary>
  245. /// <param name="value">The new value.</param>
  246. /// <param name="saveProjectSettingsImmediately">
  247. /// True to immediately serialize the ISettingsRepository that is backing this value, or false to postpone.
  248. /// If not serializing immediately, be sure to call <see cref="Settings.Save"/>.
  249. /// </param>
  250. public void SetValue(T value, bool saveProjectSettingsImmediately = false)
  251. {
  252. Init();
  253. m_Value = value;
  254. settings.Set<T>(key, m_Value, m_Scope);
  255. if (saveProjectSettingsImmediately)
  256. settings.Save();
  257. }
  258. /// <summary>
  259. /// Delete the saved setting. Does not clear the current value.
  260. /// </summary>
  261. /// <see cref="M:UnityEditor.SettingsManagement.UserSetting`1.Reset(System.Boolean)" />
  262. /// <param name="saveProjectSettingsImmediately">True to immediately re-serialize project settings.</param>
  263. /// <inheritdoc cref="IUserSetting.Delete"/>
  264. public void Delete(bool saveProjectSettingsImmediately = false)
  265. {
  266. settings.DeleteKey<T>(key, scope);
  267. // Don't Init() because that will set the key again. We just want to reset the m_Value with default and
  268. // pretend that this field hasn't been initialised yet.
  269. m_Value = ValueWrapper<T>.DeepCopy(m_DefaultValue);
  270. m_Initialized = false;
  271. }
  272. /// <summary>
  273. /// When the inspected type is a reference value, it is possible to change properties without affecting the
  274. /// backing setting. ApplyModifiedProperties provides a method to force serialize these changes.
  275. /// </summary>
  276. /// <inheritdoc cref="IUserSetting.ApplyModifiedProperties"/>
  277. public void ApplyModifiedProperties()
  278. {
  279. settings.Set<T>(key, m_Value, m_Scope);
  280. settings.Save();
  281. }
  282. /// <summary>
  283. /// Set the current value back to the default.
  284. /// </summary>
  285. /// <param name="saveProjectSettingsImmediately">True to immediately re-serialize project settings.</param>
  286. /// <inheritdoc cref="IUserSetting.Reset"/>
  287. public void Reset(bool saveProjectSettingsImmediately = false)
  288. {
  289. SetValue(defaultValue, saveProjectSettingsImmediately);
  290. }
  291. void Init()
  292. {
  293. if (!m_Initialized)
  294. {
  295. if (m_Scope == SettingsScope.Project && settings == null)
  296. throw new Exception("UserSetting \"" + m_Key + "\" is attempting to access SettingsScope.Project setting with no Settings instance!");
  297. m_Initialized = true;
  298. // DeepCopy uses EditorJsonUtility which is not permitted during construction
  299. m_DefaultValue = ValueWrapper<T>.DeepCopy(m_Value);
  300. if (settings.ContainsKey<T>(m_Key, m_Scope))
  301. m_Value = settings.Get<T>(m_Key, m_Scope);
  302. else
  303. settings.Set<T>(m_Key, m_Value, m_Scope);
  304. }
  305. }
  306. /// <value>
  307. /// The default value for this setting.
  308. /// </value>
  309. public T defaultValue
  310. {
  311. get
  312. {
  313. Init();
  314. return ValueWrapper<T>.DeepCopy(m_DefaultValue);
  315. }
  316. }
  317. /// <value>
  318. /// The currently stored value.
  319. /// </value>
  320. public T value
  321. {
  322. get
  323. {
  324. Init();
  325. return m_Value;
  326. }
  327. set { SetValue(value); }
  328. }
  329. /// <summary>
  330. /// Implicit cast to backing type.
  331. /// </summary>
  332. /// <param name="pref">The UserSetting{T} to cast to {T}.</param>
  333. /// <returns>
  334. /// The currently stored <see cref="value"/>.
  335. /// </returns>
  336. public static implicit operator T(UserSetting<T> pref)
  337. {
  338. return pref.value;
  339. }
  340. /// <summary>
  341. /// Get a summary of this setting.
  342. /// </summary>
  343. /// <returns>A string summary of this setting.</returns>
  344. public override string ToString()
  345. {
  346. return string.Format("{0} setting. Key: {1} Value: {2}", scope, key, value);
  347. }
  348. }
  349. }