commit fc1cfa084ca07577058c7fc4a6cdd75c5f69a623
parent f62b47d3498b7da0874dc7ace47016c8298ae290
Author: Jacob R. Edwards <jacob@jacobedwards.org>
Date: Thu, 22 Aug 2024 12:07:43 -0700
Add handler for changing pointmap type in editor
Diffstat:
4 files changed, 160 insertions(+), 10 deletions(-)
diff --git a/files/floorplans/floorplan/editor.js b/files/floorplans/floorplan/editor.js
@@ -594,3 +594,8 @@ function byId(id) {
function refId(ref) {
return ref.type + "_" + ref.id
}
+
+export function idRef(id) {
+ let a = id.split("_")
+ return backend.newRef(a[0], a[1])
+}
diff --git a/files/floorplans/floorplan/main.css b/files/floorplans/floorplan/main.css
@@ -72,6 +72,14 @@ aside.terminal {
color: white;
}
+aside.menu {
+ padding: 1em;
+}
+
+aside.menu > form > input[type=radio] {
+ width: 100%;
+}
+
aside.message {
position: absolute;
box-sizing: border-box;
diff --git a/files/floorplans/floorplan/main.js b/files/floorplans/floorplan/main.js
@@ -2,7 +2,7 @@ import { default as SVG } from "/lib/github.com/svgdotjs/svg.js/svg.js"
import "/lib/github.com/svgdotjs/svg.panzoom.js/svg.panzoom.js"
import * as ui from "/lib/ui.js"
import * as etc from "/lib/etc.js"
-import { FloorplanEditor as Editor } from "./editor.js"
+import { FloorplanEditor as Editor, idRef } from "./editor.js"
import { Vector2 } from "/lib/github.com/ros2jsguy/threejs-math/math/Vector2.js"
import "./geometry.js"
@@ -176,7 +176,7 @@ let modes = {
mousedown: preciseAddWallHandler,
mousemove: preciseAddWallHandler,
mouseup: preciseAddWallHandler,
- keydown: [zoomKeysHandler, undoRedoHandler, preciseAddWallHandler,
+ keydown: [zoomKeysHandler, undoRedoHandler, preciseAddWallHandler, pointMapTypeHandler],
click: pointMapTypeHandler
}
}
@@ -193,6 +193,135 @@ function zoomKeysHandler(event, editor) {
event.preventDefault()
}
+// click, keydown
+function pointMapTypeHandler(event, editor, state) {
+ const cleanup = function() {
+ state.menu.remove()
+ for (let i in state) {
+ delete state[i]
+ }
+ }
+ const commit = function() {
+ editor.finishAction()
+ cleanup()
+ }
+ const cancel = function() {
+ // NOTE: I would use editor.undo(), but I'm not sure
+ // if I'll allow asynchronous menus,etc. in the future
+ editor.mapPointsById(state.orig, state.map.a, state.map.b)
+ cleanup()
+ }
+ const change = function(newvalue) {
+ editor.mapPointsById(newvalue, state.map.a, state.map.b)
+ editor.updateDisplay()
+ }
+
+ if (event.type === "keydown") {
+ if (!state.menu) {
+ return
+ }
+ if (event.key === "Enter") {
+ commit(event)
+ } else if (event.key === "Escape") {
+ cancel(event)
+ } else {
+ return
+ }
+ event.preventDefault()
+ return
+ }
+
+ if (event.type != "click") {
+ return
+ }
+
+ // No matter where the user clicks, the old
+ // menu should canceled
+ if (state.menu) {
+ cancel()
+ }
+
+ let map = editor.thingAt(editor.draw.point(event.clientX, event.clientY), "#pointmaps")
+ if (!map) {
+ return
+ }
+
+ map.select()
+ let ref = idRef(map.attr("id"))
+ state.map = editor.backend.cache.pointmaps[ref.id]
+ state.orig = state.map.type
+ if (state.menu) {
+ throw new Error("Menu should have already been removed")
+ }
+ state.menu = document.body.appendChild(
+ radioMenu(editor, "map_type", ["wall", "door"], state.orig, { callbacks: {
+ commit: commit,
+ change: change
+ }})
+ )
+
+ event.preventDefault()
+}
+
+function radioMenu(editor, key, values, initial, options) {
+ options = options ?? {}
+ options.callbacks = options.callbacks ?? {}
+
+ let menu = document.createElement("aside")
+ menu.classList.add("terminal")
+ menu.classList.add("menu")
+
+ let form = menu.appendChild(document.createElement("form"))
+ let container = form
+
+ if (options.legend) {
+ container.appendChild(document.createElement("legend"))
+ .appendChild(document.createTextNode(options.legend))
+ }
+
+ let radios = radioInputs(key, values, initial)
+ for (let i in radios) {
+ if (options.callbacks.change) {
+ radios[i].addEventListener("change", function(event) {
+ options.callbacks.change(event.target.value)
+ event.preventDefault()
+ })
+ }
+ container.append(radios[i])
+ }
+
+ let submit = container.appendChild(document.createElement("input"))
+ submit.setAttribute("type", "submit")
+ submit.setAttribute("value", "Change")
+
+ form.addEventListener("submit", function(event) {
+ if (options.callbacks.commit) {
+ options.callbacks.commit(event)
+ }
+ event.preventDefault()
+ })
+
+ return menu
+}
+
+function radioInputs(key, values, initial) {
+ let radios = []
+ for (let i in values) {
+ let label = document.createElement("label")
+ let radio = label.appendChild(document.createElement("input"))
+ radio.setAttribute("type", "radio")
+ radio.setAttribute("name", key)
+ radio.setAttribute("value", values[i])
+ if (values[i] === initial) {
+ radio.setAttribute("checked", true)
+ }
+ label.append(radio)
+ label.append(document.createTextNode(values[i]))
+ radios.push(label)
+ }
+ return radios
+}
+
// keydown
function undoRedoHandler(event, editor) {
if (event.ctrlKey) {
diff --git a/files/floorplans/floorplan/svg.css b/files/floorplans/floorplan/svg.css
@@ -1,20 +1,28 @@
/* SVG element CSS */
-.preview.wall {
- stroke: grey;
- stroke-width: 400;
+circle.selected {
+ fill: blue;
}
-#walls > line {
+line {
stroke: black;
stroke-width: 400;
}
+line.selected {
+ stroke: blue;
+}
+
+line.door {
+ stroke-width: 100;
+ stroke-dasharray: 400 100;
+}
+
+.preview.wall {
+ stroke: grey;
+}
+
.point {
r: 250;
fill: lightgrey;
}
-
-.point.selected {
- fill: blue;
-}