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;
///
/// Строка структуры, представляющая поле сущности.
///
internal class StructureRow : INotifyPropertyChanged
{
///
/// Отображаемая строка поля сущности.
///
public StructureField Field { get; }
///
/// Список типов лестницы.
///
public List Ladder { get; set; } = [];
///
/// Флаг наличия кнопки.
///
public bool HasButton =>
Field.FieldType == StructureFieldType.Complex && ((StructureFieldComplex)Field).Collapsable;
///
/// Флаг, указывающий, отображается ли строка.
///
public bool Visible => Field.Visible;
///
/// Флаг, указывающий, отображается ли строка.
///
public Visibility ItemVisibility => Visible ? Visibility.Visible : Visibility.Collapsed;
///
/// Флаг, указывающий, отображается ли строка.
///
public Visibility ButtonVisibility => HasButton ? Visibility.Visible : Visibility.Collapsed;
///
/// Иконка кнопки.
///
public string ButtonIcon =>
HasButton && !((StructureFieldComplex)Field).Collapsed
? IconChar.MinusSquare.ToChar()
: IconChar.PlusSquare.ToChar();
///
/// Глубина отображения поля.
///
public int Depth => Field.Depth;
///
/// Строковое представление названия поля.
///
public string Name => Field.Name;
///
/// Строковое представление типа поля.
///
public string Type
{
get
{
string result = Field.GetTypeString();
if (result != "")
{
result = $@"({result})";
}
return result;
}
}
///
/// Строковое представление значения поля.
///
public string Value => Field.GetValueString().Replace("\r", "").Replace("\n", "");
///
/// Цвет значения
///
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,
};
///
/// Команда переключения.
///
public ICommand CollapseCommand { get; }
///
/// Кониструктор класса .
///
/// Поле.
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));
}
///
/// Событие изменения поля.
///
public event Action? OnChange;
///
/// Изменение поля.
///
public event PropertyChangedEventHandler? PropertyChanged;
///
/// При изменении поля.
///
/// Название поля.
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new(propertyName));
}
}
///
/// Команда для сворачивания/разворачивания поля структуры.
///
/// Строка структуры, содержащая поле.
internal class CollapseCommand(StructureRow structureRow) : ICommand
{
///
/// Строка структуры, содержащая поле, для которого выполняется команда.
///
private StructureRow StructureRow { get; } = structureRow;
///
/// Событие, вызываемое при изменении возможности выполнения команды.
///
public event EventHandler? CanExecuteChanged;
///
/// Проверяет, может ли команда быть выполнена с указанным параметром.
///
/// Параметр, передаваемый команде.
/// true, если команда может быть выполнена; в противном случае false.
public bool CanExecute(object? parameter)
{
return true;
}
///
/// Выполняет команду с указанным параметром.
///
/// Параметр, передаваемый команде.
public void Execute(object? parameter)
{
StructureFieldComplex field = (StructureFieldComplex)StructureRow.Field;
field.Collapsed = !field.Collapsed;
}
}
///
/// Преобразователь, который адаптирует цвет в зависимости от типа целевого свойства.
///
public class ColorAdapterConverter : IMultiValueConverter
{
///
/// Смешивает два компнента цвета с заданным коэффициентом смешивания.
///
/// Первый компонент цвета.
/// Второй компонент цвета.
/// Коэффициент смешивания, где 0.0 означает полный компонент , а 1.0 означает полный компонент .
/// Смешанный компонент цвета.
private byte Mix(byte a, byte b, double rate) =>
System.Convert.ToByte(Math.Round(a * rate + b * (1 - rate)));
///
/// Преобразует массив значений в целевой тип, усредняя цвета.
///
/// Массив значений, содержащий цвета.
/// Целевой тип, в который нужно преобразовать значения.
/// Параметр преобразования, не используется.
/// Культура, используемая для преобразования, не используется.
/// Результат преобразования в целевой тип, который может быть null, если преобразование невозможно.
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> @switch = new()
{
{ typeof(Brush), () => new SolidColorBrush(resultColor) },
};
return @switch.TryGetValue(targetType, out Func