Allow the Id of a device to be changed, toast errors

This commit is contained in:
Rachel Powers
2024-04-14 17:21:57 -07:00
parent 9283d9d939
commit eed4f1f429
13 changed files with 235 additions and 95 deletions

View File

@@ -52,6 +52,7 @@ export class VMICControls extends VMActiveICMixin(BaseElement) {
sl-button[variant="success"] {
/* Changes the success theme color to purple using primitives */
--sl-color-success-600: var(--sl-color-purple-700);
--sl-color-success-500: var(--sl-color-purple-600);
}
sl-button[variant="primary"] {
/* Changes the success theme color to purple using primitives */

View File

@@ -62,7 +62,7 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
width: 10rem;
}
.device-id::part(input) {
width: 2rem;
width: 7rem;
}
.device-name-hash::part(input) {
width: 7rem;
@@ -129,7 +129,7 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
size="small"
pill
value=${this.deviceID}
disabled
@sl-change=${this._handleChangeID}
>
<span slot="prefix">Id</span>
<sl-copy-button slot="suffix" value=${this.deviceID}></sl-copy-button>
@@ -314,6 +314,16 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
`;
}
_handleChangeID(e: CustomEvent) {
const input = e.target as SlInput;
const val = input.valueAsNumber;
if (!isNaN(val)) {
window.VM.changeDeviceId(this.deviceID, val);
} else {
input.value = this.deviceID.toString();
}
}
_handleChangeName(e: CustomEvent) {
const input = e.target as SlInput;
window.VM?.setDeviceName(this.deviceID, input.value);
@@ -404,7 +414,14 @@ export class VMDeviceList extends BaseElement {
}
protected render(): HTMLTemplateResult {
return html`
const deviceCards: HTMLTemplateResult[] = this.devices.map(
(id, _index, _ids) =>
html`<vm-device-card
.deviceID=${id}
class="device-list-card"
></vm-device-card>`,
);
const result = html`
<div class="header">
<span>
Devices:
@@ -413,15 +430,11 @@ export class VMDeviceList extends BaseElement {
<vm-add-device-button class="ms-auto"></vm-add-device-button>
</div>
<div class="device-list">
${this.devices.map(
(id, _index, _ids) =>
html`<vm-device-card
.deviceID=${id}
class="device-list-card"
></vm-device-card>`,
)}
${deviceCards}
</div>
`;
return result;
}
}

View File

@@ -386,7 +386,7 @@ export type DeviceDBEntry = {
slotlogic?: { [key in SlotLogicType]: number[] };
slots?: { name: string; typ: SlotClass }[];
modes?: { [key: string]: string };
conn?: { [key in SlotLogicType]: [NetworkType, ConnectionRole] };
conn?: { [key: number]: [NetworkType, ConnectionRole] };
slotclass?: SlotClass;
sorting?: SortingClass;
pins?: number;
@@ -403,3 +403,30 @@ export type DeviceDB = {
};
names_by_hash: { [key: number]: string };
};
export type PreCastDeviceDBEntry = {
name: string;
hash: number;
desc: string;
logic?: { [key in LogicType]?: string };
slotlogic?: { [key in SlotLogicType]?: number[] };
slots?: { name: string; typ: string }[];
modes?: { [key: string]: string };
conn?: { [key: number]: string[] };
slotclass?: string;
sorting?: string;
pins?: number;
};
export type PreCastDeviceDB = {
logic_enabled: string[];
slot_logic_enabled: string[];
devices: string[];
items: string[];
structures: string[];
db: {
[key: string]: PreCastDeviceDBEntry;
};
names_by_hash: { [key: number]: string };
};

View File

