mirror of
https://github.com/atom/atom.git
synced 2026-04-06 03:02:13 -04:00
Merge pull request #8905 from atom/as-display-buffer-logical-coordinates
Use logical coordinates in DisplayBuffer
This commit is contained in:
@@ -26,11 +26,6 @@ class DisplayBuffer extends Model
|
||||
defaultCharWidth: null
|
||||
height: null
|
||||
width: null
|
||||
scrollTop: 0
|
||||
scrollLeft: 0
|
||||
scrollWidth: 0
|
||||
verticalScrollbarWidth: 15
|
||||
horizontalScrollbarHeight: 15
|
||||
|
||||
@deserialize: (state) ->
|
||||
state.tokenizedBuffer = TokenizedBuffer.deserialize(state.tokenizedBuffer)
|
||||
@@ -99,15 +94,11 @@ class DisplayBuffer extends Model
|
||||
id: @id
|
||||
softWrapped: @isSoftWrapped()
|
||||
editorWidthInChars: @editorWidthInChars
|
||||
scrollTop: @scrollTop
|
||||
scrollLeft: @scrollLeft
|
||||
tokenizedBuffer: @tokenizedBuffer.serialize()
|
||||
largeFileMode: @largeFileMode
|
||||
|
||||
copy: ->
|
||||
newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength(), @largeFileMode})
|
||||
newDisplayBuffer.setScrollTop(@getScrollTop())
|
||||
newDisplayBuffer.setScrollLeft(@getScrollLeft())
|
||||
|
||||
for marker in @findMarkers(displayBufferId: @id)
|
||||
marker.copy(displayBufferId: newDisplayBuffer.id)
|
||||
@@ -134,19 +125,8 @@ class DisplayBuffer extends Model
|
||||
onDidChangeCharacterWidths: (callback) ->
|
||||
@emitter.on 'did-change-character-widths', callback
|
||||
|
||||
onDidChangeScrollTop: (callback) ->
|
||||
@emitter.on 'did-change-scroll-top', callback
|
||||
|
||||
onDidChangeScrollLeft: (callback) ->
|
||||
@emitter.on 'did-change-scroll-left', callback
|
||||
|
||||
observeScrollTop: (callback) ->
|
||||
callback(@scrollTop)
|
||||
@onDidChangeScrollTop(callback)
|
||||
|
||||
observeScrollLeft: (callback) ->
|
||||
callback(@scrollLeft)
|
||||
@onDidChangeScrollLeft(callback)
|
||||
onDidRequestAutoscroll: (callback) ->
|
||||
@emitter.on 'did-request-autoscroll', callback
|
||||
|
||||
observeDecorations: (callback) ->
|
||||
callback(decoration) for decoration in @getDecorations()
|
||||
@@ -189,105 +169,24 @@ class DisplayBuffer extends Model
|
||||
|
||||
setVerticalScrollMargin: (@verticalScrollMargin) -> @verticalScrollMargin
|
||||
|
||||
getVerticalScrollMarginInPixels: -> @getVerticalScrollMargin() * @getLineHeightInPixels()
|
||||
|
||||
getHorizontalScrollMargin: -> Math.min(@horizontalScrollMargin, Math.floor(((@getWidth() / @getDefaultCharWidth()) - 1) / 2))
|
||||
setHorizontalScrollMargin: (@horizontalScrollMargin) -> @horizontalScrollMargin
|
||||
|
||||
getHorizontalScrollMarginInPixels: -> scrollMarginInPixels = @getHorizontalScrollMargin() * @getDefaultCharWidth()
|
||||
|
||||
getHorizontalScrollbarHeight: -> @horizontalScrollbarHeight
|
||||
setHorizontalScrollbarHeight: (@horizontalScrollbarHeight) -> @horizontalScrollbarHeight
|
||||
|
||||
getVerticalScrollbarWidth: -> @verticalScrollbarWidth
|
||||
setVerticalScrollbarWidth: (@verticalScrollbarWidth) -> @verticalScrollbarWidth
|
||||
|
||||
getHeight: ->
|
||||
if @height?
|
||||
@height
|
||||
else
|
||||
if @horizontallyScrollable()
|
||||
@getScrollHeight() + @getHorizontalScrollbarHeight()
|
||||
else
|
||||
@getScrollHeight()
|
||||
@height
|
||||
|
||||
setHeight: (@height) -> @height
|
||||
|
||||
getClientHeight: (reentrant) ->
|
||||
if @horizontallyScrollable(reentrant)
|
||||
@getHeight() - @getHorizontalScrollbarHeight()
|
||||
else
|
||||
@getHeight()
|
||||
|
||||
getClientWidth: (reentrant) ->
|
||||
if @verticallyScrollable(reentrant)
|
||||
@getWidth() - @getVerticalScrollbarWidth()
|
||||
else
|
||||
@getWidth()
|
||||
|
||||
horizontallyScrollable: (reentrant) ->
|
||||
return false unless @width?
|
||||
return false if @isSoftWrapped()
|
||||
if reentrant
|
||||
@getScrollWidth() > @getWidth()
|
||||
else
|
||||
@getScrollWidth() > @getClientWidth(true)
|
||||
|
||||
verticallyScrollable: (reentrant) ->
|
||||
return false unless @height?
|
||||
if reentrant
|
||||
@getScrollHeight() > @getHeight()
|
||||
else
|
||||
@getScrollHeight() > @getClientHeight(true)
|
||||
setHeight: (@height) ->
|
||||
@height
|
||||
|
||||
getWidth: ->
|
||||
if @width?
|
||||
@width
|
||||
else
|
||||
if @verticallyScrollable()
|
||||
@getScrollWidth() + @getVerticalScrollbarWidth()
|
||||
else
|
||||
@getScrollWidth()
|
||||
@width
|
||||
|
||||
setWidth: (newWidth) ->
|
||||
oldWidth = @width
|
||||
@width = newWidth
|
||||
@updateWrappedScreenLines() if newWidth isnt oldWidth and @isSoftWrapped()
|
||||
@setScrollTop(@getScrollTop()) # Ensure scrollTop is still valid in case horizontal scrollbar disappeared
|
||||
@width
|
||||
|
||||
getScrollTop: -> @scrollTop
|
||||
setScrollTop: (scrollTop) ->
|
||||
scrollTop = Math.round(Math.max(0, Math.min(@getMaxScrollTop(), scrollTop)))
|
||||
unless scrollTop is @scrollTop
|
||||
@scrollTop = scrollTop
|
||||
@emitter.emit 'did-change-scroll-top', @scrollTop
|
||||
@scrollTop
|
||||
|
||||
getMaxScrollTop: ->
|
||||
@getScrollHeight() - @getClientHeight()
|
||||
|
||||
getScrollBottom: -> @scrollTop + @getClientHeight()
|
||||
setScrollBottom: (scrollBottom) ->
|
||||
@setScrollTop(scrollBottom - @getClientHeight())
|
||||
@getScrollBottom()
|
||||
|
||||
getScrollLeft: -> @scrollLeft
|
||||
setScrollLeft: (scrollLeft) ->
|
||||
scrollLeft = Math.round(Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft)))
|
||||
unless scrollLeft is @scrollLeft
|
||||
@scrollLeft = scrollLeft
|
||||
@emitter.emit 'did-change-scroll-left', @scrollLeft
|
||||
@scrollLeft
|
||||
|
||||
getMaxScrollLeft: ->
|
||||
@getScrollWidth() - @getClientWidth()
|
||||
|
||||
getScrollRight: -> @scrollLeft + @width
|
||||
setScrollRight: (scrollRight) ->
|
||||
@setScrollLeft(scrollRight - @width)
|
||||
@getScrollRight()
|
||||
|
||||
getLineHeightInPixels: -> @lineHeightInPixels
|
||||
setLineHeightInPixels: (@lineHeightInPixels) -> @lineHeightInPixels
|
||||
|
||||
@@ -295,7 +194,6 @@ class DisplayBuffer extends Model
|
||||
setDefaultCharWidth: (defaultCharWidth) ->
|
||||
if defaultCharWidth isnt @defaultCharWidth
|
||||
@defaultCharWidth = defaultCharWidth
|
||||
@computeScrollWidth()
|
||||
defaultCharWidth
|
||||
|
||||
getCursorWidth: -> 1
|
||||
@@ -324,84 +222,14 @@ class DisplayBuffer extends Model
|
||||
@characterWidthsChanged() unless @batchingCharacterMeasurement
|
||||
|
||||
characterWidthsChanged: ->
|
||||
@computeScrollWidth()
|
||||
@emitter.emit 'did-change-character-widths', @scopedCharacterWidthsChangeCount
|
||||
|
||||
clearScopedCharWidths: ->
|
||||
@charWidthsByScope = {}
|
||||
|
||||
getScrollHeight: ->
|
||||
lineHeight = @getLineHeightInPixels()
|
||||
return 0 unless lineHeight > 0
|
||||
|
||||
scrollHeight = @getLineCount() * lineHeight
|
||||
if @height? and @configSettings.scrollPastEnd
|
||||
scrollHeight = scrollHeight + @height - (lineHeight * 3)
|
||||
|
||||
scrollHeight
|
||||
|
||||
getScrollWidth: ->
|
||||
@scrollWidth
|
||||
|
||||
# Returns an {Array} of two numbers representing the first and the last visible rows.
|
||||
getVisibleRowRange: ->
|
||||
return [0, 0] unless @getLineHeightInPixels() > 0
|
||||
|
||||
startRow = Math.floor(@getScrollTop() / @getLineHeightInPixels())
|
||||
endRow = Math.ceil((@getScrollTop() + @getHeight()) / @getLineHeightInPixels()) - 1
|
||||
endRow = Math.min(@getLineCount(), endRow)
|
||||
|
||||
[startRow, endRow]
|
||||
|
||||
intersectsVisibleRowRange: (startRow, endRow) ->
|
||||
[visibleStart, visibleEnd] = @getVisibleRowRange()
|
||||
not (endRow <= visibleStart or visibleEnd <= startRow)
|
||||
|
||||
selectionIntersectsVisibleRowRange: (selection) ->
|
||||
{start, end} = selection.getScreenRange()
|
||||
@intersectsVisibleRowRange(start.row, end.row + 1)
|
||||
|
||||
scrollToScreenRange: (screenRange, options) ->
|
||||
verticalScrollMarginInPixels = @getVerticalScrollMarginInPixels()
|
||||
horizontalScrollMarginInPixels = @getHorizontalScrollMarginInPixels()
|
||||
|
||||
{top, left} = @pixelRectForScreenRange(new Range(screenRange.start, screenRange.start))
|
||||
{top: endTop, left: endLeft, height: endHeight} = @pixelRectForScreenRange(new Range(screenRange.end, screenRange.end))
|
||||
bottom = endTop + endHeight
|
||||
right = endLeft
|
||||
|
||||
if options?.center
|
||||
desiredScrollCenter = (top + bottom) / 2
|
||||
unless @getScrollTop() < desiredScrollCenter < @getScrollBottom()
|
||||
desiredScrollTop = desiredScrollCenter - @getHeight() / 2
|
||||
desiredScrollBottom = desiredScrollCenter + @getHeight() / 2
|
||||
else
|
||||
desiredScrollTop = top - verticalScrollMarginInPixels
|
||||
desiredScrollBottom = bottom + verticalScrollMarginInPixels
|
||||
|
||||
desiredScrollLeft = left - horizontalScrollMarginInPixels
|
||||
desiredScrollRight = right + horizontalScrollMarginInPixels
|
||||
|
||||
if options?.reversed ? true
|
||||
if desiredScrollBottom > @getScrollBottom()
|
||||
@setScrollBottom(desiredScrollBottom)
|
||||
if desiredScrollTop < @getScrollTop()
|
||||
@setScrollTop(desiredScrollTop)
|
||||
|
||||
if desiredScrollRight > @getScrollRight()
|
||||
@setScrollRight(desiredScrollRight)
|
||||
if desiredScrollLeft < @getScrollLeft()
|
||||
@setScrollLeft(desiredScrollLeft)
|
||||
else
|
||||
if desiredScrollTop < @getScrollTop()
|
||||
@setScrollTop(desiredScrollTop)
|
||||
if desiredScrollBottom > @getScrollBottom()
|
||||
@setScrollBottom(desiredScrollBottom)
|
||||
|
||||
if desiredScrollLeft < @getScrollLeft()
|
||||
@setScrollLeft(desiredScrollLeft)
|
||||
if desiredScrollRight > @getScrollRight()
|
||||
@setScrollRight(desiredScrollRight)
|
||||
scrollToScreenRange: (screenRange, options = {}) ->
|
||||
scrollEvent = {screenRange, options}
|
||||
@emitter.emit "did-request-autoscroll", scrollEvent
|
||||
|
||||
scrollToScreenPosition: (screenPosition, options) ->
|
||||
@scrollToScreenRange(new Range(screenPosition, screenPosition), options)
|
||||
@@ -409,19 +237,6 @@ class DisplayBuffer extends Model
|
||||
scrollToBufferPosition: (bufferPosition, options) ->
|
||||
@scrollToScreenPosition(@screenPositionForBufferPosition(bufferPosition), options)
|
||||
|
||||
pixelRectForScreenRange: (screenRange) ->
|
||||
if screenRange.end.row > screenRange.start.row
|
||||
top = @pixelPositionForScreenPosition(screenRange.start).top
|
||||
left = 0
|
||||
height = (screenRange.end.row - screenRange.start.row + 1) * @getLineHeightInPixels()
|
||||
width = @getScrollWidth()
|
||||
else
|
||||
{top, left} = @pixelPositionForScreenPosition(screenRange.start, false)
|
||||
height = @getLineHeightInPixels()
|
||||
width = @pixelPositionForScreenPosition(screenRange.end, false).left - left
|
||||
|
||||
{top, left, width, height}
|
||||
|
||||
# Retrieves the current tab length.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
@@ -465,8 +280,7 @@ class DisplayBuffer extends Model
|
||||
|
||||
# Returns the editor width in characters for soft wrap.
|
||||
getEditorWidthInChars: ->
|
||||
width = @width ? @getScrollWidth()
|
||||
width -= @getVerticalScrollbarWidth()
|
||||
width = @getWidth()
|
||||
if width? and @defaultCharWidth > 0
|
||||
Math.max(0, Math.floor(width / @defaultCharWidth))
|
||||
else
|
||||
@@ -678,80 +492,6 @@ class DisplayBuffer extends Model
|
||||
end = @bufferPositionForScreenPosition(screenRange.end)
|
||||
new Range(start, end)
|
||||
|
||||
pixelRangeForScreenRange: (screenRange, clip=true) ->
|
||||
{start, end} = Range.fromObject(screenRange)
|
||||
{start: @pixelPositionForScreenPosition(start, clip), end: @pixelPositionForScreenPosition(end, clip)}
|
||||
|
||||
pixelPositionForScreenPosition: (screenPosition, clip=true) ->
|
||||
screenPosition = Point.fromObject(screenPosition)
|
||||
screenPosition = @clipScreenPosition(screenPosition) if clip
|
||||
|
||||
targetRow = screenPosition.row
|
||||
targetColumn = screenPosition.column
|
||||
defaultCharWidth = @defaultCharWidth
|
||||
|
||||
top = targetRow * @lineHeightInPixels
|
||||
left = 0
|
||||
column = 0
|
||||
|
||||
iterator = @tokenizedLineForScreenRow(targetRow).getTokenIterator()
|
||||
while iterator.next()
|
||||
charWidths = @getScopedCharWidths(iterator.getScopes())
|
||||
valueIndex = 0
|
||||
value = iterator.getText()
|
||||
while valueIndex < value.length
|
||||
if iterator.isPairedCharacter()
|
||||
char = value
|
||||
charLength = 2
|
||||
valueIndex += 2
|
||||
else
|
||||
char = value[valueIndex]
|
||||
charLength = 1
|
||||
valueIndex++
|
||||
|
||||
return {top, left} if column is targetColumn
|
||||
left += charWidths[char] ? defaultCharWidth unless char is '\0'
|
||||
column += charLength
|
||||
{top, left}
|
||||
|
||||
screenPositionForPixelPosition: (pixelPosition) ->
|
||||
targetTop = pixelPosition.top
|
||||
targetLeft = pixelPosition.left
|
||||
defaultCharWidth = @defaultCharWidth
|
||||
row = Math.floor(targetTop / @getLineHeightInPixels())
|
||||
targetLeft = 0 if row < 0
|
||||
targetLeft = Infinity if row > @getLastRow()
|
||||
row = Math.min(row, @getLastRow())
|
||||
row = Math.max(0, row)
|
||||
|
||||
left = 0
|
||||
column = 0
|
||||
|
||||
iterator = @tokenizedLineForScreenRow(row).getTokenIterator()
|
||||
while iterator.next()
|
||||
charWidths = @getScopedCharWidths(iterator.getScopes())
|
||||
value = iterator.getText()
|
||||
valueIndex = 0
|
||||
while valueIndex < value.length
|
||||
if iterator.isPairedCharacter()
|
||||
char = value
|
||||
charLength = 2
|
||||
valueIndex += 2
|
||||
else
|
||||
char = value[valueIndex]
|
||||
charLength = 1
|
||||
valueIndex++
|
||||
|
||||
charWidth = charWidths[char] ? defaultCharWidth
|
||||
break if targetLeft <= left + (charWidth / 2)
|
||||
left += charWidth
|
||||
column += charLength
|
||||
|
||||
new Point(row, column)
|
||||
|
||||
pixelPositionForBufferPosition: (bufferPosition) ->
|
||||
@pixelPositionForScreenPosition(@screenPositionForBufferPosition(bufferPosition))
|
||||
|
||||
# Gets the number of screen lines.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
@@ -1191,7 +931,6 @@ class DisplayBuffer extends Model
|
||||
@changeCount = @tokenizedBuffer.changeCount
|
||||
{start, end, delta, bufferChange} = tokenizedBufferChange
|
||||
@updateScreenLines(start, end + 1, delta, refreshMarkers: false)
|
||||
@setScrollTop(Math.min(@getScrollTop(), @getMaxScrollTop())) if delta < 0
|
||||
|
||||
updateScreenLines: (startBufferRow, endBufferRow, bufferDelta=0, options={}) ->
|
||||
return if @largeFileMode
|
||||
@@ -1296,13 +1035,6 @@ class DisplayBuffer extends Model
|
||||
@longestScreenRow = screenRow
|
||||
@maxLineLength = length
|
||||
|
||||
@computeScrollWidth() if oldMaxLineLength isnt @maxLineLength
|
||||
|
||||
computeScrollWidth: ->
|
||||
@scrollWidth = @pixelPositionForScreenPosition([@longestScreenRow, @maxLineLength]).left
|
||||
@scrollWidth += 1 unless @isSoftWrapped()
|
||||
@setScrollLeft(Math.min(@getScrollLeft(), @getMaxScrollLeft()))
|
||||
|
||||
handleBufferMarkerCreated: (textBufferMarker) =>
|
||||
if textBufferMarker.matchesParams(@getFoldMarkerAttributes())
|
||||
fold = new Fold(this, textBufferMarker)
|
||||
|
||||
@@ -368,6 +368,3 @@ class Marker
|
||||
@wasValid = isValid
|
||||
|
||||
@emitter.emit 'did-change', changeEvent
|
||||
|
||||
getPixelRange: ->
|
||||
@displayBuffer.pixelRangeForScreenRange(@getScreenRange(), false)
|
||||
|
||||
@@ -50,8 +50,10 @@ class TextEditorComponent
|
||||
|
||||
@presenter = new TextEditorPresenter
|
||||
model: @editor
|
||||
scrollTop: @editor.getScrollTop()
|
||||
scrollLeft: @editor.getScrollLeft()
|
||||
scrollTop: 0
|
||||
scrollLeft: 0
|
||||
scrollRow: @editor.getScrollRow()
|
||||
scrollColumn: @editor.getScrollColumn()
|
||||
tileSize: tileSize
|
||||
cursorBlinkPeriod: @cursorBlinkPeriod
|
||||
cursorBlinkResumeDelay: @cursorBlinkResumeDelay
|
||||
@@ -314,7 +316,7 @@ class TextEditorComponent
|
||||
inputNode.value = event.data if insertedRange
|
||||
|
||||
onVerticalScroll: (scrollTop) =>
|
||||
return if @updateRequested or scrollTop is @editor.getScrollTop()
|
||||
return if @updateRequested or scrollTop is @presenter.getScrollTop()
|
||||
|
||||
animationFramePending = @pendingScrollTop?
|
||||
@pendingScrollTop = scrollTop
|
||||
@@ -323,15 +325,17 @@ class TextEditorComponent
|
||||
pendingScrollTop = @pendingScrollTop
|
||||
@pendingScrollTop = null
|
||||
@presenter.setScrollTop(pendingScrollTop)
|
||||
@presenter.commitPendingScrollTopPosition()
|
||||
|
||||
onHorizontalScroll: (scrollLeft) =>
|
||||
return if @updateRequested or scrollLeft is @editor.getScrollLeft()
|
||||
return if @updateRequested or scrollLeft is @presenter.getScrollLeft()
|
||||
|
||||
animationFramePending = @pendingScrollLeft?
|
||||
@pendingScrollLeft = scrollLeft
|
||||
unless animationFramePending
|
||||
@requestAnimationFrame =>
|
||||
@presenter.setScrollLeft(@pendingScrollLeft)
|
||||
@presenter.commitPendingScrollLeftPosition()
|
||||
@pendingScrollLeft = null
|
||||
|
||||
onMouseWheel: (event) =>
|
||||
@@ -350,14 +354,18 @@ class TextEditorComponent
|
||||
if Math.abs(wheelDeltaX) > Math.abs(wheelDeltaY)
|
||||
# Scrolling horizontally
|
||||
previousScrollLeft = @presenter.getScrollLeft()
|
||||
@presenter.setScrollLeft(previousScrollLeft - Math.round(wheelDeltaX * @scrollSensitivity))
|
||||
event.preventDefault() unless previousScrollLeft is @presenter.getScrollLeft()
|
||||
updatedScrollLeft = previousScrollLeft - Math.round(wheelDeltaX * @scrollSensitivity)
|
||||
|
||||
event.preventDefault() if @presenter.canScrollLeftTo(updatedScrollLeft)
|
||||
@presenter.setScrollLeft(updatedScrollLeft)
|
||||
else
|
||||
# Scrolling vertically
|
||||
@presenter.setMouseWheelScreenRow(@screenRowForNode(event.target))
|
||||
previousScrollTop = @presenter.getScrollTop()
|
||||
@presenter.setScrollTop(previousScrollTop - Math.round(wheelDeltaY * @scrollSensitivity))
|
||||
event.preventDefault() unless previousScrollTop is @presenter.getScrollTop()
|
||||
updatedScrollTop = previousScrollTop - Math.round(wheelDeltaY * @scrollSensitivity)
|
||||
|
||||
event.preventDefault() if @presenter.canScrollTopTo(updatedScrollTop)
|
||||
@presenter.setScrollTop(updatedScrollTop)
|
||||
|
||||
onScrollViewScroll: =>
|
||||
if @mounted
|
||||
@@ -365,6 +373,77 @@ class TextEditorComponent
|
||||
@scrollViewNode.scrollTop = 0
|
||||
@scrollViewNode.scrollLeft = 0
|
||||
|
||||
onDidChangeScrollTop: (callback) ->
|
||||
@presenter.onDidChangeScrollTop(callback)
|
||||
|
||||
onDidChangeScrollLeft: (callback) ->
|
||||
@presenter.onDidChangeScrollLeft(callback)
|
||||
|
||||
setScrollLeft: (scrollLeft) ->
|
||||
@presenter.setScrollLeft(scrollLeft)
|
||||
|
||||
setScrollRight: (scrollRight) ->
|
||||
@presenter.setScrollRight(scrollRight)
|
||||
|
||||
setScrollTop: (scrollTop) ->
|
||||
@presenter.setScrollTop(scrollTop)
|
||||
|
||||
setScrollBottom: (scrollBottom) ->
|
||||
@presenter.setScrollBottom(scrollBottom)
|
||||
|
||||
getScrollTop: ->
|
||||
@presenter.getScrollTop()
|
||||
|
||||
getScrollLeft: ->
|
||||
@presenter.getScrollLeft()
|
||||
|
||||
getScrollRight: ->
|
||||
@presenter.getScrollRight()
|
||||
|
||||
getScrollBottom: ->
|
||||
@presenter.getScrollBottom()
|
||||
|
||||
getScrollHeight: ->
|
||||
@presenter.getScrollHeight()
|
||||
|
||||
getScrollWidth: ->
|
||||
@presenter.getScrollWidth()
|
||||
|
||||
getVerticalScrollbarWidth: ->
|
||||
@presenter.getVerticalScrollbarWidth()
|
||||
|
||||
getHorizontalScrollbarHeight: ->
|
||||
@presenter.getHorizontalScrollbarHeight()
|
||||
|
||||
getVisibleRowRange: ->
|
||||
@presenter.getVisibleRowRange()
|
||||
|
||||
pixelPositionForScreenPosition: (screenPosition) ->
|
||||
position = @presenter.pixelPositionForScreenPosition(screenPosition)
|
||||
position.top += @presenter.getScrollTop()
|
||||
position.left += @presenter.getScrollLeft()
|
||||
position
|
||||
|
||||
screenPositionForPixelPosition: (pixelPosition) ->
|
||||
@presenter.screenPositionForPixelPosition(pixelPosition)
|
||||
|
||||
pixelRectForScreenRange: (screenRange) ->
|
||||
rect = @presenter.pixelRectForScreenRange(screenRange)
|
||||
rect.top += @presenter.getScrollTop()
|
||||
rect.bottom += @presenter.getScrollTop()
|
||||
rect.left += @presenter.getScrollLeft()
|
||||
rect.right += @presenter.getScrollLeft()
|
||||
rect
|
||||
|
||||
pixelRangeForScreenRange: (screenRange, clip=true) ->
|
||||
{start, end} = Range.fromObject(screenRange)
|
||||
{start: @pixelPositionForScreenPosition(start, clip), end: @pixelPositionForScreenPosition(end, clip)}
|
||||
|
||||
pixelPositionForBufferPosition: (bufferPosition) ->
|
||||
@pixelPositionForScreenPosition(
|
||||
@editor.screenPositionForBufferPosition(bufferPosition)
|
||||
)
|
||||
|
||||
onMouseDown: (event) =>
|
||||
unless event.button is 0 or (event.button is 1 and process.platform is 'linux')
|
||||
# Only handle mouse down events for left mouse button on all platforms
|
||||
@@ -546,9 +625,11 @@ class TextEditorComponent
|
||||
|
||||
if mouseYDelta?
|
||||
@presenter.setScrollTop(@presenter.getScrollTop() + yDirection * scaleScrollDelta(mouseYDelta))
|
||||
@presenter.commitPendingScrollTopPosition()
|
||||
|
||||
if mouseXDelta?
|
||||
@presenter.setScrollLeft(@presenter.getScrollLeft() + xDirection * scaleScrollDelta(mouseXDelta))
|
||||
@presenter.commitPendingScrollLeftPosition()
|
||||
|
||||
scaleScrollDelta = (scrollDelta) ->
|
||||
Math.pow(scrollDelta / 2, 3) / 280
|
||||
@@ -774,19 +855,22 @@ class TextEditorComponent
|
||||
|
||||
screenPositionForMouseEvent: (event, linesClientRect) ->
|
||||
pixelPosition = @pixelPositionForMouseEvent(event, linesClientRect)
|
||||
@editor.screenPositionForPixelPosition(pixelPosition)
|
||||
@presenter.screenPositionForPixelPosition(pixelPosition)
|
||||
|
||||
pixelPositionForMouseEvent: (event, linesClientRect) ->
|
||||
{clientX, clientY} = event
|
||||
|
||||
linesClientRect ?= @linesComponent.getDomNode().getBoundingClientRect()
|
||||
top = clientY - linesClientRect.top + @presenter.scrollTop
|
||||
left = clientX - linesClientRect.left + @presenter.scrollLeft
|
||||
bottom = linesClientRect.top + @presenter.scrollTop + linesClientRect.height - clientY
|
||||
right = linesClientRect.left + @presenter.scrollLeft + linesClientRect.width - clientX
|
||||
top = clientY - linesClientRect.top + @presenter.getRealScrollTop()
|
||||
left = clientX - linesClientRect.left + @presenter.getRealScrollLeft()
|
||||
bottom = linesClientRect.top + @presenter.getRealScrollTop() + linesClientRect.height - clientY
|
||||
right = linesClientRect.left + @presenter.getRealScrollLeft() + linesClientRect.width - clientX
|
||||
|
||||
{top, left, bottom, right}
|
||||
|
||||
getGutterWidth: ->
|
||||
@presenter.getGutterWidth()
|
||||
|
||||
getModel: ->
|
||||
@editor
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ class TextEditorElement extends HTMLElement
|
||||
#
|
||||
# Returns an {Object} with two values: `top` and `left`, representing the pixel position.
|
||||
pixelPositionForBufferPosition: (bufferPosition) ->
|
||||
@getModel().pixelPositionForBufferPosition(bufferPosition, true)
|
||||
@component.pixelPositionForBufferPosition(bufferPosition)
|
||||
|
||||
# Extended: Converts a screen position to a pixel position.
|
||||
#
|
||||
@@ -190,21 +190,21 @@ class TextEditorElement extends HTMLElement
|
||||
#
|
||||
# Returns an {Object} with two values: `top` and `left`, representing the pixel positions.
|
||||
pixelPositionForScreenPosition: (screenPosition) ->
|
||||
@getModel().pixelPositionForScreenPosition(screenPosition, true)
|
||||
@component.pixelPositionForScreenPosition(screenPosition)
|
||||
|
||||
# Extended: Retrieves the number of the row that is visible and currently at the
|
||||
# top of the editor.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
getFirstVisibleScreenRow: ->
|
||||
@getModel().getFirstVisibleScreenRow(true)
|
||||
@getVisibleRowRange()[0]
|
||||
|
||||
# Extended: Retrieves the number of the row that is visible and currently at the
|
||||
# bottom of the editor.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
getLastVisibleScreenRow: ->
|
||||
@getModel().getLastVisibleScreenRow(true)
|
||||
@getVisibleRowRange()[1]
|
||||
|
||||
# Extended: call the given `callback` when the editor is attached to the DOM.
|
||||
#
|
||||
@@ -218,6 +218,90 @@ class TextEditorElement extends HTMLElement
|
||||
onDidDetach: (callback) ->
|
||||
@emitter.on("did-detach", callback)
|
||||
|
||||
onDidChangeScrollTop: (callback) ->
|
||||
@component.onDidChangeScrollTop(callback)
|
||||
|
||||
onDidChangeScrollLeft: (callback) ->
|
||||
@component.onDidChangeScrollLeft(callback)
|
||||
|
||||
setScrollLeft: (scrollLeft) ->
|
||||
@component.setScrollLeft(scrollLeft)
|
||||
|
||||
setScrollRight: (scrollRight) ->
|
||||
@component.setScrollRight(scrollRight)
|
||||
|
||||
setScrollTop: (scrollTop) ->
|
||||
@component.setScrollTop(scrollTop)
|
||||
|
||||
setScrollBottom: (scrollBottom) ->
|
||||
@component.setScrollBottom(scrollBottom)
|
||||
|
||||
# Essential: Scrolls the editor to the top
|
||||
scrollToTop: ->
|
||||
@setScrollTop(0)
|
||||
|
||||
# Essential: Scrolls the editor to the bottom
|
||||
scrollToBottom: ->
|
||||
@setScrollBottom(Infinity)
|
||||
|
||||
getScrollTop: ->
|
||||
@component.getScrollTop()
|
||||
|
||||
getScrollLeft: ->
|
||||
@component.getScrollLeft()
|
||||
|
||||
getScrollRight: ->
|
||||
@component.getScrollRight()
|
||||
|
||||
getScrollBottom: ->
|
||||
@component.getScrollBottom()
|
||||
|
||||
getScrollHeight: ->
|
||||
@component.getScrollHeight()
|
||||
|
||||
getScrollWidth: ->
|
||||
@component.getScrollWidth()
|
||||
|
||||
getVerticalScrollbarWidth: ->
|
||||
@component.getVerticalScrollbarWidth()
|
||||
|
||||
getHorizontalScrollbarHeight: ->
|
||||
@component.getHorizontalScrollbarHeight()
|
||||
|
||||
getVisibleRowRange: ->
|
||||
@component.getVisibleRowRange()
|
||||
|
||||
intersectsVisibleRowRange: (startRow, endRow) ->
|
||||
[visibleStart, visibleEnd] = @getVisibleRowRange()
|
||||
not (endRow <= visibleStart or visibleEnd <= startRow)
|
||||
|
||||
selectionIntersectsVisibleRowRange: (selection) ->
|
||||
{start, end} = selection.getScreenRange()
|
||||
@intersectsVisibleRowRange(start.row, end.row + 1)
|
||||
|
||||
screenPositionForPixelPosition: (pixelPosition) ->
|
||||
@component.screenPositionForPixelPosition(pixelPosition)
|
||||
|
||||
pixelRectForScreenRange: (screenRange) ->
|
||||
@component.pixelRectForScreenRange(screenRange)
|
||||
|
||||
pixelRangeForScreenRange: (screenRange) ->
|
||||
@component.pixelRangeForScreenRange(screenRange)
|
||||
|
||||
setWidth: (width) ->
|
||||
@style.width = (@component.getGutterWidth() + width) + "px"
|
||||
@component.measureDimensions()
|
||||
|
||||
getWidth: ->
|
||||
@style.offsetWidth - @component.getGutterWidth()
|
||||
|
||||
setHeight: (height) ->
|
||||
@style.height = height + "px"
|
||||
@component.measureDimensions()
|
||||
|
||||
getHeight: ->
|
||||
@style.offsetHeight
|
||||
|
||||
stopEventPropagation = (commandListeners) ->
|
||||
newCommandListeners = {}
|
||||
for commandName, commandListener of commandListeners
|
||||
|
||||
@@ -14,7 +14,7 @@ class TextEditorPresenter
|
||||
minimumReflowInterval: 200
|
||||
|
||||
constructor: (params) ->
|
||||
{@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @boundingClientRect, @windowWidth, @windowHeight, @gutterWidth} = params
|
||||
{@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @scrollColumn, @scrollRow, @boundingClientRect, @windowWidth, @windowHeight, @gutterWidth} = params
|
||||
{horizontalScrollbarHeight, verticalScrollbarWidth} = params
|
||||
{@lineHeight, @baseCharacterWidth, @backgroundColor, @gutterBackgroundColor, @tileSize} = params
|
||||
{@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @focused} = params
|
||||
@@ -32,6 +32,7 @@ class TextEditorPresenter
|
||||
@lineNumberDecorationsByScreenRow = {}
|
||||
@customGutterDecorationsByGutterNameAndScreenRow = {}
|
||||
@transferMeasurementsToModel()
|
||||
@transferMeasurementsFromModel()
|
||||
@observeModel()
|
||||
@observeConfig()
|
||||
@buildState()
|
||||
@@ -50,14 +51,11 @@ class TextEditorPresenter
|
||||
@emitter.emit "did-update-state" if @isBatching()
|
||||
|
||||
transferMeasurementsToModel: ->
|
||||
@model.setHeight(@explicitHeight) if @explicitHeight?
|
||||
@model.setWidth(@contentFrameWidth) if @contentFrameWidth?
|
||||
@model.setLineHeightInPixels(@lineHeight) if @lineHeight?
|
||||
@model.setDefaultCharWidth(@baseCharacterWidth) if @baseCharacterWidth?
|
||||
@model.setScrollTop(@scrollTop) if @scrollTop?
|
||||
@model.setScrollLeft(@scrollLeft) if @scrollLeft?
|
||||
@model.setVerticalScrollbarWidth(@measuredVerticalScrollbarWidth) if @measuredVerticalScrollbarWidth?
|
||||
@model.setHorizontalScrollbarHeight(@measuredHorizontalScrollbarHeight) if @measuredHorizontalScrollbarHeight?
|
||||
|
||||
transferMeasurementsFromModel: ->
|
||||
@editorWidthInChars = @model.getEditorWidthInChars()
|
||||
|
||||
# Private: Determines whether {TextEditorPresenter} is currently batching changes.
|
||||
# Returns a {Boolean}, `true` if is collecting changes, `false` if is applying them.
|
||||
@@ -71,6 +69,7 @@ class TextEditorPresenter
|
||||
|
||||
@updateContentDimensions()
|
||||
@updateScrollbarDimensions()
|
||||
@updateScrollPosition()
|
||||
@updateStartRow()
|
||||
@updateEndRow()
|
||||
@updateCommonGutterState()
|
||||
@@ -115,8 +114,6 @@ class TextEditorPresenter
|
||||
|
||||
observeModel: ->
|
||||
@disposables.add @model.onDidChange =>
|
||||
@updateContentDimensions()
|
||||
|
||||
@shouldUpdateHeightState = true
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@shouldUpdateHorizontalScrollState = true
|
||||
@@ -162,8 +159,7 @@ class TextEditorPresenter
|
||||
|
||||
@disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this))
|
||||
@disposables.add @model.onDidAddCursor(@didAddCursor.bind(this))
|
||||
@disposables.add @model.onDidChangeScrollTop(@setScrollTop.bind(this))
|
||||
@disposables.add @model.onDidChangeScrollLeft(@setScrollLeft.bind(this))
|
||||
@disposables.add @model.onDidRequestAutoscroll(@requestAutoscroll.bind(this))
|
||||
@observeDecoration(decoration) for decoration in @model.getDecorations()
|
||||
@observeCursor(cursor) for cursor in @model.getCursors()
|
||||
@disposables.add @model.onDidAddGutter(@didAddGutter.bind(this))
|
||||
@@ -235,6 +231,7 @@ class TextEditorPresenter
|
||||
@shouldUpdateLineNumbersState = true
|
||||
|
||||
@updateContentDimensions()
|
||||
@updateScrollPosition()
|
||||
@updateScrollbarDimensions()
|
||||
@updateStartRow()
|
||||
@updateEndRow()
|
||||
@@ -690,6 +687,8 @@ class TextEditorPresenter
|
||||
return unless @height? and @horizontalScrollbarHeight?
|
||||
|
||||
clientHeight = @height - @horizontalScrollbarHeight
|
||||
@model.setHeight(clientHeight, true)
|
||||
|
||||
unless @clientHeight is clientHeight
|
||||
@clientHeight = clientHeight
|
||||
@updateScrollHeight()
|
||||
@@ -699,6 +698,8 @@ class TextEditorPresenter
|
||||
return unless @contentFrameWidth? and @verticalScrollbarWidth?
|
||||
|
||||
clientWidth = @contentFrameWidth - @verticalScrollbarWidth
|
||||
@model.setWidth(clientWidth, true) unless @editorWidthInChars
|
||||
|
||||
unless @clientWidth is clientWidth
|
||||
@clientWidth = clientWidth
|
||||
@updateScrollWidth()
|
||||
@@ -708,6 +709,7 @@ class TextEditorPresenter
|
||||
scrollTop = @constrainScrollTop(@scrollTop)
|
||||
unless @scrollTop is scrollTop
|
||||
@scrollTop = scrollTop
|
||||
@realScrollTop = @scrollTop
|
||||
@updateStartRow()
|
||||
@updateEndRow()
|
||||
|
||||
@@ -717,6 +719,7 @@ class TextEditorPresenter
|
||||
|
||||
updateScrollLeft: ->
|
||||
@scrollLeft = @constrainScrollLeft(@scrollLeft)
|
||||
@realScrollLeft = @scrollLeft
|
||||
|
||||
constrainScrollLeft: (scrollLeft) ->
|
||||
return scrollLeft unless scrollLeft? and @scrollWidth? and @clientWidth?
|
||||
@@ -809,26 +812,28 @@ class TextEditorPresenter
|
||||
@emitDidUpdateState()
|
||||
|
||||
setScrollTop: (scrollTop) ->
|
||||
scrollTop = @constrainScrollTop(scrollTop)
|
||||
return unless scrollTop?
|
||||
|
||||
unless @scrollTop is scrollTop or Number.isNaN(scrollTop)
|
||||
@scrollTop = scrollTop
|
||||
@model.setScrollTop(scrollTop)
|
||||
@didStartScrolling()
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@shouldUpdateHiddenInputState = true
|
||||
@shouldUpdateDecorations = true
|
||||
@shouldUpdateLinesState = true
|
||||
@shouldUpdateCursorsState = true
|
||||
@shouldUpdateLineNumbersState = true
|
||||
@shouldUpdateCustomGutterDecorationState = true
|
||||
@shouldUpdateOverlaysState = true
|
||||
@pendingScrollLogicalPosition = null
|
||||
@pendingScrollTop = scrollTop
|
||||
|
||||
@emitDidUpdateState()
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@shouldUpdateHiddenInputState = true
|
||||
@shouldUpdateDecorations = true
|
||||
@shouldUpdateLinesState = true
|
||||
@shouldUpdateCursorsState = true
|
||||
@shouldUpdateLineNumbersState = true
|
||||
@shouldUpdateCustomGutterDecorationState = true
|
||||
@shouldUpdateOverlaysState = true
|
||||
|
||||
@emitDidUpdateState()
|
||||
|
||||
getScrollTop: ->
|
||||
@scrollTop
|
||||
|
||||
getRealScrollTop: ->
|
||||
@realScrollTop ? @scrollTop
|
||||
|
||||
didStartScrolling: ->
|
||||
if @stoppedScrollingTimeoutId?
|
||||
clearTimeout(@stoppedScrollingTimeoutId)
|
||||
@@ -848,28 +853,58 @@ class TextEditorPresenter
|
||||
@emitDidUpdateState()
|
||||
|
||||
setScrollLeft: (scrollLeft) ->
|
||||
scrollLeft = @constrainScrollLeft(scrollLeft)
|
||||
unless @scrollLeft is scrollLeft or Number.isNaN(scrollLeft)
|
||||
oldScrollLeft = @scrollLeft
|
||||
@scrollLeft = scrollLeft
|
||||
@model.setScrollLeft(scrollLeft)
|
||||
@shouldUpdateHorizontalScrollState = true
|
||||
@shouldUpdateHiddenInputState = true
|
||||
@shouldUpdateCursorsState = true
|
||||
@shouldUpdateOverlaysState = true
|
||||
@shouldUpdateDecorations = true
|
||||
@shouldUpdateLinesState = true
|
||||
return unless scrollLeft?
|
||||
|
||||
@emitDidUpdateState()
|
||||
@pendingScrollLogicalPosition = null
|
||||
@pendingScrollLeft = scrollLeft
|
||||
|
||||
@shouldUpdateHorizontalScrollState = true
|
||||
@shouldUpdateHiddenInputState = true
|
||||
@shouldUpdateCursorsState = true
|
||||
@shouldUpdateOverlaysState = true
|
||||
@shouldUpdateDecorations = true
|
||||
@shouldUpdateLinesState = true
|
||||
|
||||
@emitDidUpdateState()
|
||||
|
||||
getScrollLeft: ->
|
||||
@scrollLeft
|
||||
|
||||
getRealScrollLeft: ->
|
||||
@realScrollLeft ? @scrollLeft
|
||||
|
||||
getClientHeight: ->
|
||||
if @clientHeight
|
||||
@clientHeight
|
||||
else
|
||||
@explicitHeight - @horizontalScrollbarHeight
|
||||
|
||||
getClientWidth: ->
|
||||
if @clientWidth
|
||||
@clientWidth
|
||||
else
|
||||
@contentFrameWidth - @verticalScrollbarWidth
|
||||
|
||||
getScrollBottom: -> @getScrollTop() + @getClientHeight()
|
||||
setScrollBottom: (scrollBottom) ->
|
||||
@setScrollTop(scrollBottom - @getClientHeight())
|
||||
@getScrollBottom()
|
||||
|
||||
getScrollRight: -> @getScrollLeft() + @getClientWidth()
|
||||
setScrollRight: (scrollRight) ->
|
||||
@setScrollLeft(scrollRight - @getClientWidth())
|
||||
@getScrollRight()
|
||||
|
||||
getScrollHeight: ->
|
||||
@scrollHeight
|
||||
|
||||
getScrollWidth: ->
|
||||
@scrollWidth
|
||||
|
||||
setHorizontalScrollbarHeight: (horizontalScrollbarHeight) ->
|
||||
unless @measuredHorizontalScrollbarHeight is horizontalScrollbarHeight
|
||||
oldHorizontalScrollbarHeight = @measuredHorizontalScrollbarHeight
|
||||
@measuredHorizontalScrollbarHeight = horizontalScrollbarHeight
|
||||
@model.setHorizontalScrollbarHeight(horizontalScrollbarHeight)
|
||||
@shouldUpdateScrollbarsState = true
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@shouldUpdateHorizontalScrollState = true
|
||||
@@ -881,7 +916,6 @@ class TextEditorPresenter
|
||||
unless @measuredVerticalScrollbarWidth is verticalScrollbarWidth
|
||||
oldVerticalScrollbarWidth = @measuredVerticalScrollbarWidth
|
||||
@measuredVerticalScrollbarWidth = verticalScrollbarWidth
|
||||
@model.setVerticalScrollbarWidth(verticalScrollbarWidth)
|
||||
@shouldUpdateScrollbarsState = true
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@shouldUpdateHorizontalScrollState = true
|
||||
@@ -899,7 +933,6 @@ class TextEditorPresenter
|
||||
setExplicitHeight: (explicitHeight) ->
|
||||
unless @explicitHeight is explicitHeight
|
||||
@explicitHeight = explicitHeight
|
||||
@model.setHeight(explicitHeight)
|
||||
@updateHeight()
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@shouldUpdateScrollbarsState = true
|
||||
@@ -921,10 +954,10 @@ class TextEditorPresenter
|
||||
@updateEndRow()
|
||||
|
||||
setContentFrameWidth: (contentFrameWidth) ->
|
||||
unless @contentFrameWidth is contentFrameWidth
|
||||
if @contentFrameWidth isnt contentFrameWidth or @editorWidthInChars?
|
||||
oldContentFrameWidth = @contentFrameWidth
|
||||
@contentFrameWidth = contentFrameWidth
|
||||
@model.setWidth(contentFrameWidth)
|
||||
@editorWidthInChars = null
|
||||
@updateScrollbarDimensions()
|
||||
@updateClientWidth()
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
@@ -982,6 +1015,9 @@ class TextEditorPresenter
|
||||
@gutterWidth = gutterWidth
|
||||
@updateOverlaysState()
|
||||
|
||||
getGutterWidth: ->
|
||||
@gutterWidth
|
||||
|
||||
setLineHeight: (lineHeight) ->
|
||||
unless @lineHeight is lineHeight
|
||||
@lineHeight = lineHeight
|
||||
@@ -1438,3 +1474,179 @@ class TextEditorPresenter
|
||||
@startBlinkingCursorsAfterDelay ?= _.debounce(@startBlinkingCursors, @getCursorBlinkResumeDelay())
|
||||
@startBlinkingCursorsAfterDelay()
|
||||
@emitDidUpdateState()
|
||||
|
||||
requestAutoscroll: (position) ->
|
||||
@pendingScrollLogicalPosition = position
|
||||
@pendingScrollTop = null
|
||||
@pendingScrollLeft = null
|
||||
|
||||
@shouldUpdateCursorsState = true
|
||||
@shouldUpdateCustomGutterDecorationState = true
|
||||
@shouldUpdateDecorations = true
|
||||
@shouldUpdateHiddenInputState = true
|
||||
@shouldUpdateHorizontalScrollState = true
|
||||
@shouldUpdateLinesState = true
|
||||
@shouldUpdateLineNumbersState = true
|
||||
@shouldUpdateOverlaysState = true
|
||||
@shouldUpdateScrollPosition = true
|
||||
@shouldUpdateVerticalScrollState = true
|
||||
|
||||
@emitDidUpdateState()
|
||||
|
||||
getVerticalScrollMarginInPixels: ->
|
||||
@model.getVerticalScrollMargin() * @lineHeight
|
||||
|
||||
getHorizontalScrollMarginInPixels: ->
|
||||
@model.getHorizontalScrollMargin() * @baseCharacterWidth
|
||||
|
||||
getVerticalScrollbarWidth: ->
|
||||
@verticalScrollbarWidth
|
||||
|
||||
getHorizontalScrollbarHeight: ->
|
||||
@horizontalScrollbarHeight
|
||||
|
||||
commitPendingLogicalScrollPosition: ->
|
||||
return unless @pendingScrollLogicalPosition?
|
||||
|
||||
{screenRange, options} = @pendingScrollLogicalPosition
|
||||
|
||||
verticalScrollMarginInPixels = @getVerticalScrollMarginInPixels()
|
||||
horizontalScrollMarginInPixels = @getHorizontalScrollMarginInPixels()
|
||||
|
||||
{top, left} = @pixelRectForScreenRange(new Range(screenRange.start, screenRange.start))
|
||||
{top: endTop, left: endLeft, height: endHeight} = @pixelRectForScreenRange(new Range(screenRange.end, screenRange.end))
|
||||
bottom = endTop + endHeight
|
||||
right = endLeft
|
||||
|
||||
top += @scrollTop
|
||||
bottom += @scrollTop
|
||||
left += @scrollLeft
|
||||
right += @scrollLeft
|
||||
|
||||
if options?.center
|
||||
desiredScrollCenter = (top + bottom) / 2
|
||||
unless @getScrollTop() < desiredScrollCenter < @getScrollBottom()
|
||||
desiredScrollTop = desiredScrollCenter - @getClientHeight() / 2
|
||||
desiredScrollBottom = desiredScrollCenter + @getClientHeight() / 2
|
||||
else
|
||||
desiredScrollTop = top - verticalScrollMarginInPixels
|
||||
desiredScrollBottom = bottom + verticalScrollMarginInPixels
|
||||
|
||||
desiredScrollLeft = left - horizontalScrollMarginInPixels
|
||||
desiredScrollRight = right + horizontalScrollMarginInPixels
|
||||
|
||||
if options?.reversed ? true
|
||||
if desiredScrollBottom > @getScrollBottom()
|
||||
@setScrollBottom(desiredScrollBottom)
|
||||
if desiredScrollTop < @getScrollTop()
|
||||
@setScrollTop(desiredScrollTop)
|
||||
|
||||
if desiredScrollRight > @getScrollRight()
|
||||
@setScrollRight(desiredScrollRight)
|
||||
if desiredScrollLeft < @getScrollLeft()
|
||||
@setScrollLeft(desiredScrollLeft)
|
||||
else
|
||||
if desiredScrollTop < @getScrollTop()
|
||||
@setScrollTop(desiredScrollTop)
|
||||
if desiredScrollBottom > @getScrollBottom()
|
||||
@setScrollBottom(desiredScrollBottom)
|
||||
|
||||
if desiredScrollLeft < @getScrollLeft()
|
||||
@setScrollLeft(desiredScrollLeft)
|
||||
if desiredScrollRight > @getScrollRight()
|
||||
@setScrollRight(desiredScrollRight)
|
||||
|
||||
@pendingScrollLogicalPosition = null
|
||||
|
||||
commitPendingScrollLeftPosition: ->
|
||||
return unless @pendingScrollLeft?
|
||||
|
||||
scrollLeft = @constrainScrollLeft(@pendingScrollLeft)
|
||||
if scrollLeft isnt @scrollLeft and not Number.isNaN(scrollLeft)
|
||||
@realScrollLeft = scrollLeft
|
||||
@scrollLeft = Math.round(scrollLeft)
|
||||
@scrollColumn = Math.round(@scrollLeft / @baseCharacterWidth)
|
||||
@model.setScrollColumn(@scrollColumn)
|
||||
|
||||
@emitter.emit 'did-change-scroll-left', @scrollLeft
|
||||
|
||||
@pendingScrollLeft = null
|
||||
|
||||
commitPendingScrollTopPosition: ->
|
||||
return unless @pendingScrollTop?
|
||||
|
||||
scrollTop = @constrainScrollTop(@pendingScrollTop)
|
||||
if scrollTop isnt @scrollTop and not Number.isNaN(scrollTop)
|
||||
@realScrollTop = scrollTop
|
||||
@scrollTop = Math.round(scrollTop)
|
||||
@scrollRow = Math.round(@scrollTop / @lineHeight)
|
||||
@model.setScrollRow(@scrollRow)
|
||||
|
||||
@didStartScrolling()
|
||||
@emitter.emit 'did-change-scroll-top', @scrollTop
|
||||
|
||||
@pendingScrollTop = null
|
||||
|
||||
restoreScrollPosition: ->
|
||||
return if @hasRestoredScrollPosition or not @hasPixelPositionRequirements()
|
||||
|
||||
@setScrollTop(@scrollRow * @lineHeight) if @scrollRow?
|
||||
@setScrollLeft(@scrollColumn * @baseCharacterWidth) if @scrollColumn?
|
||||
|
||||
@hasRestoredScrollPosition = true
|
||||
|
||||
updateScrollPosition: ->
|
||||
@restoreScrollPosition()
|
||||
@commitPendingLogicalScrollPosition()
|
||||
@commitPendingScrollLeftPosition()
|
||||
@commitPendingScrollTopPosition()
|
||||
|
||||
canScrollLeftTo: (scrollLeft) ->
|
||||
@scrollLeft isnt @constrainScrollLeft(scrollLeft)
|
||||
|
||||
canScrollTopTo: (scrollTop) ->
|
||||
@scrollTop isnt @constrainScrollTop(scrollTop)
|
||||
|
||||
onDidChangeScrollTop: (callback) ->
|
||||
@emitter.on 'did-change-scroll-top', callback
|
||||
|
||||
onDidChangeScrollLeft: (callback) ->
|
||||
@emitter.on 'did-change-scroll-left', callback
|
||||
|
||||
getVisibleRowRange: ->
|
||||
[@startRow, @endRow]
|
||||
|
||||
screenPositionForPixelPosition: (pixelPosition) ->
|
||||
targetTop = pixelPosition.top
|
||||
targetLeft = pixelPosition.left
|
||||
defaultCharWidth = @baseCharacterWidth
|
||||
row = Math.floor(targetTop / @lineHeight)
|
||||
targetLeft = 0 if row < 0
|
||||
targetLeft = Infinity if row > @model.getLastScreenRow()
|
||||
row = Math.min(row, @model.getLastScreenRow())
|
||||
row = Math.max(0, row)
|
||||
|
||||
left = 0
|
||||
column = 0
|
||||
|
||||
iterator = @model.tokenizedLineForScreenRow(row).getTokenIterator()
|
||||
while iterator.next()
|
||||
charWidths = @getScopedCharacterWidths(iterator.getScopes())
|
||||
value = iterator.getText()
|
||||
valueIndex = 0
|
||||
while valueIndex < value.length
|
||||
if iterator.isPairedCharacter()
|
||||
char = value
|
||||
charLength = 2
|
||||
valueIndex += 2
|
||||
else
|
||||
char = value[valueIndex]
|
||||
charLength = 1
|
||||
valueIndex++
|
||||
|
||||
charWidth = charWidths[char] ? defaultCharWidth
|
||||
break if targetLeft <= left + (charWidth / 2)
|
||||
left += charWidth
|
||||
column += charLength
|
||||
|
||||
new Point(row, column)
|
||||
|
||||
@@ -80,7 +80,7 @@ class TextEditor extends Model
|
||||
state.registerEditor = true
|
||||
new this(state)
|
||||
|
||||
constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode}={}) ->
|
||||
constructor: ({@softTabs, @scrollRow, @scrollColumn, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode}={}) ->
|
||||
super
|
||||
|
||||
@emitter = new Emitter
|
||||
@@ -109,12 +109,6 @@ class TextEditor extends Model
|
||||
|
||||
@setEncoding(atom.config.get('core.fileEncoding', scope: @getRootScopeDescriptor()))
|
||||
|
||||
@disposables.add @displayBuffer.onDidChangeScrollTop (scrollTop) =>
|
||||
@emitter.emit 'did-change-scroll-top', scrollTop
|
||||
|
||||
@disposables.add @displayBuffer.onDidChangeScrollLeft (scrollLeft) =>
|
||||
@emitter.emit 'did-change-scroll-left', scrollLeft
|
||||
|
||||
@gutterContainer = new GutterContainer(this)
|
||||
@lineNumberGutter = @gutterContainer.addGutter
|
||||
name: 'line-number'
|
||||
@@ -127,8 +121,8 @@ class TextEditor extends Model
|
||||
deserializer: 'TextEditor'
|
||||
id: @id
|
||||
softTabs: @softTabs
|
||||
scrollTop: @scrollTop
|
||||
scrollLeft: @scrollLeft
|
||||
scrollRow: @getScrollRow()
|
||||
scrollColumn: @getScrollColumn()
|
||||
displayBuffer: @displayBuffer.serialize()
|
||||
|
||||
subscribeToBuffer: ->
|
||||
@@ -433,10 +427,17 @@ class TextEditor extends Model
|
||||
@displayBuffer.onDidChangeCharacterWidths(callback)
|
||||
|
||||
onDidChangeScrollTop: (callback) ->
|
||||
@emitter.on 'did-change-scroll-top', callback
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::onDidChangeScrollTop instead.")
|
||||
|
||||
atom.views.getView(this).onDidChangeScrollTop(callback)
|
||||
|
||||
onDidChangeScrollLeft: (callback) ->
|
||||
@emitter.on 'did-change-scroll-left', callback
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::onDidChangeScrollLeft instead.")
|
||||
|
||||
atom.views.getView(this).onDidChangeScrollLeft(callback)
|
||||
|
||||
onDidRequestAutoscroll: (callback) ->
|
||||
@displayBuffer.onDidRequestAutoscroll(callback)
|
||||
|
||||
# TODO Remove once the tabs package no longer uses .on subscriptions
|
||||
onDidChangeIcon: (callback) ->
|
||||
@@ -525,6 +526,10 @@ class TextEditor extends Model
|
||||
setEditorWidthInChars: (editorWidthInChars) ->
|
||||
@displayBuffer.setEditorWidthInChars(editorWidthInChars)
|
||||
|
||||
# Returns the editor width in characters.
|
||||
getEditorWidthInChars: ->
|
||||
@displayBuffer.getEditorWidthInChars()
|
||||
|
||||
###
|
||||
Section: File Details
|
||||
###
|
||||
@@ -2852,25 +2857,27 @@ class TextEditor extends Model
|
||||
scrollToScreenPosition: (screenPosition, options) ->
|
||||
@displayBuffer.scrollToScreenPosition(screenPosition, options)
|
||||
|
||||
# Essential: Scrolls the editor to the top
|
||||
scrollToTop: ->
|
||||
@setScrollTop(0)
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::scrollToTop instead.")
|
||||
|
||||
atom.views.getView(this).scrollToTop()
|
||||
|
||||
# Essential: Scrolls the editor to the bottom
|
||||
scrollToBottom: ->
|
||||
@setScrollBottom(Infinity)
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::scrollToTop instead.")
|
||||
|
||||
atom.views.getView(this).scrollToBottom()
|
||||
|
||||
scrollToScreenRange: (screenRange, options) -> @displayBuffer.scrollToScreenRange(screenRange, options)
|
||||
|
||||
horizontallyScrollable: -> @displayBuffer.horizontallyScrollable()
|
||||
getHorizontalScrollbarHeight: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getHorizontalScrollbarHeight instead.")
|
||||
|
||||
verticallyScrollable: -> @displayBuffer.verticallyScrollable()
|
||||
atom.views.getView(this).getHorizontalScrollbarHeight()
|
||||
|
||||
getHorizontalScrollbarHeight: -> @displayBuffer.getHorizontalScrollbarHeight()
|
||||
setHorizontalScrollbarHeight: (height) -> @displayBuffer.setHorizontalScrollbarHeight(height)
|
||||
getVerticalScrollbarWidth: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getVerticalScrollbarWidth instead.")
|
||||
|
||||
getVerticalScrollbarWidth: -> @displayBuffer.getVerticalScrollbarWidth()
|
||||
setVerticalScrollbarWidth: (width) -> @displayBuffer.setVerticalScrollbarWidth(width)
|
||||
atom.views.getView(this).getVerticalScrollbarWidth()
|
||||
|
||||
pageUp: ->
|
||||
@moveUp(@getRowsPerPage())
|
||||
@@ -2933,25 +2940,21 @@ class TextEditor extends Model
|
||||
@placeholderText = placeholderText
|
||||
@emitter.emit 'did-change-placeholder-text', @placeholderText
|
||||
|
||||
getFirstVisibleScreenRow: (suppressDeprecation) ->
|
||||
unless suppressDeprecation
|
||||
deprecate("This is now a view method. Call TextEditorElement::getFirstVisibleScreenRow instead.")
|
||||
@getVisibleRowRange()[0]
|
||||
getFirstVisibleScreenRow: ->
|
||||
deprecate("This is now a view method. Call TextEditorElement::getFirstVisibleScreenRow instead.")
|
||||
atom.views.getView(this).getVisibleRowRange()[0]
|
||||
|
||||
getLastVisibleScreenRow: (suppressDeprecation) ->
|
||||
unless suppressDeprecation
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getLastVisibleScreenRow instead.")
|
||||
@getVisibleRowRange()[1]
|
||||
getLastVisibleScreenRow: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getLastVisibleScreenRow instead.")
|
||||
atom.views.getView(this).getVisibleRowRange()[1]
|
||||
|
||||
pixelPositionForBufferPosition: (bufferPosition, suppressDeprecation) ->
|
||||
unless suppressDeprecation
|
||||
Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForBufferPosition` instead")
|
||||
@displayBuffer.pixelPositionForBufferPosition(bufferPosition)
|
||||
pixelPositionForBufferPosition: (bufferPosition) ->
|
||||
Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForBufferPosition` instead")
|
||||
atom.views.getView(this).pixelPositionForBufferPosition(bufferPosition)
|
||||
|
||||
pixelPositionForScreenPosition: (screenPosition, suppressDeprecation) ->
|
||||
unless suppressDeprecation
|
||||
Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForScreenPosition` instead")
|
||||
@displayBuffer.pixelPositionForScreenPosition(screenPosition)
|
||||
pixelPositionForScreenPosition: (screenPosition) ->
|
||||
Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForScreenPosition` instead")
|
||||
atom.views.getView(this).pixelPositionForScreenPosition(screenPosition)
|
||||
|
||||
getSelectionMarkerAttributes: ->
|
||||
{type: 'selection', editorId: @id, invalidate: 'never', maintainHistory: true}
|
||||
@@ -2977,38 +2980,110 @@ class TextEditor extends Model
|
||||
getDefaultCharWidth: -> @displayBuffer.getDefaultCharWidth()
|
||||
setDefaultCharWidth: (defaultCharWidth) -> @displayBuffer.setDefaultCharWidth(defaultCharWidth)
|
||||
|
||||
setHeight: (height) -> @displayBuffer.setHeight(height)
|
||||
getHeight: -> @displayBuffer.getHeight()
|
||||
setHeight: (height, reentrant=false) ->
|
||||
if reentrant
|
||||
@displayBuffer.setHeight(height)
|
||||
else
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setHeight instead.")
|
||||
atom.views.getView(this).setHeight(height)
|
||||
|
||||
getHeight: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getHeight instead.")
|
||||
@displayBuffer.getHeight()
|
||||
|
||||
getClientHeight: -> @displayBuffer.getClientHeight()
|
||||
|
||||
setWidth: (width) -> @displayBuffer.setWidth(width)
|
||||
getWidth: -> @displayBuffer.getWidth()
|
||||
setWidth: (width, reentrant=false) ->
|
||||
if reentrant
|
||||
@displayBuffer.setWidth(width)
|
||||
else
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setWidth instead.")
|
||||
atom.views.getView(this).setWidth(width)
|
||||
|
||||
getScrollTop: -> @displayBuffer.getScrollTop()
|
||||
setScrollTop: (scrollTop) -> @displayBuffer.setScrollTop(scrollTop)
|
||||
getWidth: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getWidth instead.")
|
||||
@displayBuffer.getWidth()
|
||||
|
||||
getScrollBottom: -> @displayBuffer.getScrollBottom()
|
||||
setScrollBottom: (scrollBottom) -> @displayBuffer.setScrollBottom(scrollBottom)
|
||||
getScrollRow: -> @scrollRow
|
||||
setScrollRow: (@scrollRow) ->
|
||||
|
||||
getScrollLeft: -> @displayBuffer.getScrollLeft()
|
||||
setScrollLeft: (scrollLeft) -> @displayBuffer.setScrollLeft(scrollLeft)
|
||||
getScrollColumn: -> @scrollColumn
|
||||
setScrollColumn: (@scrollColumn) ->
|
||||
|
||||
getScrollRight: -> @displayBuffer.getScrollRight()
|
||||
setScrollRight: (scrollRight) -> @displayBuffer.setScrollRight(scrollRight)
|
||||
getScrollTop: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollTop instead.")
|
||||
|
||||
getScrollHeight: -> @displayBuffer.getScrollHeight()
|
||||
getScrollWidth: -> @displayBuffer.getScrollWidth()
|
||||
atom.views.getView(this).getScrollTop()
|
||||
|
||||
getVisibleRowRange: -> @displayBuffer.getVisibleRowRange()
|
||||
setScrollTop: (scrollTop) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollTop instead.")
|
||||
|
||||
intersectsVisibleRowRange: (startRow, endRow) -> @displayBuffer.intersectsVisibleRowRange(startRow, endRow)
|
||||
atom.views.getView(this).setScrollTop(scrollTop)
|
||||
|
||||
selectionIntersectsVisibleRowRange: (selection) -> @displayBuffer.selectionIntersectsVisibleRowRange(selection)
|
||||
getScrollBottom: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollBottom instead.")
|
||||
|
||||
screenPositionForPixelPosition: (pixelPosition) -> @displayBuffer.screenPositionForPixelPosition(pixelPosition)
|
||||
atom.views.getView(this).getScrollBottom()
|
||||
|
||||
pixelRectForScreenRange: (screenRange) -> @displayBuffer.pixelRectForScreenRange(screenRange)
|
||||
setScrollBottom: (scrollBottom) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollBottom instead.")
|
||||
|
||||
atom.views.getView(this).setScrollBottom(scrollBottom)
|
||||
|
||||
getScrollLeft: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollLeft instead.")
|
||||
|
||||
atom.views.getView(this).getScrollLeft()
|
||||
|
||||
setScrollLeft: (scrollLeft) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollLeft instead.")
|
||||
|
||||
atom.views.getView(this).setScrollLeft(scrollLeft)
|
||||
|
||||
getScrollRight: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollRight instead.")
|
||||
|
||||
atom.views.getView(this).getScrollRight()
|
||||
|
||||
setScrollRight: (scrollRight) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollRight instead.")
|
||||
|
||||
atom.views.getView(this).setScrollRight(scrollRight)
|
||||
|
||||
getScrollHeight: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollHeight instead.")
|
||||
|
||||
atom.views.getView(this).getScrollHeight()
|
||||
|
||||
getScrollWidth: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollWidth instead.")
|
||||
|
||||
atom.views.getView(this).getScrollWidth()
|
||||
|
||||
getVisibleRowRange: ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getVisibleRowRange instead.")
|
||||
|
||||
atom.views.getView(this).getVisibleRowRange()
|
||||
|
||||
intersectsVisibleRowRange: (startRow, endRow) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::intersectsVisibleRowRange instead.")
|
||||
|
||||
atom.views.getView(this).intersectsVisibleRowRange(startRow, endRow)
|
||||
|
||||
selectionIntersectsVisibleRowRange: (selection) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::selectionIntersectsVisibleRowRange instead.")
|
||||
|
||||
atom.views.getView(this).selectionIntersectsVisibleRowRange(selection)
|
||||
|
||||
screenPositionForPixelPosition: (pixelPosition) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::screenPositionForPixelPosition instead.")
|
||||
|
||||
atom.views.getView(this).screenPositionForPixelPosition(pixelPosition)
|
||||
|
||||
pixelRectForScreenRange: (screenRange) ->
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::pixelRectForScreenRange instead.")
|
||||
|
||||
atom.views.getView(this).pixelRectForScreenRange(screenRange)
|
||||
|
||||
###
|
||||
Section: Utility
|
||||
|
||||
Reference in New Issue
Block a user