Files
Pf2eDataScrapper/Pf2eViewer/EntityTreeViewer/EntityTreeViewerControl.cs
T

289 lines
7.4 KiB
C#

using System.ComponentModel;
using System.Diagnostics;
namespace Pf2eViewer.EntityTreeViewer;
public sealed partial class EntityTreeViewerControl : UserControl
{
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("The height of each item in the tree view.")]
public int ItemHeight
{
get => _itemHeight;
set
{
_itemHeight = value;
UpdateView();
}
}
private int _itemHeight = 20;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public EntityView? EntityView
{
get => _entityView;
set
{
_entityView = value;
UpdateData();
}
}
private EntityView? _entityView;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("The size of tab.")]
public int DepthSize
{
get => _depthSize;
set
{
_depthSize = value;
UpdateView();
}
}
private int _depthSize = 20;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("The size of plus/minus button.")]
public int ButtonSize
{
get => _buttonSize;
set
{
_buttonSize = value;
UpdateView();
}
}
private int _buttonSize = 20;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public int NameWidth { get; private set; } = 200;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("Color on item hover.")]
public Color HoverColor
{
get => _hoverColor;
set
{
_hoverColor = value;
UpdateView();
}
}
private Color _hoverColor = SystemColors.ControlDark;
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public int ContentWidth => Width - SystemInformation.VerticalScrollBarWidth - 2;
private readonly List<StructureField> _rows = [];
private List<EntityTreeViewerControlRow> _viewerRows = [];
private bool _rendering;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public Bitmap ContentImage { get; set; }
public EntityTreeViewerControl()
{
InitializeComponent();
ContentImage = new(ContentWidth, Height);
DoubleBuffered = true;
VerticalScroll.Visible = true;
HorizontalScroll.Visible = false;
ContentPanel.MouseWheel += ContentPanel_MouseWheel;
}
public void UpdateData()
{
if (EntityView?.Entity is null)
{
return;
}
_rows.Clear();
ContentPanel.Controls.Clear();
StructureBuilder builder = new();
_rows.Add(builder.Create("Entity", EntityView.Entity));
if (EntityView.SubEntity is not null)
{
string typeName = EntityView.SubEntity.GetType().Name;
_rows.Add(builder.Create(typeName, EntityView.SubEntity));
}
_viewerRows = _rows
.SelectMany(r => r.GetRows(row => new EntityTreeViewerControlRow(this, row)))
.ToList();
UpdateRenders();
}
public void UpdateRenders()
{
int maxNameWidth = -1;
foreach (EntityTreeViewerControlRow row in _viewerRows)
{
int nameWidth = row.NameWidth + row.Item.Depth * DepthSize;
maxNameWidth = Math.Max(maxNameWidth, nameWidth);
}
NameWidth = maxNameWidth + 3;
// Debug.WriteLine($@"Height Inner {ContentWidth} / Outer {Width}");
// Debug.WriteLine($@"Name {NameWidth} / Full {ContentWidth}");
foreach (EntityTreeViewerControlRow row in _viewerRows)
{
row.UpdateCache();
}
UpdateView();
}
public void UpdateView()
{
_viewerRows.ForEach(row => row.UpdateButton());
List<EntityTreeViewerControlRow> rows = _viewerRows.Where(r => r.Item.Visible).ToList();
if (rows.Count == 0)
{
return;
}
BuildLadder(rows);
_rendering = true;
ContentImage = new(ContentWidth, rows.Count * ItemHeight);
Graphics g = Graphics.FromImage(ContentImage);
int viewRow = 0;
foreach (EntityTreeViewerControlRow row in rows)
{
row.ViewIndex = viewRow++;
row.Invalidate(g);
}
g.Save();
ContentPanel.Image = ContentImage;
ContentPanel.Width = ContentImage.Width;
ContentPanel.Height = ContentImage.Height;
_rendering = false;
}
private void BuildLadder(List<EntityTreeViewerControlRow> rows)
{
List<LadderType> lastLadder = [];
for (int i = rows.Count - 1; i >= 0; i--)
{
EntityTreeViewerControlRow row = rows[i];
List<LadderType> ladder;
if (row.Depth == 0)
{
ladder = [];
}
else if (row.Depth < lastLadder.Count)
{
ladder =
[
.. lastLadder[..(row.Depth - 1)],
lastLadder[row.Depth - 1] == LadderType.Empty
? LadderType.Last
: LadderType.Through,
];
}
else if (row.Depth == lastLadder.Count)
{
ladder = lastLadder;
}
else
{
ladder =
[
.. lastLadder,
.. Enumerable.Repeat(LadderType.Empty, row.Depth - lastLadder.Count - 1),
LadderType.Last,
];
}
row.Ladder = ladder;
lastLadder = ladder
.Select(l => (l == LadderType.Last) ? LadderType.Through : l)
.ToList();
}
}
// Events
private void EntityTreeViewerControl_Resize(object sender, EventArgs e)
{
if (_rendering)
{
return;
}
ContentPanel.Width = Width;
UpdateRenders();
}
private void ContentPanel_MouseWheel(object? sender, MouseEventArgs e)
{
/*
int initValue = VerticalScroll.Value;
int delta = -e.Delta / 120;
VerticalScroll.Value = Math.Clamp(
initValue + delta,
VerticalScrollBar.Minimum,
VerticalScrollBar.Maximum - VerticalScrollBar.LargeChange + 1
);
if (VerticalScrollBar.Value != initValue)
{
ContentPanel.Invalidate();
}
*/
}
private void ContentPanel_MouseMove(object sender, MouseEventArgs e)
{
PointF p = new(e.X, e.Y);
foreach (EntityTreeViewerControlRow row in _viewerRows)
{
bool contained = row.Target.Contains(p);
if (contained != row.Hovered)
{
Rectangle r = new();
row.RealTarget.Intersect(r);
ContentPanel.Invalidate(r);
}
row.Hovered = contained;
}
}
}