mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-04-19 13:59:22 -04:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
345 lines
7.7 KiB
C#
345 lines
7.7 KiB
C#
namespace Editor.GraphicsItems;
|
|
|
|
/// <summary>
|
|
/// Anatomy of an EditableCurve: https://files.facepunch.com/garry/72bd3a5f-c9e4-40fe-8748-05e782d3a230.png
|
|
/// </summary>
|
|
public partial class EditableCurve : GraphicsItem
|
|
{
|
|
public List<Handle> Handles { get; } = new();
|
|
public Vector2 TimeRange => _curve.TimeRange;
|
|
public Vector2 ValueRange => _curve.ValueRange;
|
|
public Color CurveColor { get; set; } = Theme.Green;
|
|
public Color SelectionColor { get; set; } = Color.White;
|
|
public float CurveThickness { get; set; } = 1.0f;
|
|
public float HandleDistance { get; set; } = 50.0f;
|
|
|
|
public bool IsPartOfRange { get; set; }
|
|
public bool CanEditTimeRange { get; set; } = true;
|
|
public bool CanEditValueRange { get; set; } = true;
|
|
|
|
public Vector4 Viewport { get; set; } = Vector4.Zero;
|
|
public Vector2 ViewportRangeX => new Vector2( Viewport.x, Viewport.z );
|
|
public Vector2 ViewportRangeY => new Vector2( Viewport.y, Viewport.w );
|
|
|
|
|
|
CurveEditor editor;
|
|
|
|
Curve _curve;
|
|
public Curve Value
|
|
{
|
|
get { return _curve; }
|
|
set
|
|
{
|
|
_curve = value;
|
|
_curve.Fix();
|
|
|
|
FitViewportToCurve();
|
|
DeleteAllHandles();
|
|
|
|
foreach ( var k in _curve.Frames )
|
|
{
|
|
var handle = new Handle( this, k );
|
|
Handles.Add( handle );
|
|
}
|
|
editor?.UpdateBackgroundFromCurve( this );
|
|
|
|
Update();
|
|
}
|
|
}
|
|
|
|
public EditableCurve( CurveEditor parent ) : base( null )
|
|
{
|
|
editor = parent;
|
|
HoverEvents = true;
|
|
Cursor = CursorShape.DragCopy;
|
|
Clip = true;
|
|
//ClipChildren = true;
|
|
}
|
|
|
|
protected override void OnPaint()
|
|
{
|
|
PaintCurve();
|
|
PaintHandleExtras();
|
|
|
|
base.OnPaint();
|
|
}
|
|
|
|
void PaintCurve()
|
|
{
|
|
if ( Handles.Count == 0 )
|
|
return;
|
|
|
|
float alpha = 0.8f;
|
|
|
|
if ( IsPartOfRange ) alpha *= 0.5f;
|
|
if ( !Hovered ) alpha *= 0.5f;
|
|
|
|
Paint.SetPen( CurveColor.WithAlpha( alpha ), CurveThickness, PenStyle.Solid );
|
|
|
|
var viewportCurve = GetViewportAdjustedCurve();
|
|
viewportCurve.DrawLine( LocalRect, 3.0f );
|
|
}
|
|
|
|
void PaintHandleExtras()
|
|
{
|
|
foreach ( var handle in Handles )
|
|
{
|
|
Paint.ResetTransform();
|
|
Paint.Translate( Position );
|
|
Paint.Translate( handle.Position );
|
|
|
|
handle.PaintExtras();
|
|
}
|
|
Paint.ResetTransform();
|
|
}
|
|
|
|
public void DeleteAllHandles()
|
|
{
|
|
foreach ( var handle in Handles )
|
|
{
|
|
handle?.Destroy();
|
|
}
|
|
|
|
Handles.Clear();
|
|
UpdateTooltip();
|
|
}
|
|
|
|
public void OnEdited()
|
|
{
|
|
SaveCurve();
|
|
BindSystem.Flush();
|
|
}
|
|
|
|
public void OnHandleMoved()
|
|
{
|
|
OnEdited();
|
|
UpdateTooltip();
|
|
}
|
|
|
|
public void UpdateZoomRangeX( Vector2 range )
|
|
{
|
|
// Zoom the viewport to the new range
|
|
Viewport = new Vector4(
|
|
range.x, Viewport.y,
|
|
range.y, Viewport.w
|
|
);
|
|
}
|
|
|
|
public void UpdateZoomRangeY( Vector2 range )
|
|
{
|
|
// Zoom the viewport to the new range
|
|
Viewport = new Vector4(
|
|
Viewport.x, range.x,
|
|
Viewport.z, range.y
|
|
);
|
|
}
|
|
|
|
public void FitViewportToCurve()
|
|
{
|
|
Viewport = new Vector4(
|
|
TimeRange.x, ValueRange.x,
|
|
TimeRange.y, ValueRange.y
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write from editor to the curve (_value)
|
|
/// </summary>
|
|
public void SaveCurve()
|
|
{
|
|
if ( Value.Length > 0 )
|
|
{
|
|
var timeRange = new Vector2( float.MaxValue, float.MinValue );
|
|
var valueRange = new Vector2( float.MaxValue, float.MinValue );
|
|
|
|
foreach ( var frame in Value.Frames )
|
|
{
|
|
var time = frame.Time.Remap( 0, 1, TimeRange.x, TimeRange.y, false );
|
|
var value = frame.Value.Remap( 0, 1, ValueRange.x, ValueRange.y, false );
|
|
timeRange = timeRange.WithX( System.MathF.Min( timeRange.x, time ) )
|
|
.WithY( System.MathF.Max( timeRange.y, time ) );
|
|
valueRange = valueRange.WithX( System.MathF.Min( valueRange.x, value ) )
|
|
.WithY( System.MathF.Max( valueRange.y, value ) );
|
|
}
|
|
|
|
if ( !CanEditTimeRange || IsPartOfRange )
|
|
{
|
|
timeRange = TimeRange;
|
|
}
|
|
|
|
if ( !CanEditValueRange || IsPartOfRange )
|
|
{
|
|
valueRange = ValueRange;
|
|
}
|
|
|
|
var newCurve = Value.WithFrames( new List<Curve.Frame>() );
|
|
var timeRangeLength = timeRange.y - timeRange.x;
|
|
var valueRangeLength = valueRange.y - valueRange.x;
|
|
|
|
foreach ( var handle in Handles.OrderBy( x => x.Position.x ) )
|
|
{
|
|
newCurve.AddPoint( handle.GetKeyFrame() );
|
|
|
|
if ( timeRangeLength != 0 )
|
|
{
|
|
handle.Frame.Time = handle.Frame.Time.Remap( 0, 1, MathF.Min( TimeRange.x, TimeRange.y ), MathF.Max( TimeRange.x, TimeRange.y ), false );
|
|
handle.Frame.Time = handle.Frame.Time.Remap( timeRange.x, timeRange.y, 0, 1, false );
|
|
}
|
|
|
|
if ( valueRangeLength != 0 )
|
|
{
|
|
handle.Frame.Value = handle.Frame.Value.Remap( 0, 1, MathF.Min( ValueRange.x, ValueRange.y ), MathF.Max( ValueRange.x, ValueRange.y ), false );
|
|
handle.Frame.Value = handle.Frame.Value.Remap( valueRange.x, valueRange.y, 0, 1, false );
|
|
}
|
|
}
|
|
if ( timeRangeLength != 0 )
|
|
{
|
|
newCurve.UpdateTimeRange( timeRange, true );
|
|
}
|
|
if ( valueRangeLength != 0 )
|
|
{
|
|
newCurve.UpdateValueRange( valueRange, true );
|
|
}
|
|
|
|
_curve = newCurve;
|
|
}
|
|
|
|
editor?.UpdateBackgroundFromCurve( this );
|
|
Update();
|
|
}
|
|
|
|
internal Curve GetViewportAdjustedCurve()
|
|
{
|
|
var viewportCurve = Value.WithFrames( Value.Frames );
|
|
viewportCurve.UpdateTimeRange( ViewportRangeX, true );
|
|
viewportCurve.UpdateValueRange( ViewportRangeY, true );
|
|
return viewportCurve;
|
|
}
|
|
|
|
internal void Delete( Handle editableCurveHandle )
|
|
{
|
|
// Keep at least one around
|
|
if ( Handles.Count == 1 )
|
|
return;
|
|
|
|
if ( Handles.Remove( editableCurveHandle ) )
|
|
{
|
|
editableCurveHandle.Destroy();
|
|
UpdateTooltip();
|
|
SaveCurve();
|
|
}
|
|
|
|
}
|
|
|
|
internal void FocusedHandleKeyPress( KeyEvent e )
|
|
{
|
|
var selectedHandles = Handles.Where( x => x.Selected ).ToArray();
|
|
|
|
if ( e.Key == KeyCode.Delete )
|
|
{
|
|
foreach ( var selected in selectedHandles )
|
|
{
|
|
Delete( selected );
|
|
}
|
|
}
|
|
}
|
|
|
|
public void UpdateTimeRange( Vector2 range, bool retainTimes, bool fitViewport = false )
|
|
{
|
|
var oldViewport = Viewport;
|
|
var c = Value;
|
|
c.UpdateTimeRange( range, retainTimes );
|
|
Value = c;
|
|
if ( !fitViewport )
|
|
{
|
|
Viewport = oldViewport;
|
|
}
|
|
}
|
|
|
|
public void UpdateValueRange( Vector2 range, bool retainValues, bool fitViewport = false )
|
|
{
|
|
var oldViewport = Viewport;
|
|
var c = Value;
|
|
c.UpdateValueRange( range, retainValues );
|
|
Value = c;
|
|
if ( !fitViewport )
|
|
{
|
|
Viewport = oldViewport;
|
|
}
|
|
}
|
|
|
|
public override bool Contains( Vector2 localPos )
|
|
{
|
|
var x = localPos.x / Size.x;
|
|
|
|
var curve = GetViewportAdjustedCurve();
|
|
|
|
var f = curve.Evaluate( ViewportRangeX.x.LerpTo( ViewportRangeX.y, x ) );
|
|
f = f.LerpInverse( ViewportRangeY.y, ViewportRangeY.x );
|
|
f = f * Size.y;
|
|
|
|
var distance = System.MathF.Abs( f - localPos.y );
|
|
return distance < 10.0f;
|
|
}
|
|
|
|
protected override void OnMousePressed( GraphicsMouseEvent e )
|
|
{
|
|
base.OnMousePressed( e );
|
|
|
|
if ( e.LeftMouseButton )
|
|
{
|
|
var curve = GetViewportAdjustedCurve();
|
|
|
|
var x = e.LocalPosition.x / Size.x;
|
|
x = x.Remap( 0, 1, ViewportRangeX.x, ViewportRangeX.y, false );
|
|
x = x.Remap( TimeRange.x, TimeRange.y, 0, 1, false );
|
|
|
|
var v = Value.EvaluateDelta( x );
|
|
var k = new Curve.Frame( x, v );
|
|
|
|
var handle = new Handle( this, k );
|
|
Handles.Add( handle );
|
|
SaveCurve();
|
|
}
|
|
}
|
|
|
|
HandlePopup ValuePopup;
|
|
Handle popupTarget;
|
|
|
|
public virtual void HandleSelectionChanged()
|
|
{
|
|
UpdateTooltip();
|
|
}
|
|
|
|
internal void UpdateHandlePositions()
|
|
{
|
|
Update();
|
|
foreach ( var handle in Handles )
|
|
{
|
|
handle.UpdatePositionFromValue();
|
|
}
|
|
}
|
|
|
|
public void UpdateTooltip()
|
|
{
|
|
if ( !GraphicsView.IsValid() )
|
|
return;
|
|
|
|
popupTarget = Handles.Where( x => x.Selected || x.Hovered ).OrderBy( x => !x.Hovered ).FirstOrDefault();
|
|
|
|
if ( popupTarget.IsValid() && GraphicsView.IsValid() )
|
|
{
|
|
ValuePopup ??= new HandlePopup( GraphicsView );
|
|
ValuePopup.UpdateFrom( popupTarget );
|
|
ValuePopup.ConstrainTo( GraphicsView.LocalRect.Shrink( 8, 2 ) );
|
|
ValuePopup.Visible = true;
|
|
}
|
|
else
|
|
{
|
|
ValuePopup?.Destroy();
|
|
ValuePopup = null;
|
|
}
|
|
}
|
|
}
|
|
//}
|