Files
FlaxEngine/Source/Editor/Surface/ResizableSurfaceNode.cs

183 lines
5.3 KiB
C#

// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Surface
{
/// <summary>
/// Visject Surface node control that cna be resized.
/// </summary>
/// <seealso cref="SurfaceNode" />
[HideInEditor]
public class ResizableSurfaceNode : SurfaceNode
{
private Float2 _startResizingSize;
private Float2 _startResizingCornerOffset;
/// <summary>
/// Indicates whether the node is currently being resized.
/// </summary>
protected bool _isResizing;
/// <summary>
/// Index of the Float2 value in the node values list to store node size.
/// </summary>
protected int _sizeValueIndex = -1;
/// <summary>
/// Minimum node size.
/// </summary>
protected Float2 _sizeMin = new Float2(240, 160);
/// <summary>
/// Node resizing rectangle bounds.
/// </summary>
protected Rectangle _resizeButtonRect;
private Float2 SizeValue
{
get => (Float2)Values[_sizeValueIndex];
set => SetValue(_sizeValueIndex, value, false);
}
/// <inheritdoc />
public ResizableSurfaceNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
: base(id, context, nodeArch, groupArch)
{
}
/// <inheritdoc />
public override bool CanSelect(ref Float2 location)
{
return base.CanSelect(ref location) && !_resizeButtonRect.MakeOffsetted(Location).Contains(ref location);
}
/// <inheritdoc />
public override void OnSurfaceLoaded(SurfaceNodeActions action)
{
// Reapply the curve node size
var size = SizeValue;
if (Surface != null && Surface.GridSnappingEnabled)
size = Surface.SnapToGrid(size, true);
Resize(size.X, size.Y);
base.OnSurfaceLoaded(action);
}
/// <inheritdoc />
public override void OnValuesChanged()
{
base.OnValuesChanged();
var size = SizeValue;
Resize(size.X, size.Y);
}
/// <inheritdoc />
public override void Draw()
{
base.Draw();
if (Surface.CanEdit)
{
var style = Style.Current;
if (_isResizing)
{
Render2D.FillRectangle(_resizeButtonRect, style.Selection);
Render2D.DrawRectangle(_resizeButtonRect, style.SelectionBorder);
}
Render2D.DrawSprite(style.Scale, _resizeButtonRect, _resizeButtonRect.Contains(_mousePosition) ? style.Foreground : style.ForegroundGrey);
}
}
/// <inheritdoc />
public override void OnLostFocus()
{
if (_isResizing)
EndResizing();
base.OnLostFocus();
}
/// <inheritdoc />
public override void OnEndMouseCapture()
{
if (_isResizing)
EndResizing();
base.OnEndMouseCapture();
}
/// <inheritdoc />
public override bool OnMouseDown(Float2 location, MouseButton button)
{
if (base.OnMouseDown(location, button))
return true;
if (button == MouseButton.Left && _resizeButtonRect.Contains(ref location) && Surface.CanEdit)
{
// Start resizing
_isResizing = true;
_startResizingSize = Size;
_startResizingCornerOffset = Size - location;
StartMouseCapture();
Cursor = CursorType.SizeNWSE;
return true;
}
return false;
}
/// <inheritdoc />
public override void OnMouseMove(Float2 location)
{
if (_isResizing)
{
var emptySize = CalculateNodeSize(0, 0);
var size = Float2.Max(location - emptySize + _startResizingCornerOffset, _sizeMin);
Resize(size.X, size.Y);
}
else
{
base.OnMouseMove(location);
}
}
/// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _isResizing)
{
EndResizing();
return true;
}
return base.OnMouseUp(location, button);
}
/// <inheritdoc />
protected override void UpdateRectangles()
{
base.UpdateRectangles();
const float buttonMargin = Constants.NodeCloseButtonMargin;
const float buttonSize = Constants.NodeCloseButtonSize;
_resizeButtonRect = new Rectangle(_closeButtonRect.Left, Height - buttonSize - buttonMargin - 4, buttonSize, buttonSize);
}
private void EndResizing()
{
Cursor = CursorType.Default;
EndMouseCapture();
_isResizing = false;
if (_startResizingSize != Size)
{
var emptySize = CalculateNodeSize(0, 0);
SizeValue = Size - emptySize;
Surface.MarkAsEdited(false);
}
}
}
}