描述如何在非等宽文本中处理导航的标准?
Standards describing how navigation is handled in non-monospace text?
对于最近的一个项目,我一直在开发一个简单的文字处理器,并且因为我需要细粒度控制,所以不得不实现很多 text shaping myself. Most of this is fairly straight-forward and described in detail places like here and here。
在处理拆分成多行的非等宽文本时,如何处理键盘上的向下或向上按下不太明显。在等宽文本中,算法很简单:将文本插入符向下移动一行,并向右移动相同数量的字符。但是可变宽度字体呢?我试过这样的算法(伪代码):
; Return text offset into next line after navigating down
function moveCaretDown():
Move text caret to start of next line
targetPixelOffset := previous pixel offset of caret in line above
textOffsetIntoLine := 0
pixelOffsetIntoLine := 0
prevDelta := Infinity
for each char in text of new line:
delta = abs(pixelOffsetIntoLine - targetPixelOffset)
; We are now further from the desired cursor offset than before, this must
; be closest slot to the caret's previous horizontal offset in this line.
if (delta > prevDelta):
return textOffsetIntoLine - 1
prevDelta = delta
pixelOffsetIntoLine += measureWidth(char)
currentOffset++
; Else return the offset of the last character in the line
return length of newline - 1
但我发现它的行为不同于主要网络浏览器 and/or 文本编辑器中的文本输入(如果需要,我可以提出一些具体示例)。 GUI 工具包或文本整形库是否为此使用了一些标准算法?我很惊讶我找不到 W3C 标准,例如,考虑到这是每个网络浏览器都需要的行为。
* 在字符串的正确位置插入换行符,处理参差不齐或完全对齐的文本等
我认为除了遵循 Principle of Least Astonishment 之外没有其他标准。如今,这通常意味着查看主要应用程序的功能,因为这可能是用户熟悉的行为。
在当前行上,您知道当前的水平偏移量。我们称它为 x
。我说的是像素位置,而不是自该行开头以来的字符数或字形数。
在目标行上,有一组可以放置插入符的水平偏移量(例如,在字形之间)。因此,您想选择与当前 x
尽可能相似的那些。
此外,如果用户连续多次垂直移动插入符,您可能希望找到最接近原始符号的 x
。当用户上下移动时,插入符号可能会水平摆动一点,但您不希望它漂移。一旦用户做了一些有意改变水平偏移的事情(例如,插入一个字符、使用水平箭头、单击鼠标等),这就是更新 x
.
的最佳时间
如果您已经有代码可以找到最接近鼠标点击的插入位置,您可以重新使用它,就好像用户点击了当前点上方或下方正好一行的点 x
.
我还看到一些编辑器(包括等宽文本编辑器)将行尾视为一种特殊情况。因此,如果您在一行的末尾向上或向下移动,则会移动到前一行或后一行的末尾。这似乎是处理段落末尾参差不齐的右侧文本和短行的好方法。
对于最近的一个项目,我一直在开发一个简单的文字处理器,并且因为我需要细粒度控制,所以不得不实现很多 text shaping myself. Most of this is fairly straight-forward and described in detail places like here and here。
在处理拆分成多行的非等宽文本时,如何处理键盘上的向下或向上按下不太明显。在等宽文本中,算法很简单:将文本插入符向下移动一行,并向右移动相同数量的字符。但是可变宽度字体呢?我试过这样的算法(伪代码):
; Return text offset into next line after navigating down
function moveCaretDown():
Move text caret to start of next line
targetPixelOffset := previous pixel offset of caret in line above
textOffsetIntoLine := 0
pixelOffsetIntoLine := 0
prevDelta := Infinity
for each char in text of new line:
delta = abs(pixelOffsetIntoLine - targetPixelOffset)
; We are now further from the desired cursor offset than before, this must
; be closest slot to the caret's previous horizontal offset in this line.
if (delta > prevDelta):
return textOffsetIntoLine - 1
prevDelta = delta
pixelOffsetIntoLine += measureWidth(char)
currentOffset++
; Else return the offset of the last character in the line
return length of newline - 1
但我发现它的行为不同于主要网络浏览器 and/or 文本编辑器中的文本输入(如果需要,我可以提出一些具体示例)。 GUI 工具包或文本整形库是否为此使用了一些标准算法?我很惊讶我找不到 W3C 标准,例如,考虑到这是每个网络浏览器都需要的行为。
* 在字符串的正确位置插入换行符,处理参差不齐或完全对齐的文本等
我认为除了遵循 Principle of Least Astonishment 之外没有其他标准。如今,这通常意味着查看主要应用程序的功能,因为这可能是用户熟悉的行为。
在当前行上,您知道当前的水平偏移量。我们称它为 x
。我说的是像素位置,而不是自该行开头以来的字符数或字形数。
在目标行上,有一组可以放置插入符的水平偏移量(例如,在字形之间)。因此,您想选择与当前 x
尽可能相似的那些。
此外,如果用户连续多次垂直移动插入符,您可能希望找到最接近原始符号的 x
。当用户上下移动时,插入符号可能会水平摆动一点,但您不希望它漂移。一旦用户做了一些有意改变水平偏移的事情(例如,插入一个字符、使用水平箭头、单击鼠标等),这就是更新 x
.
如果您已经有代码可以找到最接近鼠标点击的插入位置,您可以重新使用它,就好像用户点击了当前点上方或下方正好一行的点 x
.
我还看到一些编辑器(包括等宽文本编辑器)将行尾视为一种特殊情况。因此,如果您在一行的末尾向上或向下移动,则会移动到前一行或后一行的末尾。这似乎是处理段落末尾参差不齐的右侧文本和短行的好方法。