From 8f9ccd49e912a06eeaecab6b34e133af623bc2e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr> Date: Mon, 13 Nov 2023 15:36:25 +0100 Subject: [PATCH] [ivette/controller] auto-scrolling --- ivette/src/renderer/Controller.tsx | 52 +++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/ivette/src/renderer/Controller.tsx b/ivette/src/renderer/Controller.tsx index 4f6638e793a..c25aaf08e20 100644 --- a/ivette/src/renderer/Controller.tsx +++ b/ivette/src/renderer/Controller.tsx @@ -33,6 +33,7 @@ import * as Toolbars from 'dome/frame/toolbars'; import { IconButton } from 'dome/controls/buttons'; import { LED, LEDstatus } from 'dome/controls/displays'; import { Label, Code } from 'dome/controls/labels'; +import * as Text from 'dome/text/richtext'; import { TextBuffer, TextView } from 'dome/text/richtext'; import { resolve } from 'dome/system'; @@ -229,25 +230,41 @@ const RenderConsole = (): JSX.Element => { const [cursor, setCursor] = React.useState(-1); const [isEmpty, setEmpty] = React.useState(true); const [noTrash, setNoTrash] = React.useState(true); + const [scrolling, setScrolling] = React.useState(true); const [history, setHistory] = useHistory(); const [maxLines] = Settings.useGlobalSettings(Preferences.ConsoleScrollback); + const edited = 0 <= cursor; const headCmd = history[0]; + const onVisible = React.useCallback((s: Text.Selection) => { + if (!edited) { + const { offset, length } = Server.buffer.range(); + const endOfBuffer = offset + length; + const endOfViewport = s.offset + s.length; + setScrolling(endOfViewport >= endOfBuffer); + } + }, [edited, setScrolling]); + + const flipScrolling = React.useCallback(() => setScrolling((s) => !s), []); + const onChanged = React.useCallback(() => { - if (cursor < 0) { + if (edited) { + const cmd = editor.toString().trim(); + setEmpty(cmd === ''); + setNoTrash((noTrash) => noTrash && cmd === headCmd); + } else { const { length, toLine: lines } = Server.buffer.range(); if (lines > maxLines) { const cut = Server.buffer.lineRange(lines - maxLines + 1); Server.buffer.replaceContents({ offset: 0, length: cut.offset }); - Server.buffer.scrollTo({ offset: length - cut.offset, length: 0 }); - } else - Server.buffer.scrollTo({ offset: length, length: 0 }); - } else { - const cmd = editor.toString().trim(); - setEmpty(cmd === ''); - setNoTrash((noTrash) => noTrash && cmd === headCmd); + if (scrolling) + Server.buffer.scrollTo({ offset: length - cut.offset, length: 0 }); + } else { + if (scrolling) + Server.buffer.scrollTo({ offset: length, length: 0 }); + } } - }, [cursor, maxLines, headCmd]); + }, [scrolling, edited, maxLines, headCmd]); const doReload = (): void => { const cfg = Server.getConfig(); @@ -261,11 +278,12 @@ const RenderConsole = (): JSX.Element => { }; const doSwitch = (): void => { - if (cursor < 0) doReload(); - else { + if (edited) { editor.clear(); scratch.current = []; setCursor(-1); + } else { + doReload(); } }; @@ -275,6 +293,7 @@ const RenderConsole = (): JSX.Element => { setHistory(hst); setCursor(-1); editor.clear(); + setScrolling(true); Server.setConfig(cfg); Server.restart(); }; @@ -310,7 +329,6 @@ const RenderConsole = (): JSX.Element => { const doPrev = doMove(cursor + 1); const doNext = doMove(cursor - 1); - const edited = 0 <= cursor; const n = history.length; return ( @@ -364,11 +382,21 @@ const RenderConsole = (): JSX.Element => { onClick={doSwitch} title="Toggle command line editing" /> + <IconButton + icon="MEDIA.NEXT" + disabled={edited} + selected={scrolling} + onClick={flipScrolling} + title="Auto scrolling" + /> </Ivette.TitleBar> <TextView text={edited ? editor : Server.buffer} readOnly={!edited} onChange={onChanged} + onViewport={onVisible} + onSelection={onVisible} + showCurrentLine={!scrolling} /> </> ); -- GitLab