move resize handling in the window model

This commit is contained in:
Fabian Jakobs 2011-08-01 18:47:37 +02:00
commit cd42d284fd
6 changed files with 207 additions and 227 deletions

View file

@ -142,7 +142,8 @@ var Editor = function(windowView, buffer) {
};
this.resize = function() {
this.renderer.onResize();
//this.renderer.onResize();
this.windowController.resize();
};
this.setTheme = function(theme) {
@ -196,117 +197,6 @@ var Editor = function(windowView, buffer) {
this._dispatchEvent("blur");
};
/* this.onDocumentChange = function(e) {
var delta = e.data;
var range = delta.range;
if (range.start.row == range.end.row && delta.action != "insertLines" && delta.action != "removeLines")
var lastRow = range.end.row;
else
lastRow = Infinity;
this.renderer.updateLines(range.start.row, lastRow);
// update cursor because tab characters can influence the cursor position
this.renderer.updateCursor();
};
this.onTokenizerUpdate = function(e) {
var rows = e.data;
this.renderer.updateLines(rows.first, rows.last);
};
this.onCursorChange = function(e) {
this.renderer.updateCursor();
if (!this.$blockScrolling) {
this.windowModel.scrollCursorIntoView();
}
// move text input over the cursor
// this is required for iOS and IME
this.renderer.moveTextAreaToCursor(this.textInput.getElement());
this.$highlightBrackets();
this.$updateHighlightActiveLine();
};
this.$updateHighlightActiveLine = function() {
var session = this.getSession();
if (session.$highlightLineMarker) {
session.removeMarker(session.$highlightLineMarker);
}
session.$highlightLineMarker = null;
if (this.getHighlightActiveLine() && (this.getSelectionStyle() != "line" || !this.selection.isMultiLine())) {
var cursor = this.getCursorPosition(),
foldLine = this.session.getFoldLine(cursor.row);
var range;
if (foldLine) {
range = new Range(foldLine.start.row, 0, foldLine.end.row + 1, 0);
} else {
range = new Range(cursor.row, 0, cursor.row+1, 0);
}
session.$highlightLineMarker = session.addMarker(range, "ace_active_line", "background");
}
};
this.onSelectionChange = function(e) {
var session = this.getSession();
if (session.$selectionMarker) {
session.removeMarker(session.$selectionMarker);
}
session.$selectionMarker = null;
if (!this.selection.isEmpty()) {
var range = this.selection.getRange();
var style = this.getSelectionStyle();
session.$selectionMarker = session.addMarker(range, "ace_selection", style);
} else {
this.$updateHighlightActiveLine();
}
if (this.$highlightSelectedWord)
this.session.getMode().highlightSelection(this);
};
this.onChangeFrontMarker = function() {
this.renderer.updateFrontMarkers();
};
this.onChangeBackMarker = function() {
this.renderer.updateBackMarkers();
};
this.onChangeBreakpoint = function() {
this.renderer.setBreakpoints(this.session.getBreakpoints());
};
this.onChangeAnnotation = function() {
this.renderer.setAnnotations(this.session.getAnnotations());
};
this.onChangeMode = function() {
this.renderer.updateText()
};
this.onChangeWrapLimit = function() {
this.renderer.updateFull();
};
this.onChangeWrapMode = function() {
this.renderer.onResize(true);
};
this.onChangeFold = function() {
// Update the active line marker as due to folding changes the current
// line range on the screen might have changed.
this.$updateHighlightActiveLine();
// TODO: This might be too much updating. Okay for now.
this.renderer.updateFull();
};*/
this.getCopyText = function() {
var text = "";
if (!this.selection.isEmpty())
@ -816,7 +706,6 @@ var Editor = function(windowView, buffer) {
this.renderer.hideComposition();
};
this.getFirstVisibleRow = function() {
return this.windowModel.getFirstVisibleRow();
};
@ -826,22 +715,19 @@ var Editor = function(windowView, buffer) {
};
this.isRowVisible = function(row) {
return (row >= this.getFirstVisibleRow() && row <= this.getLastVisibleRow());
return this.windowModel.isRowVisible(row);
};
this.$getVisibleRowCount = function() {
return this.windowModel.getScrollBottomRow() - this.windowModel.getScrollTopRow() + 1;
return this.windowModel.getVisibleRowCount();
};
this.$getPageDownRow = function() {
return this.windowModel.getScrollBottomRow();
return this.windowModel.getPageDownRow();
};
this.$getPageUpRow = function() {
var firstRow = this.windowModel.getScrollTopRow();
var lastRow = this.windowModel.getScrollBottomRow();
return firstRow - (lastRow - firstRow);
return this.windowModel.getPageUpRow();
};
this.selectPageDown = function() {
@ -900,58 +786,44 @@ var Editor = function(windowView, buffer) {
};
this.centerSelection = function() {
var range = this.getSelectionRange();
var line = Math.floor(range.start.row + (range.end.row - range.start.row) / 2);
this.windowModel.scrollToLine(line, true);
this.windowModel.centerSelection();
};
this.getCursorPosition = function() {
return this.selection.getCursor();
return this.windowModel.getCursorPosition();
};
this.getCursorPositionScreen = function() {
return this.session.documentToScreenPosition(this.getCursorPosition());
return this.windowModel.getCursorPositionScreen();
};
this.getSelectionRange = function() {
return this.selection.getRange();
return this.windowModel.getSelectionRange();
};
this.selectAll = function() {
this.$blockScrolling += 1;
this.selection.selectAll();
this.$blockScrolling -= 1;
this.windowModel.selectAll();
};
this.clearSelection = function() {
this.selection.clearSelection();
this.windowModel.clearSelection();
};
this.moveCursorTo = function(row, column) {
this.selection.moveCursorTo(row, column);
this.windowModel.moveCursorTo(row, column);
};
this.moveCursorToPosition = function(pos) {
this.selection.moveCursorToPosition(pos);
this.windowModel.moveCursorToPosition(pos);
};
this.gotoLine = function(lineNumber, column) {
this.selection.clearSelection();
this.$blockScrolling += 1;
this.moveCursorTo(lineNumber-1, column || 0);
this.$blockScrolling -= 1;
if (!this.isRowVisible(this.getCursorPosition().row)) {
this.scrollToLine(lineNumber, true);
}
},
this.windowModel.gotoLine(lineNumber, column);
};
this.navigateTo = function(row, column) {
this.clearSelection();
this.moveCursorTo(row, column);
this.windowModel.navigateTo(row, column);
};
this.navigateUp = function(times) {

View file

@ -43,6 +43,7 @@ if (typeof process !== "undefined") {
define(function(require, exports, module) {
var Buffer = require("ace/model/buffer").Buffer;
var Window = require("ace/model/window").Window;
var Editor = require("ace/editor").Editor;
var MockRenderer = require("ace/view/window_view_mock").MockRenderer;
var assert = require("ace/test/assertions");
@ -78,38 +79,48 @@ module.exports = {
assert.equal(editor.getFirstVisibleRow(), 0);
},
"test: goto hidden line should scroll the line into the middle of the viewport" : function() {
var editor = new Editor(new MockRenderer(), this.createBuffer(200, 5));
">test: goto hidden line should scroll the line into the middle of the viewport" : function() {
//var editor = new Editor(new MockRenderer(), this.createBuffer(200, 5));
var win = new Window();
win.setBuffer(this.createBuffer(200, 5));
win.setSizes({
heigth: 410,
width: 640,
scrollerHeight: 410,
scrollerWidth: 600
});
win.setComputedCharacterSize({width: 10, height: 20});
//win.updateLayerConfig();
editor.navigateTo(0, 0);
editor.gotoLine(101);
assert.position(editor.getCursorPosition(), 100, 0);
assert.equal(editor.getFirstVisibleRow(), 90);
win.navigateTo(0, 0);
win.gotoLine(101);
assert.position(win.getCursorPosition(), 100, 0);
assert.equal(win.getFirstVisibleRow(), 90);
editor.navigateTo(100, 0);
editor.gotoLine(11);
assert.position(editor.getCursorPosition(), 10, 0);
assert.equal(editor.getFirstVisibleRow(), 0);
win.navigateTo(100, 0);
win.gotoLine(11);
assert.position(win.getCursorPosition(), 10, 0);
assert.equal(win.getFirstVisibleRow(), 0);
editor.navigateTo(100, 0);
editor.gotoLine(6);
assert.position(editor.getCursorPosition(), 5, 0);
assert.equal(0, editor.getFirstVisibleRow(), 0);
win.navigateTo(100, 0);
win.gotoLine(6);
assert.position(win.getCursorPosition(), 5, 0);
assert.equal(0, win.getFirstVisibleRow(), 0);
editor.navigateTo(100, 0);
editor.gotoLine(1);
assert.position(editor.getCursorPosition(), 0, 0);
assert.equal(editor.getFirstVisibleRow(), 0);
win.navigateTo(100, 0);
win.gotoLine(1);
assert.position(win.getCursorPosition(), 0, 0);
assert.equal(win.getFirstVisibleRow(), 0);
editor.navigateTo(0, 0);
editor.gotoLine(191);
assert.position(editor.getCursorPosition(), 190, 0);
assert.equal(editor.getFirstVisibleRow(), 180);
win.navigateTo(0, 0);
win.gotoLine(191);
assert.position(win.getCursorPosition(), 190, 0);
assert.equal(win.getFirstVisibleRow(), 180);
editor.navigateTo(0, 0);
editor.gotoLine(196);
assert.position(editor.getCursorPosition(), 195, 0);
assert.equal(editor.getFirstVisibleRow(), 180);
win.navigateTo(0, 0);
win.gotoLine(196);
assert.position(win.getCursorPosition(), 195, 0);
assert.equal(win.getFirstVisibleRow(), 180);
},
"test: goto visible line should only move the cursor and not scroll": function() {

View file

@ -77,6 +77,7 @@ var Window = exports.Window = function(theme) {
this.scrollLeft = 0;
this.scrollTop = 0;
this._blockScrolling = 0;
this.showInvisibles = false;
this.showPrintMargin = true;
@ -94,6 +95,31 @@ var Window = exports.Window = function(theme) {
oop.implement(this, EventEmitter);
// VIEWPORT SIZE
this.setSizes = function(size) {
if (this.size.width !== size.width || this.size.scrollerWidth !== size.scrollerWidth) {
this.size.width = size.width;
this.size.scrollerWidth = size.scrollerWidth;
this.size.gutterWidth = size.gutterWidth;
this._emit("changeWidth");
}
if (this.size.height !== size.height || this.size.scrollerHeight !== size.scrollerHeight) {
this.size.height = size.height;
this.size.scrollerHeight = size.scrollerHeight;
this._emit("changeHeight");
}
};
this.setComputedCharacterSize = function(size) {
if (this.charSize.height == size.height && this.charSize.width == size.width)
return;
this.charSize = size;
this._emit("changeCharacterSize")
};
// VIEWPORT COMPUTATIONS
this.getFirstVisibleRow = function() {
@ -113,6 +139,25 @@ var Window = exports.Window = function(theme) {
return this.layerConfig.firstRow - 1 + flint;
};
this.isRowVisible = function(row) {
return (row >= this.getFirstVisibleRow() && row <= this.getLastVisibleRow());
};
this.getVisibleRowCount = function() {
return this.getScrollBottomRow() - this.getScrollTopRow() + 1;
};
this.getPageDownRow = function() {
return this.getScrollBottomRow();
};
this.getPageUpRow = function() {
var firstRow = this.getScrollTopRow();
var lastRow = this.getScrollBottomRow();
return firstRow - (lastRow - firstRow);
};
this.getCursorPixelPosition = function(onScreen) {
if (!this.buffer) {
return {
@ -140,6 +185,62 @@ var Window = exports.Window = function(theme) {
this.getRowHeight = function(row) {
return this.buffer.getRowLength(row) * this.charSize.height;
};
// SELECTION HANDLING
this.centerSelection = function() {
var range = this.getSelectionRange();
var line = Math.floor(range.start.row + (range.end.row - range.start.row) / 2);
this.scrollToLine(line, true);
};
this.getCursorPosition = function() {
return this.selection.getCursor();
};
this.getCursorPositionScreen = function() {
return this.buffer.documentToScreenPosition(this.getCursorPosition());
};
this.getSelectionRange = function() {
return this.selection.getRange();
};
this.selectAll = function() {
this._blockScrolling += 1;
this.selection.selectAll();
this._blockScrolling -= 1;
};
this.clearSelection = function() {
this.selection.clearSelection();
};
this.moveCursorTo = function(row, column) {
this.selection.moveCursorTo(row, column);
};
this.moveCursorToPosition = function(pos) {
this.selection.moveCursorToPosition(pos);
};
// NAVIGATION
this.gotoLine = function(lineNumber, column) {
this.selection.clearSelection();
this._blockScrolling += 1;
this.moveCursorTo(lineNumber-1, column || 0);
this._blockScrolling -= 1;
if (!this.isRowVisible(this.getCursorPosition().row))
this.scrollToLine(lineNumber, true);
};
this.navigateTo = function(row, column) {
this.clearSelection();
this.moveCursorTo(row, column);
};
// SCROLLING
@ -204,6 +305,9 @@ var Window = exports.Window = function(theme) {
if (this.size.scrollerHeight === 0)
return;
if (this._blockScrolling)
return;
var pos = this.getCursorPixelPosition();
var left = pos.left;
@ -340,14 +444,6 @@ var Window = exports.Window = function(theme) {
return this.horizScrollAlwaysVisible;
};
this.setComputedCharacterSize = function(size) {
if (this.charSize.height == size.height && this.charSize.width == size.width)
return;
this.charSize = size;
this._emit("changeCharacterSize")
};
this.setSelectionStyle = function(style) {
if (this.selectionStyle === style)
return;

View file

@ -176,45 +176,47 @@ var WindowView = function(windowModel, container) {
this.$textLayer.checkForSizeChanges();
};
/**
* Triggers resize of the editor
*/
this.onResize = function(force) {
if (!this.scroller || !this.container || !this.model.buffer)
return;
var changes = this.CHANGE_SIZE;
var size = this.model.size;
var height = dom.getInnerHeight(this.container);
if (force || size.height != height) {
size.height = height;
this.scroller.style.height = height + "px";
size.scrollerHeight = this.scroller.clientHeight;
this.scrollBar.setHeight(size.scrollerHeight);
if (this.model.buffer) {
this.model.scrollToY(this.model.scrollTop);
changes = changes | this.CHANGE_FULL;
}
}
this.measureSizes = function() {
var width = dom.getInnerWidth(this.container);
if (force || size.width != width) {
size.width = width;
var gutterWidth = this.model.showGutter ? this.$gutter.offsetWidth : 0;
this.scroller.style.left = gutterWidth + "px";
size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBar.getWidth())
this.scroller.style.width = size.scrollerWidth + "px";
if (this.model.buffer.getUseWrapMode() && this.adjustWrapLimit() || force)
changes = changes | this.CHANGE_FULL;
var gutterWidth = this.model.showGutter ? this.$gutter.offsetWidth : 0;
return {
width: width,
height: dom.getInnerHeight(this.container),
scrollerHeight: this.scroller.clientHeight,
scrollerWidth: Math.max(0, width - gutterWidth - this.scrollBar.getWidth()),
gutterWidth: gutterWidth
}
};
this.updateHeight = function() {
var size = this.model.size;
this.scroller.style.height = size.height + "px";
this.scrollBar.setHeight(size.scrollerHeight);
var changes = this.CHANGE_SIZE;
if (this.model.buffer) {
this.model.scrollToY(this.model.scrollTop);
changes = changes | this.CHANGE_FULL;
}
this.$loop.schedule(changes);
};
this.updateWidth = function() {
var size = this.model.size;
var changes = this.CHANGE_SIZE;
this.scroller.style.left = size.gutterWidth + "px";
this.scroller.style.width = size.scrollerWidth + "px";
// TODO refactor
// move to the model
if (this.model.buffer.getUseWrapMode() && this.adjustWrapLimit())
changes = changes | this.CHANGE_FULL;
this.$loop.schedule(changes);
}
this.adjustWrapLimit = function(){
var availableWidth = this.model.size.scrollerWidth - this.model.padding * 2;
@ -238,7 +240,7 @@ var WindowView = function(windowModel, container) {
this.updateShowGutter = function(){
this.$gutter.style.display = this.model.showGutter ? "block" : "none";
this.onResize(true);
this._emit("resize");
};
this.updatePrintMargin = function() {
@ -302,7 +304,7 @@ var WindowView = function(windowModel, container) {
this.updateCharacterSize = function() {
this.updatePrintMargin();
this.onResize(true);
this._emit("resize");
this.$loop.schedule(this.CHANGE_FULL);
};
@ -449,7 +451,7 @@ var WindowView = function(windowModel, container) {
// Horizontal scrollbar visibility may have changed, which changes
// the client height of the scroller
if (horizScrollChanged)
this.onResize(true);
this._emit("resize");
};
this.$updateLines = function() {
@ -619,7 +621,7 @@ var WindowView = function(windowModel, container) {
// force re-measure of the gutter width
if (this.model.size) {
this.model.size.width = 0;
this.onResize();
this._emit("resize");
}
};

View file

@ -98,11 +98,4 @@ WindowViewMock.prototype.getSession = function(session) {
WindowViewMock.prototype[name] = function() {};
})
WindowViewMock.prototype.textToScreenCoordinates = function() {
return {
pageX: 0,
pageY: 0
}
};
});

View file

@ -52,16 +52,24 @@ var WindowController = exports.WindowController = function(model, view) {
model.on("changeCharacterSize", view.updateCharacterSize.bind(view));
model.on("changeScrollLeft", view.updateScrollLeft.bind(view));
model.on("changeScrollTop", view.updateScrollTop.bind(view));
model.on("changeWidth", view.updateWidth.bind(view));
model.on("changeHeight", view.updateHeight.bind(view));
model.on("changeSelectionStyle", this.onSelectionChange.bind(this));
model.on("changeHighlightActiveLine", this._updateHighlightActiveLine.bind(this));
model.on("changeHighlightSelectedWord", this.onChangeHighlightSelectedWord.bind(this));
model.on("changeBuffer", this.onChangeBuffer.bind(this));
view.on("resize", this.resize.bind(this));
};
(function() {
this.resize = function() {
this.model.setSizes(this.view.measureSizes());
};
this.onChangeHighlightSelectedWord = function() {
var buffer = this.model.buffer;
if (this.model.shouldHighlight)
@ -193,9 +201,7 @@ var WindowController = exports.WindowController = function(model, view) {
this.onCursorChange = function(e) {
this.view.updateCursor();
if (!this._blockScrolling)
this.model.scrollCursorIntoView();
this.model.scrollCursorIntoView();
// move text input over the cursor
// this is required for iOS and IME