SanAndreasUnity/Assets/Scripts/UI/OptionsWindow.cs
2020-05-31 19:09:51 +02:00

492 lines
11 KiB
C#

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 = "";
public System.Func<bool> isAvailable = () => true;
public abstract void Load ();
public abstract void Save ();
public abstract void Display ();
public abstract void SetValueNonGeneric(object value);
public abstract object GetValueNonGeneric();
public abstract void SetDefaultValueNonGeneric(object value);
public abstract object GetDefaultValueNonGeneric();
}
public abstract class Input<T> : Input
{
public T defaultValue = default(T);
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 ();
}
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;
}
}
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)
{
int value = int.Parse (str, System.Globalization.CultureInfo.InvariantCulture);
value = Mathf.Clamp(value, this.minValue, this.maxValue);
return value;
}
public override string SaveAsString (int value)
{
return value.ToString (System.Globalization.CultureInfo.InvariantCulture);
}
}
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)
{
float value = float.Parse (str, System.Globalization.CultureInfo.InvariantCulture);
value = Mathf.Clamp(value, this.minValue, this.maxValue);
return value;
}
public override string SaveAsString (float value)
{
return value.ToString (System.Globalization.CultureInfo.InvariantCulture);
}
}
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
float windowWidth = Mathf.Max (Screen.width * 0.7f, 600);
float windowHeight = windowWidth * 9f / 16f;
this.windowRect = Utilities.GUIUtils.GetCenteredRect (new Vector2 (windowWidth, windowHeight));
SaveDefaultValues();
LoadSettings (InputPersistType.OnStart);
}
void OnLoaderFinished ()
{
LoadSettings (InputPersistType.AfterLoaderFinishes);
}
protected override void OnWindowStart()
{
base.OnWindowStart();
m_scrollViewStyle = GUI.skin.box;
}
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 ();
}
}
/*
var groupings = s_registeredInputs.GroupBy (i => i.category);
foreach (var grouping in groupings)
{
GUILayout.Label ("\n" + grouping.Key + "\n");
foreach (var input in grouping)
{
input.Display ();
}
}
*/
onGUI ();
}
protected override void OnWindowGUIAfterContent ()
{
GUILayout.BeginHorizontal ();
if (Utilities.GUIUtils.ButtonWithCalculatedSize ("Reset"))
ResetSettingsToDefaults ();
GUILayout.FlexibleSpace ();
// display Save button
if (Utilities.GUIUtils.ButtonWithCalculatedSize ("Save"))
SaveSettings ();
GUILayout.Space (5);
// display Load button
if (Utilities.GUIUtils.ButtonWithCalculatedSize ("Load"))
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)
{
s_registeredInputs.AddIfNotPresent ( input );
}
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 ();
}
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);
}
});
}
}
public static void ResetSettingsToDefaults()
{
foreach (var input in s_registeredInputs)
{
F.RunExceptionSafe (() => {
if (input.isAvailable())
{
object defaultValue = input.GetDefaultValueNonGeneric();
object currentValue = input.GetValueNonGeneric();
if (! defaultValue.Equals(currentValue))
input.SetValueNonGeneric(defaultValue);
}
});
}
}
}
}