diff --git a/addons/addon-image/src/IIPImageStorage.ts b/addons/addon-image/src/IIPImageStorage.ts index 0da91607f..6c773f53d 100644 --- a/addons/addon-image/src/IIPImageStorage.ts +++ b/addons/addon-image/src/IIPImageStorage.ts @@ -3,6 +3,7 @@ * @license MIT */ +import { IAddImageOpts } from 'Types'; import { ImageStorage } from './ImageStorage'; /** @@ -12,6 +13,7 @@ import { ImageStorage } from './ImageStorage'; * - Always uses scrolling mode (cursor advances with image) */ export class IIPImageStorage { + private _addImageOpts: IAddImageOpts = {scrolling: true, layer: 'top', zIndex: 0, cursorPos: 'iip'}; constructor( private readonly _storage: ImageStorage ) {} @@ -21,6 +23,6 @@ export class IIPImageStorage { * Always uses scrolling mode — cursor advances past the image. */ public addImage(img: HTMLCanvasElement | ImageBitmap): void { - this._storage.addImage(img, true); + this._storage.addImage(img, this._addImageOpts); } } diff --git a/addons/addon-image/src/ImageStorage.ts b/addons/addon-image/src/ImageStorage.ts index 8c89a16b0..ea5934f1f 100644 --- a/addons/addon-image/src/ImageStorage.ts +++ b/addons/addon-image/src/ImageStorage.ts @@ -5,7 +5,11 @@ import { IDisposable } from '@xterm/xterm'; import { ImageRenderer } from './ImageRenderer'; -import { ITerminalExt, IExtendedAttrsImage, IImageAddonOptions, IImageSpec, IBufferLineExt, BgFlags, Cell, Content, ICellSize, ExtFlags, Attributes, UnderlineStyle, ImageLayer } from './Types'; +import { + ITerminalExt, IExtendedAttrsImage, IImageAddonOptions, IImageSpec, + IBufferLineExt, BgFlags, Cell, Content, ICellSize, ExtFlags, Attributes, + UnderlineStyle, IAddImageOpts +} from './Types'; // fallback default cell size @@ -241,7 +245,7 @@ export class ImageStorage implements IDisposable { * @param zIndex - Z-index for image layering within the same layer. * @returns The internal image ID assigned to the stored image. */ - public addImage(img: HTMLCanvasElement | ImageBitmap, scrolling: boolean, layer: ImageLayer = 'top', zIndex: number = 0): number { + public addImage(img: HTMLCanvasElement | ImageBitmap, opts: IAddImageOpts): number { // never allow storage to exceed memory limit this._evictOldest(img.width * img.height); @@ -263,7 +267,7 @@ export class ImageStorage implements IDisposable { let offset = originX; let tileCount = 0; - if (!scrolling) { + if (!opts.scrolling) { buffer.x = 0; buffer.y = 0; offset = 0; @@ -277,7 +281,7 @@ export class ImageStorage implements IDisposable { this._writeToCell(line as IBufferLineExt, offset + col, imageId, row * cols + col); tileCount++; } - if (scrolling) { + if (opts.scrolling) { if (row < rows - 1) this._terminal._core._inputHandler.lineFeed(); } else { if (++buffer.y >= termRows) break; @@ -287,8 +291,12 @@ export class ImageStorage implements IDisposable { this._terminal._core._inputHandler._dirtyRowTracker.markDirty(buffer.y); // cursor positioning modes - if (scrolling) { - buffer.x = offset; + if (opts.scrolling) { + if (opts.cursorPos === 'iip') { + buffer.x = Math.min(offset + cols, termCols); + } else { + buffer.x = offset; + } } else { buffer.x = originX; buffer.y = originY; @@ -331,8 +339,8 @@ export class ImageStorage implements IDisposable { marker: endMarker || undefined, tileCount, bufferType: this._terminal.buffer.active.type, - layer, - zIndex + layer: opts.layer, + zIndex: opts.zIndex }; // finally add the image diff --git a/addons/addon-image/src/SixelImageStorage.ts b/addons/addon-image/src/SixelImageStorage.ts index 4c5f555bb..b9f57fae0 100644 --- a/addons/addon-image/src/SixelImageStorage.ts +++ b/addons/addon-image/src/SixelImageStorage.ts @@ -4,7 +4,7 @@ */ import { ImageStorage, CELL_SIZE_DEFAULT } from './ImageStorage'; -import { IImageAddonOptions, ITerminalExt } from './Types'; +import { IImageAddonOptions, ITerminalExt, IAddImageOpts } from './Types'; import { ImageRenderer } from './ImageRenderer'; /** @@ -15,6 +15,7 @@ import { ImageRenderer } from './ImageRenderer'; * - advanceCursor for empty sixels carrying only height */ export class SixelImageStorage { + private _addImageOpts: IAddImageOpts = {scrolling: true, layer: 'top', zIndex: 0, cursorPos: 'vt340'}; constructor( private readonly _storage: ImageStorage, private readonly _opts: IImageAddonOptions, @@ -27,7 +28,8 @@ export class SixelImageStorage { * Cursor behavior depends on the sixelScrolling option (DECSET 80). */ public addImage(img: HTMLCanvasElement | ImageBitmap): void { - this._storage.addImage(img, this._opts.sixelScrolling); + this._addImageOpts.scrolling = this._opts.sixelScrolling; + this._storage.addImage(img, this._addImageOpts); } /** diff --git a/addons/addon-image/src/Types.ts b/addons/addon-image/src/Types.ts index 80cec9e24..19a1acca1 100644 --- a/addons/addon-image/src/Types.ts +++ b/addons/addon-image/src/Types.ts @@ -100,6 +100,14 @@ export interface ICellSize { } export type ImageLayer = 'top' | 'bottom'; +export type CursorPos = 'vt340' | 'iip'; + +export interface IAddImageOpts { + scrolling: boolean; + layer: ImageLayer; + zIndex: number; + cursorPos: CursorPos; +} export interface IImageSpec { orig: HTMLCanvasElement | ImageBitmap | undefined; diff --git a/addons/addon-image/src/kitty/KittyImageStorage.ts b/addons/addon-image/src/kitty/KittyImageStorage.ts index 95ea594c7..b55b6cf7e 100644 --- a/addons/addon-image/src/kitty/KittyImageStorage.ts +++ b/addons/addon-image/src/kitty/KittyImageStorage.ts @@ -5,7 +5,7 @@ import { IDisposable } from '@xterm/xterm'; import { ImageStorage } from '../ImageStorage'; -import { ImageLayer } from '../Types'; +import { ImageLayer, IAddImageOpts } from '../Types'; import { IKittyImageData } from './KittyGraphicsTypes'; // Kitty-specific image storage controller. @@ -42,6 +42,7 @@ export class KittyImageStorage implements IDisposable { this._images.delete(kittyId); } }; + private _addImageOpts: IAddImageOpts = {scrolling: true, layer: 'top', zIndex: 0, cursorPos: 'iip'}; constructor( private readonly _storage: ImageStorage @@ -98,7 +99,10 @@ export class KittyImageStorage implements IDisposable { if (oldStorageId !== undefined) { this._storageIdToKittyId.delete(oldStorageId); } - const storageId = this._storage.addImage(image, scrolling, layer, zIndex); + this._addImageOpts.scrolling = scrolling; + this._addImageOpts.layer = layer; + this._addImageOpts.zIndex = zIndex; + const storageId = this._storage.addImage(image, this._addImageOpts); this._kittyIdToStorageId.set(kittyId, storageId); this._storageIdToKittyId.set(storageId, kittyId); }