Cache the overlay dimensions in the presenter

This commit is contained in:
Ben Ogle
2015-03-31 19:11:56 -07:00
parent 01905ae55b
commit c62f06af9d
3 changed files with 87 additions and 17 deletions

View File

@@ -1,30 +1,86 @@
module.exports =
class OverlayManager
constructor: (@presenter, @container) ->
@overlayNodesById = {}
@overlaysById = {}
render: (state) ->
for decorationId, {pixelPosition, item} of state.content.overlays
@renderOverlay(state, decorationId, item, pixelPosition)
editorDimensionsHaveChanged = !@editorDimensionsAreEqual(state)
for id, overlayNode of @overlayNodesById
for decorationId, overlay of state.content.overlays
overlayHasChanged = not @overlayStateIsEqual(decorationId, overlay)
if editorDimensionsHaveChanged or overlayHasChanged
@renderOverlay(state, decorationId, overlay)
@cacheOverlayState(decorationId, overlay)
for id, {overlayNode} of @overlaysById
unless state.content.overlays.hasOwnProperty(id)
delete @overlayNodesById[id]
delete @overlaysById[id]
overlayNode.remove()
return
@cacheEditorDimensions(state)
renderOverlay: (state, decorationId, item, pixelPosition) ->
overlayStateIsEqual: (decorationId, overlay) ->
return false unless @overlaysById[decorationId]?
@overlaysById[decorationId].itemWidth is overlay.itemWidth and
@overlaysById[decorationId].itemHeight is overlay.itemHeight and
@overlaysById[decorationId].contentMargin is overlay.contentMargin and
@overlaysById[decorationId].pixelPosition?.top is overlay.pixelPosition?.top and
@overlaysById[decorationId].pixelPosition?.left is overlay.pixelPosition?.left
cacheOverlayState: (decorationId, overlay) ->
return unless @overlaysById[decorationId]?
@overlaysById[decorationId].itemWidth = overlay.itemWidth
@overlaysById[decorationId].itemHeight = overlay.itemHeight
@overlaysById[decorationId].contentMargin = overlay.contentMargin
@overlaysById[decorationId].pixelPosition = overlay.pixelPosition
cacheEditorDimensions: (state) ->
@cachedEditorDimensions =
lineHeight: @presenter.lineHeight
contentFrameWidth: @presenter.contentFrameWidth
editorTop: @presenter.boundingClientRect?.top
editorLeft: @presenter.boundingClientRect?.left
editorWidth: @presenter.boundingClientRect?.width
windowWidth: @presenter.windowWidth
windowHeight: @presenter.windowHeight
scrollTop: state.content.scrollTop
scrollLeft: state.content.scrollLeft
editorDimensionsAreEqual: (state) ->
return false unless @cachedEditorDimensions?
@cachedEditorDimensions.lineHeight is @presenter.lineHeight and
@cachedEditorDimensions.contentFrameWidth is @presenter.contentFrameWidth and
@cachedEditorDimensions.editorTop is @presenter.boundingClientRect?.top and
@cachedEditorDimensions.editorLeft is @presenter.boundingClientRect?.left and
@cachedEditorDimensions.editorWidth is @presenter.boundingClientRect?.width and
@cachedEditorDimensions.windowWidth is @presenter.windowWidth and
@cachedEditorDimensions.windowHeight is @presenter.windowHeight and
@cachedEditorDimensions.scrollTop is state.content.scrollTop and
@cachedEditorDimensions.scrollLeft is state.content.scrollLeft
measureOverlays: ->
for decorationId, {item} of @overlaysById
@measureOverlay(decorationId, item)
measureOverlay: (decorationId, item) ->
contentMargin = parseInt(getComputedStyle(item)['margin-left']) ? 0
@presenter.setOverlayDimensions(decorationId, item.offsetWidth, item.offsetHeight, contentMargin)
renderOverlay: (state, decorationId, {item, pixelPosition}) ->
item = atom.views.getView(item)
unless overlayNode = @overlayNodesById[decorationId]
overlayNode = @overlayNodesById[decorationId] = document.createElement('atom-overlay')
overlay = @overlaysById[decorationId]
unless overlayNode = overlay?.overlayNode
overlayNode = document.createElement('atom-overlay')
overlayNode.appendChild(item)
@container.appendChild(overlayNode)
@overlaysById[decorationId] = overlay = {overlayNode, item}
itemWidth = item.offsetWidth
itemHeight = item.offsetHeight
contentMargin = parseInt(getComputedStyle(item)['margin-left']) ? 0
overlayDimensions = @presenter.getOverlayDimensions(decorationId)
unless overlayDimensions?.itemWidth?
@measureOverlay(decorationId, item)
overlayDimensions = @presenter.getOverlayDimensions(decorationId)
{itemWidth, itemHeight, contentMargin} = overlayDimensions
{scrollTop, scrollLeft} = state.content
editorBounds = @presenter.boundingClientRect

View File

@@ -158,6 +158,7 @@ class TextEditorComponent
readAfterUpdateSync: =>
@linesComponent.measureCharactersInNewLines() if @isVisible() and not @newState.content.scrollingVertically
@overlayManager?.measureOverlays()
mountGutterComponent: ->
@gutterComponent = new GutterComponent({@editor, onMouseDown: @onGutterMouseDown})
@@ -189,6 +190,8 @@ class TextEditorComponent
else unless @updateRequested
@updateRequested = true
atom.views.updateDocument =>
@editor.horribleUpdateMethod?()
@editor.horribleUpdateMethod = null
@updateRequested = false
@updateSync() if @editor.isAlive()
atom.views.readDocument(@readAfterUpdateSync)
@@ -568,6 +571,7 @@ class TextEditorComponent
@sampleBackgroundColors()
@measureDimensions()
@sampleFontStyling()
@overlayManager?.measureOverlays()
checkForVisibilityChange: ->
if @isVisible()
@@ -617,11 +621,7 @@ class TextEditorComponent
measureWindowSize: ->
return unless @mounted
width = window.innerWidth
height = window.innerHeight
@presenter.setWindowSize(width, height)
@presenter.setWindowSize(window.innerWidth, window.innerHeight)
sampleFontStyling: =>
oldFontSize = @fontSize

View File

@@ -1012,6 +1012,20 @@ class TextEditorPresenter
regions
setOverlayDimensions: (decorationId, itemWidth, itemHeight, contentMargin) ->
if overlayState = @state.content.overlays[decorationId]
dimensionsAreEqual = overlayState.itemWidth is itemWidth and
overlayState.itemHeight is itemHeight and
overlayState.contentMargin is contentMargin
unless dimensionsAreEqual
overlayState.itemWidth = itemWidth
overlayState.itemHeight = itemHeight
overlayState.contentMargin = contentMargin
@updateOverlaysState()
getOverlayDimensions: (decorationId) ->
@state.content.overlays[decorationId]
observeCursor: (cursor) ->
didChangePositionDisposable = cursor.onDidChangePosition =>
@updateHiddenInputState() if cursor.isLastCursor()