mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
@@ -69,9 +69,10 @@ export class FitAddon implements ITerminalAddon, IFitApi {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const scrollbarWidth = (this._terminal.options.scrollback === 0
|
||||
const showScrollbar = this._terminal.options.scrollbar?.showScrollbar ?? true;
|
||||
const scrollbarWidth = (this._terminal.options.scrollback === 0 || !showScrollbar
|
||||
? 0
|
||||
: (this._terminal.options.overviewRuler?.width || ViewportConstants.DEFAULT_SCROLL_BAR_WIDTH));
|
||||
: (this._terminal.options.overviewRuler?.width ?? ViewportConstants.DEFAULT_SCROLL_BAR_WIDTH));
|
||||
|
||||
const parentElementStyle = _getComputedStyle(this._terminal.element.parentElement);
|
||||
const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));
|
||||
|
||||
@@ -284,7 +284,7 @@ function createTerminal(): Terminal {
|
||||
|
||||
const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0;
|
||||
term = new Terminal({
|
||||
scrollbar: { showArrows: true },
|
||||
scrollbar: { showScrollbar: true },
|
||||
allowProposedApi: true,
|
||||
windowsPty: isWindows ? {
|
||||
// In a real scenario, these values should be verified on the backend
|
||||
|
||||
@@ -123,6 +123,8 @@ export class OptionsWindow extends BaseWindow implements IControlWindow {
|
||||
'windowsPty',
|
||||
];
|
||||
const nestedBooleanOptions: { label: string, parent: string, prop: string }[] = [
|
||||
{ label: 'scrollbar.showScrollbar', parent: 'scrollbar', prop: 'showScrollbar' },
|
||||
{ label: 'scrollbar.showArrows', parent: 'scrollbar', prop: 'showArrows' },
|
||||
{ label: 'vtExtensions.kittyKeyboard', parent: 'vtExtensions', prop: 'kittyKeyboard' },
|
||||
{ label: 'vtExtensions.kittySgrBoldFaintControl', parent: 'vtExtensions', prop: 'kittySgrBoldFaintControl' },
|
||||
{ label: 'vtExtensions.win32InputMode', parent: 'vtExtensions', prop: 'win32InputMode' }
|
||||
|
||||
@@ -616,11 +616,19 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
||||
}
|
||||
this._register(this.optionsService.onSpecificOptionChange('screenReaderMode', e => this._handleScreenReaderModeOptionChange(e)));
|
||||
|
||||
if (this.options.overviewRuler.width) {
|
||||
const showScrollbar = this.options.scrollbar?.showScrollbar ?? true;
|
||||
if (showScrollbar && this.options.overviewRuler.width) {
|
||||
this._overviewRulerRenderer = this._register(this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement));
|
||||
}
|
||||
this.optionsService.onSpecificOptionChange('overviewRuler', value => {
|
||||
if (!this._overviewRulerRenderer && value && this._viewportElement && this.screenElement) {
|
||||
const shouldShow = (this.options.scrollbar?.showScrollbar ?? true) && !!value?.width;
|
||||
if (!this._overviewRulerRenderer && shouldShow && this._viewportElement && this.screenElement) {
|
||||
this._overviewRulerRenderer = this._register(this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement));
|
||||
}
|
||||
});
|
||||
this.optionsService.onSpecificOptionChange('scrollbar', value => {
|
||||
const shouldShow = (value?.showScrollbar ?? true) && !!this.options.overviewRuler.width;
|
||||
if (!this._overviewRulerRenderer && shouldShow && this._viewportElement && this.screenElement) {
|
||||
this._overviewRulerRenderer = this._register(this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement));
|
||||
}
|
||||
});
|
||||
|
||||
+10
-2
@@ -62,7 +62,8 @@ export class Viewport extends Disposable {
|
||||
this._register(this._optionsService.onMultipleOptionChange([
|
||||
'scrollSensitivity',
|
||||
'fastScrollSensitivity',
|
||||
'overviewRuler'
|
||||
'overviewRuler',
|
||||
'scrollbar'
|
||||
], () => this._scrollableElement.updateOptions(this._getChangeOptions())));
|
||||
// Don't handle mouse wheel if wheel events are supported by the current mouse prototcol
|
||||
this._register(coreMouseService.onProtocolChange(type => {
|
||||
@@ -131,10 +132,17 @@ export class Viewport extends Disposable {
|
||||
}
|
||||
|
||||
private _getChangeOptions(): IScrollableElementChangeOptions {
|
||||
const showScrollbar = this._optionsService.rawOptions.scrollbar?.showScrollbar ?? true;
|
||||
const showArrows = this._optionsService.rawOptions.scrollbar?.showArrows ?? false;
|
||||
const verticalScrollbarSize = showScrollbar
|
||||
? (this._optionsService.rawOptions.overviewRuler?.width ?? ViewportConstants.DEFAULT_SCROLL_BAR_WIDTH)
|
||||
: 0;
|
||||
return {
|
||||
mouseWheelScrollSensitivity: this._optionsService.rawOptions.scrollSensitivity,
|
||||
fastScrollSensitivity: this._optionsService.rawOptions.fastScrollSensitivity,
|
||||
verticalScrollbarSize: this._optionsService.rawOptions.overviewRuler?.width || ViewportConstants.DEFAULT_SCROLL_BAR_WIDTH
|
||||
vertical: showScrollbar ? ScrollbarVisibility.AUTO : ScrollbarVisibility.HIDDEN,
|
||||
verticalScrollbarSize,
|
||||
verticalHasArrows: showArrows
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,11 @@ export class OverviewRulerRenderer extends Disposable {
|
||||
private readonly _ctx: CanvasRenderingContext2D;
|
||||
private readonly _colorZoneStore: IColorZoneStore = new ColorZoneStore();
|
||||
private get _width(): number {
|
||||
return this._optionsService.options.overviewRuler?.width || 0;
|
||||
const showScrollbar = this._optionsService.rawOptions.scrollbar?.showScrollbar ?? true;
|
||||
if (!showScrollbar) {
|
||||
return 0;
|
||||
}
|
||||
return this._optionsService.rawOptions.overviewRuler?.width ?? 0;
|
||||
}
|
||||
private _animationFrame: number | undefined;
|
||||
|
||||
@@ -96,6 +100,7 @@ export class OverviewRulerRenderer extends Disposable {
|
||||
|
||||
this._register(this._coreBrowserService.onDprChange(() => this._queueRefresh(true)));
|
||||
this._register(this._optionsService.onSpecificOptionChange('overviewRuler', () => this._queueRefresh(true)));
|
||||
this._register(this._optionsService.onSpecificOptionChange('scrollbar', () => this._queueRefresh(true)));
|
||||
this._register(this._themeService.onChangeColors(() => this._queueRefresh()));
|
||||
this._queueRefresh(true);
|
||||
}
|
||||
|
||||
@@ -82,10 +82,11 @@ export abstract class AbstractScrollbar extends Widget {
|
||||
/**
|
||||
* Creates the dom node for an arrow & adds it to the container
|
||||
*/
|
||||
protected _createArrow(opts: IScrollbarArrowOptions): void {
|
||||
protected _createArrow(opts: IScrollbarArrowOptions): ScrollbarArrow {
|
||||
const arrow = this._register(new ScrollbarArrow(opts));
|
||||
this.domNode.domNode.appendChild(arrow.bgDomNode);
|
||||
this.domNode.domNode.appendChild(arrow.domNode);
|
||||
return arrow;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -314,6 +314,12 @@ export class SmoothScrollableElement extends Widget {
|
||||
if (typeof newOptions.vertical !== 'undefined') {
|
||||
this._options.vertical = newOptions.vertical;
|
||||
}
|
||||
if (typeof newOptions.horizontalHasArrows !== 'undefined') {
|
||||
this._options.horizontalHasArrows = newOptions.horizontalHasArrows;
|
||||
}
|
||||
if (typeof newOptions.verticalHasArrows !== 'undefined') {
|
||||
this._options.verticalHasArrows = newOptions.verticalHasArrows;
|
||||
}
|
||||
if (typeof newOptions.horizontalScrollbarSize !== 'undefined') {
|
||||
this._options.horizontalScrollbarSize = newOptions.horizontalScrollbarSize;
|
||||
}
|
||||
|
||||
@@ -128,8 +128,10 @@ export interface IScrollableElementChangeOptions {
|
||||
scrollPredominantAxis?: boolean;
|
||||
horizontal?: ScrollbarVisibility;
|
||||
horizontalScrollbarSize?: number;
|
||||
horizontalHasArrows?: boolean;
|
||||
vertical?: ScrollbarVisibility;
|
||||
verticalScrollbarSize?: number;
|
||||
verticalHasArrows?: boolean;
|
||||
scrollByPage?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ export class ScrollbarState {
|
||||
* For the vertical scrollbar: the height of the scrollbar's arrows.
|
||||
* For the horizontal scrollbar: the width of the scrollbar's arrows.
|
||||
*/
|
||||
private readonly _arrowSize: number;
|
||||
private _arrowSize: number;
|
||||
|
||||
// --- variables
|
||||
/**
|
||||
@@ -127,6 +127,14 @@ export class ScrollbarState {
|
||||
this._scrollbarSize = Math.round(scrollbarSize);
|
||||
}
|
||||
|
||||
public setArrowSize(arrowSize: number): void {
|
||||
const iArrowSize = Math.round(arrowSize);
|
||||
if (this._arrowSize !== iArrowSize) {
|
||||
this._arrowSize = iArrowSize;
|
||||
this._refreshComputedValues();
|
||||
}
|
||||
}
|
||||
|
||||
public setOppositeScrollbarSize(oppositeScrollbarSize: number): void {
|
||||
this._oppositeScrollbarSize = Math.round(oppositeScrollbarSize);
|
||||
}
|
||||
|
||||
@@ -7,17 +7,22 @@ import { AbstractScrollbar, ISimplifiedPointerEvent, IScrollbarHost } from './ab
|
||||
import { IScrollableElementResolvedOptions } from './scrollableElementOptions';
|
||||
import { ScrollbarState } from './scrollbarState';
|
||||
import { INewScrollPosition, Scrollable, ScrollbarVisibility, IScrollEvent } from './scrollable';
|
||||
import type { ScrollbarArrow } from './scrollbarArrow';
|
||||
|
||||
export class VerticalScrollbar extends AbstractScrollbar {
|
||||
private _arrowUp: ScrollbarArrow | undefined;
|
||||
private _arrowDown: ScrollbarArrow | undefined;
|
||||
private _arrowScrollDelta: number = 0;
|
||||
|
||||
constructor(scrollable: Scrollable, options: IScrollableElementResolvedOptions, host: IScrollbarHost) {
|
||||
const scrollDimensions = scrollable.getScrollDimensions();
|
||||
const scrollPosition = scrollable.getCurrentScrollPosition();
|
||||
const hasArrows = options.verticalHasArrows;
|
||||
super({
|
||||
lazyRender: options.lazyRender,
|
||||
host: host,
|
||||
scrollbarState: new ScrollbarState(
|
||||
(options.verticalHasArrows ? options.verticalScrollbarSize : 0),
|
||||
(hasArrows ? options.verticalScrollbarSize : 0),
|
||||
(options.vertical === ScrollbarVisibility.HIDDEN ? 0 : options.verticalScrollbarSize),
|
||||
0,
|
||||
scrollDimensions.height,
|
||||
@@ -30,26 +35,7 @@ export class VerticalScrollbar extends AbstractScrollbar {
|
||||
scrollByPage: options.scrollByPage
|
||||
});
|
||||
|
||||
if (options.verticalHasArrows) {
|
||||
const arrowSize = options.verticalScrollbarSize;
|
||||
const arrowDelta = 0;
|
||||
this._createArrow({
|
||||
className: 'xterm-scra xterm-arrow-up',
|
||||
top: arrowDelta,
|
||||
left: arrowDelta,
|
||||
bgWidth: options.verticalScrollbarSize,
|
||||
bgHeight: arrowSize,
|
||||
handleActivate: () => this._arrowScroll(-arrowSize)
|
||||
});
|
||||
this._createArrow({
|
||||
className: 'xterm-scra xterm-arrow-down',
|
||||
bottom: arrowDelta,
|
||||
left: arrowDelta,
|
||||
bgWidth: options.verticalScrollbarSize,
|
||||
bgHeight: arrowSize,
|
||||
handleActivate: () => this._arrowScroll(arrowSize)
|
||||
});
|
||||
}
|
||||
this._setArrows(hasArrows, options.verticalScrollbarSize);
|
||||
|
||||
this._createSlider(0, Math.floor((options.verticalScrollbarSize - options.verticalSliderSize) / 2), options.verticalSliderSize, undefined);
|
||||
}
|
||||
@@ -98,7 +84,56 @@ export class VerticalScrollbar extends AbstractScrollbar {
|
||||
this._scrollable.setScrollPositionNow({ scrollTop: currentPosition.scrollTop + delta });
|
||||
}
|
||||
|
||||
private _setArrows(showArrows: boolean, size: number): void {
|
||||
this._arrowScrollDelta = size;
|
||||
if (!this._arrowUp || !this._arrowDown) {
|
||||
const arrowDelta = 0;
|
||||
this._arrowUp = this._createArrow({
|
||||
className: 'xterm-scra xterm-arrow-up',
|
||||
top: arrowDelta,
|
||||
left: arrowDelta,
|
||||
bgWidth: size,
|
||||
bgHeight: size,
|
||||
handleActivate: () => this._arrowScroll(-this._arrowScrollDelta)
|
||||
});
|
||||
this._arrowDown = this._createArrow({
|
||||
className: 'xterm-scra xterm-arrow-down',
|
||||
bottom: arrowDelta,
|
||||
left: arrowDelta,
|
||||
bgWidth: size,
|
||||
bgHeight: size,
|
||||
handleActivate: () => this._arrowScroll(this._arrowScrollDelta)
|
||||
});
|
||||
}
|
||||
|
||||
this._updateArrowSize(this._arrowUp, size);
|
||||
this._updateArrowSize(this._arrowDown, size);
|
||||
|
||||
if (!this._arrowUp || !this._arrowDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
const display = showArrows ? '' : 'none';
|
||||
this._arrowUp.bgDomNode.style.display = display;
|
||||
this._arrowUp.domNode.style.display = display;
|
||||
this._arrowDown.bgDomNode.style.display = display;
|
||||
this._arrowDown.domNode.style.display = display;
|
||||
}
|
||||
|
||||
private _updateArrowSize(arrow: ScrollbarArrow | undefined, size: number): void {
|
||||
if (!arrow) {
|
||||
return;
|
||||
}
|
||||
arrow.bgDomNode.style.width = `${size}px`;
|
||||
arrow.bgDomNode.style.height = `${size}px`;
|
||||
arrow.domNode.style.width = `${size}px`;
|
||||
arrow.domNode.style.height = `${size}px`;
|
||||
}
|
||||
|
||||
public updateOptions(options: IScrollableElementResolvedOptions): void {
|
||||
const arrowSize = options.verticalHasArrows ? options.verticalScrollbarSize : 0;
|
||||
this._scrollbarState.setArrowSize(arrowSize);
|
||||
this._setArrows(options.verticalHasArrows, options.verticalScrollbarSize);
|
||||
this.updateScrollbarSize(options.vertical === ScrollbarVisibility.HIDDEN ? 0 : options.verticalScrollbarSize);
|
||||
this._scrollbarState.setOppositeScrollbarSize(0);
|
||||
this._visibilityController.setVisibility(options.vertical);
|
||||
|
||||
@@ -32,7 +32,7 @@ export const DEFAULT_OPTIONS: Readonly<Required<ITerminalOptions>> = {
|
||||
logLevel: 'info',
|
||||
logger: null,
|
||||
scrollback: 1000,
|
||||
scrollbar: {},
|
||||
scrollbar: { showScrollbar: true },
|
||||
scrollOnEraseInDisplay: false,
|
||||
scrollOnUserInput: true,
|
||||
scrollSensitivity: 1,
|
||||
|
||||
@@ -311,6 +311,7 @@ export interface ITerminalQuirks {
|
||||
}
|
||||
|
||||
export interface IScrollbarOptions {
|
||||
showScrollbar?: boolean;
|
||||
showArrows?: boolean;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+6
@@ -716,6 +716,7 @@ declare module '@xterm/xterm' {
|
||||
/**
|
||||
* When defined, renders decorations in the overview ruler to the right of
|
||||
* the terminal. This must be set in order to see the overview ruler.
|
||||
* This is ignored when {@link IScrollbarOptions.showScrollbar} is false.
|
||||
* @param color The color of the decoration.
|
||||
* @param position The position of the decoration.
|
||||
*/
|
||||
@@ -738,6 +739,11 @@ declare module '@xterm/xterm' {
|
||||
* Options for configuring the scrollbar.
|
||||
*/
|
||||
export interface IScrollbarOptions {
|
||||
/**
|
||||
* Whether to show the scrollbar. When false, this supersedes
|
||||
* {@link IOverviewRulerOptions.width}. Defaults to true.
|
||||
*/
|
||||
showScrollbar?: boolean;
|
||||
/**
|
||||
* Whether to show arrows at the top and bottom of the scrollbar. Defaults
|
||||
* to false.
|
||||
|
||||
Reference in New Issue
Block a user