From 92ab8f320231b4f75a8bfca5a9ba9cbe8c761e41 Mon Sep 17 00:00:00 2001 From: Nick Beckley Date: Mon, 22 Jun 2026 14:43:09 +0100 Subject: [PATCH] Done. The Selected Block editor now uses grid-style coordinate dropdowns in [Edit.cshtml (line 423)](C:/Source/PlotLine/PlotLine/Views/FloorPlans/Edit.cshtml:423). What changed: X is now a dropdown showing A, B, C, AA, etc., while still saving 0, 1, 2, etc. Y is now a dropdown showing 1, 2, 3, etc., while still saving 0, 1, 2, etc. Options are limited to valid positions for the active floor and current block size. Dragging, manual dropdown changes, block resizing, and grid resizing all keep the controls synced through the existing block write/clamp path. Verification: dotnet build PlotLine.slnx passes with 0 warnings and 0 errors. No database, rendering model, transition logic, or AJAX architecture changes. --- PlotLine/Views/FloorPlans/Edit.cshtml | 65 ++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/PlotLine/Views/FloorPlans/Edit.cshtml b/PlotLine/Views/FloorPlans/Edit.cshtml index b225bcb..13efd58 100644 --- a/PlotLine/Views/FloorPlans/Edit.cshtml +++ b/PlotLine/Views/FloorPlans/Edit.cshtml @@ -423,11 +423,21 @@
- +
- +
@@ -1167,6 +1177,23 @@ return label; } + function populateCoordinateSelect(select, count, labelForValue, selectedValue) { + if (!select) return; + const selected = String(Math.max(0, Math.min(Number(selectedValue || 0), Math.max(count - 1, 0)))); + const existingValues = [...select.options].map(option => option.value).join("|"); + const nextValues = Array.from({ length: Math.max(count, 1) }, (_, index) => String(index)).join("|"); + if (existingValues !== nextValues) { + select.replaceChildren(...Array.from({ length: Math.max(count, 1) }, (_, index) => { + const option = document.createElement("option"); + option.value = String(index); + option.textContent = labelForValue(index); + return option; + })); + } + select.value = selected; + select.dataset.coordinateValue = selected; + } + function refreshGridCoordinateLabels() { const show = gridCoordinatesToggle?.checked === true; panels.forEach(panel => { @@ -1665,11 +1692,16 @@ const wrap = document.createElement("div"); wrap.className = "col-6"; wrap.innerHTML = ``; - const input = document.createElement("input"); - input.className = "form-control form-control-sm"; - input.type = "number"; - input.min = field === "x" || field === "y" ? "0" : "1"; - input.max = field === "x" || field === "y" ? "79" : "80"; + const input = field === "x" || field === "y" ? document.createElement("select") : document.createElement("input"); + input.className = field === "x" || field === "y" ? "form-select form-select-sm" : "form-control form-control-sm"; + if (input instanceof HTMLInputElement) { + input.type = "number"; + input.min = "1"; + input.max = "80"; + } else { + input.dataset.coordinateAxis = field; + input.dataset.coordinateValue = value; + } input.name = `Blocks[${index}].${property}`; input.value = value; input.dataset.blockField = field; @@ -1738,6 +1770,7 @@ blocks.push(button); attachBlockEvents(button); createBlockEditor(block); + writeBlock(button, readBlock(button)); checkOverlaps(); return button; } @@ -1818,8 +1851,8 @@ function readBlock(block) { const fields = fieldsFor(block); return { - x: Number(fields.x?.value || block.style.getPropertyValue("--x") || 0), - y: Number(fields.y?.value || block.style.getPropertyValue("--y") || 0), + x: Number(fields.x?.value || fields.x?.dataset.coordinateValue || block.style.getPropertyValue("--x") || 0), + y: Number(fields.y?.value || fields.y?.dataset.coordinateValue || block.style.getPropertyValue("--y") || 0), w: Number(fields.w?.value || block.style.getPropertyValue("--w") || 1), h: Number(fields.h?.value || block.style.getPropertyValue("--h") || 1) }; @@ -1827,13 +1860,18 @@ function writeBlock(block, values) { const next = clampBlock(block, values); + const grid = gridFor(block); + const gridWidth = Number(grid?.dataset.gridWidth || 24); + const gridHeight = Number(grid?.dataset.gridHeight || 16); + const maxXOptions = Math.max(gridWidth - next.w + 1, 1); + const maxYOptions = Math.max(gridHeight - next.h + 1, 1); block.style.setProperty("--x", next.x); block.style.setProperty("--y", next.y); block.style.setProperty("--w", next.w); block.style.setProperty("--h", next.h); const fields = fieldsFor(block); - if (fields.x) fields.x.value = next.x; - if (fields.y) fields.y.value = next.y; + populateCoordinateSelect(fields.x, maxXOptions, gridColumnLabel, next.x); + populateCoordinateSelect(fields.y, maxYOptions, value => String(value + 1), next.y); if (fields.w) fields.w.value = next.w; if (fields.h) fields.h.value = next.h; scheduleGeometryRefresh(); @@ -2467,7 +2505,10 @@ saveLayoutAsync(); }); - blocks.forEach(attachBlockEvents); + blocks.forEach(block => { + attachBlockEvents(block); + writeBlock(block, readBlock(block)); + }); editor.addEventListener("pointermove", event => { if (!pointerState) return;