Merge branch 'reordering' of https://github.com/Menotdan/FlaxEngine into Menotdan-reordering

#2670
This commit is contained in:
Menotdan
2024-06-10 23:13:50 +02:00
committed by Wojtek Figat
parent 7f6805aac6
commit 892ab47b7a
4 changed files with 449 additions and 4 deletions

View File

@@ -111,6 +111,11 @@ namespace FlaxEditor.CustomEditors
/// </summary>
public PropertyNameLabel LinkedLabel;
/// <summary>
/// Gets the layout for this editor. Used to calculate bounds.
/// </summary>
public LayoutElementsContainer Layout => _layout;
internal virtual void Initialize(CustomEditorPresenter presenter, LayoutElementsContainer layout, ValueContainer values)
{
_layout = layout;

View File

@@ -38,6 +38,9 @@ namespace FlaxEditor.CustomEditors.Editors
/// </summary>
public readonly int Index;
private Rectangle _arrangeButtonRect;
private bool _arrangeButtonInUse;
/// <summary>
/// Initializes a new instance of the <see cref="CollectionItemLabel"/> class.
/// </summary>
@@ -50,6 +53,12 @@ namespace FlaxEditor.CustomEditors.Editors
Index = index;
SetupContextMenu += OnSetupContextMenu;
_arrangeButtonRect = new Rectangle(2, 3, 12, 12);
// Extend margin of the label to support a dragging handle.
Margin m = Margin;
m.Left += 16;
Margin = m;
}
private void OnSetupContextMenu(PropertyNameLabel label, ContextMenu menu, CustomEditor linkedEditor)
@@ -71,6 +80,107 @@ namespace FlaxEditor.CustomEditors.Editors
b.Enabled = !Editor._readOnly;
}
/// <inheritdoc />
public override void OnEndMouseCapture()
{
base.OnEndMouseCapture();
_arrangeButtonInUse = false;
}
/// <inheritdoc />
public override void Draw()
{
base.Draw();
var style = FlaxEngine.GUI.Style.Current;
var mousePosition = PointFromScreen(Input.MouseScreenPosition);
var dragBarColor = _arrangeButtonRect.Contains(mousePosition) ? style.Foreground : style.ForegroundGrey;
Render2D.DrawSprite(FlaxEditor.Editor.Instance.Icons.DragBar12, _arrangeButtonRect, _arrangeButtonInUse ? Color.Orange : dragBarColor);
if (_arrangeButtonInUse && ArrangeAreaCheck(out _, out var arrangeTargetRect))
{
Render2D.FillRectangle(arrangeTargetRect, style.Selection);
}
}
private bool ArrangeAreaCheck(out int index, out Rectangle rect)
{
var child = Editor.ChildrenEditors[0];
var container = child.Layout.ContainerControl;
var mousePosition = container.PointFromScreen(Input.MouseScreenPosition);
var barSidesExtend = 20.0f;
var barHeight = 5.0f;
var barCheckAreaHeight = 40.0f;
var pos = mousePosition.Y + barCheckAreaHeight * 0.5f;
for (int i = 0; i < container.Children.Count / 2; i++)
{
var containerChild = container.Children[i * 2]; // times 2 to skip the value editor
if (Mathf.IsInRange(pos, containerChild.Top, containerChild.Top + barCheckAreaHeight) || (i == 0 && pos < containerChild.Top))
{
index = i;
var p1 = containerChild.UpperLeft;
rect = new Rectangle(PointFromParent(p1) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
return true;
}
}
var p2 = container.Children[((container.Children.Count / 2) - 1) * 2].BottomLeft;
if (pos > p2.Y)
{
index = (container.Children.Count / 2) - 1;
rect = new Rectangle(PointFromParent(p2) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
return true;
}
index = -1;
rect = Rectangle.Empty;
return false;
}
/// <inheritdoc />
public override bool OnMouseDown(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _arrangeButtonRect.Contains(ref location))
{
_arrangeButtonInUse = true;
Focus();
StartMouseCapture();
return true;
}
return base.OnMouseDown(location, button);
}
/// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _arrangeButtonInUse)
{
_arrangeButtonInUse = false;
EndMouseCapture();
if (ArrangeAreaCheck(out var index, out _))
{
Editor.Shift(Index, index);
}
}
return base.OnMouseUp(location, button);
}
/// <inheritdoc />
public override void OnLostFocus()
{
if (_arrangeButtonInUse)
{
_arrangeButtonInUse = false;
EndMouseCapture();
}
base.OnLostFocus();
}
private void OnMoveUpClicked()
{
Editor.Move(Index, Index - 1);
@@ -106,6 +216,9 @@ namespace FlaxEditor.CustomEditors.Editors
private bool _canReorder = true;
private Rectangle _arrangeButtonRect;
private bool _arrangeButtonInUse;
public void Setup(CollectionEditor editor, int index, bool canReorder = true)
{
HeaderHeight = 18;
@@ -123,10 +236,92 @@ namespace FlaxEditor.CustomEditors.Editors
MouseButtonRightClicked += OnMouseButtonRightClicked;
if (_canReorder)
{
// TODO: Drag drop
HeaderTextMargin = new Margin(18, 0, 0, 0);
_arrangeButtonRect = new Rectangle(16, 3, 12, 12);
}
}
private bool ArrangeAreaCheck(out int index, out Rectangle rect)
{
var container = Parent;
var mousePosition = container.PointFromScreen(Input.MouseScreenPosition);
var barSidesExtend = 20.0f;
var barHeight = 5.0f;
var barCheckAreaHeight = 40.0f;
var pos = mousePosition.Y + barCheckAreaHeight * 0.5f;
for (int i = 0; i < (container.Children.Count + 1) / 2; i++) // Add 1 to pretend there is a spacer at the end.
{
var containerChild = container.Children[i * 2]; // times 2 to skip the value editor
if (Mathf.IsInRange(pos, containerChild.Top, containerChild.Top + barCheckAreaHeight) || (i == 0 && pos < containerChild.Top))
{
index = i;
var p1 = containerChild.UpperLeft;
rect = new Rectangle(PointFromParent(p1) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
return true;
}
}
var p2 = container.Children[container.Children.Count - 1].BottomLeft;
if (pos > p2.Y)
{
index = ((container.Children.Count + 1) / 2) - 1;
rect = new Rectangle(PointFromParent(p2) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
return true;
}
index = -1;
rect = Rectangle.Empty;
return false;
}
public override void Draw()
{
base.Draw();
if (_canReorder)
{
var style = FlaxEngine.GUI.Style.Current;
var mousePosition = PointFromScreen(Input.MouseScreenPosition);
var dragBarColor = _arrangeButtonRect.Contains(mousePosition) ? style.Foreground : style.ForegroundGrey;
Render2D.DrawSprite(FlaxEditor.Editor.Instance.Icons.DragBar12, _arrangeButtonRect, _arrangeButtonInUse ? Color.Orange : dragBarColor);
if (_arrangeButtonInUse && ArrangeAreaCheck(out _, out var arrangeTargetRect))
{
Render2D.FillRectangle(arrangeTargetRect, style.Selection);
}
}
}
/// <inheritdoc />
public override bool OnMouseDown(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _arrangeButtonRect.Contains(ref location))
{
_arrangeButtonInUse = true;
Focus();
StartMouseCapture();
return true;
}
return base.OnMouseDown(location, button);
}
/// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _arrangeButtonInUse)
{
_arrangeButtonInUse = false;
EndMouseCapture();
if (ArrangeAreaCheck(out var index, out _))
{
Editor.Shift(Index, index);
}
}
return base.OnMouseUp(location, button);
}
private void OnMouseButtonRightClicked(DropPanel panel, Float2 location)
{
if (LinkedEditor == null)
@@ -324,7 +519,6 @@ namespace FlaxEditor.CustomEditors.Editors
(elementType.GetProperties().Length == 1 && elementType.GetFields().Length == 0) ||
elementType.Equals(new ScriptType(typeof(JsonAsset))) ||
elementType.Equals(new ScriptType(typeof(SettingsBase)));
for (int i = 0; i < size; i++)
{
// Apply spacing
@@ -440,6 +634,39 @@ namespace FlaxEditor.CustomEditors.Editors
SetValue(cloned);
}
/// <summary>
/// Shifts the specified item at the given index and moves it through the list to the other item. It supports undo.
/// </summary>
/// <param name="srcIndex">Index of the source item.</param>
/// <param name="dstIndex">Index of the destination to move to.</param>
private void Shift(int srcIndex, int dstIndex)
{
if (IsSetBlocked)
return;
var cloned = CloneValues();
if (dstIndex > srcIndex)
{
for (int i = srcIndex; i < dstIndex; i++)
{
var tmp = cloned[i + 1];
cloned[i + 1] = cloned[i];
cloned[i] = tmp;
}
}
else
{
for (int i = srcIndex; i > dstIndex; i--)
{
var tmp = cloned[i - 1];
cloned[i - 1] = cloned[i];
cloned[i] = tmp;
}
}
SetValue(cloned);
}
/// <summary>
/// Removes the item at the specified index. It supports undo.
/// </summary>

View File

@@ -35,6 +35,12 @@ namespace FlaxEditor.Surface
return RootContext.GetParameter(name);
}
/// <inheritdoc />
public void OnParamReordered()
{
MarkAsEdited();
}
/// <inheritdoc />
public void OnParamCreated(SurfaceParameter param)
{

View File

@@ -350,6 +350,213 @@ namespace FlaxEditor.Surface
}
}
sealed class ReorderParamAction : IUndoAction
{
/// <summary>
/// The window reference.
/// </summary>
public IVisjectSurfaceWindow Window;
/// <summary>
/// The parameters editor for this action.
/// </summary>
public ParametersEditor Editor;
/// <summary>
/// The old index the parameter was at.
/// </summary>
public int OldIndex;
/// <summary>
/// The new index the parameter will be at.
/// </summary>
public int NewIndex;
/// <inheritdoc />
public string ActionString => "Reorder Parameter";
/// <inheritdoc />
public void Dispose()
{
Window = null;
Editor = null;
}
public void Swap(int oldIdx, int newIdx)
{
if (oldIdx == newIdx)
return; // ?
var parameters = Window.VisjectSurface.Parameters;
if (newIdx > oldIdx)
{
for (int i = oldIdx; i < newIdx; i++)
{
SurfaceParameter old = parameters[i + 1];
parameters[i + 1] = parameters[i];
parameters[i] = old;
}
}
else
{
for (int i = oldIdx; i > newIdx; i--)
{
SurfaceParameter old = parameters[i - 1];
parameters[i - 1] = parameters[i];
parameters[i] = old;
}
}
}
/// <inheritdoc />
public void Do()
{
Swap(OldIndex, NewIndex);
Window.VisjectSurface.OnParamReordered();
}
/// <inheritdoc />
public void Undo()
{
Swap(NewIndex, OldIndex);
Window.VisjectSurface.OnParamReordered();
}
}
/// <summary>
/// Custom draggable property name label that handles reordering visject parameters.
/// </summary>
/// <seealso cref="FlaxEditor.CustomEditors.GUI.DraggablePropertyNameLabel" />
[HideInEditor]
public class ParameterPropertyNameLabel : DraggablePropertyNameLabel
{
private ParametersEditor _editor;
private IVisjectSurfaceWindow _window;
private Rectangle _arrangeButtonRect;
private bool _arrangeButtonInUse;
/// <inheritdoc />
public ParameterPropertyNameLabel(string name, ParametersEditor editor)
: base(name)
{
_editor = editor;
_window = _editor.Values[0] as IVisjectSurfaceWindow;
_arrangeButtonRect = new Rectangle(2, 3, 12, 12);
// Extend margin of the label to support a dragging handle
Margin m = Margin;
m.Left += 16;
Margin = m;
}
private bool ArrangeAreaCheck(out int index, out Rectangle rect)
{
var child = _editor.ChildrenEditors[0];
var container = child.Layout.ContainerControl;
var mousePosition = container.PointFromScreen(Input.MouseScreenPosition);
var barSidesExtend = 20.0f;
var barHeight = 5.0f;
var barCheckAreaHeight = 40.0f;
var pos = mousePosition.Y + barCheckAreaHeight * 0.5f;
for (int i = 0; i < container.Children.Count / 2; i++)
{
var containerChild = container.Children[i * 2]; // times 2 to skip the value editor
if (Mathf.IsInRange(pos, containerChild.Top, containerChild.Top + barCheckAreaHeight) || (i == 0 && pos < containerChild.Top))
{
index = i;
var p1 = containerChild.UpperLeft;
rect = new Rectangle(PointFromParent(p1) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
return true;
}
}
var p2 = container.Children[((container.Children.Count / 2) - 1) * 2].BottomLeft;
if (pos > p2.Y)
{
index = (container.Children.Count / 2) - 1;
rect = new Rectangle(PointFromParent(p2) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
return true;
}
index = -1;
rect = Rectangle.Empty;
return false;
}
/// <inheritdoc />
public override void Draw()
{
base.Draw();
var style = Style.Current;
var mousePosition = PointFromScreen(Input.MouseScreenPosition);
var dragBarColor = _arrangeButtonRect.Contains(mousePosition) ? style.Foreground : style.ForegroundGrey;
Render2D.DrawSprite(Editor.Instance.Icons.DragBar12, _arrangeButtonRect, _arrangeButtonInUse ? Color.Orange : dragBarColor);
if (_arrangeButtonInUse && ArrangeAreaCheck(out _, out var arrangeTargetRect))
{
Render2D.FillRectangle(arrangeTargetRect, style.Selection);
}
}
/// <inheritdoc />
public override bool OnMouseDown(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _arrangeButtonRect.Contains(ref location))
{
_arrangeButtonInUse = true;
Focus();
StartMouseCapture();
return true;
}
return base.OnMouseDown(location, button);
}
/// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _arrangeButtonInUse)
{
_arrangeButtonInUse = false;
EndMouseCapture();
ArrangeAreaCheck(out var index, out _);
var action = new ReorderParamAction
{
OldIndex = (int)Tag,
NewIndex = index,
Window = _window,
Editor = _editor
};
action.Do();
_window.Undo.AddAction(action);
}
return base.OnMouseUp(location, button);
}
/// <inheritdoc />
public override void OnLostFocus()
{
if (_arrangeButtonInUse)
{
_arrangeButtonInUse = false;
EndMouseCapture();
}
base.OnLostFocus();
}
/// <inheritdoc />
protected override void OnSizeChanged()
{
base.OnSizeChanged();
// Center the drag button vertically
_arrangeButtonRect = new Rectangle(2, Mathf.Ceil((Height - 12) * 0.5f) + 1, 12, 12);
}
}
/// <summary>
/// Custom editor for editing Visject Surface parameters collection.
/// </summary>
@@ -431,10 +638,10 @@ namespace FlaxEditor.Surface
attributes
);
var propertyLabel = new DraggablePropertyNameLabel(name)
var propertyLabel = new ParameterPropertyNameLabel(name, this)
{
Tag = pIndex,
Drag = OnDragParameter
Drag = OnDragParameter,
};
if (!p.IsPublic)
propertyLabel.TextColor = propertyLabel.TextColor.RGBMultiplied(0.7f);