您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
627 行
18 KiB
627 行
18 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEditorInternal;
|
|
using UnityEditorInternal.Experimental;
|
|
using UnityEngine;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace UnityEditor.Experimental
|
|
{
|
|
public class CanvasElement : UnityEditorInternal.Experimental.IBounds
|
|
{
|
|
[Flags]
|
|
public enum Capabilities
|
|
{
|
|
Normal,
|
|
Unselectable,
|
|
DoesNotCollapse,
|
|
Floating
|
|
}
|
|
|
|
protected int m_ZIndex;
|
|
protected List<CanvasElement> m_Children = new List<CanvasElement>();
|
|
protected List<CanvasElement> m_Dependencies = new List<CanvasElement>();
|
|
protected Vector3 m_Translation = Vector3.zero;
|
|
protected Vector3 m_Scale = Vector3.one;
|
|
protected bool m_Selected;
|
|
protected bool m_Collapsed;
|
|
protected RenderTexture m_Texture;
|
|
protected CanvasElement m_Parent;
|
|
protected Object m_Target;
|
|
protected bool m_SupportsRenderToTexture = true;
|
|
private bool m_Dirty = true;
|
|
protected Capabilities m_Caps = Capabilities.Normal;
|
|
|
|
public event CanvasEvent MouseDown;
|
|
public event CanvasEvent MouseDrag;
|
|
public event CanvasEvent MouseUp;
|
|
public event CanvasEvent DoubleClick;
|
|
public event CanvasEvent ScrollWheel;
|
|
public event CanvasEvent KeyDown;
|
|
public event CanvasEvent ValidateCommand;
|
|
public event CanvasEvent ExecuteCommand;
|
|
public event CanvasEvent OnWidget;
|
|
public event CanvasEvent ContextClick;
|
|
public event CanvasEvent DragPerform;
|
|
public event CanvasEvent DragExited;
|
|
public event CanvasEvent DragUpdated;
|
|
public event CanvasEvent AllEvents;
|
|
|
|
private struct AnimationData
|
|
{
|
|
public Vector2 scaleFrom;
|
|
public Vector2 scaleTo;
|
|
public float scaleTime;
|
|
}
|
|
|
|
private AnimationData m_Animationdata;
|
|
|
|
public Capabilities caps
|
|
{
|
|
get { return m_Caps; }
|
|
set { m_Caps = value; }
|
|
}
|
|
|
|
public CanvasElement parent
|
|
{
|
|
get { return m_Parent; }
|
|
set { m_Parent = value; }
|
|
}
|
|
|
|
public Object target
|
|
{
|
|
get { return m_Target; }
|
|
set { m_Target = value; }
|
|
}
|
|
|
|
public bool selected
|
|
{
|
|
get { return m_Selected; }
|
|
set
|
|
{
|
|
if ((caps & Capabilities.Unselectable) == Capabilities.Unselectable)
|
|
value = false;
|
|
m_Selected = value;
|
|
foreach (CanvasElement e in m_Children)
|
|
{
|
|
e.selected = value;
|
|
}
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
public bool collapsed
|
|
{
|
|
get { return m_Collapsed; }
|
|
set
|
|
{
|
|
m_Collapsed = value;
|
|
foreach (CanvasElement e in m_Children)
|
|
{
|
|
e.collapsed = value;
|
|
}
|
|
UpdateModel(UpdateType.Update);
|
|
}
|
|
}
|
|
|
|
public T FindParent<T>() where T : class
|
|
{
|
|
if (m_Parent == null)
|
|
return default(T);
|
|
|
|
T casted = m_Parent as T;
|
|
|
|
if (casted != null)
|
|
{
|
|
return casted;
|
|
}
|
|
|
|
return m_Parent.FindParent<T>();
|
|
}
|
|
|
|
public Canvas2D ParentCanvas()
|
|
{
|
|
if (this is Canvas2D)
|
|
return this as Canvas2D;
|
|
|
|
CanvasElement e = FindTopMostParent();
|
|
if (e is Canvas2D)
|
|
return e as Canvas2D;
|
|
|
|
return e.parent as Canvas2D;
|
|
}
|
|
|
|
public CanvasElement FindTopMostParent()
|
|
{
|
|
if (m_Parent == null)
|
|
return null;
|
|
|
|
if (m_Parent is Canvas2D)
|
|
return this;
|
|
|
|
return m_Parent.FindTopMostParent();
|
|
}
|
|
|
|
public void ZSort()
|
|
{
|
|
m_Children = m_Children.OrderBy(c => c.zIndex).ToList();
|
|
}
|
|
|
|
public bool IsCollapsed()
|
|
{
|
|
if ((caps & Capabilities.DoesNotCollapse) == Capabilities.DoesNotCollapse)
|
|
return false;
|
|
|
|
return collapsed;
|
|
}
|
|
|
|
public Rect elementRect
|
|
{
|
|
get
|
|
{
|
|
Rect rect = new Rect
|
|
{
|
|
xMin = m_Translation.x,
|
|
yMin = m_Translation.y
|
|
};
|
|
rect.xMax = rect.xMin + m_Scale.x;
|
|
rect.yMax = rect.yMin + m_Scale.y;
|
|
return rect;
|
|
}
|
|
}
|
|
|
|
public virtual Rect boundingRect
|
|
{
|
|
get
|
|
{
|
|
Rect rect = new Rect
|
|
{
|
|
xMin = m_Translation.x,
|
|
yMin = m_Translation.y
|
|
};
|
|
rect.xMax = rect.xMin + m_Scale.x;
|
|
rect.yMax = rect.yMin + m_Scale.y;
|
|
|
|
for (int i = 0; i < m_Children.Count; i++)
|
|
{
|
|
CanvasElement e = m_Children[i];
|
|
Rect childRect = e.boundingRect;
|
|
childRect.x += rect.x;
|
|
childRect.y += rect.y;
|
|
rect = UnityEditorInternal.Experimental.RectUtils.Encompass(rect, childRect);
|
|
}
|
|
|
|
if ((m_Caps & Capabilities.Floating) != 0)
|
|
{
|
|
var canvas2d = ParentCanvas();
|
|
var matrix = Matrix4x4.TRS(canvas2d.translation, Quaternion.identity, canvas2d.scale).inverse;
|
|
Vector3 topCorner = new Vector3(rect.x, rect.y, 0.0f);
|
|
topCorner = matrix.MultiplyPoint(topCorner);
|
|
|
|
Vector3 bottomCorner = new Vector3(rect.xMax, rect.yMax, 0.0f);
|
|
bottomCorner = matrix.MultiplyPoint(bottomCorner);
|
|
|
|
rect.x = topCorner.x;
|
|
rect.y = topCorner.y;
|
|
rect.width = bottomCorner.x - topCorner.x;
|
|
rect.height = bottomCorner.y - topCorner.y;
|
|
}
|
|
return rect;
|
|
}
|
|
}
|
|
|
|
public Rect canvasBoundingRect
|
|
{
|
|
get
|
|
{
|
|
Rect currentRect = boundingRect;
|
|
CanvasElement p = parent;
|
|
while (p != null)
|
|
{
|
|
if (p is Canvas2D)
|
|
break;
|
|
|
|
currentRect.x += p.boundingRect.x;
|
|
currentRect.y += p.boundingRect.y;
|
|
p = p.parent;
|
|
}
|
|
return currentRect;
|
|
}
|
|
}
|
|
|
|
public int zIndex
|
|
{
|
|
get { return m_ZIndex; }
|
|
set { m_ZIndex = value; }
|
|
}
|
|
|
|
public Texture texture
|
|
{
|
|
get { return m_Texture; }
|
|
}
|
|
|
|
public Vector3 translation
|
|
{
|
|
get { return m_Translation; }
|
|
set { m_Translation = value; }
|
|
}
|
|
|
|
public Vector3 scale
|
|
{
|
|
get { return m_Scale; }
|
|
set { m_Scale = value; }
|
|
}
|
|
|
|
public virtual bool Contains(Vector2 point)
|
|
{
|
|
return canvasBoundingRect.Contains(point);
|
|
}
|
|
|
|
public virtual bool Intersects(Rect rect)
|
|
{
|
|
if (UnityEditorInternal.Experimental.RectUtils.Contains(rect, canvasBoundingRect))
|
|
{
|
|
return true;
|
|
}
|
|
else if (canvasBoundingRect.Overlaps(rect))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public virtual void DeepInvalidate()
|
|
{
|
|
m_Dirty = true;
|
|
foreach (CanvasElement e in m_Children)
|
|
{
|
|
e.DeepInvalidate();
|
|
}
|
|
|
|
foreach (CanvasElement d in m_Dependencies)
|
|
{
|
|
d.DeepInvalidate();
|
|
}
|
|
}
|
|
|
|
public void Invalidate()
|
|
{
|
|
m_Dirty = true;
|
|
|
|
foreach (CanvasElement d in m_Dependencies)
|
|
{
|
|
d.Invalidate();
|
|
}
|
|
|
|
CanvasElement theParent = parent;
|
|
|
|
if (theParent == null || (theParent is Canvas2D))
|
|
return;
|
|
|
|
while (theParent.parent != null && !(theParent.parent is Canvas2D))
|
|
{
|
|
theParent = theParent.parent;
|
|
}
|
|
|
|
theParent.DeepInvalidate();
|
|
}
|
|
|
|
public void AddManipulator(IManipulate m)
|
|
{
|
|
m.AttachTo(this);
|
|
}
|
|
|
|
private void CreateTexture()
|
|
{
|
|
Rect textureRect = boundingRect;
|
|
textureRect.width = Mathf.Max(textureRect.width, 1.0f);
|
|
textureRect.height = Mathf.Max(textureRect.height, 1.0f);
|
|
m_Texture = new RenderTexture((int)textureRect.width, (int)textureRect.height, 0, RenderTextureFormat.ARGB32);
|
|
}
|
|
|
|
private RenderTexture m_OldActive;
|
|
|
|
public bool PrepareRender()
|
|
{
|
|
if (Event.current.type != EventType.Repaint)
|
|
return false;
|
|
|
|
if (!m_Dirty || !m_SupportsRenderToTexture)
|
|
return false;
|
|
|
|
var bounds = boundingRect;
|
|
|
|
// if null create
|
|
// if size is differnt destroy / create
|
|
if (m_Texture == null)
|
|
CreateTexture();
|
|
else if ((int)bounds.width != m_Texture.width || (int)bounds.height != m_Texture.height)
|
|
{
|
|
Object.DestroyImmediate(m_Texture);
|
|
CreateTexture();
|
|
}
|
|
|
|
m_OldActive = RenderTexture.active;
|
|
RenderTexture.active = m_Texture;
|
|
|
|
Layout();
|
|
m_Dirty = false;
|
|
return true;
|
|
}
|
|
|
|
public void EndRender(float renderTextureHeight)
|
|
{
|
|
RenderTexture.active = m_OldActive;
|
|
}
|
|
|
|
bool Collide(Vector2 p)
|
|
{
|
|
return boundingRect.Contains(p);
|
|
}
|
|
|
|
public CanvasElement[] Children()
|
|
{
|
|
return m_Children.ToArray();
|
|
}
|
|
|
|
public bool HasDependency<T>()
|
|
{
|
|
foreach (CanvasElement d in m_Dependencies)
|
|
{
|
|
if (d is T)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void AddDependency(CanvasElement e)
|
|
{
|
|
m_Dependencies.Add(e);
|
|
}
|
|
|
|
public CanvasElement[] FindChildren<T>()
|
|
{
|
|
List<CanvasElement> filtered = new List<CanvasElement>();
|
|
foreach (CanvasElement e in m_Children)
|
|
{
|
|
CanvasElement[] inner = e.FindChildren<T>();
|
|
filtered.AddRange(inner);
|
|
|
|
if (e is T)
|
|
{
|
|
filtered.Add(e);
|
|
}
|
|
}
|
|
|
|
return filtered.ToArray();
|
|
}
|
|
|
|
public virtual void DebugDraw()
|
|
{
|
|
Handles.DrawSolidRectangleWithOutline(canvasBoundingRect, new Color(1.0f, 0.0f, 0.0f, 0.2f), new Color(1.0f, 0.0f, 0.0f, 0.4f));
|
|
foreach (CanvasElement e in m_Children)
|
|
{
|
|
e.DebugDraw();
|
|
}
|
|
}
|
|
|
|
public virtual void Clear()
|
|
{
|
|
m_Texture = null;
|
|
m_Children.Clear();
|
|
}
|
|
|
|
public virtual void UpdateModel(UpdateType t)
|
|
{
|
|
foreach (CanvasElement c in m_Children)
|
|
{
|
|
c.UpdateModel(t);
|
|
}
|
|
foreach (CanvasElement e in m_Dependencies)
|
|
{
|
|
e.UpdateModel(t);
|
|
}
|
|
}
|
|
|
|
public virtual void AddChild(CanvasElement e)
|
|
{
|
|
e.parent = this;
|
|
if (!(e.parent is Canvas2D))
|
|
{
|
|
e.collapsed = collapsed;
|
|
}
|
|
m_Children.Add(e);
|
|
}
|
|
|
|
public virtual void Layout()
|
|
{
|
|
foreach (CanvasElement e in m_Children)
|
|
{
|
|
e.Layout();
|
|
}
|
|
}
|
|
|
|
public virtual void OnRenderList(List<CanvasElement> visibleList, Canvas2D parent, bool renderWidgets)
|
|
{
|
|
Rect screenRect = new Rect
|
|
{
|
|
min = parent.MouseToCanvas(parent.clientRect.min),
|
|
max = parent.MouseToCanvas(new Vector2(parent.clientRect.width, parent.clientRect.height))
|
|
};
|
|
Rect thisRect = boundingRect;
|
|
for (int i = 0; i < visibleList.Count; i++)
|
|
{
|
|
CanvasElement e = visibleList[i];
|
|
if (e.texture != null)
|
|
{
|
|
float ratioY = 1.0f;
|
|
float ratioX = 1.0f;
|
|
Rect r = new Rect(e.translation.x, e.translation.y, e.texture.width, e.texture.height);
|
|
if (r.y < screenRect.y)
|
|
{
|
|
float overlap = (screenRect.y - r.y);
|
|
r.y = screenRect.y;
|
|
r.height -= overlap;
|
|
if (r.height < 0.0f)
|
|
r.height = 0.0f;
|
|
ratioY = r.height / e.texture.height;
|
|
}
|
|
|
|
if (r.xMax > screenRect.xMax)
|
|
{
|
|
float overlap = r.xMax - screenRect.xMax;
|
|
r.width -= overlap;
|
|
if (r.width < 0.0f)
|
|
r.width = 0.0f;
|
|
ratioX = r.width / e.texture.width;
|
|
}
|
|
|
|
Graphics.DrawTexture(r, e.texture, new Rect(0, 0, ratioX, ratioY), 0, 0, 0, 0);
|
|
}
|
|
else
|
|
e.Render(thisRect, parent);
|
|
|
|
e.RenderWidgets(parent);
|
|
}
|
|
|
|
if (OnWidget != null && renderWidgets)
|
|
OnWidget(this, Event.current, parent);
|
|
}
|
|
|
|
private void RenderWidgets(Canvas2D parent)
|
|
{
|
|
if (OnWidget != null)
|
|
{
|
|
OnWidget(this, Event.current, parent);
|
|
}
|
|
|
|
foreach (CanvasElement e in m_Children)
|
|
{
|
|
e.RenderWidgets(parent);
|
|
}
|
|
}
|
|
|
|
public virtual bool DispatchEvents(Event evt, Canvas2D parent)
|
|
{
|
|
foreach (CanvasElement e in m_Children)
|
|
{
|
|
if (e.DispatchEvents(evt, parent))
|
|
return true;
|
|
}
|
|
|
|
return FireEvents(evt, parent, this);
|
|
}
|
|
|
|
public bool FireEvents(Event evt, Canvas2D parent, CanvasElement target)
|
|
{
|
|
if (parent != this && (evt.type == EventType.MouseDown))
|
|
{
|
|
if (!Contains(parent.MouseToCanvas(evt.mousePosition)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (target == null)
|
|
{
|
|
target = this;
|
|
}
|
|
|
|
bool handled = false;
|
|
if (AllEvents != null)
|
|
{
|
|
bool wasNotUsed = evt.type != EventType.Used;
|
|
|
|
AllEvents(target, evt, parent);
|
|
if (wasNotUsed && evt.type == EventType.Used)
|
|
{
|
|
parent.LogInfo("AllEvent handler on " + target);
|
|
}
|
|
}
|
|
|
|
switch (evt.type)
|
|
{
|
|
case EventType.MouseUp:
|
|
handled = MouseUp == null ? false : MouseUp(target, evt, parent);
|
|
break;
|
|
case EventType.MouseDown:
|
|
{
|
|
if (evt.clickCount < 2)
|
|
{
|
|
handled = MouseDown == null ? false : MouseDown(target, evt, parent);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
handled = DoubleClick == null ? false : DoubleClick(target, evt, parent);
|
|
break;
|
|
}
|
|
}
|
|
case EventType.MouseDrag:
|
|
handled = MouseDrag == null ? false : MouseDrag(target, evt, parent);
|
|
break;
|
|
case EventType.DragPerform:
|
|
handled = DragPerform == null ? false : DragPerform(target, evt, parent);
|
|
break;
|
|
case EventType.DragExited:
|
|
handled = DragExited == null ? false : DragExited(target, evt, parent);
|
|
break;
|
|
case EventType.DragUpdated:
|
|
handled = DragUpdated == null ? false : DragUpdated(target, evt, parent);
|
|
break;
|
|
case EventType.ScrollWheel:
|
|
handled = ScrollWheel == null ? false : ScrollWheel(target, evt, parent);
|
|
break;
|
|
case EventType.KeyDown:
|
|
handled = KeyDown == null ? false : KeyDown(target, evt, parent);
|
|
break;
|
|
case EventType.ContextClick:
|
|
handled = ContextClick == null ? false : ContextClick(target, evt, parent);
|
|
break;
|
|
case EventType.ValidateCommand:
|
|
handled = ValidateCommand == null ? false : ValidateCommand(target, evt, parent);
|
|
break;
|
|
case EventType.ExecuteCommand:
|
|
handled = ExecuteCommand == null ? false : ExecuteCommand(target, evt, parent);
|
|
break;
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
public virtual void Render(Rect parentRect, Canvas2D canvas)
|
|
{
|
|
foreach (CanvasElement e in m_Children)
|
|
{
|
|
e.Render(parentRect, canvas);
|
|
}
|
|
|
|
if (OnWidget != null)
|
|
OnWidget(this, Event.current, canvas);
|
|
}
|
|
|
|
public void AnimateScale(Vector2 from, Vector2 to)
|
|
{
|
|
var canvas = ParentCanvas();
|
|
m_Animationdata.scaleFrom = from;
|
|
m_Animationdata.scaleTo = to;
|
|
m_Animationdata.scaleTime = 0.0f;
|
|
canvas.OnLayout += OnAnimateScaleDelegate;
|
|
canvas.Invalidate();
|
|
}
|
|
|
|
private bool OnAnimateScaleDelegate(CanvasElement element, Event e, Canvas2D parent)
|
|
{
|
|
parent.Invalidate();
|
|
Invalidate();
|
|
scale = Vector2.Lerp(m_Animationdata.scaleFrom, m_Animationdata.scaleTo, m_Animationdata.scaleTime);
|
|
m_Animationdata.scaleTime += 0.01f;
|
|
if (m_Animationdata.scaleTime > 1.0f)
|
|
{
|
|
parent.OnLayout -= OnAnimateScaleDelegate;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
}
|