Browse Source

AvalonEdit: Fixed caret rectangle calculation when there are inline UI elements that extend below the baseline.

Add VisualYPosition.TextBottom and VisualYPosition.BaseLine options. Fixed VisualYPosition.TextTop calculation.
pull/18/head
Daniel Grunwald 14 years ago
parent
commit
e17d6e0482
  1. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs
  2. 62
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs
  3. 7
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs
  4. 20
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualYPosition.cs

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs

@ -351,7 +351,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -351,7 +351,7 @@ namespace ICSharpCode.AvalonEdit.Editing
TextLine textLine = visualLine.GetTextLine(position.VisualColumn);
double xPos = visualLine.GetTextLineVisualXPosition(textLine, position.VisualColumn);
double lineTop = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.TextTop);
double lineBottom = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineBottom);
double lineBottom = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.TextBottom);
return new Rect(xPos,
lineTop,

62
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs

@ -115,7 +115,8 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -115,7 +115,8 @@ namespace ICSharpCode.AvalonEdit.Rendering
if (newValue != null) {
TextDocumentWeakEventManager.Changing.AddListener(newValue, this);
formatter = TextFormatterFactory.Create(this);
heightTree = new HeightTree(newValue, DefaultLineHeight); // measuring DefaultLineHeight depends on formatter
InvalidateDefaultTextMetrics(); // measuring DefaultLineHeight depends on formatter
heightTree = new HeightTree(newValue, DefaultLineHeight);
cachedElements = new TextViewCachedElements();
}
InvalidateMeasure(DispatcherPriority.Normal);
@ -1369,29 +1370,64 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -1369,29 +1370,64 @@ namespace ICSharpCode.AvalonEdit.Rendering
OnScrollChange();
}
bool defaultTextMetricsValid;
double wideSpaceWidth; // Width of an 'x'. Used as basis for the tab width, and for scrolling.
double defaultLineHeight; // Height of a line containing 'x'. Used for scrolling.
double defaultBaseline; // Baseline of a line containing 'x'. Used for TextTop/TextBottom calculation.
internal double WideSpaceWidth {
/// <summary>
/// Gets the width of a 'wide space' (the space width used for calculating the tab size).
/// </summary>
/// <remarks>
/// This is the width of an 'x' in the current font.
/// We do not measure the width of an actual space as that would lead to tiny tabs in
/// some proportional fonts.
/// For monospaced fonts, this property will return the expected value, as 'x' and ' ' have the same width.
/// </remarks>
public double WideSpaceWidth {
get {
if (wideSpaceWidth == 0) {
MeasureWideSpaceWidthAndDefaultLineHeight();
}
CalculateDefaultTextMetrics();
return wideSpaceWidth;
}
}
double DefaultLineHeight {
/// <summary>
/// Gets the default line height. This is the height of an empty line or a line containing regular text.
/// Lines that include formatted text or custom UI elements may have a different line height.
/// </summary>
public double DefaultLineHeight {
get {
if (defaultLineHeight == 0) {
MeasureWideSpaceWidthAndDefaultLineHeight();
}
CalculateDefaultTextMetrics();
return defaultLineHeight;
}
}
void MeasureWideSpaceWidthAndDefaultLineHeight()
/// <summary>
/// Gets the default baseline position. This is the difference between <see cref="VisualYPosition.TextTop"/>
/// and <see cref="VisualYPosition.Baseline"/> for a line containing regular text.
/// Lines that include formatted text or custom UI elements may have a different baseline.
/// </summary>
public double DefaultBaseline {
get {
CalculateDefaultTextMetrics();
return defaultBaseline;
}
}
void InvalidateDefaultTextMetrics()
{
defaultTextMetricsValid = false;
if (heightTree != null) {
// calculate immediately so that height tree gets updated
CalculateDefaultTextMetrics();
}
}
void CalculateDefaultTextMetrics()
{
if (defaultTextMetricsValid)
return;
defaultTextMetricsValid = true;
if (formatter != null) {
var textRunProperties = CreateGlobalTextRunProperties();
using (var line = formatter.FormatLine(
@ -1401,10 +1437,12 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -1401,10 +1437,12 @@ namespace ICSharpCode.AvalonEdit.Rendering
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;
}
// Update heightTree.DefaultLineHeight, if a document is loaded.
@ -1831,7 +1869,7 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -1831,7 +1869,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
// changing text formatter requires recreating the cached elements
RecreateCachedElements();
// and we need to re-measure the font metrics:
MeasureWideSpaceWidthAndDefaultLineHeight();
InvalidateDefaultTextMetrics();
} else if (e.Property == Control.ForegroundProperty
|| e.Property == TextView.NonPrintableCharacterBrushProperty)
{
@ -1848,7 +1886,7 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -1848,7 +1886,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
// changing font properties requires recreating cached elements
RecreateCachedElements();
// and we need to re-measure the font metrics:
MeasureWideSpaceWidthAndDefaultLineHeight();
InvalidateDefaultTextMetrics();
Redraw();
}
}

7
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System.Windows.Controls;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Utils;
using System;
@ -268,7 +269,11 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -268,7 +269,11 @@ namespace ICSharpCode.AvalonEdit.Rendering
case VisualYPosition.LineBottom:
return pos + tl.Height;
case VisualYPosition.TextTop:
return pos + tl.Height - textView.FontSize;
return pos + tl.Baseline - textView.DefaultBaseline;
case VisualYPosition.TextBottom:
return pos + tl.Baseline - textView.DefaultBaseline + textView.DefaultLineHeight;
case VisualYPosition.Baseline:
return pos + tl.Baseline;
default:
throw new ArgumentException("Invalid yPositionMode:" + yPositionMode);
}

20
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualYPosition.cs

@ -15,18 +15,28 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -15,18 +15,28 @@ namespace ICSharpCode.AvalonEdit.Rendering
/// </summary>
LineTop,
/// <summary>
/// Returns the top of the text. If the line contains inline UI elements larger than the text, TextTop
/// will be below LineTop.
/// Returns the top of the text.
/// If the line contains inline UI elements larger than the text, TextTop may be below LineTop.
/// For a line containing regular text (all in the editor's main font), this will be equal to LineTop.
/// </summary>
TextTop,
/// <summary>
/// Returns the bottom of the TextLine. This is the same as the bottom of the text (the text is always
/// aligned at the bottom border).
/// Returns the bottom of the TextLine.
/// </summary>
LineBottom,
/// <summary>
/// The middle between LineTop and LineBottom.
/// </summary>
LineMiddle
LineMiddle,
/// <summary>
/// Returns the bottom of the text.
/// If the line contains inline UI elements larger than the text, TextBottom might be above LineBottom.
/// For a line containing regular text (all in the editor's main font), this will be equal to LineBottom.
/// </summary>
TextBottom,
/// <summary>
/// Returns the baseline of the text.
/// </summary>
Baseline
}
}

Loading…
Cancel
Save