Files
Pf2eDataScrapper/Pf2e/WPF/EntityViewer/EntityViewStructure/StructureRow.cs
T

272 lines
9.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using FontAwesome.Sharp;
using Color = System.Windows.Media.Color;
namespace Pf2e.WPF.EntityViewer.EntityViewStructure;
/// <summary>
/// Строка структуры, представляющая поле сущности.
/// </summary>
internal class StructureRow : INotifyPropertyChanged
{
/// <summary>
/// Отображаемая строка поля сущности.
/// </summary>
public StructureField Field { get; }
/// <summary>
/// Список типов лестницы.
/// </summary>
public List<LadderType> Ladder { get; set; } = [];
/// <summary>
/// Флаг наличия кнопки.
/// </summary>
public bool HasButton =>
Field.FieldType == StructureFieldType.Complex && ((StructureFieldComplex)Field).Collapsable;
/// <summary>
/// Флаг, указывающий, отображается ли строка.
/// </summary>
public bool Visible => Field.Visible;
/// <summary>
/// Флаг, указывающий, отображается ли строка.
/// </summary>
public Visibility ItemVisibility => Visible ? Visibility.Visible : Visibility.Collapsed;
/// <summary>
/// Флаг, указывающий, отображается ли строка.
/// </summary>
public Visibility ButtonVisibility => HasButton ? Visibility.Visible : Visibility.Collapsed;
/// <summary>
/// Иконка кнопки.
/// </summary>
public string ButtonIcon =>
HasButton && !((StructureFieldComplex)Field).Collapsed
? IconChar.MinusSquare.ToChar()
: IconChar.PlusSquare.ToChar();
/// <summary>
/// Глубина отображения поля.
/// </summary>
public int Depth => Field.Depth;
/// <summary>
/// Строковое представление названия поля.
/// </summary>
public string Name => Field.Name;
/// <summary>
/// Строковое представление типа поля.
/// </summary>
public string Type
{
get
{
string result = Field.GetTypeString();
if (result != "")
{
result = $@"({result})";
}
return result;
}
}
/// <summary>
/// Строковое представление значения поля.
/// </summary>
public string Value => Field.GetValueString().Replace("\r", "").Replace("\n", "");
/// <summary>
/// Цвет значения
/// </summary>
public Color? AccentColor =>
Field switch
{
StructureFieldPrimitive primitive => System.Type.GetTypeCode(primitive.Type) switch
{
TypeCode.Boolean => Colors.DarkGoldenrod,
TypeCode.Int32 => Colors.Blue,
TypeCode.Double => Colors.Aqua,
TypeCode.String => Colors.Green,
_ => null,
},
StructureFieldEnum => Colors.Red,
StructureFieldNull => Colors.Transparent,
_ => null,
};
/// <summary>
/// Команда переключения.
/// </summary>
public ICommand CollapseCommand { get; }
/// <summary>
/// Кониструктор класса <see cref="StructureRow"/>.
/// </summary>
/// <param name="field">Поле.</param>
public StructureRow(StructureField field)
{
Field = field;
CollapseCommand = new CollapseCommand(this);
Field.PropertyChanged += Field_PropertyChanged;
}
private void Field_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(nameof(Field));
OnPropertyChanged(nameof(Visible));
OnPropertyChanged(nameof(ItemVisibility));
OnPropertyChanged(nameof(ButtonVisibility));
OnPropertyChanged(nameof(ButtonIcon));
}
/// <summary>
/// Событие изменения поля.
/// </summary>
public event Action<StructureRow, StructureField>? OnChange;
/// <summary>
/// Изменение поля.
/// </summary>
public event PropertyChangedEventHandler? PropertyChanged;
/// <summary>
/// При изменении поля.
/// </summary>
/// <param name="propertyName">Название поля.</param>
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new(propertyName));
}
}
/// <summary>
/// Команда для сворачивания/разворачивания поля структуры.
/// </summary>
/// <param name="structureRow">Строка структуры, содержащая поле.</param>
internal class CollapseCommand(StructureRow structureRow) : ICommand
{
/// <summary>
/// Строка структуры, содержащая поле, для которого выполняется команда.
/// </summary>
private StructureRow StructureRow { get; } = structureRow;
/// <summary>
/// Событие, вызываемое при изменении возможности выполнения команды.
/// </summary>
public event EventHandler? CanExecuteChanged;
/// <summary>
/// Проверяет, может ли команда быть выполнена с указанным параметром.
/// </summary>
/// <param name="parameter">Параметр, передаваемый команде.</param>
/// <returns><c>true</c>, если команда может быть выполнена; в противном случае <c>false</c>.</returns>
public bool CanExecute(object? parameter)
{
return true;
}
/// <summary>
/// Выполняет команду с указанным параметром.
/// </summary>
/// <param name="parameter">Параметр, передаваемый команде.</param>
public void Execute(object? parameter)
{
StructureFieldComplex field = (StructureFieldComplex)StructureRow.Field;
field.Collapsed = !field.Collapsed;
}
}
/// <summary>
/// Преобразователь, который адаптирует цвет в зависимости от типа целевого свойства.
/// </summary>
public class ColorAdapterConverter : IMultiValueConverter
{
/// <summary>
/// Смешивает два компнента цвета с заданным коэффициентом смешивания.
/// </summary>
/// <param name="a">Первый компонент цвета.</param>
/// <param name="b">Второй компонент цвета.</param>
/// <param name="rate">Коэффициент смешивания, где 0.0 означает полный компонент <paramref name="a"/>, а 1.0 означает полный компонент <paramref name="b"/>.</param>
/// <returns>Смешанный компонент цвета.</returns>
private byte Mix(byte a, byte b, double rate) =>
System.Convert.ToByte(Math.Round(a * rate + b * (1 - rate)));
/// <summary>
/// Преобразует массив значений в целевой тип, усредняя цвета.
/// </summary>
/// <param name="value">Массив значений, содержащий цвета.</param>
/// <param name="targetType">Целевой тип, в который нужно преобразовать значения.</param>
/// <param name="parameter">Параметр преобразования, не используется.</param>
/// <param name="culture">Культура, используемая для преобразования, не используется.</param>
/// <returns>Результат преобразования в целевой тип, который может быть <c>null</c>, если преобразование невозможно.</returns>
public object? Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
{
Color textColor = SystemColors.WindowTextColor;
double a = textColor.A;
double r = textColor.R;
double g = textColor.G;
double b = textColor.B;
int n = 1 + value.Length;
foreach (object item in value)
{
if (item is not Color color)
{
n--;
continue;
}
a += color.A;
r += color.R;
g += color.G;
b += color.B;
}
Color resultColor = Color.FromArgb(
System.Convert.ToByte(Math.Round(a / n)),
System.Convert.ToByte(Math.Round(r / n)),
System.Convert.ToByte(Math.Round(g / n)),
System.Convert.ToByte(Math.Round(b / n))
);
Dictionary<Type, Func<object>> @switch = new()
{
{ typeof(Brush), () => new SolidColorBrush(resultColor) },
};
return @switch.TryGetValue(targetType, out Func<object>? action) ? action() : null;
}
/// <summary>
/// Преобразует значение обратно в массив типов, но не реализован.
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public object[] ConvertBack(
object value,
Type[] targetType,
object parameter,
CultureInfo culture
)
{
throw new NotImplementedException();
}
}