我正在使用AvalonEdit编写电影脚本编辑器。
我将DocumentLine类扩展为具有“Type”属性,其值代表“Character”,“Dialog Line”等。
我希望脚本中的某种类型的文档行以大写形式写出(例如字符名称)。
渲染管道中是否有一个扩展点可以让我获取文档行并更改它的外壳?
我尝试创建一个扩展DocumentColorizingTransformer的类,但更改“受保护的覆盖void ColorizeLine(DocumentLine line)”方法中的外壳不起作用。
答案 0 :(得分:4)
这很难,因为上壳可以改变显示的字符和文档之间的映射(可视列与文档偏移)。
例如,单个字符'ß'(德语sharp s)仅作为小写字母存在,并在调用string.ToUpper()
时转换为双字符串“SS”。
编辑此文本很棘手:我们不允许用户只替换其中一个'S',因为底层文档只包含'ß'。
一个简单的解决方案是使用char.ToUpper()
方法,强制执行原始字符和大写字符之间的一对一映射。这将保持像'ß'这样的字母不变。
在AvalonEdit 4.2中,在已生成的VisualLineElements上只允许两次转换:
ChangeLinePart()
在内部使用,以便可以更改文本部分的属性。这意味着无法在着色器中进行文本替换,您需要使用VisualLineElementGenerator
来实现此目的。
/// <summary>
/// Makes all text after a colon (until the end of line) upper-case.
/// </summary>
public class UppercaseGenerator : VisualLineElementGenerator
{
public override int GetFirstInterestedOffset(int startOffset)
{
TextDocument document = CurrentContext.Document;
int endOffset = CurrentContext.VisualLine.LastDocumentLine.EndOffset;
for (int i = startOffset; i < endOffset; i++) {
char c = document.GetCharAt(i);
if (c == ':')
return i + 1;
}
return -1;
}
public override VisualLineElement ConstructElement(int offset)
{
DocumentLine line = CurrentContext.Document.GetLineByOffset(offset);
return new UppercaseText(CurrentContext.VisualLine, line.EndOffset - offset);
}
/// <summary>
/// Displays a portion of the document text, but upper-cased.
/// </summary>
class UppercaseText : VisualLineText
{
public UppercaseText(VisualLine parentVisualLine, int length) : base(parentVisualLine, length)
{
}
protected override VisualLineText CreateInstance(int length)
{
return new UppercaseText(ParentVisualLine, length);
}
public override TextRun CreateTextRun(int startVisualColumn, ITextRunConstructionContext context)
{
if (context == null)
throw new ArgumentNullException("context");
int relativeOffset = startVisualColumn - VisualColumn;
StringSegment text = context.GetText(context.VisualLine.FirstDocumentLine.Offset + RelativeTextOffset + relativeOffset, DocumentLength - relativeOffset);
char[] uppercase = new char[text.Count];
for (int i = 0; i < text.Count; i++) {
uppercase[i] = char.ToUpper(text.Text[text.Offset + i]);
}
return new TextCharacters(uppercase, 0, uppercase.Length, this.TextRunProperties);
}
}
}
在AvalonEdit 4.3.0.8868中,我添加了方法VisualLine.ReplaceElement()
。这可以用来替换行变换器(colorizer)中VisualText
元素的默认UppercaseText
元素。
请注意,也可以实现对'ß'的支持,显示为'SS'。为此,您必须实现自己的VisualLineText
副本,而不是仅覆盖现有副本。然后,您可以使用与文档长度不同的可视长度。 GetRelativeOffset
和GetVisualColumns
方法将用于提供文档和视觉坐标之间的映射。
您可以使用另一个选项:小型大写。
// in the colorizer:
ChangeLinePart(start, end, e => e.TextRunProperties.SetTypographyProperties(new CapsTypography()));
// helper class
class CapsTypography : DefaultTextRunTypographyProperties
{
public override FontCapitals Capitals {
get { return FontCapitals.SmallCaps; }
}
}
但是,只有在使用支持它们的OpenType字体时,WPF才会呈现小型大写字母。在我的测试中,Cambria
使用小型大写字母,而大多数其他字体则没有。
此外,SetTypographyProperties
方法和DefaultTextRunTypographyProperties
类需要AvalonEdit 4.3。