This commit is contained in:
2021-06-13 10:28:03 +02:00
parent eb70603c85
commit df2d24cbd3
7487 changed files with 943244 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
/// <summary>
/// Represents an Action to process when the user clicks a particular mouse button a certain number of times.
/// </summary>
public class ClickAction : HoveredControlAction
{
private int m_Button;
private bool m_UseEvent;
/// <summary>
/// The number of button clicks required to satisfy the trigger condition
/// </summary>
public int clickCount = 1;
/// <summary>
/// The Action to execute when the user satisfies the trigger condition.
/// </summary>
public Action<IGUIState, Control> onClick;
private int m_ClickCounter = 0;
/// <summary>
/// Initializes and returns an instance of ClickAction
/// </summary>
/// <param name="control">Current control</param>
/// <param name="button">The mouse button to check for.</param>
/// <param name="useEvent">Whether to Use the current event after the trigger condition has been met.</param>
public ClickAction(Control control, int button, bool useEvent = true) : base(control)
{
m_Button = button;
m_UseEvent = useEvent;
}
/// <summary>
/// Checks to see if the trigger condition has been met or not.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Returns `true` if the trigger condition has been met. Otherwise, returns false.</returns>
protected override bool GetTriggerContidtion(IGUIState guiState)
{
if (guiState.mouseButton == m_Button && guiState.eventType == EventType.MouseDown)
{
if (guiState.clickCount == 1)
m_ClickCounter = 0;
++m_ClickCounter;
if (m_ClickCounter == clickCount)
return true;
}
return false;
}
/// <summary>
/// Calls the methods in its invocation list when the trigger conditions are met.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
protected override void OnTrigger(IGUIState guiState)
{
base.OnTrigger(guiState);
if (onClick != null)
onClick(guiState, hoveredControl);
if (m_UseEvent)
guiState.UseEvent();
}
/// <summary>
/// Checks to see if the finish condition has been met or not. For a ClickAction, this is always `true`.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Returns `true`.</returns>
protected override bool GetFinishContidtion(IGUIState guiState)
{
return true;
}
}
}

View File

@@ -0,0 +1,70 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
/// <summary>
/// Represents an Action to process when the custom editor validates a command.
/// </summary>
public class CommandAction : GUIAction
{
private string m_CommandName;
/// <summary>
/// The Action to execute.
/// </summary>
public Action<IGUIState> onCommand;
/// <summary>
/// Initializes and returns an instance of CommandAction
/// </summary>
/// <param name="commandName">The name of the command. When the custom editor validates a command with this name, it triggers the action.</param>
public CommandAction(string commandName)
{
m_CommandName = commandName;
}
/// <summary>
/// Checks to see if the trigger condition has been met or not.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Returns `true` if the trigger condition has been met. Otherwise, returns `false`.</returns>
protected override bool GetTriggerContidtion(IGUIState guiState)
{
if (guiState.eventType == EventType.ValidateCommand && guiState.commandName == m_CommandName)
{
guiState.UseEvent();
return true;
}
return false;
}
/// <summary>
/// Checks to see if the finish condition has been met or not.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Returns `true` if the trigger condition is finished. Otherwise, returns `false`.</returns>
protected override bool GetFinishContidtion(IGUIState guiState)
{
if (guiState.eventType == EventType.ExecuteCommand && guiState.commandName == m_CommandName)
{
guiState.UseEvent();
return true;
}
return false;
}
/// <summary>
/// Calls the methods in its invocation list when the finish condition is met.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
protected override void OnFinish(IGUIState guiState)
{
if (onCommand != null)
onCommand(guiState);
}
}
}

View File

