namespace UIWidgets
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using UIWidgets.Attributes;
using UIWidgets.Styles;
using UnityEngine;
using UnityEngine.UI;
///
/// Scale widget.
///
[RequireComponent(typeof(RectTransform))]
public class Scale : MonoBehaviourConditional, IObservable, INotifyPropertyChanged, IStylable
{
///
/// Mark data.
///
public struct MarkData : IEquatable
{
///
/// Position.
///
public readonly Vector2 Position;
///
/// Rotation.
///
public readonly float Rotation;
///
/// Anchors min.
///
public readonly Vector2 AnchorMin;
///
/// Anchors max.
///
public readonly Vector2 AnchorMax;
///
/// Pivot.
///
public readonly Vector2 Pivot;
///
/// Value.
///
public readonly float Value;
///
/// Convert value to label.
///
public readonly Func Value2Label;
///
/// Label.
///
public string Label
{
get
{
return Value2Label != null ? Value2Label(Value) : Value.ToString();
}
}
///
/// Initializes a new instance of the struct.
///
/// Value.
/// Position.
/// Rotation.
/// Anchors min.
/// Anchors max.
/// Pivot.
/// Convert value to label.
public MarkData(
float value,
Vector2 position = default(Vector2),
float rotation = 0f,
Vector2 anchorMin = default(Vector2),
Vector2 anchorMax = default(Vector2),
Vector2? pivot = null,
Func value2label = null)
{
Value = value;
Position = position;
Rotation = rotation;
AnchorMin = anchorMin;
AnchorMax = anchorMax;
Pivot = pivot.HasValue ? pivot.Value : new Vector2(0.5f, 0.5f);
Value2Label = value2label;
}
///
/// Determines whether the specified object is equal to the current object.
///
/// The object to compare with the current object.
/// true if the specified object is equal to the current object; otherwise, false.
public override bool Equals(object obj)
{
if (obj is MarkData)
{
return Equals((MarkData)obj);
}
return false;
}
///
/// Determines whether the specified object is equal to the current object.
///
/// The object to compare with the current object.
/// true if the specified object is equal to the current object; otherwise, false.
public bool Equals(MarkData other)
{
return (Position == other.Position)
&& (Rotation == other.Rotation)
&& (AnchorMin == other.AnchorMin)
&& (AnchorMax == other.AnchorMax)
&& (Pivot == other.Pivot)
&& (Value == other.Value)
&& (Value2Label == other.Value2Label);
}
///
/// Hash function.
///
/// A hash code for the current object.
public override int GetHashCode()
{
return Position.GetHashCode() ^ Rotation.GetHashCode() ^ AnchorMin.GetHashCode() ^ AnchorMax.GetHashCode() ^ Pivot.GetHashCode() ^ Value.GetHashCode() ^ Value2Label.GetHashCode();
}
///
/// Compare specified instances.
///
/// First instance.
/// Second instance.
/// true if the instances are equal; otherwise, false.
public static bool operator ==(MarkData a, MarkData b)
{
return a.Equals(b);
}
///
/// Compare specified instances.
///
/// First instance.
/// Second instance.
/// true if the instances not equal; otherwise, false.
public static bool operator !=(MarkData a, MarkData b)
{
return !a.Equals(b);
}
}
[SerializeField]
RectTransform container;
///
/// Container.
///
public RectTransform Container
{
get
{
return container;
}
set
{
if (container != value)
{
container = value;
NotifyPropertyChanged("Container");
}
}
}
[SerializeField]
Image mainLine;
///
/// Main line.
///
public Image MainLine
{
get
{
return mainLine;
}
set
{
if (mainLine != value)
{
mainLine = value;
NotifyPropertyChanged("MainLine");
}
}
}
[SerializeField]
bool showCurrentValue = true;
///
/// Show current values.
///
public bool ShowCurrentValue
{
get
{
return showCurrentValue;
}
set
{
if (showCurrentValue != value)
{
showCurrentValue = value;
NotifyPropertyChanged("ShowCurrentValue");
}
}
}
[SerializeField]
[EditorConditionBool("showCurrentValue")]
ScaleMarkTemplate currentMarkTemplate;
///
/// Current mark template.
///
public ScaleMarkTemplate CurrentMarkTemplate
{
get
{
return currentMarkTemplate;
}
set
{
if (currentMarkTemplate != value)
{
currentMarkTemplate = value;
NotifyPropertyChanged("CurrentTemplate");
}
}
}
[SerializeField]
bool showMinValue = true;
///
/// Show minimal value.
///
public bool ShowMinValue
{
get
{
return showMinValue;
}
set
{
if (showMinValue != value)
{
showMinValue = value;
NotifyPropertyChanged("ShowMinValue");
}
}
}
[SerializeField]
[EditorConditionBool("showMinValue")]
ScaleMarkTemplate minMark;
///
/// Min mark.
///
public ScaleMarkTemplate MinMark
{
get
{
return minMark;
}
set
{
if (minMark != value)
{
minMark = value;
NotifyPropertyChanged("MinTemplate");
}
}
}
[SerializeField]
bool showMaxValue = true;
///
/// Show max value.
///
public bool ShowMaxValue
{
get
{
return showMaxValue;
}
set
{
if (showMaxValue != value)
{
showMaxValue = value;
NotifyPropertyChanged("ShowMaxValue");
}
}
}
[SerializeField]
[EditorConditionBool("showMaxValue")]
ScaleMarkTemplate maxMark;
///
/// Max mark.
///
public ScaleMarkTemplate MaxMark
{
get
{
return maxMark;
}
set
{
if (maxMark != value)
{
maxMark = value;
NotifyPropertyChanged("MaxTemplate");
}
}
}
[SerializeField]
List scaleMarks = new List();
ObservableList marks;
///
/// Marks.
///
public ObservableList Marks
{
get
{
if (marks == null)
{
marks = new ObservableList(scaleMarks);
marks.Comparison = MarkComparison;
}
return marks;
}
set
{
if (marks != null)
{
marks.OnChange -= MarksChanged;
}
marks = value;
if (marks != null)
{
marks.Comparison = MarkComparison;
marks.OnChange += MarksChanged;
}
MarksChanged();
}
}
RectTransform rectTransform;
///
/// RectTransform.
///
public RectTransform RectTransform
{
get
{
if (rectTransform == null)
{
rectTransform = transform as RectTransform;
}
return rectTransform;
}
}
bool isInited;
///
/// Items comparison.
///
/// First item.
/// Second item.
/// Result of the comparison.
public static int MarkComparison(ScaleMark x, ScaleMark y)
{
return -x.Step.CompareTo(y.Step);
}
///
/// Process the start event.
///
protected virtual void Start()
{
Init();
}
///
/// Process the destroy event.
///
protected virtual void OnDestroy()
{
Clear();
if (marks != null)
{
marks.OnChange -= MarksChanged;
marks = null;
}
}
///
/// Init this instance.
///
public virtual void Init()
{
if (isInited)
{
return;
}
isInited = true;
if (container == null)
{
container = transform as RectTransform;
}
if (currentMarkTemplate != null)
{
currentMarkTemplate.gameObject.SetActive(false);
}
if (minMark != null)
{
minMark.gameObject.SetActive(false);
}
if (maxMark != null)
{
maxMark.gameObject.SetActive(false);
}
if (mainLine != null)
{
mainLine.gameObject.SetActive(false);
}
for (int i = 0; i < Marks.Count; i++)
{
var mark = Marks[i];
if (mark.Step <= 0)
{
Debug.LogWarning("ScaleMark.Step cannot be negative or zero.", this);
continue;
}
mark.Template.gameObject.SetActive(false);
}
foreach (var instance in MarksInstances)
{
if (instance != null)
{
instance.Return();
}
}
MarksInstances.Clear();
}
///
/// Occurs when a property value changes.
///
public event OnChange OnChange;
///
/// Occurs when a property value changes.
///
public event PropertyChangedEventHandler PropertyChanged;
///
/// Mark values, temporary list.
///
[HideInInspector]
protected List MarkValues = new List();
///
/// Mark values generator.
///
public Action> MarkValuesGenerator = DefaultGenerator;
///
/// Used values.
///
protected HashSet UsedValues = new HashSet();
///
/// Marks instances.
///
[SerializeField]
[HideInInspector]
protected List MarksInstances = new List();
///
/// Properties tracker.
///
protected DrivenRectTransformTracker PropertiesTracker;
///
/// Driven properties.
///
protected DrivenTransformProperties DrivenProperties = DrivenTransformProperties.AnchoredPosition | DrivenTransformProperties.Anchors | DrivenTransformProperties.Pivot | DrivenTransformProperties.Rotation;
///
/// Raise PropertyChanged event.
///
/// Property name.
protected virtual void NotifyPropertyChanged(string propertyName)
{
var c_handlers = OnChange;
if (c_handlers != null)
{
c_handlers();
}
var handlers = PropertyChanged;
if (handlers != null)
{
handlers(this, new PropertyChangedEventArgs(propertyName));
}
}
///
/// Process marks changed events.
///
protected virtual void MarksChanged()
{
Clear();
NotifyPropertyChanged("Marks");
}
///
/// Clear this instance.
///
public virtual void Clear()
{
PropertiesTracker.Clear();
UsedValues.Clear();
if (CurrentMarkTemplate != null)
{
CurrentMarkTemplate.gameObject.SetActive(false);
}
if (MinMark != null)
{
MinMark.gameObject.SetActive(false);
}
if (MaxMark != null)
{
MaxMark.gameObject.SetActive(false);
}
foreach (var instance in MarksInstances)
{
if (instance != null)
{
instance.Return();
}
}
MarksInstances.Clear();
}
///
/// Set min mark.
///
/// Mark data.
protected virtual void SetMin(MarkData mark)
{
if (MinMark == null)
{
return;
}
if (ShowMinValue)
{
MinMark.gameObject.SetActive(true);
Set(MinMark, mark);
}
else
{
MinMark.gameObject.SetActive(false);
}
}
///
/// Set max mark.
///
/// Mark data.
protected virtual void SetMax(MarkData mark)
{
if (MaxMark == null)
{
return;
}
if (ShowMaxValue)
{
MaxMark.gameObject.SetActive(true);
Set(MaxMark, mark);
}
else
{
MaxMark.gameObject.SetActive(false);
}
}
///
/// Set mark.
///
/// Instance.
/// Mark data.
protected virtual void Set(ScaleMarkTemplate instance, MarkData mark)
{
var rt = instance.RectTransform;
PropertiesTracker.Add(this, rt, DrivenProperties);
rt.anchorMin = mark.AnchorMin;
rt.anchorMax = mark.AnchorMax;
rt.pivot = mark.Pivot;
rt.anchoredPosition = mark.Position;
rt.localRotation = Quaternion.Euler(0f, 0f, mark.Rotation);
if (instance.Label != null)
{
instance.Label.text = mark.Label;
var label_rt = instance.Label.transform as RectTransform;
label_rt.localRotation = Quaternion.Euler(0f, 0f, -mark.Rotation);
}
}
///
/// Default marks values generator.
///
/// Min value.
/// Max value.
/// Step.
/// Result.
public static void DefaultGenerator(float min, float max, float step, List output)
{
for (var value = min; value < max; value += step)
{
output.Add(value);
}
}
///
/// Set scale data.
///
/// Convert value to mark data.
/// Min value.
/// Max value.
/// Current values.
public virtual void Set(Func value2mark, float min, float max, params float[] current)
{
Set(value2mark, min, max);
if (ShowCurrentValue)
{
SetCurrent(value2mark, current);
}
}
///
/// Set base scale data.
///
/// Convert value to mark data.
/// Min value.
/// Max value.
public virtual void Set(Func value2mark, float min, float max)
{
Init();
Clear();
if (MarkValuesGenerator == null)
{
MarkValuesGenerator = DefaultGenerator;
}
if (MainLine != null)
{
MainLine.gameObject.SetActive(true);
}
SetMin(value2mark(min));
if (ShowMinValue)
{
UsedValues.Add(min);
}
SetMax(value2mark(max));
if (ShowMinValue)
{
UsedValues.Add(max);
}
for (int i = 0; i < Marks.Count; i++)
{
var mark = Marks[i];
if (mark.Step <= 0)
{
continue;
}
MarkValues.Clear();
MarkValuesGenerator(min, max, mark.Step, MarkValues);
foreach (var value in MarkValues)
{
if (UsedValues.Contains(value))
{
continue;
}
var instance = mark.Template.GetInstance(Container);
Set(instance, value2mark(value));
MarksInstances.Add(instance);
UsedValues.Add(value);
}
MarkValues.Clear();
}
}
///
/// Set scale data.
///
/// Convert value to mark data.
/// Min value.
/// Max value.
/// Current value 0.
public virtual void Set(Func value2mark, float min, float max, float current)
{
Set(value2mark, min, max);
if (ShowCurrentValue)
{
SetCurrent(value2mark, current);
}
}
///
/// Set scale data.
///
/// Convert value to mark data.
/// Min value.
/// Max value.
/// Current value 0.
/// Current value 1.
public virtual void Set(Func value2mark, float min, float max, float current0, float current1)
{
Set(value2mark, min, max);
if (ShowCurrentValue)
{
SetCurrent(value2mark, current0);
SetCurrent(value2mark, current1);
}
}
///
/// Set scale data.
///
/// Convert value to mark data.
/// Min value.
/// Max value.
/// Current value 0.
/// Current value 1.
/// Current value 2.
public virtual void Set(Func value2mark, float min, float max, float current0, float current1, float current2)
{
Set(value2mark, min, max);
if (ShowCurrentValue)
{
SetCurrent(value2mark, current0);
SetCurrent(value2mark, current1);
SetCurrent(value2mark, current2);
}
}
///
/// Set scale data.
///
/// Convert value to mark data.
/// Min value.
/// Max value.
/// Current value 0.
/// Current value 1.
/// Current value 2.
/// Current value 3.
public virtual void Set(Func value2mark, float min, float max, float current0, float current1, float current2, float current3)
{
Set(value2mark, min, max);
if (ShowCurrentValue)
{
SetCurrent(value2mark, current0);
SetCurrent(value2mark, current1);
SetCurrent(value2mark, current2);
SetCurrent(value2mark, current3);
}
}
///
/// Set scale data.
///
/// Convert value to mark data.
/// Min value.
/// Max value.
/// Current value 0.
/// Current value 1.
/// Current value 2.
/// Current value 3.
/// Current value 4.
public virtual void Set(Func value2mark, float min, float max, float current0, float current1, float current2, float current3, float current4)
{
Set(value2mark, min, max);
if (ShowCurrentValue)
{
SetCurrent(value2mark, current0);
SetCurrent(value2mark, current1);
SetCurrent(value2mark, current2);
SetCurrent(value2mark, current3);
SetCurrent(value2mark, current4);
}
}
///
/// Set current marks.
///
/// Convert value to mark data.
/// Current values.
protected virtual void SetCurrent(Func value2mark, params float[] current)
{
foreach (var value in current)
{
SetCurrent(value2mark, value);
}
}
///
/// Set current mark.
///
/// Convert value to mark data.
/// Current value.
protected virtual void SetCurrent(Func value2mark, float current)
{
var instance = CurrentMarkTemplate.GetInstance(Container);
Set(instance, value2mark(current));
MarksInstances.Add(instance);
}
#region IStylable implementation
///
public virtual bool SetStyle(Style style)
{
style.Scale.MainLine.ApplyTo(MainLine);
foreach (var instance in MarksInstances)
{
if (instance != null)
{
instance.SetStyle(style);
}
}
if (currentMarkTemplate != null)
{
currentMarkTemplate.SetStyle(style);
}
if (minMark != null)
{
minMark.SetStyle(style);
}
if (maxMark != null)
{
maxMark.SetStyle(style);
}
if (isInited)
{
for (int i = 0; i < Marks.Count; i++)
{
Marks[i].Template.SetStyle(style);
}
}
else
{
for (int i = 0; i < scaleMarks.Count; i++)
{
scaleMarks[i].Template.SetStyle(style);
}
}
return true;
}
///
public virtual bool GetStyle(Style style)
{
style.Scale.MainLine.GetFrom(MainLine);
if (currentMarkTemplate != null)
{
currentMarkTemplate.GetStyle(style);
}
else if (minMark != null)
{
minMark.GetStyle(style);
}
else if (maxMark != null)
{
maxMark.GetStyle(style);
}
else
{
for (int i = 0; i < scaleMarks.Count; i++)
{
scaleMarks[i].Template.GetStyle(style);
}
}
return true;
}
#endregion
}
}