Initial support for variable width fonts

When translating a logical screen position (columns/rows) to a pixel
position, the editor now builds a temporary version of the line for the
given row. It then uses the DOM range API to insert an empty range
at the correct text node and offset for the given column and determines
the left position based on its clientRect.

Depending on the speed impact, we may want to optimize this by
recycling the existing line node if it exists on screen rather than
building a new one every time. We will still have to build one if the
line we're moving to isn't on screen yet. We could also increase the
chances of the line being on screen by autoscrolling to the vertical
position first, and *then* calculating the horizontal position. Lots
to explore here.
This commit is contained in:
Nathan Sobo
2013-02-09 16:36:29 -07:00
parent 8922a27eb3
commit 81145eb35f
2 changed files with 38 additions and 2 deletions

View File

@@ -1184,8 +1184,31 @@ class Editor extends View
@pixelPositionForScreenPosition(@screenPositionForBufferPosition(position))
pixelPositionForScreenPosition: (position) ->
position = Point.fromObject(position)
{ top: position.row * @lineHeight, left: position.column * @charWidth }
{row, column} = Point.fromObject(position)
[lineElement] = @buildLineElementsForScreenRows(row, row)
@renderedLines.append(lineElement)
left = @positionLeftForLineAndColumn(lineElement, column)
@renderedLines[0].removeChild(lineElement)
{ top: row * @lineHeight, left: left }
positionLeftForLineAndColumn: (lineElement, column) ->
return 0 if column is 0
delta = 0
iterator = document.createNodeIterator(lineElement, NodeFilter.SHOW_TEXT, acceptNode: -> NodeFilter.FILTER_ACCEPT)
while textNode = iterator.nextNode()
nextDelta = delta + textNode.textContent.length
if nextDelta >= column
offset = column - delta
break
delta = nextDelta
range = document.createRange()
range.setEnd(textNode, offset)
range.collapse()
leftPixels = range.getClientRects()[0].left - @scrollView.offset().left + @scrollView.scrollLeft()
range.detach()
leftPixels
pixelOffsetForScreenPosition: (position) ->
{top, left} = @pixelPositionForScreenPosition(position)