diff --git a/www/src/ts/virtual_machine/base_device.ts b/www/src/ts/virtual_machine/base_device.ts index a2626b9..cdcae29 100644 --- a/www/src/ts/virtual_machine/base_device.ts +++ b/www/src/ts/virtual_machine/base_device.ts @@ -59,7 +59,8 @@ export type VMDeviceMixinSubscription = | "ic" | "active-ic" | { field: LogicType } - | { slot: number }; + | { slot: number } + | "visible-devices"; export const VMDeviceMixin = >( superClass: T, @@ -124,6 +125,10 @@ export const VMDeviceMixin = >( "vm-device-id-change", this._handleDeviceIdChange.bind(this), ); + vm.addEventListener( + "vm-devices-removed", + this._handleDevicesRemoved.bind(this), + ) }); this.updateDevice(); return root; @@ -143,6 +148,10 @@ export const VMDeviceMixin = >( "vm-device-id-change", this._handleDeviceIdChange.bind(this), ); + vm.removeEventListener( + "vm-devices-removed", + this._handleDevicesRemoved.bind(this), + ) }); } @@ -156,6 +165,13 @@ export const VMDeviceMixin = >( this.deviceSubscriptions.includes("active-ic") ) { this.updateDevice(); + this.requestUpdate(); + } else if (this.deviceSubscriptions.includes("visible-devices")) { + const visibleDevices = window.VM.vm.visibleDeviceIds(this.deviceID); + if (visibleDevices.includes(id)) { + this.updateDevice(); + this.requestUpdate(); + } } } @@ -164,17 +180,39 @@ export const VMDeviceMixin = >( const ids = e.detail; if (ids.includes(this.deviceID)) { this.updateDevice(); + if (this.deviceSubscriptions.includes("visible-devices")) { + this.requestUpdate(); + } } else if ( ids.includes(activeIcId) && this.deviceSubscriptions.includes("active-ic") ) { this.updateDevice(); + this.requestUpdate(); + } else if (this.deviceSubscriptions.includes("visible-devices")) { + const visibleDevices = window.VM.vm.visibleDeviceIds(this.deviceID); + if (ids.some( id => visibleDevices.includes(id))) { + this.updateDevice(); + this.requestUpdate(); + } } } _handleDeviceIdChange(e: CustomEvent<{ old: number; new: number }>) { if (this.deviceID === e.detail.old) { this.deviceID = e.detail.new; + } else if (this.deviceSubscriptions.includes("visible-devices")) { + const visibleDevices = window.VM.vm.visibleDeviceIds(this.deviceID); + if (visibleDevices.some(id => id === e.detail.old || id === e.detail.new)) { + this.requestUpdate() + } + } + } + + _handleDevicesRemoved(e: CustomEvent) { + const _ids = e.detail; + if (this.deviceSubscriptions.includes("visible-devices")) { + this.requestUpdate() } } diff --git a/www/src/ts/virtual_machine/device/card.ts b/www/src/ts/virtual_machine/device/card.ts index c66a636..75d8b92 100644 --- a/www/src/ts/virtual_machine/device/card.ts +++ b/www/src/ts/virtual_machine/device/card.ts @@ -8,6 +8,7 @@ import SlInput from "@shoelace-style/shoelace/dist/components/input/input.compon import SlDialog from "@shoelace-style/shoelace/dist/components/dialog/dialog.component.js"; import "./slot"; import "./fields"; +import "./pins"; import { until } from "lit/directives/until.js"; import { repeat } from "lit/directives/repeat.js"; @@ -238,24 +239,12 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) { } renderPins() { - const pins = this.pins; - const visibleDevices = window.VM.vm.visibleDevices(this.deviceID); - const pinsHtml = pins?.map( - (pin, index) => - html` - - d${index} - ${visibleDevices.map( - (device, _index) => - html` - - Device ${device.id} : ${device.name ?? device.prefabName} - - `, - )} - `, + return this.delayRenderTab( + "pins", + html`
+ +
` ); - return this.delayRenderTab("pins", html`
${pinsHtml}
`); } private tabsShown: CardTab[] = ["fields"]; @@ -306,7 +295,7 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) { Slots Reagents Networks - Pins + Pins ${until(this.renderFields(), html``)} @@ -320,7 +309,7 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) { ${until(this.renderNetworks(), html``)} - ${this.renderPins()} + ${until(this.renderPins(), html``)} @@ -399,11 +388,4 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) { 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; - window.VM.get().then((vm) => vm.setDevicePin(this.deviceID, pin, val)); - this.updateDevice(); - } } diff --git a/www/src/ts/virtual_machine/device/pins.ts b/www/src/ts/virtual_machine/device/pins.ts new file mode 100644 index 0000000..1bb5cba --- /dev/null +++ b/www/src/ts/virtual_machine/device/pins.ts @@ -0,0 +1,44 @@ + +import { html, css } from "lit"; +import { customElement, property } from "lit/decorators.js"; +import { BaseElement, defaultCss } from "components"; +import { VMDeviceDBMixin, VMDeviceMixin } from "virtual_machine/base_device"; +import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.component.js"; + +@customElement("vm-device-pins") +export class VMDevicePins extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) { + constructor() { + super(); + this.subscribe("ic", "visible-devices"); + } + + render() { + const pins = this.pins; + const visibleDevices = window.VM.vm.visibleDevices(this.deviceID); + const pinsHtml = pins?.map( + (pin, index) => + html` + + d${index} + ${visibleDevices.map( + (device, _index) => + html` + + Device ${device.id} : ${device.name ?? device.prefabName} + + `, + )} + `, + ); + return pinsHtml; + } + + _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; + window.VM.get().then((vm) => vm.setDevicePin(this.deviceID, pin, val)); + this.updateDevice(); + } + +} diff --git a/www/src/ts/virtual_machine/index.ts b/www/src/ts/virtual_machine/index.ts index 8e90d7c..65375ca 100644 --- a/www/src/ts/virtual_machine/index.ts +++ b/www/src/ts/virtual_machine/index.ts @@ -119,8 +119,14 @@ class VirtualMachine extends EventTarget { return ids.map((id, _index) => this._devices.get(id)!); } + visibleDeviceIds(source: number) { + const ids = Array.from(this.ic10vm.visibleDevices(source)); + return ids; + } + updateDevices() { var update_flag = false; + const removedDevices = []; const device_ids = this.ic10vm.devices; for (const id of device_ids) { if (!this._devices.has(id)) { @@ -132,6 +138,7 @@ class VirtualMachine extends EventTarget { if (!device_ids.includes(id)) { this._devices.delete(id); update_flag = true; + removedDevices.push(id); } } @@ -160,6 +167,13 @@ class VirtualMachine extends EventTarget { detail: ids, }), ); + if (removedDevices.length > 0) { + this.dispatchEvent( + new CustomEvent("vm-devices-removed", { + detail: removedDevices, + }), + ); + } this.app.session.save(); } }