Support toggled state in arduino toolbar items

fix hover state on toolbar items

Improved statemanagement for ToolbarItem and Menus

Disable Upload buttons while a sketch upload is already in progress

toggled state to have override disabled button opacity

doublecheck internal status before verify/upload a sketch

fixes after code review
This commit is contained in:
Francesco Stasi 2021-03-09 14:47:41 +01:00 committed by Francesco Stasi
parent 6dadd1775a
commit 1e0f52bbdd
5 changed files with 85 additions and 11 deletions

View File

@ -414,11 +414,20 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
id: 'arduino.toolbar.hoverBackground', id: 'arduino.toolbar.hoverBackground',
defaults: { defaults: {
dark: 'button.hoverBackground', dark: 'button.hoverBackground',
light: 'button.hoverBackground', light: 'button.foreground',
hc: 'activityBar.inactiveForeground' hc: 'textLink.foreground'
}, },
description: 'Background color of the toolbar items when hovering over them. Such as Upload, Verify, etc.' description: 'Background color of the toolbar items when hovering over them. Such as Upload, Verify, etc.'
}, },
{
id: 'arduino.toolbar.toggleBackground',
defaults: {
dark: 'editor.selectionBackground',
light: 'editor.selectionBackground',
hc: 'textPreformat.foreground'
},
description: 'Toggle color of the toolbar items when they are currently toggled (the command is in progress)'
},
{ {
id: 'arduino.output.foreground', id: 'arduino.output.foreground',
defaults: { defaults: {

View File

@ -1,4 +1,5 @@
import { inject, injectable } from 'inversify'; import { inject, injectable } from 'inversify';
import { Emitter } from '@theia/core/lib/common/event';
import { CoreService } from '../../common/protocol'; import { CoreService } from '../../common/protocol';
import { ArduinoMenus } from '../menu/arduino-menus'; import { ArduinoMenus } from '../menu/arduino-menus';
import { ArduinoToolbar } from '../toolbar/arduino-toolbar'; import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
@ -22,15 +23,24 @@ export class UploadSketch extends SketchContribution {
@inject(BoardsServiceProvider) @inject(BoardsServiceProvider)
protected readonly boardsServiceClientImpl: BoardsServiceProvider; protected readonly boardsServiceClientImpl: BoardsServiceProvider;
protected readonly onDidChangeEmitter = new Emitter<Readonly<void>>();
readonly onDidChange = this.onDidChangeEmitter.event;
protected uploadInProgress = false;
registerCommands(registry: CommandRegistry): void { registerCommands(registry: CommandRegistry): void {
registry.registerCommand(UploadSketch.Commands.UPLOAD_SKETCH, { registry.registerCommand(UploadSketch.Commands.UPLOAD_SKETCH, {
execute: () => this.uploadSketch() execute: () => this.uploadSketch(),
isEnabled: () => !this.uploadInProgress,
}); });
registry.registerCommand(UploadSketch.Commands.UPLOAD_SKETCH_USING_PROGRAMMER, { registry.registerCommand(UploadSketch.Commands.UPLOAD_SKETCH_USING_PROGRAMMER, {
execute: () => this.uploadSketch(true) execute: () => this.uploadSketch(true),
isEnabled: () => !this.uploadInProgress,
}); });
registry.registerCommand(UploadSketch.Commands.UPLOAD_SKETCH_TOOLBAR, { registry.registerCommand(UploadSketch.Commands.UPLOAD_SKETCH_TOOLBAR, {
isVisible: widget => ArduinoToolbar.is(widget) && widget.side === 'left', isVisible: widget => ArduinoToolbar.is(widget) && widget.side === 'left',
isEnabled: () => !this.uploadInProgress,
isToggled: () => this.uploadInProgress,
execute: () => registry.executeCommand(UploadSketch.Commands.UPLOAD_SKETCH.id) execute: () => registry.executeCommand(UploadSketch.Commands.UPLOAD_SKETCH.id)
}); });
} }
@ -64,11 +74,22 @@ export class UploadSketch extends SketchContribution {
id: UploadSketch.Commands.UPLOAD_SKETCH_TOOLBAR.id, id: UploadSketch.Commands.UPLOAD_SKETCH_TOOLBAR.id,
command: UploadSketch.Commands.UPLOAD_SKETCH_TOOLBAR.id, command: UploadSketch.Commands.UPLOAD_SKETCH_TOOLBAR.id,
tooltip: 'Upload', tooltip: 'Upload',
priority: 1 priority: 1,
onDidChange: this.onDidChange
}); });
} }
async uploadSketch(usingProgrammer: boolean = false): Promise<void> { async uploadSketch(usingProgrammer: boolean = false): Promise<void> {
// even with buttons disabled, better to double check if an upload is already in progress
if (this.uploadInProgress) {
return;
}
// toggle the toolbar button and menu item state.
// uploadInProgress will be set to false whether the upload fails or not
this.uploadInProgress = true;
this.onDidChangeEmitter.fire();
const sketch = await this.sketchServiceClient.currentSketch(); const sketch = await this.sketchServiceClient.currentSketch();
if (!sketch) { if (!sketch) {
return; return;
@ -131,6 +152,9 @@ export class UploadSketch extends SketchContribution {
} catch (e) { } catch (e) {
this.messageService.error(e.toString()); this.messageService.error(e.toString());
} finally { } finally {
this.uploadInProgress = false;
this.onDidChangeEmitter.fire();
if (monitorConfig) { if (monitorConfig) {
const { board, port } = monitorConfig; const { board, port } = monitorConfig;
try { try {

View File

@ -1,4 +1,5 @@
import { inject, injectable } from 'inversify'; import { inject, injectable } from 'inversify';
import { Emitter } from '@theia/core/lib/common/event';
import { CoreService } from '../../common/protocol'; import { CoreService } from '../../common/protocol';
import { ArduinoMenus } from '../menu/arduino-menus'; import { ArduinoMenus } from '../menu/arduino-menus';
import { ArduinoToolbar } from '../toolbar/arduino-toolbar'; import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
@ -18,15 +19,24 @@ export class VerifySketch extends SketchContribution {
@inject(BoardsServiceProvider) @inject(BoardsServiceProvider)
protected readonly boardsServiceClientImpl: BoardsServiceProvider; protected readonly boardsServiceClientImpl: BoardsServiceProvider;
protected readonly onDidChangeEmitter = new Emitter<Readonly<void>>();
readonly onDidChange = this.onDidChangeEmitter.event;
protected verifyInProgress = false;
registerCommands(registry: CommandRegistry): void { registerCommands(registry: CommandRegistry): void {
registry.registerCommand(VerifySketch.Commands.VERIFY_SKETCH, { registry.registerCommand(VerifySketch.Commands.VERIFY_SKETCH, {
execute: () => this.verifySketch() execute: () => this.verifySketch(),
isEnabled: () => !this.verifyInProgress,
}); });
registry.registerCommand(VerifySketch.Commands.EXPORT_BINARIES, { registry.registerCommand(VerifySketch.Commands.EXPORT_BINARIES, {
execute: () => this.verifySketch(true) execute: () => this.verifySketch(true),
isEnabled: () => !this.verifyInProgress,
}); });
registry.registerCommand(VerifySketch.Commands.VERIFY_SKETCH_TOOLBAR, { registry.registerCommand(VerifySketch.Commands.VERIFY_SKETCH_TOOLBAR, {
isVisible: widget => ArduinoToolbar.is(widget) && widget.side === 'left', isVisible: widget => ArduinoToolbar.is(widget) && widget.side === 'left',
isEnabled: () => !this.verifyInProgress,
isToggled: () => this.verifyInProgress,
execute: () => registry.executeCommand(VerifySketch.Commands.VERIFY_SKETCH.id) execute: () => registry.executeCommand(VerifySketch.Commands.VERIFY_SKETCH.id)
}); });
} }
@ -60,12 +70,24 @@ export class VerifySketch extends SketchContribution {
id: VerifySketch.Commands.VERIFY_SKETCH_TOOLBAR.id, id: VerifySketch.Commands.VERIFY_SKETCH_TOOLBAR.id,
command: VerifySketch.Commands.VERIFY_SKETCH_TOOLBAR.id, command: VerifySketch.Commands.VERIFY_SKETCH_TOOLBAR.id,
tooltip: 'Verify', tooltip: 'Verify',
priority: 0 priority: 0,
onDidChange: this.onDidChange
}); });
} }
async verifySketch(exportBinaries?: boolean): Promise<void> { async verifySketch(exportBinaries?: boolean): Promise<void> {
// even with buttons disabled, better to double check if a verify is already in progress
if (this.verifyInProgress) {
return;
}
// toggle the toolbar button and menu item state.
// verifyInProgress will be set to false whether the compilation fails or not
this.verifyInProgress = true;
this.onDidChangeEmitter.fire();
const sketch = await this.sketchServiceClient.currentSketch(); const sketch = await this.sketchServiceClient.currentSketch();
if (!sketch) { if (!sketch) {
return; return;
} }
@ -90,6 +112,9 @@ export class VerifySketch extends SketchContribution {
this.messageService.info('Done compiling.', { timeout: 1000 }); this.messageService.info('Done compiling.', { timeout: 1000 });
} catch (e) { } catch (e) {
this.messageService.error(e.toString()); this.messageService.error(e.toString());
} finally {
this.verifyInProgress = false;
this.onDidChangeEmitter.fire();
} }
} }

View File

@ -15,8 +15,8 @@
background: var(--theia-arduino-toolbar-background); background: var(--theia-arduino-toolbar-background);
} }
.p-TabBar-toolbar .item.arduino-tool-item > div:hover { .p-TabBar-toolbar .item.arduino-tool-item.enabled:hover > div {
background: (--theia-arduino-toolbar-hoverBackground); background: var(--theia-arduino-toolbar-hoverBackground);
} }
.arduino-verify-sketch--toolbar, .arduino-verify-sketch--toolbar,
@ -24,6 +24,16 @@
border-radius: 12px; border-radius: 12px;
} }
.item.arduino-tool-item.toggled {
background-color: unset;
opacity: 1;
border: none;
}
.item.arduino-tool-item.toggled .arduino-verify-sketch--toolbar {
background-color: var(--theia-arduino-toolbar-toggleBackground) !important;
}
.arduino-tool-icon { .arduino-tool-icon {
height: 24px; height: 24px;
width: 24px; width: 24px;

View File

@ -13,6 +13,7 @@ export namespace ArduinoToolbarComponent {
commands: CommandRegistry, commands: CommandRegistry,
labelParser: LabelParser, labelParser: LabelParser,
commandIsEnabled: (id: string) => boolean, commandIsEnabled: (id: string) => boolean,
commandIsToggled: (id: string) => boolean,
executeCommand: (e: React.MouseEvent<HTMLElement>) => void executeCommand: (e: React.MouseEvent<HTMLElement>) => void
} }
export interface State { export interface State {
@ -39,7 +40,7 @@ export class ArduinoToolbarComponent extends React.Component<ArduinoToolbarCompo
} }
} }
const command = this.props.commands.getCommand(item.command); const command = this.props.commands.getCommand(item.command);
const cls = `${ARDUINO_TOOLBAR_ITEM_CLASS} ${TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM} ${command && this.props.commandIsEnabled(command.id) ? 'enabled' : ''}` const cls = `${ARDUINO_TOOLBAR_ITEM_CLASS} ${TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM} ${command && this.props.commandIsEnabled(command.id) ? 'enabled' : ''} ${command && this.props.commandIsToggled(command.id) ? 'toggled' : ''}`
return <div key={item.id} className={cls} > return <div key={item.id} className={cls} >
<div className={item.id}> <div className={item.id}>
<div <div
@ -112,6 +113,10 @@ export class ArduinoToolbar extends ReactWidget {
protected commandIsEnabled(command: string): boolean { protected commandIsEnabled(command: string): boolean {
return this.commands.isEnabled(command, this); return this.commands.isEnabled(command, this);
} }
protected readonly doCommandIsToggled = (id: string) => this.commandIsToggled(id);
protected commandIsToggled(command: string): boolean {
return this.commands.isToggled(command, this);
}
protected render(): React.ReactNode { protected render(): React.ReactNode {
return <ArduinoToolbarComponent return <ArduinoToolbarComponent
@ -121,6 +126,7 @@ export class ArduinoToolbar extends ReactWidget {
items={[...this.items.values()]} items={[...this.items.values()]}
commands={this.commands} commands={this.commands}
commandIsEnabled={this.doCommandIsEnabled} commandIsEnabled={this.doCommandIsEnabled}
commandIsToggled={this.doCommandIsToggled}
executeCommand={this.executeCommand} executeCommand={this.executeCommand}
/> />
} }