diff --git a/src/Terminal.ts b/src/Terminal.ts index 86c18a41..594a6fb2 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -752,9 +752,9 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT this.on('resize', () => this.renderer.onResize(this.cols, this.rows)); this.charMeasure.on('charsizechanged', () => this.renderer.onCharSizeChanged(this.charMeasure.width, this.charMeasure.height)); this.selectionManager = new SelectionManager(this, this.buffer, this.rowContainer, this.charMeasure); - this.selectionManager.on('refresh', data => { - this.renderer.refreshSelection(data.start, data.end); - }); + // this.selectionManager.on('refresh', data => { + // this.renderer.refreshSelection(data.start, data.end); + // }); this.selectionManager.on('newselection', text => { // If there's a new selection, put it into the textarea, focus and select it // in order to register it as a selection on the OS. This event is fired diff --git a/src/renderer/BackgroundRenderLayer.ts b/src/renderer/BackgroundRenderLayer.ts index ea7bea60..dac476a0 100644 --- a/src/renderer/BackgroundRenderLayer.ts +++ b/src/renderer/BackgroundRenderLayer.ts @@ -39,7 +39,6 @@ export class BackgroundRenderLayer implements IRenderLayer { let bg = attr & 0x1ff; const flags = attr >> 18; - // If inverse flag is on, the background should become the foreground. if (flags & FLAGS.INVERSE) { bg = (attr >> 9) & 0x1ff; diff --git a/src/renderer/ForegroundRenderLayer.ts b/src/renderer/ForegroundRenderLayer.ts index 05cceb47..2b1ff272 100644 --- a/src/renderer/ForegroundRenderLayer.ts +++ b/src/renderer/ForegroundRenderLayer.ts @@ -55,6 +55,7 @@ export class ForegroundRenderLayer implements IRenderLayer { for (let y = startRow; y <= endRow; y++) { let row = y + terminal.buffer.ydisp; let line = terminal.buffer.lines.get(row); + for (let x = 0; x < terminal.cols; x++) { const charData = line[x]; const code: number = charData[CHAR_DATA_CODE_INDEX]; diff --git a/src/renderer/SelectionRenderLayer.ts b/src/renderer/SelectionRenderLayer.ts new file mode 100644 index 00000000..bc31022c --- /dev/null +++ b/src/renderer/SelectionRenderLayer.ts @@ -0,0 +1,83 @@ +import { IRenderLayer } from './Interfaces'; +import { IBuffer, ICharMeasure, ITerminal } from '../Interfaces'; +import { CHAR_DATA_ATTR_INDEX } from '../Buffer'; +import { TANGO_COLORS } from './Color'; +import { GridCache } from './GridCache'; +import { FLAGS } from './Types'; + +export class BackgroundRenderLayer implements IRenderLayer { + private _canvas: HTMLCanvasElement; + private _ctx: CanvasRenderingContext2D; + private _state: {start: [number, number], end: [number, number]}; + + constructor(container: HTMLElement) { + this._canvas = document.createElement('canvas'); + this._canvas.classList.add('xterm-bg-layer'); + this._ctx = this._canvas.getContext('2d'); + this._ctx.scale(window.devicePixelRatio, window.devicePixelRatio); + this._ctx.fillStyle = 'rgba(255, 255, 255, 0.5)'; + container.appendChild(this._canvas); + this._state = { + start: null, + end: null + }; + } + + public resize(terminal: ITerminal, canvasWidth: number, canvasHeight: number, charSizeChanged: boolean): void { + this._canvas.width = canvasWidth * window.devicePixelRatio; + this._canvas.height = canvasHeight * window.devicePixelRatio; + this._canvas.style.width = `${canvasWidth}px`; + this._canvas.style.height = `${canvasHeight}px`; + } + + public render(terminal: ITerminal, startRow: number, endRow: number): void { + const scaledCharWidth = Math.ceil(terminal.charMeasure.width) * window.devicePixelRatio; + const scaledCharHeight = Math.ceil(terminal.charMeasure.height) * window.devicePixelRatio; + + const start = terminal.selectionManager.selectionStart; + const end = terminal.selectionManager.selectionEnd; + + // TODO: Need to redraw selection if the viewport has moved + + // Selection has not changed + if (this._state.start === start || this._state.end === end) { + return; + } + + // Remove all selections + this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height); + + // Selection does not exist + if (!start || !end) { + return; + } + + // Translate from buffer position to viewport position + const viewportStartRow = start[1] - terminal.buffer.ydisp; + const viewportEndRow = end[1] - terminal.buffer.ydisp; + const viewportCappedStartRow = Math.max(viewportStartRow, 0); + const viewportCappedEndRow = Math.min(viewportEndRow, terminal.rows - 1); + + // No need to draw the selection + if (viewportCappedStartRow >= terminal.rows || viewportCappedEndRow < 0) { + return; + } + + // Create the selections + // Draw first row + const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0; + const endCol = viewportCappedStartRow === viewportCappedEndRow ? end[0] : terminal.cols; + this._ctx.fillRect(startCol * scaledCharWidth, viewportCappedStartRow * scaledCharHeight, (endCol - startCol) * scaledCharWidth, scaledCharHeight); + // documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow, startCol, endCol)); + // Draw middle rows + // const middleRowsCount = viewportCappedEndRow - viewportCappedStartRow - 1; + // documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow + 1, 0, this._terminal.cols, middleRowsCount)); + // // Draw final row + // if (viewportCappedStartRow !== viewportCappedEndRow) { + // // Only draw viewportEndRow if it's not the same as viewporttartRow + // const endCol = viewportEndRow === viewportCappedEndRow ? end[0] : this._terminal.cols; + // documentFragment.appendChild(this._createSelectionElement(viewportCappedEndRow, 0, endCol)); + // } + // this._terminal.selectionContainer.appendChild(documentFragment); + } +} diff --git a/src/renderer/Types.ts b/src/renderer/Types.ts index 09e74439..621db0bd 100644 --- a/src/renderer/Types.ts +++ b/src/renderer/Types.ts @@ -8,3 +8,8 @@ export enum FLAGS { INVERSE = 8, INVISIBLE = 16 }; + +export type Point = { + x: number, + y: number +};