diff --git a/Pf2eViewer/EntityTreeViewerControl.Designer.cs b/Pf2eViewer/EntityTreeViewerControl.Designer.cs
new file mode 100644
index 0000000..8c79c98
--- /dev/null
+++ b/Pf2eViewer/EntityTreeViewerControl.Designer.cs
@@ -0,0 +1,66 @@
+namespace Pf2eViewer;
+
+partial class EntityTreeViewerControl
+{
+ ///
+ /// Обязательная переменная конструктора.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Освободить все используемые ресурсы.
+ ///
+ /// истинно, если управляемый ресурс должен быть удален; иначе ложно.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Код, автоматически созданный конструктором компонентов
+
+ ///
+ /// Требуемый метод для поддержки конструктора — не изменяйте
+ /// содержимое этого метода с помощью редактора кода.
+ ///
+ private void InitializeComponent()
+ {
+ VerticalScrollBar = new VScrollBar();
+ ContentPanel = new Panel();
+ SuspendLayout();
+ //
+ // VerticalScrollBar
+ //
+ VerticalScrollBar.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right;
+ VerticalScrollBar.Location = new Point(400, 0);
+ VerticalScrollBar.Name = "VerticalScrollBar";
+ VerticalScrollBar.Size = new Size(20, 520);
+ VerticalScrollBar.TabIndex = 0;
+ //
+ // 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, 520);
+ ContentPanel.TabIndex = 2;
+ //
+ // EntityTreeViewerControl
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ Controls.Add(ContentPanel);
+ Controls.Add(VerticalScrollBar);
+ Name = "EntityTreeViewerControl";
+ Size = new Size(420, 520);
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private VScrollBar VerticalScrollBar;
+ private Panel ContentPanel;
+}
diff --git a/Pf2eViewer/EntityTreeViewerControl.cs b/Pf2eViewer/EntityTreeViewerControl.cs
new file mode 100644
index 0000000..db1f4d5
--- /dev/null
+++ b/Pf2eViewer/EntityTreeViewerControl.cs
@@ -0,0 +1,229 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Windows.Forms.VisualStyles;
+using Microsoft.EntityFrameworkCore.Metadata.Internal;
+
+namespace Pf2eViewer;
+
+public partial class EntityTreeViewerControl : UserControl
+{
+ private int _itemHeight = 20;
+
+ private EntityView? _entityView = null;
+
+ public int ItemHeight
+ {
+ get => _itemHeight;
+ set
+ {
+ _itemHeight = value;
+ UpdateView();
+ }
+ }
+
+ public EntityView? EntityView
+ {
+ get => _entityView;
+ set
+ {
+ _entityView = value;
+ UpdateView();
+ }
+ }
+
+ public EntityTreeViewerControl()
+ {
+ InitializeComponent();
+ }
+
+ public void UpdateView()
+ {
+ ContentPanel.Controls.Clear();
+
+ if (EntityView?.Entity is null)
+ {
+ return;
+ }
+
+ Rows.Clear();
+
+ Rows.Add(new HeaderRow("Entity"));
+ Rows.Add(new ObjectComplex(null, EntityView.Entity));
+ Rows.Add(new HeaderRow(EntityView.SubEntity?.GetType().ToString() ?? "SubEntity"));
+ Rows.Add(new ObjectComplex(null, EntityView.SubEntity));
+
+ List displayRows = Rows.SelectMany(r => r.GetTextRows()).ToList();
+
+ for (int i = 0; i < displayRows.Count; i++)
+ {
+ DisplayRow dr = displayRows[i];
+
+ TextBox tb = new()
+ {
+ Top = i * ItemHeight,
+ Left = 0,
+ Width = ContentPanel.Width,
+ Height = ItemHeight,
+ Font = Font,
+ Text = string.Join(
+ "",
+ [new(' ', dr.Depth * 2), dr.Name, dr.Value != "" ? " : " : "", dr.Value]
+ ),
+ Margin = new(0),
+ };
+
+ ContentPanel.Controls.Add(tb);
+ }
+ }
+
+ private Panel GetObjectPanel(object obj)
+ {
+ Panel result = new();
+
+ Type type = obj.GetType();
+
+ PropertyInfo[] properties = type.GetProperties();
+ /*
+ FieldInfo[] fields = type.GetFields(
+ BindingFlags.Instance
+ | BindingFlags.Static
+ | BindingFlags.NonPublic
+ | BindingFlags.Public
+ );
+ */
+ for (int i = 0; i < properties.Length; i++)
+ {
+ PropertyInfo property = properties[i];
+
+ TextBox tb = new()
+ {
+ Top = i * ItemHeight,
+ Left = 0,
+ Width = ContentPanel.Width,
+ Height = ItemHeight,
+ Font = Font,
+ Text = property.Name,
+ Margin = new(0),
+ };
+
+ result.Controls.Add(tb);
+ }
+
+ result.Width = ContentPanel.Width;
+ result.Height = properties.Length * ItemHeight * 2;
+
+ return result;
+ }
+
+ private List Rows = [];
+
+ private class DisplayRow
+ {
+ public string Name = "";
+
+ public string Value = "";
+
+ public int Depth = 0;
+ }
+
+ private abstract class Row
+ {
+ public abstract ICollection GetTextRows();
+
+ public int Depth = 0;
+ }
+
+ private class HeaderRow(string name) : Row
+ {
+ public readonly string Name = name;
+
+ public override ICollection GetTextRows()
+ {
+ return [new() { Name = Name, Depth = Depth }];
+ }
+ }
+
+ private abstract class ObjectField(PropertyInfo property, object? parent) : Row
+ {
+ public readonly PropertyInfo? Property = property;
+
+ public readonly string Name = property.Name;
+
+ public readonly Type Type = property.PropertyType;
+
+ public abstract int Rows { get; }
+
+ public static ObjectField Resolve(PropertyInfo property, object? parent)
+ {
+ return property.PropertyType.IsPrimitive
+ ? new ObjectPrimitive(property, parent)
+ : new ObjectComplex(property, parent);
+ }
+ }
+
+ private class ObjectPrimitive : ObjectField
+ {
+ public readonly object? Value;
+
+ public override int Rows => 1;
+
+ public ObjectPrimitive(PropertyInfo? property, object? parent)
+ : base(property, parent)
+ {
+ Value = Property.GetValue(parent, null);
+ }
+
+ public override ICollection GetTextRows()
+ {
+ return
+ [
+ new()
+ {
+ Name = Name,
+ Value = Value?.ToString() ?? "null",
+ Depth = Depth,
+ },
+ ];
+ }
+ }
+
+ private class ObjectComplex : ObjectField
+ {
+ public readonly List Fields;
+
+ public bool Collapsed = false;
+
+ public override int Rows => 1 + Fields.Select(f => f.Rows).Sum();
+
+ public ObjectComplex(PropertyInfo? property, object? parent)
+ : base(property, parent)
+ {
+ PropertyInfo[] properties = Type.GetProperties();
+
+ object? value = Property?.GetValue(parent, null) ?? parent;
+
+ Fields = properties.Select(f => Resolve(f, value)).ToList();
+ }
+
+ public override ICollection GetTextRows()
+ {
+ List rows = [new() { Name = Name, Depth = Depth }];
+
+ if (!Collapsed)
+ {
+ rows.AddRange(Fields.SelectMany(f => f.GetTextRows()).ToList());
+ }
+
+ return rows;
+ }
+ }
+}
diff --git a/Pf2eViewer/EntityTreeViewerControl.resx b/Pf2eViewer/EntityTreeViewerControl.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/Pf2eViewer/EntityTreeViewerControl.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Pf2eViewer/Program.cs b/Pf2eViewer/Program.cs
index cef9888..2e0c427 100644
--- a/Pf2eViewer/Program.cs
+++ b/Pf2eViewer/Program.cs
@@ -11,6 +11,7 @@ internal static class Program
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
- Application.Run(new MainViewForm());
+ // Application.Run(new MainViewForm());
+ Application.Run(new TestForm());
}
}
diff --git a/Pf2eViewer/TestForm.Designer.cs b/Pf2eViewer/TestForm.Designer.cs
new file mode 100644
index 0000000..519a836
--- /dev/null
+++ b/Pf2eViewer/TestForm.Designer.cs
@@ -0,0 +1,57 @@
+namespace Pf2eViewer;
+
+partial class TestForm
+{
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ entityTreeViewerControl1 = new EntityTreeViewerControl();
+ SuspendLayout();
+ //
+ // entityTreeViewerControl1
+ //
+ entityTreeViewerControl1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
+ entityTreeViewerControl1.EntityView = null;
+ entityTreeViewerControl1.Location = new Point(12, 12);
+ entityTreeViewerControl1.Name = "entityTreeViewerControl1";
+ entityTreeViewerControl1.Size = new Size(426, 632);
+ entityTreeViewerControl1.TabIndex = 0;
+ //
+ // TestForm
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(450, 656);
+ Controls.Add(entityTreeViewerControl1);
+ Name = "TestForm";
+ Text = "TestForm";
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private EntityTreeViewerControl entityTreeViewerControl1;
+}
\ No newline at end of file
diff --git a/Pf2eViewer/TestForm.cs b/Pf2eViewer/TestForm.cs
new file mode 100644
index 0000000..c4ae87b
--- /dev/null
+++ b/Pf2eViewer/TestForm.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Pf2eModel;
+using Pf2eModel.Model.Base;
+
+namespace Pf2eViewer;
+
+public partial class TestForm : Form
+{
+ public TestForm()
+ {
+ InitializeComponent();
+
+ _ = new DarkModeCS(this) { ColorMode = DarkModeCS.DisplayMode.SystemDefault };
+
+ Pf2eDbContext context = new();
+ int count = context.Entities.Count();
+ int id = Random.Shared.Next(1, count + 1);
+
+ Entity entity = context.Entities.FirstOrDefault(e => e.Id == id)!;
+
+ EntityView view = new(context, entity.Type, id);
+ entityTreeViewerControl1.EntityView = view;
+ }
+}
diff --git a/Pf2eViewer/TestForm.resx b/Pf2eViewer/TestForm.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/Pf2eViewer/TestForm.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file