From 119a4a893a77b8da416b047555a4a0bb4653d726 Mon Sep 17 00:00:00 2001 From: Ilya Kozhemyakin Date: Mon, 5 May 2025 10:30:29 +0400 Subject: [PATCH] =?UTF-8?q?=D0=91=D0=BE=D0=BB=D1=8C=D1=88=D0=B5=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Pf2eDataScrapper.sln.DotSettings | 49 +++ .../EntityTreeViewerControl.Designer.cs | 15 +- .../EntityTreeViewerControl.cs | 197 ++++++--- .../EntityTreeViewerControlRow.cs | 385 ++++++++++++++++++ .../EntityTreeViewerRow.Designer.cs | 4 +- .../EntityTreeViewer/EntityTreeViewerRow.cs | 6 +- .../EntityTreeViewer/StructureBuilder.cs | 117 +++--- Pf2eViewer/Program.cs | 4 +- Pf2eViewer/TestForm.Designer.cs | 11 +- 9 files changed, 675 insertions(+), 113 deletions(-) create mode 100644 Pf2eDataScrapper.sln.DotSettings create mode 100644 Pf2eViewer/EntityTreeViewer/EntityTreeViewerControlRow.cs diff --git a/Pf2eDataScrapper.sln.DotSettings b/Pf2eDataScrapper.sln.DotSettings new file mode 100644 index 0000000..06f6382 --- /dev/null +++ b/Pf2eDataScrapper.sln.DotSettings @@ -0,0 +1,49 @@ + + True + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + TargetTyped + True + False + False + 137 + True + E:\proj\pf2e\Pf2eDataScrapper\Pf2eDataScrapper.sln.DotSettings + + True + 1 + False + 12 + dotCover_2025.1 + ReSharper_2025.1 + ReSharperAI_2025.1 + 05/05/2025 08:54:55 + 05/02/2025 05:43:20 + 04/26/2025 06:45:16 + 05/05/2025 08:58:37 + True + True + True + True + True + True + True + [-407,3](1107,1026) + 0,-126 + 422 + 268.5 + 211 + 89.5 + True + CodeInspectionSettings + True + True + 2025.1.0.0 + 2025.1.0.0 \ No newline at end of file diff --git a/Pf2eViewer/EntityTreeViewer/EntityTreeViewerControl.Designer.cs b/Pf2eViewer/EntityTreeViewer/EntityTreeViewerControl.Designer.cs index d27033b..a0d535f 100644 --- a/Pf2eViewer/EntityTreeViewer/EntityTreeViewerControl.Designer.cs +++ b/Pf2eViewer/EntityTreeViewer/EntityTreeViewerControl.Designer.cs @@ -28,28 +28,33 @@ sealed partial class EntityTreeViewerControl /// private void InitializeComponent() { - ContentPanel = new Panel(); + ContentPanel = new PictureBox(); + ((System.ComponentModel.ISupportInitialize)ContentPanel).BeginInit(); SuspendLayout(); // // ContentPanel // - ContentPanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; ContentPanel.Location = new Point(0, 0); ContentPanel.Name = "ContentPanel"; ContentPanel.Size = new Size(400, 500); - ContentPanel.TabIndex = 2; - ContentPanel.Resize += ContentPanel_Resize; + ContentPanel.TabIndex = 0; + ContentPanel.TabStop = false; + ContentPanel.MouseMove += ContentPanel_MouseMove; // // EntityTreeViewerControl // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; + AutoScroll = true; Controls.Add(ContentPanel); Name = "EntityTreeViewerControl"; Size = new Size(400, 500); + Resize += EntityTreeViewerControl_Resize; + ((System.ComponentModel.ISupportInitialize)ContentPanel).EndInit(); ResumeLayout(false); } #endregion - public Panel ContentPanel; + + public PictureBox ContentPanel; } diff --git a/Pf2eViewer/EntityTreeViewer/EntityTreeViewerControl.cs b/Pf2eViewer/EntityTreeViewer/EntityTreeViewerControl.cs index b3823d0..07793ce 100644 --- a/Pf2eViewer/EntityTreeViewer/EntityTreeViewerControl.cs +++ b/Pf2eViewer/EntityTreeViewer/EntityTreeViewerControl.cs @@ -1,18 +1,13 @@ -using System.Collections.Generic; -using System.ComponentModel; -using Pf2eViewer.EntityTreeViewer; +using System.ComponentModel; +using System.Diagnostics; namespace Pf2eViewer.EntityTreeViewer; public sealed partial class EntityTreeViewerControl : UserControl { - private int _itemHeight = 20; - - private EntityView? _entityView; - - private int _depthSize = 20; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + [Category("Entity Render")] + [Description("The height of each item in the tree view.")] public int ItemHeight { get => _itemHeight; @@ -22,8 +17,11 @@ public sealed partial class EntityTreeViewerControl : UserControl UpdateView(); } } + private int _itemHeight = 20; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] public EntityView? EntityView { get => _entityView; @@ -33,8 +31,11 @@ public sealed partial class EntityTreeViewerControl : UserControl UpdateData(); } } + private EntityView? _entityView; [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + [Category("Entity Render")] + [Description("The size of tab.")] public int DepthSize { get => _depthSize; @@ -44,35 +45,76 @@ public sealed partial class EntityTreeViewerControl : UserControl 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 _rows = []; - private List _viewerRows = []; + private List _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.AutoScroll = false; - ContentPanel.HorizontalScroll.Maximum = 0; - ContentPanel.HorizontalScroll.Visible = false; - ContentPanel.AutoScroll = true; + ContentPanel.MouseWheel += ContentPanel_MouseWheel; } public void UpdateData() { - ContentPanel.Controls.Clear(); - if (EntityView?.Entity is null) { return; } _rows.Clear(); + ContentPanel.Controls.Clear(); StructureBuilder builder = new(); @@ -85,57 +127,75 @@ public sealed partial class EntityTreeViewerControl : UserControl _rows.Add(builder.Create(typeName, EntityView.SubEntity)); } - UpdateRows(); - UpdateView(); + _viewerRows = _rows + .SelectMany(r => r.GetRows(row => new EntityTreeViewerControlRow(this, row))) + .ToList(); + + UpdateRenders(); } - public void UpdateRows() + public void UpdateRenders() { - _viewerRows = _rows.SelectMany(r => r.GetTextRows(this)).ToList(); + int maxNameWidth = -1; - ContentPanel.Controls.Clear(); - ContentPanel.Controls.AddRange(_viewerRows.ToArray()); + 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() { - foreach (EntityTreeViewerRow row in _viewerRows) + _viewerRows.ForEach(row => row.UpdateButton()); + + List rows = _viewerRows.Where(r => r.Item.Visible).ToList(); + if (rows.Count == 0) { - row.Visible = row.Item.Visible; + return; } - List rows = _viewerRows.Where(r => r.Item.Visible).ToList(); - - int maxNameWidth = -1; - int viewRow = 0; - - foreach (EntityTreeViewerRow row in rows) - { - row.ViewIndex = viewRow++; - int nameWidth = row.NameWidth + row.Item.Depth * DepthSize; - maxNameWidth = Math.Max(maxNameWidth, nameWidth); - } - - NameWidth = maxNameWidth; - BuildLadder(rows); - foreach (EntityTreeViewerRow row in rows) + _rendering = true; + ContentImage = new(ContentWidth, rows.Count * ItemHeight); + Graphics g = Graphics.FromImage(ContentImage); + + int viewRow = 0; + foreach (EntityTreeViewerControlRow row in rows) { - row.Refresh(); + 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 rows) + private void BuildLadder(List rows) { List lastLadder = []; - ContentPanel.VerticalScroll.Visible = true; for (int i = rows.Count - 1; i >= 0; i--) { - EntityTreeViewerRow row = rows[i]; + EntityTreeViewerControlRow row = rows[i]; List ladder; if (row.Depth == 0) @@ -176,8 +236,53 @@ public sealed partial class EntityTreeViewerControl : UserControl // Events - private void ContentPanel_Resize(object sender, EventArgs e) + private void EntityTreeViewerControl_Resize(object sender, EventArgs e) { - UpdateView(); + 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; + } } } diff --git a/Pf2eViewer/EntityTreeViewer/EntityTreeViewerControlRow.cs b/Pf2eViewer/EntityTreeViewer/EntityTreeViewerControlRow.cs new file mode 100644 index 0000000..031a00e --- /dev/null +++ b/Pf2eViewer/EntityTreeViewer/EntityTreeViewerControlRow.cs @@ -0,0 +1,385 @@ +using FontAwesome.Sharp; +using Font = System.Drawing.Font; +using FontStyle = System.Drawing.FontStyle; +using Image = System.Drawing.Image; + +namespace Pf2eViewer.EntityTreeViewer; + +internal class EntityTreeViewerControlRow +{ + public readonly EntityTreeViewerControl ParentControl; + + public readonly StructureField Item; + + // Local fields + public Image Cache + { + get + { + if (_cache == null) + { + UpdateCache(); + } + return _cache!; + } + set => _cache = value; + } + private Image? _cache; + + public List Ladder + { + get => _ladder; + set + { + _ladder = value; + _cache = null; + } + } + private List _ladder = []; + + public bool Hovered + { + get => _hovered; + set + { + if (value != _hovered) + { + _hovered = value; + Invalidate(); + } + } + } + private bool _hovered = false; + + public int ViewIndex { get; set; } // = -1; + + public IconButton? Button { get; set; } = null; + + // Inherited fields + + public Font Font + { + get => ParentControl.Font; + set => ParentControl.Font = value; + } + public Color ForeColor + { + get => ParentControl.ForeColor; + set => ParentControl.ForeColor = value; + } + public Color BackColor + { + get => ParentControl.BackColor; + set => ParentControl.BackColor = value; + } + public Color HoverColor + { + get => ParentControl.HoverColor; + set => ParentControl.HoverColor = value; + } + public int ItemHeight + { + get => ParentControl.ItemHeight; + set => ParentControl.ItemHeight = value; + } + public int DepthSize + { + get => ParentControl.DepthSize; + set => ParentControl.DepthSize = value; + } + public int ButtonSize + { + get => ParentControl.ButtonSize; + set => ParentControl.ButtonSize = value; + } + + // ValueText functions + + public int Width => ParentControl.ContentWidth; + public int Height => ItemHeight; + public bool HasButton => Item.FieldType == StructureFieldType.Complex; + public int Depth => Item.Depth; + public int NameWidth + { + get + { + Graphics g = Graphics.FromImage(Cache); + return Convert.ToInt32(g.MeasureString(Item.Name, Font).Width + DepthSize); + } + } + + public string TypeText + { + get + { + string result = Item.GetTypeString(); + if (result != "") + { + result = $@"({result})"; + } + return result; + } + } + public Font TypeFont => new(Font.FontFamily, Font.Size * 0.6f, FontStyle.Italic); + + public string ValueText => Item.GetValueString(); + public Font ValueFont => + new( + Font.FontFamily, + Font.Size, + Item.FieldType == StructureFieldType.Complex ? FontStyle.Italic : FontStyle.Regular + ); + + public RectangleF Target => new(0, ViewIndex * Height, Width, Height); + public RectangleF RealTarget => + new(0, ViewIndex * Height - ParentControl.VerticalScroll.Value, Width, Height); + + // Simple fields + + private readonly List _renderData = []; + + // Main methods + + public EntityTreeViewerControlRow(EntityTreeViewerControl parent, StructureField item) + { + ParentControl = parent; + Item = item; + ApplyItem(); + UpdateCache(); + + UpdateButton(); + } + + private void ApplyItem() + { + _renderData.Clear(); + + _renderData.Add(new(Item.Name, Font, ForeColor)); + _renderData.Add(new(TypeText, TypeFont, GetValueColor())); + _renderData.Add( + new(ValueText.Replace("\r", "").Replace('\n', ' '), ValueFont, GetValueColor()) + ); + + if (HasButton) + { + Button = new() + { + Width = ButtonSize, + Height = ButtonSize, + IconSize = ButtonSize, + IconChar = IconChar.MinusSquare, + ImageAlign = ContentAlignment.MiddleCenter, + TextAlign = ContentAlignment.MiddleCenter, + Visible = false, + }; + + Button.Click += Button_Click; + + ParentControl.ContentPanel.Controls.Add(Button); + } + } + + public void UpdateCache() + { + Cache = new Bitmap(Width, Height); + Graphics g = Graphics.FromImage(Cache); + + RenderLadder(g); + RenderContent(g); + + g.Save(); + } + + public void Invalidate(Graphics? g = null) + { + g ??= Graphics.FromImage(ParentControl.ContentImage); + + g.FillRectangle(new SolidBrush(Hovered ? HoverColor : BackColor), Target); + g.DrawImage(Cache, Target); + + UpdateButton(); + } + + // Button + + public void UpdateButton() + { + if (Button is null) + { + return; + } + + int cx = Convert.ToInt32((0.5 + Depth) * DepthSize - 0.5 * ButtonSize); + int cy = Convert.ToInt32((0.5 + ViewIndex) * ItemHeight - 0.5 * ButtonSize); + + Button.Left = cx; + Button.Top = cy; + + Button!.IconChar = ((StructureFieldComplex)Item).Collapsed + ? IconChar.PlusSquare + : IconChar.MinusSquare; + Button.Visible = Item.Visible; + } + + private void Button_Click(object? sender, EventArgs e) + { + if (Item is StructureFieldComplex complex) + { + complex.Collapsed = !complex.Collapsed; + ParentControl.UpdateView(); + } + } + + // Render + + private void RenderLadder(Graphics g) + { + int n = Depth; + int h = ItemHeight; + int w = DepthSize; + + if (_ladder.Count < Depth) + { + return; + } + + 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); + } + } + } + + private void RenderContent(Graphics g) + { + float[] xs = + [ + DepthSize * (Item.Depth + 1), + ParentControl.NameWidth, + ParentControl.NameWidth + g.MeasureString(TypeText, TypeFont).Width + 3, + Width, + ]; + + Pen p = new(Color.Aqua, 1); + + for (int i = 0; i < 3; i++) + { + StringRenderData item = _renderData[i]; + + item.Left = xs[i]; + item.Width = xs[i + 1] - xs[i]; + item.Height = ItemHeight; + + // g.DrawRectangle(p, item.Rect); + item.Draw(g); + } + } + + // Helper functions + + 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, + }; + } + + private class StringRenderData(string text, Font font, Color color) + { + public string Text { get; } = text; + public Font Font { get; } = font; + public Color Color { get; } = color; + + public float Left { get; set; } + public float Width { get; set; } + public float Height { get; set; } + + public RectangleF Rect => new(Left, 0, Width, Height); + + private string Fit(Graphics g, RectangleF rect) + { + if (Text.Length == 0 || g.MeasureString(Text, Font).Width <= rect.Width) + { + return Text; + } + + string txt = Text.Length > 100 ? Text[..100] : Text; + + int i = txt.Length; + + while (g.MeasureString(txt + "...", Font).Width > rect.Width) + { + txt = txt[..--i]; + if (i == 0) + break; + } + + return txt + "..."; + } + + public void Draw(Graphics g) + { + g.DrawString( + Fit(g, Rect), + Font, + new SolidBrush(Color), + Rect, + new StringFormat + { + Alignment = StringAlignment.Near, + LineAlignment = StringAlignment.Center, + FormatFlags = StringFormatFlags.NoWrap, + } + ); + } + } +} diff --git a/Pf2eViewer/EntityTreeViewer/EntityTreeViewerRow.Designer.cs b/Pf2eViewer/EntityTreeViewer/EntityTreeViewerRow.Designer.cs index 8836e52..05f782b 100644 --- a/Pf2eViewer/EntityTreeViewer/EntityTreeViewerRow.Designer.cs +++ b/Pf2eViewer/EntityTreeViewer/EntityTreeViewerRow.Designer.cs @@ -91,7 +91,7 @@ sealed partial class EntityTreeViewerRow TypeLabel.Name = "TypeLabel"; TypeLabel.Size = new Size(57, 38); TypeLabel.TabIndex = 3; - TypeLabel.Text = "Type"; + TypeLabel.Text = "TypeText"; TypeLabel.TextAlign = ContentAlignment.MiddleLeft; // // ValueLabel @@ -102,7 +102,7 @@ sealed partial class EntityTreeViewerRow ValueLabel.Name = "ValueLabel"; ValueLabel.Size = new Size(288, 38); ValueLabel.TabIndex = 4; - ValueLabel.Text = "Value"; + ValueLabel.Text = "ValueText"; ValueLabel.TextAlign = ContentAlignment.MiddleLeft; // // EntityTreeViewerRow diff --git a/Pf2eViewer/EntityTreeViewer/EntityTreeViewerRow.cs b/Pf2eViewer/EntityTreeViewer/EntityTreeViewerRow.cs index 1f30723..3d3eafe 100644 --- a/Pf2eViewer/EntityTreeViewer/EntityTreeViewerRow.cs +++ b/Pf2eViewer/EntityTreeViewer/EntityTreeViewerRow.cs @@ -76,7 +76,7 @@ internal sealed partial class EntityTreeViewerRow : UserControl set => ParentControl.ItemHeight = value; } - // Value functions + // ValueText functions public bool HasButton => Item.FieldType == StructureFieldType.Complex; public int Depth => Item.Depth; @@ -122,7 +122,7 @@ internal sealed partial class EntityTreeViewerRow : UserControl Left = 0; Top = ViewIndex * ParentControl.ItemHeight; - Width = ParentControl.ContentPanel.Width - Left - SystemInformation.VerticalScrollBarWidth; + Width = ParentControl.ContentWidth - Left - SystemInformation.VerticalScrollBarWidth; Height = ParentControl.ItemHeight; // Name Panel @@ -135,7 +135,7 @@ internal sealed partial class EntityTreeViewerRow : UserControl NameLabel.Left = IconPictureBox.Width; NameLabel.Width = NamePanel.Width - NameLabel.Left; - // Value Panel + // ValueText Panel ValuePanel.Left = NamePanel.Left + NamePanel.Width; ValuePanel.Width = Width - ValuePanel.Left; diff --git a/Pf2eViewer/EntityTreeViewer/StructureBuilder.cs b/Pf2eViewer/EntityTreeViewer/StructureBuilder.cs index c2ef7ed..427d00d 100644 --- a/Pf2eViewer/EntityTreeViewer/StructureBuilder.cs +++ b/Pf2eViewer/EntityTreeViewer/StructureBuilder.cs @@ -36,7 +36,7 @@ internal class StructureBuilder public void CompleteProcessed(object value, StructureFieldComplex field) { - var q = _processedObjects.FirstOrDefault(p => p.Value == value); + StructureProcessedObject? q = _processedObjects.FirstOrDefault(p => p.Value == value); if (q == null) { @@ -59,6 +59,9 @@ internal class StructureBuilder case StructureFieldType.Enum: return new StructureFieldEnum(this, value!, name, depth); + case StructureFieldType.Reference: + break; + case StructureFieldType.Complex: default: @@ -66,15 +69,22 @@ internal class StructureBuilder p.Value == value ); - if (processed is not null) + if (processed is null) { - var reference = new StructureFieldReference(this, name, null, depth); - processed.AddReference(reference); - return reference; + return Create(name, value!, depth); } - return Create(name, value!, depth); + StructureFieldReference reference = new StructureFieldReference( + this, + name, + null, + depth + ); + processed.AddReference(reference); + return reference; } + + throw new("Impossible"); } public static StructureFieldType GetFieldType(object? value) @@ -112,7 +122,7 @@ internal class StructureProcessedObject(object value) set { _field = value; - foreach (var reference in _references) + foreach (StructureFieldReference reference in _references) { reference.Reference = Field; } @@ -158,7 +168,7 @@ internal abstract class StructureField(StructureBuilder builder, string name, in public virtual bool Visible { get; set; } = true; - public int Depth = depth; + public readonly int Depth = depth; public abstract string GetTypeString(); @@ -166,7 +176,13 @@ internal abstract class StructureField(StructureBuilder builder, string name, in public virtual ICollection GetTextRows(EntityTreeViewerControl control) { - return [new EntityTreeViewerRow(control, this)]; + return [new(control, this)]; + } + + public virtual ICollection GetRows(Func func) + { + StructureField[] q = [this]; + return q.Select(func).ToList(); } } @@ -189,7 +205,7 @@ internal class StructureFieldPrimitive( { public override StructureFieldType FieldType => StructureFieldType.Primitive; - public object Value = value; + public readonly object Value = value; public readonly Type Type = value.GetType(); @@ -221,7 +237,7 @@ internal class StructureFieldEnum(StructureBuilder builder, object value, string { public override StructureFieldType FieldType => StructureFieldType.Enum; - public object Value = value; + public readonly object Value = value; public readonly Type Type = value.GetType(); @@ -238,8 +254,6 @@ internal class StructureFieldComplex : StructureField public readonly Type Type; - private bool _collapsed = false; - public bool Collapsed { get => _collapsed; @@ -249,16 +263,7 @@ internal class StructureFieldComplex : StructureField UpdateFieldVisibility(); } } - - private bool _visible = true; - - public StructureFieldComplex(StructureBuilder builder, object value, string name, int depth) - : base(builder, name, depth) - { - Type = value.GetType(); - - SetFields((dynamic)value); - } + private bool _collapsed = false; public override bool Visible { @@ -269,10 +274,19 @@ internal class StructureFieldComplex : StructureField UpdateFieldVisibility(); } } + private bool _visible = true; + + public StructureFieldComplex(StructureBuilder builder, object value, string name, int depth) + : base(builder, name, depth) + { + Type = value.GetType(); + + SetFields((dynamic)value); + } private void UpdateFieldVisibility() { - foreach (var field in Fields) + foreach (StructureField field in Fields) { field.Visible = Visible && !Collapsed; } @@ -280,24 +294,22 @@ internal class StructureFieldComplex : StructureField private void SetFields(LocaleString localeString) { - List records = []; - - foreach (var field in localeString) - { - records.Add(new FieldRecord(field.Locale.ToString(), field.Value)); - } - - SetFieldsFromRecords(records); + SetFieldsFromRecords( + localeString + .Select(field => new FieldRecord(field.Locale.ToString(), field.Value)) + .ToList() + ); } - private void SetFields(IEnumerable enumrable) + private void SetFields(IEnumerable enumerable) { int i = 0; + List records = []; - foreach (var item in enumrable) + foreach (object? item in enumerable) { - records.Add(new FieldRecord($"[{i++}]", item)); + records.Add(new($"[{i++}]", item)); } SetFieldsFromRecords(records); @@ -320,24 +332,22 @@ internal class StructureFieldComplex : StructureField private void SetFieldsFromRecords(List records) { - foreach (FieldRecord record in records) + foreach ( + FieldRecord record in records.Where(record => + record.FieldType == StructureFieldType.Complex + ) + ) { - if (record.FieldType == StructureFieldType.Complex) - { - record.Allowed = Builder.RegisterProcessed(record.Value!); - } + record.Allowed = Builder.RegisterProcessed(record.Value!); } - foreach (var record in records) + foreach (FieldRecord record in records) { - if (record.FieldType == StructureFieldType.Complex && record.Allowed) - { - Fields.Add(Builder.Create(record.Name, record.Value!, Depth + 1)); - } - else - { - Fields.Add(Builder.Resolve(record.Name, record.Value!, Depth + 1)); - } + Fields.Add( + record is { FieldType: StructureFieldType.Complex, Allowed: true } + ? Builder.Create(record.Name, record.Value!, Depth + 1) + : Builder.Resolve(record.Name, record.Value!, Depth + 1) + ); } } @@ -350,11 +360,16 @@ internal class StructureFieldComplex : StructureField return rows; } + public override ICollection GetRows(Func func) + { + return [.. base.GetRows(func), .. Fields.SelectMany(f => f.GetRows(func)).ToList()]; + } + private class FieldRecord(string name, object? value) { - public string Name = name; + public readonly string Name = name; - public object? Value = value; + public readonly object? Value = value; public StructureFieldType FieldType => StructureBuilder.GetFieldType(Value); diff --git a/Pf2eViewer/Program.cs b/Pf2eViewer/Program.cs index 7e3bb13..a9482a2 100644 --- a/Pf2eViewer/Program.cs +++ b/Pf2eViewer/Program.cs @@ -18,7 +18,7 @@ internal static class Program Application.SetColorMode(SystemColorMode.System); #pragma warning restore WFO5001 - Application.Run(new MainViewForm() { StartPosition = FormStartPosition.CenterScreen }); - // Application.Run(new TestForm() { StartPosition = FormStartPosition.CenterScreen }); + // Application.Run(new MainViewForm() { StartPosition = FormStartPosition.CenterScreen }); + Application.Run(new TestForm() { StartPosition = FormStartPosition.CenterScreen }); } } diff --git a/Pf2eViewer/TestForm.Designer.cs b/Pf2eViewer/TestForm.Designer.cs index 50d3864..e1deba6 100644 --- a/Pf2eViewer/TestForm.Designer.cs +++ b/Pf2eViewer/TestForm.Designer.cs @@ -49,13 +49,16 @@ partial class TestForm // entityTreeViewerControl1 // entityTreeViewerControl1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; - entityTreeViewerControl1.DepthSize = 20; - entityTreeViewerControl1.EntityView = null; + entityTreeViewerControl1.AutoScroll = true; + entityTreeViewerControl1.ButtonSize = 15; + entityTreeViewerControl1.DepthSize = 15; entityTreeViewerControl1.Font = new Font("Consolas", 9F); + entityTreeViewerControl1.HoverColor = SystemColors.ControlLight; entityTreeViewerControl1.ItemHeight = 20; - entityTreeViewerControl1.Location = new Point(12, 38); + entityTreeViewerControl1.Location = new Point(14, 46); + entityTreeViewerControl1.Margin = new Padding(3, 4, 3, 4); entityTreeViewerControl1.Name = "entityTreeViewerControl1"; - entityTreeViewerControl1.Size = new Size(426, 606); + entityTreeViewerControl1.Size = new Size(424, 597); entityTreeViewerControl1.TabIndex = 1; // // TestForm