@@ -0,0 +1,250 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
/// <summary>
/// Represents a UI control in a custom editor.
/// </summary>
public abstract class Control
{
private string m_Name;
private int m_NameHashCode;
private int m_ID;
private LayoutData m_LayoutData;
private int m_ActionID = -1;
private LayoutData m_HotLayoutData;
/// <summary>
/// The name of the control.
/// </summary>
public string name
{
get { return m_Name; }
}
/// <summary>
/// The control ID. The GUI uses this to identify the control.
/// </summary>
public int ID
{
get { return m_ID; }
}
/// <summary>
/// The action ID.
/// </summary>
public int actionID
{
get { return m_ActionID; }
}
/// <summary>
/// The control's layout data. This contains information about the control's position and orientation.
/// </summary>
public LayoutData layoutData
{
get { return m_LayoutData; }
set { m_LayoutData = value; }
}
/// <summary>
/// The control's hot layout data
/// </summary>
public LayoutData hotLayoutData
{
get { return m_HotLayoutData; }
}
/// <summary>
/// Initializes and returns an instance of Control
/// </summary>
/// <param name="name">The name of the control</param>
public Control(string name)
{
m_Name = name;
m_NameHashCode = name.GetHashCode();
}
/// <summary>
/// Gets the control from the guiState.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
public void GetControl(IGUIState guiState)
{
m_ID = guiState.GetControlID(m_NameHashCode, FocusType.Passive);
}
internal void SetActionID(int actionID)
{
m_ActionID = actionID;
m_HotLayoutData = m_LayoutData;
}
/// <summary>
/// Begins the layout for this control. A call to EndLayout must always follow a call to this function.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
public void BeginLayout(IGUIState guiState)
{
Debug.Assert(guiState.eventType == EventType.Layout);
m_LayoutData = OnBeginLayout(LayoutData.zero, guiState);
}
/// <summary>
/// Gets the control's layout data from the guiState.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
public void Layout(IGUIState guiState)
{
Debug.Assert(guiState.eventType == EventType.Layout);
for (var i = 0; i < GetCount(); ++i)
{
if (guiState.hotControl == actionID && hotLayoutData.index == i)
continue;
var layoutData = new LayoutData()
{
index = i,
position = GetPosition(guiState, i),
distance = GetDistance(guiState, i),
forward = GetForward(guiState, i),
up = GetUp(guiState, i),
right = GetRight(guiState, i),
userData = GetUserData(guiState, i)
};
m_LayoutData = LayoutData.Nearest(m_LayoutData, layoutData);
}
}
/// <summary>
/// Ends the layout for this control. This function must always follow a call to BeginLayout().
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
public void EndLayout(IGUIState guiState)
{
Debug.Assert(guiState.eventType == EventType.Layout);
OnEndLayout(guiState);
}
/// <summary>
/// Repaints the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
public void Repaint(IGUIState guiState)
{
for (var i = 0; i < GetCount(); ++i)
OnRepaint(guiState, i);
}
/// <summary>
/// Called when the control begins its layout.
/// </summary>
/// <param name="data">The layout data.</param>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Returns the layout data to use.</returns>
protected virtual LayoutData OnBeginLayout(LayoutData data, IGUIState guiState)
{
return data;
}
/// <summary>
/// Called when the control ends its layout.
/// /// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
protected virtual void OnEndLayout(IGUIState guiState)
{
}
/// <summary>
/// Called when the control repaints its contents.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The index.</param>
protected virtual void OnRepaint(IGUIState guiState, int index)
{
}
/// <summary>
/// Gets the number of sub-controllers.
/// </summary>
/// <remarks>
/// By default, this is `1`. If you implement your own controller and want to use multiple sub-controllers within it, you can override this function to declare how to count the sub-controllers.
/// </remarks>
/// <returns>Returns the number of sub-controllers. If you do not override this function, this returns 1.</returns>
protected virtual int GetCount()
{
return 1;
}
/// <summary>
/// Gets the position of the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The index.</param>
/// <returns>Returns Vector3.zero.</returns>
protected virtual Vector3 GetPosition(IGUIState guiState, int index)
{
return Vector3.zero;
}
/// <summary>
/// Gets the forward vector of the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The index.</param>
/// <returns>Returns Vector3.forward.</returns>
protected virtual Vector3 GetForward(IGUIState guiState, int index)
{
return Vector3.forward;
}
/// <summary>
/// Gets the up vector of the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The index.</param>
/// <returns>Returns Vector3.up,</returns>
protected virtual Vector3 GetUp(IGUIState guiState, int index)
{
return Vector3.up;
}
/// <summary>
/// Gets the right vector of the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The index.</param>
/// <returns>Returns Vector3.right.</returns>
protected virtual Vector3 GetRight(IGUIState guiState, int index)
{
return Vector3.right;
}
/// <summary>
/// Gets the distance from the Scene view camera to the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The index.</param>
/// <returns>Returns layoutData.distance.</returns>
protected virtual float GetDistance(IGUIState guiState, int index)
{
return layoutData.distance;
}
/// <summary>
/// Gets the control's user data.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The index.</param>
/// <returns>Returns `null`.</returns>
protected virtual object GetUserData(IGUIState guiState, int index)
{
return null;
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
/// <summary>
/// Represents the default implementation of a control.
/// </summary>
public abstract class DefaultControl : Control
{
/// <summary>
/// Default kPickDistance == 5.0f
/// </summary>
public static readonly float kPickDistance = 5f;
/// <summary>
/// Initializes and returns an instance of DefaultControl
/// </summary>
/// <param name="name">The name of the default control.</param>
public DefaultControl(string name) : base(name)
{
}
/// <summary>
/// Overrides the Control.OnBeginLayout function.
/// </summary>
/// <remarks>
/// Sets the LayoutData.distance to DefaultControl.kPickDistance.
/// </remarks>
/// <param name="data">The layout data.</param>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Returns the modified layout data.</returns>
protected override LayoutData OnBeginLayout(LayoutData data, IGUIState guiState)
{
data.distance = kPickDistance;
return data;
}
}
}

View File

@@ -0,0 +1,184 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
/// <summary>
/// Represents an action that is tied to a GUI element.
/// </summary>
public abstract class GUIAction
{
private int m_ID = -1;
/// <summary>
/// Func for GetEnable
/// </summary>
public Func<IGUIState, GUIAction, bool> enable;
/// <summary>
/// Func for EnabledRepaint
/// </summary>
public Func<IGUIState, GUIAction, bool> enableRepaint;
/// <summary>
/// Func for repaintOnMouseMove
/// </summary>
public Func<IGUIState, GUIAction, bool> repaintOnMouseMove;
/// <summary>
/// Action for OnPreRepaint
/// </summary>
public Action<IGUIState, GUIAction> onPreRepaint;
/// <summary>
/// Func for OnRepaint
/// </summary>
public Action<IGUIState, GUIAction> onRepaint;
/// <summary>
/// The action ID.
/// </summary>
public int ID
{
get { return m_ID; }
}
/// <summary>
/// Calls the methods in its invocation list when Unity draws this GUIAction's GUI.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
public void OnGUI(IGUIState guiState)
{
m_ID = guiState.GetControlID(GetType().GetHashCode(), FocusType.Passive);
if (guiState.hotControl == 0 && IsEnabled(guiState) && CanTrigger(guiState) && GetTriggerContidtion(guiState))
{
guiState.hotControl = ID;
OnTrigger(guiState);
}
if (guiState.hotControl == ID)
{
if (GetFinishContidtion(guiState))
{
OnFinish(guiState);
guiState.hotControl = 0;
}
else
{
OnPerform(guiState);
}
}
if (guiState.eventType == EventType.Repaint && IsRepaintEnabled(guiState))
Repaint(guiState);
}
/// <summary>
/// Checks whether the GUIAction is enabled.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Returns `true` if the GUIAction is enabled in the custom editor. Otherwise, returns `false`.</returns>
public bool IsEnabled(IGUIState guiState)
{
if (enable != null)
return enable(guiState, this);
return true;
}
/// <summary>
/// Checks whether the GUIAction should repaint.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Returns `true` if the GUIAction should repaint. Otherwise, returns `false`.</returns>
public bool IsRepaintEnabled(IGUIState guiState)
{
if (!IsEnabled(guiState))
return false;
if (enableRepaint != null)
return enableRepaint(guiState, this);
return true;
}
/// <summary>
/// Preprocessing that occurs before the GUI repaints.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
public void PreRepaint(IGUIState guiState)
{
Debug.Assert(guiState.eventType == EventType.Repaint);
if (IsEnabled(guiState) && onPreRepaint != null)
onPreRepaint(guiState, this);
}
/// <summary>
/// Calls the methods in its invocation list when repainting the GUI.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
private void Repaint(IGUIState guiState)
{
Debug.Assert(guiState.eventType == EventType.Repaint);
if (onRepaint != null)
onRepaint(guiState, this);
}
/// <summary>
/// Checks whether the GUI should repaint if the mouse moves over it.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Returns `true` if the GUI should repaint if the moves moves over it. Otherwise, returns `false`.</returns>
internal bool IsRepaintOnMouseMoveEnabled(IGUIState guiState)
{
if (!IsEnabled(guiState) || !IsRepaintEnabled(guiState))
return false;
if (repaintOnMouseMove != null)
return repaintOnMouseMove(guiState, this);
return false;
}
/// <summary>
/// Determines whether the finish condition has been met.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Returns `true` if finish condition has been met. Otherwise, returns `false`.</returns>
protected abstract bool GetFinishContidtion(IGUIState guiState);
/// <summary>
/// Determines whether the trigger condition has been met.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Returns `true` if finish condition has been met. Otherwise, returns `false`.</returns>
protected abstract bool GetTriggerContidtion(IGUIState guiState);
/// <summary>
/// Determines whether the GUIAction can trigger.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Always returns `true`.</returns>
protected virtual bool CanTrigger(IGUIState guiState) { return true; }
/// <summary>
/// Calls the methods in its invocation list when triggered.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
protected virtual void OnTrigger(IGUIState guiState)
{
}
/// <summary>
/// Calls the methods in its invocation list when performed.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
protected virtual void OnPerform(IGUIState guiState)
{
}
/// <summary>
/// Calls the methods in its invocation list when finished.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
protected virtual void OnFinish(IGUIState guiState)
{
}
}
}

