mirror of
https://github.com/atom/atom.git
synced 2026-04-06 03:02:13 -04:00
Merge pull request #4144 from atom/bo-overlay-decoration
Overlay decorations
This commit is contained in:
@@ -17,7 +17,7 @@ class Cursor extends Model
|
||||
visible: true
|
||||
needsAutoscroll: null
|
||||
|
||||
# Instantiated by an {TextEditor}
|
||||
# Instantiated by a {TextEditor}
|
||||
constructor: ({@editor, @marker, id}) ->
|
||||
@emitter = new Emitter
|
||||
|
||||
@@ -171,6 +171,10 @@ class Cursor extends Model
|
||||
Section: Cursor Position Details
|
||||
###
|
||||
|
||||
# Public: Returns the underlying {Marker} for the cursor.
|
||||
# Useful with overlay {Decoration}s.
|
||||
getMarker: -> @marker
|
||||
|
||||
# Public: Identifies if the cursor is surrounded by whitespace.
|
||||
#
|
||||
# "Surrounded" here means that the character directly before and after the
|
||||
|
||||
@@ -7,6 +7,7 @@ React = require 'react-atom-fork'
|
||||
Decoration = require './decoration'
|
||||
CursorsComponent = require './cursors-component'
|
||||
HighlightsComponent = require './highlights-component'
|
||||
OverlayManager = require './overlay-manager'
|
||||
|
||||
DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0]
|
||||
AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT}
|
||||
@@ -20,7 +21,7 @@ LinesComponent = React.createClass
|
||||
{performedInitialMeasurement, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
|
||||
|
||||
if performedInitialMeasurement
|
||||
{editor, highlightDecorations, scrollHeight, scrollWidth, placeholderText, backgroundColor} = @props
|
||||
{editor, overlayDecorations, highlightDecorations, scrollHeight, scrollWidth, placeholderText, backgroundColor} = @props
|
||||
{lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount} = @props
|
||||
{scrollTop, scrollLeft, cursorPixelRects, mini} = @props
|
||||
style =
|
||||
@@ -63,10 +64,17 @@ LinesComponent = React.createClass
|
||||
insertionPoint.setAttribute('select', '.overlayer')
|
||||
@getDOMNode().appendChild(insertionPoint)
|
||||
|
||||
insertionPoint = document.createElement('content')
|
||||
insertionPoint.setAttribute('select', 'atom-overlay')
|
||||
@overlayManager = new OverlayManager(@props.hostElement)
|
||||
@getDOMNode().appendChild(insertionPoint)
|
||||
else
|
||||
@overlayManager = new OverlayManager(@getDOMNode())
|
||||
|
||||
shouldComponentUpdate: (newProps) ->
|
||||
return true unless isEqualForProperties(newProps, @props,
|
||||
'renderedRowRange', 'lineDecorations', 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth',
|
||||
'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'visible',
|
||||
'overlayDecorations', 'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'visible',
|
||||
'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'useHardwareAcceleration',
|
||||
'placeholderText', 'performedInitialMeasurement', 'backgroundColor', 'cursorPixelRects'
|
||||
)
|
||||
@@ -92,6 +100,8 @@ LinesComponent = React.createClass
|
||||
@updateLines(@props.lineWidth isnt prevProps.lineWidth)
|
||||
@measureCharactersInNewLines() if visible and not scrollingVertically
|
||||
|
||||
@overlayManager?.render(@props)
|
||||
|
||||
clearScreenRowCaches: ->
|
||||
@screenRowsByLineId = {}
|
||||
@lineIdsByScreenRow = {}
|
||||
|
||||
43
src/overlay-manager.coffee
Normal file
43
src/overlay-manager.coffee
Normal file
@@ -0,0 +1,43 @@
|
||||
module.exports =
|
||||
class OverlayManager
|
||||
constructor: (@container) ->
|
||||
@overlays = {}
|
||||
|
||||
render: (props) ->
|
||||
{editor, overlayDecorations, lineHeightInPixels} = props
|
||||
|
||||
existingDecorations = null
|
||||
for markerId, {isMarkerReversed, headPixelPosition, decorations} of overlayDecorations
|
||||
for decoration in decorations
|
||||
@renderOverlay(editor, decoration, headPixelPosition, lineHeightInPixels)
|
||||
|
||||
existingDecorations ?= {}
|
||||
existingDecorations[decoration.id] = true
|
||||
|
||||
for id, overlay of @overlays
|
||||
unless existingDecorations? and id of existingDecorations
|
||||
@container.removeChild(overlay)
|
||||
delete @overlays[id]
|
||||
|
||||
return
|
||||
|
||||
renderOverlay: (editor, decoration, pixelPosition, lineHeightInPixels) ->
|
||||
item = atom.views.getView(decoration.item)
|
||||
unless overlay = @overlays[decoration.id]
|
||||
overlay = @overlays[decoration.id] = document.createElement('atom-overlay')
|
||||
overlay.appendChild(item)
|
||||
@container.appendChild(overlay)
|
||||
|
||||
itemWidth = item.offsetWidth
|
||||
itemHeight = item.offsetHeight
|
||||
|
||||
left = pixelPosition.left
|
||||
if left + itemWidth - editor.getScrollLeft() > editor.getWidth() and left - itemWidth >= editor.getScrollLeft()
|
||||
left -= itemWidth
|
||||
|
||||
top = pixelPosition.top + lineHeightInPixels
|
||||
if top + itemHeight - editor.getScrollTop() > editor.getHeight() and top - itemHeight - lineHeightInPixels >= editor.getScrollTop()
|
||||
top -= itemHeight + lineHeightInPixels
|
||||
|
||||
overlay.style.top = top + 'px'
|
||||
overlay.style.left = left + 'px'
|
||||
@@ -50,7 +50,7 @@ TextEditorComponent = React.createClass
|
||||
|
||||
render: ->
|
||||
{focused, showIndentGuide, showLineNumbers, visible} = @state
|
||||
{editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
|
||||
{editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay, hostElement} = @props
|
||||
maxLineNumberDigits = editor.getLineCount().toString().length
|
||||
hasSelection = editor.getLastSelection()? and !editor.getLastSelection().isEmpty()
|
||||
style = {}
|
||||
@@ -66,6 +66,7 @@ TextEditorComponent = React.createClass
|
||||
|
||||
decorations = editor.decorationsForScreenRowRange(renderedStartRow, renderedEndRow)
|
||||
highlightDecorations = @getHighlightDecorations(decorations)
|
||||
overlayDecorations = @getOverlayDecorations(decorations)
|
||||
lineDecorations = @getLineDecorations(decorations)
|
||||
placeholderText = editor.getPlaceholderText() if editor.isEmpty()
|
||||
visible = @isVisible()
|
||||
@@ -110,7 +111,8 @@ TextEditorComponent = React.createClass
|
||||
|
||||
LinesComponent {
|
||||
ref: 'lines',
|
||||
editor, lineHeightInPixels, defaultCharWidth, tokenizedLines, lineDecorations, highlightDecorations,
|
||||
editor, lineHeightInPixels, defaultCharWidth, tokenizedLines,
|
||||
lineDecorations, highlightDecorations, overlayDecorations, hostElement,
|
||||
showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft,
|
||||
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow,
|
||||
visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration,
|
||||
@@ -351,7 +353,23 @@ TextEditorComponent = React.createClass
|
||||
endPixelPosition: editor.pixelPositionForScreenPosition(screenRange.end)
|
||||
decorations: []
|
||||
filteredDecorations[markerId].decorations.push decorationParams
|
||||
filteredDecorations
|
||||
|
||||
getOverlayDecorations: (decorationsByMarkerId) ->
|
||||
{editor} = @props
|
||||
filteredDecorations = {}
|
||||
for markerId, decorations of decorationsByMarkerId
|
||||
marker = editor.getMarker(markerId)
|
||||
headBufferPosition = marker.getHeadBufferPosition()
|
||||
if marker.isValid()
|
||||
for decoration in decorations
|
||||
if decoration.isType('overlay')
|
||||
decorationParams = decoration.getProperties()
|
||||
filteredDecorations[markerId] ?=
|
||||
id: markerId
|
||||
headPixelPosition: editor.pixelPositionForScreenPosition(headBufferPosition)
|
||||
decorations: []
|
||||
filteredDecorations[markerId].decorations.push decorationParams
|
||||
filteredDecorations
|
||||
|
||||
observeEditor: ->
|
||||
|
||||
@@ -77,7 +77,6 @@ class TextEditorView extends View
|
||||
|
||||
@scrollView = @root.find('.scroll-view')
|
||||
|
||||
|
||||
if atom.config.get('editor.useShadowDOM')
|
||||
@underlayer = $("<div class='underlayer'></div>").appendTo(this)
|
||||
@overlayer = $("<div class='overlayer'></div>").appendTo(this)
|
||||
|
||||
Reference in New Issue
Block a user