diff --git a/spec/atom/root-view-spec.coffee b/spec/atom/root-view-spec.coffee index 2de81d372..a270d39d9 100644 --- a/spec/atom/root-view-spec.coffee +++ b/spec/atom/root-view-spec.coffee @@ -41,22 +41,27 @@ describe "RootView", -> editor1 = rootView.find('.editor').view() editor1.setBuffer(new Buffer(require.resolve 'fixtures/sample.js')) editor1.setCursorScreenPosition([3, 2]) + rootView.width(800) + rootView.height(600) describe "vertical splits", -> describe "when split-right is triggered on the editor", -> it "places a new editor to the right of the current editor in a .horizontal div, and focuses the new editor", -> - expect(rootView.find('.horizontal')).not.toExist() + expect(rootView.find('.row')).not.toExist() editor1.trigger 'split-right' - expect(rootView.find('.horizontal')).toExist() - expect(rootView.find('.horizontal .editor').length).toBe 2 - expect(rootView.find('.horizontal .editor:eq(0)').view()).toBe editor1 - editor2 = rootView.find('.horizontal .editor:eq(1)').view() + expect(rootView.find('.row')).toExist() + expect(rootView.find('.row .editor').length).toBe 2 + expect(rootView.find('.row .editor:eq(0)').view()).toBe editor1 + editor2 = rootView.find('.row .editor:eq(1)').view() expect(editor2.buffer).toBe editor1.buffer expect(editor2.getCursorScreenPosition()).toEqual [3, 2] - expect(editor1).toHaveClass 'split' - expect(editor2).toHaveClass 'split' + + expectedColumnWidth = Math.floor(rootView.width() / 2) + expect(editor1.width()).toBe expectedColumnWidth + expect(editor2.position().left).toBe expectedColumnWidth + expect(editor2.width()).toBe expectedColumnWidth expect(editor1.has(':focus')).not.toExist() expect(editor2.has(':focus')).toExist() @@ -67,19 +72,22 @@ describe "RootView", -> expect(editor2.lines.find('.line:first').text()).toContain 'ABC' describe "when split-left is triggered on the editor", -> - it "places a new editor to the left of the current editor in a .horizontal div, and focuses the new editor", -> - expect(rootView.find('.horizontal')).not.toExist() + it "places a new editor to the left of the current editor in a .row div, and focuses the new editor", -> + expect(rootView.find('.row')).not.toExist() editor1.trigger 'split-left' - expect(rootView.find('.horizontal')).toExist() - expect(rootView.find('.horizontal .editor').length).toBe 2 - expect(rootView.find('.horizontal .editor:eq(1)').view()).toBe editor1 - editor2 = rootView.find('.horizontal .editor:eq(0)').view() + expect(rootView.find('.row')).toExist() + expect(rootView.find('.row .editor').length).toBe 2 + expect(rootView.find('.row .editor:eq(1)').view()).toBe editor1 + editor2 = rootView.find('.row .editor:eq(0)').view() expect(editor2.buffer).toBe editor1.buffer expect(editor2.getCursorScreenPosition()).toEqual [3, 2] - expect(editor1).toHaveClass 'split' - expect(editor2).toHaveClass 'split' + + expectedColumnWidth = Math.floor(rootView.width() / 2) + expect(editor2.width()).toBe expectedColumnWidth + expect(editor1.position().left).toBe expectedColumnWidth + expect(editor1.width()).toBe expectedColumnWidth expect(editor1.has(':focus')).not.toExist() expect(editor2.has(':focus')).toExist() @@ -96,14 +104,17 @@ describe "RootView", -> editor1.trigger 'split-up' - expect(rootView.find('.vertical')).toExist() - expect(rootView.find('.vertical .editor').length).toBe 2 - expect(rootView.find('.vertical .editor:eq(1)').view()).toBe editor1 - editor2 = rootView.find('.vertical .editor:eq(0)').view() + expect(rootView.find('.column')).toExist() + expect(rootView.find('.column .editor').length).toBe 2 + expect(rootView.find('.column .editor:eq(1)').view()).toBe editor1 + editor2 = rootView.find('.column .editor:eq(0)').view() expect(editor2.buffer).toBe editor1.buffer expect(editor2.getCursorScreenPosition()).toEqual [3, 2] - expect(editor1).toHaveClass 'split' - expect(editor2).toHaveClass 'split' + + expectedRowHeight = Math.floor(rootView.height() / 2) + expect(editor2.height()).toBe expectedRowHeight + expect(editor1.position().top).toBe expectedRowHeight + expect(editor1.height()).toBe expectedRowHeight expect(editor1.has(':focus')).not.toExist() expect(editor2.has(':focus')).toExist() @@ -115,18 +126,21 @@ describe "RootView", -> describe "when split-down is triggered on the editor", -> it "places a new editor below the current editor in a .vertical div, and focuses the new editor", -> - expect(rootView.find('.vertical')).not.toExist() + expect(rootView.find('.column')).not.toExist() editor1.trigger 'split-down' - expect(rootView.find('.vertical')).toExist() - expect(rootView.find('.vertical .editor').length).toBe 2 - expect(rootView.find('.vertical .editor:eq(0)').view()).toBe editor1 - editor2 = rootView.find('.vertical .editor:eq(1)').view() + expect(rootView.find('.column')).toExist() + expect(rootView.find('.column .editor').length).toBe 2 + expect(rootView.find('.column .editor:eq(0)').view()).toBe editor1 + editor2 = rootView.find('.column .editor:eq(1)').view() expect(editor2.buffer).toBe editor1.buffer expect(editor2.getCursorScreenPosition()).toEqual [3, 2] - expect(editor1).toHaveClass 'split' - expect(editor2).toHaveClass 'split' + + expectedRowHeight = Math.floor(rootView.height() / 2) + expect(editor1.height()).toBe expectedRowHeight + expect(editor2.position().top).toBe expectedRowHeight + expect(editor2.height()).toBe expectedRowHeight expect(editor1.has(':focus')).not.toExist() expect(editor2.has(':focus')).toExist() @@ -136,6 +150,62 @@ describe "RootView", -> expect(editor1.lines.find('.line:first').text()).toContain 'ABC' expect(editor2.lines.find('.line:first').text()).toContain 'ABC' + describe "layout of nested vertical and horizontal splits", -> + it "lays out rows and columns with a consistent width", -> + editor = rootView.find('.editor:has(:focus)').view() + editor.trigger 'split-left' + editor = rootView.find('.editor:has(:focus)').view() + editor.trigger 'split-up' + editor = rootView.find('.editor:has(:focus)').view() + editor.trigger 'split-left' + editor = rootView.find('.editor:has(:focus)').view() + editor.trigger 'split-up' + + row1 = rootView.children(':eq(0)') + expect(row1.children().length).toBe 2 + column1 = row1.children(':eq(0)') + editor1 = row1.children(':eq(1)') + expect(column1.width()).toBe Math.floor(2/3 * rootView.width()) + expect(column1.height()).toBe rootView.height() + expect(editor1.width()).toBe Math.floor(1/3 * rootView.width()) + expect(editor1.height()).toBe rootView.height() + expect(editor1.position().left).toBe column1.width() + + expect(column1.children().length).toBe 2 + row2 = column1.children(':eq(0)') + editor2 = column1.children(':eq(1)') + expect(row2.width()).toBe column1.width() + expect(row2.height()).toBe Math.floor(2/3 * rootView.height()) + expect(editor2.width()).toBe column1.width() + expect(editor2.height()).toBe Math.floor(1/3 * rootView.height()) + expect(editor2.position().top).toBe row2.height() + + expect(row2.children().length).toBe 2 + column3 = row2.children(':eq(0)') + editor3 = row2.children(':eq(1)') + expect(column3.width()).toBe Math.floor(1/3 * rootView.width()) + expect(column3.height()).toBe row2.height() + expect(editor3.width()).toBe Math.floor(1/3 * rootView.width()) + expect(editor3.height()).toBe row2.height() + expect(editor3.position().left).toBe column3.width() + + expect(column3.children().length).toBe 2 + editor4 = column3.children(':eq(0)') + editor5 = column3.children(':eq(1)') + expect(editor4.width()).toBe column3.width() + expect(editor4.height()).toBe Math.floor(1/3 * rootView.height()) + expect(editor5.width()).toBe column3.width() + expect(editor5.position().top).toBe editor4.height() + expect(editor5.height()).toBe Math.floor(1/3 * rootView.height()) + + + + + + + + + describe ".addPane(view)", -> it "adds the given view to the rootView (at the bottom by default)", -> diff --git a/src/atom/editor.coffee b/src/atom/editor.coffee index b29b4dfe6..eb6252c59 100644 --- a/src/atom/editor.coffee +++ b/src/atom/editor.coffee @@ -418,30 +418,26 @@ class Editor extends View @renderer.logLines() splitLeft: -> - @split('horizontal', 'before') + @split('row', 'before') splitRight: -> - @split('horizontal', 'after') + @split('row', 'after') splitUp: -> - @split('vertical', 'before') + @split('column', 'before') splitDown: -> - @split('vertical', 'after') + @split('column', 'after') - split: (axis, side) -> - unless @parent().hasClass(axis) + split: (axis, insertMethod) -> + unless @parent().hasClass axis container = $$ -> @div class: axis container.insertBefore(this).append(this.detach()) editor = new Editor({@buffer}) editor.setCursorScreenPosition(@getCursorScreenPosition()) - @addClass 'split' - editor.addClass('split') - if side is 'before' - @before(editor) - else - @after(editor) + this[insertMethod](editor) + @parents('#root-view').view().adjustSplitPanes() remove: (selector, keepData) -> @unsubscribeFromBuffer() unless keepData diff --git a/src/atom/root-view.coffee b/src/atom/root-view.coffee index 9a2cd9ae5..8ed1ded4c 100644 --- a/src/atom/root-view.coffee +++ b/src/atom/root-view.coffee @@ -36,6 +36,57 @@ class RootView extends View addPane: (view) -> @append(view) + adjustSplitPanes: (element = @children(':first'))-> + if element.hasClass('row') + totalUnits = @horizontalGridUnits(element) + console.log totalUnits + unitsSoFar = 0 + for child in element.children() + child = $(child) + childUnits = @horizontalGridUnits(child) + child.css + width: "#{childUnits / totalUnits * 100}%" + height: '100%' + top: 0 + left: "#{unitsSoFar / totalUnits * 100}%" + @adjustSplitPanes(child) + unitsSoFar += childUnits + + else if element.hasClass('column') + totalUnits = @verticalGridUnits(element) + console.log "total vertical", totalUnits + unitsSoFar = 0 + for child in element.children() + child = $(child) + childUnits = @verticalGridUnits(child) + child.css + width: '100%' + height: "#{childUnits / totalUnits * 100}%" + top: "#{unitsSoFar / totalUnits * 100}%" + left: 0 + @adjustSplitPanes(child) + unitsSoFar += childUnits + + horizontalGridUnits: (element) -> + if element.is('.row, .column') + childUnits = (@horizontalGridUnits($(child)) for child in element.children()) + if element.hasClass('row') + _.sum(childUnits) + else # it's a column + Math.max(childUnits...) + else + 1 + + verticalGridUnits: (element) -> + if element.is('.row, .column') + childUnits = (@verticalGridUnits($(child)) for child in element.children()) + if element.hasClass('column') + _.sum(childUnits) + else # it's a row + Math.max(childUnits...) + else + 1 + toggleFileFinder: -> return unless @project diff --git a/src/stdlib/underscore-extensions.coffee b/src/stdlib/underscore-extensions.coffee index 334e7fde4..32d3ff078 100644 --- a/src/stdlib/underscore-extensions.coffee +++ b/src/stdlib/underscore-extensions.coffee @@ -4,3 +4,7 @@ _.mixin remove: (array, element) -> array.splice(array.indexOf(element), 1) + sum: (array) -> + sum = 0 + sum += elt for elt in array + sum diff --git a/static/atom.css b/static/atom.css index 83013bb53..74cc34d3b 100644 --- a/static/atom.css +++ b/static/atom.css @@ -16,39 +16,23 @@ body { background-image: url(static/images/linen.png); } -.vertical { - display: -webkit-flexbox; - -webkit-flex-flow: column; - overflow-y: visible; +.column { + position: absolute; + width: 100%; height: 100%; - position: relative; + overflow-y: hidden; } -.horizontal { - display: -webkit-flexbox; - -webkit-flex-flow: row; - overflow-x: visible; - position: relative; +.row { + position: absolute; + width: 100%; + height: 100%; + overflow-x: hidden; } -/* hack workaround that shouldn't be needed when flexbox works right */ -.horizontal > .vertical { +.column > *, .row > * { + position: absolute; + width: 100%; height: 100%; } -.horizontal > div { - width: -webkit-flex(1); - height: auto; -} - -.vertical > div { - height: -webkit-flex(1); -} - -.horizontal > * + * { - border-left: 5px solid #515151; -} - -.vertical > * + * { - border-top: 5px solid #515151; -}