View File

@@ -0,0 +1,245 @@
using UnityEngine;
using UnityEditor;
namespace UnityEditor.U2D.Path.GUIFramework
{
/// <summary>
/// An implementation of an IGUIState that represents a generic GUI state.
/// </summary>
public class GUIState : IGUIState
{
private Handles.CapFunction nullCap = (int c, Vector3 p , Quaternion r, float s, EventType ev) => {};
/// <summary>
/// The current mouse position.
/// </summary>
public Vector2 mousePosition
{
get { return Event.current.mousePosition; }
}
/// <summary>
/// The currently pressed button.
/// </summary>
public int mouseButton
{
get { return Event.current.button; }
}
/// <summary>
/// The current number of mouse clicks.
/// </summary>
public int clickCount
{
get { return Event.current.clickCount; }
set { Event.current.clickCount = Mathf.Max(0, value); }
}
/// <summary>
/// Indicates whether the shift key is pressed.
/// </summary>
public bool isShiftDown
{
get { return Event.current.shift; }
}
/// <summary>
/// Indicates whether the alt key is pressed.
/// </summary>
public bool isAltDown
{
get { return Event.current.alt; }
}
/// <summary>
/// Indicates whether the action key is pressed.
/// </summary>
public bool isActionKeyDown
{
get { return EditorGUI.actionKey; }
}
/// <summary>
/// The KeyCode of the currently pressed key.
/// </summary>
public KeyCode keyCode
{
get { return Event.current.keyCode; }
}
/// <summary>
/// The type of the current event.
/// </summary>
public EventType eventType
{
get { return Event.current.type; }
}
/// <summary>
/// The name of the current event's command.
/// </summary>
public string commandName
{
get { return Event.current.commandName; }
}
/// <summary>
/// The closest control to the event.
/// </summary>
public int nearestControl
{
get { return HandleUtility.nearestControl; }
set { HandleUtility.nearestControl = value; }
}
/// <summary>
/// Hot Control
/// </summary>
public int hotControl
{
get { return GUIUtility.hotControl; }
set { GUIUtility.hotControl = value; }
}
/// <summary>
/// Indicates whether the GUI has changed.
/// </summary>
public bool changed
{
get { return GUI.changed; }
set { GUI.changed = value; }
}
/// <summary>
/// Gets the ID of a nested control by a hint and focus type.
/// </summary>
/// <param name="hint">The hint this function uses to identify the control ID.</param>
/// <param name="focusType">The focus Type</param>
/// <returns>Returns the ID of the control that matches the hint and focus type.</returns>
public int GetControlID(int hint, FocusType focusType)
{
return GUIUtility.GetControlID(hint, focusType);
}
/// <summary>
/// Adds a control to the GUIState.
/// </summary>
/// <param name="controlID">The ID of the control to add.</param>
/// <param name="distance">The distance from the camera to the control.</param>
public void AddControl(int controlID, float distance)
{
HandleUtility.AddControl(controlID, distance);
}
/// <summary>
/// Checks whether a slider value has changed.
/// </summary>
/// <param name="id">The ID of the slider to check.</param>
/// <param name="sliderData">The slider's data.</param>
/// <param name="newPosition">The new position of the slider.</param>
/// <returns>Returns `true` if the slider has changed. Otherwise, returns `false`.</returns>
public bool Slider(int id, SliderData sliderData, out Vector3 newPosition)
{
if (mouseButton == 0 && eventType == EventType.MouseDown)
{
hotControl = 0;
nearestControl = id;
}
EditorGUI.BeginChangeCheck();
newPosition = Handles.Slider2D(id, sliderData.position, sliderData.forward, sliderData.right, sliderData.up, 1f, nullCap, Vector2.zero);
return EditorGUI.EndChangeCheck();
}
/// <summary>
/// Uses the current event.
/// </summary>
public void UseEvent()
{
Event.current.Use();
}
/// <summary>
/// Repaints the GUI.
/// </summary>
public void Repaint()
{
HandleUtility.Repaint();
}
/// <summary>
/// Checks if the current camera is valid.
/// </summary>
/// <returns>Returns `true` if the current camera is not null. Otherwise, returns `false`.</returns>
public bool HasCurrentCamera()
{
return Camera.current != null;
}
/// <summary>
/// Gets the size of the handle.
/// </summary>
/// <param name="position">The position of the handle.</param>
/// <returns>Returns the size of the handle.</returns>
public float GetHandleSize(Vector3 position)
{
var scale = HasCurrentCamera() ? 0.01f : 0.05f;
return HandleUtility.GetHandleSize(position) * scale;
}
/// <summary>
/// Measures the GUI-space distance between two points of a segment.
/// </summary>
/// <param name="p1">The first point.</param>
/// <param name="p2">The seconde point.</param>
/// <returns>Returns the GUI-space distance between p1 and p2.</returns>
public float DistanceToSegment(Vector3 p1, Vector3 p2)
{
p1 = HandleUtility.WorldToGUIPoint(p1);
p2 = HandleUtility.WorldToGUIPoint(p2);
return HandleUtility.DistancePointToLineSegment(Event.current.mousePosition, p1, p2);
}
/// <summary>
/// Measures the distance to a circle.
/// </summary>
/// <param name="center">The center of the circle.</param>
/// <param name="radius">The radius of the circle.</param>
/// <returns>Returns the distance to a circle with the specified center and radius.</returns>
public float DistanceToCircle(Vector3 center, float radius)
{
return HandleUtility.DistanceToCircle(center, radius);
}
/// <summary>
/// Transforms a GUI-space position into world space.
/// </summary>
/// <param name="guiPosition">The GUI position</param>
/// <param name="planeNormal">The plane normal.</param>
/// <param name="planePos">The plane position.</param>
/// <returns>Returns the world-space position of `guiPosition`.</returns>
public Vector3 GUIToWorld(Vector2 guiPosition, Vector3 planeNormal, Vector3 planePos)
{
Vector3 worldPos = Handles.inverseMatrix.MultiplyPoint(guiPosition);
if (Camera.current)
{
Ray ray = HandleUtility.GUIPointToWorldRay(guiPosition);
planeNormal = Handles.matrix.MultiplyVector(planeNormal);
planePos = Handles.matrix.MultiplyPoint(planePos);
Plane plane = new Plane(planeNormal, planePos);
float distance = 0f;
if (plane.Raycast(ray, out distance))
{
worldPos = Handles.inverseMatrix.MultiplyPoint(ray.GetPoint(distance));
}
}
return worldPos;
}
}
}

