import * as React from 'react'; import { BoardsService, Board, AttachedSerialBoard } from '../../common/protocol/boards-service'; import { ContextMenuRenderer, StatusBar, StatusBarAlignment } from '@theia/core/lib/browser'; import { BoardsNotificationService } from '../boards-notification-service'; import { Command, CommandRegistry } from '@theia/core'; import { ArduinoCommands } from '../arduino-commands'; import ReactDOM = require('react-dom'); export interface BoardsDropdownItem { label: string; commandExecutor: () => void; isSelected: () => boolean; } export interface BoardsDropDownListCoord { top: number; left: number; width: number; paddingTop: number; } export namespace BoardsDropdownItemComponent { export interface Props { label: string; onClick: () => void; isSelected: boolean; } } export class BoardsDropdownItemComponent extends React.Component { render() { return
{this.props.label}
{this.props.isSelected ? : ''}
; } } export namespace BoardsDropDown { export interface Props { readonly coords: BoardsDropDownListCoord; readonly isOpen: boolean; readonly dropDownItems: BoardsDropdownItem[]; readonly openDialog: () => void; } } export class BoardsDropDown extends React.Component { protected dropdownId: string = 'boards-dropdown-container'; protected dropdownElement: HTMLElement; constructor(props: BoardsDropDown.Props) { super(props); let list = document.getElementById(this.dropdownId); if (!list) { list = document.createElement('div'); list.id = this.dropdownId; document.body.appendChild(list); this.dropdownElement = list; } } render(): React.ReactNode { return ReactDOM.createPortal(this.renderNode(), this.dropdownElement); } renderNode(): React.ReactNode { if (this.props.isOpen) { return
{ this.props.dropDownItems.map(item => { return ; }) }
} else { return ''; } } } export namespace BoardsToolBarItem { export interface Props { readonly contextMenuRenderer: ContextMenuRenderer; readonly boardsNotificationService: BoardsNotificationService; readonly boardService: BoardsService; readonly commands: CommandRegistry; readonly statusBar: StatusBar; } export interface State { selectedBoard?: Board; selectedIsAttached: boolean; boardItems: BoardsDropdownItem[]; isOpen: boolean; } } export class BoardsToolBarItem extends React.Component { protected attachedBoards: Board[]; protected dropDownListCoord: BoardsDropDownListCoord; constructor(props: BoardsToolBarItem.Props) { super(props); this.state = { selectedBoard: undefined, selectedIsAttached: true, boardItems: [], isOpen: false }; document.addEventListener('click', () => { this.setState({ isOpen: false }); }); } componentDidMount() { this.setAttachedBoards(); } setSelectedBoard(board: Board) { if (this.attachedBoards && this.attachedBoards.length) { this.setState({ selectedIsAttached: !!this.attachedBoards.find(attachedBoard => attachedBoard.name === board.name) }); } this.setState({ selectedBoard: board }); } protected async setAttachedBoards() { this.props.boardService.getAttachedBoards().then(attachedBoards => { this.attachedBoards = attachedBoards.boards; if (this.attachedBoards.length) { this.createBoardDropdownItems(); this.props.boardService.selectBoard(this.attachedBoards[0]).then(() => this.setSelectedBoard(this.attachedBoards[0])); } }) } protected createBoardDropdownItems() { const boardItems: BoardsDropdownItem[] = []; this.attachedBoards.forEach(board => { const { commands } = this.props; const port = this.getPort(board); const command: Command = { id: 'selectBoard' + port } commands.registerCommand(command, { execute: () => { commands.executeCommand(ArduinoCommands.SELECT_BOARD.id, board); this.setState({ isOpen: false, selectedBoard: board }); } }); boardItems.push({ commandExecutor: () => commands.executeCommand(command.id), label: board.name + ' at ' + port, isSelected: () => this.doIsSelectedBoard(board) }); }); this.setState({ boardItems }); } protected doIsSelectedBoard = (board: Board) => this.isSelectedBoard(board); protected isSelectedBoard(board: Board): boolean { return AttachedSerialBoard.is(board) && !!this.state.selectedBoard && AttachedSerialBoard.is(this.state.selectedBoard) && board.port === this.state.selectedBoard.port && board.fqbn === this.state.selectedBoard.fqbn; } protected getPort(board: Board): string { if (AttachedSerialBoard.is(board)) { return board.port; } return ''; } protected readonly doShowSelectBoardsMenu = (event: React.MouseEvent) => { this.showSelectBoardsMenu(event); event.stopPropagation(); event.nativeEvent.stopImmediatePropagation(); }; protected showSelectBoardsMenu(event: React.MouseEvent) { const el = (event.currentTarget as HTMLElement); if (el) { this.dropDownListCoord = { top: el.getBoundingClientRect().top, left: el.getBoundingClientRect().left, paddingTop: el.getBoundingClientRect().height, width: el.getBoundingClientRect().width } this.setState({ isOpen: !this.state.isOpen }); } } render(): React.ReactNode { const selectedBoard = this.state.selectedBoard; const port = selectedBoard ? this.getPort(selectedBoard) : undefined; const boardTxt = selectedBoard && `${selectedBoard.name}${port ? ' at ' + port : ''}` || ''; this.props.statusBar.setElement('arduino-selected-board', { alignment: StatusBarAlignment.RIGHT, text: boardTxt }); return
{selectedBoard ? boardTxt : 'no board selected'}
; } protected openDialog = () => { this.props.commands.executeCommand(ArduinoCommands.OPEN_BOARDS_DIALOG.id); this.setState({ isOpen: false }); }; }