Put layout between screen and renderer

pull/1/head
cpsdqs 7 years ago
parent 3ef4f0712b
commit 3851cd6aa6
Signed by untrusted user: cpsdqs
GPG Key ID: 3F59586BB7448DD1
  1. 2
      js/term/index.js
  2. 70
      js/term/screen.js
  3. 23
      js/term/screen_layout.js
  4. 146
      js/term/screen_renderer.js

@ -127,7 +127,7 @@ module.exports = function (opts) {
return false return false
} }
qs('#screen').appendChild(screen.canvas) qs('#screen').appendChild(screen.layout.canvas)
initSoftKeyboard(screen, input) initSoftKeyboard(screen, input)
if (attachDebugger) attachDebugger(screen, conn) if (attachDebugger) attachDebugger(screen, conn)

@ -24,6 +24,28 @@ module.exports = class TermScreen extends EventEmitter {
console.warn('No AudioContext!') console.warn('No AudioContext!')
} }
this._window = {
width: 0,
height: 0,
// two bits. LSB: debug enabled by user, MSB: debug enabled by server
debug: 0,
statusScreen: null
}
// make writing to window update size and draw
this.window = new Proxy(this._window, {
set (target, key, value) {
if (target[key] !== value) {
target[key] = value
self.updateLayout()
self.emit(`update-window:${key}`, value)
}
return true
}
})
this.on('update-window:debug', debug => { this.layout.window.debug = !!debug })
this.cursor = { this.cursor = {
x: 0, x: 0,
y: 0, y: 0,
@ -69,20 +91,20 @@ module.exports = class TermScreen extends EventEmitter {
let selectStart = (x, y) => { let selectStart = (x, y) => {
if (selecting) return if (selecting) return
selecting = true selecting = true
this.selection.start = this.selection.end = this.screenToGrid(x, y, true) this.selection.start = this.selection.end = this.layout.screenToGrid(x, y, true)
this.layout.scheduleDraw('select-start') this.layout.scheduleDraw('select-start')
} }
let selectMove = (x, y) => { let selectMove = (x, y) => {
if (!selecting) return if (!selecting) return
this.selection.end = this.screenToGrid(x, y, true) this.selection.end = this.layout.screenToGrid(x, y, true)
this.layout.scheduleDraw('select-move') this.layout.scheduleDraw('select-move')
} }
let selectEnd = (x, y) => { let selectEnd = (x, y) => {
if (!selecting) return if (!selecting) return
selecting = false selecting = false
this.selection.end = this.screenToGrid(x, y, true) this.selection.end = this.layout.screenToGrid(x, y, true)
this.layout.scheduleDraw('select-end') this.layout.scheduleDraw('select-end')
Object.assign(this.selection, this.getNormalizedSelection()) Object.assign(this.selection, this.getNormalizedSelection())
} }
@ -94,7 +116,7 @@ module.exports = class TermScreen extends EventEmitter {
if ((this.selection.selectable || e.altKey) && e.button === 0) { if ((this.selection.selectable || e.altKey) && e.button === 0) {
selectStart(e.offsetX, e.offsetY) selectStart(e.offsetX, e.offsetY)
} else { } else {
this.emit('mousedown', ...this.screenToGrid(e.offsetX, e.offsetY), e.button + 1) this.emit('mousedown', ...this.layout.screenToGrid(e.offsetX, e.offsetY), e.button + 1)
} }
}) })
@ -150,7 +172,7 @@ module.exports = class TermScreen extends EventEmitter {
// selection ended; show touch select menu // selection ended; show touch select menu
// use middle position for x and one line above for y // use middle position for x and one line above for y
let selectionPos = this.gridToScreen( let selectionPos = this.layout.gridToScreen(
(this.selection.start[0] + this.selection.end[0]) / 2, (this.selection.start[0] + this.selection.end[0]) / 2,
this.selection.start[1] - 1 this.selection.start[1] - 1
) )
@ -184,13 +206,13 @@ module.exports = class TermScreen extends EventEmitter {
this.layout.on('mousemove', e => { this.layout.on('mousemove', e => {
if (!selecting) { if (!selecting) {
this.emit('mousemove', ...this.screenToGrid(e.offsetX, e.offsetY)) this.emit('mousemove', ...this.layout.screenToGrid(e.offsetX, e.offsetY))
} }
}) })
this.layout.on('mouseup', e => { this.layout.on('mouseup', e => {
if (!selecting) { if (!selecting) {
this.emit('mouseup', ...this.screenToGrid(e.offsetX, e.offsetY), this.emit('mouseup', ...this.layout.screenToGrid(e.offsetX, e.offsetY),
e.button + 1) e.button + 1)
} }
}) })
@ -200,12 +222,12 @@ module.exports = class TermScreen extends EventEmitter {
if (this.mouseMode.clicks) { if (this.mouseMode.clicks) {
if (Math.abs(e.wheelDeltaY) === 120) { if (Math.abs(e.wheelDeltaY) === 120) {
// mouse wheel scrolling // mouse wheel scrolling
this.emit('mousewheel', ...this.screenToGrid(e.offsetX, e.offsetY), e.deltaY > 0 ? 1 : -1) this.emit('mousewheel', ...this.layout.screenToGrid(e.offsetX, e.offsetY), e.deltaY > 0 ? 1 : -1)
} else { } else {
// smooth scrolling // smooth scrolling
aggregateWheelDelta -= e.wheelDeltaY aggregateWheelDelta -= e.wheelDeltaY
if (Math.abs(aggregateWheelDelta) >= 40) { if (Math.abs(aggregateWheelDelta) >= 40) {
this.emit('mousewheel', ...this.screenToGrid(e.offsetX, e.offsetY), aggregateWheelDelta > 0 ? 1 : -1) this.emit('mousewheel', ...this.layout.screenToGrid(e.offsetX, e.offsetY), aggregateWheelDelta > 0 ? 1 : -1)
aggregateWheelDelta = 0 aggregateWheelDelta = 0
} }
} }
@ -233,6 +255,24 @@ module.exports = class TermScreen extends EventEmitter {
this.screen.screenAttrs = new Array(width * height).fill(0) this.screen.screenAttrs = new Array(width * height).fill(0)
} }
updateLayout () {
this.layout.window.width = this.window.width
this.layout.window.height = this.window.height
}
renderScreen () {
this.layout.render({
width: this.window.width,
height: this.window.height,
screen: this.screen,
screenFG: this.screenFG,
screenBG: this.screenBG,
screenAttrs: this.screenAttrs,
cursor: this.cursor,
statusScreen: this.window.statusScreen
})
}
/** /**
* Returns a normalized version of the current selection, such that `start` * Returns a normalized version of the current selection, such that `start`
* is always before `end`. * is always before `end`.
@ -399,8 +439,8 @@ module.exports = class TermScreen extends EventEmitter {
this.window.height = update.height this.window.height = update.height
this.resetScreen() this.resetScreen()
} }
this.renderer.loadTheme(update.theme) this.layout.renderer.loadTheme(update.theme)
this.renderer.setDefaultColors(update.defFG, update.defBG) this.layout.renderer.setDefaultColors(update.defFG, update.defBG)
this.cursor.visible = update.cursorVisible this.cursor.visible = update.cursorVisible
this.emit('input-alts', ...update.inputAlts) this.emit('input-alts', ...update.inputAlts)
this.mouseMode.clicks = update.trackMouseClicks this.mouseMode.clicks = update.trackMouseClicks
@ -409,7 +449,7 @@ module.exports = class TermScreen extends EventEmitter {
this.selection.setSelectable(!update.trackMouseClicks && !update.trackMouseMovement) this.selection.setSelectable(!update.trackMouseClicks && !update.trackMouseMovement)
if (this.cursor.blinking !== update.cursorBlinking) { if (this.cursor.blinking !== update.cursorBlinking) {
this.cursor.blinking = update.cursorBlinking this.cursor.blinking = update.cursorBlinking
this.renderer.resetCursorBlink() this.layout.renderer.resetCursorBlink()
} }
this.cursor.style = update.cursorStyle this.cursor.style = update.cursorStyle
this.bracketedPaste = update.bracketedPaste this.bracketedPaste = update.bracketedPaste
@ -426,9 +466,9 @@ module.exports = class TermScreen extends EventEmitter {
this.cursor.x = update.x this.cursor.x = update.x
this.cursor.y = update.y this.cursor.y = update.y
this.cursor.hanging = update.hanging this.cursor.hanging = update.hanging
this.renderer.resetCursorBlink() this.layout.renderer.resetCursorBlink()
this.emit('cursor-moved') this.emit('cursor-moved')
this.renderer.scheduleDraw('cursor-moved') this.layout.renderer.scheduleDraw('cursor-moved')
} }
break break
@ -479,7 +519,7 @@ module.exports = class TermScreen extends EventEmitter {
if (this.window.debug) console.log(`Blinking cells: ${this.blinkingCellCount}`) if (this.window.debug) console.log(`Blinking cells: ${this.blinkingCellCount}`)
this.renderer.scheduleDraw('load', 16) this.layout.renderer.scheduleDraw('load', 16)
this.emit('load') this.emit('load')
break break

@ -9,8 +9,7 @@ module.exports = class ScreenLayout extends EventEmitter {
super() super()
this.canvas = document.createElement('canvas') this.canvas = document.createElement('canvas')
this.renderer = new CanvasRenderer(this.canvas)
this.renderer = new CanvasRenderer(this.canvas.getContext('2d'))
this._window = { this._window = {
width: 0, width: 0,
@ -23,10 +22,7 @@ module.exports = class ScreenLayout extends EventEmitter {
gridScaleY: 1.2, gridScaleY: 1.2,
fitIntoWidth: 0, fitIntoWidth: 0,
fitIntoHeight: 0, fitIntoHeight: 0,
// two bits. LSB: debug enabled by user, MSB: debug enabled by server graphics: 0
debug: 0,
graphics: 0,
statusScreen: null
} }
// scaling caused by fitIntoWidth/fitIntoHeight // scaling caused by fitIntoWidth/fitIntoHeight
@ -46,7 +42,8 @@ module.exports = class ScreenLayout extends EventEmitter {
fontFamily: '', fontFamily: '',
fontSize: 0, fontSize: 0,
fitIntoWidth: 0, fitIntoWidth: 0,
fitIntoHeight: 0 fitIntoHeight: 0,
debug: false
} }
this.charSize = { width: 0, height: 0 } this.charSize = { width: 0, height: 0 }
@ -55,7 +52,7 @@ module.exports = class ScreenLayout extends EventEmitter {
// make writing to window update size and draw // make writing to window update size and draw
this.window = new Proxy(this._window, { this.window = new Proxy(this._window, {
set (target, key, value, receiver) { set (target, key, value) {
if (target[key] !== value) { if (target[key] !== value) {
target[key] = value target[key] = value
self.scheduleSizeUpdate() self.scheduleSizeUpdate()
@ -66,6 +63,8 @@ module.exports = class ScreenLayout extends EventEmitter {
} }
}) })
this.on('update-window:debug', debug => { this.renderer.debug = debug })
this.canvas.addEventListener('mousedown', e => this.emit('mousedown', e)) this.canvas.addEventListener('mousedown', e => this.emit('mousedown', e))
this.canvas.addEventListener('mousemove', e => this.emit('mousemove', e)) this.canvas.addEventListener('mousemove', e => this.emit('mousemove', e))
this.canvas.addEventListener('mouseup', e => this.emit('mouseup', e)) this.canvas.addEventListener('mouseup', e => this.emit('mouseup', e))
@ -159,10 +158,8 @@ module.exports = class ScreenLayout extends EventEmitter {
* @returns {Object} the character size with `width` and `height` in pixels * @returns {Object} the character size with `width` and `height` in pixels
*/ */
updateCharSize () { updateCharSize () {
this.ctx.font = this.getFont()
this.charSize = { this.charSize = {
width: Math.floor(this.ctx.measureText(' ').width), width: this.renderer.getCharWidthFor(this.getFont()),
height: this.window.fontSize height: this.window.fontSize
} }
@ -251,4 +248,8 @@ module.exports = class ScreenLayout extends EventEmitter {
this.renderer.draw('update-size') this.renderer.draw('update-size')
} }
} }
render (...args) {
this.renderer.render(...args)
}
} }

@ -1,3 +1,4 @@
const EventEmitter = require('events')
const { const {
themes, themes,
buildColorTable, buildColorTable,
@ -30,9 +31,12 @@ const frakturExceptions = {
/** /**
* A terminal screen renderer, using canvas 2D * A terminal screen renderer, using canvas 2D
*/ */
module.exports = class CanvasRenderer { module.exports = class CanvasRenderer extends EventEmitter {
constructor (context) { constructor (canvas) {
this.ctx = context super()
this.canvas = canvas
this.ctx = this.canvas.getContext('2d')
this._palette = null // colors 0-15 this._palette = null // colors 0-15
this.defaultBgNum = 0 this.defaultBgNum = 0
@ -42,6 +46,21 @@ module.exports = class CanvasRenderer {
// should not be used to look up 0-15 (will return transparent) // should not be used to look up 0-15 (will return transparent)
this.colorTable256 = buildColorTable() this.colorTable256 = buildColorTable()
this.debug = false
// screen data, considered immutable
this.width = 0
this.height = 0
this.padding = 0
this.charSize = { width: 0, height: 0 }
this.cellSize = { width: 0, height: 0 }
this.fonts = ['', '', '', ''] // normal, bold, italic, bold-italic
this.screen = []
this.screenFG = []
this.screenBG = []
this.screenAttrs = []
this.cursor = {}
this.resetDrawn() this.resetDrawn()
this.blinkStyleOn = false this.blinkStyleOn = false
@ -57,9 +76,8 @@ module.exports = class CanvasRenderer {
resetDrawn () { resetDrawn () {
// used to determine if a cell should be redrawn; storing the current state // used to determine if a cell should be redrawn; storing the current state
// as it is on screen // as it is on screen
if (this.screen.window && this.screen.window.debug) { if (this.debug) console.log('Resetting drawn screen')
console.log('Resetting drawn screen')
}
this.drawnScreen = [] this.drawnScreen = []
this.drawnScreenFG = [] this.drawnScreenFG = []
this.drawnScreenBG = [] this.drawnScreenBG = []
@ -84,6 +102,11 @@ module.exports = class CanvasRenderer {
} }
} }
getCharWidthFor (font) {
this.ctx.font = font
return Math.floor(this.ctx.measureText(' ').width)
}
loadTheme (i) { loadTheme (i) {
if (i in themes) this.palette = themes[i] if (i in themes) this.palette = themes[i]
} }
@ -96,7 +119,7 @@ module.exports = class CanvasRenderer {
this.scheduleDraw('default-colors') this.scheduleDraw('default-colors')
// full bg with default color (goes behind the image) // full bg with default color (goes behind the image)
this.screen.canvas.style.backgroundColor = this.getColor(bg) this.canvas.style.backgroundColor = this.getColor(bg)
} }
} }
@ -130,10 +153,8 @@ module.exports = class CanvasRenderer {
this.cursorBlinkOn = true this.cursorBlinkOn = true
clearInterval(this.cursorBlinkInterval) clearInterval(this.cursorBlinkInterval)
this.cursorBlinkInterval = setInterval(() => { this.cursorBlinkInterval = setInterval(() => {
this.cursorBlinkOn = this.screen.cursor.blinking this.cursorBlinkOn = this.cursor.blinking ? !this.cursorBlinkOn : true
? !this.cursorBlinkOn if (this.cursor.blinking) this.scheduleDraw('cursor-blink')
: true
if (this.screen.cursor.blinking) this.scheduleDraw('cursor-blink')
}, 500) }, 500)
} }
@ -145,7 +166,7 @@ module.exports = class CanvasRenderer {
clearInterval(this.blinkInterval) clearInterval(this.blinkInterval)
let intervals = 0 let intervals = 0
this.blinkInterval = setInterval(() => { this.blinkInterval = setInterval(() => {
if (this.screen.blinkingCellCount <= 0) return if (this.blinkingCellCount <= 0) return
intervals++ intervals++
if (intervals >= 4 && this.blinkStyleOn) { if (intervals >= 4 && this.blinkStyleOn) {
@ -171,9 +192,8 @@ module.exports = class CanvasRenderer {
* @param {number} options.isDefaultBG - if true, will draw image background if available * @param {number} options.isDefaultBG - if true, will draw image background if available
*/ */
drawBackground ({ x, y, cellWidth, cellHeight, bg, isDefaultBG }) { drawBackground ({ x, y, cellWidth, cellHeight, bg, isDefaultBG }) {
const ctx = this.ctx const { ctx, width, height, padding } = this
const { width, height } = this.screen.window
const padding = Math.round(this.screen._padding)
ctx.fillStyle = this.getColor(bg) ctx.fillStyle = this.getColor(bg)
let screenX = x * cellWidth + padding let screenX = x * cellWidth + padding
let screenY = y * cellHeight + padding let screenY = y * cellHeight + padding
@ -225,8 +245,7 @@ module.exports = class CanvasRenderer {
drawCharacter ({ x, y, charSize, cellWidth, cellHeight, text, fg, attrs }) { drawCharacter ({ x, y, charSize, cellWidth, cellHeight, text, fg, attrs }) {
if (!text) return if (!text) return
const ctx = this.ctx const { ctx, padding } = this
const padding = Math.round(this.screen._padding)
let underline = false let underline = false
let strike = false let strike = false
@ -426,7 +445,7 @@ module.exports = class CanvasRenderer {
* @returns {number[]} an array of cell indices * @returns {number[]} an array of cell indices
*/ */
getAdjacentCells (cell, radius = 1) { getAdjacentCells (cell, radius = 1) {
const { width, height } = this.screen.window const { width, height } = this
const screenLength = width * height const screenLength = width * height
let cells = [] let cells = []
@ -452,7 +471,7 @@ module.exports = class CanvasRenderer {
height, height,
devicePixelRatio, devicePixelRatio,
statusScreen statusScreen
} = this.screen.window } = this
if (statusScreen) { if (statusScreen) {
// draw status screen instead // draw status screen instead
@ -461,15 +480,15 @@ module.exports = class CanvasRenderer {
return return
} else this.stopDrawLoop() } else this.stopDrawLoop()
const charSize = this.screen.getCharSize() const charSize = this.charSize
const { width: cellWidth, height: cellHeight } = this.screen.getCellSize() const { width: cellWidth, height: cellHeight } = this.cellSize
const screenLength = width * height const screenLength = width * height
ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0) ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0)
if (this.screen.window.debug && this.screen._debug) this.screen._debug.drawStart(why) // if (this.debug) this.screen._debug.drawStart(why)
ctx.font = this.screen.getFont() ctx.font = this.fonts[0]
ctx.textAlign = 'center' ctx.textAlign = 'center'
ctx.textBaseline = 'middle' ctx.textBaseline = 'middle'
@ -486,18 +505,18 @@ module.exports = class CanvasRenderer {
let x = cell % width let x = cell % width
let y = Math.floor(cell / width) let y = Math.floor(cell / width)
let isCursor = this.cursorBlinkOn && let isCursor = this.cursorBlinkOn &&
this.screen.cursor.x === x && this.cursor.x === x &&
this.screen.cursor.y === y && this.cursor.y === y &&
this.screen.cursor.visible this.cursor.visible
let wasCursor = x === this.drawnCursor[0] && y === this.drawnCursor[1] let wasCursor = x === this.drawnCursor[0] && y === this.drawnCursor[1]
let inSelection = this.screen.isInSelection(x, y) let inSelection = this.screen.isInSelection(x, y)
let text = this.screen.screen[cell] let text = this.screen[cell]
let fg = this.screen.screenFG[cell] | 0 let fg = this.screenFG[cell] | 0
let bg = this.screen.screenBG[cell] | 0 let bg = this.screenBG[cell] | 0
let attrs = this.screen.screenAttrs[cell] | 0 let attrs = this.screenAttrs[cell] | 0
let isDefaultBG = false let isDefaultBG = false
@ -526,8 +545,8 @@ module.exports = class CanvasRenderer {
bg !== this.drawnScreenBG[cell] || // background updated bg !== this.drawnScreenBG[cell] || // background updated
attrs !== this.drawnScreenAttrs[cell] || // attributes updated attrs !== this.drawnScreenAttrs[cell] || // attributes updated
isCursor !== wasCursor || // cursor blink/position updated isCursor !== wasCursor || // cursor blink/position updated
(isCursor && this.screen.cursor.style !== this.drawnCursor[2]) || // cursor style updated (isCursor && this.cursor.style !== this.drawnCursor[2]) || // cursor style updated
(isCursor && this.screen.cursor.hanging !== this.drawnCursor[3]) // cursor hanging updated (isCursor && this.cursor.hanging !== this.drawnCursor[3]) // cursor hanging updated
let font = attrs & FONT_MASK let font = attrs & FONT_MASK
if (!fontGroups.has(font)) fontGroups.set(font, []) if (!fontGroups.has(font)) fontGroups.set(font, [])
@ -547,7 +566,7 @@ module.exports = class CanvasRenderer {
let shouldUpdate = updateMap.get(cell) || redrawMap.get(cell) || false let shouldUpdate = updateMap.get(cell) || redrawMap.get(cell) || false
// TODO: fonts (necessary?) // TODO: fonts (necessary?)
let text = this.screen.screen[cell] let text = this.screen[cell]
let isWideCell = isTextWide(text) let isWideCell = isTextWide(text)
let checkRadius = isWideCell ? 2 : 1 let checkRadius = isWideCell ? 2 : 1
@ -559,7 +578,7 @@ module.exports = class CanvasRenderer {
// update this cell if: // update this cell if:
// - the adjacent cell updated (For now, this'll always be true because characters can be slightly larger than they say they are) // - the adjacent cell updated (For now, this'll always be true because characters can be slightly larger than they say they are)
// - the adjacent cell updated and this cell or the adjacent cell is wide // - the adjacent cell updated and this cell or the adjacent cell is wide
if (updateMap.get(adjacentCell) && (this.screen.window.graphics < 2 || isWideCell || isTextWide(this.screen.screen[adjacentCell]))) { if (updateMap.get(adjacentCell) && (this.graphics < 2 || isWideCell || isTextWide(this.screen[adjacentCell]))) {
adjacentDidUpdate = true adjacentDidUpdate = true
break break
} }
@ -574,9 +593,10 @@ module.exports = class CanvasRenderer {
for (let cell of updateMap.keys()) updateRedrawMapAt(cell) for (let cell of updateMap.keys()) updateRedrawMapAt(cell)
// mask to redrawing regions only // mask to redrawing regions only
if (this.screen.window.graphics >= 1) { if (this.graphics >= 1) {
let debug = this.screen.window.debug && this.screen._debug // TODO: include padding in border cells
let padding = Math.round(this.screen._padding) const padding = this.padding
ctx.save() ctx.save()
ctx.beginPath() ctx.beginPath()
for (let y = 0; y < height; y++) { for (let y = 0; y < height; y++) {
@ -587,13 +607,13 @@ module.exports = class CanvasRenderer {
if (redrawing && regionStart === null) regionStart = x if (redrawing && regionStart === null) regionStart = x
if (!redrawing && regionStart !== null) { if (!redrawing && regionStart !== null) {
ctx.rect(padding + regionStart * cellWidth, padding + y * cellHeight, (x - regionStart) * cellWidth, cellHeight) ctx.rect(padding + regionStart * cellWidth, padding + y * cellHeight, (x - regionStart) * cellWidth, cellHeight)
if (debug) this.screen._debug.clipRect(regionStart * cellWidth, y * cellHeight, (x - regionStart) * cellWidth, cellHeight) // if (this.debug) this.screen._debug.clipRect(regionStart * cellWidth, y * cellHeight, (x - regionStart) * cellWidth, cellHeight)
regionStart = null regionStart = null
} }
} }
if (regionStart !== null) { if (regionStart !== null) {
ctx.rect(padding + regionStart * cellWidth, padding + y * cellHeight, (width - regionStart) * cellWidth, cellHeight) ctx.rect(padding + regionStart * cellWidth, padding + y * cellHeight, (width - regionStart) * cellWidth, cellHeight)
if (debug) this.screen._debug.clipRect(regionStart * cellWidth, y * cellHeight, (width - regionStart) * cellWidth, cellHeight) // if (this.debug) this.screen._debug.clipRect(regionStart * cellWidth, y * cellHeight, (width - regionStart) * cellWidth, cellHeight)
} }
} }
ctx.clip() ctx.clip()
@ -607,12 +627,12 @@ module.exports = class CanvasRenderer {
if (redrawMap.get(cell)) { if (redrawMap.get(cell)) {
this.drawBackground({ x, y, cellWidth, cellHeight, bg, isDefaultBG }) this.drawBackground({ x, y, cellWidth, cellHeight, bg, isDefaultBG })
if (this.screen.window.debug && this.screen._debug) { if (this.debug) {
// set cell flags // set cell flags
let flags = (+redrawMap.get(cell)) let flags = (+redrawMap.get(cell))
flags |= (+updateMap.get(cell)) << 1 flags |= (+updateMap.get(cell)) << 1
flags |= (+isTextWide(text)) << 2 flags |= (+isTextWide(text)) << 2
this.screen._debug.setCell(cell, flags) // this.screen._debug.setCell(cell, flags)
} }
} }
} }
@ -625,10 +645,10 @@ module.exports = class CanvasRenderer {
for (let font of fontGroups.keys()) { for (let font of fontGroups.keys()) {
// set font once because in Firefox, this is a really slow action for some // set font once because in Firefox, this is a really slow action for some
// reason // reason
let modifiers = {} let fontIndex = 0
if (font & ATTR_BOLD) modifiers.weight = 'bold' if (font & ATTR_BOLD) fontIndex |= 1
if (font & ATTR_ITALIC) modifiers.style = 'italic' if (font & ATTR_ITALIC) fontIndex |= 2
ctx.font = this.screen.getFont(modifiers) ctx.font = this.fonts[fontIndex]
for (let data of fontGroups.get(font)) { for (let data of fontGroups.get(font)) {
let { cell, x, y, text, fg, bg, attrs, isCursor, inSelection } = data let { cell, x, y, text, fg, bg, attrs, isCursor, inSelection } = data
@ -643,7 +663,7 @@ module.exports = class CanvasRenderer {
this.drawnScreenBG[cell] = bg this.drawnScreenBG[cell] = bg
this.drawnScreenAttrs[cell] = attrs this.drawnScreenAttrs[cell] = attrs
if (isCursor) this.drawnCursor = [x, y, this.screen.cursor.style, this.screen.cursor.hanging] if (isCursor) this.drawnCursor = [x, y, this.cursor.style, this.cursor.hanging]
// draw cursor // draw cursor
if (isCursor && !inSelection) { if (isCursor && !inSelection) {
@ -653,21 +673,21 @@ module.exports = class CanvasRenderer {
let cursorX = x let cursorX = x
let cursorY = y let cursorY = y
if (this.screen.cursor.hanging) { if (this.cursor.hanging) {
// draw hanging cursor in the margin // draw hanging cursor in the margin
cursorX += 1 cursorX += 1
} }
let screenX = cursorX * cellWidth + this.screen._padding let screenX = cursorX * cellWidth + this.padding
let screenY = cursorY * cellHeight + this.screen._padding let screenY = cursorY * cellHeight + this.padding
if (this.screen.cursor.style === 'block') { if (this.cursor.style === 'block') {
// block // block
ctx.rect(screenX, screenY, cellWidth, cellHeight) ctx.rect(screenX, screenY, cellWidth, cellHeight)
} else if (this.screen.cursor.style === 'bar') { } else if (this.cursor.style === 'bar') {
// vertical bar // vertical bar
let barWidth = 2 let barWidth = 2
ctx.rect(screenX, screenY, barWidth, cellHeight) ctx.rect(screenX, screenY, barWidth, cellHeight)
} else if (this.screen.cursor.style === 'line') { } else if (this.cursor.style === 'line') {
// underline // underline
let lineHeight = 2 let lineHeight = 2
ctx.rect(screenX, screenY + charSize.height, cellWidth, lineHeight) ctx.rect(screenX, screenY + charSize.height, cellWidth, lineHeight)
@ -690,34 +710,28 @@ module.exports = class CanvasRenderer {
} }
} }
if (this.screen.window.graphics >= 1) ctx.restore() if (this.graphics >= 1) ctx.restore()
if (this.screen.window.debug && this.screen._debug) this.screen._debug.drawEnd() // if (this.debug) this.screen._debug.drawEnd()
this.screen.emit('draw', why) this.emit('draw', why)
} }
drawStatus (statusScreen) { drawStatus (statusScreen) {
const ctx = this.ctx const { ctx, width, height, devicePixelRatio } = this
const {
fontFamily,
width,
height,
devicePixelRatio
} = this.screen.window
// reset drawnScreen to force redraw when statusScreen is disabled // reset drawnScreen to force redraw when statusScreen is disabled
this.drawnScreen = [] this.drawnScreen = []
const cellSize = this.screen.getCellSize() const cellSize = this.cellSize
const screenWidth = width * cellSize.width + 2 * this.screen._padding const screenWidth = width * cellSize.width + 2 * this.padding
const screenHeight = height * cellSize.height + 2 * this.screen._padding const screenHeight = height * cellSize.height + 2 * this.padding
ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0) ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0)
ctx.fillStyle = this.getColor(this.defaultBgNum) ctx.fillStyle = this.getColor(this.defaultBgNum)
ctx.fillRect(0, 0, screenWidth, screenHeight) ctx.fillRect(0, 0, screenWidth, screenHeight)
ctx.font = `24px ${fontFamily}` ctx.font = `24px ${this.statusFont}`
ctx.fillStyle = this.getColor(this.defaultFgNum) ctx.fillStyle = this.getColor(this.defaultFgNum)
ctx.textAlign = 'center' ctx.textAlign = 'center'
ctx.textBaseline = 'middle' ctx.textBaseline = 'middle'

Loading…
Cancel
Save