Skip to content

Commit

Permalink
Add stand-alone mode in minimap
Browse files Browse the repository at this point in the history
In stand-alone mode the minimap can operate using a fixed width and
height.
  • Loading branch information
abe33 committed Aug 15, 2015
1 parent 5f37e22 commit 5560408
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 7 deletions.
53 changes: 46 additions & 7 deletions lib/minimap.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Minimap
# options - An {Object} with the following properties:
# :textEditor - A `TextEditor` instance.
constructor: (options={}) ->
{@textEditor} = options
{@textEditor, @standAlone, @width, @height} = options
unless @textEditor?
throw new Error('Cannot create a minimap without an editor')

Expand Down Expand Up @@ -135,6 +135,14 @@ class Minimap
onDidDestroy: (callback) ->
@emitter.on 'did-destroy', callback

# Returns `true` when the minimap is in stand-alone mode.
#
# The stand-alone mode means that the minimap size won't be tied
# to the `TextEditor` but based on the specified options instead.
#
# Returns a {Boolean}.
isStandAlone: -> @standAlone

# Returns the `TextEditor` that this minimap represents.
#
# Returns a `TextEditor`.
Expand All @@ -143,7 +151,8 @@ class Minimap
# Returns the height of the `TextEditor` at the {Minimap} scale.
#
# Returns a {Number}.
getTextEditorScaledHeight: -> @textEditor.getHeight() * @getVerticalScaleFactor()
getTextEditorScaledHeight: ->
@textEditor.getHeight() * @getVerticalScaleFactor()

# Returns the `TextEditor::getScrollTop` value at the {Minimap} scale.
#
Expand Down Expand Up @@ -196,14 +205,43 @@ class Minimap
# Returns a {Number}.
getHeight: -> @textEditor.getScreenLineCount() * @getLineHeight()

# Returns the height the {Minimap} will take on screen.
# Returns the width of the whole minimap in pixels based on the `minimap`
# settings.
#
# Returns a {Number}.
getWidth: -> @textEditor.getMaxScreenLineLength() * @getCharWidth()

# Returns the height the {Minimap} content will take on screen.
#
# When the {Minimap} height is greater than the `TextEditor` height, the
# `TextEditor` height is returned instead.
#
# Returns a {Number}.
getVisibleHeight: ->
Math.min(@textEditor.getHeight(), @getHeight())
getVisibleHeight: -> Math.min(@getScreenHeight(), @getHeight())

# Returns the height the minimap should take once displayed, it's either the
# height of the `TextEditor` or the provided `height` when in standAlone mode.
#
# Returns a {Number}.
getScreenHeight: ->
if @isStandAlone()
if @height? then @height else @getHeight()
else
@textEditor.getHeight()

# Returns the width the whole {Minimap} will take on screen.
#
# Returns a {Number}.
getVisibleWidth: ->
Math.min(@getScreenWidth(), @getWidth())

# Returns the width the minimap should take once displayed, it's either the
# width of the minimap content or the provided `width` when in standAlone
# mode.
#
# Returns a {Number}.
getScreenWidth: ->
if @isStandAlone() and @width? then @width else @getWidth()

# Returns the vertical scaling factor when converting coordinates from the
# `TextEditor` to the {Minimap}.
Expand Down Expand Up @@ -249,7 +287,7 @@ class Minimap
#
# Returns a {Number}.
getLastVisibleScreenRow: ->
Math.ceil((@getScrollTop() + @textEditor.getHeight()) / @getLineHeight())
Math.ceil((@getScrollTop() + @getScreenHeight()) / @getLineHeight())

# Returns the current scroll of the {Minimap}.
#
Expand All @@ -263,7 +301,8 @@ class Minimap
# Returns the maximum scroll value of the {Minimap}.
#
# Returns a {Number}.
getMaxScrollTop: -> Math.max(0, @getHeight() - @textEditor.getHeight())
getMaxScrollTop: ->
Math.max(0, @getHeight() - @getScreenHeight())

