mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-19 03:33:56 +00:00
Allow detaching from autoscroll
This commit is contained in:
@@ -136,3 +136,9 @@ button.fancy.bg-secondary:hover {
|
||||
.terminal-dark-gray {
|
||||
color: rgb(81, 81, 81);
|
||||
}
|
||||
|
||||
.terminal-glass {
|
||||
box-shadow: 0px 0px 15px 4px rgba(255, 255, 255, 0.04);
|
||||
backdrop-filter: blur(6px) brightness(0.8) saturate(1.3);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
.emulation-summary {
|
||||
box-shadow: 0px 0px 15px 4px rgba(255, 255, 255, 0.04);
|
||||
/*border: 1px solid rgba(255, 255, 255, 0.2);*/
|
||||
backdrop-filter: blur(7px) brightness(0.8) saturate(1.3);
|
||||
}
|
||||
@@ -2,8 +2,6 @@ import { EmulationStatus } from "@/emulator";
|
||||
import { TextTooltip } from "./text-tooltip";
|
||||
import { BarChartSteps, CpuFill, FloppyFill } from "react-bootstrap-icons";
|
||||
|
||||
import "./emulation-summary.css";
|
||||
|
||||
export interface EmulationSummaryProps {
|
||||
status?: EmulationStatus;
|
||||
}
|
||||
@@ -28,7 +26,7 @@ export function EmulationSummary(props: EmulationSummaryProps) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="emulation-summary items-center absolute z-49 right-0 m-6 rounded-xl min-w-[150px] p-3 text-whtie cursor-default font-medium text-right text-sm whitespace-nowrap leading-6 font-mono">
|
||||
<div className="emulation-summary terminal-glass items-center absolute z-49 right-0 m-6 rounded-xl min-w-[150px] p-3 text-white cursor-default font-medium text-right text-sm whitespace-nowrap leading-6 font-mono">
|
||||
<TextTooltip tooltip={"Active threads"}>
|
||||
{props.status.activeThreads}
|
||||
<BarChartSteps className="inline ml-3" />
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import React from "react";
|
||||
import {
|
||||
List,
|
||||
ListImperativeAPI,
|
||||
useListRef,
|
||||
type RowComponentProps,
|
||||
} from "react-window";
|
||||
import { List, ListImperativeAPI, type RowComponentProps } from "react-window";
|
||||
import { ArrowDown } from "react-bootstrap-icons";
|
||||
import { Button } from "./ui/button";
|
||||
|
||||
interface OutputProps {}
|
||||
|
||||
@@ -26,6 +23,7 @@ interface FullOutputState extends OutputState {
|
||||
height: number;
|
||||
width: number;
|
||||
state: SizeState;
|
||||
autoScroll: boolean;
|
||||
}
|
||||
|
||||
interface LogLine {
|
||||
@@ -182,6 +180,7 @@ export class Output extends React.Component<OutputProps, FullOutputState> {
|
||||
private outputRef: React.RefObject<HTMLDivElement | null>;
|
||||
private listRef: React.RefObject<ListImperativeAPI | null>;
|
||||
private resizeObserver: ResizeObserver;
|
||||
private scrollElement: HTMLDivElement | null | undefined;
|
||||
|
||||
constructor(props: OutputProps) {
|
||||
super(props);
|
||||
@@ -189,6 +188,7 @@ export class Output extends React.Component<OutputProps, FullOutputState> {
|
||||
this.clear = this.clear.bind(this);
|
||||
this.logLine = this.logLine.bind(this);
|
||||
this.logLines = this.logLines.bind(this);
|
||||
this.handleScroll = this.handleScroll.bind(this);
|
||||
this.updateDimensions = this.updateDimensions.bind(this);
|
||||
|
||||
this.outputRef = React.createRef();
|
||||
@@ -202,6 +202,7 @@ export class Output extends React.Component<OutputProps, FullOutputState> {
|
||||
height: 10,
|
||||
width: 10,
|
||||
state: SizeState.Final,
|
||||
autoScroll: true,
|
||||
};
|
||||
|
||||
this.state.grouper.handler = (lines: string[]) => {
|
||||
@@ -209,28 +210,65 @@ export class Output extends React.Component<OutputProps, FullOutputState> {
|
||||
};
|
||||
}
|
||||
|
||||
handleScroll(e: Event) {
|
||||
const threshold = 40;
|
||||
const element = e.target as HTMLElement;
|
||||
const { scrollTop, scrollHeight, clientHeight } = element;
|
||||
const isAtEnd = scrollTop + clientHeight >= scrollHeight - threshold;
|
||||
|
||||
this.setState({ autoScroll: isAtEnd });
|
||||
}
|
||||
|
||||
unregisterScrollListener() {
|
||||
this.scrollElement?.removeEventListener("scroll", this.handleScroll);
|
||||
}
|
||||
|
||||
registerScrollListener(element: HTMLDivElement | null | undefined) {
|
||||
if (element == this.scrollElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.unregisterScrollListener();
|
||||
this.scrollElement = element;
|
||||
element?.addEventListener("scroll", this.handleScroll);
|
||||
}
|
||||
|
||||
registerScrollOnList() {
|
||||
this.registerScrollListener(this.listRef.current?.element);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.updateDimensions();
|
||||
|
||||
if (this.outputRef.current) {
|
||||
this.resizeObserver.observe(this.outputRef.current);
|
||||
}
|
||||
|
||||
this.registerScrollOnList();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.resizeObserver.disconnect();
|
||||
this.unregisterScrollListener();
|
||||
}
|
||||
|
||||
scrollListToEnd() {
|
||||
if (this.listRef.current && this.state.lines.length > 0) {
|
||||
this.listRef.current.scrollToRow({ index: this.state.lines.length - 1 });
|
||||
}
|
||||
|
||||
this.setState({ autoScroll: true });
|
||||
}
|
||||
|
||||
componentDidUpdate(_: OutputProps, prevState: FullOutputState) {
|
||||
if (
|
||||
!this.listRef.current ||
|
||||
this.state.lines.length == 0 ||
|
||||
prevState.lines.length == this.state.lines.length
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.registerScrollOnList();
|
||||
|
||||
this.listRef.current.scrollToRow({ index: this.state.lines.length - 1 });
|
||||
if (
|
||||
this.state.autoScroll &&
|
||||
prevState.lines.length != this.state.lines.length
|
||||
) {
|
||||
this.scrollListToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
@@ -292,6 +330,20 @@ export class Output extends React.Component<OutputProps, FullOutputState> {
|
||||
rowHeight={20}
|
||||
style={{ height: this.state.height, width: this.state.width }}
|
||||
/>
|
||||
|
||||
{this.state.autoScroll ? (
|
||||
<></>
|
||||
) : (
|
||||
<Button
|
||||
className="absolute bottom-6 right-6 z-50 terminal-glass"
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
this.scrollListToEnd();
|
||||
}}
|
||||
>
|
||||
<ArrowDown />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user