diff --git a/arduino-ide-extension/src/browser/arduino-file-menu.ts b/arduino-ide-extension/src/browser/arduino-file-menu.ts index 8dbca73f..a33dd454 100644 --- a/arduino-ide-extension/src/browser/arduino-file-menu.ts +++ b/arduino-ide-extension/src/browser/arduino-file-menu.ts @@ -54,7 +54,7 @@ export class ArduinoToolbarMenuContribution implements MenuContribution { }); registry.registerMenuAction(ArduinoToolbarContextMenu.CONNECTED_GROUP, { commandId: command.id, - label: board.name + (selectedPort === port ? '*' : '') + label: board.name + ' at ' + port + (selectedPort === port ? '*' : '') }); }); } diff --git a/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx index 1f582ef3..0d228020 100644 --- a/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx +++ b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx @@ -90,6 +90,8 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C @inject(SelectBoardsDialog) protected readonly selectBoardsDialog: SelectBoardsDialog; + protected boardsToolbarItem: BoardsToolBarItem | null; + @postConstruct() protected async init(): Promise { // This is a hack. Otherwise, the backend services won't bind. @@ -124,15 +126,10 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C registry.registerItem({ id: ConnectedBoards.TOOLBAR_ID, render: () => this.boardsToolbarItem = ref} contextMenuRenderer={this.contextMenuRenderer} - onNoBoardsInstalled={this.onNoBoardsInstalled.bind(this)} - onUnknownBoard={this.onUnknownBoard.bind(this)} />, - // render: () => , + boardsNotificationService={this.boardsNotificationService} + boardService={this.boardService} />, isVisible: widget => this.isArduinoToolbar(widget) }) } @@ -230,31 +227,37 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C }); registry.registerCommand(ArduinoCommands.SELECT_BOARD, { isEnabled: () => true, - execute: (board: Board) => { - this.boardService.selectBoard(board).then(() => { - return this.boardService.getSelectBoard(); - }).then(board => { - console.log("and the selected board is", board); - }) + execute: async (board: Board) => { + this.selectBoard(board); } }) registry.registerCommand(ArduinoCommands.OPEN_BOARDS_DIALOG, { isEnabled: () => true, execute: async () => { const boardAndPort = await this.selectBoardsDialog.open(); - if(boardAndPort && boardAndPort.board){ + if (boardAndPort && boardAndPort.board) { const selectedBoard = { fqbn: boardAndPort.board.fqbn, name: boardAndPort.board.name, port: boardAndPort.port } - this.boardService.selectBoard(selectedBoard); - + this.selectBoard(selectedBoard); } } }) } + protected async selectBoard(board: Board) { + const attached = await this.boardService.getAttachedBoards(); + if(attached.boards.length) { + board = attached.boards.find(b => b.name === board.name && b.fqbn === board.fqbn) || board; + } + await this.boardService.selectBoard(board) + if (this.boardsToolbarItem) { + this.boardsToolbarItem.setSelectedBoard(board); + } + } + protected async openSketchFilesInNewWindow(uri: string) { const location = new URL(window.location.href); location.searchParams.set('sketch', uri); @@ -309,24 +312,24 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C return widget; } - private async onNoBoardsInstalled() { - const action = await this.messageService.info("You have no boards installed. Use the boards mangager to install one.", "Open Boards Manager"); - if (!action) { - return; - } + // private async onNoBoardsInstalled() { + // const action = await this.messageService.info("You have no boards installed. Use the boards mangager to install one.", "Open Boards Manager"); + // if (!action) { + // return; + // } - this.boardsListWidgetFrontendContribution.openView({ reveal: true }); - } + // this.boardsListWidgetFrontendContribution.openView({ reveal: true }); + // } - private async onUnknownBoard() { - const action = await this.messageService.warn("There's a board connected for which you need to install software." + - " If this were not a PoC we would offer you the right package now.", "Open Boards Manager"); - if (!action) { - return; - } + // private async onUnknownBoard() { + // const action = await this.messageService.warn("There's a board connected for which you need to install software." + + // " If this were not a PoC we would offer you the right package now.", "Open Boards Manager"); + // if (!action) { + // return; + // } - this.boardsListWidgetFrontendContribution.openView({ reveal: true }); - } + // this.boardsListWidgetFrontendContribution.openView({ reveal: true }); + // } private isArduinoToolbar(maybeToolbarWidget: any): boolean { if (maybeToolbarWidget instanceof ArduinoToolbar) { diff --git a/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx b/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx index 39ec85cb..859410d0 100644 --- a/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx +++ b/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx @@ -1,20 +1,53 @@ import * as React from 'react'; -import { Board } from '../../common/protocol/boards-service'; +import { BoardsService, Board } from '../../common/protocol/boards-service'; import { ContextMenuRenderer } from '@theia/core/lib/browser'; import { ArduinoToolbarContextMenu } from '../arduino-file-menu'; +import { BoardsNotificationService } from '../boards-notification-service'; export namespace BoardsToolBarItem { export interface Props { - readonly onNoBoardsInstalled: () => void; - readonly onUnknownBoard: (board: Board) => void; readonly contextMenuRenderer: ContextMenuRenderer; + readonly boardsNotificationService: BoardsNotificationService; + readonly boardService: BoardsService; + } + + export interface State { + selectedBoard?: Board; + selectedIsAttached: boolean } } -export class BoardsToolBarItem extends React.Component { +export class BoardsToolBarItem extends React.Component { + + protected attachedBoards: Board[]; constructor(props: BoardsToolBarItem.Props) { super(props); + + this.state = { + selectedBoard: undefined, + selectedIsAttached: true + }; + } + + componentDidMount() { + this.setAttachedBoards(); + } + + protected async setAttachedBoards() { + const { boards } = await this.props.boardService.getAttachedBoards(); + this.attachedBoards = boards; + if(this.attachedBoards.length){ + await this.props.boardService.selectBoard(this.attachedBoards[0]); + this.setSelectedBoard(this.attachedBoards[0]); + } + } + + setSelectedBoard(board: Board) { + if (this.attachedBoards.length) { + this.setState({ selectedIsAttached: !!this.attachedBoards.find(attachedBoard => attachedBoard.name === board.name) }); + } + this.setState({ selectedBoard: board }); } protected readonly doShowSelectBoardsMenu = (event: React.MouseEvent) => this.showSelectBoardsMenu(event); @@ -29,12 +62,13 @@ export class BoardsToolBarItem extends React.Component
-
Show selected Board here
+ +
{this.state.selectedBoard ? this.state.selectedBoard.name : 'no board selected'}
+
diff --git a/arduino-ide-extension/src/browser/boards/select-board-dialog-widget.tsx b/arduino-ide-extension/src/browser/boards/select-board-dialog-widget.tsx index 11751a70..ab400243 100644 --- a/arduino-ide-extension/src/browser/boards/select-board-dialog-widget.tsx +++ b/arduino-ide-extension/src/browser/boards/select-board-dialog-widget.tsx @@ -10,42 +10,84 @@ export interface BoardAndPortSelection { port?: string; } -export namespace SelectableBoardsItem { +export namespace BoardAndPortSelectableItem { export interface Props { - board: Board, + item: BoardAndPortSelection, selected: boolean, - onClick: (selection: BoardAndPortSelection) => void + onSelect: (selection: BoardAndPortSelection) => void } } -export class SelectableBoardsItem extends React.Component { +export class BoardAndPortSelectableItem extends React.Component { render(): React.ReactNode { - return
{this.props.board.name}
+ if (this.props.item.board || this.props.item.port) { + return
+ {this.props.item.board ? this.props.item.board.name : this.props.item.port} + {this.props.selected ? : ''} +
; + } } protected readonly select = (() => { - this.props.onClick({ board: this.props.board }) + this.props.onSelect({ board: this.props.item.board, port: this.props.item.port }) }).bind(this); } -export namespace SelectablePortsItem { +export namespace BoardAndPortSelectionList { export interface Props { - port: string, - selected: boolean, - onClick: (selection: BoardAndPortSelection) => void + type: 'boards' | 'ports'; + list: BoardAndPortSelection[]; + onSelect: (selection: BoardAndPortSelection) => void; + } + + export interface State { + selection: BoardAndPortSelection } } -export class SelectablePortsItem extends React.Component { +export class BoardAndPortSelectionList extends React.Component { + + constructor(props: BoardAndPortSelectionList.Props) { + super(props); + + this.state = { + selection: {} + } + } + + reset(): void { + this.setState({ selection: {} }); + } render(): React.ReactNode { - return
this.props.onClick({ port: this.props.port })} className={`item ${this.props.selected ? 'selected' : ''}`}>{this.props.port}
+ return
+ {this.props.list.map(item => )} +
} - protected readonly select = (() => { - this.props.onClick({ port: this.props.port }) - }).bind(this); + protected readonly doSelect = (boardAndPortSelection: BoardAndPortSelection) => { + this.setState({ selection: boardAndPortSelection }); + this.props.onSelect(boardAndPortSelection); + } + + protected readonly isSelectedItem = ((item: BoardAndPortSelection) => { + if (this.state.selection.board) { + return (this.state.selection.board === item.board); + } else if (this.state.selection.port) { + return (this.state.selection.port === item.port); + } + return false; + }); + + protected readonly isSelectedPort = ((port: string) => { + return (this.state.selection.port && this.state.selection.port === port) || false; + }); } export namespace BoardAndPortSelectionComponent { @@ -64,6 +106,8 @@ export namespace BoardAndPortSelectionComponent { export class BoardAndPortSelectionComponent extends React.Component { protected allBoards: Board[] = []; + protected boardListComponent: BoardAndPortSelectionList | null; + protected portListComponent: BoardAndPortSelectionList | null; constructor(props: BoardAndPortSelectionComponent.Props) { super(props); @@ -80,6 +124,16 @@ export class BoardAndPortSelectionComponent extends React.Component
@@ -87,13 +141,16 @@ export class BoardAndPortSelectionComponent extends React.Component
BOARDS -
+
+
-
- {this.state.boards.map(board => )} -
+ { this.boardListComponent = ref }} + type='boards' + onSelect={this.doSelect} + list={this.state.boards.map(board => ({ board }))} />
@@ -101,35 +158,17 @@ export class BoardAndPortSelectionComponent extends React.Component PORTS
-
- {this.state.ports.map(port => )} -
+ { this.portListComponent = ref }} + type='ports' + onSelect={this.doSelect} + list={this.state.ports.map(port => ({ port }))} /> } - protected readonly isSelectedBoard = ((board: Board) => { - return (this.state.selection.board && this.state.selection.board === board) || false; - }); - - protected readonly isSelectedPort = ((port: string) => { - return (this.state.selection.port && this.state.selection.port === port) || false; - }); - - protected readonly doSelect = (boardAndPortSelection: BoardAndPortSelection) => { - const selection = this.state.selection; - if (boardAndPortSelection.board) { - selection.board = boardAndPortSelection.board; - } - if (boardAndPortSelection.port) { - selection.port = boardAndPortSelection.port; - } - this.setState({ selection }); - this.props.onSelect(this.state.selection); - } - protected sort(items: Board[]): Board[] { return items.sort((a, b) => { if (a.name < b.name) { @@ -142,6 +181,18 @@ export class BoardAndPortSelectionComponent extends React.Component { + const selection = this.state.selection; + if (boardAndPortSelection.board) { + selection.board = boardAndPortSelection.board; + } + if (boardAndPortSelection.port) { + selection.port = boardAndPortSelection.port; + } + this.setState({ selection }); + this.props.onSelect(this.state.selection); + } + protected readonly doFilter = (event: React.ChangeEvent) => { const boards = this.allBoards.filter(board => board.name.toLowerCase().indexOf(event.target.value.toLowerCase()) >= 0); this.setState({ boards }) @@ -175,6 +226,7 @@ export class SelectBoardDialogWidget extends ReactWidget { protected readonly boardsNotificationService: BoardsNotificationService; protected readonly onChangedEmitter = new Emitter(); + protected boardAndPortSelectionComponent: BoardAndPortSelectionComponent | null; boardAndPort: BoardAndPortSelection = {}; @@ -189,6 +241,13 @@ export class SelectBoardDialogWidget extends ReactWidget { return this.onChangedEmitter.event; } + reset(): void { + if (this.boardAndPortSelectionComponent) { + this.boardAndPortSelectionComponent.reset(); + } + this.boardAndPort = {}; + } + protected fireChanged(boardAndPort: BoardAndPortSelection): void { this.onChangedEmitter.fire(boardAndPort); } @@ -215,11 +274,12 @@ export class SelectBoardDialogWidget extends ReactWidget { Select Other Board & Port
- Select both a BOARD and a PORT if you want to upload a sketch.
- If you only select a BOARD you will be able just to compile, but not to upload your sketch. +

Select both a BOARD and a PORT if you want to upload a sketch.

+

If you only select a BOARD you will be able just to compile,

+

but not to upload your sketch.

- + this.boardAndPortSelectionComponent = ref} boardsService={boardsService} onSelect={this.onSelect} /> diff --git a/arduino-ide-extension/src/browser/boards/select-board-dialog.ts b/arduino-ide-extension/src/browser/boards/select-board-dialog.ts index 55278bfb..2541b4ad 100644 --- a/arduino-ide-extension/src/browser/boards/select-board-dialog.ts +++ b/arduino-ide-extension/src/browser/boards/select-board-dialog.ts @@ -44,7 +44,6 @@ export class SelectBoardsDialog extends AbstractDialog { protected onUpdateRequest(msg: Message) { super.onUpdateRequest(msg); - this.widget.update(); } @@ -59,8 +58,8 @@ export class SelectBoardsDialog extends AbstractDialog { } protected isValid(value: BoardAndPortSelection): DialogError { - if(!value.board) { - if(value.port) { + if (!value.board) { + if (value.port) { return 'Please pick the Board connected to the Port you have selected'; } return false; @@ -72,7 +71,13 @@ export class SelectBoardsDialog extends AbstractDialog { return this.widget.boardAndPort; } - protected async accept(): Promise { - super.accept(); + close(): void { + this.widget.reset(); + super.close(); + } + + onAfterDetach(msg: Message) { + this.widget.reset(); + super.onAfterDetach(msg); } } \ No newline at end of file diff --git a/arduino-ide-extension/src/browser/style/arduino.useable.css b/arduino-ide-extension/src/browser/style/arduino.useable.css index 74f9056e..8862821c 100644 --- a/arduino-ide-extension/src/browser/style/arduino.useable.css +++ b/arduino-ide-extension/src/browser/style/arduino.useable.css @@ -86,7 +86,7 @@ is not optimized for dense, information rich UIs. --theia-brand-color3: var(--md-blue-100); /* Secondary Brand colors */ --theia-secondary-brand-color0: var(--md-grey-700); - --theia-secondary-brand-color1: var(--md-grey-500); + --theia-secondary-brand-color1: #b5c8c9; --theia-secondary-brand-color2: var(--md-grey-300); --theia-secondary-brand-color3: var(--md-grey-100); /* Accent colors (dark to bright): Use these to create contrast to layout colors. */ @@ -147,7 +147,7 @@ is not optimized for dense, information rich UIs. /* Menu */ --theia-menu-color0: var(--theia-layout-color3); --theia-menu-color1: var(--theia-layout-color0); - --theia-menu-color2: var(--theia-layout-color3); + --theia-menu-color2: #dae3e3; /* Statusbar */ --theia-statusbar-color: var(--theia-arduino-light); --theia-statusBar-font-color: var(--theia-inverse-ui-font-color0); @@ -157,7 +157,7 @@ is not optimized for dense, information rich UIs. --theia-ui-button-color-hover: var(--theia-arduino-light1); --theia-ui-button-font-color: var(--theia-inverse-ui-font-color0); --theia-ui-button-color-secondary: var(--theia-secondary-brand-color1); - --theia-ui-button-color-secondary-hover: var(--theia-secondary-brand-color0); + --theia-ui-button-color-secondary-hover: var(--theia-menu-color2); --theia-ui-button-font-color-secondary: var(--theia-inverse-ui-font-color0); --theia-ui-button-color-disabled: var(--theia-accent-color3); --theia-ui-button-font-color-disabled: var(--theia-ui-font-color2); @@ -170,7 +170,7 @@ is not optimized for dense, information rich UIs. --theia-ui-dialog-header-color: var(--theia-arduino-light); --theia-ui-dialog-header-font-color: var(--theia-inverse-ui-font-color0); --theia-ui-dialog-color: rgb(236, 241, 241); - --theia-ui-dialog-font-color: var(--theia-ui-font-color1); + --theia-ui-dialog-font-color: black; /* Variables */ --theia-variable-name-color: #9B46B0; --theia-variable-value-color: rgba(108, 108, 108, 0.8); diff --git a/arduino-ide-extension/src/browser/style/board-select-dialog.css b/arduino-ide-extension/src/browser/style/board-select-dialog.css new file mode 100644 index 00000000..ce19946f --- /dev/null +++ b/arduino-ide-extension/src/browser/style/board-select-dialog.css @@ -0,0 +1,152 @@ +div#select-board-dialog { + margin: 5px 20px 50px 20px; +} + +div#select-board-dialog .selectBoardContainer .body { + display: flex; + overflow: hidden; +} + +div#select-board-dialog .selectBoardContainer .head { + margin-bottom: 10px; +} + +div#select-board-dialog .selectBoardContainer .head .title { + font-weight: 400; + letter-spacing: .02em; + font-size: 1.2em; + color: #00979d; + margin: 17px 0; +} + +div#select-board-dialog .selectBoardContainer .head .text { + margin-bottom: 21px; +} + +div#select-board-dialog .selectBoardContainer .body .list .item.selected { + background: var(--theia-ui-button-color-secondary-hover); +} + +div#select-board-dialog .selectBoardContainer .body .list .item.selected i{ + color: var(--theia-arduino-light); +} + +#select-board-dialog .selectBoardContainer .body .search input, +#select-board-dialog .selectBoardContainer .body .boards.list, +#select-board-dialog .selectBoardContainer .body .search, +#select-board-dialog .selectBoardContainer .body .ports.list { + background: white; +} + +#select-board-dialog .selectBoardContainer .body .search input { + border: none; + width: 100%; + height: auto; + max-height: 37px; + padding: 10px 8px; + margin: 0; + vertical-align: top; + display: flex; + color: var(--theia-content-font-color0); +} + +#select-board-dialog .selectBoardContainer .body .search input:focus { + box-shadow: none; +} + +#select-board-dialog .selectBoardContainer .body .container { + flex: 1; +} + +#select-board-dialog .selectBoardContainer .body .left.container .content { + margin: 0 5px 0 0; +} + +#select-board-dialog .selectBoardContainer .body .right.container .content { + margin: 0 0 0 5px; +} + +#select-board-dialog .selectBoardContainer .body .container .content .title{ + color: #7f8c8d; + margin-bottom: 10px; +} + +#select-board-dialog .selectBoardContainer .body .list .item { + padding: 10px 5px 10px 20px; + display: flex; + justify-content: space-between; +} +#select-board-dialog .selectBoardContainer .body .list .item:hover { + background: var(--theia-ui-button-color-secondary-hover); +} + +#select-board-dialog .selectBoardContainer .body .list { + max-height: 265px; + overflow-y: auto; +} + +#select-board-dialog .selectBoardContainer .body .search { + margin-bottom: 10px; + display: flex; + align-items: center; + padding-right: 5px; +} + +.p-Widget.dialogOverlay .dialogBlock { + width: 740px; +} + +button.theia-button { + height: 31px; +} + +button.theia-button.secondary { + background-color: #b5c8c9; + color: #000; + box-shadow: 0 4px #95a5a6; +} + +button.theia-button.main { + color: #fff; + background-color: #00979c; + box-shadow: 0 4px #005c5f; +} + +.dialogControl { + margin: 0 20px 30px 0; +} + +.arduino-boards-toolbar-item-container { + margin-left: 3px; +} + +.arduino-boards-toolbar-item-container .arduino-boards-toolbar-item .inner-container { + display: flex; + align-items: baseline; + margin: 0 5px; +} + +.arduino-boards-toolbar-item-container .arduino-boards-toolbar-item .inner-container .notAttached { + width: 10px; + height: 10px; + color: red; + margin-right: 5px; +} + +.arduino-boards-toolbar-item-container { + display: flex; + align-items: center; +} + +.arduino-boards-toolbar-item .label { + height: 100%; + display: flex; + align-items: center; + margin-right: 5px; +} + +.arduino-boards-toolbar-item { + background: white; + height: 18px; +} + diff --git a/arduino-ide-extension/src/browser/style/index.css b/arduino-ide-extension/src/browser/style/index.css index 4a57acb5..e9e53b25 100644 --- a/arduino-ide-extension/src/browser/style/index.css +++ b/arduino-ide-extension/src/browser/style/index.css @@ -1,3 +1,3 @@ @import './list-widget.css'; -@import './select-board-dialog.css'; -@import './main.css'; \ No newline at end of file +@import './board-select-dialog.css'; +@import './main.css'; diff --git a/arduino-ide-extension/src/browser/style/main.css b/arduino-ide-extension/src/browser/style/main.css index cb38cd29..2d0e9f04 100644 --- a/arduino-ide-extension/src/browser/style/main.css +++ b/arduino-ide-extension/src/browser/style/main.css @@ -53,25 +53,10 @@ opacity: 1; } -.arduino-boards-toolbar-item-container { - display: flex; - align-items: center; -} - -.arduino-boards-toolbar-item .label { - height: 100%; - display: flex; - align-items: center; -} - .arduino-open-boards-button { background: white; } -.arduino-boards-toolbar-item { - background: white; - height: 18px; -} .arduino-tool-item.item.connected-boards select { line-height: var(--theia-content-line-height); @@ -96,48 +81,4 @@ display: flex; align-items: center; color: var(--theia-ui-font-color3); -} - -div#select-board-dialog .selectBoardContainer .body { - display: flex; -} - -div#select-board-dialog .selectBoardContainer .head { - margin-bottom: 10px; -} - -div#select-board-dialog .selectBoardContainer .body .list .item.selected { - background: #aaaaaa; -} - -#select-board-dialog .selectBoardContainer .body .search input, -#select-board-dialog .selectBoardContainer .body .boards.list, -#select-board-dialog .selectBoardContainer .body .search, -#select-board-dialog .selectBoardContainer .body .ports.list { - background: white; -} - -#select-board-dialog .selectBoardContainer .body .search input { - border: none; - width: 100%; -} - -#select-board-dialog .selectBoardContainer .body .container { - flex: 1; -} - -#select-board-dialog .selectBoardContainer .body .container .content { - margin: 0 5px; -} - -#select-board-dialog .selectBoardContainer .body .list .item { - padding: 10px 5px 10px 20px; -} - -#select-board-dialog .selectBoardContainer .body .list { - max-height: 265px; -} - -#select-board-dialog .selectBoardContainer .body .search { - margin-bottom: 10px; } \ No newline at end of file diff --git a/arduino-ide-extension/src/browser/style/select-board-dialog.css b/arduino-ide-extension/src/browser/style/select-board-dialog.css deleted file mode 100644 index 1e3004e8..00000000 --- a/arduino-ide-extension/src/browser/style/select-board-dialog.css +++ /dev/null @@ -1,13 +0,0 @@ - -.select-board-dialog { - width: 600px; -} - -.select-board-dialog input { - width: calc(100% - 8px); - margin-bottom: 5px; -} - -.select-board-dialog select { - width: 100%; -} \ No newline at end of file