mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-11-18 14:49:27 +00:00
243 lines
8.8 KiB
TypeScript
243 lines
8.8 KiB
TypeScript
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<BoardsDropdownItemComponent.Props> {
|
|
render() {
|
|
return <div className={`arduino-boards-dropdown-item ${this.props.isSelected ? 'selected' : ''}`} onClick={this.props.onClick}>
|
|
<div>{this.props.label}</div>
|
|
{this.props.isSelected ? <span className='fa fa-check'></span> : ''}
|
|
</div>;
|
|
}
|
|
}
|
|
|
|
export namespace BoardsDropDown {
|
|
export interface Props {
|
|
readonly coords: BoardsDropDownListCoord;
|
|
readonly isOpen: boolean;
|
|
readonly dropDownItems: BoardsDropdownItem[];
|
|
readonly openDialog: () => void;
|
|
}
|
|
}
|
|
|
|
export class BoardsDropDown extends React.Component<BoardsDropDown.Props> {
|
|
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 <div className='arduino-boards-dropdown-list'
|
|
style={{
|
|
position: 'absolute',
|
|
top: this.props.coords.top,
|
|
left: this.props.coords.left,
|
|
width: this.props.coords.width,
|
|
paddingTop: this.props.coords.paddingTop
|
|
}}>
|
|
{
|
|
this.props.dropDownItems.map(item => {
|
|
return <React.Fragment key={item.label}>
|
|
<BoardsDropdownItemComponent isSelected={item.isSelected()} label={item.label} onClick={item.commandExecutor}></BoardsDropdownItemComponent>
|
|
</React.Fragment>;
|
|
})
|
|
}
|
|
<BoardsDropdownItemComponent isSelected={false} label={'Select Other Board & Port'} onClick={this.props.openDialog}></BoardsDropdownItemComponent>
|
|
</div>
|
|
} 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<BoardsToolBarItem.Props, BoardsToolBarItem.State> {
|
|
|
|
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<HTMLElement>) => {
|
|
this.showSelectBoardsMenu(event);
|
|
event.stopPropagation();
|
|
event.nativeEvent.stopImmediatePropagation();
|
|
};
|
|
protected showSelectBoardsMenu(event: React.MouseEvent<HTMLElement>) {
|
|
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 <React.Fragment>
|
|
<div className='arduino-boards-toolbar-item-container'>
|
|
<div className='arduino-boards-toolbar-item' title={boardTxt}>
|
|
<div className='inner-container' onClick={this.doShowSelectBoardsMenu}>
|
|
<span className={!selectedBoard || !this.state.selectedIsAttached ? 'fa fa-times notAttached' : ''}></span>
|
|
<div className='label noWrapInfo'>
|
|
<div className='noWrapInfo noselect'>
|
|
{selectedBoard ? boardTxt : 'no board selected'}
|
|
</div>
|
|
</div>
|
|
<span className='fa fa-caret-down caret'></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<BoardsDropDown
|
|
isOpen={this.state.isOpen}
|
|
coords={this.dropDownListCoord}
|
|
dropDownItems={this.state.boardItems}
|
|
openDialog={this.openDialog}>
|
|
</BoardsDropDown>
|
|
</React.Fragment>;
|
|
}
|
|
|
|
protected openDialog = () => {
|
|
this.props.commands.executeCommand(ArduinoCommands.OPEN_BOARDS_DIALOG.id);
|
|
this.setState({ isOpen: false });
|
|
};
|
|
} |