From 535a9da94657f92498f8bc7f3f27c07c779555d6 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 24 Sep 2015 10:13:00 +0200 Subject: [PATCH] wip --- src/display-buffer.coffee | 33 -------- src/text-editor-component.coffee | 20 ++++- src/text-editor-element.coffee | 28 ++++++- src/text-editor-presenter.coffee | 49 ++++++++++- src/text-editor.coffee | 134 ++++++++++++++++++++----------- 5 files changed, 180 insertions(+), 84 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 7b544a16e..a039ecc4a 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -125,23 +125,9 @@ class DisplayBuffer extends Model onDidChangeCharacterWidths: (callback) -> @emitter.on 'did-change-character-widths', callback - onDidChangeScrollTop: (callback) -> - @emitter.on 'did-change-scroll-top', callback - - onDidChangeScrollLeft: (callback) -> - @emitter.on 'did-change-scroll-left', callback - onDidChangeScrollPosition: (callback) -> @emitter.on 'did-change-scroll-position', callback - observeScrollTop: (callback) -> - callback(@scrollTop) - @onDidChangeScrollTop(callback) - - observeScrollLeft: (callback) -> - callback(@scrollLeft) - @onDidChangeScrollLeft(callback) - observeDecorations: (callback) -> callback(decoration) for decoration in @getDecorations() @onDidAddDecoration(callback) @@ -1147,25 +1133,6 @@ class DisplayBuffer extends Model # this one. Only emit when the marker still exists. @emitter.emit 'did-create-marker', marker - # TODO: serialize state in TextEditorElement, rather than saving scroll - # positions here. - - getScrollTop: -> @scrollTop - - setScrollTop: (scrollTop) -> - unless scrollTop is @scrollTop - @scrollTop = scrollTop - @emitter.emit 'did-change-scroll-top', @scrollTop - @scrollTop - - getScrollLeft: -> @scrollLeft - - setScrollLeft: (scrollLeft) -> - unless scrollLeft is @scrollLeft - @scrollLeft = scrollLeft - @emitter.emit 'did-change-scroll-left', @scrollLeft - @scrollLeft - decorateFold: (fold) -> @decorateMarker(fold.marker, type: 'line-number', class: 'folded') diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index a64d46668..505be6a07 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -403,6 +403,24 @@ class TextEditorComponent getHorizontalScrollbarHeight: -> @presenter.getHorizontalScrollbarHeight() + getVisibleRowRange: -> + @presenter.getVisibleRowRange() + + pixelPositionForBufferPosition: (bufferPosition) -> + @presenter.pixelPositionForBufferPosition(bufferPosition) + + pixelPositionForScreenPosition: (screenPosition) -> + @presenter.pixelPositionForScreenPosition(screenPosition) + + screenPositionForPixelPosition: (pixelPosition) -> + @presenter.screenPositionForPixelPosition(pixelPosition) + + pixelRectForScreenRange: (screenRange) -> + @presenter.pixelRectForScreenRange(screenRange) + + pixelRangeForScreenRange: (screenRange, clip) -> + @presenter.pixelRangeForScreenRange(screenRange, clip) + onMouseDown: (event) => unless event.button is 0 or (event.button is 1 and process.platform is 'linux') # Only handle mouse down events for left mouse button on all platforms @@ -810,7 +828,7 @@ class TextEditorComponent screenPositionForMouseEvent: (event, linesClientRect) -> pixelPosition = @pixelPositionForMouseEvent(event, linesClientRect) - @editor.screenPositionForPixelPosition(pixelPosition) + @presenter.screenPositionForPixelPosition(pixelPosition) pixelPositionForMouseEvent: (event, linesClientRect) -> {clientX, clientY} = event diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index fe66b6f44..5b4322203 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -181,7 +181,7 @@ class TextEditorElement extends HTMLElement # # Returns an {Object} with two values: `top` and `left`, representing the pixel position. pixelPositionForBufferPosition: (bufferPosition) -> - @getModel().pixelPositionForBufferPosition(bufferPosition, true) + @component.pixelPositionForBufferPosition(bufferPosition, true) # Extended: Converts a screen position to a pixel position. # @@ -190,21 +190,21 @@ class TextEditorElement extends HTMLElement # # Returns an {Object} with two values: `top` and `left`, representing the pixel positions. pixelPositionForScreenPosition: (screenPosition) -> - @getModel().pixelPositionForScreenPosition(screenPosition, true) + @component.pixelPositionForScreenPosition(screenPosition, true) # Extended: Retrieves the number of the row that is visible and currently at the # top of the editor. # # Returns a {Number}. getFirstVisibleScreenRow: -> - @getModel().getFirstVisibleScreenRow(true) + @getVisibleRowRange()[0] # Extended: Retrieves the number of the row that is visible and currently at the # bottom of the editor. # # Returns a {Number}. getLastVisibleScreenRow: -> - @getModel().getLastVisibleScreenRow(true) + @getVisibleRowRange()[1] # Extended: call the given `callback` when the editor is attached to the DOM. # @@ -266,6 +266,26 @@ class TextEditorElement extends HTMLElement getHorizontalScrollbarHeight: -> @component.getHorizontalScrollbarHeight() + getVisibleRowRange: -> + @component.getVisibleRowRange() + + intersectsVisibleRowRange: (startRow, endRow) -> + [visibleStart, visibleEnd] = @getVisibleRowRange() + not (endRow <= visibleStart or visibleEnd <= startRow) + + selectionIntersectsVisibleRowRange: (selection) -> + {start, end} = selection.getScreenRange() + @intersectsVisibleRowRange(start.row, end.row + 1) + + screenPositionForPixelPosition: (pixelPosition) -> + @component.screenPositionForPixelPosition(pixelPosition) + + pixelRectForScreenRange: (screenRange) -> + @component.pixelRectForScreenRange(screenRange) + + pixelRangeForScreenRange: (screenRange, clip) -> + @component.pixelRangeForScreenRange(screenRange, clip) + stopEventPropagation = (commandListeners) -> newCommandListeners = {} for commandName, commandListener of commandListeners diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index e01a8a20d..15d19d1a6 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1561,7 +1561,7 @@ class TextEditorPresenter @scrollColumn = Math.round(@scrollLeft / @baseCharacterWidth) @model.setScrollColumn(@scrollColumn) - @emitter.emit 'did-change-scroll-top', @scrollLeft + @emitter.emit 'did-change-scroll-left', @scrollLeft @pendingScrollLeft = null @@ -1599,3 +1599,50 @@ class TextEditorPresenter onDidChangeScrollLeft: (callback) -> @emitter.on 'did-change-scroll-left', callback + + getVisibleRowRange: -> + [@startRow, @endRow] + + pixelPositionForBufferPosition: (bufferPosition) -> + @pixelPositionForScreenPosition( + @model.screenPositionForBufferPosition(bufferPosition) + ) + + screenPositionForPixelPosition: (pixelPosition) -> + targetTop = pixelPosition.top + targetLeft = pixelPosition.left + defaultCharWidth = @baseCharacterWidth + row = Math.floor(targetTop / @lineHeight) + targetLeft = 0 if row < 0 + targetLeft = Infinity if row > @model.getLastScreenRow() + row = Math.min(row, @model.getLastScreenRow()) + row = Math.max(0, row) + + left = 0 + column = 0 + + iterator = @model.tokenizedLineForScreenRow(row).getTokenIterator() + while iterator.next() + charWidths = @getScopedCharacterWidths(iterator.getScopes()) + value = iterator.getText() + valueIndex = 0 + while valueIndex < value.length + if iterator.isPairedCharacter() + char = value + charLength = 2 + valueIndex += 2 + else + char = value[valueIndex] + charLength = 1 + valueIndex++ + + charWidth = charWidths[char] ? defaultCharWidth + break if targetLeft <= left + (charWidth / 2) + left += charWidth + column += charLength + + new Point(row, column) + + pixelRangeForScreenRange: (screenRange, clip=true) -> + {start, end} = Range.fromObject(screenRange) + {start: @pixelPositionForScreenPosition(start, clip), end: @pixelPositionForScreenPosition(end, clip)} diff --git a/src/text-editor.coffee b/src/text-editor.coffee index e15ee13dd..76d09d381 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -109,12 +109,6 @@ class TextEditor extends Model @setEncoding(atom.config.get('core.fileEncoding', scope: @getRootScopeDescriptor())) - @disposables.add @displayBuffer.onDidChangeScrollTop (scrollTop) => - @emitter.emit 'did-change-scroll-top', scrollTop - - @disposables.add @displayBuffer.onDidChangeScrollLeft (scrollLeft) => - @emitter.emit 'did-change-scroll-left', scrollLeft - @gutterContainer = new GutterContainer(this) @lineNumberGutter = @gutterContainer.addGutter name: 'line-number' @@ -2865,23 +2859,27 @@ class TextEditor extends Model # Essential: Scrolls the editor to the top scrollToTop: -> - @setScrollTop(0) + Grim.deprecate("This is now a view method. Call TextEditorElement::scrollToTop instead.") + + atom.views.getView(this).scrollToTop() # Essential: Scrolls the editor to the bottom scrollToBottom: -> - @setScrollBottom(Infinity) + Grim.deprecate("This is now a view method. Call TextEditorElement::scrollToTop instead.") + + atom.views.getView(this).scrollToBottom() scrollToScreenRange: (screenRange, options) -> @displayBuffer.scrollToScreenRange(screenRange, options) - horizontallyScrollable: -> @displayBuffer.horizontallyScrollable() + getHorizontalScrollbarHeight: -> + Grim.deprecate("This is now a view method. Call TextEditorElement::getHorizontalScrollbarHeight instead.") - verticallyScrollable: -> @displayBuffer.verticallyScrollable() + atom.views.getView(this).getHorizontalScrollbarHeight() - getHorizontalScrollbarHeight: -> @displayBuffer.getHorizontalScrollbarHeight() - setHorizontalScrollbarHeight: (height) -> @displayBuffer.setHorizontalScrollbarHeight(height) + getVerticalScrollbarWidth: -> + Grim.deprecate("This is now a view method. Call TextEditorElement::getVerticalScrollbarWidth instead.") - getVerticalScrollbarWidth: -> @displayBuffer.getVerticalScrollbarWidth() - setVerticalScrollbarWidth: (width) -> @displayBuffer.setVerticalScrollbarWidth(width) + atom.views.getView(this).getVerticalScrollbarWidth() pageUp: -> @moveUp(@getRowsPerPage()) @@ -2944,25 +2942,21 @@ class TextEditor extends Model @placeholderText = placeholderText @emitter.emit 'did-change-placeholder-text', @placeholderText - getFirstVisibleScreenRow: (suppressDeprecation) -> - unless suppressDeprecation - deprecate("This is now a view method. Call TextEditorElement::getFirstVisibleScreenRow instead.") - @getVisibleRowRange()[0] + getFirstVisibleScreenRow: -> + deprecate("This is now a view method. Call TextEditorElement::getFirstVisibleScreenRow instead.") + atom.views.getView(this).getVisibleRowRange()[0] - getLastVisibleScreenRow: (suppressDeprecation) -> - unless suppressDeprecation - Grim.deprecate("This is now a view method. Call TextEditorElement::getLastVisibleScreenRow instead.") - @getVisibleRowRange()[1] + getLastVisibleScreenRow: -> + Grim.deprecate("This is now a view method. Call TextEditorElement::getLastVisibleScreenRow instead.") + atom.views.getView(this).getVisibleRowRange()[1] - pixelPositionForBufferPosition: (bufferPosition, suppressDeprecation) -> - unless suppressDeprecation - Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForBufferPosition` instead") - @displayBuffer.pixelPositionForBufferPosition(bufferPosition) + pixelPositionForBufferPosition: (bufferPosition) -> + Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForBufferPosition` instead") + atom.views.getView(this).pixelPositionForBufferPosition(bufferPosition) - pixelPositionForScreenPosition: (screenPosition, suppressDeprecation) -> - unless suppressDeprecation - Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForScreenPosition` instead") - @displayBuffer.pixelPositionForScreenPosition(screenPosition) + pixelPositionForScreenPosition: (screenPosition) -> + Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForScreenPosition` instead") + atom.views.getView(this).pixelPositionForScreenPosition(screenPosition) getSelectionMarkerAttributes: -> {type: 'selection', editorId: @id, invalidate: 'never', maintainHistory: true} @@ -3002,30 +2996,80 @@ class TextEditor extends Model getScrollColumn: -> @scrollColumn setScrollColumn: (@scrollColumn) -> - getScrollTop: -> @displayBuffer.getScrollTop() - setScrollTop: (scrollTop) -> @displayBuffer.setScrollTop(scrollTop) + getScrollTop: -> + Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollTop instead.") - getScrollBottom: -> @displayBuffer.getScrollBottom() - setScrollBottom: (scrollBottom) -> @displayBuffer.setScrollBottom(scrollBottom) + atom.views.getView(this).getScrollTop() - getScrollLeft: -> @displayBuffer.getScrollLeft() - setScrollLeft: (scrollLeft) -> @displayBuffer.setScrollLeft(scrollLeft) + setScrollTop: (scrollTop) -> + Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollTop instead.") - getScrollRight: -> @displayBuffer.getScrollRight() - setScrollRight: (scrollRight) -> @displayBuffer.setScrollRight(scrollRight) + atom.views.getView(this).setScrollTop(scrollTop) - getScrollHeight: -> @displayBuffer.getScrollHeight() - getScrollWidth: -> @displayBuffer.getScrollWidth() + getScrollBottom: -> + Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollBottom instead.") - getVisibleRowRange: -> @displayBuffer.getVisibleRowRange() + atom.views.getView(this).getScrollBottom() - intersectsVisibleRowRange: (startRow, endRow) -> @displayBuffer.intersectsVisibleRowRange(startRow, endRow) + setScrollBottom: (scrollBottom) -> + Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollBottom instead.") - selectionIntersectsVisibleRowRange: (selection) -> @displayBuffer.selectionIntersectsVisibleRowRange(selection) + atom.views.getView(this).setScrollBottom(scrollBottom) - screenPositionForPixelPosition: (pixelPosition) -> @displayBuffer.screenPositionForPixelPosition(pixelPosition) + getScrollLeft: -> + Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollLeft instead.") - pixelRectForScreenRange: (screenRange) -> @displayBuffer.pixelRectForScreenRange(screenRange) + atom.views.getView(this).getScrollLeft() + + setScrollLeft: (scrollLeft) -> + Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollLeft instead.") + + atom.views.getView(this).setScrollLeft(scrollLeft) + + getScrollRight: -> + Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollRight instead.") + + atom.views.getView(this).getScrollRight() + + setScrollRight: (scrollRight) -> + Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollRight instead.") + + atom.views.getView(this).setScrollRight(scrollRight) + + getScrollHeight: -> + Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollHeight instead.") + + atom.views.getView(this).getScrollHeight() + + getScrollWidth: -> + Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollWidth instead.") + + atom.views.getView(this).getScrollWidth() + + getVisibleRowRange: -> + Grim.deprecate("This is now a view method. Call TextEditorElement::getVisibleRowRange instead.") + + atom.views.getView(this).getVisibleRowRange() + + intersectsVisibleRowRange: (startRow, endRow) -> + Grim.deprecate("This is now a view method. Call TextEditorElement::intersectsVisibleRowRange instead.") + + atom.views.getView(this).intersectsVisibleRowRange(startRow, endRow) + + selectionIntersectsVisibleRowRange: (selection) -> + Grim.deprecate("This is now a view method. Call TextEditorElement::selectionIntersectsVisibleRowRange instead.") + + atom.views.getView(this).selectionIntersectsVisibleRowRange(selection) + + screenPositionForPixelPosition: (pixelPosition) -> + Grim.deprecate("This is now a view method. Call TextEditorElement::screenPositionForPixelPosition instead.") + + atom.views.getView(this).screenPositionForPixelPosition(pixelPosition) + + pixelRectForScreenRange: (screenRange) -> + Grim.deprecate("This is now a view method. Call TextEditorElement::pixelRectForScreenRange instead.") + + atom.views.getView(this).pixelRectForScreenRange(screenRange) ### Section: Utility