Adopt CharSizeService in MouseHelper

This commit is contained in:
Daniel Imms
2019-06-08 15:20:03 -07:00
parent 38bb122bbd
commit 6246bb5026
10 changed files with 42 additions and 49 deletions
+9 -22
View File
@@ -3,62 +3,49 @@
* @license MIT
*/
import jsdom = require('jsdom');
import { assert } from 'chai';
import { MouseHelper } from './MouseHelper';
import { MockCharMeasure, MockRenderer } from './TestUtils.test';
import { MockRenderer, MockCharSizeService } from './TestUtils.test';
const CHAR_WIDTH = 10;
const CHAR_HEIGHT = 20;
describe('MouseHelper.getCoords', () => {
let dom: jsdom.JSDOM;
let window: Window;
let document: Document;
let mouseHelper: MouseHelper;
let charMeasure: MockCharMeasure;
beforeEach(() => {
dom = new jsdom.JSDOM('');
window = dom.window;
document = window.document;
charMeasure = new MockCharMeasure();
charMeasure.width = CHAR_WIDTH;
charMeasure.height = CHAR_HEIGHT;
const renderer = new MockRenderer();
renderer.dimensions = <any>{
actualCellWidth: CHAR_WIDTH,
actualCellHeight: CHAR_HEIGHT
};
mouseHelper = new MouseHelper(renderer as any);
mouseHelper = new MouseHelper(renderer as any, new MockCharSizeService(CHAR_WIDTH, CHAR_HEIGHT));
});
describe('when charMeasure is not initialized', () => {
it('should return null', () => {
charMeasure = new MockCharMeasure();
assert.equal(mouseHelper.getCoords({ clientX: 0, clientY: 0 }, document.createElement('div'), charMeasure, 10, 10), null);
assert.equal(mouseHelper.getCoords({ clientX: 0, clientY: 0 }, document.createElement('div'), 10, 10), null);
});
});
it('should return the cell that was clicked', () => {
let coords: [number, number];
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH / 2, clientY: CHAR_HEIGHT / 2 }, document.createElement('div'), charMeasure, 10, 10);
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH / 2, clientY: CHAR_HEIGHT / 2 }, document.createElement('div'), 10, 10);
assert.deepEqual(coords, [1, 1]);
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT }, document.createElement('div'), charMeasure, 10, 10);
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT }, document.createElement('div'), 10, 10);
assert.deepEqual(coords, [1, 1]);
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT + 1 }, document.createElement('div'), charMeasure, 10, 10);
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT + 1 }, document.createElement('div'), 10, 10);
assert.deepEqual(coords, [1, 2]);
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH + 1, clientY: CHAR_HEIGHT }, document.createElement('div'), charMeasure, 10, 10);
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH + 1, clientY: CHAR_HEIGHT }, document.createElement('div'), 10, 10);
assert.deepEqual(coords, [2, 1]);
});
it('should ensure the coordinates are returned within the terminal bounds', () => {
let coords: [number, number];
coords = mouseHelper.getCoords({ clientX: -1, clientY: -1 }, document.createElement('div'), charMeasure, 10, 10);
coords = mouseHelper.getCoords({ clientX: -1, clientY: -1 }, document.createElement('div'), 10, 10);
assert.deepEqual(coords, [1, 1]);
// Event are double the cols/rows
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH * 20, clientY: CHAR_HEIGHT * 20 }, document.createElement('div'), charMeasure, 10, 10);
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH * 20, clientY: CHAR_HEIGHT * 20 }, document.createElement('div'), 10, 10);
assert.deepEqual(coords, [10, 10], 'coordinates should never come back as larger than the terminal');
});
});
+9 -7
View File
@@ -3,12 +3,14 @@
* @license MIT
*/
import { ICharMeasure, IMouseHelper } from './Types';
import { IMouseHelper } from './Types';
import { RenderCoordinator } from './renderer/RenderCoordinator';
import { ICharSizeService } from 'ui/services/Services';
export class MouseHelper implements IMouseHelper {
constructor(
private _renderCoordinator: RenderCoordinator
private _renderCoordinator: RenderCoordinator,
private _charSizeService: ICharSizeService
) {
}
@@ -30,9 +32,9 @@ export class MouseHelper implements IMouseHelper {
* apply an offset to the x value such that the left half of the cell will
* select that cell and the right half will select the next cell.
*/
public getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, charMeasure: ICharMeasure, colCount: number, rowCount: number, isSelection?: boolean): [number, number] {
// Coordinates cannot be measured if charMeasure has not been initialized
if (!charMeasure.width || !charMeasure.height) {
public getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] {
// Coordinates cannot be measured if there are no valid
if (!this._charSizeService.hasValidSize) {
return null;
}
@@ -63,8 +65,8 @@ export class MouseHelper implements IMouseHelper {
* @param colCount The number of columns in the terminal.
* @param rowCount The number of rows in the terminal.
*/
public getRawByteCoords(event: MouseEvent, element: HTMLElement, charMeasure: ICharMeasure, colCount: number, rowCount: number): { x: number, y: number } {
const coords = this.getCoords(event, element, charMeasure, colCount, rowCount);
public getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number, y: number } {
const coords = this.getCoords(event, element, colCount, rowCount);
let x = coords[0];
let y = coords[1];
+1 -1
View File
@@ -203,7 +203,7 @@ export class MouseZoneManager extends Disposable implements IMouseZoneManager {
}
private _findZoneEventAt(e: MouseEvent): IMouseZone {
const coords = this._terminal.mouseHelper.getCoords(e, this._terminal.screenElement, this._terminal.charMeasure, this._terminal.cols, this._terminal.rows);
const coords = this._terminal.mouseHelper.getCoords(e, this._terminal.screenElement, this._terminal.cols, this._terminal.rows);
if (!coords) {
return null;
}
+1 -1
View File
@@ -354,7 +354,7 @@ export class SelectionManager implements ISelectionManager {
* @param event The mouse event.
*/
private _getMouseBufferCoords(event: MouseEvent): [number, number] {
const coords = this._terminal.mouseHelper.getCoords(event, this._terminal.screenElement, this._charMeasure, this._terminal.cols, this._terminal.rows, true);
const coords = this._terminal.mouseHelper.getCoords(event, this._terminal.screenElement, this._terminal.cols, this._terminal.rows, true);
if (!coords) {
return null;
}
+10 -4
View File
@@ -55,6 +55,8 @@ import { ColorManager } from 'ui/ColorManager';
import { RenderCoordinator } from './renderer/RenderCoordinator';
import { IOptionsService } from 'common/options/Types';
import { OptionsService } from 'common/options/OptionsService';
import { ICharSizeService } from 'ui/services/Services';
import { CharSizeService } from 'ui/services/CharSizeService';
// Let it work inside Node.js for automated testing purposes.
const document = (typeof window !== 'undefined') ? window.document : null;
@@ -107,9 +109,12 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
private _customKeyEventHandler: CustomKeyEventHandler;
// services
// common services
public optionsService: IOptionsService;
// browser services
private _charSizeService: ICharSizeService;
// modes
public applicationKeypad: boolean;
public applicationCursor: boolean;
@@ -615,6 +620,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
this._helperContainer.appendChild(this._compositionView);
this.charMeasure = new CharMeasure(document, this._helperContainer);
this._charSizeService = new CharSizeService(this._document, this._helperContainer, this.optionsService);
// Performance: Add viewport and helper elements from the fragment
this.element.appendChild(fragment);
@@ -658,7 +664,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
}));
this.register(addDisposableDomListener(this._viewportElement, 'scroll', () => this.selectionManager.refresh()));
this.mouseHelper = new MouseHelper(this._renderCoordinator);
this.mouseHelper = new MouseHelper(this._renderCoordinator, this._charSizeService);
// apply mouse event classes set by escape codes before terminal was attached
this.element.classList.toggle('enable-mouse-events', this.mouseEvents);
if (this.mouseEvents) {
@@ -738,7 +744,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
button = getButton(ev);
// get mouse coordinates
pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.charMeasure, self.cols, self.rows);
pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.cols, self.rows);
if (!pos) return;
sendEvent(button, pos);
@@ -764,7 +770,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
// ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
function sendMove(ev: MouseEvent): void {
let button = pressed;
const pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.charMeasure, self.cols, self.rows);
const pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.cols, self.rows);
if (!pos) return;
// buttons marked as motions
+8 -9
View File
@@ -14,6 +14,7 @@ import { Terminal } from './Terminal';
import { AttributeData } from 'core/buffer/BufferLine';
import { IColorManager, IColorSet } from 'ui/Types';
import { IOptionsService } from 'common/options/Types';
import { ICharSizeService } from 'ui/services/Services';
export class TestTerminal extends Terminal {
writeSync(data: string): void {
@@ -182,15 +183,6 @@ export class MockTerminal implements ITerminal {
deregisterCharacterJoiner(joinerId: number): void { }
}
export class MockCharMeasure implements ICharMeasure {
onCharSizeChanged: IEvent<void>;
width: number;
height: number;
measure(options: ITerminalOptions): void {
throw new Error('Method not implemented.');
}
}
export class MockInputHandlingTerminal implements IInputHandlingTerminal {
element: HTMLElement;
options: ITerminalOptions = {};
@@ -438,3 +430,10 @@ export class MockCompositionHelper implements ICompositionHelper {
return true;
}
}
export class MockCharSizeService implements ICharSizeService {
get hasValidSize(): boolean { return this.width > 0 && this.height > 0; }
onCharSizeChange: IEvent<string>;
constructor(public width: number, public height: number) {}
measure(): void {}
}
+2 -2
View File
@@ -284,8 +284,8 @@ export interface ILinkifierAccessor {
}
export interface IMouseHelper {
getCoords(event: { clientX: number, clientY: number }, element: HTMLElement, charMeasure: ICharMeasure, colCount: number, rowCount: number, isSelection?: boolean): [number, number];
getRawByteCoords(event: MouseEvent, element: HTMLElement, charMeasure: ICharMeasure, colCount: number, rowCount: number): { x: number, y: number };
getCoords(event: { clientX: number, clientY: number }, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number];
getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number, y: number };
}
export interface ICharMeasure {
-1
View File
@@ -33,7 +33,6 @@ export class AltClickHandler {
const coordinates = this._terminal.mouseHelper.getCoords(
this._mouseEvent,
this._terminal.element,
this._terminal.charMeasure,
this._terminal.cols,
this._terminal.rows,
false
+1 -1
View File
@@ -12,7 +12,7 @@ export class CharSizeService implements ICharSizeService {
public height: number = 0;
private _measureStrategy: IMeasureStrategy;
public get hasValidDimensions(): boolean { return this.width > 0 && this.height > 0; }
public get hasValidSize(): boolean { return this.width > 0 && this.height > 0; }
private _onCharSizeChange = new EventEmitter2<string>();
public get onCharSizeChange(): IEvent<string> { return this._onCharSizeChange.event; }
+1 -1
View File
@@ -8,7 +8,7 @@ import { IEvent } from 'common/EventEmitter2';
export interface ICharSizeService {
readonly width: number;
readonly height: number;
readonly hasValidDimensions: boolean;
readonly hasValidSize: boolean;
readonly onCharSizeChange: IEvent<string>;