Move vertical scroll state to root of presenter state object

Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
Nathan Sobo
2015-01-27 07:29:24 -07:00
parent 1ff0b20cea
commit d26e8a2df1
3 changed files with 61 additions and 53 deletions

View File

@@ -33,6 +33,31 @@ describe "TextEditorPresenter", ->
# These `describe` and `it` blocks mirror the structure of the ::state object.
# Please maintain this structure when adding specs for new state fields.
describe "::state", ->
describe ".scrollHeight", ->
it "is initialized based on the lineHeight, the number of lines, and the clientHeight", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expect(presenter.state.scrollHeight).toBe editor.getScreenLineCount() * 10
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, clientHeight: 500)
expect(presenter.state.scrollHeight).toBe 500
it "updates when the ::lineHeight changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> presenter.setLineHeight(20)
expect(presenter.state.scrollHeight).toBe editor.getScreenLineCount() * 20
it "updates when the line count changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n")
expect(presenter.state.scrollHeight).toBe editor.getScreenLineCount() * 10
describe ".scrollTop", ->
it "tracks the value of ::scrollTop", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 10, lineHeight: 10)
expect(presenter.state.scrollTop).toBe 10
expectStateUpdate presenter, -> presenter.setScrollTop(50)
expect(presenter.state.scrollTop).toBe 50
describe ".content", ->
describe ".scrollWidth", ->
it "is initialized as the max of the clientWidth and the width of the longest line", ->
@@ -79,28 +104,6 @@ describe "TextEditorPresenter", ->
expectStateUpdate presenter, -> editor.setSoftWrapped(false)
expect(presenter.state.content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1
describe ".scrollHeight", ->
it "is initialized based on the lineHeight and the number of lines", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1)
expect(presenter.state.content.scrollHeight).toBe editor.getScreenLineCount() * 10
it "updates when the ::lineHeight changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1)
expectStateUpdate presenter, -> presenter.setLineHeight(20)
expect(presenter.state.content.scrollHeight).toBe editor.getScreenLineCount() * 20
it "updates when the line count changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1)
expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n")
expect(presenter.state.content.scrollHeight).toBe editor.getScreenLineCount() * 10
describe ".scrollTop", ->
it "tracks the value of ::scrollTop", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 10, lineHeight: 10, lineOverdrawMargin: 1)
expect(presenter.state.content.scrollTop).toBe 10
expectStateUpdate presenter, -> presenter.setScrollTop(50)
expect(presenter.state.content.scrollTop).toBe 50
describe ".scrollLeft", ->
it "tracks the value of ::scrollLeft", ->
presenter = new TextEditorPresenter(model: editor, scrollLeft: 10, lineHeight: 10, lineOverdrawMargin: 1)

View File