View File

@@ -0,0 +1,154 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
/// <summary>
/// Represents a system of GUI elements and controls.
/// </summary>
public class GUISystem
{
private readonly int kControlIDCheckHashCode = "ControlIDCheckHashCode".GetHashCode();
private List<Control> m_Controls = new List<Control>();
private List<GUIAction> m_Actions = new List<GUIAction>();
private IGUIState m_GUIState;
private int m_PrevNearestControl = -1;
private LayoutData m_PrevNearestLayoutData = LayoutData.zero;
private int m_ControlIDCheck = -1;
/// <summary>
/// Initializes and returns an instance of GUISystem
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
public GUISystem(IGUIState guiState)
{
m_GUIState = guiState;
}
/// <summary>
/// Adds a control to the internal list of controls.
/// </summary>
/// <param name="control">The control to add.</param>
public void AddControl(Control control)
{
if (control == null)
throw new NullReferenceException("Control is null");
m_Controls.Add(control);
}
/// <summary>
/// Removes a control from the internal list of controls.
/// </summary>
/// <param name="control">The control to remove.</param>
public void RemoveControl(Control control)
{
m_Controls.Remove(control);
}
/// <summary>
/// Adds an action to the internal list of actions.
/// </summary>
/// <param name="action">The action to add.</param>
public void AddAction(GUIAction action)
{
if (action == null)
throw new NullReferenceException("Action is null");
m_Actions.Add(action);
}
/// <summary>
/// Removes an action from the internal list of actions.
/// </summary>
/// <param name="action">The action to remove.</param>
public void RemoveAction(GUIAction action)
{
m_Actions.Remove(action);
}
/// <summary>
/// Calls the methods in its invocation list when Unity draws this GUISystems's GUI.
/// </summary>
public void OnGUI()
{
var controlIDCheck = m_GUIState.GetControlID(kControlIDCheckHashCode, FocusType.Passive);
if (m_GUIState.eventType == EventType.Layout)
m_ControlIDCheck = controlIDCheck;
else if (m_GUIState.eventType != EventType.Used && m_ControlIDCheck != controlIDCheck)
Debug.LogWarning("GetControlID at event " + m_GUIState.eventType + " returns a controlID different from the one in Layout event");
var nearestLayoutData = LayoutData.zero;
foreach (var control in m_Controls)
control.GetControl(m_GUIState);
if (m_GUIState.eventType == EventType.Layout)
{
foreach (var control in m_Controls)
control.BeginLayout(m_GUIState);
foreach (var control in m_Controls)
{
control.Layout(m_GUIState);
nearestLayoutData = LayoutData.Nearest(nearestLayoutData, control.layoutData);
}
foreach (var control in m_Controls)
m_GUIState.AddControl(control.ID, control.layoutData.distance);
foreach (var control in m_Controls)
control.EndLayout(m_GUIState);
if (m_PrevNearestControl == m_GUIState.nearestControl)
{
if (nearestLayoutData.index != m_PrevNearestLayoutData.index)
m_GUIState.Repaint();
}
else
{
m_PrevNearestControl = m_GUIState.nearestControl;
m_GUIState.Repaint();
}
m_PrevNearestLayoutData = nearestLayoutData;
}
if (m_GUIState.eventType == EventType.Repaint)
{
foreach (var action in m_Actions)
if (action.IsRepaintEnabled(m_GUIState))
action.PreRepaint(m_GUIState);
foreach (var control in m_Controls)
control.Repaint(m_GUIState);
}
var repaintOnMouseMove = false;
foreach (var action in m_Actions)
{
if (IsMouseMoveEvent())
repaintOnMouseMove |= action.IsRepaintOnMouseMoveEnabled(m_GUIState);
action.OnGUI(m_GUIState);
}
if (repaintOnMouseMove)
m_GUIState.Repaint();
}
/// <summary>
/// Calls the methods in its invocation list when the mouse moves.
/// </summary>
/// <returns>Returns `true` if the mouse moved. Otherwise, returns `false`.</returns>
private bool IsMouseMoveEvent()
{
return m_GUIState.eventType == EventType.MouseMove || m_GUIState.eventType == EventType.MouseDrag;
}
}
}

