diff --git a/js/term/screen.js b/js/term/screen.js index b24ce98..e350234 100644 --- a/js/term/screen.js +++ b/js/term/screen.js @@ -55,6 +55,7 @@ module.exports = class TermScreen extends EventEmitter { devicePixelRatio: 1, fontFamily: '"DejaVu Sans Mono", "Liberation Mono", "Inconsolata", "Menlo", monospace', fontSize: 20, + padding: 6, gridScaleX: 1.0, gridScaleY: 1.2, fitIntoWidth: 0, @@ -67,11 +68,15 @@ module.exports = class TermScreen extends EventEmitter { // scaling caused by fitIntoWidth/fitIntoHeight this._windowScale = 1 + // actual padding, as it may be disabled by fullscreen mode etc. + this._padding = 0 + // properties of this.window that require updating size and redrawing this.windowState = { width: 0, height: 0, devicePixelRatio: 0, + padding: 0, gridScaleX: 0, gridScaleY: 0, fontFamily: '', @@ -313,8 +318,8 @@ module.exports = class TermScreen extends EventEmitter { let cellSize = this.getCellSize() return [ - Math.floor((x + (rounded ? cellSize.width / 2 : 0)) / cellSize.width), - Math.floor(y / cellSize.height) + Math.floor((x - this._padding + (rounded ? cellSize.width / 2 : 0)) / cellSize.width), + Math.floor((y - this._padding) / cellSize.height) ] } @@ -328,7 +333,7 @@ module.exports = class TermScreen extends EventEmitter { gridToScreen (x, y, withScale = false) { let cellSize = this.getCellSize() - return [x * cellSize.width, y * cellSize.height].map(v => withScale ? v * this._windowScale : v) + return [x * cellSize.width, y * cellSize.height].map(v => this._padding + (withScale ? v * this._windowScale : v)) } /** @@ -378,13 +383,14 @@ module.exports = class TermScreen extends EventEmitter { width, height, fitIntoWidth, - fitIntoHeight + fitIntoHeight, + padding } = this.window const cellSize = this.getCellSize() // real height of the canvas element in pixels - let realWidth = width * cellSize.width - let realHeight = height * cellSize.height + let realWidth = width * cellSize.width + 2 * padding + let realHeight = height * cellSize.height + 2 * padding if (fitIntoWidth && fitIntoHeight) { let terminalAspect = realWidth / realHeight @@ -409,13 +415,16 @@ module.exports = class TermScreen extends EventEmitter { // store new window scale this._windowScale = realWidth / (width * cellSize.width) + // and padding + // TODO: disable in fullscreen mode + this._padding = padding // the DPR must be rounded to a very nice value to prevent gaps between cells let devicePixelRatio = this._window.devicePixelRatio = Math.round(this._windowScale * (window.devicePixelRatio || 1) * 2) / 2 - this.canvas.width = width * devicePixelRatio * cellSize.width + this.canvas.width = (width * cellSize.width + 2 * padding) * devicePixelRatio this.canvas.style.width = `${realWidth}px` - this.canvas.height = height * devicePixelRatio * cellSize.height + this.canvas.height = (height * cellSize.height + 2 * padding) * devicePixelRatio this.canvas.style.height = `${realHeight}px` // the screen has been cleared (by changing canvas width) diff --git a/js/term/screen_renderer.js b/js/term/screen_renderer.js index a557351..9d0f5af 100644 --- a/js/term/screen_renderer.js +++ b/js/term/screen_renderer.js @@ -159,9 +159,26 @@ module.exports = class ScreenRenderer { */ drawBackground ({ x, y, cellWidth, cellHeight, bg }) { const ctx = this.ctx + const { width, height } = this.screen.window ctx.fillStyle = this.getColor(bg) - ctx.clearRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight) - ctx.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight) + let screenX = x * cellWidth + this.screen._padding + let screenY = y * cellHeight + this.screen._padding + let isBorderCell = x === 0 || y === 0 || x === width - 1 || y === height - 1 + if (isBorderCell) { + let left = screenX + let top = screenY + let right = screenX + cellWidth + let bottom = screenY + cellHeight + if (x === 0) left -= this.screen._padding + else if (x === width - 1) right += this.screen._padding + if (y === 0) top -= this.screen._padding + else if (y === height - 1) bottom += this.screen._padding + ctx.clearRect(left, top, right - left, bottom - top) + ctx.fillRect(left, top, right - left, bottom - top) + } else { + ctx.clearRect(screenX, screenY, cellWidth, cellHeight) + ctx.fillRect(screenX, screenY, cellWidth, cellHeight) + } } /** @@ -194,12 +211,15 @@ module.exports = class ScreenRenderer { ctx.fillStyle = this.getColor(fg) + let screenX = x * cellWidth + this.screen._padding + let screenY = y * cellHeight + this.screen._padding + let codePoint = text.codePointAt(0) if (codePoint >= 0x2580 && codePoint <= 0x259F) { // block elements ctx.beginPath() - const left = x * cellWidth - const top = y * cellHeight + const left = screenX + const top = screenY const cw = cellWidth const ch = cellHeight const c2w = cellWidth / 2 @@ -251,16 +271,16 @@ module.exports = class ScreenRenderer { for (let dx = 0; dx < cw; dx += dotSpacingX) { // prevent overflow let dotSizeY = Math.min(dotSize, ch - dy) - ctx.rect(x * cw + (alignRight ? cw - dx - dotSize : dx), y * ch + dy, dotSize, dotSizeY) + ctx.rect(left + (alignRight ? cw - dx - dotSize : dx), top + dy, dotSize, dotSizeY) } alignRight = !alignRight } } else if (codePoint === 0x2594) { // upper one eighth block >▔< - ctx.rect(x * cw, y * ch, cw, ch / 8) + ctx.rect(left, top, cw, ch / 8) } else if (codePoint === 0x2595) { // right one eighth block >▕< - ctx.rect((x + 7 / 8) * cw, y * ch, cw / 8, ch) + ctx.rect(left + (7 / 8) * cw, top, cw / 8, ch) } else if (codePoint === 0x2596) { // left bottom quadrant >▖< ctx.rect(left, top + c2h, c2w, c2h) @@ -302,7 +322,7 @@ module.exports = class ScreenRenderer { ctx.fill() } else { // Draw other characters using the text renderer - ctx.fillText(text, (x + 0.5) * cellWidth, (y + 0.5) * cellHeight) + ctx.fillText(text, screenX + 0.5 * cellWidth, screenY + 0.5 * cellHeight) } // -- line drawing - a reference for a possible future rect/line implementation --- @@ -324,21 +344,21 @@ module.exports = class ScreenRenderer { ctx.beginPath() if (underline) { - let lineY = Math.round(y * cellHeight + charSize.height) + 0.5 - ctx.moveTo(x * cellWidth, lineY) - ctx.lineTo((x + 1) * cellWidth, lineY) + let lineY = Math.round(screenY + charSize.height) + 0.5 + ctx.moveTo(screenX, lineY) + ctx.lineTo(screenX + cellWidth, lineY) } if (strike) { - let lineY = Math.round((y + 0.5) * cellHeight) + 0.5 - ctx.moveTo(x * cellWidth, lineY) - ctx.lineTo((x + 1) * cellWidth, lineY) + let lineY = Math.round(screenY + 0.5 * cellHeight) + 0.5 + ctx.moveTo(screenX, lineY) + ctx.lineTo(screenX + cellWidth, lineY) } if (overline) { - let lineY = Math.round(y * cellHeight) + 0.5 - ctx.moveTo(x * cellWidth, lineY) - ctx.lineTo((x + 1) * cellWidth, lineY) + let lineY = Math.round(screenY) + 0.5 + ctx.moveTo(screenX, lineY) + ctx.lineTo(screenX + cellWidth, lineY) } ctx.stroke() @@ -570,17 +590,19 @@ module.exports = class ScreenRenderer { if (isCursor && !inSelection) { ctx.save() ctx.beginPath() + let screenX = x * cellWidth + this.screen._padding + let screenY = y * cellHeight + this.screen._padding if (this.screen.cursor.style === 'block') { // block - ctx.rect(x * cellWidth, y * cellHeight, cellWidth, cellHeight) + ctx.rect(screenX, screenY, cellWidth, cellHeight) } else if (this.screen.cursor.style === 'bar') { // vertical bar let barWidth = 2 - ctx.rect(x * cellWidth, y * cellHeight, barWidth, cellHeight) + ctx.rect(screenX, screenY, barWidth, cellHeight) } else if (this.screen.cursor.style === 'line') { // underline let lineHeight = 2 - ctx.rect(x * cellWidth, y * cellHeight + charSize.height, cellWidth, lineHeight) + ctx.rect(screenX, screenY + charSize.height, cellWidth, lineHeight) } ctx.clip() diff --git a/sass/pages/_term.scss b/sass/pages/_term.scss index 19df4d1..6eaddd8 100644 --- a/sass/pages/_term.scss +++ b/sass/pages/_term.scss @@ -18,7 +18,6 @@ body.term { #screen { white-space: nowrap; background: #111213; - padding: 6px; display: inline-block; border: 2px solid #3983CD; position: relative;