Изменение высоты строки по умолчанию в редакторе avalon

Я пишу специальное программное обеспечение с использованием редактирования avalon, и я ищу способ сделать пространство (рост) между строками больше. В настоящий момент я вынужден добавлять пустую строку каждый раз, когда пользователь закончил писать строку и хочет написать другую.

Я начал изучать класс TextView, где defaultLineHeight, кажется, вычисляется, но единственное, что я смог затронуть, это высота визуального каретки, но не самого содержимого.

В настоящий момент я смотрю, как сделать каждую пару невидимой, но я надеюсь, что есть простой способ добиться простой операции добавления большего количества пробелов между строками.

Вот метод из класса TextView, который я просматриваю на данный момент. Любые советы или подсказки будут приветствоваться.

void CalculateDefaultTextMetrics()
{
 if (defaultTextMetricsValid)
 {
 return;
 }
 defaultTextMetricsValid = true;
 if (formatter != null)
 {
 var textRunProperties = CreateGlobalTextRunProperties();
 using (
 var line = formatter.FormatLine(
 new SimpleTextSource("x", textRunProperties),
 0,
 32000,
 new VisualLineTextParagraphProperties { defaultTextRunProperties = textRunProperties },
 null))
 {
 wideSpaceWidth = Math.Max(1, line.WidthIncludingTrailingWhitespace);
 defaultBaseline = Math.Max(1, line.Baseline);
 defaultLineHeight = Math.Max(1, line.Height);
 }
 }
 else
 {
 wideSpaceWidth = FontSize / 2;
 defaultBaseline = FontSize;
 **defaultLineHeight = FontSize + 3; // bigger value only affects caret height :(**
 }
 // Update heightTree.DefaultLineHeight, if a document is loaded.
 if (heightTree != null)
 {
 heightTree.DefaultLineHeight = defaultLineHeight;
 }
}

Спасибо

4 ответа

DefaultLineHeight - это высота строки шрифта по умолчанию, которая используется как исходное предположение для каждой высоты строки. (например, для вычисления положения полосы прокрутки)

Всякий раз, когда линия фактически измеряется (TextView.BuildVisualLine), измеренная высота сохраняется в дереве высоты, переписывая высоту по умолчанию. Это связано с тем, что перенос слов (или линейный трансформатор, изменяющий размер шрифта) может привести к тому, что каждая строка будет иметь разную высоту.

Межстрочный интервал на данный момент не поддерживается. Если вы хотите добавить это, вы можете попробовать изменить расчет высоты VisualLine, например. путем изменения VisualLine.SetTextLines().


Включая то, что сказал @Peter Moore. Для обеспечения правильного отображения текста требуется еще один шаг.

В нижней части VisualLine.cs находится класс ***********************, который отвечает за рисование фактического текста, но не имеет доступа к классу TextView.

Измените конструктор, чтобы включить ****** lineSpacing в качестве пареметра и умножить все экземпляры textLine.Height на lineSpacing.

В VisualLine.Render() передайте textView.LineSpacing в качестве вторичного параметра для теперь модифицированного конструктора для ***********************. После этого все должно правильно рисоваться.

Здесь полный вид модифицированного кода:

TextView.cs

public static readonly DependencyProperty LineSpacingProperty =
 DependencyProperty.Register("LineSpacing", typeof(******), typeof(TextView),
 new FrameworkPropertyMetadata(1.0));
public ****** LineSpacing {
 get { return (******) GetValue(LineSpacingProperty); }
 set { SetValue(LineSpacingProperty, value); }
}

VisualLine.cs

Линия 269

internal void SetTextLines(List<textline> textLines) {
 this.textLines = textLines.AsReadOnly();
 Height = 0;
 foreach (TextLine line in textLines)
 Height += line.Height * textView.LineSpacing;
}
</textline>

Линия 335

public ****** GetTextLineVisualYPosition(TextLine textLine, VisualYPosition yPositionMode) {
 if (textLine == null)
 throw new ArgumentNullException("textLine");
 ****** pos = VisualTop;
 foreach (TextLine tl in TextLines) {
 if (tl == textLine) {
 switch (yPositionMode) {
 case VisualYPosition.LineTop:
 return pos;
 case VisualYPosition.LineMiddle:
 return pos + tl.Height / 2 * textView.LineSpacing;
 case VisualYPosition.LineBottom:
 return pos + tl.Height * textView.LineSpacing;
 case VisualYPosition.TextTop:
 return pos + tl.Baseline - textView.DefaultBaseline;
 case VisualYPosition.TextBottom:
 return pos + tl.Baseline - textView.DefaultBaseline + textView.DefaultLineHeight;
 case VisualYPosition.TextMiddle:
 return pos + tl.Baseline - textView.DefaultBaseline + textView.DefaultLineHeight / 2;
 case VisualYPosition.Baseline:
 return pos + tl.Baseline;
 default:
 throw new ArgumentException("Invalid yPositionMode:" + yPositionMode);
 }
 }
 else {
 pos += tl.Height * textView.LineSpacing;
 }
 }
 throw new ArgumentException("textLine is not a line in this VisualLine");
}

