I am writing a custom software using avalon edit and I am looking for a way to make the space (height) between lines bigger. At the moment I am forced to add an empty line every time the user has ended writing a line and wants to write another.
I have started looking into the TextView
Class where defaultLineHeight seems to be calculated but the only thing I was able to affect is the height of the visual caret but not the content itself.
At the moment I am looking at making every pair line invisible but I am hoping there is an easier way to achieve the simple operation of adding more space between lines.
Here is the method from class TextView
I am inspecting at the moment. Any tips or hints would be welcome.
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;
}
}
Thanks
The DefaultLineHeight
is the height of a line in the default font, which is used as an initial assumption for the each line's height. (e.g. for calculating the scroll bar position)
Whenever a line gets actually measured (TextView.BuildVisualLine
), the measured height gets stored in the height tree, overwriting the default height. This is because word wrapping (or a line transformer changing the font size) can cause each line to have a different height.
Inter-line spacing isn't really supported at the moment. If you want to add that, you can try changing the height calculation of the VisualLine
, e.g. by changing VisualLine.SetTextLines()
.
Including what @Peter Moore said. There's one more step required in order to force the text to render correctly.
At the bottom of VisualLine.cs
lies the class VisualLineDrawingVisual
which is responsible for drawing the actual text but doesn't have access to the TextView
class.
Modify the constructor to include double lineSpacing
as a paremeter and multiply all instances of textLine.Height
by lineSpacing
.
In VisualLine.Render()
, pass textView.LineSpacing
as the secondary parameter for the now-modified constructor for VisualLineDrawingVisual
. After this everything should draw correctly.
Here's a full view of the modified code:
TextView.cs
public static readonly DependencyProperty LineSpacingProperty =
DependencyProperty.Register("LineSpacing", typeof(double), typeof(TextView),
new FrameworkPropertyMetadata(1.0));
public double LineSpacing {
get { return (double) GetValue(LineSpacingProperty); }
set { SetValue(LineSpacingProperty, value); }
}
VisualLine.cs
Line 269
internal void SetTextLines(List<TextLine> textLines) {
this.textLines = textLines.AsReadOnly();
Height = 0;
foreach (TextLine line in textLines)
Height += line.Height * textView.LineSpacing;
}
Line 335
public double GetTextLineVisualYPosition(TextLine textLine, VisualYPosition yPositionMode) {
if (textLine == null)
throw new ArgumentNullException("textLine");
double 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");
}
Line 386
public TextLine GetTextLineByVisualYPosition(double visualTop) {
const double epsilon = 0.0001;
double pos = this.VisualTop;
foreach (TextLine tl in TextLines) {
pos += tl.Height * textView.LineSpacing;
if (visualTop + epsilon < pos)
return tl;
}
return TextLines[TextLines.Count - 1];
}
Line 701
internal VisualLineDrawingVisual Render() {
Debug.Assert(phase == LifetimePhase.Live);
if (visual == null)
visual = new VisualLineDrawingVisual(this, textView.LineSpacing);
return visual;
}
Line 714
public VisualLineDrawingVisual(VisualLine visualLine, double lineSpacing) {
this.VisualLine = visualLine;
var drawingContext = RenderOpen();
double 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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With