5 Commits

Author SHA1 Message Date
melekhin
08b39b7bfe Sheet.TryMergeBy...()
All checks were successful
Publish NuGet packages / publish (push) Successful in 23s
2026-06-17 10:39:00 +07:00
melekhin
c9ef2a796e Remove ICellText
All checks were successful
Publish NuGet packages / publish (push) Successful in 27s
2026-06-17 09:33:21 +07:00
melekhin
eccb12b83c Text() debug
All checks were successful
Publish NuGet packages / publish (push) Successful in 25s
2026-06-16 15:52:08 +07:00
melekhin
804fc84563 ICellText rename
All checks were successful
Publish NuGet packages / publish (push) Successful in 26s
2026-06-16 12:03:56 +07:00
melekhin
282be475d5 Formula Debug
All checks were successful
Publish NuGet packages / publish (push) Successful in 27s
2026-06-15 14:37:25 +07:00
6 changed files with 713 additions and 669 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,270 +0,0 @@
namespace QWERTYkez.ExcelProcessor;
/// <summary>
/// Внутренняя реализация <see cref="ICellText"/> для работы с богатым текстом ячейки.
/// Хранит коллекцию фрагментов <see cref="ExcelRun"/>.
/// Минимизирует аллокации, не использует рефлексию.
/// </summary>
internal sealed class ExcelCellText : ICellText
{
private List<IRun>? _runs;
/// <inheritdoc />
public int Count => _runs?.Count ?? 0;
/// <inheritdoc />
public IEnumerable<IRun> GetRuns()
{
if (_runs is null)
return [];
// Возвращаем сам список, чтобы избежать копирования.
// Вызывающий не должен модифицировать коллекцию.
return _runs;
}
/// <inheritdoc />
public IRun? GetRunAt(int index)
{
if (_runs is null || index < 0 || index >= _runs.Count)
return null;
return _runs[index];
}
/// <inheritdoc />
public bool TryGetRunAt(int index, out IRun run)
{
run = GetRunAt(index)!;
return run != null;
}
/// <inheritdoc />
public IRun? First()
{
if (_runs is null || _runs.Count == 0)
return null;
return _runs[0];
}
/// <inheritdoc />
public bool TryGetFirst(out IRun run)
{
run = First()!;
return run != null;
}
/// <inheritdoc />
public IRun? Last()
{
if (_runs is null || _runs.Count == 0)
return null;
return _runs[_runs.Count - 1];
}
/// <inheritdoc />
public bool TryGetLast(out IRun run)
{
run = Last()!;
return run != null;
}
/// <inheritdoc />
public bool TryRemoveRun(IRun run)
{
if (run is null || _runs is null)
return false;
return _runs.Remove(run);
}
/// <inheritdoc />
public bool TryRemoveRun(int index)
{
if (_runs is null || index < 0 || index >= _runs.Count)
return false;
_runs.RemoveAt(index);
return true;
}
/// <inheritdoc />
public bool TryRemoveRun(int index, out IRun? removed)
{
removed = GetRunAt(index);
if (removed is null)
return false;
return TryRemoveRun(index);
}
/// <inheritdoc />
public ICellText AddBreak()
{
// Добавляем символ переноса строки в последний существующий Run
if (_runs != null && _runs.Count > 0)
{
var lastRun = _runs[_runs.Count - 1];
lastRun.Text += "\n";
}
else
{
// Если нет ни одного Run, создаём новый с символом переноса
AddRun("\n", null);
}
return this;
}
/// <inheritdoc />
public ICellText AddRun(string text, RunFormat? format = null)
{
if (string.IsNullOrEmpty(text))
return this;
_runs ??= [];
var run = new ExcelRun { Text = text, Format = format };
_runs.Add(run);
return this;
}
/// <inheritdoc />
public ICellText AddRunBreak(string text, RunFormat? format = null)
{
AddRun(text, format);
AddBreak();
return this;
}
/// <inheritdoc />
public ICellText AddSubRun(string text, RunFormat? format = null)
{
var subFormat = format is { } fmt
? new RunFormat
{
IsBold = fmt.IsBold,
IsItalic = fmt.IsItalic,
Underline = fmt.Underline,
IsStrike = fmt.IsStrike,
Color = fmt.Color,
FontSize = fmt.FontSize,
FontFamily = fmt.FontFamily,
Vertical = VerticalTextRunAlignment.Subscript
}
: new RunFormat { Vertical = VerticalTextRunAlignment.Subscript };
return AddRun(text, subFormat);
}
/// <inheritdoc />
public ICellText AddSupRun(string text, RunFormat? format = null)
{
var supFormat = format is { } fmt
? new RunFormat
{
IsBold = fmt.IsBold,
IsItalic = fmt.IsItalic,
Underline = fmt.Underline,
IsStrike = fmt.IsStrike,
Color = fmt.Color,
FontSize = fmt.FontSize,
FontFamily = fmt.FontFamily,
Vertical = VerticalTextRunAlignment.Subscript
}
: new RunFormat { Vertical = VerticalTextRunAlignment.Superscript };
return AddRun(text, supFormat);
}
/// <inheritdoc />
public bool TryInsertRun(int index, string text, RunFormat? format = null)
{
if (index < 0 || string.IsNullOrEmpty(text))
return false;
_runs ??= [];
if (index > _runs.Count)
return false;
var run = new ExcelRun { Text = text, Format = format };
_runs.Insert(index, run);
return true;
}
/// <inheritdoc />
public bool TryInsertRunBreak(int index, string text, RunFormat? format = null)
{
if (!TryInsertRun(index, text, format))
return false;
// После вставленного run добавляем break на следующей позиции
AddBreak();
// Сдвигаем? Просто добавляем break в конец неверно. Break должен быть сразу после вставленного.
// Но AddBreak добавляет в конец. Нужно вставить break на index+1.
return TryInsertRun(index + 1, "\n", null);
}
/// <inheritdoc />
public bool TryInsertSubRun(int index, string text, RunFormat? format = null)
{
var subFormat = format is { } fmt
? new RunFormat
{
IsBold = fmt.IsBold,
IsItalic = fmt.IsItalic,
Underline = fmt.Underline,
IsStrike = fmt.IsStrike,
Color = fmt.Color,
FontSize = fmt.FontSize,
FontFamily = fmt.FontFamily,
Vertical = VerticalTextRunAlignment.Subscript
}
: new RunFormat { Vertical = VerticalTextRunAlignment.Subscript };
return TryInsertRun(index, text, subFormat);
}
/// <inheritdoc />
public bool TryInsertSupRun(int index, string text, RunFormat? format = null)
{
var supFormat = format is { } fmt
? new RunFormat
{
IsBold = fmt.IsBold,
IsItalic = fmt.IsItalic,
Underline = fmt.Underline,
IsStrike = fmt.IsStrike,
Color = fmt.Color,
FontSize = fmt.FontSize,
FontFamily = fmt.FontFamily,
Vertical = VerticalTextRunAlignment.Subscript
}
: new RunFormat { Vertical = VerticalTextRunAlignment.Superscript };
return TryInsertRun(index, text, supFormat);
}
/// <inheritdoc />
public void ApplyFormatToAllRuns(RunFormat format)
{
if (_runs is null || _runs.Count == 0)
return;
foreach (var run in _runs)
{
if (run is ExcelRun xRun)
{
// Объединение форматов: ненулевые свойства overlay заменяют значения в base.
var baseFmt = xRun.Format ?? new RunFormat();
xRun.Format = MergeRunFormat(baseFmt, format);
}
}
}
/// <inheritdoc />
public void Clear()
{
_runs?.Clear();
_runs = null;
}
private static RunFormat MergeRunFormat(RunFormat baseFmt, RunFormat overlay)
{
return new RunFormat
{
IsBold = overlay.IsBold ?? baseFmt.IsBold,
IsItalic = overlay.IsItalic ?? baseFmt.IsItalic,
Underline = overlay.Underline ?? baseFmt.Underline,
IsStrike = overlay.IsStrike ?? baseFmt.IsStrike,
Color = overlay.Color ?? baseFmt.Color,
FontSize = overlay.FontSize ?? baseFmt.FontSize,
FontFamily = overlay.FontFamily ?? baseFmt.FontFamily,
Vertical = overlay.Vertical ?? baseFmt.Vertical
};
}
}

