Editor/Tileset/TilesetTools/LayerControl/TilesetLayerControl.cs
using Editor;
using Sandbox;
using System.Collections.Generic;
using System.Linq;
namespace SpriteTools.TilesetTool;
public class TilesetLayerControl : Widget
{
TilesetLayerListControl ParentList;
TilesetComponent.Layer Layer;
LabelTextEntry labelText;
Drag dragData;
bool draggingAbove = false;
bool draggingBelow = false;
internal Widget icoCollisionLayer;
public TilesetLayerControl ( TilesetLayerListControl list, TilesetComponent.Layer layer )
{
ParentList = list;
Layer = layer;
VerticalSizeMode = SizeMode.Flexible;
StatusTip = $"Select Layer \"{Layer.Name}\"";
Cursor = TilesetTool.Active is not null ? CursorShape.Finger : CursorShape.None;
Layout = Layout.Row();
Layout.Margin = 4;
Layout.Spacing = 4;
var serializedObject = Layer.GetSerialized();
serializedObject.TryGetProperty( nameof( TilesetComponent.Layer.Name ), out var name );
labelText = new LabelTextEntry( name );
labelText.IsItalic = Layer.IsLocked;
labelText.IsHidden = !Layer.IsVisible;
Layout.Add( labelText );
icoCollisionLayer = new Widget( this )
{
FixedSize = new Vector2( 16, 16 ),
OnPaintOverride = () =>
{
Paint.SetPen( Color.Transparent );
Paint.SetBrush( Pixmap.FromTexture( Texture.LoadFromFileSystem( "images/collision-bounce.png", Editor.FileSystem.Mounted ) ) );
Paint.Scale( 0.5f, 0.5f );
Paint.DrawRect( LocalRect );
Paint.Scale( 1, 1 );
return true;
},
ToolTip = "Collision Layer",
Visible = false
};
Layout.Add( icoCollisionLayer );
var btnVisible = new IconButton( Layer.IsVisible ? "visibility" : "visibility_off" );
btnVisible.ToolTip = "Toggle Visibility";
btnVisible.StatusTip = "Toggle Visibility of Layer " + Layer.Name;
btnVisible.OnClick += () =>
{
Layer.IsVisible = !Layer.IsVisible;
btnVisible.Icon = Layer.IsVisible ? "visibility" : "visibility_off";
labelText.IsHidden = !Layer.IsVisible;
};
Layout.Add( btnVisible );
var btnLock = new IconButton( Layer.IsLocked ? "lock" : "lock_open" );
btnLock.ToolTip = "Lock Layer";
btnLock.StatusTip = "Lock Layer " + Layer.Name;
btnLock.OnClick += () =>
{
Layer.IsLocked = !Layer.IsLocked;
btnLock.Icon = Layer.IsLocked ? "lock" : "lock_open";
labelText.IsItalic = Layer.IsLocked;
};
Layout.Add( btnLock );
IsDraggable = true;
AcceptDrops = true;
}
protected override void OnPaint ()
{
if ( dragData?.IsValid ?? false )
{
Paint.SetBrushAndPen( Theme.WindowBackground.WithAlpha( 0.5f ) );
Paint.DrawRect( LocalRect, 4 );
}
else if ( TilesetTool.Active?.SelectedLayer == Layer )
{
Paint.SetBrushAndPen( Theme.Highlight.Darken( 0.5f ) );
Paint.DrawRect( LocalRect, 4 );
}
else if ( IsUnderMouse && TilesetTool.Active is not null )
{
Paint.SetBrushAndPen( Theme.Text.WithAlpha( 0.1f ) );
Paint.DrawRect( LocalRect, 4 );
}
if ( draggingAbove )
{
Paint.SetPen( Theme.Highlight, 2f, PenStyle.Dot );
Paint.DrawLine( LocalRect.TopLeft, LocalRect.TopRight );
draggingAbove = false;
}
else if ( draggingBelow )
{
Paint.SetPen( Theme.Highlight, 2f, PenStyle.Dot );
Paint.DrawLine( LocalRect.BottomLeft, LocalRect.BottomRight );
draggingBelow = false;
}
}
void SetAsCollisionLayer ()
{
var list = ParentList.SerializedProperty.GetValue<List<TilesetComponent.Layer>>();
foreach ( var layer in list )
{
layer.IsCollisionLayer = false;
}
Layer.IsCollisionLayer = true;
foreach ( var layerControl in ParentList.LayerControls )
{
layerControl.icoCollisionLayer.Visible = layerControl.Layer.IsCollisionLayer;
}
if ( Layer.TilesetComponent.IsValid() )
{
Layer.TilesetComponent.IsDirty = true;
}
}
void Rename ()
{
labelText.Edit();
}
void DeleteLayerPopup ()
{
var popup = new PopupWidget( ParentList );
popup.Layout = Layout.Column();
popup.Layout.Margin = 16;
popup.Layout.Spacing = 8;
popup.Layout.Add( new Label( $"Are you sure you want to delete this Layer?" ) );
var button = new Button.Primary( "Delete" );
button.MouseClick = () =>
{
Delete();
popup.Visible = false;
};
popup.Layout.Add( button );
var bottomBar = popup.Layout.AddRow();
bottomBar.AddStretchCell();
bottomBar.Add( button );
var popupPos = new Vector2( Editor.Application.CursorPosition.x - 250, Editor.Application.CursorPosition.y );
popup.Position = popupPos;
popup.Visible = true;
}
[Shortcut( "editor.delete", "DEL" )]
void Delete ()
{
ParentList.DeleteLayer( Layer );
}
void DuplicateLayerPopup ()
{
var popup = new PopupWidget( ParentList );
popup.Layout = Layout.Column();
popup.Layout.Margin = 16;
popup.Layout.Spacing = 8;
popup.Layout.Add( new Label( $"What would you like to name the duplicated Layer?" ) );
var entry = new LineEdit( popup );
entry.Text = $"{Layer.Name} 2";
var button = new Button.Primary( "Duplicate" );
button.MouseClick = () =>
{
Duplicate( entry.Text );
popup.Visible = false;
};
entry.ReturnPressed += button.MouseClick;
popup.Layout.Add( entry );
var bottomBar = popup.Layout.AddRow();
bottomBar.AddStretchCell();
bottomBar.Add( button );
popup.Position = Editor.Application.CursorPosition;
popup.Visible = true;
entry.Focus();
}
void Duplicate ( string name )
{
var list = ParentList.SerializedProperty.GetValue<List<TilesetComponent.Layer>>();
var index = list.IndexOf( Layer );
var layer = Layer.Copy();
layer.Name = name;
list.Insert( index + 1, layer );
ParentList.SerializedProperty.SetValue( list );
ParentList.UpdateList();
}
protected override void OnContextMenu ( ContextMenuEvent e )
{
base.OnContextMenu( e );
var m = new Menu( this );
var list = ParentList.SerializedProperty.GetValue<List<TilesetComponent.Layer>>();
var collisionLayer = list.FirstOrDefault( x => x.IsCollisionLayer );
var firstLayer = list.FirstOrDefault();
if ( !Layer.IsCollisionLayer && ( collisionLayer is not null || Layer != firstLayer ) )
{
m.AddOption( "Set as Collision Layer", "touch_app", SetAsCollisionLayer );
m.AddSeparator();
}
m.AddOption( "Rename", "edit", Rename );
m.AddOption( "Duplicate", "content_copy", DuplicateLayerPopup );
m.AddOption( "Delete", "delete", Delete );
m.OpenAtCursor( false );
}
protected override void OnDragStart ()
{
base.OnDragStart();
dragData = new Drag( this );
dragData.Data.Object = Layer;
dragData.Execute();
}
public override void OnDragHover ( DragEvent ev )
{
base.OnDragHover( ev );
if ( !TryDragOperation( ev, out var dragDelta ) )
{
draggingAbove = false;
draggingBelow = false;
return;
}
draggingAbove = dragDelta > 0;
draggingBelow = dragDelta < 0;
}
public override void OnDragDrop ( DragEvent ev )
{
base.OnDragDrop( ev );
if ( !TryDragOperation( ev, out var delta ) ) return;
var list = ParentList.SerializedProperty.GetValue<List<TilesetComponent.Layer>>();
var index = list.IndexOf( Layer );
var movingIndex = index + delta;
var layer = list[movingIndex];
list.RemoveAt( movingIndex );
list.Insert( index, layer );
ParentList.SerializedProperty.SetValue( list );
ParentList.UpdateList();
}
bool TryDragOperation ( DragEvent ev, out int delta )
{
delta = 0;
var layer = ev.Data.OfType<TilesetComponent.Layer>().FirstOrDefault();
if ( layer == null || ParentList == null ) return false;
var layerList = ParentList.SerializedProperty.GetValue<List<TilesetComponent.Layer>>();
var myIndex = layerList.IndexOf( Layer );
var otherIndex = layerList.IndexOf( layer );
if ( myIndex == -1 || otherIndex == -1 ) return false;
delta = otherIndex - myIndex;
return true;
}
}