Move autoScrolling methods from cursor to editor

Scroll methods are now Editor.scrollTo(), Editor.scrollHorizontally() and Editor.scrollVertically()

Editor.scrollTo() can only be called once per runloop
This commit is contained in:
Corey Johnson 2012-04-03 16:12:04 -07:00
parent bd20d34132
commit d016cc27d3
4 changed files with 206 additions and 213 deletions

View File

@ -42,46 +42,3 @@ describe "Cursor", ->
cursor.setScreenPosition([1,30])
expect(cursor.isOnEOL()).toBeTruthy()
describe "vertical auto scroll", ->
beforeEach ->
editor.attachToDom()
editor.focus()
editor.vScrollMargin = 2
it "only attempts to scroll when a cursor is visible", ->
setEditorWidthInChars(editor, 20)
setEditorHeightInChars(editor, 10)
editor.setCursorBufferPosition([11,0])
editor.addCursorAtBufferPosition([0,0])
editor.addCursorAtBufferPosition([6,50])
window.advanceClock()
offscreenScrollHandler = spyOn(editor.getCursors()[0], 'autoScrollVertically')
onscreenScrollHandler = spyOn(editor.getCursors()[1], 'autoScrollVertically')
anotherOffscreenScrollHandler = spyOn(editor.getCursors()[2], 'autoScrollVertically')
editor.moveCursorRight()
window.advanceClock()
expect(offscreenScrollHandler).not.toHaveBeenCalled()
expect(onscreenScrollHandler).toHaveBeenCalled()
expect(anotherOffscreenScrollHandler).not.toHaveBeenCalled()
it "only attempts to scroll once when multiple cursors are visible", ->
setEditorWidthInChars(editor, 20)
setEditorHeightInChars(editor, 10)
editor.setCursorBufferPosition([11,0])
editor.addCursorAtBufferPosition([0,0])
editor.addCursorAtBufferPosition([6,0])
window.advanceClock()
offscreenScrollHandler = spyOn(editor.getCursors()[0], 'autoScrollVertically')
onscreenScrollHandler = spyOn(editor.getCursors()[1], 'autoScrollVertically')
anotherOnscreenScrollHandler = spyOn(editor.getCursors()[2], 'autoScrollVertically')
editor.moveCursorRight()
window.advanceClock()
expect(offscreenScrollHandler).not.toHaveBeenCalled()
expect(onscreenScrollHandler).toHaveBeenCalled()
expect(anotherOnscreenScrollHandler).not.toHaveBeenCalled()

View File