View File

@@ -0,0 +1,195 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
/// <summary>
/// Represents a generic UI control.
/// </summary>
public class GenericControl : Control
{
/// <summary>
/// Func for OnBeginLayout
/// </summary>
public Func<IGUIState, LayoutData> onBeginLayout;
/// <summary>
/// Action for OnEndLayout
/// </summary>
public Action<IGUIState> onEndLayout;
/// <summary>
/// Action for OnRepaint
/// </summary>
public Action<IGUIState, Control, int> onRepaint;
/// <summary>
/// Func for GetCount
/// </summary>
public Func<int> count;
/// <summary>
/// Func for GetPosition
/// </summary>
public Func<int, Vector3> position;
/// <summary>
/// Func for GetDistance
/// </summary>
public Func<IGUIState, int, float> distance;
/// <summary>
/// Func for GetForward
/// </summary>
public Func<int, Vector3> forward;
/// <summary>
/// Func for GetUp
/// </summary>
public Func<int, Vector3> up;
/// <summary>
/// Func for GetRight
/// </summary>
public Func<int, Vector3> right;
/// <summary>
/// Func for GetUserData
/// </summary>
public Func<int, object> userData;
/// <summary>
/// Initializes and returns an instance of GenericControl
/// </summary>
/// <param name="name">The name of the generic control.</param>
public GenericControl(string name) : base(name)
{
}
/// <summary>
/// Gets the number of sub-controllers.
/// </summary>
/// <remarks>
/// By default, this is `1`. If you implement your own controller and want to use multiple sub-controllers within it, you can assign getCount to a function that returns the number of sub-controllers.
/// </remarks>
/// <returns>Returns the number of sub-controllers. If you do not assign getCount, this returns 1.</returns>
protected override int GetCount()
{
if (count != null)
return count();
return base.GetCount();
}
/// <summary>
/// Called when the control ends its layout.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
protected override void OnEndLayout(IGUIState guiState)
{
if (onEndLayout != null)
onEndLayout(guiState);
}
/// <summary>
/// Called when the control repaints its contents.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">Current Index</param>
protected override void OnRepaint(IGUIState guiState, int index)
{
if (onRepaint != null)
onRepaint(guiState, this, index);
}
/// <summary>
/// Called when the control begins its layout.
/// </summary>
/// <param name="data">The layout data.</param>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>The LayoutData</returns>
protected override LayoutData OnBeginLayout(LayoutData data, IGUIState guiState)
{
if (onBeginLayout != null)
return onBeginLayout(guiState);
return data;
}
/// <summary>
/// Gets the position of the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The Index</param>
/// <returns>The position</returns>
protected override Vector3 GetPosition(IGUIState guiState, int index)
{
if (position != null)
return position(index);
return base.GetPosition(guiState,index);
}
/// <summary>
/// Gets the distance from the Scene view camera to the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The Index</param>
/// <returns>Returns the distance from the Scene view camera to the control.</returns>
protected override float GetDistance(IGUIState guiState, int index)
{
if (distance != null)
return distance(guiState, index);
return base.GetDistance(guiState, index);
}
/// <summary>
/// Gets the forward vector of the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The Index</param>
/// <returns>Returns the generic control's forward vector.</returns>
protected override Vector3 GetForward(IGUIState guiState, int index)
{
if (forward != null)
return forward(index);
return base.GetForward(guiState,index);
}
/// <summary>
/// Gets the up vector of the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The Index</param>
/// <returns>Returns the generic control's up vector.</returns>
protected override Vector3 GetUp(IGUIState guiState, int index)
{
if (up != null)
return up(index);
return base.GetUp(guiState,index);
}
/// <summary>
/// Gets the right vector of the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The Index</param>
/// <returns>Returns the generic control's right vector.</returns>
protected override Vector3 GetRight(IGUIState guiState, int index)
{
if (right != null)
return right(index);
return base.GetRight(guiState,index);
}
/// <summary>
/// Override for GetUserData
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The Index</param>
/// <returns>Return the user data</returns>
protected override object GetUserData(IGUIState guiState, int index)
{
if (userData != null)
return userData(index);
return base.GetUserData(guiState,index);
}
}
}

