2020-05-31 17:07:22 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using SanAndreasUnity.Utilities;
|
|
|
|
|
|
|
|
|
|
namespace SanAndreasUnity.UI {
|
|
|
|
|
|
|
|
|
|
public class OptionsWindow : PauseMenuWindow {
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Subscribe to this event to draw gui inside options window.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static event System.Action onGUI = delegate {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public enum InputPersistType
|
|
|
|
|
{
|
|
|
|
|
None,
|
|
|
|
|
OnStart,
|
|
|
|
|
AfterLoaderFinishes
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public abstract class Input
|
|
|
|
|
{
|
|
|
|
|
public string description = "";
|
|
|
|
|
public InputPersistType persistType = InputPersistType.None;
|
|
|
|
|
public string category = "";
|
2019-11-05 18:00:13 +00:00
|
|
|
|
public System.Func<bool> isAvailable = () => true;
|
2020-05-31 17:07:22 +00:00
|
|
|
|
|
|
|
|
|
public abstract void Load ();
|
|
|
|
|
public abstract void Save ();
|
|
|
|
|
public abstract void Display ();
|
2019-11-05 18:00:13 +00:00
|
|
|
|
public abstract void SetValueNonGeneric(object value);
|
|
|
|
|
public abstract object GetValueNonGeneric();
|
|
|
|
|
public abstract void SetDefaultValueNonGeneric(object value);
|
|
|
|
|
public abstract object GetDefaultValueNonGeneric();
|
|
|
|
|
|
2020-05-31 17:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public abstract class Input<T> : Input
|
|
|
|
|
{
|
2019-11-05 18:00:13 +00:00
|
|
|
|
public T defaultValue = default(T);
|
2020-05-31 17:07:22 +00:00
|
|
|
|
public System.Func<T> getValue = () => default(T);
|
|
|
|
|
public System.Action<T> setValue = (val) => {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Input ()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Input (string description)
|
|
|
|
|
{
|
|
|
|
|
this.description = description;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void Display ()
|
|
|
|
|
{
|
|
|
|
|
if (!this.isAvailable ())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var oldValue = this.getValue ();
|
|
|
|
|
|
|
|
|
|
var newValue = this.Display (oldValue);
|
|
|
|
|
|
|
|
|
|
if (!newValue.Equals( oldValue ))
|
|
|
|
|
{
|
|
|
|
|
this.setValue (newValue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public abstract T Display (T currentValue);
|
|
|
|
|
|
|
|
|
|
public override void Load () {
|
|
|
|
|
if (!this.isAvailable ())
|
|
|
|
|
return;
|
|
|
|
|
if (!PlayerPrefs.HasKey (this.description))
|
|
|
|
|
return;
|
|
|
|
|
string str = PlayerPrefs.GetString (this.description, null);
|
|
|
|
|
if (str != null)
|
|
|
|
|
{
|
|
|
|
|
this.setValue (this.Load (str));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public abstract T Load (string str);
|
|
|
|
|
|
|
|
|
|
public override void Save () {
|
|
|
|
|
if (!this.isAvailable ())
|
|
|
|
|
return;
|
|
|
|
|
string str = this.SaveAsString (this.getValue ());
|
|
|
|
|
if (str != null)
|
|
|
|
|
PlayerPrefs.SetString (this.description, str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual string SaveAsString (T value) {
|
|
|
|
|
return value.ToString ();
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-05 18:00:13 +00:00
|
|
|
|
public override void SetValueNonGeneric(object value)
|
|
|
|
|
{
|
|
|
|
|
this.setValue((T)value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override object GetValueNonGeneric()
|
|
|
|
|
{
|
|
|
|
|
return this.getValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void SetDefaultValueNonGeneric(object value)
|
|
|
|
|
{
|
|
|
|
|
this.defaultValue = (T) value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override object GetDefaultValueNonGeneric()
|
|
|
|
|
{
|
|
|
|
|
return this.defaultValue;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-31 17:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-26 21:25:07 +00:00
|
|
|
|
public class IntInput : Input<int>
|
|
|
|
|
{
|
|
|
|
|
public int minValue;
|
|
|
|
|
public int maxValue;
|
|
|
|
|
|
|
|
|
|
public IntInput () { }
|
|
|
|
|
|
|
|
|
|
public IntInput (string description, int minValue, int maxValue) : base (description)
|
|
|
|
|
{
|
|
|
|
|
this.minValue = minValue;
|
|
|
|
|
this.maxValue = maxValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override int Display (int currentValue)
|
|
|
|
|
{
|
|
|
|
|
return Mathf.RoundToInt( OptionsWindow.FloatSlider (currentValue, this.minValue, this.maxValue, this.description) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override int Load (string str)
|
|
|
|
|
{
|
2019-07-27 17:04:35 +00:00
|
|
|
|
int value = int.Parse (str, System.Globalization.CultureInfo.InvariantCulture);
|
|
|
|
|
value = Mathf.Clamp(value, this.minValue, this.maxValue);
|
|
|
|
|
return value;
|
2019-07-26 21:25:07 +00:00
|
|
|
|
}
|
2019-11-05 14:14:09 +00:00
|
|
|
|
|
|
|
|
|
public override string SaveAsString (int value)
|
|
|
|
|
{
|
|
|
|
|
return value.ToString (System.Globalization.CultureInfo.InvariantCulture);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-26 21:25:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-31 17:07:22 +00:00
|
|
|
|
public class FloatInput : Input<float>
|
|
|
|
|
{
|
|
|
|
|
public float minValue;
|
|
|
|
|
public float maxValue;
|
|
|
|
|
|
|
|
|
|
public FloatInput () { }
|
|
|
|
|
|
|
|
|
|
public FloatInput (string description, float minValue, float maxValue) : base (description)
|
|
|
|
|
{
|
|
|
|
|
this.minValue = minValue;
|
|
|
|
|
this.maxValue = maxValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override float Display (float currentValue)
|
|
|
|
|
{
|
|
|
|
|
return OptionsWindow.FloatSlider (currentValue, this.minValue, this.maxValue, this.description);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override float Load (string str)
|
|
|
|
|
{
|
2019-07-27 17:04:35 +00:00
|
|
|
|
float value = float.Parse (str, System.Globalization.CultureInfo.InvariantCulture);
|
|
|
|
|
value = Mathf.Clamp(value, this.minValue, this.maxValue);
|
|
|
|
|
return value;
|
2020-05-31 17:07:22 +00:00
|
|
|
|
}
|
2019-11-05 14:14:09 +00:00
|
|
|
|
|
|
|
|
|
public override string SaveAsString (float value)
|
|
|
|
|
{
|
|
|
|
|
return value.ToString (System.Globalization.CultureInfo.InvariantCulture);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-31 17:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class BoolInput : Input<bool>
|
|
|
|
|
{
|
|
|
|
|
public BoolInput () { }
|
|
|
|
|
|
|
|
|
|
public BoolInput (string description) : base (description)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool Display (bool currentValue)
|
|
|
|
|
{
|
|
|
|
|
return GUILayout.Toggle (currentValue, this.description);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool Load (string str)
|
|
|
|
|
{
|
|
|
|
|
return bool.Parse (str);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class EnumInput<T> : Input<T> where T : struct
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
public override T Display (T currentValue)
|
|
|
|
|
{
|
|
|
|
|
return OptionsWindow.Enum (currentValue, this.description);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override T Load (string str)
|
|
|
|
|
{
|
|
|
|
|
return (T) System.Enum.Parse (typeof(T), str);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class MultipleOptionsInput<T> : Input<T>
|
|
|
|
|
{
|
|
|
|
|
public T[] Options { get; set; }
|
|
|
|
|
|
|
|
|
|
public override T Display (T currentValue)
|
|
|
|
|
{
|
|
|
|
|
return OptionsWindow.MultipleOptions (currentValue, this.description, this.Options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override T Load (string str)
|
|
|
|
|
{
|
|
|
|
|
int index = this.Options.FindIndex (t => this.SaveAsString (t) == str);
|
|
|
|
|
if (index < 0)
|
|
|
|
|
throw new System.ArgumentException (
|
|
|
|
|
string.Format ("Error loading multiple options of type {0} - specified option '{1}' was not found",
|
|
|
|
|
typeof(T), str));
|
|
|
|
|
|
|
|
|
|
return this.Options [index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static List<OptionsWindow.Input> s_registeredInputs = new List<OptionsWindow.Input> ();
|
|
|
|
|
private static int s_currentTabIndex = 0;
|
|
|
|
|
private static string[] s_categories;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OptionsWindow() {
|
|
|
|
|
|
|
|
|
|
// set default parameters
|
|
|
|
|
|
|
|
|
|
this.windowName = "Options";
|
|
|
|
|
this.useScrollView = true;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Start () {
|
|
|
|
|
|
|
|
|
|
this.RegisterButtonInPauseMenu ();
|
|
|
|
|
|
|
|
|
|
// adjust rect
|
2019-07-28 20:19:50 +00:00
|
|
|
|
float windowWidth = Mathf.Max (Screen.width * 0.7f, 600);
|
2019-07-28 22:26:56 +00:00
|
|
|
|
float windowHeight = windowWidth * 9f / 16f;
|
2020-05-31 17:07:22 +00:00
|
|
|
|
this.windowRect = Utilities.GUIUtils.GetCenteredRect (new Vector2 (windowWidth, windowHeight));
|
|
|
|
|
|
2019-11-06 12:35:23 +00:00
|
|
|
|
SaveDefaultValues();
|
|
|
|
|
|
2020-05-31 17:07:22 +00:00
|
|
|
|
LoadSettings (InputPersistType.OnStart);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnLoaderFinished ()
|
|
|
|
|
{
|
|
|
|
|
LoadSettings (InputPersistType.AfterLoaderFinishes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-07-28 19:34:11 +00:00
|
|
|
|
protected override void OnWindowStart()
|
|
|
|
|
{
|
|
|
|
|
base.OnWindowStart();
|
|
|
|
|
m_scrollViewStyle = GUI.skin.box;
|
|
|
|
|
}
|
2019-07-28 20:19:50 +00:00
|
|
|
|
|
2020-05-31 17:07:22 +00:00
|
|
|
|
protected override void OnWindowGUIBeforeContent ()
|
|
|
|
|
{
|
|
|
|
|
s_categories = s_registeredInputs.Select (i => i.category).Distinct ().ToArray ();
|
|
|
|
|
|
|
|
|
|
if (s_categories.Length > 0)
|
|
|
|
|
{
|
|
|
|
|
s_currentTabIndex = GUIUtils.TabsControl (s_currentTabIndex, s_categories);
|
|
|
|
|
|
|
|
|
|
GUILayout.Space (20);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnWindowGUI ()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// draw inputs
|
|
|
|
|
|
|
|
|
|
if (s_categories.Length > 0)
|
|
|
|
|
{
|
|
|
|
|
foreach (var input in s_registeredInputs.Where( i => i.category == s_categories[s_currentTabIndex] ))
|
|
|
|
|
{
|
|
|
|
|
input.Display ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onGUI ();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnWindowGUIAfterContent ()
|
|
|
|
|
{
|
|
|
|
|
GUILayout.BeginHorizontal ();
|
2019-11-05 18:00:13 +00:00
|
|
|
|
|
2021-01-02 18:02:42 +00:00
|
|
|
|
if (Utilities.GUIUtils.ButtonWithCalculatedSize ("Reset to defaults"))
|
2019-11-05 18:00:13 +00:00
|
|
|
|
ResetSettingsToDefaults ();
|
|
|
|
|
|
2020-05-31 17:07:22 +00:00
|
|
|
|
GUILayout.FlexibleSpace ();
|
|
|
|
|
|
|
|
|
|
// display Save button
|
2019-07-28 20:19:50 +00:00
|
|
|
|
if (Utilities.GUIUtils.ButtonWithCalculatedSize ("Save"))
|
2020-05-31 17:07:22 +00:00
|
|
|
|
SaveSettings ();
|
|
|
|
|
|
|
|
|
|
GUILayout.Space (5);
|
|
|
|
|
|
|
|
|
|
// display Load button
|
2019-07-28 20:19:50 +00:00
|
|
|
|
if (Utilities.GUIUtils.ButtonWithCalculatedSize ("Load"))
|
2020-05-31 17:07:22 +00:00
|
|
|
|
LoadSettings ();
|
|
|
|
|
|
|
|
|
|
GUILayout.EndHorizontal ();
|
|
|
|
|
|
|
|
|
|
GUILayout.Space (5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Displays float slider with description.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static void FloatSlider(ref float value, float min, float max, string description) {
|
|
|
|
|
|
|
|
|
|
GUILayout.Label(description + " : " + value);
|
|
|
|
|
value = GUILayout.HorizontalSlider( value, min, max );
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Displays float slider with description.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static float FloatSlider(float value, float min, float max, string description) {
|
|
|
|
|
|
|
|
|
|
GUILayout.Label(description + " : " + value);
|
|
|
|
|
float newValue = GUILayout.HorizontalSlider( value, min, max );
|
|
|
|
|
return newValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static T MultipleOptions<T>( T currentValue, string description, params T[] allValues ) {
|
|
|
|
|
|
|
|
|
|
GUILayout.Label (description + " : " + currentValue.ToString ());
|
|
|
|
|
|
|
|
|
|
GUILayout.BeginHorizontal ();
|
|
|
|
|
|
|
|
|
|
T newValue = currentValue;
|
|
|
|
|
|
|
|
|
|
foreach (var v in allValues) {
|
|
|
|
|
if (GUILayout.Button (v.ToString ())) {
|
|
|
|
|
newValue = v;
|
|
|
|
|
}
|
|
|
|
|
GUILayout.Space (5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GUILayout.EndHorizontal ();
|
|
|
|
|
|
|
|
|
|
return newValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static T Enum<T>( T currentValue, string description ) where T : struct {
|
|
|
|
|
|
|
|
|
|
var values = System.Enum.GetValues (typeof(T));
|
|
|
|
|
|
|
|
|
|
var newValue = MultipleOptions (currentValue, description, values.Cast<T> ().ToArray ());
|
|
|
|
|
return newValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void DisplayInput<T>( Input<T> input )
|
|
|
|
|
{
|
|
|
|
|
input.Display ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void RegisterInput (Input input)
|
|
|
|
|
{
|
2019-11-06 12:35:23 +00:00
|
|
|
|
s_registeredInputs.AddIfNotPresent ( input );
|
2020-05-31 17:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void RegisterInputs (string category, params Input[] inputs)
|
|
|
|
|
{
|
|
|
|
|
foreach (var input in inputs)
|
|
|
|
|
{
|
|
|
|
|
input.category = category;
|
|
|
|
|
RegisterInput (input);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void LoadSettings (InputPersistType persistType)
|
|
|
|
|
{
|
|
|
|
|
var inputs = s_registeredInputs.Where (input => input.persistType == persistType).ToArray ();
|
|
|
|
|
|
|
|
|
|
Debug.Log ("The following inputs will be loaded: " + string.Join(", ", inputs.Select( i => i.description )));
|
|
|
|
|
|
|
|
|
|
foreach (var input in inputs)
|
|
|
|
|
{
|
|
|
|
|
F.RunExceptionSafe (() => input.Load ());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void LoadSettings ()
|
|
|
|
|
{
|
|
|
|
|
LoadSettings (InputPersistType.OnStart);
|
|
|
|
|
if (Behaviours.Loader.HasLoaded)
|
|
|
|
|
LoadSettings (InputPersistType.AfterLoaderFinishes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void SaveSettings ()
|
|
|
|
|
{
|
|
|
|
|
var inputs = s_registeredInputs.Where (input => input.persistType != InputPersistType.None).ToArray ();
|
|
|
|
|
|
|
|
|
|
Debug.Log ("The following inputs will be saved: " + string.Join(", ", inputs.Select( i => i.description )));
|
|
|
|
|
|
|
|
|
|
foreach (var input in inputs)
|
|
|
|
|
{
|
|
|
|
|
F.RunExceptionSafe (() => input.Save ());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PlayerPrefs.Save ();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-06 12:35:23 +00:00
|
|
|
|
static void SaveDefaultValues()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
foreach (var input in s_registeredInputs)
|
|
|
|
|
{
|
|
|
|
|
F.RunExceptionSafe (() => {
|
|
|
|
|
// assign default value
|
|
|
|
|
if (input.isAvailable())
|
|
|
|
|
{
|
|
|
|
|
input.SetDefaultValueNonGeneric(input.GetValueNonGeneric());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Debug.LogErrorFormat("Input '{0}' was not available when tried to obtain default value", input.description);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-05 18:00:13 +00:00
|
|
|
|
public static void ResetSettingsToDefaults()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
foreach (var input in s_registeredInputs)
|
|
|
|
|
{
|
|
|
|
|
F.RunExceptionSafe (() => {
|
|
|
|
|
if (input.isAvailable())
|
|
|
|
|
{
|
2019-11-06 12:53:18 +00:00
|
|
|
|
object defaultValue = input.GetDefaultValueNonGeneric();
|
|
|
|
|
object currentValue = input.GetValueNonGeneric();
|
|
|
|
|
if (! defaultValue.Equals(currentValue))
|
|
|
|
|
input.SetValueNonGeneric(defaultValue);
|
2019-11-05 18:00:13 +00:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-31 17:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|