274 lines
7.3 KiB
C#
274 lines
7.3 KiB
C#
using System.ComponentModel;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Windows.Markup;
|
|
using FontAwesome.Sharp;
|
|
|
|
namespace Pf2eViewer.EntityTreeViewer;
|
|
|
|
internal sealed partial class EntityTreeViewerRow : UserControl
|
|
{
|
|
public readonly EntityTreeViewerControl ParentControl;
|
|
|
|
public readonly StructureField Item;
|
|
|
|
public int ViewIndex = 0;
|
|
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public Bitmap IconCache
|
|
{
|
|
get
|
|
{
|
|
if (_iconCache == null)
|
|
{
|
|
UpdateCache();
|
|
}
|
|
return _iconCache!;
|
|
}
|
|
set => _iconCache = value;
|
|
}
|
|
private Bitmap? _iconCache;
|
|
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public List<LadderType> Ladder
|
|
{
|
|
get => _ladder;
|
|
set
|
|
{
|
|
_ladder = value;
|
|
_iconCache = null;
|
|
}
|
|
}
|
|
private List<LadderType> _ladder = [];
|
|
|
|
[AllowNull]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
|
public override Font Font
|
|
{
|
|
get => ParentControl.Font;
|
|
set => ParentControl.Font = value;
|
|
}
|
|
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
|
public override Color ForeColor
|
|
{
|
|
get => ParentControl.ForeColor;
|
|
set => ParentControl.ForeColor = value;
|
|
}
|
|
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
|
public override Color BackColor
|
|
{
|
|
get => ParentControl.BackColor;
|
|
set => ParentControl.BackColor = value;
|
|
}
|
|
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public int ItemHeight
|
|
{
|
|
get => ParentControl.ItemHeight;
|
|
set => ParentControl.ItemHeight = value;
|
|
}
|
|
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public int DepthSize
|
|
{
|
|
get => ParentControl.ItemHeight;
|
|
set => ParentControl.ItemHeight = value;
|
|
}
|
|
|
|
// ValueText functions
|
|
|
|
public bool HasButton => Item.FieldType == StructureFieldType.Complex;
|
|
public int Depth => Item.Depth;
|
|
public int NameWidth => TextRenderer.MeasureText(NameLabel.Text, Font).Width + DepthSize;
|
|
|
|
public EntityTreeViewerRow(EntityTreeViewerControl parent, StructureField item)
|
|
{
|
|
ParentControl = parent;
|
|
|
|
Item = item;
|
|
|
|
InitializeComponent();
|
|
ApplyItem();
|
|
Refresh();
|
|
}
|
|
|
|
private void ApplyItem()
|
|
{
|
|
TypeLabel.Font = new(Font.FontFamily, Font.Size - 2, FontStyle.Italic);
|
|
|
|
NameLabel.Text = Item.Name;
|
|
TypeLabel.Text = Item.GetTypeString();
|
|
if (TypeLabel.Text != "")
|
|
{
|
|
TypeLabel.Text = $@"({TypeLabel.Text})";
|
|
}
|
|
|
|
ValueLabel.Text = Item.GetValueString();
|
|
TypeLabel.ForeColor = ValueLabel.ForeColor = GetValueColor();
|
|
|
|
if (Item.FieldType == StructureFieldType.Complex)
|
|
{
|
|
ValueLabel.Font = new(Font, FontStyle.Italic);
|
|
}
|
|
|
|
UpdateCache();
|
|
Refresh();
|
|
}
|
|
|
|
public new void Refresh()
|
|
{
|
|
base.Refresh();
|
|
|
|
Left = 0;
|
|
Top = ViewIndex * ParentControl.ItemHeight;
|
|
Width = ParentControl.ContentWidth - Left - SystemInformation.VerticalScrollBarWidth;
|
|
Height = ParentControl.ItemHeight;
|
|
|
|
// Name Panel
|
|
NamePanel.Left = 0;
|
|
NamePanel.Width = ParentControl.NameWidth - NamePanel.Left;
|
|
|
|
IconPictureBox.Width = IconCache.Width;
|
|
IconPictureBox.Image = IconCache;
|
|
|
|
NameLabel.Left = IconPictureBox.Width;
|
|
NameLabel.Width = NamePanel.Width - NameLabel.Left;
|
|
|
|
// ValueText Panel
|
|
ValuePanel.Left = NamePanel.Left + NamePanel.Width;
|
|
ValuePanel.Width = Width - ValuePanel.Left;
|
|
|
|
Size typeSize = TextRenderer.MeasureText(TypeLabel.Text, TypeLabel.Font);
|
|
TypeLabel.Width = typeSize.Width + 3;
|
|
}
|
|
|
|
private Color BlendColor(Color color, double rate = 0.5)
|
|
{
|
|
return BlendColor(ForeColor, color, rate);
|
|
}
|
|
|
|
private Color BlendColor(Color color1, Color color2, double rate)
|
|
{
|
|
return Color.FromArgb(
|
|
Mix(color1.A, color2.A),
|
|
Mix(color1.R, color2.R),
|
|
Mix(color1.G, color2.G),
|
|
Mix(color1.B, color2.B)
|
|
);
|
|
|
|
int Mix(int a, int b) => Convert.ToInt32(Math.Round(a * rate + b * (1 - rate)));
|
|
}
|
|
|
|
public Color GetValueColor()
|
|
{
|
|
return Item switch
|
|
{
|
|
StructureFieldPrimitive primitive => Type.GetTypeCode(primitive.Type) switch
|
|
{
|
|
TypeCode.Boolean => BlendColor(Color.DarkGoldenrod),
|
|
TypeCode.Int32 => BlendColor(Color.Blue),
|
|
TypeCode.Double => BlendColor(Color.Aqua),
|
|
TypeCode.String => BlendColor(Color.Green),
|
|
_ => ForeColor,
|
|
},
|
|
StructureFieldEnum => BlendColor(Color.Red),
|
|
_ => ForeColor,
|
|
};
|
|
}
|
|
|
|
// Events
|
|
|
|
private void IconPictureBox_Click(object sender, EventArgs e)
|
|
{
|
|
if (Item.GetType() != typeof(StructureFieldComplex))
|
|
{
|
|
return;
|
|
}
|
|
|
|
StructureFieldComplex complex = (StructureFieldComplex)Item;
|
|
|
|
complex.Collapsed = !complex.Collapsed;
|
|
ParentControl.UpdateView();
|
|
}
|
|
|
|
private Bitmap? GetIconImage()
|
|
{
|
|
if (Item.GetType() != typeof(StructureFieldComplex))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
StructureFieldComplex complex = (StructureFieldComplex)Item;
|
|
|
|
int size = Convert.ToInt32(Math.Round(DepthSize * 0.6));
|
|
|
|
return complex.Collapsed
|
|
? IconChar.PlusSquare.ToBitmap(IconFont.Auto, size, ForeColor)
|
|
: IconChar.MinusSquare.ToBitmap(IconFont.Auto, size, ForeColor);
|
|
}
|
|
|
|
private void UpdateCache()
|
|
{
|
|
int n = Depth;
|
|
int h = ItemHeight;
|
|
int w = DepthSize;
|
|
|
|
_iconCache = new(w * (n + 1), h);
|
|
|
|
if (_ladder.Count < Depth)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Graphics g = Graphics.FromImage(_iconCache);
|
|
|
|
Pen pen = new(Color.FromArgb(127, ForeColor.R, ForeColor.G, ForeColor.B), 1);
|
|
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
|
|
|
|
float cy = 0.5f * h;
|
|
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
float cx = (i + 1.5f) * w;
|
|
|
|
switch (_ladder[i])
|
|
{
|
|
case LadderType.Last:
|
|
g.DrawLine(pen, cx, 0, cx, cy);
|
|
break;
|
|
case LadderType.Through:
|
|
g.DrawLine(pen, cx, 0, cx, h);
|
|
break;
|
|
case LadderType.Empty:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (i == n - 1)
|
|
{
|
|
g.DrawLine(pen, cx, cy, (i + 2) * w, cy);
|
|
}
|
|
}
|
|
|
|
Bitmap? icon = GetIconImage();
|
|
|
|
if (icon is not null)
|
|
{
|
|
float cx = (n + 0.5f) * w;
|
|
|
|
g.FillRectangle(
|
|
new SolidBrush(BackColor),
|
|
cx - 0.5f * icon.Width - 1,
|
|
cy - 0.5f * icon.Height - 1,
|
|
icon.Width + 2,
|
|
icon.Height + 2
|
|
);
|
|
|
|
g.DrawImage(icon, new PointF(cx - 0.5f * icon.Width, cy - 0.5f * icon.Height));
|
|
}
|
|
|
|
g.Save();
|
|
}
|
|
}
|