From b5a59017d51b7500cd1acac0ba708f621cee2250 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 22 Sep 2015 16:20:15 +0200 Subject: [PATCH] wip --- spec/text-editor-presenter-spec.coffee | 8 ++- src/display-buffer.coffee | 38 +++++++++++ src/text-editor-presenter.coffee | 91 +++++++++++++++++++++++--- src/text-editor.coffee | 3 + 4 files changed, 129 insertions(+), 11 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 76589416e..ca4ab4ba4 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -5,7 +5,7 @@ TextBuffer = require 'text-buffer' TextEditor = require '../src/text-editor' TextEditorPresenter = require '../src/text-editor-presenter' -describe "TextEditorPresenter", -> +fdescribe "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 "::getState()", -> @@ -483,7 +483,7 @@ describe "TextEditorPresenter", -> describe ".hiddenInput", -> describe ".top/.left", -> - it "is positioned over the last cursor it is in view and the editor is focused", -> + fffit "is positioned over the last cursor it is in view and the editor is focused", -> editor.setCursorBufferPosition([3, 6]) presenter = buildPresenter(focused: false, explicitHeight: 50, contentFrameWidth: 300, horizontalScrollbarHeight: 0, verticalScrollbarWidth: 0) expectValues presenter.getState().hiddenInput, {top: 0, left: 0} @@ -503,8 +503,10 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> presenter.setScrollLeft(70) expectValues presenter.getState().hiddenInput, {top: 0, left: 0} + global.enableLogs = true expectStateUpdate presenter, -> editor.setCursorBufferPosition([11, 43]) expectValues presenter.getState().hiddenInput, {top: 11 * 10 - editor.getScrollTop(), left: 43 * 10 - editor.getScrollLeft()} + global.enableLogs = false newCursor = null expectStateUpdate presenter, -> newCursor = editor.addCursorAtBufferPosition([6, 10]) @@ -1821,7 +1823,7 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> editor.insertNewline() - editor.setScrollTop(scrollTop) # I'm fighting the editor + presenter.setScrollTop(scrollTop) # I'm fighting the editor expectValues stateForOverlay(presenter, decoration), { item: item pixelPosition: {top: 6 * 10 - scrollTop - itemHeight, left: gutterWidth} diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 5d5628689..94831eac1 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -132,6 +132,9 @@ class DisplayBuffer extends Model onDidChangeScrollLeft: (callback) -> @emitter.on 'did-change-scroll-left', callback + onDidChangeScrollPosition: (callback) -> + @emitter.on 'did-change-scroll-position', callback + observeScrollTop: (callback) -> callback(@scrollTop) @onDidChangeScrollTop(callback) @@ -348,6 +351,10 @@ class DisplayBuffer extends Model [startRow, endRow] + getLogicalHeight: -> + [startRow, endRow] = @getVisibleRowRange() + endRow - startRow + intersectsVisibleRowRange: (startRow, endRow) -> [visibleStart, visibleEnd] = @getVisibleRowRange() not (endRow <= visibleStart or visibleEnd <= startRow) @@ -356,7 +363,31 @@ class DisplayBuffer extends Model {start, end} = selection.getScreenRange() @intersectsVisibleRowRange(start.row, end.row + 1) + scrollToScreenRangeLogical: (screenRange, options) -> + top = screenRange.start.row + left = screenRange.start.column + bottom = screenRange.end.row + right = screenRange.end.column + + if options?.center + center = (top + bottom) / 2 + top = center - @getLogicalHeight() / 2 + bottom = center + @getLogicalHeight() / 2 + else + top -= @getVerticalScrollMargin() + bottom += @getVerticalScrollMargin() + + left -= @getHorizontalScrollMargin() + right += @getHorizontalScrollMargin() + + screenRange = new Range(new Point(top, left), new Point(bottom, right)) + + scrollEvent = {screenRange, options} + @emitter.emit "did-change-scroll-position", scrollEvent + scrollToScreenRange: (screenRange, options) -> + @scrollToScreenRangeLogical(screenRange, options) + verticalScrollMarginInPixels = @getVerticalScrollMarginInPixels() horizontalScrollMarginInPixels = @getHorizontalScrollMarginInPixels() @@ -377,6 +408,13 @@ class DisplayBuffer extends Model desiredScrollLeft = left - horizontalScrollMarginInPixels desiredScrollRight = right + horizontalScrollMarginInPixels + if global.enableLogs + console.log "====== DB ======" + console.log "Client Height: #{@getClientHeight()}" + console.log "#{desiredScrollTop}/#{desiredScrollBottom}" + console.log "#{@getScrollTop()}/#{@getScrollBottom()}" + console.log "================" + if options?.reversed ? true if desiredScrollBottom > @getScrollBottom() @setScrollBottom(desiredScrollBottom) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index e6a9043c5..91450ca57 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -71,6 +71,7 @@ class TextEditorPresenter @updateContentDimensions() @updateScrollbarDimensions() + @updateScrollPosition() @updateStartRow() @updateEndRow() @updateCommonGutterState() @@ -115,8 +116,6 @@ class TextEditorPresenter observeModel: -> @disposables.add @model.onDidChange => - @updateContentDimensions() - @shouldUpdateHeightState = true @shouldUpdateVerticalScrollState = true @shouldUpdateHorizontalScrollState = true @@ -162,8 +161,9 @@ 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.onDidChangeScrollPosition(@didChangeScrollPosition.bind(this)) + # @disposables.add @model.onDidChangeScrollTop(@setScrollTop.bind(this)) + # @disposables.add @model.onDidChangeScrollLeft(@setScrollLeft.bind(this)) @observeDecoration(decoration) for decoration in @model.getDecorations() @observeCursor(cursor) for cursor in @model.getCursors() @disposables.add @model.onDidAddGutter(@didAddGutter.bind(this)) @@ -813,7 +813,7 @@ class TextEditorPresenter unless @scrollTop is scrollTop or Number.isNaN(scrollTop) @scrollTop = scrollTop - @model.setScrollTop(scrollTop) + @model.setScrollTop(@scrollTop) @didStartScrolling() @shouldUpdateVerticalScrollState = true @shouldUpdateHiddenInputState = true @@ -852,7 +852,7 @@ class TextEditorPresenter unless @scrollLeft is scrollLeft or Number.isNaN(scrollLeft) oldScrollLeft = @scrollLeft @scrollLeft = scrollLeft - @model.setScrollLeft(scrollLeft) + @model.setScrollLeft(@scrollLeft) @shouldUpdateHorizontalScrollState = true @shouldUpdateHiddenInputState = true @shouldUpdateCursorsState = true @@ -865,11 +865,29 @@ class TextEditorPresenter getScrollLeft: -> @scrollLeft + getClientHeight: -> + if @clientHeight + @clientHeight + else + @explicitHeight - @horizontalScrollbarHeight + + getClientWidth: -> + @clientWidth ? @contentFrameWidth + + getScrollBottom: -> @getScrollTop() + @getClientHeight() + setScrollBottom: (scrollBottom) -> + @setScrollTop(scrollBottom - @getClientHeight()) + @getScrollBottom() + + getScrollRight: -> @getScrollLeft() + @getClientWidth() + setScrollRight: (scrollRight) -> + @setScrollLeft(scrollRight - @getClientWidth()) + @getScrollRight() + setHorizontalScrollbarHeight: (horizontalScrollbarHeight) -> unless @measuredHorizontalScrollbarHeight is horizontalScrollbarHeight oldHorizontalScrollbarHeight = @measuredHorizontalScrollbarHeight @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight - @model.setHorizontalScrollbarHeight(horizontalScrollbarHeight) @shouldUpdateScrollbarsState = true @shouldUpdateVerticalScrollState = true @shouldUpdateHorizontalScrollState = true @@ -881,7 +899,6 @@ class TextEditorPresenter unless @measuredVerticalScrollbarWidth is verticalScrollbarWidth oldVerticalScrollbarWidth = @measuredVerticalScrollbarWidth @measuredVerticalScrollbarWidth = verticalScrollbarWidth - @model.setVerticalScrollbarWidth(verticalScrollbarWidth) @shouldUpdateScrollbarsState = true @shouldUpdateVerticalScrollState = true @shouldUpdateHorizontalScrollState = true @@ -1438,3 +1455,61 @@ class TextEditorPresenter @startBlinkingCursorsAfterDelay ?= _.debounce(@startBlinkingCursors, @getCursorBlinkResumeDelay()) @startBlinkingCursorsAfterDelay() @emitDidUpdateState() + + didChangeScrollPosition: (position) -> + @pendingScrollLogicalPosition = position + + @shouldUpdateCursorsState = true + @shouldUpdateCustomGutterDecorationState = true + @shouldUpdateDecorations = true + @shouldUpdateHiddenInputState = true + @shouldUpdateHorizontalScrollState = true + @shouldUpdateLinesState = true + @shouldUpdateLineNumbersState = true + @shouldUpdateOverlaysState = true + @shouldUpdateScrollPosition = true + @shouldUpdateVerticalScrollState = true + + @emitDidUpdateState() + + updateScrollPosition: -> + return unless @pendingScrollLogicalPosition? + + {screenRange, options} = @pendingScrollLogicalPosition + + console.log screenRange.start.toString() + console.log screenRange.end.toString() + {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 global.enableLogs + console.log "====== presenter ======" + console.log "Client Height: #{@getClientHeight()}" + console.log "#{desiredScrollTop}/#{desiredScrollBottom}" + console.log "#{@getScrollTop()}/#{@getScrollBottom()}" + console.log "=======================" + + 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 diff --git a/src/text-editor.coffee b/src/text-editor.coffee index edd35ae93..9f3e230fb 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -464,6 +464,9 @@ class TextEditor extends Model onDidChangeScrollLeft: (callback) -> @emitter.on 'did-change-scroll-left', callback + onDidChangeScrollPosition: (callback) -> + @displayBuffer.onDidChangeScrollPosition(callback) + # TODO Remove once the tabs package no longer uses .on subscriptions onDidChangeIcon: (callback) -> @emitter.on 'did-change-icon', callback