Линия 386

public TextLine GetTextLineByVisualYPosition(****** visualTop) {
 const ****** epsilon = 0.0001;
 ****** pos = this.VisualTop;
 foreach (TextLine tl in TextLines) {
 pos += tl.Height * textView.LineSpacing;
 if (visualTop + epsilon < pos)
 return tl;
 }
 return TextLines[TextLines.Count - 1];
}

Линия 701

internal *********************** Render() {
 Debug.Assert(phase == LifetimePhase.Live);
 if (visual == null)
 visual = new ***********************(this, textView.LineSpacing);
 return visual;
}

Линия 714

public ***********************(VisualLine visualLine, ****** lineSpacing) {
 this.VisualLine = visualLine;
 var drawingContext = RenderOpen();
 ****** pos = 0;
 foreach (TextLine textLine in visualLine.TextLines) {
 textLine.Draw(drawingContext, new Point(0, pos), InvertAxes.None);
 pos += textLine.Height * lineSpacing;
 }
 this.Height = pos;
 drawingContext.Close();
}


Я знаю, что это старый пост, но я просто встретил это с тем же вопросом. Мне удалось добавить межстрочный интервал очень легко со следующими изменениями:

  • Добавьте новое свойство зависимостей ****** к TextView, называемому LineSpacing со значением по умолчанию 1.0
  • В VisualLine.SetTextLines, умножьте line.Height на textView.LineSpacing
  • В VisualLine.GetTextLineVisualYPosition и VisualLine.GetTextLineByVisualYPosition умножьте каждое вхождение tl.Height на textView.LineSpacing

Затем вы можете установить textView.LineSpacing непосредственно в код или через собственный стиль XAML и т.д.

Казалось, это было все, что было необходимо.

PS - AvalonEdit фантастичен!


В дополнение к тому, что сказал @Robert Jordan, есть еще несколько изменений, которые мне пришлось сделать, чтобы получить удовлетворительный результат.

Прежде всего, чтобы сделать наложение текста на всю высоту линии, измените следующие строки в BackgroundGeometryBuilder.cs

Метод ProcessTextLines, строка 196:

Строка 215:

yield return new Rect(pos, y, 1, line.Height * textView.LineSpacing);

Строка 259:

lastRect = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height * textView.LineSpacing);

Строка 259:

Rect extendSelection = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height * textView.LineSpacing);

Вторая проблема, которая была у меня, заключалась в том, что текст был отображен в верхней части увеличенной длины строки, а не снизу. Чтобы исправить это, дополнительное пространство должно быть добавлено до визуализации строки, а не после. Итак, внесите следующие изменения:

VisualLine.cs, строка 714

public ***********************(VisualLine visualLine, ****** lineSpacing) {
 this.VisualLine = visualLine;
 var drawingContext = RenderOpen();
 ****** pos = 0;
 foreach (TextLine textLine in visualLine.TextLines) {
 pos +=(textLine.Height * lineSpacing)-textLine.Height
 textLine.Draw(drawingContext, new Point(0, pos), InvertAxes.None);
 pos += textLine.Height;
 }
 this.Height = pos;
 drawingContext.Close();
}

Кроме того, я нашел тривиальным преобразование для поддержки динамических линейных расстояний между линиями. Просто переместите свойство LineSpacing в VisualLine, затем добавьте VisualLineTransformer следующим образом:

class LinePaddingTransformer : IVisualLineTransformer
{
 public LinePaddingTransformer()
 {
 _clientLines = clientLines;
 }
 public void Transform(ITextRunConstructionContext context, IList<visuallineelement> elements)
 {
 int index = context.VisualLine.FirstDocumentLine.LineNumber - 1;
 //You need to calculate your padding from the line index somehow.
 //for example create a list of objects with the spacing in them and pass to this transformer.
 ****** spacing= GetLinePaddingMethod(index); 
 context.VisualLine.LineSpacing= spacing;
 }
}
</visuallineelement>

Если вам требуется, чтобы интервал был добавлен только к первой строке в случае переноса текста, вам нужно перейти в любое место, которое вы ранее умножали на свойство LineSpacing, и поместить проверку, если TextLine является первой строкой в коллекция.

licensed under cc by-sa 3.0 with attribution.