# Returns `true` when the {Minimap} can scroll.
#
Expand Down
104 changes: 104 additions & 0 deletions spec/minimap-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,107 @@ describe 'Minimap', ->
expect(decorations['line']['3'].length).toEqual(1)

expect(decorations['highlight-under']['5'].length).toEqual(1)

## ###### ######## ### ## ## ########
## ## ## ## ## ## ### ## ## ##
## ## ## ## ## #### ## ## ##
## ###### ## ## ## ## ## ## ## ##
## ## ## ######### ## #### ## ##
## ## ## ## ## ## ## ### ## ##
## ###### ## ## ## ## ## ########
##
## ### ## ####### ## ## ########
## ## ## ## ## ## ### ## ##
## ## ## ## ## ## #### ## ##
## ## ## ## ## ## ## ## ## ######
## ######### ## ## ## ## #### ##
## ## ## ## ## ## ## ### ##
## ## ## ######## ####### ## ## ########

describe 'Stand alone minimap', ->
[editor, minimap, largeSample, smallSample] = []

beforeEach ->
atom.config.set 'minimap.charHeight', 4
atom.config.set 'minimap.charWidth', 2
atom.config.set 'minimap.interline', 1

editor = new TextEditor({})
editor.setLineHeightInPixels(10)
editor.setHeight(50)
editor.setWidth(200)

dir = atom.project.getDirectories()[0]

minimap = new Minimap({
textEditor: editor
standAlone: true
})

largeSample = fs.readFileSync(dir.resolve('large-file.coffee')).toString()
smallSample = fs.readFileSync(dir.resolve('sample.coffee')).toString()

it 'has an associated editor', ->
expect(minimap.getTextEditor()).toEqual(editor)

it 'measures the minimap size based on the current editor content', ->
editor.setText(smallSample)
expect(minimap.getHeight()).toEqual(editor.getScreenLineCount() * 5)

editor.setText(largeSample)
expect(minimap.getHeight()).toEqual(editor.getScreenLineCount() * 5)

it 'measures the scaling factor between the editor and the minimap', ->
expect(minimap.getVerticalScaleFactor()).toEqual(0.5)
expect(minimap.getHorizontalScaleFactor()).toEqual(2 / editor.getDefaultCharWidth())

it 'measures the editor visible area size at minimap scale', ->
editor.setText(largeSample)
expect(minimap.getTextEditorScaledHeight()).toEqual(25)

it 'has a visible height based on the passed-in options', ->
expect(minimap.getVisibleHeight()).toEqual(5)

editor.setText(smallSample)
expect(minimap.getVisibleHeight()).toEqual(20)

editor.setText(largeSample)
expect(minimap.getVisibleHeight()).toEqual(editor.getScreenLineCount() * 5)

minimap.height = 100
expect(minimap.getVisibleHeight()).toEqual(100)

it 'has a visible width based on the passed-in options', ->
expect(minimap.getVisibleWidth()).toEqual(0)

editor.setText(smallSample)
expect(minimap.getVisibleWidth()).toEqual(36)

editor.setText(largeSample)
expect(minimap.getVisibleWidth()).toEqual(editor.getMaxScreenLineLength() * 2)

minimap.width = 50
expect(minimap.getVisibleWidth()).toEqual(50)

it 'measures the available minimap scroll', ->
editor.setText(largeSample)
largeLineCount = editor.getScreenLineCount()

expect(minimap.getMaxScrollTop()).toEqual(0)
expect(minimap.canScroll()).toBeFalsy()

minimap.height = 100

expect(minimap.getMaxScrollTop()).toEqual(largeLineCount * 5 - 100)
expect(minimap.canScroll()).toBeTruthy()

it 'computes the first visible row in the minimap', ->
expect(minimap.getFirstVisibleScreenRow()).toEqual(0)

it 'computes the last visible row in the minimap', ->
editor.setText(largeSample)

expect(minimap.getLastVisibleScreenRow()).toEqual(editor.getScreenLineCount())

minimap.height = 100
expect(minimap.getLastVisibleScreenRow()).toEqual(20)

0 comments on commit 5560408

Please sign in to comment.