diff --git a/src/app/line/lines.less b/src/app/line/lines.less index 33da44989..66ebfc7e7 100644 --- a/src/app/line/lines.less +++ b/src/app/line/lines.less @@ -467,7 +467,7 @@ display: flex; flex-direction: column; overflow: auto; - padding: 10px 0; + padding: 0 0 10px 0; flex-grow: 1; position: relative; diff --git a/src/app/magiclayout.ts b/src/app/magiclayout.ts new file mode 100644 index 000000000..df8c90daf --- /dev/null +++ b/src/app/magiclayout.ts @@ -0,0 +1,34 @@ +// Copyright 2023, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +// magical layout constants to power TypeScript calculations +// these need to match the CSS (usually margins, paddings, positions, etc.) +let MagicLayout = { + CmdInputHeight: 92, // height of full cmd-input div + CmdInputBottom: 12, // .cmd-input + + LineHeaderHeight: 46, // .line-header + LinePadding: 24, // .line-header (12px * 2) + WindowHeightOffset: 6, // .window-view, height is calc(100%-0.5rem) + LinesBottomPadding: 10, // .lines, padding + LineMarginTop: 12, // .line, margin + + ScreenMaxContentWidthBuffer: 50, + ScreenMaxContentHeightBuffer: 0, // calc below + ScreenMinContentSize: 100, + ScreenMaxContentSize: 5000, + + // the 3 is for descenders, which get cut off in the terminal without this + TermDescendersHeight: 3, + TermWidthBuffer: 15, + +}; + +let m = MagicLayout; + +// add up all the line overhead + padding. subtract 2 so we don't see the border of neighboring line +m.ScreenMaxContentHeightBuffer = m.LineHeaderHeight + m.LinePadding + m.WindowHeightOffset + m.LinesBottomPadding + m.LineMarginTop - 2; + +window.MagicLayout = MagicLayout; + +export { MagicLayout }; diff --git a/src/app/workspace/cmdinput/cmdInput.less b/src/app/workspace/cmdinput/cmdInput.less index 772db8b22..6b5c63c07 100644 --- a/src/app/workspace/cmdinput/cmdInput.less +++ b/src/app/workspace/cmdinput/cmdInput.less @@ -6,10 +6,11 @@ display: flex; flex-direction: column; position: absolute; - bottom: 16px; - right: 16px; - width: calc(100% - 28px); + bottom: 12px; + right: 12px; + width: calc(100% - 24px); padding: 12px; + padding-bottom: 6px; z-index: 100; background: @background-session-components; box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.5), 0px 3px 8px 0px rgba(0, 0, 0, 0.35), diff --git a/src/app/workspace/screen/screenview.less b/src/app/workspace/screen/screenview.less index 275b93e10..aa88b389d 100644 --- a/src/app/workspace/screen/screenview.less +++ b/src/app/workspace/screen/screenview.less @@ -11,7 +11,7 @@ flex-direction: column; position: absolute; width: 100%; - height: calc(100% - 3em); + height: calc(100% - 0.5rem); overflow-x: hidden; .rendermode-tag { diff --git a/src/app/workspace/workspace.less b/src/app/workspace/workspace.less index 565a4639f..f8d4777a3 100644 --- a/src/app/workspace/workspace.less +++ b/src/app/workspace/workspace.less @@ -12,8 +12,8 @@ background: @background-session; border: 1px solid @base-border; border-radius: 8px; - margin-bottom: 1em; transition: width 0.2s ease; + margin-bottom: 0.5em; } .collapsed + .session-view { max-width: calc(100% - 6.7em); diff --git a/src/app/workspace/workspaceview.tsx b/src/app/workspace/workspaceview.tsx index 9816ee7ef..d98685936 100644 --- a/src/app/workspace/workspaceview.tsx +++ b/src/app/workspace/workspaceview.tsx @@ -12,6 +12,7 @@ import { CmdInput } from "./cmdinput/cmdinput"; import { ScreenView } from "./screen/screenview"; import { ScreenTabs } from "./screen/tabs"; import { ErrorBoundary } from "../../app/common/error/errorboundary"; +import { MagicLayout } from "../magiclayout"; import "./workspace.less"; dayjs.extend(localizedFormat); @@ -29,8 +30,9 @@ class WorkspaceView extends React.Component<{}, {}> { let activeScreen = session.getActiveScreen(); let cmdInputHeight = model.inputModel.cmdInputHeight.get(); if (cmdInputHeight == 0) { - cmdInputHeight = 110; + cmdInputHeight = MagicLayout.CmdInputHeight; // this is the base size of cmdInput (measured using devtools) } + cmdInputHeight += MagicLayout.CmdInputBottom; // reference to .cmd-input, bottom: 12px let isHidden = GlobalModel.activeMainView.get() != "session"; return ( @@ -38,7 +40,7 @@ class WorkspaceView extends React.Component<{}, {}> { -
+
diff --git a/src/electron/emain.ts b/src/electron/emain.ts index 5c9c581f0..527bad306 100644 --- a/src/electron/emain.ts +++ b/src/electron/emain.ts @@ -339,7 +339,7 @@ function mainResizeHandler(e, win) { return; } let bounds = win.getBounds(); - console.log("resize/move", win.getBounds()); + // console.log("resize/move", win.getBounds()); let winSize = { width: bounds.width, height: bounds.height, top: bounds.y, left: bounds.x }; let url = getBaseHostPort() + "/api/set-winsize"; let fetchHeaders = getFetchHeaders(); diff --git a/src/model/model.ts b/src/model/model.ts index fc8f73b3e..b259f9b6a 100644 --- a/src/model/model.ts +++ b/src/model/model.ts @@ -76,6 +76,7 @@ import localizedFormat from "dayjs/plugin/localizedFormat"; import customParseFormat from "dayjs/plugin/customParseFormat"; import { getRendererContext, cmdStatusIsRunning } from "../app/line/lineutil"; import { sortAndFilterRemotes } from "../util/util"; +import { MagicLayout } from "../app/magiclayout"; dayjs.extend(customParseFormat); dayjs.extend(localizedFormat); @@ -644,10 +645,11 @@ class Screen { let height = termHeightFromRows(25, GlobalModel.termFontSize.get()); return { width, height }; } - // TODO calculate these sizes more deliberately let winSize = this.lastScreenSize; - let width = boundInt(winSize.width - 50, 100, 5000); - let height = boundInt(winSize.height - 120, 100, 5000); + let minSize = MagicLayout.ScreenMinContentSize; + let maxSize = MagicLayout.ScreenMaxContentSize; + let width = boundInt(winSize.width - MagicLayout.ScreenMaxContentWidthBuffer, minSize, maxSize); + let height = boundInt(winSize.height - MagicLayout.ScreenMaxContentHeightBuffer, minSize, maxSize); return { width, height }; } diff --git a/src/plugins/image/image.tsx b/src/plugins/image/image.tsx index 24b12d615..5859577b4 100644 --- a/src/plugins/image/image.tsx +++ b/src/plugins/image/image.tsx @@ -11,23 +11,6 @@ import "./image.less"; type OV = mobx.IObservableValue; type CV = mobx.IComputedValue; -// ctor(RendererContext, RenderOpts, isDone); -// type RendererModel = { -// dispose : () => void, -// reload : (delayMs : number) => void, -// receiveData : (pos : number, data : Uint8Array, reason? : string) => void, -// cmdDone : () => void, -// resizeWindow : (size : WindowSize) => void, -// resizeCols : (cols : number) => void, -// giveFocus : () => void, -// getUsedRows : () => number, -// }; - -// two types of renderers -// JSON -// blob -// - @mobxReact.observer class SimpleImageRenderer extends React.Component< { data: Blob; context: RendererContext; opts: RendererOpts; savedHeight: number }, diff --git a/src/plugins/terminal/term.ts b/src/plugins/terminal/term.ts index 056e5ed94..38e0571c1 100644 --- a/src/plugins/terminal/term.ts +++ b/src/plugins/terminal/term.ts @@ -188,6 +188,10 @@ class TermWrap { let termNumLines = termBuf.lines.length; let termYPos = termBuf.y; if (termNumLines > term.rows) { + // TODO: there is a weird case here. for commands that output more than term.rows rows of output + // they get an "extra" blank line at the bottom because the cursor is positioned on the next line! + // hard problem to solve because the line is already written to the buffer. we only want to "fix" + // this when the command is no longer running. return term.rows; } let usedRows = this.isRunning ? 1 : 0; diff --git a/src/util/textmeasure.ts b/src/util/textmeasure.ts index e6f35b3f3..0c37e9706 100644 --- a/src/util/textmeasure.ts +++ b/src/util/textmeasure.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { boundInt } from "./util"; +import { MagicLayout } from "../app/magiclayout"; const MinTermCols = 10; const MaxTermCols = 1024; @@ -62,14 +63,14 @@ function measureText( function windowWidthToCols(width: number, fontSize: number): number { let dr = getMonoFontSize(fontSize); - let cols = Math.trunc((width - 50) / dr.width) - 1; + let cols = Math.trunc((width - MagicLayout.ScreenMaxContentWidthBuffer) / dr.width) - 1; cols = boundInt(cols, MinTermCols, MaxTermCols); return cols; } function windowHeightToRows(height: number, fontSize: number): number { let dr = getMonoFontSize(fontSize); - let rows = Math.floor((height - 80) / dr.height) - 1; + let rows = Math.floor((height - MagicLayout.ScreenMaxContentHeightBuffer) / dr.height) - 1; if (rows <= 0) { rows = 1; } @@ -78,13 +79,13 @@ function windowHeightToRows(height: number, fontSize: number): number { function termWidthFromCols(cols: number, fontSize: number): number { let dr = getMonoFontSize(fontSize); - return Math.ceil(dr.width * cols) + 15; + return Math.ceil(dr.width * cols) + MagicLayout.TermWidthBuffer; } function termHeightFromRows(rows: number, fontSize: number): number { let dr = getMonoFontSize(fontSize); - // TODO: replace the +3 with some calculation based on termFontSize. the +3 is for descenders, which get cut off without this. - return Math.ceil(dr.height * rows) + 3; + // TODO: replace the TermDescendersHeight with some calculation based on termFontSize. + return Math.ceil(dr.height * rows) + MagicLayout.TermDescendersHeight; } export { measureText, getMonoFontSize, windowWidthToCols, windowHeightToRows, termWidthFromCols, termHeightFromRows };