Share selection render model code
This commit is contained in:
@@ -9,6 +9,7 @@ import { TEXT_BASELINE } from 'browser/renderer/shared/Constants';
|
|||||||
import { tryDrawCustomChar } from 'browser/renderer/shared/CustomGlyphs';
|
import { tryDrawCustomChar } from 'browser/renderer/shared/CustomGlyphs';
|
||||||
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
||||||
import { IRasterizedGlyph, IRenderDimensions, ISelectionRenderModel, ITextureAtlas } from 'browser/renderer/shared/Types';
|
import { IRasterizedGlyph, IRenderDimensions, ISelectionRenderModel, ITextureAtlas } from 'browser/renderer/shared/Types';
|
||||||
|
import { createSelectionRenderModel } from 'browser/renderer/shared/SelectionRenderModel';
|
||||||
import { ICoreBrowserService } from 'browser/services/Services';
|
import { ICoreBrowserService } from 'browser/services/Services';
|
||||||
import { IColorSet } from 'browser/Types';
|
import { IColorSet } from 'browser/Types';
|
||||||
import { CellData } from 'common/buffer/CellData';
|
import { CellData } from 'common/buffer/CellData';
|
||||||
@@ -16,7 +17,6 @@ import { Attributes, BgFlags, FgFlags, WHITESPACE_CELL_CODE } from 'common/buffe
|
|||||||
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
|
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
|
||||||
import { ICellData } from 'common/Types';
|
import { ICellData } from 'common/Types';
|
||||||
import { Terminal } from 'xterm';
|
import { Terminal } from 'xterm';
|
||||||
import { IGlyphIdentifier } from './atlas/Types';
|
|
||||||
import { IRenderLayer } from './Types';
|
import { IRenderLayer } from './Types';
|
||||||
|
|
||||||
// Work variables to avoid garbage collection
|
// Work variables to avoid garbage collection
|
||||||
@@ -39,16 +39,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
|||||||
protected _selectionStart: [number, number] | undefined;
|
protected _selectionStart: [number, number] | undefined;
|
||||||
protected _selectionEnd: [number, number] | undefined;
|
protected _selectionEnd: [number, number] | undefined;
|
||||||
protected _columnSelectMode: boolean = false;
|
protected _columnSelectMode: boolean = false;
|
||||||
protected _selectionModel: ISelectionRenderModel = {
|
protected _selectionModel: ISelectionRenderModel = createSelectionRenderModel();
|
||||||
hasSelection: false,
|
|
||||||
columnSelectMode: false,
|
|
||||||
viewportStartRow: 0,
|
|
||||||
viewportEndRow: 0,
|
|
||||||
viewportCappedStartRow: 0,
|
|
||||||
viewportCappedEndRow: 0,
|
|
||||||
startCol: 0,
|
|
||||||
endCol: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
protected _charAtlas!: ITextureAtlas;
|
protected _charAtlas!: ITextureAtlas;
|
||||||
|
|
||||||
@@ -99,7 +90,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
|||||||
this._selectionStart = start;
|
this._selectionStart = start;
|
||||||
this._selectionEnd = end;
|
this._selectionEnd = end;
|
||||||
this._columnSelectMode = columnSelectMode;
|
this._columnSelectMode = columnSelectMode;
|
||||||
this._updateSelectionModel(start, end, columnSelectMode);
|
this._selectionModel.update(this._terminal, start, end, columnSelectMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setColors(colorSet: IColorSet): void {
|
public setColors(colorSet: IColorSet): void {
|
||||||
@@ -430,9 +421,8 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Selection?
|
|
||||||
// Apply the selection color if needed
|
// Apply the selection color if needed
|
||||||
$isSelected = this._isCellSelected(x, y);
|
$isSelected = this._selectionModel.isCellSelected(this._terminal, x, y);
|
||||||
if ($isSelected) {
|
if ($isSelected) {
|
||||||
$bg = (this._coreBrowserService.isFocused ? this._colors.selectionBackgroundOpaque : this._colors.selectionInactiveBackgroundOpaque).rgba >> 8 & 0xFFFFFF;
|
$bg = (this._coreBrowserService.isFocused ? this._colors.selectionBackgroundOpaque : this._colors.selectionInactiveBackgroundOpaque).rgba >> 8 & 0xFFFFFF;
|
||||||
$hasBg = true;
|
$hasBg = true;
|
||||||
@@ -498,66 +488,6 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
|||||||
workColors.fg = $hasFg ? $fg : workColors.fg;
|
workColors.fg = $hasFg ? $fg : workColors.fg;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _isCellSelected(x: number, y: number): boolean {
|
|
||||||
if (!this._selectionStart) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
y -= this._terminal.buffer.active.viewportY;
|
|
||||||
if (this._selectionModel.columnSelectMode) {
|
|
||||||
if (this._selectionModel.startCol <= this._selectionModel.endCol) {
|
|
||||||
return x >= this._selectionModel.startCol && y >= this._selectionModel.viewportCappedStartRow &&
|
|
||||||
x < this._selectionModel.endCol && y <= this._selectionModel.viewportCappedEndRow;
|
|
||||||
}
|
|
||||||
return x < this._selectionModel.startCol && y >= this._selectionModel.viewportCappedStartRow &&
|
|
||||||
x >= this._selectionModel.endCol && y <= this._selectionModel.viewportCappedEndRow;
|
|
||||||
}
|
|
||||||
return (y > this._selectionModel.viewportStartRow && y < this._selectionModel.viewportEndRow) ||
|
|
||||||
(this._selectionModel.viewportStartRow === this._selectionModel.viewportEndRow && y === this._selectionModel.viewportStartRow && x >= this._selectionModel.startCol && x < this._selectionModel.endCol) ||
|
|
||||||
(this._selectionModel.viewportStartRow < this._selectionModel.viewportEndRow && y === this._selectionModel.viewportEndRow && x < this._selectionModel.endCol) ||
|
|
||||||
(this._selectionModel.viewportStartRow < this._selectionModel.viewportEndRow && y === this._selectionModel.viewportStartRow && x >= this._selectionModel.startCol);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _updateSelectionModel(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean = false): void {
|
|
||||||
const terminal = this._terminal;
|
|
||||||
|
|
||||||
// Selection does not exist
|
|
||||||
if (!start || !end || (start[0] === end[0] && start[1] === end[1])) {
|
|
||||||
this._clearSelectionMoidel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translate from buffer position to viewport position
|
|
||||||
const viewportStartRow = start[1] - terminal.buffer.active.viewportY;
|
|
||||||
const viewportEndRow = end[1] - terminal.buffer.active.viewportY;
|
|
||||||
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) {
|
|
||||||
this._clearSelectionMoidel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._selectionModel.hasSelection = true;
|
|
||||||
this._selectionModel.columnSelectMode = columnSelectMode;
|
|
||||||
this._selectionModel.viewportStartRow = viewportStartRow;
|
|
||||||
this._selectionModel.viewportEndRow = viewportEndRow;
|
|
||||||
this._selectionModel.viewportCappedStartRow = viewportCappedStartRow;
|
|
||||||
this._selectionModel.viewportCappedEndRow = viewportCappedEndRow;
|
|
||||||
this._selectionModel.startCol = start[0];
|
|
||||||
this._selectionModel.endCol = end[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
private _clearSelectionMoidel(): void {
|
|
||||||
this._selectionModel.hasSelection = false;
|
|
||||||
this._selectionModel.viewportStartRow = 0;
|
|
||||||
this._selectionModel.viewportEndRow = 0;
|
|
||||||
this._selectionModel.viewportCappedStartRow = 0;
|
|
||||||
this._selectionModel.viewportCappedEndRow = 0;
|
|
||||||
this._selectionModel.startCol = 0;
|
|
||||||
this._selectionModel.endCol = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clips a row to ensure no pixels will be drawn outside the cells in the row.
|
* Clips a row to ensure no pixels will be drawn outside the cells in the row.
|
||||||
* @param y The row to clip.
|
* @param y The row to clip.
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
import { IRenderModel } from './Types';
|
import { IRenderModel } from './Types';
|
||||||
import { fill } from 'common/TypedArrayUtils';
|
import { fill } from 'common/TypedArrayUtils';
|
||||||
import { ISelectionRenderModel } from 'browser/renderer/shared/Types';
|
import { ISelectionRenderModel } from 'browser/renderer/shared/Types';
|
||||||
|
import { createSelectionRenderModel } from 'browser/renderer/shared/SelectionRenderModel';
|
||||||
|
|
||||||
export const RENDER_MODEL_INDICIES_PER_CELL = 4;
|
export const RENDER_MODEL_INDICIES_PER_CELL = 4;
|
||||||
export const RENDER_MODEL_BG_OFFSET = 1;
|
export const RENDER_MODEL_BG_OFFSET = 1;
|
||||||
@@ -22,16 +23,7 @@ export class RenderModel implements IRenderModel {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.cells = new Uint32Array(0);
|
this.cells = new Uint32Array(0);
|
||||||
this.lineLengths = new Uint32Array(0);
|
this.lineLengths = new Uint32Array(0);
|
||||||
this.selection = {
|
this.selection = createSelectionRenderModel();
|
||||||
hasSelection: false,
|
|
||||||
columnSelectMode: false,
|
|
||||||
viewportStartRow: 0,
|
|
||||||
viewportEndRow: 0,
|
|
||||||
viewportCappedStartRow: 0,
|
|
||||||
viewportCappedEndRow: 0,
|
|
||||||
startCol: 0,
|
|
||||||
endCol: 0
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public resize(cols: number, rows: number): void {
|
public resize(cols: number, rows: number): void {
|
||||||
@@ -46,14 +38,4 @@ export class RenderModel implements IRenderModel {
|
|||||||
fill(this.cells, 0, 0);
|
fill(this.cells, 0, 0);
|
||||||
fill(this.lineLengths, 0, 0);
|
fill(this.lineLengths, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public clearSelection(): void {
|
|
||||||
this.selection.hasSelection = false;
|
|
||||||
this.selection.viewportStartRow = 0;
|
|
||||||
this.selection.viewportEndRow = 0;
|
|
||||||
this.selection.viewportCappedStartRow = 0;
|
|
||||||
this.selection.viewportCappedEndRow = 0;
|
|
||||||
this.selection.startCol = 0;
|
|
||||||
this.selection.endCol = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
for (const l of this._renderLayers) {
|
for (const l of this._renderLayers) {
|
||||||
l.onSelectionChanged(this._terminal, start, end, columnSelectMode);
|
l.onSelectionChanged(this._terminal, start, end, columnSelectMode);
|
||||||
}
|
}
|
||||||
this._updateSelectionModel(start, end, columnSelectMode);
|
this._model.selection.update(this._terminal, start, end, columnSelectMode);
|
||||||
this._requestRedrawViewport();
|
this._requestRedrawViewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +336,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
// Tell renderer the frame is beginning
|
// Tell renderer the frame is beginning
|
||||||
if (this._glyphRenderer.beginFrame()) {
|
if (this._glyphRenderer.beginFrame()) {
|
||||||
this._clearModel(true);
|
this._clearModel(true);
|
||||||
this._updateSelectionModel(undefined, undefined);
|
this._model.selection.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update model to reflect what's drawn
|
// Update model to reflect what's drawn
|
||||||
@@ -484,7 +484,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Apply the selection color if needed
|
// Apply the selection color if needed
|
||||||
$isSelected = this._isCellSelected(x, y);
|
$isSelected = this._model.selection.isCellSelected(this._terminal, x, y);
|
||||||
if ($isSelected) {
|
if ($isSelected) {
|
||||||
$bg = (this._coreBrowserService.isFocused ? this._colors.selectionBackgroundOpaque : this._colors.selectionInactiveBackgroundOpaque).rgba >> 8 & 0xFFFFFF;
|
$bg = (this._coreBrowserService.isFocused ? this._colors.selectionBackgroundOpaque : this._colors.selectionInactiveBackgroundOpaque).rgba >> 8 & 0xFFFFFF;
|
||||||
$hasBg = true;
|
$hasBg = true;
|
||||||
@@ -550,56 +550,6 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
this._workColors.fg = $hasFg ? $fg : this._workColors.fg;
|
this._workColors.fg = $hasFg ? $fg : this._workColors.fg;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _isCellSelected(x: number, y: number): boolean {
|
|
||||||
if (!this._model.selection.hasSelection) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
y -= this._terminal.buffer.active.viewportY;
|
|
||||||
if (this._model.selection.columnSelectMode) {
|
|
||||||
if (this._model.selection.startCol <= this._model.selection.endCol) {
|
|
||||||
return x >= this._model.selection.startCol && y >= this._model.selection.viewportCappedStartRow &&
|
|
||||||
x < this._model.selection.endCol && y <= this._model.selection.viewportCappedEndRow;
|
|
||||||
}
|
|
||||||
return x < this._model.selection.startCol && y >= this._model.selection.viewportCappedStartRow &&
|
|
||||||
x >= this._model.selection.endCol && y <= this._model.selection.viewportCappedEndRow;
|
|
||||||
}
|
|
||||||
return (y > this._model.selection.viewportStartRow && y < this._model.selection.viewportEndRow) ||
|
|
||||||
(this._model.selection.viewportStartRow === this._model.selection.viewportEndRow && y === this._model.selection.viewportStartRow && x >= this._model.selection.startCol && x < this._model.selection.endCol) ||
|
|
||||||
(this._model.selection.viewportStartRow < this._model.selection.viewportEndRow && y === this._model.selection.viewportEndRow && x < this._model.selection.endCol) ||
|
|
||||||
(this._model.selection.viewportStartRow < this._model.selection.viewportEndRow && y === this._model.selection.viewportStartRow && x >= this._model.selection.startCol);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _updateSelectionModel(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean = false): void {
|
|
||||||
const terminal = this._terminal;
|
|
||||||
|
|
||||||
// Selection does not exist
|
|
||||||
if (!start || !end || (start[0] === end[0] && start[1] === end[1])) {
|
|
||||||
this._model.clearSelection();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translate from buffer position to viewport position
|
|
||||||
const viewportStartRow = start[1] - terminal.buffer.active.viewportY;
|
|
||||||
const viewportEndRow = end[1] - terminal.buffer.active.viewportY;
|
|
||||||
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) {
|
|
||||||
this._model.clearSelection();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._model.selection.hasSelection = true;
|
|
||||||
this._model.selection.columnSelectMode = columnSelectMode;
|
|
||||||
this._model.selection.viewportStartRow = viewportStartRow;
|
|
||||||
this._model.selection.viewportEndRow = viewportEndRow;
|
|
||||||
this._model.selection.viewportCappedStartRow = viewportCappedStartRow;
|
|
||||||
this._model.selection.viewportCappedEndRow = viewportCappedEndRow;
|
|
||||||
this._model.selection.startCol = start[0];
|
|
||||||
this._model.selection.endCol = end[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recalculates the character and canvas dimensions.
|
* Recalculates the character and canvas dimensions.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2022 The xterm.js authors. All rights reserved.
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ISelectionRenderModel } from 'browser/renderer/shared/Types';
|
||||||
|
import { Terminal } from 'xterm';
|
||||||
|
|
||||||
|
class SelectionRenderModel implements ISelectionRenderModel {
|
||||||
|
public hasSelection!: boolean;
|
||||||
|
public columnSelectMode!: boolean;
|
||||||
|
public viewportStartRow!: number;
|
||||||
|
public viewportEndRow!: number;
|
||||||
|
public viewportCappedStartRow!: number;
|
||||||
|
public viewportCappedEndRow!: number;
|
||||||
|
public startCol!: number;
|
||||||
|
public endCol!: number;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear(): void {
|
||||||
|
this.hasSelection = false;
|
||||||
|
this.columnSelectMode = false;
|
||||||
|
this.viewportStartRow = 0;
|
||||||
|
this.viewportEndRow = 0;
|
||||||
|
this.viewportCappedStartRow = 0;
|
||||||
|
this.viewportCappedEndRow = 0;
|
||||||
|
this.startCol = 0;
|
||||||
|
this.endCol = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public update(terminal: Terminal, start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean = false): void {
|
||||||
|
// Selection does not exist
|
||||||
|
if (!start || !end || (start[0] === end[0] && start[1] === end[1])) {
|
||||||
|
this.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate from buffer position to viewport position
|
||||||
|
const viewportStartRow = start[1] - terminal.buffer.active.viewportY;
|
||||||
|
const viewportEndRow = end[1] - terminal.buffer.active.viewportY;
|
||||||
|
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) {
|
||||||
|
this.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hasSelection = true;
|
||||||
|
this.columnSelectMode = columnSelectMode;
|
||||||
|
this.viewportStartRow = viewportStartRow;
|
||||||
|
this.viewportEndRow = viewportEndRow;
|
||||||
|
this.viewportCappedStartRow = viewportCappedStartRow;
|
||||||
|
this.viewportCappedEndRow = viewportCappedEndRow;
|
||||||
|
this.startCol = start[0];
|
||||||
|
this.endCol = end[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public isCellSelected(terminal: Terminal, x: number, y: number): boolean {
|
||||||
|
if (!this.hasSelection) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
y -= terminal.buffer.active.viewportY;
|
||||||
|
if (this.columnSelectMode) {
|
||||||
|
if (this.startCol <= this.endCol) {
|
||||||
|
return x >= this.startCol && y >= this.viewportCappedStartRow &&
|
||||||
|
x < this.endCol && y <= this.viewportCappedEndRow;
|
||||||
|
}
|
||||||
|
return x < this.startCol && y >= this.viewportCappedStartRow &&
|
||||||
|
x >= this.endCol && y <= this.viewportCappedEndRow;
|
||||||
|
}
|
||||||
|
return (y > this.viewportStartRow && y < this.viewportEndRow) ||
|
||||||
|
(this.viewportStartRow === this.viewportEndRow && y === this.viewportStartRow && x >= this.startCol && x < this.endCol) ||
|
||||||
|
(this.viewportStartRow < this.viewportEndRow && y === this.viewportEndRow && x < this.endCol) ||
|
||||||
|
(this.viewportStartRow < this.viewportEndRow && y === this.viewportStartRow && x >= this.startCol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createSelectionRenderModel(): ISelectionRenderModel {
|
||||||
|
return new SelectionRenderModel();
|
||||||
|
}
|
||||||
+12
-9
@@ -3,7 +3,7 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { FontWeight } from 'xterm';
|
import { FontWeight, Terminal } from 'xterm';
|
||||||
import { IColorSet } from 'browser/Types';
|
import { IColorSet } from 'browser/Types';
|
||||||
import { IDisposable } from 'common/Types';
|
import { IDisposable } from 'common/Types';
|
||||||
import { IEvent } from 'common/EventEmitter';
|
import { IEvent } from 'common/EventEmitter';
|
||||||
@@ -141,12 +141,15 @@ export interface IBoundingBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ISelectionRenderModel {
|
export interface ISelectionRenderModel {
|
||||||
hasSelection: boolean;
|
readonly hasSelection: boolean;
|
||||||
columnSelectMode: boolean;
|
readonly columnSelectMode: boolean;
|
||||||
viewportStartRow: number;
|
readonly viewportStartRow: number;
|
||||||
viewportEndRow: number;
|
readonly viewportEndRow: number;
|
||||||
viewportCappedStartRow: number;
|
readonly viewportCappedStartRow: number;
|
||||||
viewportCappedEndRow: number;
|
readonly viewportCappedEndRow: number;
|
||||||
startCol: number;
|
readonly startCol: number;
|
||||||
endCol: number;
|
readonly endCol: number;
|
||||||
|
clear(): void;
|
||||||
|
update(terminal: Terminal, start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode?: boolean): void;
|
||||||
|
isCellSelected(terminal: Terminal, x: number, y: number): boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user