fix: device id change UI event chain fixed; changing the Active IC's ID no longer breaks the UI
This commit is contained in:
@@ -285,11 +285,15 @@ impl VM {
|
||||
device.borrow_mut().id = new_id;
|
||||
self.devices.insert(new_id, device);
|
||||
self.ics.iter().for_each(|(_id, ic)| {
|
||||
ic.borrow().pins.borrow_mut().iter_mut().for_each(|pin| {
|
||||
let mut ic_ref = ic.borrow_mut();
|
||||
if ic_ref.device == old_id {
|
||||
ic_ref.device = new_id;
|
||||
}
|
||||
ic_ref.pins.borrow_mut().iter_mut().for_each(|pin| {
|
||||
if pin.is_some_and(|d| d == old_id) {
|
||||
pin.replace(new_id);
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
self.networks.iter().for_each(|(_net_id, net)| {
|
||||
if let Ok(mut net_ref) = net.try_borrow_mut() {
|
||||
|
||||
@@ -35,9 +35,9 @@ export class IC10Editor extends BaseElement {
|
||||
};
|
||||
sessions: Map<number, Ace.EditSession>;
|
||||
|
||||
@state() active_session: number = 1;
|
||||
@state() activeSession: number = 1;
|
||||
|
||||
active_line_markers: Map<number, number | null> = new Map();
|
||||
activeLineMarkers: Map<number, number | null> = new Map();
|
||||
languageProvider?: LanguageProvider;
|
||||
// ui: IC10EditorUI;
|
||||
|
||||
@@ -78,56 +78,35 @@ export class IC10Editor extends BaseElement {
|
||||
};
|
||||
|
||||
this.sessions = new Map();
|
||||
this.active_line_markers = new Map();
|
||||
this.activeLineMarkers = new Map();
|
||||
|
||||
// this.ui = new IC10EditorUI(this);
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const result = html`
|
||||
<div
|
||||
id="editorContainer"
|
||||
style="height: 100%; width: 100%; position: relative; z-index: auto;"
|
||||
>
|
||||
<div
|
||||
id="editor"
|
||||
style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 0; isolation: isolate;"
|
||||
></div>
|
||||
<div id="editorContainer" style="height: 100%; width: 100%; position: relative; z-index: auto;">
|
||||
<div id="editor" style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 0; isolation: isolate;">
|
||||
</div>
|
||||
<div id="editorStatusbar"></div>
|
||||
</div>
|
||||
<sl-dialog label="Editor Settings" class="dialog-focus e-settings-dialog">
|
||||
<sl-radio-group
|
||||
id="editorKeyboardRadio"
|
||||
label="Editor Keyboard Bindings"
|
||||
value=${this.settings.keyboard}
|
||||
>
|
||||
<sl-radio-group id="editorKeyboardRadio" label="Editor Keyboard Bindings" value=${this.settings.keyboard}>
|
||||
<sl-radio-button value="ace">Ace</sl-radio-button>
|
||||
<sl-radio-button value="vim">Vim</sl-radio-button>
|
||||
<sl-radio-button value="emacs">Emacs</sl-radio-button>
|
||||
<sl-radio-button value="sublime">Sublime</sl-radio-button>
|
||||
<sl-radio-button value="vscode">VS Code</sl-radio-button>
|
||||
</sl-radio-group>
|
||||
<sl-radio-group
|
||||
id="editorCursorRadio"
|
||||
label="Editor Cursor Style"
|
||||
value=${this.settings.cursor}
|
||||
>
|
||||
<sl-radio-group id="editorCursorRadio" label="Editor Cursor Style" value=${this.settings.cursor}>
|
||||
<sl-radio-button value="ace">Ace</sl-radio-button>
|
||||
<sl-radio-button value="slim">Slim</sl-radio-button>
|
||||
<sl-radio-button value="smooth">Smooth</sl-radio-button>
|
||||
<sl-radio-button value="smooth slim">Smooth And Slim</sl-radio-button>
|
||||
<sl-radio-button value="wide">Wide</sl-radio-button>
|
||||
</sl-radio-group>
|
||||
<sl-input
|
||||
id="editorFontSize"
|
||||
label="Font Size"
|
||||
type="number"
|
||||
value="${this.settings.fontSize}"
|
||||
></sl-input>
|
||||
<sl-switch
|
||||
id="editorRelativeLineNumbers"
|
||||
?checked=${this.settings.relativeLineNumbers}
|
||||
>
|
||||
<sl-input id="editorFontSize" label="Font Size" type="number" value="${this.settings.fontSize}"></sl-input>
|
||||
<sl-switch id="editorRelativeLineNumbers" ?checked=${this.settings.relativeLineNumbers}>
|
||||
Relative Line Numbers
|
||||
</sl-switch>
|
||||
</sl-dialog>
|
||||
@@ -230,12 +209,9 @@ export class IC10Editor extends BaseElement {
|
||||
// characterData: false,
|
||||
// });
|
||||
|
||||
this.sessions.set(this.active_session, this.editor.getSession());
|
||||
this.bindSession(
|
||||
this.active_session,
|
||||
this.sessions.get(this.active_session),
|
||||
);
|
||||
this.active_line_markers.set(this.active_session, null);
|
||||
this.sessions.set(this.activeSession, this.editor.getSession());
|
||||
this.bindSession(this.activeSession, this.sessions.get(this.activeSession));
|
||||
this.activeLineMarkers.set(this.activeSession, null);
|
||||
|
||||
const worker = await setupLspWorker();
|
||||
this.setupLsp(worker);
|
||||
@@ -264,35 +240,35 @@ export class IC10Editor extends BaseElement {
|
||||
const that = this;
|
||||
|
||||
const app = await window.App.get();
|
||||
app.session.onLoad(((e: CustomEvent) => {
|
||||
app.session.onLoad((_e) => {
|
||||
const session = app.session;
|
||||
const updated_ids: number[] = [];
|
||||
for (const [id, code] of session.programs) {
|
||||
updated_ids.push(id);
|
||||
that.createOrSetSession(id, code);
|
||||
}
|
||||
that.activateSession(that.active_session);
|
||||
that.activateSession(that.activeSession);
|
||||
for (const [id, _] of that.sessions) {
|
||||
if (!updated_ids.includes(id)) {
|
||||
that.destroySession(id);
|
||||
}
|
||||
}
|
||||
}) as EventListener);
|
||||
});
|
||||
app.session.loadFromFragment();
|
||||
|
||||
app.session.onActiveLine(((e: CustomEvent) => {
|
||||
app.session.onActiveLine((e) => {
|
||||
const session = app.session;
|
||||
const id: number = e.detail;
|
||||
const active_line = session.getActiveLine(id);
|
||||
if (typeof active_line !== "undefined") {
|
||||
const marker = that.active_line_markers.get(id);
|
||||
const marker = that.activeLineMarkers.get(id);
|
||||
if (marker) {
|
||||
that.sessions.get(id)?.removeMarker(marker);
|
||||
that.active_line_markers.set(id, null);
|
||||
that.activeLineMarkers.set(id, null);
|
||||
}
|
||||
const session = that.sessions.get(id);
|
||||
if (session) {
|
||||
that.active_line_markers.set(
|
||||
that.activeLineMarkers.set(
|
||||
id,
|
||||
session.addMarker(
|
||||
new Range(active_line, 0, active_line, 1),
|
||||
@@ -301,14 +277,30 @@ export class IC10Editor extends BaseElement {
|
||||
true,
|
||||
),
|
||||
);
|
||||
if (that.active_session == id) {
|
||||
if (that.activeSession == id) {
|
||||
// editor.resize(true);
|
||||
// TODO: Scroll to line if vm was stepped
|
||||
//that.editor.scrollToLine(active_line, true, true, ()=>{})
|
||||
}
|
||||
}
|
||||
}
|
||||
}) as EventListener);
|
||||
});
|
||||
|
||||
app.session.onIDChange((e) => {
|
||||
const oldID = e.detail.old;
|
||||
const newID = e.detail.new;
|
||||
if (this.sessions.has(oldID)) {
|
||||
this.sessions.set(newID, this.sessions.get(oldID));
|
||||
this.sessions.delete(oldID);
|
||||
}
|
||||
if (this.activeLineMarkers.has(oldID)) {
|
||||
this.activeLineMarkers.set(newID, this.activeLineMarkers.get(oldID));
|
||||
this.activeLineMarkers.delete(oldID);
|
||||
}
|
||||
if (this.activeSession === oldID) {
|
||||
this.activeSession = newID;
|
||||
}
|
||||
});
|
||||
|
||||
// change -> possibility to allow saving the value without having to wait for blur
|
||||
editor.on("change", () => this.editorChangeAction());
|
||||
@@ -521,7 +513,7 @@ export class IC10Editor extends BaseElement {
|
||||
const mode = ace.require(this.mode);
|
||||
const options = mode?.options ?? {};
|
||||
this.languageProvider?.setSessionOptions(session, options);
|
||||
this.active_session = session_id;
|
||||
this.activeSession = session_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -569,7 +561,7 @@ export class IC10Editor extends BaseElement {
|
||||
}
|
||||
const session = this.sessions.get(session_id);
|
||||
this.sessions.delete(session_id);
|
||||
if ((this.active_session = session_id)) {
|
||||
if ((this.activeSession = session_id)) {
|
||||
this.activateSession(this.sessions.entries().next().value);
|
||||
}
|
||||
session?.destroy();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import type { ICError, FrozenVM, SlotType } from "ic10emu_wasm";
|
||||
import { App } from "./app";
|
||||
|
||||
@@ -57,7 +56,25 @@ export class Session extends EventTarget {
|
||||
);
|
||||
}
|
||||
|
||||
onActiveIc(callback: EventListenerOrEventListenerObject) {
|
||||
changeID(oldID: number, newID: number) {
|
||||
if (this.programs.has(oldID)) {
|
||||
this.programs.set(newID, this.programs.get(oldID));
|
||||
this.programs.delete(oldID);
|
||||
}
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("session-id-change", {
|
||||
detail: { old: oldID, new: newID },
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
onIDChange(
|
||||
callback: (e: CustomEvent<{ old: number; new: number }>) => any,
|
||||
) {
|
||||
this.addEventListener("session-id-change", callback);
|
||||
}
|
||||
|
||||
onActiveIc(callback: (e: CustomEvent<number>) => any,) {
|
||||
this.addEventListener("session-active-ic", callback);
|
||||
}
|
||||
|
||||
@@ -98,11 +115,11 @@ export class Session extends EventTarget {
|
||||
);
|
||||
}
|
||||
|
||||
onErrors(callback: EventListenerOrEventListenerObject) {
|
||||
onErrors(callback: (e: CustomEvent<number[]>) => any) {
|
||||
this.addEventListener("session-errors", callback);
|
||||
}
|
||||
|
||||
onLoad(callback: EventListenerOrEventListenerObject) {
|
||||
onLoad(callback: (e: CustomEvent<Session>) => any) {
|
||||
this.addEventListener("session-load", callback);
|
||||
}
|
||||
|
||||
@@ -114,7 +131,7 @@ export class Session extends EventTarget {
|
||||
);
|
||||
}
|
||||
|
||||
onActiveLine(callback: EventListenerOrEventListenerObject) {
|
||||
onActiveLine(callback: (e: CustomEvent<number>) => any) {
|
||||
this.addEventListener("active-line", callback);
|
||||
}
|
||||
|
||||
|
||||
@@ -111,60 +111,80 @@ export const VMDeviceMixin = <T extends Constructor<LitElement>>(
|
||||
|
||||
connectedCallback(): void {
|
||||
const root = super.connectedCallback();
|
||||
window.VM.get().then((vm) =>
|
||||
window.VM.get().then((vm) => {
|
||||
vm.addEventListener(
|
||||
"vm-device-modified",
|
||||
this._handleDeviceModified.bind(this),
|
||||
),
|
||||
);
|
||||
window.VM.get().then((vm) =>
|
||||
);
|
||||
vm.addEventListener(
|
||||
"vm-devices-update",
|
||||
this._handleDevicesModified.bind(this),
|
||||
),
|
||||
);
|
||||
);
|
||||
vm.addEventListener(
|
||||
"vm-device-id-change",
|
||||
this._handleDeviceIdChange.bind(this),
|
||||
);
|
||||
});
|
||||
this.updateDevice();
|
||||
return root;
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
window.VM.get().then((vm) =>
|
||||
window.VM.get().then((vm) => {
|
||||
vm.removeEventListener(
|
||||
"vm-device-modified",
|
||||
this._handleDeviceModified.bind(this),
|
||||
),
|
||||
);
|
||||
window.VM.get().then((vm) =>
|
||||
);
|
||||
vm.removeEventListener(
|
||||
"vm-devices-update",
|
||||
this._handleDevicesModified.bind(this),
|
||||
),
|
||||
);
|
||||
);
|
||||
vm.removeEventListener(
|
||||
"vm-device-id-change",
|
||||
this._handleDeviceIdChange.bind(this),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
_handleDeviceModified(e: CustomEvent) {
|
||||
const id = e.detail;
|
||||
const activeIc = window.VM.vm.activeIC;
|
||||
const activeIcId = window.App.app.session.activeIC;
|
||||
if (this.deviceID === id) {
|
||||
this.updateDevice();
|
||||
} else if (id === activeIc.id && this.deviceSubscriptions.includes("active-ic")) {
|
||||
} else if (
|
||||
id === activeIcId &&
|
||||
this.deviceSubscriptions.includes("active-ic")
|
||||
) {
|
||||
this.updateDevice();
|
||||
}
|
||||
}
|
||||
|
||||
_handleDevicesModified(e: CustomEvent<number[]>) {
|
||||
const activeIc = window.VM.vm.activeIC;
|
||||
const activeIcId = window.App.app.session.activeIC;
|
||||
const ids = e.detail;
|
||||
if (ids.includes(this.deviceID)) {
|
||||
this.updateDevice()
|
||||
} else if (ids.includes(activeIc.id) && this.deviceSubscriptions.includes("active-ic")) {
|
||||
this.updateDevice();
|
||||
} else if (
|
||||
ids.includes(activeIcId) &&
|
||||
this.deviceSubscriptions.includes("active-ic")
|
||||
) {
|
||||
this.updateDevice();
|
||||
}
|
||||
}
|
||||
|
||||
_handleDeviceIdChange(e: CustomEvent<{ old: number; new: number }>) {
|
||||
if (this.deviceID === e.detail.old) {
|
||||
this.deviceID = e.detail.new;
|
||||
}
|
||||
}
|
||||
|
||||
updateDevice() {
|
||||
this.device = window.VM.vm.devices.get(this.deviceID)!;
|
||||
|
||||
if (typeof this.device === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const sub of this.deviceSubscriptions) {
|
||||
if (typeof sub === "string") {
|
||||
if (sub == "name") {
|
||||
@@ -220,16 +240,21 @@ export const VMDeviceMixin = <T extends Constructor<LitElement>>(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( "field" in sub ) {
|
||||
if ("field" in sub) {
|
||||
const fields = this.device.fields;
|
||||
if (this.fields.get(sub.field) !== fields.get(sub.field)) {
|
||||
this.fields = fields;
|
||||
}
|
||||
} else if ( "slot" in sub) {
|
||||
} else if ("slot" in sub) {
|
||||
const slots = this.device.slots;
|
||||
if (typeof this.slots === "undefined" || this.slots.length < sub.slot) {
|
||||
if (
|
||||
typeof this.slots === "undefined" ||
|
||||
this.slots.length < sub.slot
|
||||
) {
|
||||
this.slots = slots;
|
||||
} else if (!structuralEqual(this.slots[sub.slot], slots[sub.slot])) {
|
||||
} else if (
|
||||
!structuralEqual(this.slots[sub.slot], slots[sub.slot])
|
||||
) {
|
||||
this.slots = slots;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,7 +361,7 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) {
|
||||
const val = parseIntWithHexOrBinary(input.value);
|
||||
if (!isNaN(val)) {
|
||||
window.VM.get().then((vm) => {
|
||||
if (!vm.changeDeviceId(this.deviceID, val)) {
|
||||
if (!vm.changeDeviceID(this.deviceID, val)) {
|
||||
input.value = this.deviceID.toString();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ export interface ToastMessage {
|
||||
}
|
||||
|
||||
export interface CacheDeviceRef extends DeviceRef {
|
||||
dirty: boolean
|
||||
dirty: boolean;
|
||||
}
|
||||
|
||||
function cachedDeviceRef(ref: DeviceRef) {
|
||||
@@ -43,12 +43,12 @@ function cachedDeviceRef(ref: DeviceRef) {
|
||||
},
|
||||
set(target, prop, value) {
|
||||
if (prop === "dirty") {
|
||||
slotsDirty = value
|
||||
slotsDirty = value;
|
||||
return true;
|
||||
}
|
||||
return Reflect.set(target, prop, value)
|
||||
}
|
||||
}) as CacheDeviceRef
|
||||
return Reflect.set(target, prop, value);
|
||||
},
|
||||
}) as CacheDeviceRef;
|
||||
}
|
||||
|
||||
class VirtualMachine extends EventTarget {
|
||||
@@ -264,13 +264,22 @@ class VirtualMachine extends EventTarget {
|
||||
this.dispatchEvent(new CustomEvent("vm-message", { detail: message }));
|
||||
}
|
||||
|
||||
changeDeviceId(old_id: number, new_id: number): boolean {
|
||||
changeDeviceID(oldID: number, newID: number): boolean {
|
||||
try {
|
||||
this.ic10vm.changeDeviceId(old_id, new_id);
|
||||
this.updateDevices();
|
||||
if (this.app.session.activeIC === old_id) {
|
||||
this.app.session.activeIC = new_id;
|
||||
this.ic10vm.changeDeviceId(oldID, newID);
|
||||
if (this.app.session.activeIC === oldID) {
|
||||
this.app.session.activeIC = newID;
|
||||
}
|
||||
this.updateDevices();
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("vm-device-id-change", {
|
||||
detail: {
|
||||
old: oldID,
|
||||
new: newID,
|
||||
},
|
||||
}),
|
||||
);
|
||||
this.app.session.changeID(oldID, newID);
|
||||
return true;
|
||||
} catch (err) {
|
||||
this.handleVmError(err);
|
||||
@@ -430,7 +439,11 @@ class VirtualMachine extends EventTarget {
|
||||
}
|
||||
}
|
||||
|
||||
setDeviceSlotOccupant(id: number, index: number, template: SlotOccupantTemplate): boolean {
|
||||
setDeviceSlotOccupant(
|
||||
id: number,
|
||||
index: number,
|
||||
template: SlotOccupantTemplate,
|
||||
): boolean {
|
||||
const device = this._devices.get(id);
|
||||
if (typeof device !== "undefined") {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user