View File

@@ -0,0 +1,110 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
/// <summary>
/// Represents a default generic UI control.
/// </summary>
public class GenericDefaultControl : DefaultControl
{
/// <summary>
/// Func for GetPosition
/// </summary>
public Func<IGUIState, Vector3> position;
/// <summary>
/// Func for GetForward
/// </summary>
public Func<IGUIState, Vector3> forward;
/// <summary>
/// Func for GetUp
/// </summary>
public Func<IGUIState, Vector3> up;
/// <summary>
/// Func for GetRight
/// </summary>
public Func<IGUIState, Vector3> right;
/// <summary>
/// Func for GetUserData
/// </summary>
public Func<IGUIState, object> userData;
/// <summary>
/// Initializes and returns an instance of GenericDefaultControl
/// </summary>
/// <param name="name">The name of the generic default control.</param>
public GenericDefaultControl(string name) : base(name)
{
}
/// <summary>
/// Gets the distance from the Scene view camera to the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The Index</param>
/// <returns>The distance from the Scene view camera to the control.</returns>
protected override Vector3 GetPosition(IGUIState guiState, int index)
{
if (position != null)
return position(guiState);
return base.GetPosition(guiState, index);
}
/// <summary>
/// Gets the forward vector of the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The Index</param>
/// <returns>Returns the generic control's forward vector.</returns>
protected override Vector3 GetForward(IGUIState guiState, int index)
{
if (forward != null)
return forward(guiState);
return base.GetForward(guiState, index);
}
/// <summary>
/// Gets the up vector of the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The Index</param>
/// <returns>Returns the generic control's up vector.</returns>
protected override Vector3 GetUp(IGUIState guiState, int index)
{
if (up != null)
return up(guiState);
return base.GetUp(guiState, index);
}
/// <summary>
/// Gets the right vector of the control.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The Index</param>
/// <returns>Returns the generic control's right vector.</returns>
protected override Vector3 GetRight(IGUIState guiState, int index)
{
if (right != null)
return right(guiState);
return base.GetRight(guiState, index);
}
/// <summary>
/// Gets the control's user data.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <param name="index">The Index</param>
/// <returns>Returns the user data</returns>
protected override object GetUserData(IGUIState guiState, int index)
{
if (userData != null)
return userData(guiState);
return base.GetUserData(guiState, index);
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
/// <summary>
/// Represents an action that is tied to a Control.
/// </summary>
public abstract class HoveredControlAction : GUIAction
{
private Control m_HoveredControl;
/// <summary>
/// The hovered control.
/// </summary>
public Control hoveredControl
{
get { return m_HoveredControl; }
}
/// <summary>
/// Initializes and returns an instance of HoverControlAction.
/// </summary>
/// <param name="control">The control to execcute an action for on hover.</param>
public HoveredControlAction(Control control)
{
m_HoveredControl = control;
}
/// <summary>
/// Determines whether the HoveredControlAction can trigger.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Returns `true` if the HoveredControlAction can trigger. Otherwise, returns `false`.</returns>
protected override bool CanTrigger(IGUIState guiState)
{
return guiState.nearestControl == hoveredControl.ID;
}
/// <summary>
/// Calls the methods in its invocation list when triggered.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
protected override void OnTrigger(IGUIState guiState)
{
m_HoveredControl.SetActionID(ID);
}
}
}

View File

@@ -0,0 +1,155 @@
using UnityEngine;
using UnityEditor;
namespace UnityEditor.U2D.Path.GUIFramework
{
/// <summary>
/// Represents transform data for a slider.
/// </summary>
/// <remarks>
/// Unity uses this data to position and orient the slider in the custom editor.
/// </remarks>
public struct SliderData
{
/// <summary>
/// The slider's position.
/// </summary>
public Vector3 position;
/// <summary>
/// The slider's forward vector.
/// </summary>
public Vector3 forward;
/// <summary>
/// The slider's up vector.
/// </summary>
public Vector3 up;
/// <summary>
/// The slider's right vector.
/// </summary>
public Vector3 right;
/// <summary>
/// zero definition for SliderData
/// </summary>
public static readonly SliderData zero = new SliderData() { position = Vector3.zero, forward = Vector3.forward, up = Vector3.up, right = Vector3.right };
}
/// <summary>
/// Interface for GUIStates
/// </summary>
public interface IGUIState
{
/// <summary>
/// The mouse position.
/// </summary>
Vector2 mousePosition { get; }
/// <summary>
/// The mouse button pressed.
/// </summary>
int mouseButton { get; }
/// <summary>
/// The number of mouse clicks.
/// </summary>
int clickCount { get; set; }
/// <summary>
/// Indicates whether the shift key is pressed.
/// </summary>
bool isShiftDown { get; }
/// <summary>
/// Indicates whether the alt key is pressed.
/// </summary>
bool isAltDown { get; }
/// <summary>
/// Indicates whether the action key is pressed.
/// </summary>
bool isActionKeyDown { get; }
/// <summary>
/// The KeyCode of the currently pressed key.
/// </summary>
KeyCode keyCode { get; }
/// <summary>
/// The type of the event.
/// </summary>
EventType eventType { get; }
/// <summary>
/// The name of the event's command.
/// </summary>
string commandName { get; }
/// <summary>
/// The closest control to the event.
/// </summary>
int nearestControl { get; set; }
/// <summary>
/// Hot Control
/// </summary>
int hotControl { get; set; }
/// <summary>
/// Indicates whether the GUI has changed.
/// </summary>
bool changed { get; set; }
/// <summary>
/// <summary>
/// Gets the ID of a nested control by a hint and focus type.
/// </summary>
/// <param name="hint">The hint this function uses to identify the control ID.</param>
/// <param name="focusType">The focus Type</param>
/// <returns>Returns the ID of the control that matches the hint and focus type.</returns>
int GetControlID(int hint, FocusType focusType);
/// <summary>
/// Adds a control to the GUIState.
/// </summary>
/// <param name="controlID">The ID of the control to add.</param>
/// <param name="distance">The distance from the camera to the control.</param>
void AddControl(int controlID, float distance);
/// <summary>
/// Checks whether a slider value has changed.
/// </summary>
/// <param name="id">The ID of the slider to check.</param>
/// <param name="sliderData">The slider's data.</param>
/// <param name="newPosition">The new position of the slider.</param>
/// <returns>Returns `true` if the slider has changed. Otherwise, returns `false`.</returns>
bool Slider(int id, SliderData sliderData, out Vector3 newPosition);
/// <summary>
/// Uses the event.
/// </summary>
void UseEvent();
/// <summary>
/// Repaints the GUI.
/// </summary>
void Repaint();
/// <summary>
/// Checks if the current camera is valid.
/// </summary>
/// <returns>Returns `true` if the current camera is not null. Otherwise, returns `false`.</returns>
bool HasCurrentCamera();
/// <summary>
/// Gets the size of the handle.
/// </summary>
/// <param name="position">The position of the handle.</param>
/// <returns>Returns the size of the handle.</returns>
float GetHandleSize(Vector3 position);
/// <summary>
/// Measures the GUI-space distance between two points of a segment.
/// </summary>
/// <param name="p1">The first point.</param>
/// <param name="p2">The second point.</param>
/// <returns>Returns the GUI-space distance between p1 and p2.</returns>
float DistanceToSegment(Vector3 p1, Vector3 p2);
/// <summary>
/// Measures the distance to a circle.
/// </summary>
/// <param name="center">The center of the circle</param>
/// <param name="radius">The radius of the circle</param>
/// <returns>Returns the distance to a circle with the specified center and radius.</returns>
float DistanceToCircle(Vector3 center, float radius);
/// <summary>
/// Transforms a GUI-space position into world space.
/// </summary>
/// <param name="guiPosition">The GUI Position.</param>
/// <param name="planeNormal">The plane normal.</param>
/// <param name="planePos">The plane position.</param>
/// <returns>Returns the world-space position of `guiPosition`.</returns>
Vector3 GUIToWorld(Vector2 guiPosition, Vector3 planeNormal, Vector3 planePos);
}
}

View File

@@ -0,0 +1,58 @@
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
/// <summary>
/// Represents the layout of a GUI element in a custom editor.
/// </summary>
public struct LayoutData
{
/// <summary>
/// The layout's index.
/// </summary>
public int index;
/// <summary>
/// The distance from the layout to the camera.
/// </summary>
public float distance;
/// <summary>
/// The layout's world-space position.
/// </summary>
public Vector3 position;
/// <summary>
/// The layout's world-space forward vector.
/// </summary>
public Vector3 forward;
/// <summary>
/// The layout's world-space up vector.
/// </summary>
public Vector3 up;
/// <summary>
/// The layout's world-space right vector.
/// </summary>
public Vector3 right;
/// <summary>
/// The layout's user data.
/// </summary>
public object userData;
/// <summary>
/// Zero definition of LayoutData.
/// </summary>
public static readonly LayoutData zero = new LayoutData() { index = 0, distance = float.MaxValue, position = Vector3.zero, forward = Vector3.forward, up = Vector3.up, right = Vector3.right };
/// <summary>
/// Gets the layout that is closest to the camera,
/// </summary>
/// <param name="currentData">The current layout.</param>
/// <param name="newData">The new layout to compare with.</param>
/// <returns>Returns the closest layout to the camera. If `currentData` is closest to the camera, returns `currentData`. Otherwise, if `newData` is closest to the camera, returns `newData`.</returns>
public static LayoutData Nearest(LayoutData currentData, LayoutData newData)
{
if (newData.distance <= currentData.distance)
return newData;
return currentData;
}
}
}

