TrayLayout: Make generation a one step operation in the web UI

Add Java Script for generating the layout from sx and sy
Drop special handling in boxesserver
Add .UI attribute to Boxes class to allow behaving differntly on different UIs
Traylayout is still filtered out from Inkscape INX file generation
Slightly adjust layout format of GridfinityTrayLayout

Co-authored-by: Florian Festi <florian@festi.info>
This commit is contained in:
caleb crome 2023-03-02 15:14:50 +01:00 committed by Florian Festi
parent b807cc99ff
commit 0b986eeb0c
5 changed files with 108 additions and 36 deletions

View File

@ -285,6 +285,7 @@ class Boxes:
webinterface = True webinterface = True
ui_group = "Misc" ui_group = "Misc"
UI = ""
description: str = "" # Markdown syntax is supported description: str = "" # Markdown syntax is supported

View File

@ -1,10 +1,10 @@
import boxes import boxes
from boxes import Boxes from boxes import Boxes
from boxes.generators.traylayout import TrayLayout, TrayLayout2 from boxes.generators.traylayout import TrayLayout
from boxes.Color import Color from boxes.Color import Color
from boxes import restore from boxes import restore
class GridfinityTrayLayout(TrayLayout2): class GridfinityTrayLayout(TrayLayout):
"""A Gridfinity Tray Generator based on TrayLayout""" """A Gridfinity Tray Generator based on TrayLayout"""
description = """ description = """

View File

