// Copyright (c) Wojciech Figat. All rights reserved. using FlaxEngine; using FlaxEngine.GUI; namespace FlaxEditor.Surface { /// /// Visject Surface node control that cna be resized. /// /// [HideInEditor] public class ResizableSurfaceNode : SurfaceNode { private Float2 _startResizingSize; private Float2 _startResizingCornerOffset; /// /// Indicates whether the node is currently being resized. /// protected bool _isResizing; /// /// Index of the Float2 value in the node values list to store node size. /// protected int _sizeValueIndex = -1; /// /// Minimum node size. /// protected Float2 _sizeMin = new Float2(240, 160); /// /// Node resizing rectangle bounds. /// protected Rectangle _resizeButtonRect; private Float2 SizeValue { get => (Float2)Values[_sizeValueIndex]; set => SetValue(_sizeValueIndex, value, false); } /// public ResizableSurfaceNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch) : base(id, context, nodeArch, groupArch) { } /// public override bool CanSelect(ref Float2 location) { return base.CanSelect(ref location) && !_resizeButtonRect.MakeOffsetted(Location).Contains(ref location); } /// 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); } /// public override void OnValuesChanged() { base.OnValuesChanged(); var size = SizeValue; Resize(size.X, size.Y); } /// 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); } } /// public override void OnLostFocus() { if (_isResizing) EndResizing(); base.OnLostFocus(); } /// public override void OnEndMouseCapture() { if (_isResizing) EndResizing(); base.OnEndMouseCapture(); } /// 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; } /// 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); } } /// public override bool OnMouseUp(Float2 location, MouseButton button) { if (button == MouseButton.Left && _isResizing) { EndResizing(); return true; } return base.OnMouseUp(location, button); } /// 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); } } } }