You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

425 lines
13 KiB

using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;
using PositionType = UnityEngine.UIElements.Position;
namespace UnityEditor.VFX.UI
{
class LineDragger : Manipulator
{
VFXReorderableList m_Root;
VisualElement m_Line;
public LineDragger(VFXReorderableList root, VisualElement item)
{
m_Root = root;
m_Line = item;
}
protected override void RegisterCallbacksOnTarget()
{
target.RegisterCallback<MouseDownEvent>(OnMouseDown);
target.RegisterCallback<MouseUpEvent>(OnMouseUp);
}
protected override void UnregisterCallbacksFromTarget()
{
target.UnregisterCallback<MouseDownEvent>(OnMouseDown);
target.UnregisterCallback<MouseUpEvent>(OnMouseUp);
}
Vector2 startPosition;
object m_Ctx;
void Release()
{
target.UnregisterCallback<MouseMoveEvent>(OnMouseMove);
target.ReleaseMouse();
m_Ctx = null;
}
protected void OnMouseDown(MouseDownEvent evt)
{
if (evt.button == 0)
{
evt.StopPropagation();
target.CaptureMouse();
startPosition = m_Root.WorldToLocal(evt.mousePosition);
target.RegisterCallback<MouseMoveEvent>(OnMouseMove);
m_Ctx = m_Root.StartDragging(m_Line);
}
}
protected void OnMouseUp(MouseUpEvent evt)
{
Vector2 listRelativeMouse = m_Root.WorldToLocal(evt.mousePosition);
m_Root.EndDragging(m_Ctx, m_Line, listRelativeMouse.y - startPosition.y, evt.mousePosition);
evt.StopPropagation();
Release();
}
protected void OnMouseMove(MouseMoveEvent evt)
{
evt.StopPropagation();
Vector2 listRelativeMouse = m_Root.WorldToLocal(evt.mousePosition);
m_Root.ItemDragging(m_Ctx, m_Line, listRelativeMouse.y - startPosition.y, evt.mousePosition);
}
}
class LineSelecter : Manipulator
{
VFXReorderableList m_Root;
VisualElement m_Line;
public LineSelecter(VFXReorderableList root, VisualElement item)
{
m_Root = root;
m_Line = item;
}
protected override void RegisterCallbacksOnTarget()
{
target.RegisterCallback<MouseDownEvent>(OnMouseDown, TrickleDown.TrickleDown);
}
protected override void UnregisterCallbacksFromTarget()
{
target.UnregisterCallback<MouseDownEvent>(OnMouseDown, TrickleDown.TrickleDown);
}
void OnMouseDown(MouseDownEvent e)
{
m_Root.Select(m_Line);
}
}
class VFXReorderableList : VisualElement
{
int m_SelectedLine = -1;
class DraggingContext
{
public Rect[] originalPositions;
public VisualElement[] items;
public Rect myOriginalPosition;
public int draggedIndex;
}
public void Select(int index)
{
if (m_SelectedLine != -1 && m_SelectedLine < m_ListContainer.childCount)
{
m_ListContainer.ElementAt(m_SelectedLine).RemoveFromClassList("selected");
}
m_SelectedLine = index;
if (m_SelectedLine != -1 && m_SelectedLine < m_ListContainer.childCount)
{
m_ListContainer.ElementAt(m_SelectedLine).AddToClassList("selected");
m_Remove.SetEnabled(CanRemove());
}
else
{
m_Remove.SetEnabled(false);
}
}
public virtual bool CanRemove()
{
return true;
}
public void Select(VisualElement item)
{
Select(m_ListContainer.IndexOf(item));
}
public object StartDragging(VisualElement item)
{
//Fix all item so that they can be animated and we can control their positions
DraggingContext context = new DraggingContext();
context.items = m_ListContainer.Children().ToArray();
context.originalPositions = context.items.Select(t => t.layout).ToArray();
context.draggedIndex = m_ListContainer.IndexOf(item);
context.myOriginalPosition = m_ListContainer.layout;
Select(context.draggedIndex);
for (int i = 0; i < context.items.Length; ++i)
{
VisualElement child = context.items[i];
Rect rect = context.originalPositions[i];
child.style.position = PositionType.Absolute;
child.style.left = rect.x;
child.style.top = rect.y;
child.style.width = rect.width;
child.style.height = rect.height;
}
item.BringToFront();
m_ListContainer.style.width = context.myOriginalPosition.width;
m_ListContainer.style.height = context.myOriginalPosition.height;
return context;
}
public void EndDragging(object ctx, VisualElement item, float offset, Vector2 mouseWorldPosition)
{
DraggingContext context = (DraggingContext)ctx;
foreach (var child in m_ListContainer.Children())
{
child.ResetPositionProperties();
}
if (context != null)
{
int hoveredIndex = GetHoveredIndex(context, mouseWorldPosition);
m_ListContainer.Insert(hoveredIndex != -1 ? hoveredIndex : context.draggedIndex, item);
m_ListContainer.ResetPositionProperties();
if (hoveredIndex != -1)
{
ElementMoved(context.draggedIndex, hoveredIndex);
}
}
}
public void ItemDragging(object ctx, VisualElement item, float offset, Vector2 mouseWorldPosition)
{
DraggingContext context = (DraggingContext)ctx;
if (context == null)
return;
item.style.top = context.originalPositions[context.draggedIndex].y + offset;
int hoveredIndex = GetHoveredIndex(context, mouseWorldPosition);
if (hoveredIndex != -1)
{
float draggedHeight = context.originalPositions[context.draggedIndex].height;
if (hoveredIndex < context.draggedIndex)
{
for (int i = 0; i < hoveredIndex; ++i)
{
context.items[i].style.top = context.originalPositions[i].y;
}
for (int i = hoveredIndex; i < context.draggedIndex; ++i)
{
context.items[i].style.top = context.originalPositions[i].y + draggedHeight;
}
for (int i = context.draggedIndex + 1; i < context.items.Length; ++i)
{
context.items[i].style.top = context.originalPositions[i].y;
}
}
else if (hoveredIndex > context.draggedIndex)
{
for (int i = 0; i < context.draggedIndex; ++i)
{
context.items[i].style.top = context.originalPositions[i].y;
}
for (int i = hoveredIndex; i > context.draggedIndex; --i)
{
context.items[i].style.top = context.originalPositions[i].y - draggedHeight;
}
for (int i = hoveredIndex + 1; i < context.items.Length; ++i)
{
context.items[i].style.top = context.originalPositions[i].y;
}
}
}
else
{
for (int i = 0; i < context.items.Length; ++i)
{
if (i != context.draggedIndex)
context.items[i].style.top = context.originalPositions[i].y;
}
}
}
int GetHoveredIndex(DraggingContext context, Vector2 mouseWorldPosition)
{
Vector2 mousePosition = m_ListContainer.WorldToLocal(mouseWorldPosition);
int hoveredIndex = -1;
for (int i = 0; i < context.items.Length; ++i)
{
if (i != context.draggedIndex && context.originalPositions[i].Contains(mousePosition))
{
hoveredIndex = i;
break;
}
}
return hoveredIndex;
}
protected virtual void ElementMoved(int movedIndex, int targetIndex)
{
if (m_SelectedLine == movedIndex)
{
m_SelectedLine = targetIndex;
}
}
VisualElement m_ListContainer;
VisualElement m_Toolbar;
public VFXReorderableList()
{
m_ListContainer = new VisualElement() { name = "ListContainer" };
Add(m_ListContainer);
m_Toolbar = new VisualElement() { name = "Toolbar" };
var add = new VisualElement() { name = "Add" };
add.Add(new VisualElement() { name = "icon" });
add.AddManipulator(new Clickable(OnAdd));
m_Toolbar.Add(add);
m_Remove = new VisualElement() { name = "Remove" };
m_Remove.Add(new VisualElement() { name = "icon" });
m_Remove.AddManipulator(new Clickable(OnRemoveButton));
m_Toolbar.Add(m_Remove);
m_Remove.SetEnabled(false);
Add(m_Toolbar);
this.AddStyleSheetPathWithSkinVariant("VFXReorderableList");
AddToClassList("ReorderableList");
}
VisualElement m_Remove;
public void AddItem(VisualElement item)
{
m_ListContainer.Add(item);
item.AddManipulator(new LineSelecter(this, item));
if (reorderable)
{
AddDragToItem(item);
}
Select(m_ListContainer.childCount - 1);
m_Remove.SetEnabled(CanRemove());
}
void AddDragToItem(VisualElement item)
{
var draggingHandle = new VisualElement() { name = "DraggingHandle" };
draggingHandle.Add(new VisualElement() { name = "icon" });
item.Insert(0, draggingHandle);
draggingHandle.AddManipulator(new LineDragger(this, item));
}
void RemoveDragFromItem(VisualElement item)
{
if (item.childCount < 1 || item.ElementAt(0).name != "DraggingHandle")
return;
item.RemoveAt(0);
}
public bool toolbar
{
get { return m_Toolbar.parent != null; }
set
{
if (value)
{
if (m_Toolbar.parent == null)
{
Add(m_Toolbar);
}
}
else
{
if (m_Toolbar.parent != null)
{
m_Toolbar.RemoveFromHierarchy();
}
}
}
}
bool m_Reorderable = true;
public bool reorderable
{
get
{
return m_Reorderable;
}
set
{
if (m_Reorderable != value)
{
m_Reorderable = value;
foreach (var item in m_ListContainer.Children())
{
if (m_Reorderable)
{
AddDragToItem(item);
}
else
{
RemoveDragFromItem(item);
}
}
}
}
}
public void RemoveItemAt(int index)
{
m_ListContainer.RemoveAt(index);
if (m_SelectedLine >= m_ListContainer.childCount)
{
Select(m_ListContainer.childCount - 1);
}
}
public VisualElement ItemAt(int index)
{
return m_ListContainer.ElementAt(index);
}
public int itemCount
{
get { return m_ListContainer.childCount; }
}
public virtual void OnAdd()
{
}
void OnRemoveButton()
{
OnRemove(m_SelectedLine);
}
public virtual void OnRemove(int index)
{
}
}
}