@ -228,52 +228,6 @@ describe "Editor", ->
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0)
describe "vertical movement", ->
describe "auto-scrolling", ->
beforeEach ->
editor.attachToDom()
editor.focus()
editor.vScrollMargin = 3
it "scrolls the buffer with the specified scroll margin when cursor approaches the end of the screen", ->
editor.height(editor.lineHeight * 10)
_.times 6, -> editor.moveCursorDown()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(0)
editor.moveCursorDown()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(editor.lineHeight)
editor.moveCursorDown()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(editor.lineHeight * 2)
_.times 3, -> editor.moveCursorUp()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(editor.lineHeight * 2)
editor.moveCursorUp()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(editor.lineHeight)
editor.moveCursorUp()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(0)
it "reduces scroll margins when there isn't enough height to maintain them and scroll smoothly", ->
setEditorHeightInChars(editor, 5)
_.times 3, ->
editor.moveCursorDown()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(editor.lineHeight)
editor.moveCursorUp()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(0)
describe "goal column retention", ->
lineLengths = null
@ -353,86 +307,6 @@ describe "Editor", ->
editor.moveCursorUp()
expect(editor.getCursorScreenPosition().column).toBe 0
describe "horizontal movement", ->
describe "auto-scrolling", ->
charWidth = null
beforeEach ->
editor.attachToDom()
{charWidth} = editor
editor.hScrollMargin = 5
it "scrolls horizontally to keep the cursor on screen", ->
setEditorWidthInChars(editor, 30)
# moving right
editor.setCursorScreenPosition([2, 24])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe 0
editor.setCursorScreenPosition([2, 25])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe charWidth
editor.setCursorScreenPosition([2, 28])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe charWidth * 4
# moving left
editor.setCursorScreenPosition([2, 9])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe charWidth * 4
editor.setCursorScreenPosition([2, 8])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe charWidth * 3
editor.setCursorScreenPosition([2, 5])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe 0
it "reduces scroll margins when there isn't enough width to maintain them and scroll smoothly", ->
editor.hScrollMargin = 6
setEditorWidthInChars(editor, 7)
editor.setCursorScreenPosition([2, 3])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe(0)
editor.setCursorScreenPosition([2, 4])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe(charWidth)
editor.setCursorScreenPosition([2, 3])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe(0)
describe "when soft-wrap is on", ->
beforeEach ->
editor.setSoftWrap(true)
it "does not scroll the buffer horizontally", ->
editor.width(charWidth * 30)
# moving right
editor.setCursorScreenPosition([2, 24])
expect(editor.scroller.scrollLeft()).toBe 0
editor.setCursorScreenPosition([2, 25])
expect(editor.scroller.scrollLeft()).toBe 0
editor.setCursorScreenPosition([2, 28])
expect(editor.scroller.scrollLeft()).toBe 0
# moving left
editor.setCursorScreenPosition([2, 9])
expect(editor.scroller.scrollLeft()).toBe 0
editor.setCursorScreenPosition([2, 8])
expect(editor.scroller.scrollLeft()).toBe 0
editor.setCursorScreenPosition([2, 5])
expect(editor.scroller.scrollLeft()).toBe 0
describe "when left is pressed on the first column", ->
describe "when there is a previous line", ->
it "wraps to the end of the previous line", ->
@ -667,6 +541,169 @@ describe "Editor", ->
editor.lines.trigger 'mouseup'
expect(editor.getSelectedText()).toBe " if (items.length <= 1) return items;"
describe "scrolling", ->
describe "vertical scrolling", ->
beforeEach ->
editor.attachToDom()
editor.focus()
editor.vScrollMargin = 3
it "scrolls the buffer with the specified scroll margin when cursor approaches the end of the screen", ->
editor.height(editor.lineHeight * 10)
_.times 6, -> editor.moveCursorDown()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(0)
editor.moveCursorDown()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(editor.lineHeight)
editor.moveCursorDown()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(editor.lineHeight * 2)
_.times 3, -> editor.moveCursorUp()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(editor.lineHeight * 2)
editor.moveCursorUp()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(editor.lineHeight)
editor.moveCursorUp()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(0)
it "reduces scroll margins when there isn't enough height to maintain them and scroll smoothly", ->
setEditorHeightInChars(editor, 5)
_.times 3, ->
editor.moveCursorDown()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(editor.lineHeight)
editor.moveCursorUp()
window.advanceClock()
expect(editor.scroller.scrollTop()).toBe(0)
describe "horizontal scrolling", ->
charWidth = null
beforeEach ->
editor.attachToDom()
{charWidth} = editor
editor.hScrollMargin = 5
it "scrolls horizontally to keep the cursor on screen", ->
setEditorWidthInChars(editor, 30)
# moving right
editor.setCursorScreenPosition([2, 24])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe 0
editor.setCursorScreenPosition([2, 25])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe charWidth
editor.setCursorScreenPosition([2, 28])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe charWidth * 4
# moving left
editor.setCursorScreenPosition([2, 9])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe charWidth * 4
editor.setCursorScreenPosition([2, 8])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe charWidth * 3
editor.setCursorScreenPosition([2, 5])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe 0
it "reduces scroll margins when there isn't enough width to maintain them and scroll smoothly", ->
editor.hScrollMargin = 6
setEditorWidthInChars(editor, 7)
editor.setCursorScreenPosition([2, 3])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe(0)
editor.setCursorScreenPosition([2, 4])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe(charWidth)
editor.setCursorScreenPosition([2, 3])
window.advanceClock()
expect(editor.scroller.scrollLeft()).toBe(0)
describe "when soft-wrap is on", ->
beforeEach ->
editor.setSoftWrap(true)
it "does not scroll the buffer horizontally", ->
editor.width(charWidth * 30)
# moving right
editor.setCursorScreenPosition([2, 24])
expect(editor.scroller.scrollLeft()).toBe 0
editor.setCursorScreenPosition([2, 25])
expect(editor.scroller.scrollLeft()).toBe 0
editor.setCursorScreenPosition([2, 28])
expect(editor.scroller.scrollLeft()).toBe 0
# moving left
editor.setCursorScreenPosition([2, 9])
expect(editor.scroller.scrollLeft()).toBe 0
editor.setCursorScreenPosition([2, 8])
expect(editor.scroller.scrollLeft()).toBe 0
editor.setCursorScreenPosition([2, 5])
expect(editor.scroller.scrollLeft()).toBe 0
describe "when there are multiple cursor", ->
beforeEach ->
editor.attachToDom()
editor.focus()
editor.vScrollMargin = 2
it "only attempts to scroll when a cursor is visible", ->
setEditorWidthInChars(editor, 20)
setEditorHeightInChars(editor, 10)
editor.setCursorBufferPosition([11,0])
editor.addCursorAtBufferPosition([0,0])
editor.addCursorAtBufferPosition([6,50])
window.advanceClock()
scrollHandler = spyOn(editor, 'scrollVertically')
editor.moveCursorRight()
window.advanceClock()
position = editor.pixelPositionForScreenPosition([0,1])
expect(scrollHandler).toHaveBeenCalledWith(position)
it "only attempts to scroll once when multiple cursors are visible", ->
setEditorWidthInChars(editor, 20)
setEditorHeightInChars(editor, 10)
editor.setCursorBufferPosition([11,0])
editor.addCursorAtBufferPosition([0,0])
editor.addCursorAtBufferPosition([6,0])
window.advanceClock()
scrollHandler = spyOn(editor, 'scrollVertically')
editor.moveCursorRight()
window.advanceClock()
position = editor.pixelPositionForScreenPosition([0,1])
expect(scrollHandler).toHaveBeenCalledWith(position)
describe "auto indent/outdent", ->
beforeEach ->
editor.autoIndent = true

