// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Surface
{
///
/// Base class for Visject Surface components like nodes or comments. Used to unify various logic parts across different surface elements.
///
///
[HideInEditor]
public abstract class SurfaceControl : ContainerControl
{
///
/// The mouse position in local control space. Updates by auto.
///
protected Float2 _mousePosition = Float2.Minimum;
///
/// The is selected flag for element.
///
protected bool _isSelected;
///
/// The context.
///
public readonly VisjectSurfaceContext Context;
///
/// The surface.
///
public readonly VisjectSurface Surface;
///
/// Gets a value indicating whether this control is selected.
///
public bool IsSelected
{
get => _isSelected;
internal set
{
_isSelected = value;
OnSelectionChanged();
}
}
///
/// Gets the mouse position (in local control space).
///
public Float2 MousePosition => _mousePosition;
///
/// Initializes a new instance of the class.
///
/// The context.
/// The initial width.
/// The initial height.
protected SurfaceControl(VisjectSurfaceContext context, float width, float height)
: base(0, 0, width, height)
{
ClipChildren = false;
Surface = context.Surface;
Context = context;
}
///
/// Initializes a new instance of the class.
///
/// The surface.
/// The initial bounds.
protected SurfaceControl(VisjectSurface surface, ref Rectangle bounds)
: base(bounds)
{
ClipChildren = false;
Surface = surface;
}
///
/// Determines whether this element can be selected by the mouse at the specified location.
///
/// The mouse location (in surface space).
/// true if this instance can be selected by mouse at the specified location; otherwise, false.
public abstract bool CanSelect(ref Float2 location);
///
/// Determines whether selection rectangle is intersecting with the surface control area that can be selected.
///
/// The selection rectangle (in surface space, not the control space).
/// true if the selection rectangle is intersecting with the selectable parts of the control ; otherwise, false.
public virtual bool IsSelectionIntersecting(ref Rectangle selectionRect)
{
return Bounds.Intersects(ref selectionRect);
}
///
/// Called when surface can edit state gets changed. Can be used to enable/disable UI elements that are surface data editing.
///
/// True if can edit surface data, otherwise false.
public virtual void OnSurfaceCanEditChanged(bool canEdit)
{
}
///
/// Called when editor is showing secondary context menu. Can be used to inject custom options for node logic.
///
/// The menu.
/// The show location (in control space).
public virtual void OnShowSecondaryContextMenu(FlaxEditor.GUI.ContextMenu.ContextMenu menu, Float2 location)
{
}
///
/// Called after changes
///
protected virtual void OnSelectionChanged()
{
}
///
/// Called when control gets loaded and added to surface.
///
public virtual void OnLoaded(SurfaceNodeActions action)
{
}
///
/// Called when surface gets loaded and nodes boxes are connected.
///
public virtual void OnSurfaceLoaded(SurfaceNodeActions action)
{
// Snap bounds (with ceil) when using grid snapping
if (Surface != null && Surface.GridSnappingEnabled)
{
var bounds = Bounds;
bounds.Location = Surface.SnapToGrid(bounds.Location, false);
bounds.Size = Surface.SnapToGrid(bounds.Size, true);
Bounds = bounds;
}
UpdateRectangles();
}
///
/// Called after adding the control to the surface after user spawn (eg. add comment, add new node, etc.).
///
public virtual void OnSpawned(SurfaceNodeActions action)
{
}
///
/// Called on removing the control from the surface after user delete/cut operation (eg. delete comment, cut node, etc.).
///
public virtual void OnDeleted(SurfaceNodeActions action)
{
Dispose();
}
///
/// Updates the cached rectangles on control size change.
///
protected abstract void UpdateRectangles();
///
public override void OnMouseEnter(Float2 location)
{
_mousePosition = location;
base.OnMouseEnter(location);
}
///
public override void OnMouseMove(Float2 location)
{
_mousePosition = location;
base.OnMouseMove(location);
}
///
public override void OnMouseLeave()
{
_mousePosition = Float2.Minimum;
base.OnMouseLeave();
}
///
protected override void SetScaleInternal(ref Float2 scale)
{
base.SetScaleInternal(ref scale);
UpdateRectangles();
}
///
protected override void OnSizeChanged()
{
base.OnSizeChanged();
UpdateRectangles();
}
}
}