mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-13 06:16:33 +00:00
🤞 finalized the monitor UI
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
parent
29ebf055e6
commit
8c49c04359
@ -95,12 +95,12 @@ export class MonitorConnection {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Handles the `baudRate` changes by reconnecting if required.
|
// Handles the `baudRate` changes by reconnecting if required.
|
||||||
this.monitorModel.onChange(() => {
|
this.monitorModel.onChange(({ property }) => {
|
||||||
if (this.autoConnect && this.connected) {
|
if (property === 'baudRate' && this.autoConnect && this.connected) {
|
||||||
const { boardsConfig } = this.boardsServiceClient;
|
const { boardsConfig } = this.boardsServiceClient;
|
||||||
this.handleBoardConfigChange(boardsConfig);
|
this.handleBoardConfigChange(boardsConfig);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get connected(): boolean {
|
get connected(): boolean {
|
||||||
|
@ -15,7 +15,7 @@ export class MonitorModel implements FrontendApplicationContribution {
|
|||||||
@inject(BoardsServiceClientImpl)
|
@inject(BoardsServiceClientImpl)
|
||||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||||
|
|
||||||
protected readonly onChangeEmitter: Emitter<void>;
|
protected readonly onChangeEmitter: Emitter<MonitorModel.State.Change<keyof MonitorModel.State>>;
|
||||||
protected _autoscroll: boolean;
|
protected _autoscroll: boolean;
|
||||||
protected _timestamp: boolean;
|
protected _timestamp: boolean;
|
||||||
protected _baudRate: MonitorConfig.BaudRate;
|
protected _baudRate: MonitorConfig.BaudRate;
|
||||||
@ -26,7 +26,7 @@ export class MonitorModel implements FrontendApplicationContribution {
|
|||||||
this._timestamp = false;
|
this._timestamp = false;
|
||||||
this._baudRate = MonitorConfig.BaudRate.DEFAULT;
|
this._baudRate = MonitorConfig.BaudRate.DEFAULT;
|
||||||
this._lineEnding = MonitorModel.EOL.DEFAULT;
|
this._lineEnding = MonitorModel.EOL.DEFAULT;
|
||||||
this.onChangeEmitter = new Emitter<void>();
|
this.onChangeEmitter = new Emitter<MonitorModel.State.Change<keyof MonitorModel.State>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
onStart(): void {
|
onStart(): void {
|
||||||
@ -37,7 +37,7 @@ export class MonitorModel implements FrontendApplicationContribution {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get onChange(): Event<void> {
|
get onChange(): Event<MonitorModel.State.Change<keyof MonitorModel.State>> {
|
||||||
return this.onChangeEmitter.event;
|
return this.onChangeEmitter.event;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,6 +48,7 @@ export class MonitorModel implements FrontendApplicationContribution {
|
|||||||
toggleAutoscroll(): void {
|
toggleAutoscroll(): void {
|
||||||
this._autoscroll = !this._autoscroll;
|
this._autoscroll = !this._autoscroll;
|
||||||
this.storeState();
|
this.storeState();
|
||||||
|
this.storeState().then(() => this.onChangeEmitter.fire({ property: 'autoscroll', value: this._autoscroll }));
|
||||||
}
|
}
|
||||||
|
|
||||||
get timestamp(): boolean {
|
get timestamp(): boolean {
|
||||||
@ -56,7 +57,7 @@ export class MonitorModel implements FrontendApplicationContribution {
|
|||||||
|
|
||||||
toggleTimestamp(): void {
|
toggleTimestamp(): void {
|
||||||
this._timestamp = !this._timestamp;
|
this._timestamp = !this._timestamp;
|
||||||
this.storeState();
|
this.storeState().then(() => this.onChangeEmitter.fire({ property: 'timestamp', value: this._timestamp }));
|
||||||
}
|
}
|
||||||
|
|
||||||
get baudRate(): MonitorConfig.BaudRate {
|
get baudRate(): MonitorConfig.BaudRate {
|
||||||
@ -65,7 +66,7 @@ export class MonitorModel implements FrontendApplicationContribution {
|
|||||||
|
|
||||||
set baudRate(baudRate: MonitorConfig.BaudRate) {
|
set baudRate(baudRate: MonitorConfig.BaudRate) {
|
||||||
this._baudRate = baudRate;
|
this._baudRate = baudRate;
|
||||||
this.storeState().then(() => this.onChangeEmitter.fire(undefined));
|
this.storeState().then(() => this.onChangeEmitter.fire({ property: 'baudRate', value: this._baudRate }));
|
||||||
}
|
}
|
||||||
|
|
||||||
get lineEnding(): MonitorModel.EOL {
|
get lineEnding(): MonitorModel.EOL {
|
||||||
@ -74,7 +75,7 @@ export class MonitorModel implements FrontendApplicationContribution {
|
|||||||
|
|
||||||
set lineEnding(lineEnding: MonitorModel.EOL) {
|
set lineEnding(lineEnding: MonitorModel.EOL) {
|
||||||
this._lineEnding = lineEnding;
|
this._lineEnding = lineEnding;
|
||||||
this.storeState();
|
this.storeState().then(() => this.onChangeEmitter.fire({ property: 'lineEnding', value: this._lineEnding }));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected restoreState(state: MonitorModel.State) {
|
protected restoreState(state: MonitorModel.State) {
|
||||||
@ -82,7 +83,6 @@ export class MonitorModel implements FrontendApplicationContribution {
|
|||||||
this._timestamp = state.timestamp;
|
this._timestamp = state.timestamp;
|
||||||
this._baudRate = state.baudRate;
|
this._baudRate = state.baudRate;
|
||||||
this._lineEnding = state.lineEnding;
|
this._lineEnding = state.lineEnding;
|
||||||
this.onChangeEmitter.fire(undefined);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async storeState(): Promise<void> {
|
protected async storeState(): Promise<void> {
|
||||||
@ -104,6 +104,12 @@ export namespace MonitorModel {
|
|||||||
baudRate: MonitorConfig.BaudRate;
|
baudRate: MonitorConfig.BaudRate;
|
||||||
lineEnding: EOL;
|
lineEnding: EOL;
|
||||||
}
|
}
|
||||||
|
export namespace State {
|
||||||
|
export interface Change<K extends keyof State> {
|
||||||
|
readonly property: K;
|
||||||
|
readonly value: State[K];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type EOL = '' | '\n' | '\r' | '\r\n';
|
export type EOL = '' | '\n' | '\r' | '\r\n';
|
||||||
export namespace EOL {
|
export namespace EOL {
|
||||||
|
@ -59,13 +59,13 @@ export class MonitorViewContribution extends AbstractViewContribution<MonitorWid
|
|||||||
id: 'monitor-autoscroll',
|
id: 'monitor-autoscroll',
|
||||||
render: () => this.renderAutoScrollButton(),
|
render: () => this.renderAutoScrollButton(),
|
||||||
isVisible: widget => widget instanceof MonitorWidget,
|
isVisible: widget => widget instanceof MonitorWidget,
|
||||||
onDidChange: this.model.onChange
|
onDidChange: this.model.onChange as any // TODO: https://github.com/eclipse-theia/theia/pull/6696/
|
||||||
});
|
});
|
||||||
registry.registerItem({
|
registry.registerItem({
|
||||||
id: 'monitor-timestamp',
|
id: 'monitor-timestamp',
|
||||||
render: () => this.renderTimestampButton(),
|
render: () => this.renderTimestampButton(),
|
||||||
isVisible: widget => widget instanceof MonitorWidget,
|
isVisible: widget => widget instanceof MonitorWidget,
|
||||||
onDidChange: this.model.onChange
|
onDidChange: this.model.onChange as any // TODO: https://github.com/eclipse-theia/theia/pull/6696/
|
||||||
});
|
});
|
||||||
registry.registerItem({
|
registry.registerItem({
|
||||||
id: SerialMonitor.Commands.CLEAR_OUTPUT.id,
|
id: SerialMonitor.Commands.CLEAR_OUTPUT.id,
|
||||||
|
@ -88,7 +88,7 @@ export class MonitorWidget extends ReactWidget {
|
|||||||
value: ''
|
value: ''
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Newline',
|
label: 'New Line',
|
||||||
value: '\n'
|
value: '\n'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -99,7 +99,7 @@ export class MonitorWidget extends ReactWidget {
|
|||||||
label: 'Both NL & CR',
|
label: 'Both NL & CR',
|
||||||
value: '\r\n'
|
value: '\r\n'
|
||||||
}
|
}
|
||||||
]
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get baudRates(): OptionsType<SelectOption<MonitorConfig.BaudRate>> {
|
protected get baudRates(): OptionsType<SelectOption<MonitorConfig.BaudRate>> {
|
||||||
@ -111,28 +111,33 @@ export class MonitorWidget extends ReactWidget {
|
|||||||
const { baudRates, lineEndings } = this;
|
const { baudRates, lineEndings } = this;
|
||||||
const lineEnding = lineEndings.find(item => item.value === this.monitorModel.lineEnding) || lineEndings[1]; // Defaults to `\n`.
|
const lineEnding = lineEndings.find(item => item.value === this.monitorModel.lineEnding) || lineEndings[1]; // Defaults to `\n`.
|
||||||
const baudRate = baudRates.find(item => item.value === this.monitorModel.baudRate) || baudRates[4]; // Defaults to `9600`.
|
const baudRate = baudRates.find(item => item.value === this.monitorModel.baudRate) || baudRates[4]; // Defaults to `9600`.
|
||||||
return <div className='serial-monitor-container'>
|
return <div className='serial-monitor'>
|
||||||
<div className='head'>
|
<div className='head'>
|
||||||
<div className='send'>
|
<div className='send'>
|
||||||
<SerialMonitorSendField
|
<SerialMonitorSendInput
|
||||||
monitorConfig={this.monitorConnection.monitorConfig}
|
monitorConfig={this.monitorConnection.monitorConfig}
|
||||||
resolveFocus={this.onFocusResolved}
|
resolveFocus={this.onFocusResolved}
|
||||||
onSend={this.onSend} />
|
onSend={this.onSend} />
|
||||||
</div>
|
</div>
|
||||||
<div className='config'>
|
<div className='config'>
|
||||||
<ArduinoSelect
|
<div className='select'>
|
||||||
maxMenuHeight={this.widgetHeight - 40}
|
<ArduinoSelect
|
||||||
options={lineEndings}
|
maxMenuHeight={this.widgetHeight - 40}
|
||||||
defaultValue={lineEnding}
|
options={lineEndings}
|
||||||
onChange={this.onChangeLineEnding} />,
|
defaultValue={lineEnding}
|
||||||
<ArduinoSelect
|
onChange={this.onChangeLineEnding} />
|
||||||
maxMenuHeight={this.widgetHeight - 40}
|
</div>
|
||||||
options={baudRates}
|
<div className='select'>
|
||||||
defaultValue={baudRate}
|
<ArduinoSelect
|
||||||
onChange={this.onChangeBaudRate} />
|
className='select'
|
||||||
|
maxMenuHeight={this.widgetHeight - 40}
|
||||||
|
options={baudRates}
|
||||||
|
defaultValue={baudRate}
|
||||||
|
onChange={this.onChangeBaudRate} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id='serial-monitor-output-container'>
|
<div className='body'>
|
||||||
<SerialMonitorOutput
|
<SerialMonitorOutput
|
||||||
monitorModel={this.monitorModel}
|
monitorModel={this.monitorModel}
|
||||||
monitorServiceClient={this.monitorServiceClient}
|
monitorServiceClient={this.monitorServiceClient}
|
||||||
@ -157,7 +162,7 @@ export class MonitorWidget extends ReactWidget {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace SerialMonitorSendField {
|
export namespace SerialMonitorSendInput {
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly monitorConfig?: MonitorConfig;
|
readonly monitorConfig?: MonitorConfig;
|
||||||
readonly onSend: (text: string) => void;
|
readonly onSend: (text: string) => void;
|
||||||
@ -168,9 +173,9 @@ export namespace SerialMonitorSendField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SerialMonitorSendField extends React.Component<SerialMonitorSendField.Props, SerialMonitorSendField.State> {
|
export class SerialMonitorSendInput extends React.Component<SerialMonitorSendInput.Props, SerialMonitorSendInput.State> {
|
||||||
|
|
||||||
constructor(props: SerialMonitorSendField.Props) {
|
constructor(props: Readonly<SerialMonitorSendInput.Props>) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { value: '' };
|
this.state = { value: '' };
|
||||||
this.onChange = this.onChange.bind(this);
|
this.onChange = this.onChange.bind(this);
|
||||||
@ -235,6 +240,7 @@ export namespace SerialMonitorOutput {
|
|||||||
}
|
}
|
||||||
export interface State {
|
export interface State {
|
||||||
content: string;
|
content: string;
|
||||||
|
timestamp: boolean;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,7 +254,7 @@ export class SerialMonitorOutput extends React.Component<SerialMonitorOutput.Pro
|
|||||||
|
|
||||||
constructor(props: Readonly<SerialMonitorOutput.Props>) {
|
constructor(props: Readonly<SerialMonitorOutput.Props>) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { content: '' };
|
this.state = { content: '', timestamp: this.props.monitorModel.timestamp };
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): React.ReactNode {
|
render(): React.ReactNode {
|
||||||
@ -270,11 +276,17 @@ export class SerialMonitorOutput extends React.Component<SerialMonitorOutput.Pro
|
|||||||
if (eolIndex !== -1) {
|
if (eolIndex !== -1) {
|
||||||
const line = chunk.substring(0, eolIndex + 1);
|
const line = chunk.substring(0, eolIndex + 1);
|
||||||
chunk = chunk.slice(eolIndex + 1);
|
chunk = chunk.slice(eolIndex + 1);
|
||||||
const content = `${this.state.content}${false ? `${dateFormat(new Date(), 'H:M:ss.l')} -> ` : ''}${line}`;
|
const content = `${this.state.content}${this.state.timestamp ? `${dateFormat(new Date(), 'H:M:ss.l')} -> ` : ''}${line}`;
|
||||||
this.setState({ content });
|
this.setState({ content });
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
this.props.clearConsoleEvent(() => this.setState({ content: '' }))
|
this.props.clearConsoleEvent(() => this.setState({ content: '' })),
|
||||||
|
this.props.monitorModel.onChange(({ property }) => {
|
||||||
|
if (property === 'timestamp') {
|
||||||
|
const { timestamp } = this.props.monitorModel;
|
||||||
|
this.setState({ timestamp });
|
||||||
|
}
|
||||||
|
})
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +295,8 @@ export class SerialMonitorOutput extends React.Component<SerialMonitorOutput.Pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount(): void {
|
componentWillUnmount(): void {
|
||||||
this.toDisposeBeforeUnmount.dispose()
|
// TODO: "Your preferred browser's local storage is almost full." Discard `content` before saving layout?
|
||||||
|
this.toDisposeBeforeUnmount.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected scrollToBottom(): void {
|
protected scrollToBottom(): void {
|
||||||
|
@ -5,51 +5,49 @@
|
|||||||
background-position-x: 19px;
|
background-position-x: 19px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.serial-monitor-container {
|
.serial-monitor {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.serial-monitor-container .head {
|
.serial-monitor .head {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
background: var(--theia-layout-color0);
|
background: var(--theia-layout-color0);
|
||||||
height: 27px;
|
height: 27px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.serial-monitor-container .head .send {
|
.serial-monitor .head .send {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin-right: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.serial-monitor-container .head .send > input {
|
.serial-monitor .head .send > input {
|
||||||
line-height: var(--theia-content-line-height);
|
line-height: var(--theia-content-line-height);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.serial-monitor-container .head .send > input:focus {
|
.serial-monitor .head .send > input:focus {
|
||||||
border-color: var(--theia-accent-color3);
|
border-color: var(--theia-accent-color3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.serial-monitor-container .head .send > input.not-connected {
|
.serial-monitor .head .send > input.not-connected {
|
||||||
background-color: var(--theia-warn-color0);
|
background-color: var(--theia-warn-color0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.serial-monitor-container .head .send input#serial-monitor-send {
|
.serial-monitor .head .config {
|
||||||
color: var(--theia-ui-font-color1);
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.serial-monitor-container .head .config {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#serial-monitor-output-container {
|
.serial-monitor .head .config .select {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.serial-monitor .body {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 6px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-TabBar-toolbar .item.arduino-monitor {
|
.p-TabBar-toolbar .item.arduino-monitor {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user