@ -19,7 +19,7 @@ import boxes
from boxes import * from boxes import *
class TrayLayout(Boxes): class TrayLayoutFile(Boxes):
"""Generate a layout file for a typetray.""" """Generate a layout file for a typetray."""
# This class generates the skeleton text file that can then be edited # This class generates the skeleton text file that can then be edited
# to describe the actual box # to describe the actual box
@ -29,7 +29,7 @@ The layout is based on a grid of sizes in x and y direction.
Choose how many distances you need in both directions. Choose how many distances you need in both directions.
The actual sizes and all other settings can be entered in the second step.""" The actual sizes and all other settings can be entered in the second step."""
webinterface = True webinterface = False
ui_group = "Tray" ui_group = "Tray"
@ -83,13 +83,13 @@ The actual sizes and all other settings can be entered in the second step."""
f.write(str(self)) f.write(str(self))
class TrayLayout2(Boxes): class TrayLayout(Boxes):
"""Generate a typetray from a layout file.""" """Generate a typetray from a layout file."""
# This class reads in the layout either from a file (with --input) or # This class reads in the layout either from a file (with --input) or
# as string (with --layout) and turns it into a drawing for a box. # as string (with --layout) and turns it into a drawing for a box.
webinterface = True ui_group = "Tray"
description = """This is a two step process. This is step 2. description = """This is a two step process. This is step 2.
Edit the layout text graphics to adjust your tray. Edit the layout text graphics to adjust your tray.
@ -98,19 +98,19 @@ vertical bars representing the walls with a space character to remove the walls.
You can replace the space characters representing the floor by a "X" to remove the floor for this compartment. You can replace the space characters representing the floor by a "X" to remove the floor for this compartment.
""" """
def __init__(self, input=None, webargs=False) -> None: def __init__(self) -> None:
Boxes.__init__(self) super().__init__()
self.addSettingsArgs(boxes.edges.FingerJointSettings) self.addSettingsArgs(boxes.edges.FingerJointSettings)
self.buildArgParser("h", "hi", "outside") self.buildArgParser("h", "hi", "outside", "sx", "sy")
if not webargs: if self.UI == "web":
self.argparser.add_argument(
"--layout", action="store", type=str, default="")
else:
self.argparser.add_argument( self.argparser.add_argument(
"--input", action="store", type=argparse.FileType('r'), "--input", action="store", type=argparse.FileType('r'),
default="traylayout.txt", default="traylayout.txt",
help="layout file") help="layout file")
self.layout = None self.layout = None
else:
self.argparser.add_argument(
"--layout", action="store", type=str, default="")
def vWalls(self, x: int, y: int) -> int: def vWalls(self, x: int, y: int) -> int:
"""Number of vertical walls at a crossing.""" """Number of vertical walls at a crossing."""

View File

@ -113,11 +113,11 @@ class BServer:
def __init__(self, url_prefix="", static_url="static") -> None: def __init__(self, url_prefix="", static_url="static") -> None:
self.boxes = {b.__name__: b for b in boxes.generators.getAllBoxGenerators().values() if b.webinterface} self.boxes = {b.__name__: b for b in boxes.generators.getAllBoxGenerators().values() if b.webinterface}
self.boxes['TrayLayout2'] = boxes.generators.traylayout.TrayLayout2 # type: ignore # no attribute "traylayout"
self.groups = boxes.generators.ui_groups self.groups = boxes.generators.ui_groups
self.groups_by_name = boxes.generators.ui_groups_by_name self.groups_by_name = boxes.generators.ui_groups_by_name
for name, box in self.boxes.items(): for name, box in self.boxes.items():
box.UI = "web"
self.groups_by_name.get(box.ui_group, self.groups_by_name.get(box.ui_group,
self.groups_by_name["Misc"]).add(box) self.groups_by_name["Misc"]).add(box)
@ -351,8 +351,6 @@ class BServer:
<div id="{nr}">\n <ul>\n''') <div id="{nr}">\n <ul>\n''')
for box in group.generators: for box in group.generators:
name = box.__name__ name = box.__name__
if name in ("TrayLayout2",):
continue
docs = "" docs = ""
if box.__doc__: if box.__doc__:
docs = " - " + _(box.__doc__) docs = " - " + _(box.__doc__)
@ -595,10 +593,7 @@ class BServer:
self._cache[lang_name] = list(self.genPageMenu(lang)) self._cache[lang_name] = list(self.genPageMenu(lang))
return self._cache[lang_name] return self._cache[lang_name]
if name == "TrayLayout2": box = box_cls()
box = box_cls(self, webargs=True)
else:
box = box_cls()
box.translations = lang box.translations = lang
@ -618,18 +613,6 @@ class BServer:
except ArgumentParserError as e: except ArgumentParserError as e:
start_response(status, headers) start_response(status, headers)
return self.genPageError(name, e, lang) return self.genPageError(name, e, lang)
if name == "TrayLayout":
start_response(status, headers)
box.fillDefault(box.sx, box.sy)
layout2 = boxes.generators.traylayout.TrayLayout2(self, webargs=True)
layout2.argparser.set_defaults(layout=str(box))
return self.args2html(name, layout2, lang, action="TrayLayout2")
if name == "TrayLayout2":
try:
box.parse(box.layout.split("\n"))
except Exception as e:
start_response(status, headers)
return self.genPageError(name, e, lang)
try: try:
fd, box.output = tempfile.mkstemp() fd, box.output = tempfile.mkstemp()

View File

@ -108,7 +108,7 @@ function GridfinityTrayLayout_GenerateLayout(x, y, nx, ny, countx, county) {
} }
for (i = 0; i < county; i++) { for (i = 0; i < county; i++) {
layout += "+-".repeat(countx) + "+\n"; layout += "+-".repeat(countx) + "+\n";
layout += "| ".repeat(countx) + `|${stepy}mm\n`; layout += "| ".repeat(countx) + `| ${stepy}mm\n`;
} }
layout += "+-".repeat(countx) + "+\n"; layout += "+-".repeat(countx) + "+\n";
return layout return layout
@ -157,16 +157,104 @@ function GridfinityTrayLayoutInit() {
layout_id.rows = 20; layout_id.rows = 20;
layout_id.cols = 24; layout_id.cols = 24;
} }
function ParseSections(s) {
var sections = [];
for (var section of s.split(":")) {
var operands = section.split("/");
if (operands.length > 2) return sections;
if (operands.length == 2) {
for (var i=0; i<operands[1]; i++) {
sections.push(Number(operands[0])/Number(operands[1]));
}
continue;
}
operands = section.split("*");
if (operands.length > 2) return sections;
if (operands.length == 2) {
for (var i=0; i<operands[1]; i++) {
sections.push(Number(operands[0]));
}
continue;
}
sections.push(Number(section));
}
return sections;
}
function TrayLayout_GenerateLayout(sx, sy) {
sx = ParseSections(sx);
sy = ParseSections(sy);
nx = sx.length
ny = sy.length
layout = '';
if (nx <= 0)
nx = 1;
if (ny <= 0)
ny = 1;
for (i = 0; i < nx; i++) {
line = ' |'.repeat(i) + ` ,> ${sx[i].toFixed(2)}mm\n`;
layout += line;
}
for (i = 0; i < ny; i++) {
layout += "+-".repeat(nx) + "+\n";
layout += "| ".repeat(nx) + `| ${sy[i].toFixed(2)}mm\n`;
}
layout += "+-".repeat(nx) + "+\n";
return layout
}
function TrayUpdateLayout(event) {
if (window.layoutUpdated == true) {
// Don't do the update if the layout has been manually touched.
if (confirm("You have manually updated the Layout. Do you wish to regenerate it?")) {
window.layoutUpdated = false;
} else {
return;
}
}
sx = document.getElementById('sx').value;
sy = document.getElementById('sy').value;
layout_id = document.getElementById('layout');
layout_id.value = TrayLayout_GenerateLayout(sx, sy);
}
function TrayLayoutInit() {
ids = ['sx', 'sy'];
window.layoutUpdated=false;
for (id_string of ids) {
id = document.getElementById(id_string);
id.addEventListener('input', TrayUpdateLayout);
}
TrayUpdateLayout();
layout_id = document.getElementById('layout');
layout_id.addEventListener('change', setUpdated);
layout_id.addEventListener('input', setUpdated);
layout_id.rows = 20;
layout_id.cols = 24;
}
function addCallbacks() { function addCallbacks() {
if (window.location.href.includes("/GridfinityTrayLayout")) page_callbacks = {
GridfinityTrayLayoutInit(); "TrayLayout": TrayLayoutInit,
"GridfinityTrayLayout": GridfinityTrayLayoutInit,
};
loc = new URL(window.location.href);
pathname = loc.pathname;
page = pathname.substr(pathname.lastIndexOf('/')+1);
if (page in page_callbacks) {
callback = page_callbacks[page];
callback();
}
} }
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
addCallbacks(); addCallbacks();
}, false); }, false);
function collapseAll() { function collapseAll() {
const h = document.getElementsByClassName("toggle"); const h = document.getElementsByClassName("toggle");
for (let el of h) { for (let el of h) {