You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 lines
7.9 KiB

import {
world,
} from "./index.js";
import {
available_tiles,
} from "/stackline-wasm/pkg/stackline_wasm.js";
const right_pane = document.getElementById("right-pane");
const coordinates_elem = document.getElementById("coordinates");
const stack_elem = document.getElementById("stack");
const signal_elem = document.getElementById("signal");
const state_elem = document.getElementById("state");
const tile_elem = document.getElementById("tile");
const tile_name_elem = document.getElementById("tile-name");
const properties_elem = document.getElementById("tile-properties");
let templates = new Map();
export function update_selected(x, y) {
coordinates.innerText = `(${x}, ${y})`;
let full_tile = world.get(x, y);
if (!full_tile) {
right_pane.classList.remove("selected");
return;
}
let signal = full_tile.signal;
while (stack_elem.children.length > 0) {
stack_elem.removeChild(stack_elem.firstChild);
}
if (signal) {
signal_elem.classList.add("has-signal");
for (let element of signal.stack) {
let li = document.createElement("li");
if (typeof element === "string") {
li.innerText = `"${element}"`;
} else if (typeof element === "number") {
li.innerText = element.toString();
} else {
throw new Error("Unexpected element type: " + typeof element);
}
stack_elem.appendChild(li);
}
signal.free();
} else {
signal_elem.classList.remove("has-signal");
}
let tile = full_tile.tile;
if (tile) {
tile_elem.classList.add("has-tile");
let name = Object.keys(tile)[0];
tile_name_elem.innerText = name;
// Set properties
// TODO: only change the properties when necessary
while (properties_elem.children.length > 0) {
properties_elem.removeChild(properties_elem.firstChild);
}
let schema = full_tile.schema();
for (let [label, type, value] of schema_iter(schema, tile[name])) {
let input = create_input(type, value, on_change);
if (!input) continue;
let elem = document.createElement("li");
let label_elem = document.createElement("b");
label_elem.innerText = `${label}: `;
elem.appendChild(label_elem);
elem.appendChild(input);
properties_elem.appendChild(elem);
function on_change(new_value) {
// Traverse `tile` and change the corresponding schema element
tile[name] = schema_recurse(schema, tile[name], label, new_value);
let full_tile = world.get(x, y);
full_tile.tile = tile;
world.set(x, y, full_tile);
}
}
} else {
tile_elem.classList.remove("has-tile");
}
state_elem.innerText = full_tile.state;
full_tile.free();
right_pane.classList.add("selected");
}
export function init() {
// for (let name of available_tiles()) {
// let option = document.createElement("option");
// option.innerText = name;
// option.value = name;
// tile_name_elem.appendChild(option);
// }
document.querySelectorAll(".property-template").forEach((template) => {
templates.set(template.attributes?.name?.value ?? template.id, template);
});
}
function* schema_iter(schema, tile) {
if (Array.isArray(schema)) {
for (let n = 0; n < schema.length; n++) {
yield* schema_iter(schema[n], tile[n]);
}
} else if (typeof schema === "object") {
for (let name in schema) {
yield* schema_iter(schema[name], tile[name]);
}
} else if (typeof schema === "string") {
let res = schema.split(":");
res.push(tile);
yield res;
}
}
function schema_recurse(schema, tile, label, value) {
if (Array.isArray(schema)) {
for (let n = 0; n < schema.length; n++) {
tile[n] = schema_recurse(schema[n], tile[n], label, value);
}
return tile;
} else if (typeof schema === "object") {
for (let name in schema) {
tile[name] = schema_recurse(schema[name], tile[name], label, value);
}
return tile;
} else if (typeof schema === "string") {
if (schema.split(":")[0] === label) {
return value;
} else {
return tile;
}
}
}
function create_input(type, value, change_cb) {
let options = type.split("|");
for (let option of options) {
if (option === "Value") {
let res = templates.get("Value").content.cloneNode(true).querySelector("*");
let select_elem = res.querySelector("select");
let type = Object.keys(value)[0];
set_type(type);
function set_type(new_type) {
let map = new Map([["String", "string"], ["Number", "number"]]);
for (let [ty, cn] of map) {
if (ty === new_type) {
res.classList.add(cn);
} else {
res.classList.remove(cn);
}
}
type = new_type;
}
select_elem.addEventListener("change", () => {
set_type(select_elem.value);
if (type === "Number") {
value = {"Number": 0.0};
number_input.value = 0;
} else if (type === "String") {
value = {"String": ""};
string_input.value = "";
}
change_cb(value);
});
let number_input = res.querySelector(".value-number input");
if (type === "Number") {
number_input.value = value["Number"];
}
number_input.addEventListener("change", (evt) => {
if (type === "Number") {
value["Number"] = +number_input.value;
change_cb(value);
}
});
let string_input = res.querySelector(".value-string input");
if (type === "String") {
string_input.value = value["String"];
}
string_input.addEventListener("change", (evt) => {
if (type === "String") {
value["String"] = string_input.value;
change_cb(value);
}
});
return res;
} else if (option === "Uint" || option === "Int") {
let res = templates.get(option).content.cloneNode(true).querySelector("*");
if (value !== undefined) {
res.value = value;
}
res.addEventListener("change", () => {
change_cb(+res.value);
});
return res;
} else if (option === "Signal") {
let res = templates.get(option).content.cloneNode(true).querySelector("*");
let stack_elem = res.querySelector(".stack");
for (let elem of value.stack) {
let li = document.createElement("li");
if (elem["Number"]) {
li.innerText = elem["Number"];
} else if (elem["String"]) {
li.innerText = `"${elem["String"]}"`;
}
stack_elem.appendChild(li);
}
let direction_elem = res.querySelector(".direction");
direction_elem.value = value.direction;
return res;
}
if (templates.has(option)) {
let res = templates.get(option).content.cloneNode(true).querySelector("*");
if (value !== undefined) {
res.value = value;
}
res.addEventListener("change", () => {
change_cb(res.value);
});
return res;
}
}
}