From bed09cf0efb3afc65f2ce05f5332fe1da82b0fd4 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 1 Apr 2015 14:44:38 -0700 Subject: [PATCH] =?UTF-8?q?Presenter=20positions=20overlays=20when=20the?= =?UTF-8?q?=20overlay=20doesn=E2=80=99t=20have=20a=20size?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix presenter specs --- spec/text-editor-presenter-spec.coffee | 40 +++++++++++++++++--------- src/text-editor-presenter.coffee | 23 ++++++++------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index b62391db8..445ec6bf1 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -29,6 +29,9 @@ describe "TextEditorPresenter", -> model: editor explicitHeight: 130 contentFrameWidth: 500 + windowWidth: 500 + windowHeight: 130 + boundingClientRect: {left: 0, top: 0, width: 500, height: 130} lineHeight: 10 baseCharacterWidth: 10 horizontalScrollbarHeight: 10 @@ -1497,14 +1500,14 @@ describe "TextEditorPresenter", -> # Initial state expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 10} + pixelPosition: {top: 3 * 10 - presenter.state.content.scrollTop, left: 13 * 10} } # Change range expectStateUpdate presenter, -> marker.setBufferRange([[2, 13], [4, 6]]) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 4 * 10, left: 6 * 10} + pixelPosition: {top: 5 * 10 - presenter.state.content.scrollTop, left: 6 * 10} } # Valid -> invalid @@ -1515,14 +1518,14 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> editor.undo() expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 4 * 10, left: 6 * 10} + pixelPosition: {top: 5 * 10 - presenter.state.content.scrollTop, left: 6 * 10} } # Reverse direction expectStateUpdate presenter, -> marker.setBufferRange([[2, 13], [4, 6]], reversed: true) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 10} + pixelPosition: {top: 3 * 10 - presenter.state.content.scrollTop, left: 13 * 10} } # Destroy @@ -1533,53 +1536,56 @@ describe "TextEditorPresenter", -> decoration2 = editor.decorateMarker(marker, {type: 'overlay', item}) expectValues stateForOverlay(presenter, decoration2), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 10} + pixelPosition: {top: 3 * 10 - presenter.state.content.scrollTop, left: 13 * 10} } it "updates when ::baseCharacterWidth changes", -> item = {} + scrollTop = 20 marker = editor.markBufferPosition([2, 13], invalidate: 'touch') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) + presenter = buildPresenter({explicitHeight: 30, scrollTop}) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 10} + pixelPosition: {top: 3 * 10 - scrollTop, left: 13 * 10} } expectStateUpdate presenter, -> presenter.setBaseCharacterWidth(5) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 5} + pixelPosition: {top: 3 * 10 - scrollTop, left: 13 * 5} } it "updates when ::lineHeight changes", -> item = {} + scrollTop = 20 marker = editor.markBufferPosition([2, 13], invalidate: 'touch') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) + presenter = buildPresenter({explicitHeight: 30, scrollTop}) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 10} + pixelPosition: {top: 3 * 10 - scrollTop, left: 13 * 10} } expectStateUpdate presenter, -> presenter.setLineHeight(5) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 5, left: 13 * 10} + pixelPosition: {top: 3 * 5 - scrollTop, left: 13 * 10} } it "honors the 'position' option on overlay decorations", -> item = {} + scrollTop = 20 marker = editor.markBufferRange([[2, 13], [4, 14]], invalidate: 'touch') decoration = editor.decorateMarker(marker, {type: 'overlay', position: 'tail', item}) - presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) + presenter = buildPresenter({explicitHeight: 30, scrollTop}) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 10} + pixelPosition: {top: 3 * 10 - scrollTop, left: 13 * 10} } it "is empty until all of the required measurements are assigned", -> @@ -1587,13 +1593,19 @@ describe "TextEditorPresenter", -> marker = editor.markBufferRange([[2, 13], [4, 14]], invalidate: 'touch') decoration = editor.decorateMarker(marker, {type: 'overlay', position: 'tail', item}) - presenter = buildPresenter(baseCharacterWidth: null, lineHeight: null) + presenter = buildPresenter(baseCharacterWidth: null, lineHeight: null, windowWidth: null, windowHeight: null, boundingClientRect: null) expect(presenter.getState().content.overlays).toEqual({}) presenter.setBaseCharacterWidth(10) expect(presenter.getState().content.overlays).toEqual({}) presenter.setLineHeight(10) + expect(presenter.getState().content.overlays).toEqual({}) + + presenter.setWindowSize(500, 100) + expect(presenter.getState().content.overlays).toEqual({}) + + presenter.setBoundingClientRect({top: 0, left: 0, height: 100, width: 500}) expect(presenter.getState().content.overlays).not.toEqual({}) describe ".gutter", -> diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 4546c7893..f8703c085 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -12,7 +12,7 @@ class TextEditorPresenter overlayDimensions: {} constructor: (params) -> - {@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft} = params + {@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @boundingClientRect, @windowWidth, @windowHeight} = params {horizontalScrollbarHeight, verticalScrollbarWidth} = params {@lineHeight, @baseCharacterWidth, @lineOverdrawMargin, @backgroundColor, @gutterBackgroundColor} = params {@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @focused} = params @@ -315,7 +315,7 @@ class TextEditorPresenter @emitDidUpdateState() updateOverlaysState: -> @batch "shouldUpdateOverlaysState", -> - return unless @hasPixelRectRequirements() + return unless @hasOverlayPositionRequirements() visibleDecorationIds = {} @@ -330,14 +330,14 @@ class TextEditorPresenter pixelPosition = @pixelPositionForScreenPosition(screenPosition) + {scrollTop, scrollLeft} = @state.content + gutterWidth = @boundingClientRect.width - @contentFrameWidth + + left = pixelPosition.left - scrollLeft + gutterWidth + top = pixelPosition.top + @lineHeight - scrollTop + if overlayDimensions = @overlayDimensions[decoration.id] {itemWidth, itemHeight, contentMargin} = overlayDimensions - {scrollTop, scrollLeft} = @state.content - - gutterWidth = @boundingClientRect.width - @contentFrameWidth - - left = pixelPosition.left - scrollLeft + gutterWidth - top = pixelPosition.top + @lineHeight - scrollTop rightDiff = left + @boundingClientRect.left + itemWidth + contentMargin - @windowWidth left -= rightDiff if rightDiff > 0 @@ -348,8 +348,8 @@ class TextEditorPresenter if top + @boundingClientRect.top + itemHeight > @windowHeight top -= itemHeight + @lineHeight - pixelPosition.top = top - pixelPosition.left = left + pixelPosition.top = top + pixelPosition.left = left @state.content.overlays[decoration.id] ?= {item} @state.content.overlays[decoration.id].pixelPosition = pixelPosition @@ -824,6 +824,9 @@ class TextEditorPresenter hasPixelRectRequirements: -> @hasPixelPositionRequirements() and @scrollWidth? + hasOverlayPositionRequirements: -> + @hasPixelRectRequirements() and @boundingClientRect? and @windowWidth and @windowHeight + pixelRectForScreenRange: (screenRange) -> if screenRange.end.row > screenRange.start.row top = @pixelPositionForScreenPosition(screenRange.start).top