View File

@@ -212,20 +212,63 @@ internal sealed class ExcelSheet : ISheet
/// <inheritdoc />
public IRange RangeByIndexes(uint startRow, uint startCol, uint endRow, uint endCol)
{
return new ExcelRange(Book, this, startRow, startCol, endRow, endCol);
if (startRow == 0) throw new ArgumentException("startRow must be >= 1", nameof(startRow));
if (startCol == 0) throw new ArgumentException("startCol must be >= 1", nameof(startCol));
if (endRow == 0) throw new ArgumentException("endRow must be >= 1", nameof(endRow));
if (endCol == 0) throw new ArgumentException("endCol must be >= 1", nameof(endCol));
// Приводим к корректному порядку (пользователь мог передать start > end)
uint rowStart = Math.Min(startRow, endRow);
uint rowEnd = Math.Max(startRow, endRow);
uint colStart = Math.Min(startCol, endCol);
uint colEnd = Math.Max(startCol, endCol);
return new ExcelRange(Book, this, rowStart, colStart, rowEnd, colEnd);
}
/// <inheritdoc />
public IRange RangeByIndexes(uint startRow, string startCol, uint endRow, string endCol)
{
if (string.IsNullOrEmpty(startCol)) throw new ArgumentException("startCol cannot be null or empty", nameof(startCol));
if (string.IsNullOrEmpty(endCol)) throw new ArgumentException("endCol cannot be null or empty", nameof(endCol));
uint startColIdx = CellAddressHelper.ColumnLetterToIndex(startCol);
uint endColIdx = CellAddressHelper.ColumnLetterToIndex(endCol);
return new ExcelRange(Book, this, startRow, startColIdx, endRow, endColIdx);
if (startColIdx == 0) throw new ArgumentException($"Invalid column letter: '{startCol}'", nameof(startCol));
if (endColIdx == 0) throw new ArgumentException($"Invalid column letter: '{endCol}'", nameof(endCol));
return RangeByIndexes(startRow, startColIdx, endRow, endColIdx);
}
/// <inheritdoc />
public IRange RangeByLength(uint startRow, uint startCol, uint rows, uint cols)
{
if (startRow == 0) throw new ArgumentException("startRow must be >= 1", nameof(startRow));
if (startCol == 0) throw new ArgumentException("startCol must be >= 1", nameof(startCol));
if (rows == 0) throw new ArgumentException("rows must be > 0", nameof(rows));
if (cols == 0) throw new ArgumentException("cols must be > 0", nameof(cols));
checked
{
uint endRow = startRow + rows - 1;
uint endCol = startCol + cols - 1;
return new ExcelRange(Book, this, startRow, startCol, endRow, endCol);
}
}
/// <inheritdoc />
public IRange RangeByLength(uint startRow, string startCol, uint rows, uint cols)
{
if (string.IsNullOrEmpty(startCol)) throw new ArgumentException("startCol cannot be null or empty", nameof(startCol));
uint startColIdx = CellAddressHelper.ColumnLetterToIndex(startCol);
if (startColIdx == 0) throw new ArgumentException($"Invalid column letter: '{startCol}'", nameof(startCol));
return RangeByLength(startRow, startColIdx, rows, cols);
}
/// <inheritdoc />
public ISheet RangeByIndexes(uint startRow, uint startCol, uint endRow, uint endCol, Action<IRange> edit)
{
if (edit is null) throw new ArgumentNullException(nameof(edit));
var range = RangeByIndexes(startRow, startCol, endRow, endCol);
edit(range);
return this;
@@ -234,31 +277,16 @@ internal sealed class ExcelSheet : ISheet
/// <inheritdoc />
public ISheet RangeByIndexes(uint startRow, string startCol, uint endRow, string endCol, Action<IRange> edit)
{
if (edit is null) throw new ArgumentNullException(nameof(edit));
var range = RangeByIndexes(startRow, startCol, endRow, endCol);
edit(range);
return this;
}
/// <inheritdoc />
public IRange RangeByLength(uint startRow, uint startCol, uint rows, uint cols)
{
if (rows == 0 || cols == 0)
throw new ArgumentException("Rows and columns must be greater than 0");
uint endRow = startRow + rows - 1;
uint endCol = startCol + cols - 1;
return new ExcelRange(Book, this, startRow, startCol, endRow, endCol);
}
/// <inheritdoc />
public IRange RangeByLength(uint startRow, string startCol, uint rows, uint cols)
{
uint startColIdx = CellAddressHelper.ColumnLetterToIndex(startCol);
return RangeByLength(startRow, startColIdx, rows, cols);
}
/// <inheritdoc />
public ISheet RangeByLength(uint startRow, uint startCol, uint rows, uint cols, Action<IRange> edit)
{
if (edit is null) throw new ArgumentNullException(nameof(edit));
var range = RangeByLength(startRow, startCol, rows, cols);
edit(range);
return this;
@@ -267,6 +295,7 @@ internal sealed class ExcelSheet : ISheet
/// <inheritdoc />
public ISheet RangeByLength(uint startRow, string startCol, uint rows, uint cols, Action<IRange> edit)
{
if (edit is null) throw new ArgumentNullException(nameof(edit));
var range = RangeByLength(startRow, startCol, rows, cols);
edit(range);
return this;
@@ -274,4 +303,27 @@ internal sealed class ExcelSheet : ISheet
#endregion
#region Merge Operations
/// <inheritdoc />
public bool TryMergeByIndexes(uint startRow, uint startCol, uint endRow, uint endCol) =>
RangeByIndexes(startRow, startCol, endRow, endCol).TryMerge();
/// <inheritdoc />
public bool TryMergeByIndexes(uint startRow, string startCol, uint endRow, string endCol) =>
RangeByIndexes(startRow, startCol, endRow, endCol).TryMerge();
/// <inheritdoc />
public bool TryMergeByLength(uint startRow, uint startCol, uint rows, uint cols) =>
RangeByLength(startRow, startCol, rows, cols).TryMerge();
/// <inheritdoc />
public bool TryMergeByLength(uint startRow, string startCol, uint rows, uint cols) =>
RangeByLength(startRow, startCol, rows, cols).TryMerge();
#endregion
}

View File

@@ -99,6 +99,18 @@ public interface ISheet
/// <summary>Редактирует диапазон, заданный начальной ячейкой и размером (буква столбца).</summary>
ISheet RangeByLength(uint startRow, string startCol, uint rows, uint cols, Action<IRange> edit);
/// <summary>Возвращает диапазон ячеек по начальным и конечным индексам строк и столбцов.</summary>
bool TryMergeByIndexes(uint startRow, uint startCol, uint endRow, uint endCol);
/// <summary>Возвращает диапазон ячеек по начальным и конечным координатам с буквенным обозначением столбцов.</summary>
bool TryMergeByIndexes(uint startRow, string startCol, uint endRow, string endCol);
/// <summary>Возвращает диапазон, начиная с указанной ячейки, заданной размером (строки x столбцы).</summary>
bool TryMergeByLength(uint startRow, uint startCol, uint rows, uint cols);
/// <summary>Возвращает диапазон по начальной ячейке и размеру с буквенным обозначением столбца.</summary>
bool TryMergeByLength(uint startRow, string startCol, uint rows, uint cols);
/// <summary>Возвращает ячейку по номеру строки и столбца (оба начиная с 1).</summary>
ICell Cell(uint row, uint col);
@@ -560,6 +572,69 @@ public interface IRange
/// <summary>Представляет одну ячейку на листе.</summary>
public interface ICell
{
/// <summary>Количество фрагментов (Run) в тексте.</summary>
int RunsCount { get; }
/// <summary>Возвращает все фрагменты.</summary>
IEnumerable<IRun> GetRuns();
/// <summary>Возвращает фрагмент по индексу или null.</summary>
IRun? GetRunAt(int index);
/// <summary>Пытается получить фрагмент по индексу.</summary>
bool TryGetRunAt(int index, out IRun run);
/// <summary>Первый фрагмент или null.</summary>
IRun? First();
/// <summary>Пытается получить первый фрагмент.</summary>
bool TryGetFirst(out IRun run);
/// <summary>Последний фрагмент или null.</summary>
IRun? Last();
/// <summary>Пытается получить последний фрагмент.</summary>
bool TryGetLast(out IRun run);
/// <summary>Пытается удалить фрагмент.</summary>
bool TryRemoveRun(IRun run);
/// <summary>Удаляет фрагмент по индексу.</summary>
bool TryRemoveRun(int index);
/// <summary>Удаляет фрагмент по индексу и возвращает удалённый.</summary>
bool TryRemoveRun(int index, out IRun? removed);
/// <summary>Добавляет разрыв строки (перенос внутри ячейки).</summary>
ICell Break();
/// <summary>Добавляет обычный текстовый фрагмент.</summary>
ICell Run(string text, RunFormat? format = null);
/// <summary>Добавляет фрагмент с последующим разрывом строки.</summary>
ICell RunBreak(string text, RunFormat? format = null);
/// <summary>Добавляет подстрочный фрагмент (эквивалентно AddRun с Vertical = Subscript).</summary>
ICell Sub(string text, RunFormat? format = null);
/// <summary>Добавляет надстрочный фрагмент.</summary>
ICell Sup(string text, RunFormat? format = null);
/// <summary>Вставляет фрагмент по индексу.</summary>
bool TryInsertRun(int index, string text, RunFormat? format = null);
/// <summary>Вставляет фрагмент с последующим разрывом строки по индексу.</summary>
bool TryInsertRunBreak(int index, string text, RunFormat? format = null);
/// <summary>Вставляет подстрочный фрагмент по индексу.</summary>
bool TryInsertSub(int index, string text, RunFormat? format = null);
/// <summary>Вставляет надстрочный фрагмент по индексу.</summary>
bool TryInsertSup(int index, string text, RunFormat? format = null);
/// <summary>Применяет заданный формат ко всем существующим фрагментам (поверх их текущего форматирования, заменяя неуказанные свойства).</summary>
void ApplyFormatToAllRuns(RunFormat format);
/// <summary>Проверяет, входит ли ячейка в объединённый диапазон.</summary>
bool IsMerged { get; }
@@ -699,15 +774,6 @@ public interface ICell
/// <summary>Устанавливает шрифт ячейки.</summary>
ICell Set(CellFont format);
/// <summary>Устанавливает богатый текст (форматированный) с помощью делегата.</summary>
ICell Text(Action<ICellText> value);
/// <summary>Возвращает объект для редактирования богатого текста ячейки (если ячейка содержит InlineString).</summary>
bool TryText(out ICellText cellText);
/// <summary>Возвращает объект для редактирования богатого текста ячейки (если ячейка содержит InlineString).</summary>
ICellText? Text();
/// <summary>Устанавливает простое текстовое значение (без форматирования).</summary>
ICell Set(string value);
@@ -742,76 +808,6 @@ public interface ICell
void Clear();
}
/// <summary>Представляет богатый текст внутри ячейки (несколько форматированных фрагментов).</summary>
public interface ICellText
{
/// <summary>Количество фрагментов (Run) в тексте.</summary>
int Count { get; }
/// <summary>Возвращает все фрагменты.</summary>
IEnumerable<IRun> GetRuns();
/// <summary>Возвращает фрагмент по индексу или null.</summary>
IRun? GetRunAt(int index);
/// <summary>Пытается получить фрагмент по индексу.</summary>
bool TryGetRunAt(int index, out IRun run);
/// <summary>Первый фрагмент или null.</summary>
IRun? First();
/// <summary>Пытается получить первый фрагмент.</summary>
bool TryGetFirst(out IRun run);
/// <summary>Последний фрагмент или null.</summary>
IRun? Last();
/// <summary>Пытается получить последний фрагмент.</summary>
bool TryGetLast(out IRun run);
/// <summary>Пытается удалить фрагмент.</summary>
bool TryRemoveRun(IRun run);
/// <summary>Удаляет фрагмент по индексу.</summary>
bool TryRemoveRun(int index);
/// <summary>Удаляет фрагмент по индексу и возвращает удалённый.</summary>
bool TryRemoveRun(int index, out IRun? removed);
/// <summary>Добавляет разрыв строки (перенос внутри ячейки).</summary>
ICellText AddBreak();
/// <summary>Добавляет обычный текстовый фрагмент.</summary>
ICellText AddRun(string text, RunFormat? format = null);
/// <summary>Добавляет фрагмент с последующим разрывом строки.</summary>
ICellText AddRunBreak(string text, RunFormat? format = null);
/// <summary>Добавляет подстрочный фрагмент (эквивалентно AddRun с Vertical = Subscript).</summary>
ICellText AddSubRun(string text, RunFormat? format = null);
/// <summary>Добавляет надстрочный фрагмент.</summary>
ICellText AddSupRun(string text, RunFormat? format = null);
/// <summary>Вставляет фрагмент по индексу.</summary>
bool TryInsertRun(int index, string text, RunFormat? format = null);
/// <summary>Вставляет фрагмент с последующим разрывом строки по индексу.</summary>
bool TryInsertRunBreak(int index, string text, RunFormat? format = null);
/// <summary>Вставляет подстрочный фрагмент по индексу.</summary>
bool TryInsertSubRun(int index, string text, RunFormat? format = null);
/// <summary>Вставляет надстрочный фрагмент по индексу.</summary>
bool TryInsertSupRun(int index, string text, RunFormat? format = null);
/// <summary>Применяет заданный формат ко всем существующим фрагментам (поверх их текущего форматирования, заменяя неуказанные свойства).</summary>
void ApplyFormatToAllRuns(RunFormat format);
/// <summary>Удаляет все фрагменты, очищая текст ячейки.</summary>
void Clear();
}
/// <summary>Представляет один форматированный фрагмент текста внутри ячейки.</summary>
public interface IRun
{

View File

@@ -1,21 +1,21 @@
using Base = DocumentFormat.OpenXml.Math.Base;
using ControlProperties = DocumentFormat.OpenXml.Math.ControlProperties;
using Degree = DocumentFormat.OpenXml.Math.Degree;
using Denominator = DocumentFormat.OpenXml.Math.Denominator;
using Fraction = DocumentFormat.OpenXml.Math.Fraction;
using FractionProperties = DocumentFormat.OpenXml.Math.FractionProperties;
using HideDegree = DocumentFormat.OpenXml.Math.HideDegree;
using MathBase = DocumentFormat.OpenXml.Math.Base;
using MathControlProperties = DocumentFormat.OpenXml.Math.ControlProperties;
using MathDegree = DocumentFormat.OpenXml.Math.Degree;
using MathDenominator = DocumentFormat.OpenXml.Math.Denominator;
using MathFraction = DocumentFormat.OpenXml.Math.Fraction;
using MathFractionProperties = DocumentFormat.OpenXml.Math.FractionProperties;
using MathHideDegree = DocumentFormat.OpenXml.Math.HideDegree;
using MathRun = DocumentFormat.OpenXml.Math.Run;
using MathRunProperties = DocumentFormat.OpenXml.Math.RunProperties;
using MathText = DocumentFormat.OpenXml.Math.Text;
using Numerator = DocumentFormat.OpenXml.Math.Numerator;
using Radical = DocumentFormat.OpenXml.Math.Radical;
using RadicalProperties = DocumentFormat.OpenXml.Math.RadicalProperties;
using SubArgument = DocumentFormat.OpenXml.Math.SubArgument;
using Subscript = DocumentFormat.OpenXml.Math.Subscript;
using SubSuperscript = DocumentFormat.OpenXml.Math.SubSuperscript;
using SuperArgument = DocumentFormat.OpenXml.Math.SuperArgument;
using Superscript = DocumentFormat.OpenXml.Math.Superscript;
using MathNumerator = DocumentFormat.OpenXml.Math.Numerator;
using MathRadical = DocumentFormat.OpenXml.Math.Radical;
using MathRadicalProperties = DocumentFormat.OpenXml.Math.RadicalProperties;
using MathSubArgument = DocumentFormat.OpenXml.Math.SubArgument;
using MathSubscript = DocumentFormat.OpenXml.Math.Subscript;
using MathSubSuperscript = DocumentFormat.OpenXml.Math.SubSuperscript;
using MathSuperArgument = DocumentFormat.OpenXml.Math.SuperArgument;
using MathSuperscript = DocumentFormat.OpenXml.Math.Superscript;
namespace QWERTYkez.WordProcessor;
@@ -59,19 +59,19 @@ internal static class FormulaHelper
}
}
public static Fraction CreateFraction(
public static MathFraction CreateFraction(
Action<IFormula> numeratorBuilder,
Action<IFormula> denominatorBuilder,
IFormula builder)
{
var fraction = new Fraction();
var fraction = new MathFraction();
var font = builder.BaseFont;
// Добавляем свойства дроби с форматированием (для черты дроби)
var fPr = new FractionProperties();
var fPr = new MathFractionProperties();
if (font.TryExtractWithoutFamily(out var wordElements))
{
var ctrlPr = new ControlProperties();
var ctrlPr = new MathControlProperties();
var rPr = new RunProperties();
foreach (var elem in wordElements)
rPr.AppendChild(elem.CloneNode(true));
@@ -82,14 +82,14 @@ internal static class FormulaHelper
fraction.AppendChild(fPr);
// Числитель
var numeratorElem = new Numerator();
var numeratorElem = new MathNumerator();
fraction.AppendChild(numeratorElem);
builder.PushContext(numeratorElem);
numeratorBuilder(builder);
builder.PopContext();
// Знаменатель
var denominatorElem = new Denominator();
var denominatorElem = new MathDenominator();
fraction.AppendChild(denominatorElem);
builder.PushContext(denominatorElem);
denominatorBuilder(builder);
@@ -98,20 +98,20 @@ internal static class FormulaHelper
return fraction;
}
public static Radical CreateRadical(
public static MathRadical CreateRadical(
Action<IFormula> radicandBuilder,
Action<IFormula>? degreeBuilder,
IFormula builder)
{
var radical = new Radical();
var radical = new MathRadical();
var font = builder.BaseFont;
var radPr = new RadicalProperties();
var radPr = new MathRadicalProperties();
// Цвет, размер и подчёркивание для знака корня (ControlProperties)
if (font is not null && font.TryExtractWithoutFamily(out var wordElements))
{
var ctrlPr = new ControlProperties();
var ctrlPr = new MathControlProperties();
var rPr = new RunProperties();
foreach (var elem in wordElements)
rPr.AppendChild(elem.CloneNode(true));
@@ -123,7 +123,7 @@ internal static class FormulaHelper
// Если степень не задана, скрываем её
if (degreeBuilder is null)
{
radPr.HideDegree = new HideDegree { Val = DocumentFormat.OpenXml.Math.BooleanValues.One };
radPr.HideDegree = new MathHideDegree { Val = DocumentFormat.OpenXml.Math.BooleanValues.One };
}
// Добавляем свойства радикала (с цветом)
@@ -132,7 +132,7 @@ internal static class FormulaHelper
// Степень (если есть)
if (degreeBuilder is not null)
{
var degree = new Degree();
var degree = new MathDegree();
radical.AppendChild(degree);
builder.PushContext(degree);
degreeBuilder(builder);
@@ -140,7 +140,7 @@ internal static class FormulaHelper
}
// Подкоренное выражение
var radicand = new Base();
var radicand = new MathBase();
radical.AppendChild(radicand);
builder.PushContext(radicand);
radicandBuilder(builder);
@@ -179,10 +179,10 @@ internal static class FormulaHelper
}
else
{
var integralWithLimits = new SubSuperscript();
var integralWithLimits = new MathSubSuperscript();
currentContext.AppendChild(integralWithLimits);
var baseElem = new Base();
var baseElem = new MathBase();
var integralRun = CreateMathRun(font);
integralRun.AppendChild(new MathText("∫"));
baseElem.AppendChild(integralRun);
@@ -190,7 +190,7 @@ internal static class FormulaHelper
if (lowerLimitBuilder is not null)
{
var subArg = new SubArgument();
var subArg = new MathSubArgument();
integralWithLimits.AppendChild(subArg);
builder.PushContext(subArg);
lowerLimitBuilder(builder);
@@ -198,7 +198,7 @@ internal static class FormulaHelper
}
if (upperLimitBuilder is not null)
{
var superArg = new SuperArgument();
var superArg = new MathSuperArgument();
integralWithLimits.AppendChild(superArg);
builder.PushContext(superArg);
upperLimitBuilder(builder);
@@ -242,10 +242,10 @@ internal static class FormulaHelper
}
else
{
var sumWithLimits = new SubSuperscript();
var sumWithLimits = new MathSubSuperscript();
currentContext.AppendChild(sumWithLimits);
var baseElem = new Base();
var baseElem = new MathBase();
var sumRun = CreateMathRun(font);
sumRun.AppendChild(new MathText("∑"));
baseElem.AppendChild(sumRun);
@@ -253,7 +253,7 @@ internal static class FormulaHelper
if (lowerLimitBuilder is not null)
{
var subArg = new SubArgument();
var subArg = new MathSubArgument();
sumWithLimits.AppendChild(subArg);
builder.PushContext(subArg);
lowerLimitBuilder(builder);
@@ -261,7 +261,7 @@ internal static class FormulaHelper
}
if (upperLimitBuilder is not null)
{
var superArg = new SuperArgument();
var superArg = new MathSuperArgument();
sumWithLimits.AppendChild(superArg);
builder.PushContext(superArg);
upperLimitBuilder(builder);
@@ -278,22 +278,22 @@ internal static class FormulaHelper
/// <summary>Создаёт степень.</summary>
public static Superscript CreateSuperscript(
public static MathSuperscript CreateSuperscript(
Action<IFormula> baseBuilder,
Action<IFormula> supBuilder,
IFormula builder)
{
var superscript = new Superscript();
var superscript = new MathSuperscript();
// Основание
var baseElem = new Base();
var baseElem = new MathBase();
superscript.AppendChild(baseElem);
builder.PushContext(baseElem);
baseBuilder(builder);
builder.PopContext();
// Показатель
var superArg = new SuperArgument();
var superArg = new MathSuperArgument();
superscript.AppendChild(superArg);
builder.PushContext(superArg);
supBuilder(builder);
@@ -303,20 +303,20 @@ internal static class FormulaHelper
}
/// <summary>Создаёт нижний индекс.</summary>
public static Subscript CreateSubscript(
public static MathSubscript CreateSubscript(
Action<IFormula> baseBuilder,
Action<IFormula> subBuilder,
IFormula builder)
{
var subscript = new Subscript();
var subscript = new MathSubscript();
var baseElem = new Base();
var baseElem = new MathBase();
subscript.AppendChild(baseElem);
builder.PushContext(baseElem);
baseBuilder(builder);
builder.PopContext();
var subArg = new SubArgument();
var subArg = new MathSubArgument();
subscript.AppendChild(subArg);
builder.PushContext(subArg);
subBuilder(builder);
@@ -326,27 +326,27 @@ internal static class FormulaHelper
}
/// <summary>Создаёт одновременные нижний и верхний индексы.</summary>
public static SubSuperscript CreateSubSuperscript(
public static MathSubSuperscript CreateSubSuperscript(
Action<IFormula> baseBuilder,
Action<IFormula> subBuilder,
Action<IFormula> supBuilder,
IFormula builder)
{
var subSup = new SubSuperscript();
var subSup = new MathSubSuperscript();
var baseElem = new Base();
var baseElem = new MathBase();
subSup.AppendChild(baseElem);
builder.PushContext(baseElem);
baseBuilder(builder);
builder.PopContext();
var subArg = new SubArgument();
var subArg = new MathSubArgument();
subSup.AppendChild(subArg);
builder.PushContext(subArg);
subBuilder(builder);
builder.PopContext();
var superArg = new SuperArgument();
var superArg = new MathSuperArgument();
subSup.AppendChild(superArg);
builder.PushContext(superArg);
supBuilder(builder);

View File

@@ -1,4 +1,6 @@
namespace QWERTYkez.WordProcessor;
using MathOfficeMath = DocumentFormat.OpenXml.Math.OfficeMath;
namespace QWERTYkez.WordProcessor;
abstract class ParagraphBuilderBase : IParagraph, IFormula
{
@@ -176,7 +178,7 @@ abstract class ParagraphBuilderBase : IParagraph, IFormula
// Метод AddFormula для IParagraphBuilder
IParagraph IParagraph.AddFormula(Action<IFormula> configure)
{
var math = new OfficeMath();
var math = new MathOfficeMath();
try
{
_mathContextStack.Push(math);
@@ -196,7 +198,7 @@ abstract class ParagraphBuilderBase : IParagraph, IFormula
// Метод AddFormula для IParagraphBuilder
IParagraph IParagraph.AddFormulaBreak(Action<IFormula> configure)
{
var math = new OfficeMath();
var math = new MathOfficeMath();
try
{
_mathContextStack.Push(math);