import { Slot } from "ic10emu_wasm"; import { html, css, HTMLTemplateResult } from "lit"; import { customElement, state } from "lit/decorators.js"; import { BaseElement, defaultCss } from "../components"; import { VMBaseDevice } from "./base_device"; import "@shoelace-style/shoelace/dist/components/card/card.js"; import "@shoelace-style/shoelace/dist/components/icon/icon.js"; import "@shoelace-style/shoelace/dist/components/tooltip/tooltip.js"; import "@shoelace-style/shoelace/dist/components/input/input.js"; import "@shoelace-style/shoelace/dist/components/details/details.js"; import "@shoelace-style/shoelace/dist/components/tab/tab.js"; import "@shoelace-style/shoelace/dist/components/tab-panel/tab-panel.js"; import "@shoelace-style/shoelace/dist/components/tab-group/tab-group.js"; import "@shoelace-style/shoelace/dist/components/copy-button/copy-button.js"; import "@shoelace-style/shoelace/dist/components/select/select.js"; import "@shoelace-style/shoelace/dist/components/badge/badge.js"; import "@shoelace-style/shoelace/dist/components/option/option.js"; import SlInput from "@shoelace-style/shoelace/dist/components/input/input.js"; import { parseNumber, structuralEqual } from "../utils"; import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.js"; @customElement("vm-device-card") export class VMDeviceCard extends VMBaseDevice { image_err: boolean; static styles = [ ...defaultCss, css` :host { display: block; box-sizing: border-box; } .card { width: 100%; box-sizing: border-box; } .image { width: 4rem; height: 4rem; } .header { display: flex; flex-direction: row; } .header-name { display: flex; flex-direction: row; width: 100%; flex-grow: 1; align-items: center; flex-wrap: wrap; } // .device-name { // box-sizing: border-box; // width: 8rem; // } // .device-name-hash { // box-sizing: border-box; // width: 5rem; // } sl-divider { --spacing: 0.25rem; } sl-button[variant="success"] { /* Changes the success theme color to purple using primitives */ --sl-color-success-600: var(--sl-color-purple-700); } sl-button[variant="primary"] { /* Changes the success theme color to purple using primitives */ --sl-color-primary-600: var(--sl-color-cyan-600); } sl-button[variant="warning"] { /* Changes the success theme color to purple using primitives */ --sl-color-warning-600: var(--sl-color-amber-600); } sl-tab-group { margin-left: 1rem; margin-right: 1rem; --indicator-color: var(--sl-color-purple-600); --sl-color-primary-600: var(--sl-color-purple-600); } `, ]; onImageErr(e: Event) { this.image_err = true; console.log("Image load error", e); } renderHeader(): HTMLTemplateResult { const activeIc = window.VM?.activeIC; const badges: HTMLTemplateResult[] = []; if (this.deviceID == activeIc?.id) { badges.push(html`db`); } activeIc?.pins?.forEach((id, index) => { if (this.deviceID == id) { badges.push(html``); } }, this); return html`
Device ${this.deviceID} Name Hash ${badges.map((badge) => badge)}
`; } renderFields(): HTMLTemplateResult { const fields = Array.from(this.fields); return html` ${fields.map(([name, field], _index, _fields) => { return html` ${name} ${field.field_type} `; })} `; } renderSlot(slot: Slot, slotIndex: number): HTMLTemplateResult { const fields = Array.from(slot.fields); return html` ${slotIndex} : ${slot.typ}
${fields.map( ([name, field], _index, _fields) => html` ${name} ${field.field_type} `, )}
`; } renderSlots(): HTMLTemplateResult { return html`
${this.slots.map((slot, index, _slots) => this.renderSlot(slot, index))}
`; } renderReagents(): HTMLTemplateResult { return html``; } renderNetworks(): HTMLTemplateResult { const vmNetworks = window.VM!.networks; return html`
${this.connections.map((connection, index, _conns) => { const conn = typeof connection === "object" ? connection.CableNetwork : null; return html` Connection:${index} ${vmNetworks.map( (net) => html`Network ${net}`, )} `; })}
`; } renderPins(): HTMLTemplateResult { const pins = this.pins; const visibleDevices = window.VM!.visibleDevices(this.deviceID); return html`
${pins?.map( (pin, index) => html` d${index} ${visibleDevices.map( (device, _index) => html` Device ${device.id} : ${device.name ?? device.prefabName} `, )} `, )}
`; } protected render(): HTMLTemplateResult { return html`
${this.renderHeader()}
Fields Slots Reagents Networks Pins ${this.renderFields()} ${this.renderSlots()} ${this.renderReagents()} ${this.renderNetworks()} ${this.renderPins()}
`; } _handleChangeName(e: CustomEvent) { const input = e.target as SlInput; this.device.setName(input.value); this.updateDevice(); } _handleChangeField(e: CustomEvent) { const input = e.target as SlInput; const field = input.getAttribute("key")!; const val = parseNumber(input.value); this.device.setField(field, val); this.updateDevice(); } _handleChangeSlotField(e: CustomEvent) { const input = e.target as SlInput; const slot = parseInt(input.getAttribute("slotIndex")!); const field = input.getAttribute("key")!; const val = parseNumber(input.value); this.device.setSlotField(slot, field, val); this.updateDevice(); } _handleChangeConnection(e: CustomEvent) { const select = e.target as SlSelect; const conn = parseInt(select.getAttribute("key")!); const last = this.device.connections[conn]; const val = select.value ? parseInt(select.value as string) : undefined; if (typeof last === "object" && typeof last.CableNetwork === "number") { // is there no other connection to the previous network? if ( !this.device.connections.some((other_conn, index) => { structuralEqual(last, other_conn) && index !== conn; }) ) { this.device.removeDeviceFromNetwork(last.CableNetwork); } } if (typeof val !== "undefined") { this.device.addDeviceToNetwork(conn, val); } else { this.device.setConnection(conn, val); } this.updateDevice(); } _handleChangePin(e: CustomEvent) { const select = e.target as SlSelect; const pin = parseInt(select.getAttribute("key")!); const val = select.value ? parseInt(select.value as string) : undefined; this.device.setPin(pin, val); this.updateDevice(); } } @customElement("vm-device-list") export class VMDeviceList extends BaseElement { @state() accessor devices: number[]; constructor() { super(); this.devices = window.VM!.deviceIds; } connectedCallback(): void { const root = super.connectedCallback(); window.VM?.addEventListener( "vm-devices-update", this._handleDevicesUpdate.bind(this), ); return root; } _handleDevicesUpdate(e: CustomEvent) { const ids = e.detail; if (!structuralEqual(this.devices, ids)) { this.devices = ids; } } protected render(): HTMLTemplateResult { return html`
${this.devices.map( (id, _index, _ids) => html``, )}
`; } }