Документация проекта отображения.

This commit is contained in:
2025-05-10 18:05:09 +04:00
parent 54ef2cf331
commit 1a977ee988
8 changed files with 767 additions and 38 deletions
@@ -1,10 +1,17 @@
using System.ComponentModel;
using System.Diagnostics;
namespace Pf2eViewer.EntityTreeViewer;
/// <summary>
/// Элемент управления для отображения структуры сущности.
/// </summary>
public sealed partial class EntityTreeViewerControl : UserControl
{
#region "Поля элемента управления"
/// <summary>
/// Высота строки поля структуры.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("The height of each item in the tree view.")]
@@ -19,6 +26,9 @@ public sealed partial class EntityTreeViewerControl : UserControl
}
private int _itemHeight = 20;
/// <summary>
/// Сущность, которая будет отображаться в элементе управления.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
@@ -33,6 +43,9 @@ public sealed partial class EntityTreeViewerControl : UserControl
}
private EntityView? _entityView;
/// <summary>
/// Ширина отступа глубины.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("The size of tab.")]
@@ -47,6 +60,9 @@ public sealed partial class EntityTreeViewerControl : UserControl
}
private int _depthSize = 20;
/// <summary>
/// Размер шрифта типа поля сущности.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("The size of tab.")]
@@ -61,6 +77,9 @@ public sealed partial class EntityTreeViewerControl : UserControl
}
private float _typeFontSize = 9.5f;
/// <summary>
/// Размер кнопки плюс/минус.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("The size of plus/minus button.")]
@@ -75,11 +94,17 @@ public sealed partial class EntityTreeViewerControl : UserControl
}
private int _buttonSize = 20;
/// <summary>
/// Ширина имени поля сущности.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public int NameWidth { get; private set; } = 200;
/// <summary>
/// Цвет фона строки поля при наведении на элемент управления.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Entity Render")]
[Description("Color on item hover.")]
@@ -94,21 +119,50 @@ public sealed partial class EntityTreeViewerControl : UserControl
}
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;
/// <summary>
/// Изображение, используемое для отображения содержимого элемента управления.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public Bitmap ContentImage { get; set; }
#endregion
#region "Вычисляемые поля"
/// <summary>
/// Ширина области содержимого элемента управления.
/// </summary>
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public int ContentWidth => Width - SystemInformation.VerticalScrollBarWidth - 2;
#endregion
#region "Приватные поля"
/// <summary>
/// Коллекция полей структуры.
/// </summary>
private readonly List<StructureField> _rows = [];
/// <summary>
/// Коллекция строк полей структуры, которые будут отображаться в элементе управления.
/// </summary>
private List<EntityTreeViewerControlRow> _viewerRows = [];
/// <summary>
/// Флаг, указывающий, что элемент управления в данный момент перерисовывается.
/// </summary>
private bool _rendering;
#endregion
/// <summary>
/// Конструктор класса <see cref="EntityTreeViewerControl"/>.
/// </summary>
public EntityTreeViewerControl()
{
InitializeComponent();
@@ -120,6 +174,11 @@ public sealed partial class EntityTreeViewerControl : UserControl
ContentPanel.MouseWheel += ContentPanel_MouseWheel;
}
#region "Методы обновления"
/// <summary>
/// Обновление данных в элементе управления.
/// </summary>
public void UpdateData()
{
if (EntityView?.Entity is null)
@@ -148,6 +207,9 @@ public sealed partial class EntityTreeViewerControl : UserControl
UpdateRenders();
}
/// <summary>
/// Обновление отрисовок в элементе управления.
/// </summary>
public void UpdateRenders()
{
int maxNameWidth = -1;
@@ -171,6 +233,9 @@ public sealed partial class EntityTreeViewerControl : UserControl
UpdateView();
}
/// <summary>
/// Обновление отображения в элементе управления.
/// </summary>
public void UpdateView()
{
_viewerRows.ForEach(row => row.UpdateButton());
@@ -203,6 +268,14 @@ public sealed partial class EntityTreeViewerControl : UserControl
_rendering = false;
}
#endregion
#region "Вспомогательные методы"
/// <summary>
/// Построение лестницы для строк полей структуры.
/// </summary>
/// <param name="rows">Набор строк полей структуры.</param>
private void BuildLadder(List<EntityTreeViewerControlRow> rows)
{
List<LadderType> lastLadder = [];
@@ -248,8 +321,15 @@ public sealed partial class EntityTreeViewerControl : UserControl
}
}
// Events
#endregion
#region "События элемента управления"
/// <summary>
/// Обработчик события изменения размера элемента управления.
/// </summary>
/// <param name="sender">Источник события.</param>
/// <param name="e">Объект события.</param>
private void EntityTreeViewerControl_Resize(object sender, EventArgs e)
{
if (_rendering)
@@ -262,6 +342,11 @@ public sealed partial class EntityTreeViewerControl : UserControl
UpdateRenders();
}
/// <summary>
/// Обработчик события прокрутки элемента управления.
/// </summary>
/// <param name="sender">Источник события.</param>
/// <param name="e">Объект события.</param>
private void ContentPanel_MouseWheel(object? sender, MouseEventArgs e)
{
/*
@@ -281,6 +366,11 @@ public sealed partial class EntityTreeViewerControl : UserControl
*/
}
/// <summary>
/// Обработчик события движения мыши над элементом управления.
/// </summary>
/// <param name="sender">Источник события.</param>
/// <param name="e">Объект события.</param>
private void ContentPanel_MouseMove(object sender, MouseEventArgs e)
{
PointF p = new(e.X, e.Y);
@@ -299,4 +389,6 @@ public sealed partial class EntityTreeViewerControl : UserControl
row.Hovered = contained;
}
}
#endregion
}
@@ -5,13 +5,26 @@ using Image = System.Drawing.Image;
namespace Pf2eViewer.EntityTreeViewer;
/// <summary>
/// Элемент управления для отображения строки поля сущности.
/// </summary>
internal class EntityTreeViewerControlRow
{
/// <summary>
/// Элемент управления, которому принадлежит эта строка.
/// </summary>
public readonly EntityTreeViewerControl ParentControl;
/// <summary>
/// Отображаемая строка поля сущности.
/// </summary>
public readonly StructureField Item;
// Local fields
#region "Поля строки"
/// <summary>
/// Кэш изображения строки.
/// </summary>
public Image Cache
{
get
@@ -26,6 +39,9 @@ internal class EntityTreeViewerControlRow
}
private Image? _cache;
/// <summary>
/// Кэш изображения строки при наведении.
/// </summary>
public Image HoveredCache
{
get
@@ -40,6 +56,9 @@ internal class EntityTreeViewerControlRow
}
private Image? _hoveredCache;
/// <summary>
/// Список типов лестницы.
/// </summary>
public List<LadderType> Ladder
{
get => _ladder;
@@ -51,6 +70,9 @@ internal class EntityTreeViewerControlRow
}
private List<LadderType> _ladder = [];
/// <summary>
/// Проверяет, находится ли курсор над строкой.
/// </summary>
public bool Hovered
{
get => _hovered;
@@ -65,59 +87,103 @@ internal class EntityTreeViewerControlRow
}
private bool _hovered = false;
/// <summary>
/// Индекс строки в представлении.
/// </summary>
public int ViewIndex { get; set; } // = -1;
/// <summary>
/// Кнопка раскрытия/сворачивания.
/// </summary>
public IconButton? Button { get; set; } = null;
// Inherited fields
#endregion
#region "Поля для рендеринга"
/// <inheritdoc cref="EntityTreeViewerControl.Font"/>
public Font Font
{
get => ParentControl.Font;
set => ParentControl.Font = value;
}
/// <inheritdoc cref="EntityTreeViewerControl.ForeColor"/>
public Color ForeColor
{
get => ParentControl.ForeColor;
set => ParentControl.ForeColor = value;
}
/// <inheritdoc cref="EntityTreeViewerControl.BackColor"/>
public Color BackColor
{
get => ParentControl.BackColor;
set => ParentControl.BackColor = value;
}
/// <inheritdoc cref="EntityTreeViewerControl.HoverColor"/>
public Color HoverColor
{
get => ParentControl.HoverColor;
set => ParentControl.HoverColor = value;
}
/// <inheritdoc cref="EntityTreeViewerControl.ItemHeight"/>
public int ItemHeight
{
get => ParentControl.ItemHeight;
set => ParentControl.ItemHeight = value;
}
/// <inheritdoc cref="EntityTreeViewerControl.DepthSize"/>
public int DepthSize
{
get => ParentControl.DepthSize;
set => ParentControl.DepthSize = value;
}
/// <inheritdoc cref="EntityTreeViewerControl.ButtonSize"/>
public int ButtonSize
{
get => ParentControl.ButtonSize;
set => ParentControl.ButtonSize = value;
}
/// <inheritdoc cref="EntityTreeViewerControl.TypeFontSize"/>
public float TypeFontSize
{
get => ParentControl.TypeFontSize;
set => ParentControl.TypeFontSize = value;
}
// ValueText functions
#endregion
#region "Вычисляемые поля"
/// <summary>
/// Ширина строки.
/// </summary>
public int Width => ParentControl.ContentWidth;
/// <summary>
/// Высота строки.
/// </summary>
public int Height => ItemHeight;
/// <summary>
/// Флаг наличия кнопки.
/// </summary>
public bool HasButton => Item.FieldType == StructureFieldType.Complex;
/// <summary>
/// Глубина отображения строки.
/// </summary>
public int Depth => Item.Depth;
/// <summary>
/// Ширина имени в строке.
/// </summary>
public int NameWidth
{
get
@@ -127,6 +193,9 @@ internal class EntityTreeViewerControlRow
}
}
/// <summary>
/// Строковое представление типа поля.
/// </summary>
public string TypeText
{
get
@@ -140,10 +209,19 @@ internal class EntityTreeViewerControlRow
}
}
// public Font TypeFont => new(Font.FontFamily, TypeFontSize, FontStyle.Italic);
/// <summary>
/// Шрифт для отображения типа поля.
/// </summary>
public Font TypeFont => new(Font.FontFamily, TypeFontSize);
/// <summary>
/// Строковое представление значения поля.
/// </summary>
public string ValueText => Item.GetValueString();
/// <summary>
/// Шрифт для отображения значения поля.
/// </summary>
public Font ValueFont =>
new(
Font.FontFamily,
@@ -151,16 +229,31 @@ internal class EntityTreeViewerControlRow
Item.FieldType == StructureFieldType.Complex ? FontStyle.Italic : FontStyle.Regular
);
/// <summary>
/// Прямоугольник, занимаемый строкой в представлении.
/// </summary>
public RectangleF Target => new(0, ViewIndex * Height, Width, Height);
/// <summary>
/// Прямоугольник, занимаемый строкой в родительском представлении.
/// </summary>
public RectangleF RealTarget =>
new(0, ViewIndex * Height - ParentControl.VerticalScroll.Value, Width, Height);
// Simple fields
#endregion
/// <summary>
/// Список данных для рендеринга строк.
/// </summary>
private readonly List<StringRenderData> _renderData = [];
// Main methods
#region "Основные методы"
/// <summary>
/// Создание элемента управления строки поля сущности.
/// </summary>
/// <param name="parent">Родительский элемент управления.</param>
/// <param name="item">Строка поля структуры объекта.</param>
public EntityTreeViewerControlRow(EntityTreeViewerControl parent, StructureField item)
{
ParentControl = parent;
@@ -171,6 +264,9 @@ internal class EntityTreeViewerControlRow
UpdateButton();
}
/// <summary>
/// Применение свойств к элементу управления.
/// </summary>
private void ApplyItem()
{
_renderData.Clear();
@@ -200,12 +296,20 @@ internal class EntityTreeViewerControlRow
}
}
/// <summary>
/// Обновление кэша изображения строки.
/// </summary>
public void UpdateCache()
{
Cache = RenderCache(BackColor);
HoveredCache = RenderCache(HoverColor);
}
/// <summary>
/// Создание кэша изображения строки.
/// </summary>
/// <param name="backColor">Цвет заднего фона.</param>
/// <returns>Кеш изображения строки.</returns>
private Image RenderCache(Color backColor)
{
Image cache = new Bitmap(Width, Height);
@@ -220,6 +324,10 @@ internal class EntityTreeViewerControlRow
return cache;
}
/// <summary>
/// Запрос на перерисовку строки.
/// </summary>
/// <param name="g">Графический объект.</param>
public void Invalidate(Graphics? g = null)
{
g ??= Graphics.FromImage(ParentControl.ContentImage);
@@ -229,8 +337,13 @@ internal class EntityTreeViewerControlRow
UpdateButton();
}
// Button
#endregion
#region "Кнопка"
/// <summary>
/// Обновление кнопки раскрытия/сворачивания.
/// </summary>
public void UpdateButton()
{
if (Button is null)
@@ -250,6 +363,11 @@ internal class EntityTreeViewerControlRow
Button.Visible = Item.Visible;
}
/// <summary>
/// Событие нажатия кнопки раскрытия/сворачивания.
/// </summary>
/// <param name="sender">Источник события.</param>
/// <param name="e">Событие нажатие кнопки</param>
private void Button_Click(object? sender, EventArgs e)
{
if (Item is StructureFieldComplex complex)
@@ -259,8 +377,14 @@ internal class EntityTreeViewerControlRow
}
}
// Render
#endregion
#region "Отрисовка"
/// <summary>
/// Отрисовка лестницы.
/// </summary>
/// <param name="g">Графический объект.</param>
private void RenderLadder(Graphics g)
{
int n = Depth;
@@ -301,6 +425,10 @@ internal class EntityTreeViewerControlRow
}
}
/// <summary>
/// Отрисовка содержимого строки.
/// </summary>
/// <param name="g">Графический объект.</param>
private void RenderContent(Graphics g)
{
float[] xs =
@@ -326,13 +454,28 @@ internal class EntityTreeViewerControlRow
}
}
// Helper functions
#endregion
#region Функции-помощники в отрисовке
/// <summary>
/// Смешивание цвета с цветом текста.
/// </summary>
/// <param name="color">Цвет оттенка.</param>
/// <param name="rate">Степень смешения.</param>
/// <returns>Смешенный цвет.</returns>
private Color BlendColor(Color color, double rate = 0.5)
{
return BlendColor(ForeColor, color, rate);
}
/// <summary>
/// Смешивание цветов.
/// </summary>
/// <param name="color1">Первый смешиваемый цвет.</param>
/// <param name="color2">Второй смешиваемый цвет.</param>
/// <param name="rate">Степень смешения.</param>
/// <returns>Смешенный цвет.</returns>
private Color BlendColor(Color color1, Color color2, double rate)
{
return Color.FromArgb(
@@ -345,6 +488,10 @@ internal class EntityTreeViewerControlRow
int Mix(int a, int b) => Convert.ToInt32(Math.Round(a * rate + b * (1 - rate)));
}
/// <summary>
/// Получение цвета текста по типу значения поля.
/// </summary>
/// <returns>Цвет текста.</returns>
public Color GetValueColor()
{
return Item switch
@@ -363,19 +510,59 @@ internal class EntityTreeViewerControlRow
};
}
#endregion
/// <summary>
/// Класс для хранения данных рендеринга строки.
/// </summary>
/// <param name="text">Текст отображаемой строки.</param>
/// <param name="font">Шрифт отображаемой строки.</param>
/// <param name="color">Цвет отображаемой строки.</param>
private class StringRenderData(string text, Font font, Color color)
{
/// <summary>
/// Текст отображаемой строки.
/// </summary>
public string Text { get; } = text;
/// <summary>
/// Шрифт отображаемой строки.
/// </summary>
public Font Font { get; } = font;
/// <summary>
/// Цвет отображаемой строки.
/// </summary>
public Color Color { get; } = color;
/// <summary>
/// Левый край отображаемой строки.
/// </summary>
public float Left { get; set; }
/// <summary>
/// Ширина отображаемой строки.
/// </summary>
public float Width { get; set; }
/// <summary>
/// Высота отображаемой строки.
/// </summary>
public float Height { get; set; }
/// <summary>
/// Прямоугольник, занимаемый строкой.
/// </summary>
public RectangleF Rect => new(Left, 0, Width, Height);
private string Fit(Graphics g, RectangleF rect)
/// <summary>
/// Уместить строку в занимаемый прямоугольник.
/// </summary>
/// <param name="g">Элемент графики.</param>
/// <param name="rect">Занимаемый прямоугольник</param>
/// <param name="filler">Строка, на которую будет заканчиваться значнеие при переполнении.</param>
/// <returns></returns>
private string Fit(Graphics g, RectangleF rect, string filler = "…")
{
if (Text.Length == 0 || g.MeasureString(Text, Font).Width <= rect.Width)
{
@@ -386,16 +573,20 @@ internal class EntityTreeViewerControlRow
int i = txt.Length;
while (g.MeasureString(txt + "...", Font).Width > rect.Width)
while (g.MeasureString(txt + filler, Font).Width > rect.Width)
{
txt = txt[..--i];
if (i == 0)
break;
}
return txt + "...";
return txt + filler;
}
/// <summary>
/// Отрисовка строки.
/// </summary>
/// <param name="g">Элемент графики.</param>
public void Draw(Graphics g)
{
g.DrawString(
+229 -5
View File
@@ -5,10 +5,23 @@ using Pf2eModel.Model.Common.I18n;
namespace Pf2eViewer.EntityTreeViewer;
/// <summary>
/// Класс для построения структуры данных класса.
/// </summary>
internal class StructureBuilder
{
/// <summary>
/// Список обработанных объектов.
/// </summary>
private readonly List<StructureProcessedObject> _processedObjects = [];
/// <summary>
/// Создание поля структуры.
/// </summary>
/// <param name="name">Название поля.</param>
/// <param name="value">Значение поля.</param>
/// <param name="depth">Глубина, на котором поле отображается.</param>
/// <returns>Поле структуры.</returns>
public StructureFieldComplex Create(string name, object value, int depth = 0)
{
_ = RegisterProcessed(value);
@@ -20,6 +33,11 @@ internal class StructureBuilder
return field;
}
/// <summary>
/// Регистрация обработанного объекта.
/// </summary>
/// <param name="value">Регистрируемый объект.</param>
/// <returns>`true`, если объект был добавлен; `false`, если объект был добавлен ранее.</returns>
public bool RegisterProcessed(object value)
{
if (_processedObjects.Any(p => p.Value == value))
@@ -34,6 +52,11 @@ internal class StructureBuilder
return true;
}
/// <summary>
/// Дополнить обработанный объект.
/// </summary>
/// <param name="value">Значение.</param>
/// <param name="field">Поле объекта.</param>
public void CompleteProcessed(object value, StructureFieldComplex field)
{
StructureProcessedObject? q = _processedObjects.FirstOrDefault(p => p.Value == value);
@@ -46,6 +69,13 @@ internal class StructureBuilder
q.Field = field;
}
/// <summary>
/// Выбор поля структуры по значению.
/// </summary>
/// <param name="name">Название поля.</param>
/// <param name="value">Значение поля.</param>
/// <param name="depth">Глубина, на котором поле отображается.</param>
/// <returns></returns>
public StructureField Resolve(string name, object? value, int depth)
{
switch (GetFieldType(value))
@@ -87,6 +117,11 @@ internal class StructureBuilder
throw new("Impossible");
}
/// <summary>
/// Получить тип поля структуры по значению.
/// </summary>
/// <param name="value">Значение поля.</param>
/// <returns>Тип поля структуры.</returns>
public static StructureFieldType GetFieldType(object? value)
{
if (value is null)
@@ -110,6 +145,10 @@ internal class StructureBuilder
}
}
/// <summary>
/// Класс для хранения обработанного объекта.
/// </summary>
/// <param name="value">Объект.</param>
internal class StructureProcessedObject(object value)
{
public readonly object Value = value;
@@ -142,38 +181,109 @@ internal class StructureProcessedObject(object value)
}
}
/// <summary>
/// Тип поля структуры.
/// </summary>
internal enum StructureFieldType
{
/// <summary>
/// Пустое поле.
/// </summary>
Null,
/// <summary>
/// Простое поле.
/// </summary>
Primitive,
/// <summary>
/// Поле с перечислением.
/// </summary>
Enum,
/// <summary>
/// Поле с объектом.
/// </summary>
Complex,
/// <summary>
/// Поле с ссылкой на объект.
/// </summary>
Reference,
}
/// <summary>
/// Тип лестницы глубины.
/// </summary>
internal enum LadderType
{
/// <summary>
/// Пустой элемент: [ ].
/// </summary>
Empty,
/// <summary>
/// Последний элемент: [└].
/// </summary>
Last,
/// <summary>
/// Проходной элемент: [├] или [│].
/// </summary>
Through,
}
/// <summary>
/// Базовый класс для полей структуры.
/// </summary>
/// <param name="builder">Класс построения структуры данных.</param>
/// <param name="name">Название поля.</param>
/// <param name="depth">Глубина поля.</param>
internal abstract class StructureField(StructureBuilder builder, string name, int depth)
{
/// <summary>
/// Название поля.
/// </summary>
public readonly string Name = name;
/// <summary>
/// Тип поля структуры.
/// </summary>
public abstract StructureFieldType FieldType { get; }
/// <summary>
/// Класс построения структуры данных.
/// </summary>
public readonly StructureBuilder Builder = builder;
/// <summary>
/// Флаг, указывающий, отображается ли поле.
/// </summary>
public virtual bool Visible { get; set; } = true;
/// <summary>
/// Глубина поля структуры.
/// </summary>
public readonly int Depth = depth;
/// <summary>
/// Получить строку, представляющую тип поля.
/// </summary>
/// <returns>Строка, представляющая тип поля.</returns>
public abstract string GetTypeString();
/// <summary>
/// Получить строку, представляющую значение поля.
/// </summary>
/// <returns>Строка, представляющая значение поля.</returns>
public abstract string GetValueString();
/// <summary>
/// Получить набор строк, используя результат функция.
/// </summary>
/// <typeparam name="T">Тип результирующей строки.</typeparam>
/// <param name="func">Функция, оборажения поля в результирующую строку.</param>
/// <returns>Коллекция, содержащая набор строк.</returns>
public virtual ICollection<T> GetRows<T>(Func<StructureField, T> func)
{
StructureField[] q = [this];
@@ -181,16 +291,32 @@ internal abstract class StructureField(StructureBuilder builder, string name, in
}
}
/// <summary>
/// Пустое поле структуры.
/// </summary>
/// <param name="builder">Класс построения структуры данных.</param>
/// <param name="name">Название поля.</param>
/// <param name="depth">Глубина поля.</param>
internal class StructureFieldNull(StructureBuilder builder, string name, int depth)
: StructureField(builder, name, depth)
{
/// <inheritdoc/>
public override StructureFieldType FieldType => StructureFieldType.Null;
/// <inheritdoc/>
public override string GetTypeString() => "null";
/// <inheritdoc/>
public override string GetValueString() => "";
}
/// <summary>
/// Простое поле структуры.
/// </summary>
/// <param name="builder">Класс построения структуры данных.</param>
/// <param name="value">Значение поля.</param>
/// <param name="name">Название поля.</param>
/// <param name="depth">Глубина поля.</param>
internal class StructureFieldPrimitive(
StructureBuilder builder,
object value,
@@ -198,12 +324,20 @@ internal class StructureFieldPrimitive(
int depth
) : StructureField(builder, name, depth)
{
/// <inheritdoc/>
public override StructureFieldType FieldType => StructureFieldType.Primitive;
/// <summary>
/// Значение поля.
/// </summary>
public readonly object Value = value;
/// <summary>
/// Тип значения поля.
/// </summary>
public readonly Type Type = value.GetType();
/// <inheritdoc/>
public override string GetTypeString()
{
return Type.GetTypeCode(Type) switch
@@ -216,6 +350,7 @@ internal class StructureFieldPrimitive(
};
}
/// <inheritdoc/>
public override string GetValueString()
{
if (Type == typeof(string))
@@ -227,28 +362,57 @@ internal class StructureFieldPrimitive(
}
}
/// <summary>
/// Поле структуры с перечислением.
/// </summary>
/// <param name="builder">Класс построения структуры данных.</param>
/// <param name="value">Значение поля.</param>
/// <param name="name">Название поля.</param>
/// <param name="depth">Глубина поля.</param>
internal class StructureFieldEnum(StructureBuilder builder, object value, string name, int depth)
: StructureField(builder, name, depth)
{
/// <inheritdoc/>
public override StructureFieldType FieldType => StructureFieldType.Enum;
/// <summary>
/// Значение поля.
/// </summary>
public readonly object Value = value;
/// <summary>
/// Тип значения поля.
/// </summary>
public readonly Type Type = value.GetType();
/// <inheritdoc/>
public override string GetTypeString() => "enum";
/// <inheritdoc/>
public override string GetValueString() => $"{Type.Name}.{Value}";
}
/// <summary>
/// Поле стркутуры с объектом.
/// </summary>
internal class StructureFieldComplex : StructureField
{
/// <inheritdoc/>
public override StructureFieldType FieldType => StructureFieldType.Complex;
/// <summary>
/// Набор полей объекта.
/// </summary>
public readonly List<StructureField> Fields = [];
/// <summary>
/// Тип значения поля.
/// </summary>
public readonly Type Type;
/// <summary>
/// Флаг, указывающий, отображается ли поля объекта.
/// </summary>
public bool Collapsed
{
get => _collapsed;
@@ -260,6 +424,7 @@ internal class StructureFieldComplex : StructureField
}
private bool _collapsed = false;
/// <inheritdoc/>
public override bool Visible
{
get => _visible;
@@ -271,6 +436,13 @@ internal class StructureFieldComplex : StructureField
}
private bool _visible = true;
/// <summary>
/// Конструктор класса поля структуры с объектом.
/// </summary>
/// <param name="builder">Класс построения структуры данных.</param>
/// <param name="value">Значение поля.</param>
/// <param name="name">Название поля.</param>
/// <param name="depth">Глубина поля.</param>
public StructureFieldComplex(StructureBuilder builder, object value, string name, int depth)
: base(builder, name, depth)
{
@@ -279,6 +451,9 @@ internal class StructureFieldComplex : StructureField
SetFields((dynamic)value);
}
/// <summary>
/// Обновить видимость полей структуры.
/// </summary>
private void UpdateFieldVisibility()
{
foreach (StructureField field in Fields)
@@ -287,6 +462,10 @@ internal class StructureFieldComplex : StructureField
}
}
/// <summary>
/// Установить поля структуры `LocaleString`.
/// </summary>
/// <param name="localeString">Объект строки локализации.</param>
private void SetFields(LocaleString localeString)
{
SetFieldsFromRecords(
@@ -296,6 +475,10 @@ internal class StructureFieldComplex : StructureField
);
}
/// <summary>
/// Установить поля структуры `IEnumerable`.
/// </summary>
/// <param name="enumerable">Объект-перечисление.</param>
private void SetFields(IEnumerable enumerable)
{
int i = 0;
@@ -310,6 +493,10 @@ internal class StructureFieldComplex : StructureField
SetFieldsFromRecords(records);
}
/// <summary>
/// Установить поля структуры общего объекта.
/// </summary>
/// <param name="value">Объект.</param>
private void SetFields(object value)
{
Type type = value.GetType();
@@ -325,6 +512,10 @@ internal class StructureFieldComplex : StructureField
);
}
/// <summary>
/// Установить поля структуры из списка записей.
/// </summary>
/// <param name="records"></param>
private void SetFieldsFromRecords(List<FieldRecord> records)
{
foreach (
@@ -346,22 +537,35 @@ internal class StructureFieldComplex : StructureField
}
}
public override ICollection<T> GetRows<T>(Func<StructureField, T> func)
{
return [.. base.GetRows(func), .. Fields.SelectMany(f => f.GetRows(func)).ToList()];
}
/// <summary>
/// Запись поля структуры.
/// </summary>
/// <param name="name">Название поля.</param>
/// <param name="value">Значение поля.</param>
private class FieldRecord(string name, object? value)
{
/// <summary>
/// Название поля.
/// </summary>
public readonly string Name = name;
/// <summary>
/// Значение поля.
/// </summary>
public readonly object? Value = value;
/// <summary>
/// Тип поля структуры.
/// </summary>
public StructureFieldType FieldType => StructureBuilder.GetFieldType(Value);
/// <summary>
/// Флаг, указывающий, использовать ли поле.
/// </summary>
public bool Allowed = true;
}
/// <inheritdoc/>
public override string GetTypeString()
{
if (Type.IsGenericEnumerableType())
@@ -376,6 +580,7 @@ internal class StructureFieldComplex : StructureField
}
}
/// <inheritdoc/>
public override string GetValueString()
{
if (Type.IsGenericEnumerableType())
@@ -384,8 +589,21 @@ internal class StructureFieldComplex : StructureField
}
return "";
}
/// <inheritdoc/>
public override ICollection<T> GetRows<T>(Func<StructureField, T> func)
{
return [.. base.GetRows(func), .. Fields.SelectMany(f => f.GetRows(func)).ToList()];
}
}
/// <summary>
/// Поле структуры с ссылкой на объект.
/// </summary>
/// <param name="builder">Класс построения структуры данных.</param>
/// <param name="name">Название поля.</param>
/// <param name="reference">Ссылка на объект.</param>
/// <param name="depth">Глубина поля.</param>
internal class StructureFieldReference(
StructureBuilder builder,
string name,
@@ -393,11 +611,17 @@ internal class StructureFieldReference(
int depth
) : StructureField(builder, name, depth)
{
/// <summary>
/// Ссылка на объект.
/// </summary>
public StructureFieldComplex? Reference = reference;
/// <inheritdoc/>
public override StructureFieldType FieldType => StructureFieldType.Reference;
/// <inheritdoc/>
public override string GetTypeString() => Reference?.GetTypeString() ?? "???";
/// <inheritdoc/>
public override string GetValueString() => "<Reference>";
}