View File

@ -137,43 +137,4 @@ class Cursor extends View
@css(position)
if @editor.getCursors().length == 1 or @editor.screenPositionInBounds(screenPosition)
@autoScroll(position)
autoScroll: (position) ->
return if @editor._autoScrolling
@editor._autoScrolling = true
_.defer =>
@editor._autoScrolling = false
@autoScrollVertically(position)
@autoScrollHorizontally(position)
autoScrollVertically: (position) ->
linesInView = @editor.scroller.height() / @editor.lineHeight
maxScrollMargin = Math.floor((linesInView - 1) / 2)
scrollMargin = Math.min(@editor.vScrollMargin, maxScrollMargin)
margin = scrollMargin * @height()
desiredTop = position.top - margin
desiredBottom = position.top + @height() + margin
if desiredBottom > @editor.scroller.scrollBottom()
@editor.scroller.scrollBottom(desiredBottom)
else if desiredTop < @editor.scroller.scrollTop()
@editor.scroller.scrollTop(desiredTop)
autoScrollHorizontally: (position) ->
return if @editor.softWrap
charWidth = @editor.charWidth
charsInView = @editor.scroller.width() / charWidth
maxScrollMargin = Math.floor((charsInView - 1) / 2)
scrollMargin = Math.min(@editor.hScrollMargin, maxScrollMargin)
margin = scrollMargin * charWidth
desiredRight = position.left + charWidth + margin
desiredLeft = position.left - margin
if desiredRight > @editor.scroller.scrollRight()
@editor.scroller.scrollRight(desiredRight)
else if desiredLeft < @editor.scroller.scrollLeft()
@editor.scroller.scrollLeft(desiredLeft)
@editor.scrollTo(position)

View File

@ -37,6 +37,7 @@ class Editor extends View
autoIndent: null
lineCache: null
isFocused: false
isScrolling: false
initialize: ({buffer}) ->
requireStylesheet 'editor.css'
@ -328,8 +329,9 @@ class Editor extends View
clipScreenPosition: (screenPosition, options={}) ->
@renderer.clipScreenPosition(screenPosition, options)
pixelPositionForScreenPosition: ({row, column}) ->
{ top: row * @lineHeight, left: column * @charWidth }
pixelPositionForScreenPosition: (position) ->
position = Point.fromObject(position)
{ top: position.row * @lineHeight, left: position.column * @charWidth }
screenPositionFromPixelPosition: ({top, left}) ->
screenPosition = new Point(Math.floor(top / @lineHeight), Math.floor(left / @charWidth))
@ -478,5 +480,41 @@ class Editor extends View
getCurrentMode: ->
@buffer.getMode()
scrollTo: (position) ->
return if @isScrolling
@isScrolling = true
_.defer =>
@isScrolling = false
@scrollVertically(position)
@scrollHorizontally(position)
scrollVertically: (position) ->
linesInView = @scroller.height() / @lineHeight
maxScrollMargin = Math.floor((linesInView - 1) / 2)
scrollMargin = Math.min(@vScrollMargin, maxScrollMargin)
margin = scrollMargin * @lineHeight
desiredTop = position.top - margin
desiredBottom = position.top + @lineHeight + margin
if desiredBottom > @scroller.scrollBottom()
@scroller.scrollBottom(desiredBottom)
else if desiredTop < @scroller.scrollTop()
@scroller.scrollTop(desiredTop)
scrollHorizontally: (position) ->
return if @softWrap
charsInView = @scroller.width() / @charWidth
maxScrollMargin = Math.floor((charsInView - 1) / 2)
scrollMargin = Math.min(@hScrollMargin, maxScrollMargin)
margin = scrollMargin * @charWidth
desiredRight = position.left + @charWidth + margin
desiredLeft = position.left - margin
if desiredRight > @scroller.scrollRight()
@scroller.scrollRight(desiredRight)
else if desiredLeft < @scroller.scrollLeft()
@scroller.scrollLeft(desiredLeft)
logLines: ->
@renderer.logLines()