247 lines
9.5 KiB
C#
247 lines
9.5 KiB
C#
namespace QWERTYkez.ExcelProcessor;
|
||
|
||
/// <summary>
|
||
/// Определяет выравнивание содержимого ячейки: горизонтальное, вертикальное, перенос текста и уменьшение по размеру.
|
||
/// Все свойства опциональны. Если свойство не задано, соответствующий аспект не изменяется.
|
||
/// </summary>
|
||
public readonly struct CellAlign : IEquatable<CellAlign>
|
||
{
|
||
/// <summary>Горизонтальное выравнивание.</summary>
|
||
public CellAlignHorizontal? Horizontal { get; init; }
|
||
|
||
/// <summary>Вертикальное выравнивание.</summary>
|
||
public CellAlignVertical? Vertical { get; init; }
|
||
|
||
/// <summary>Переносить ли текст по словам (многострочный режим).</summary>
|
||
public bool? WrapText { get; init; }
|
||
|
||
/// <summary>Уменьшать размер шрифта, чтобы текст поместился в ячейку.</summary>
|
||
public bool? ShrinkToFit { get; init; }
|
||
|
||
|
||
internal bool TryMerge(CellAlign other, out CellAlign result)
|
||
{
|
||
// Если other не содержит новых значений, возвращаем this
|
||
if (other.Horizontal == Horizontal &&
|
||
other.Vertical == Vertical &&
|
||
other.WrapText == WrapText &&
|
||
other.ShrinkToFit == ShrinkToFit)
|
||
{
|
||
result = default;
|
||
return false;
|
||
}
|
||
|
||
result = new CellAlign
|
||
{
|
||
Horizontal = other.Horizontal ?? Horizontal,
|
||
Vertical = other.Vertical ?? Vertical,
|
||
WrapText = other.WrapText ?? WrapText,
|
||
ShrinkToFit = other.ShrinkToFit ?? ShrinkToFit
|
||
};
|
||
return true;
|
||
}
|
||
|
||
|
||
/// <summary>Преобразует горизонтальное выравнивание в тип Open XML.</summary>
|
||
public bool TryGetExcelHorizontalAlignment(out HorizontalAlignmentValues value)
|
||
{
|
||
if (Horizontal.HasValue)
|
||
{
|
||
value = Horizontal.Value switch
|
||
{
|
||
CellAlignHorizontal.Left => HorizontalAlignmentValues.Left,
|
||
CellAlignHorizontal.Center => HorizontalAlignmentValues.Center,
|
||
CellAlignHorizontal.Right => HorizontalAlignmentValues.Right,
|
||
CellAlignHorizontal.Fill => HorizontalAlignmentValues.Fill,
|
||
CellAlignHorizontal.Justify => HorizontalAlignmentValues.Justify,
|
||
CellAlignHorizontal.CenterContinuous => HorizontalAlignmentValues.CenterContinuous,
|
||
CellAlignHorizontal.Distributed => HorizontalAlignmentValues.Distributed,
|
||
_ => throw new NotSupportedException($"Unsupported horizontal alignment: {Horizontal.Value}")
|
||
};
|
||
return true;
|
||
}
|
||
value = default;
|
||
return false;
|
||
}
|
||
|
||
/// <summary>Преобразует вертикальное выравнивание в тип Open XML.</summary>
|
||
public bool TryGetExcelVerticalAlignment(out VerticalAlignmentValues value)
|
||
{
|
||
if (Vertical.HasValue)
|
||
{
|
||
value = Vertical.Value switch
|
||
{
|
||
CellAlignVertical.Top => VerticalAlignmentValues.Top,
|
||
CellAlignVertical.Center => VerticalAlignmentValues.Center,
|
||
CellAlignVertical.Bottom => VerticalAlignmentValues.Bottom,
|
||
CellAlignVertical.Justify => VerticalAlignmentValues.Justify,
|
||
CellAlignVertical.Distributed => VerticalAlignmentValues.Distributed,
|
||
_ => throw new NotSupportedException($"Unsupported vertical alignment: {Vertical.Value}")
|
||
};
|
||
return true;
|
||
}
|
||
value = default;
|
||
return false;
|
||
}
|
||
|
||
/// <summary>Создаёт элемент Alignment для Open XML.</summary>
|
||
public Alignment? ToAlignment()
|
||
{
|
||
if (!Horizontal.HasValue && !Vertical.HasValue && !WrapText.HasValue && !ShrinkToFit.HasValue)
|
||
return null;
|
||
|
||
var align = new Alignment();
|
||
if (TryGetExcelHorizontalAlignment(out var hAlign))
|
||
align.Horizontal = hAlign;
|
||
if (TryGetExcelVerticalAlignment(out var vAlign))
|
||
align.Vertical = vAlign;
|
||
if (WrapText.HasValue)
|
||
align.WrapText = WrapText.Value;
|
||
if (ShrinkToFit.HasValue)
|
||
align.ShrinkToFit = ShrinkToFit.Value;
|
||
return align;
|
||
}
|
||
|
||
/// <summary>Создаёт CellAlign из элемента Alignment Open XML.</summary>
|
||
public static CellAlign FromAlignment(Alignment? alignment)
|
||
{
|
||
if (alignment == null)
|
||
return default;
|
||
|
||
var result = new CellAlign();
|
||
if (alignment.Horizontal?.Value is { } horizontal)
|
||
{
|
||
result = result with { Horizontal = MapHorizontalFromExcel(horizontal) };
|
||
}
|
||
if (alignment.Vertical?.Value is { } vertical)
|
||
{
|
||
result = result with { Vertical = MapVerticalFromExcel(vertical) };
|
||
}
|
||
if (alignment.WrapText?.Value is { } wrapText)
|
||
{
|
||
result = result with { WrapText = wrapText };
|
||
}
|
||
if (alignment.ShrinkToFit?.Value is { } shrinkToFit)
|
||
{
|
||
result = result with { ShrinkToFit = shrinkToFit };
|
||
}
|
||
return result;
|
||
}
|
||
|
||
static CellAlignHorizontal MapHorizontalFromExcel(HorizontalAlignmentValues value)
|
||
{
|
||
if (value == HorizontalAlignmentValues.Left)
|
||
{
|
||
return CellAlignHorizontal.Left;
|
||
}
|
||
else if (value == HorizontalAlignmentValues.Center)
|
||
{
|
||
return CellAlignHorizontal.Center;
|
||
}
|
||
else if (value == HorizontalAlignmentValues.Right)
|
||
{
|
||
return CellAlignHorizontal.Right;
|
||
}
|
||
else if (value == HorizontalAlignmentValues.Fill)
|
||
{
|
||
return CellAlignHorizontal.Fill;
|
||
}
|
||
else if (value == HorizontalAlignmentValues.Justify)
|
||
{
|
||
return CellAlignHorizontal.Justify;
|
||
}
|
||
else if (value == HorizontalAlignmentValues.CenterContinuous)
|
||
{
|
||
return CellAlignHorizontal.CenterContinuous;
|
||
}
|
||
else if (value == HorizontalAlignmentValues.Distributed)
|
||
{
|
||
return CellAlignHorizontal.Distributed;
|
||
}
|
||
else throw new NotSupportedException($"Unsupported horizontal alignment: {value}");
|
||
}
|
||
|
||
static CellAlignVertical MapVerticalFromExcel(VerticalAlignmentValues value)
|
||
{
|
||
if (value == VerticalAlignmentValues.Top)
|
||
{
|
||
return CellAlignVertical.Top;
|
||
}
|
||
else if (value == VerticalAlignmentValues.Center)
|
||
{
|
||
return CellAlignVertical.Center;
|
||
}
|
||
else if (value == VerticalAlignmentValues.Bottom)
|
||
{
|
||
return CellAlignVertical.Bottom;
|
||
}
|
||
else if (value == VerticalAlignmentValues.Justify)
|
||
{
|
||
return CellAlignVertical.Justify;
|
||
}
|
||
else if (value == VerticalAlignmentValues.Distributed)
|
||
{
|
||
return CellAlignVertical.Distributed;
|
||
}
|
||
else throw new NotSupportedException($"Unsupported vertical alignment: {value}");
|
||
}
|
||
|
||
public override bool Equals(object? obj) => obj is CellAlign other && Equals(other);
|
||
public bool Equals(CellAlign other) => this == other;
|
||
|
||
public static bool operator ==(CellAlign left, CellAlign right) =>
|
||
left.Horizontal == right.Horizontal &&
|
||
left.Vertical == right.Vertical &&
|
||
left.WrapText == right.WrapText &&
|
||
left.ShrinkToFit == right.ShrinkToFit;
|
||
|
||
public static bool operator !=(CellAlign left, CellAlign right) => !(left == right);
|
||
|
||
public override int GetHashCode()
|
||
{
|
||
unchecked
|
||
{
|
||
int hash = 17;
|
||
hash = hash * 31 + (Horizontal?.GetHashCode() ?? 0);
|
||
hash = hash * 31 + (Vertical?.GetHashCode() ?? 0);
|
||
hash = hash * 31 + (WrapText?.GetHashCode() ?? 0);
|
||
hash = hash * 31 + (ShrinkToFit?.GetHashCode() ?? 0);
|
||
return hash;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>Горизонтальное выравнивание содержимого ячейки.</summary>
|
||
public enum CellAlignHorizontal
|
||
{
|
||
/// <summary>По левому краю.</summary>
|
||
Left,
|
||
/// <summary>По центру.</summary>
|
||
Center,
|
||
/// <summary>По правому краю.</summary>
|
||
Right,
|
||
/// <summary>Заполнение (повтор содержимого для заполнения ширины).</summary>
|
||
Fill,
|
||
/// <summary>По ширине (для многострочного текста).</summary>
|
||
Justify,
|
||
/// <summary>Центрирование по выделенным ячейкам (визуально, без объединения).</summary>
|
||
CenterContinuous,
|
||
/// <summary>Распределённый (выравнивание по ширине с пробелами).</summary>
|
||
Distributed,
|
||
}
|
||
|
||
/// <summary>Вертикальное выравнивание содержимого ячейки.</summary>
|
||
public enum CellAlignVertical
|
||
{
|
||
/// <summary>По верхнему краю.</summary>
|
||
Top,
|
||
/// <summary>По центру.</summary>
|
||
Center,
|
||
/// <summary>По нижнему краю (значение по умолчанию).</summary>
|
||
Bottom,
|
||
/// <summary>По высоте (для многострочного текста).</summary>
|
||
Justify,
|
||
/// <summary>Распределённый по вертикали.</summary>
|
||
Distributed,
|
||
} |