@@ -23,9 +23,10 @@ LinesComponent = React.createClass
{editor, presenter, overlayDecorations, highlightDecorations, placeholderText, backgroundColor} = @props
{lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount, cursorPixelRects} = @props
@oldState ?= {lines: {}}
@newState = presenter.state.content
{scrollWidth, scrollHeight} = @newState
@oldState ?= {content: {lines: {}}}
@newState = presenter.state
{scrollHeight} = @newState
{scrollWidth} = @newState.content
style =
height: Math.max(scrollHeight, scrollViewHeight)
@@ -40,7 +41,8 @@ LinesComponent = React.createClass
HighlightsComponent {presenter, performedInitialMeasurement}
getTransform: ->
{scrollTop, scrollLeft} = @newState
{scrollTop} = @newState
{scrollLeft} = @newState.content
{useHardwareAcceleration} = @props
if useHardwareAcceleration
@@ -72,41 +74,41 @@ LinesComponent = React.createClass
{visible, scrollingVertically, performedInitialMeasurement} = @props
return unless performedInitialMeasurement
@removeLineNodes() unless @oldState?.indentGuidesVisible is @newState?.indentGuidesVisible
@removeLineNodes() unless @oldState?.content.indentGuidesVisible is @newState?.content.indentGuidesVisible
@updateLineNodes()
@measureCharactersInNewLines() if visible and not scrollingVertically
@overlayManager?.render(@props)
@oldState.indentGuidesVisible = @newState.indentGuidesVisible
@oldState.scrollWidth = @newState.scrollWidth
@oldState.content.indentGuidesVisible = @newState.content.indentGuidesVisible
@oldState.content.scrollWidth = @newState.content.scrollWidth
clearScreenRowCaches: ->
@screenRowsByLineId = {}
@lineIdsByScreenRow = {}
removeLineNodes: ->
@removeLineNode(id) for id of @oldState.lines
@removeLineNode(id) for id of @oldState.content.lines
removeLineNode: (id) ->
@lineNodesByLineId[id].remove()
delete @lineNodesByLineId[id]
delete @lineIdsByScreenRow[@screenRowsByLineId[id]]
delete @screenRowsByLineId[id]
delete @oldState.lines[id]
delete @oldState.content.lines[id]
updateLineNodes: ->
{presenter, mouseWheelScreenRow} = @props
for id of @oldState.lines
unless @newState.lines.hasOwnProperty(id) or mouseWheelScreenRow is @screenRowsByLineId[id]
for id of @oldState.content.lines
unless @newState.content.lines.hasOwnProperty(id) or mouseWheelScreenRow is @screenRowsByLineId[id]
@removeLineNode(id)
newLineIds = null
newLinesHTML = null
for id, lineState of @newState.lines
if @oldState.lines.hasOwnProperty(id)
for id, lineState of @newState.content.lines
if @oldState.content.lines.hasOwnProperty(id)
@updateLineNode(id)
else
newLineIds ?= []
@@ -115,7 +117,7 @@ LinesComponent = React.createClass
newLinesHTML += @buildLineHTML(id)
@screenRowsByLineId[id] = lineState.screenRow
@lineIdsByScreenRow[lineState.screenRow] = id
@oldState.lines[id] = _.clone(lineState)
@oldState.content.lines[id] = _.clone(lineState)
return unless newLineIds?
@@ -129,8 +131,8 @@ LinesComponent = React.createClass
buildLineHTML: (id) ->
{presenter} = @props
{scrollWidth} = @newState
{screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.lines[id]
{scrollWidth} = @newState.content
{screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.content.lines[id]
classes = ''
if decorationClasses?
@@ -150,8 +152,8 @@ LinesComponent = React.createClass
lineHTML
buildEmptyLineInnerHTML: (id) ->
{indentGuidesVisible} = @newState
{indentLevel, tabLength, endOfLineInvisibles} = @newState.lines[id]
{indentGuidesVisible} = @newState.content
{indentLevel, tabLength, endOfLineInvisibles} = @newState.content.lines[id]
if indentGuidesVisible and indentLevel > 0
invisibleIndex = 0
@@ -174,8 +176,8 @@ LinesComponent = React.createClass
buildLineInnerHTML: (id) ->
{editor} = @props
{indentGuidesVisible} = @newState
{tokens, text} = @newState.lines[id]
{indentGuidesVisible} = @newState.content
{tokens, text} = @newState.content.lines[id]
innerHTML = ""
scopeStack = []
@@ -191,7 +193,7 @@ LinesComponent = React.createClass
innerHTML
buildEndOfLineHTML: (id) ->
{endOfLineInvisibles} = @newState.lines[id]
{endOfLineInvisibles} = @newState.content.lines[id]
html = ''
if endOfLineInvisibles?
@@ -225,13 +227,13 @@ LinesComponent = React.createClass
"<span class=\"#{scope.replace(/\.+/g, ' ')}\">"
updateLineNode: (id) ->
{scrollWidth} = @newState
{screenRow, top} = @newState.lines[id]
{scrollWidth} = @newState.content
{screenRow, top} = @newState.content.lines[id]
lineNode = @lineNodesByLineId[id]
newDecorationClasses = @newState.lines[id].decorationClasses
oldDecorationClasses = @oldState.lines[id].decorationClasses
newDecorationClasses = @newState.content.lines[id].decorationClasses
oldDecorationClasses = @oldState.content.lines[id].decorationClasses
if oldDecorationClasses?
for decorationClass in oldDecorationClasses
@@ -276,7 +278,7 @@ LinesComponent = React.createClass
node = @getDOMNode()
editor.batchCharacterMeasurement =>
for id, lineState of @oldState.lines
for id, lineState of @oldState.content.lines
unless @measuredLines.has(id)
lineNode = @lineNodesByLineId[id]
@measureCharactersInLine(lineState, lineNode)

View File

@@ -47,16 +47,19 @@ class TextEditorPresenter
@updateState()
updateState: ->
@updateVerticalScrollState()
@updateContentState()
@updateLinesState()
@updateCursorsState()
@updateHighlightsState()
@updateLineNumbersState()
updateVerticalScrollState: ->
@state.scrollHeight = @computeScrollHeight()
@state.scrollTop = @getScrollTop()
updateContentState: ->
@state.content.scrollWidth = @computeScrollWidth()
@state.content.scrollHeight = @computeScrollHeight()
@state.content.scrollTop = @getScrollTop()
@state.content.scrollLeft = @getScrollLeft()
@state.content.indentGuidesVisible = atom.config.get('editor.showIndentGuide', scope: @model.getRootScopeDescriptor())
@emitter.emit 'did-update-state'
@@ -230,7 +233,7 @@ class TextEditorPresenter
Math.max(contentWidth, @getClientWidth())
computeScrollHeight: ->
@getLineHeight() * @model.getScreenLineCount()
Math.max(@getLineHeight() * @model.getScreenLineCount(), @getClientHeight())
lineDecorationClassesForRow: (row) ->
return null if @model.isMini()
@@ -277,7 +280,7 @@ class TextEditorPresenter
getCursorBlinkResumeDelay: -> @cursorBlinkResumeDelay
setScrollTop: (@scrollTop) ->
@updateContentState()
@updateVerticalScrollState()
@updateLinesState()
@updateCursorsState()
@updateHighlightsState()
@@ -306,7 +309,7 @@ class TextEditorPresenter
getClientWidth: -> @clientWidth
setLineHeight: (@lineHeight) ->
@updateContentState()
@updateVerticalScrollState()
@updateLinesState()
@updateCursorsState()
@updateHighlightsState()