View File

@@ -0,0 +1,92 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
/// <summary>
/// SliderAction implementation of a ClickAction
/// </summary>
public class SliderAction : ClickAction
{
private SliderData m_SliderData;
/// <summary>
/// Action for OnSliderBegin
/// </summary>
public Action<IGUIState, Control, Vector3> onSliderBegin;
/// <summary>
/// Action for OnSliderChanged
/// </summary>
public Action<IGUIState, Control, Vector3> onSliderChanged;
/// <summary>
/// Action for OnSliderEnd
/// </summary>
public Action<IGUIState, Control, Vector3> onSliderEnd;
/// <summary>
/// Initializes and returns an instance of SliderAction
/// </summary>
/// <param name="control">The control to execcute an action for on slide.</param>
public SliderAction(Control control) : base(control, 0, false)
{
}
/// <summary>
/// Checks to see if the finish condition has been met or not.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
/// <returns>Returns `true` if the finish condition has been met. Otherwise, returns `false`.</returns>
protected override bool GetFinishContidtion(IGUIState guiState)
{
return guiState.eventType == EventType.MouseUp && guiState.mouseButton == 0;
}
/// <summary>
/// Called when there is interaction with the slider. It updates the stored slider data with data post-interaction.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
protected override void OnTrigger(IGUIState guiState)
{
base.OnTrigger(guiState);
m_SliderData.position = hoveredControl.hotLayoutData.position;
m_SliderData.forward = hoveredControl.hotLayoutData.forward;
m_SliderData.right = hoveredControl.hotLayoutData.right;
m_SliderData.up = hoveredControl.hotLayoutData.up;
if (onSliderBegin != null)
onSliderBegin(guiState, hoveredControl, m_SliderData.position);
}
/// <summary>
/// Post-processing for when the slider interaction finishes.
/// </summary>
/// <param name="guiState">The current state of the custom editor.</param>
protected override void OnFinish(IGUIState guiState)
{
if (onSliderEnd != null)
onSliderEnd(guiState, hoveredControl, m_SliderData.position);
guiState.UseEvent();
guiState.Repaint();
}
/// <summary>
/// Moves the slider to the new permission and executes `onSliderChanged` using the new position.
/// </summary>
/// <param name="guiState">The current state of the custom editor</param>
protected override void OnPerform(IGUIState guiState)
{
Vector3 newPosition;
var changed = guiState.Slider(ID, m_SliderData, out newPosition);
if (changed)
{
m_SliderData.position = newPosition;
if (onSliderChanged != null)
onSliderChanged(guiState, hoveredControl, newPosition);
}
}
}
}