@@ -1,5 +1,5 @@
import { DeviceRef, VM, init } from "ic10emu_wasm";
import { DeviceDB } from "./device_db";
import { DeviceDB, PreCastDeviceDB } from "./device_db";
import "./base_device";
declare global {
@@ -8,13 +8,21 @@ declare global {
}
}
export interface ToastMessage {
variant: "warning" | "danger" | "success" | "primary" | "neutral";
icon: string;
title: string;
msg: string;
id: string;
}
class VirtualMachine extends EventTarget {
ic10vm: VM;
_devices: Map<number, DeviceRef>;
_ics: Map<number, DeviceRef>;
accessor db: DeviceDB;
dbPromise: Promise<{ default: DeviceDB }>;
dbPromise: Promise<{ default: PreCastDeviceDB }>;
constructor() {
super();
@@ -28,7 +36,9 @@ class VirtualMachine extends EventTarget {
this._ics = new Map();
this.dbPromise = import("../../../data/database.json");
this.dbPromise.then((module) => this.setupDeviceDatabase(module.default));
this.dbPromise.then((module) =>
this.setupDeviceDatabase(module.default as DeviceDB),
);
this.updateDevices();
this.updateCode();
@@ -78,7 +88,6 @@ class VirtualMachine extends EventTarget {
}
for (const id of this._devices.keys()) {
if (!device_ids.includes(id)) {
this._devices.get(id)!.free();
this._devices.delete(id);
update_flag = true;
}
@@ -102,7 +111,9 @@ class VirtualMachine extends EventTarget {
if (update_flag) {
this.dispatchEvent(
new CustomEvent("vm-devices-update", { detail: device_ids }),
new CustomEvent("vm-devices-update", {
detail: Array.from(device_ids),
}),
);
}
}
@@ -122,8 +133,8 @@ class VirtualMachine extends EventTarget {
this.dispatchEvent(
new CustomEvent("vm-device-modified", { detail: id }),
);
} catch (e) {
console.log(e);
} catch (err) {
this.handleVmError(err);
}
console.timeEnd(`CompileProgram_${id}_${attempt}`);
}
@@ -136,8 +147,8 @@ class VirtualMachine extends EventTarget {
if (ic) {
try {
ic.step(false);
} catch (e) {
console.log(e);
} catch (err) {
this.handleVmError(err);
}
this.update();
this.dispatchEvent(
@@ -151,8 +162,8 @@ class VirtualMachine extends EventTarget {
if (ic) {
try {
ic.run(false);
} catch (e) {
console.log(e);
} catch (err) {
this.handleVmError(err);
}
this.update();
this.dispatchEvent(
@@ -178,7 +189,7 @@ class VirtualMachine extends EventTarget {
);
}
}, this);
this.updateDevice(this.activeIC)
this.updateDevice(this.activeIC);
}
updateDevice(device: DeviceRef) {
@@ -190,13 +201,37 @@ class VirtualMachine extends EventTarget {
}
}
handleVmError(err: Error) {
console.log("Error in Virtual Machine", err);
const message: ToastMessage = {
variant: "danger",
icon: "bug",
title: `Error in Virtual Machine ${err.name}`,
msg: err.message,
id: Date.now().toString(16),
};
this.dispatchEvent(new CustomEvent("vm-message", { detail: message }));
}
changeDeviceId(old_id: number, new_id: number) {
try {
this.ic10vm.changeDeviceId(old_id, new_id);
this.updateDevices();
if (window.App.session.activeIC === old_id) {
window.App.session.activeIC = new_id;
}
} catch (err) {
this.handleVmError(err);
}
}
setRegister(index: number, val: number) {
const ic = this.activeIC!;
try {
ic.setRegister(index, val);
this.updateDevice(ic);
} catch (e) {
console.log(e);
} catch (err) {
this.handleVmError(err);
}
}
@@ -205,8 +240,8 @@ class VirtualMachine extends EventTarget {
try {
ic!.setStack(addr, val);
this.updateDevice(ic);
} catch (e) {
console.log(e);
} catch (err) {
this.handleVmError(err);
}
}
@@ -227,8 +262,8 @@ class VirtualMachine extends EventTarget {
device.setField(field, val);
this.updateDevice(device);
return true;
} catch (e) {
console.log(e);
} catch (err) {
this.handleVmError(err);
}
}
return false;
@@ -241,8 +276,8 @@ class VirtualMachine extends EventTarget {
device.setSlotField(slot, field, val);
this.updateDevice(device);
return true;
} catch (e) {
console.log(e);
} catch (err) {
this.handleVmError(err);
}
}
return false;

View File

@@ -1,15 +1,17 @@
import { HTMLTemplateResult, html, css } from "lit";
import { customElement, property, query } from "lit/decorators.js";
import { customElement, property, query, state } from "lit/decorators.js";
import { BaseElement, defaultCss } from "../components";
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/alert/alert.js";
import "./controls";
import "./registers";
import "./stack";
import "./device";
import { ToastMessage } from ".";
@customElement("vm-ui")
export class VMUI extends BaseElement {
@@ -34,16 +36,39 @@ export class VMUI extends BaseElement {
margin-top: 0.5rem;
}
.side-container {
height: 100%
height: 100%;
overflow-y: auto;
}
`,
];
constructor() {
super();
}
connectedCallback(): void {
super.connectedCallback();
window.VM.addEventListener("vm-message", this._handleVMMessage.bind(this) )
}
_handleVMMessage(e: CustomEvent) {
const msg: ToastMessage = e.detail;
const alert = Object.assign(document.createElement('sl-alert'), {
variant: msg.variant,
closable: true,
// duration: 5000,
innerHTML: `
<sl-icon slot="icon" name="${msg.icon}"></sl-icon>
<strong>${msg.title}</strong><br />
${msg.msg}
`
});
document.body.append(alert);
alert.toast();
}
protected render() {
return html`
<div class="side-container">