diff --git a/src/imagerenderer.ts b/src/imagerenderer.ts index c9e6b6f3..9863ae5c 100644 --- a/src/imagerenderer.ts +++ b/src/imagerenderer.ts @@ -12,13 +12,15 @@ class ImageRendererModel { htmlImg : any; termOpts : TermOptsType; dataBuf : PtyDataBuffer; + fontSize : number; - constructor(imgDivElem : any, context : RendererContext, termOpts : TermOptsType, isDone : boolean) { + constructor(imgDivElem : any, context : RendererContext, termOpts : TermOptsType, isDone : boolean, fontSize : number) { this.dataBuf = new PtyDataBuffer(); this.htmlImgDivElem = imgDivElem; this.termOpts = termOpts; this.context = context; this.isDone = mobx.observable.box(isDone, {name: "isDone"}); + this.fontSize = fontSize; this.reload(0); } @@ -39,8 +41,8 @@ class ImageRendererModel { let blob = new Blob([this.dataBuf.getData()], {type: "image/jpeg"}); this.htmlImg = new Image(); this.htmlImg.src = URL.createObjectURL(blob); - this.htmlImg.style.maxHeight = termHeightFromRows(this.termOpts.rows) + "px"; - this.htmlImg.style.maxWidth = termWidthFromCols(this.termOpts.cols) + "px"; + this.htmlImg.style.maxHeight = termHeightFromRows(this.termOpts.rows, this.fontSize) + "px"; + this.htmlImg.style.maxWidth = termWidthFromCols(this.termOpts.cols, this.fontSize) + "px"; this.htmlImgDivElem.replaceChildren(this.htmlImg); } diff --git a/src/main.tsx b/src/main.tsx index 0bd19142..a806ce67 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -483,7 +483,7 @@ class TerminalRenderer extends React.Component<{sw : ScreenWindow, line : LineTy }, {name: "computed-isFocused"}).get(); let cmd = GlobalModel.getCmd(line); // will not be null let usedRows = sw.getUsedRows(line, cmd, width); - let termHeight = termHeightFromRows(usedRows); + let termHeight = termHeightFromRows(usedRows, GlobalModel.termFontSize.get()); let termLoaded = this.termLoaded.get(); return (
@@ -707,12 +707,11 @@ class LineCmd extends React.Component<{sw : ScreenWindow, line : LineType, width // header is 36px tall, padding+border = 6px // zero-terminal is 0px // terminal-wrapper overhead is 11px (margin/padding) - // each terminal line 16px // inner-height, if zero-lines => 42 - // else: 53+(lines*16) + // else: 53+(lines*lineheight) let height = 42; // height of zero height terminal if (usedRows > 0) { - height = 53 + termHeightFromRows(usedRows); + height = 53 + termHeightFromRows(usedRows, GlobalModel.termFontSize.get()); } return (
@@ -1396,6 +1395,7 @@ class InfoRemoteShow extends React.Component<{}, {}> { ); } + let termFontSize = GlobalModel.termFontSize.get(); return ( <>
@@ -1441,14 +1441,14 @@ class InfoRemoteShow extends React.Component<{}, {}> {
-
+
input is only allowed while status is 'connecting'
-
+
); @@ -2604,8 +2604,8 @@ class ScreenWindowView extends React.Component<{sw : ScreenWindow}, {}> { this.width.set(width); this.height.set(height); let {sw} = this.props; - let cols = windowWidthToCols(width); - let rows = windowHeightToRows(height); + let cols = windowWidthToCols(width, GlobalModel.termFontSize.get()); + let rows = windowHeightToRows(height, GlobalModel.termFontSize.get()); if (sw == null || cols == 0 || rows == 0) { return; } @@ -2720,9 +2720,11 @@ class ScreenView extends React.Component<{screen : Screen}, {}> {
); } + let fontSize = GlobalModel.termFontSize.get(); + let swKey = sw.windowId + "-fs" + fontSize; return (
- +
); } diff --git a/src/model.ts b/src/model.ts index f346dafe..52afb3f5 100644 --- a/src/model.ts +++ b/src/model.ts @@ -8,11 +8,9 @@ import {v4 as uuidv4} from "uuid"; import type {SessionDataType, WindowDataType, LineType, RemoteType, HistoryItem, RemoteInstanceType, RemotePtrType, CmdDataType, FeCmdPacketType, TermOptsType, RemoteStateType, ScreenDataType, ScreenWindowType, ScreenOptsType, LayoutType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, UIContextType, HistoryInfoType, HistoryQueryOpts, FeInputPacketType, TermWinSize, RemoteInputPacketType, FeStateType, ContextMenuOpts, RendererContext, RendererModel, PtyDataType, BookmarkType} from "./types"; import {WSControl} from "./ws"; import {ImageRendererModel} from "./imagerenderer"; -import {measureText} from "./textmeasure"; +import {measureText, getMonoFontSize} from "./textmeasure"; var GlobalUser = "sawka"; -const DefaultCellWidth = 7.203125; -const DefaultCellHeight = 16; const RemotePtyRows = 8; // also in main.tsx const RemotePtyCols = 80; const MinTermCols = 10; @@ -21,6 +19,9 @@ const ProdServerEndpoint = "http://localhost:1619"; const ProdServerWsEndpoint = "ws://localhost:1623"; const DevServerEndpoint = "http://localhost:8090"; const DevServerWsEndpoint = "ws://localhost:8091"; +const DefaultTermFontSize = 12; +const MinFontSize = 8; +const MaxFontSize = 15; // @ts-ignore const VERSION = __PROMPT_VERSION__; @@ -34,26 +35,30 @@ type SWLinePtr = { sw : ScreenWindow, }; -function windowWidthToCols(width : number) : number { - let cols = Math.trunc((width - 50) / DefaultCellWidth) - 1; +function windowWidthToCols(width : number, fontSize : number) : number { + let dr = getMonoFontSize(fontSize); + let cols = Math.trunc((width - 50) / dr.width) - 1; cols = boundInt(cols, MinTermCols, MaxTermCols); return cols; } -function windowHeightToRows(height : number) : number { - let rows = Math.floor((height - 80)/DefaultCellHeight) - 1; +function windowHeightToRows(height : number, fontSize : number) : number { + let dr = getMonoFontSize(fontSize); + let rows = Math.floor((height - 80) / dr.height) - 1; if (rows <= 0) { rows = 1; } return rows; } -function termWidthFromCols(cols : number) : number { - return Math.ceil(DefaultCellWidth*cols) + 15; +function termWidthFromCols(cols : number, fontSize : number) : number { + let dr = getMonoFontSize(fontSize); + return Math.ceil(dr.width*cols) + 15; } -function termHeightFromRows(rows : number) : number { - return Math.ceil(DefaultCellHeight*rows); +function termHeightFromRows(rows : number, fontSize : number) : number { + let dr = getMonoFontSize(fontSize); + return Math.ceil(dr.height*rows); } function cmdStatusIsRunning(status : string) : boolean { @@ -559,7 +564,7 @@ class ScreenWindow { loadImageRenderer(imageDivElem : any, line : LineType, cmd : Cmd) : ImageRendererModel { let cmdId = cmd.cmdId; let context = {sessionId: this.sessionId, screenId: this.screenId, windowId: this.windowId, cmdId: cmdId, lineId : line.lineid, lineNum: line.linenum}; - let imageModel = new ImageRendererModel(imageDivElem, context, cmd.getTermOpts(), !cmd.isRunning()); + let imageModel = new ImageRendererModel(imageDivElem, context, cmd.getTermOpts(), !cmd.isRunning(), GlobalModel.termFontSize.get()); this.renderers[cmdId] = imageModel; return imageModel; } @@ -571,7 +576,7 @@ class ScreenWindow { console.log("term-wrap already exists for", this.screenId, this.windowId, cmdId); return; } - let cols = windowWidthToCols(width); + let cols = windowWidthToCols(width, GlobalModel.termFontSize.get()); let usedRows = GlobalModel.getTUR(this.sessionId, cmdId, cols); if (line.contentheight != null && line.contentheight != -1) { usedRows = line.contentheight; @@ -586,6 +591,7 @@ class ScreenWindow { focusHandler: (focus : boolean) => this.setTermFocus(line.linenum, focus), isRunning: cmd.isRunning(), customKeyHandler: this.termCustomKeyHandler.bind(this), + fontSize: GlobalModel.termFontSize.get(), }); this.renderers[cmdId] = termWrap; if ((this.focusType.get() == "cmd" || this.focusType.get() == "cmd-fg") && this.selectedLine.get() == line.linenum) { @@ -612,7 +618,7 @@ class ScreenWindow { } let termWrap = this.getRenderer(cmd.cmdId); if (termWrap == null) { - let cols = windowWidthToCols(width); + let cols = windowWidthToCols(width, GlobalModel.termFontSize.get()); let usedRows = GlobalModel.getTUR(this.sessionId, cmd.cmdId, cols); if (usedRows != null) { return usedRows; @@ -1535,6 +1541,7 @@ class InputModel { keyHandler: (e, termWrap) => { this.termKeyHandler(remoteId, e, termWrap)}, focusHandler: this.setRemoteTermWrapFocus.bind(this), isRunning: true, + fontSize: GlobalModel.termFontSize.get(), }); } } @@ -1827,6 +1834,7 @@ class Model { authKey : string; isDev : boolean; activeMainView : OV<"session" | "history" | "bookmarks"> = mobx.observable.box("session", {name: "activeMainView"}); + termFontSize : OV = mobx.observable.box(DefaultTermFontSize, {name: "termFontSize"}); inputModel : InputModel; bookmarksModel : BookmarksModel; @@ -1863,6 +1871,18 @@ class Model { return ProdServerEndpoint; } + setTermFontSize(fontSize : number) { + if (fontSize < MinFontSize) { + fontSize = MinFontSize; + } + if (fontSize > MaxFontSize) { + fontSize = MaxFontSize; + } + mobx.action(() => { + this.termFontSize.set(fontSize); + })(); + } + getBaseWsHostPort() : string { if (this.isDev) { return DevServerWsEndpoint; @@ -2749,12 +2769,11 @@ let GlobalCommandRunner : CommandRunner = null; if ((window as any).GlobalModel == null) { (window as any).GlobalModel = new Model(); (window as any).GlobalCommandRunner = new CommandRunner(); + (window as any).getMonoFontSize = getMonoFontSize; } GlobalModel = (window as any).GlobalModel; GlobalCommandRunner = (window as any).GlobalCommandRunner; -window.measureText = measureText; - export {Model, Session, Window, GlobalModel, GlobalCommandRunner, Cmd, Screen, ScreenWindow, riToRPtr, windowWidthToCols, windowHeightToRows, termWidthFromCols, termHeightFromRows, getPtyData, getRemotePtyData}; diff --git a/src/term.ts b/src/term.ts index f0f55bf7..e3707631 100644 --- a/src/term.ts +++ b/src/term.ts @@ -29,6 +29,7 @@ type TermWrapOpts = { dataHandler? : (data : string, termWrap : TermWrap) => void, isRunning : boolean, customKeyHandler? : (event : any, termWrap : TermWrap) => boolean, + fontSize: number, }; // cmd-instance @@ -48,6 +49,7 @@ class TermWrap { termSize : TermWinSize; focusHandler : (focus : boolean) => void; isRunning : boolean; + fontSize : number; constructor(elem : Element, opts : TermWrapOpts) { opts = opts ?? ({} as any); @@ -57,6 +59,7 @@ class TermWrap { this.winSize = opts.winSize; this.focusHandler = opts.focusHandler; this.isRunning = opts.isRunning; + this.fontSize = opts.fontSize; if (this.flexRows) { this.atRowMax = false; this.usedRows = mobx.observable.box(opts.usedRows ?? (opts.isRunning ? 1 : 0), {name: "term-usedrows"}); @@ -69,13 +72,13 @@ class TermWrap { this.termSize = {rows: opts.termOpts.rows, cols: opts.termOpts.cols}; } else { - let cols = windowWidthToCols(opts.winSize.width); + let cols = windowWidthToCols(opts.winSize.width, opts.fontSize); this.termSize = {rows: opts.termOpts.rows, cols: cols}; } let theme = { foreground: "#d3d7cf", }; - this.terminal = new Terminal({rows: this.termSize.rows, cols: this.termSize.cols, fontSize: 12, fontFamily: "JetBrains Mono", theme: theme}); + this.terminal = new Terminal({rows: this.termSize.rows, cols: this.termSize.cols, fontSize: opts.fontSize, fontFamily: "JetBrains Mono", theme: theme}); this.terminal._core._inputHandler._parser.setErrorHandler((state) => { this.numParseErrors++; return state; @@ -238,8 +241,8 @@ class TermWrap { } resizeWindow(size : WindowSize) : void { - let cols = windowWidthToCols(size.width); - let rows = windowHeightToRows(size.height); + let cols = windowWidthToCols(size.width, this.fontSize); + let rows = windowHeightToRows(size.height, this.fontSize); this.resize({rows, cols}); } diff --git a/src/textmeasure.ts b/src/textmeasure.ts index bf8b909b..7e6eb405 100644 --- a/src/textmeasure.ts +++ b/src/textmeasure.ts @@ -1,4 +1,17 @@ -let canvasElem = document.createElement("canvas"); +let MonoFontSizes : {height : number, width : number}[] = []; + +MonoFontSizes[8] = {height: 11, width: 4.797}; +MonoFontSizes[9] = {height: 12, width: 5.398}; +MonoFontSizes[10] = {height: 13, width: 6}; +MonoFontSizes[11] = {height: 15, width: 6.602}; +MonoFontSizes[12] = {height: 16, width: 7.203}; +MonoFontSizes[13] = {height: 18, width: 7.797}; +MonoFontSizes[14] = {height: 19, width: 8.398}; +MonoFontSizes[15] = {height: 20, width: 9}; + +function getMonoFontSize(fontSize : number) : {height : number, width : number} { + return MonoFontSizes[fontSize]; +} function measureText(text : string, textOpts? : {pre? : boolean, mono? : boolean, fontSize? : number|string}) : DOMRect { if (textOpts == null) { @@ -28,4 +41,4 @@ function measureText(text : string, textOpts? : {pre? : boolean, mono? : boolean return measureDiv.getBoundingClientRect() } -export {measureText}; +export {measureText, getMonoFontSize};