Spaces:
Sleeping
Sleeping
Commit ·
dabc7b1
1
Parent(s): 975a31d
Add per-shape G-code preview boxes with correct download filenames
Browse filesOn the TIFF Slices to GCode tab, each shape now shows its generated
G-code in a fixed-height, scrollable box aligned under its download
box, populated on generation. The in-box download button is stamped
with the real filename (e.g. Hollow_Pyramid_SnakePath_gcode.txt)
instead of gr.Code's hardcoded "file.txt".
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
app.py
CHANGED
|
@@ -129,6 +129,15 @@ APP_CSS = """
|
|
| 129 |
color: var(--body-text-color-subdued);
|
| 130 |
margin-top: -0.3rem !important;
|
| 131 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
"""
|
| 133 |
|
| 134 |
# Gradio 6.10's gr.Model3D leaves the Undo (reset view) button permanently
|
|
@@ -982,6 +991,23 @@ def run_all_tiff_to_gcode(
|
|
| 982 |
return outputs[0], outputs[1], outputs[2], "\n".join(messages)
|
| 983 |
|
| 984 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 985 |
GCODE_SOURCE_SHAPE1 = "Use Shape 1 G-Code"
|
| 986 |
GCODE_SOURCE_SHAPE2 = "Use Shape 2 G-Code"
|
| 987 |
GCODE_SOURCE_SHAPE3 = "Use Shape 3 G-Code"
|
|
@@ -1572,6 +1598,22 @@ def build_demo() -> gr.Blocks:
|
|
| 1572 |
gcode_file_2 = gr.File(label="Download G-Code Shape 2")
|
| 1573 |
gcode_file_3 = gr.File(label="Download G-Code Shape 3")
|
| 1574 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1575 |
gcode_status = gr.Markdown("")
|
| 1576 |
|
| 1577 |
gcode_button.click(
|
|
@@ -1593,6 +1635,42 @@ def build_demo() -> gr.Blocks:
|
|
| 1593 |
pixel_size,
|
| 1594 |
],
|
| 1595 |
outputs=[gcode_file_1, gcode_file_2, gcode_file_3, gcode_status],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1596 |
)
|
| 1597 |
|
| 1598 |
with gr.Tab("G-Code Visualization"):
|
|
|
|
| 129 |
color: var(--body-text-color-subdued);
|
| 130 |
margin-top: -0.3rem !important;
|
| 131 |
}
|
| 132 |
+
|
| 133 |
+
/* Keep the per-shape G-code previews at a fixed height with internal scroll
|
| 134 |
+
(gr.Code's max_lines does not constrain the editor in this Gradio build). */
|
| 135 |
+
.gcode-view .cm-editor {
|
| 136 |
+
max-height: 320px;
|
| 137 |
+
}
|
| 138 |
+
.gcode-view .cm-scroller {
|
| 139 |
+
overflow: auto;
|
| 140 |
+
}
|
| 141 |
"""
|
| 142 |
|
| 143 |
# Gradio 6.10's gr.Model3D leaves the Undo (reset view) button permanently
|
|
|
|
| 991 |
return outputs[0], outputs[1], outputs[2], "\n".join(messages)
|
| 992 |
|
| 993 |
|
| 994 |
+
def load_all_gcode_text(
|
| 995 |
+
path1: str | None,
|
| 996 |
+
path2: str | None,
|
| 997 |
+
path3: str | None,
|
| 998 |
+
) -> tuple[str, str, str]:
|
| 999 |
+
"""Return the raw text of each shape's generated G-code file for display."""
|
| 1000 |
+
def read(path: str | None, shape_num: int) -> str:
|
| 1001 |
+
if not path:
|
| 1002 |
+
return f"# No G-code generated for Shape {shape_num} yet."
|
| 1003 |
+
try:
|
| 1004 |
+
return Path(path).read_text()
|
| 1005 |
+
except OSError as exc:
|
| 1006 |
+
return f"# Failed to read G-code file: {exc}"
|
| 1007 |
+
|
| 1008 |
+
return read(path1, 1), read(path2, 2), read(path3, 3)
|
| 1009 |
+
|
| 1010 |
+
|
| 1011 |
GCODE_SOURCE_SHAPE1 = "Use Shape 1 G-Code"
|
| 1012 |
GCODE_SOURCE_SHAPE2 = "Use Shape 2 G-Code"
|
| 1013 |
GCODE_SOURCE_SHAPE3 = "Use Shape 3 G-Code"
|
|
|
|
| 1598 |
gcode_file_2 = gr.File(label="Download G-Code Shape 2")
|
| 1599 |
gcode_file_3 = gr.File(label="Download G-Code Shape 3")
|
| 1600 |
|
| 1601 |
+
# Per-shape G-code preview, aligned under each download box. Fixed
|
| 1602 |
+
# height with internal scrolling so the files don't fill the page.
|
| 1603 |
+
with gr.Row():
|
| 1604 |
+
gcode_view_1 = gr.Code(
|
| 1605 |
+
label="Shape 1 G-Code", language=None, lines=15, max_lines=15,
|
| 1606 |
+
interactive=False, elem_classes=["gcode-view"], elem_id="gcode-view-1",
|
| 1607 |
+
)
|
| 1608 |
+
gcode_view_2 = gr.Code(
|
| 1609 |
+
label="Shape 2 G-Code", language=None, lines=15, max_lines=15,
|
| 1610 |
+
interactive=False, elem_classes=["gcode-view"], elem_id="gcode-view-2",
|
| 1611 |
+
)
|
| 1612 |
+
gcode_view_3 = gr.Code(
|
| 1613 |
+
label="Shape 3 G-Code", language=None, lines=15, max_lines=15,
|
| 1614 |
+
interactive=False, elem_classes=["gcode-view"], elem_id="gcode-view-3",
|
| 1615 |
+
)
|
| 1616 |
+
|
| 1617 |
gcode_status = gr.Markdown("")
|
| 1618 |
|
| 1619 |
gcode_button.click(
|
|
|
|
| 1635 |
pixel_size,
|
| 1636 |
],
|
| 1637 |
outputs=[gcode_file_1, gcode_file_2, gcode_file_3, gcode_status],
|
| 1638 |
+
).then(
|
| 1639 |
+
fn=load_all_gcode_text,
|
| 1640 |
+
inputs=[gcode_file_1, gcode_file_2, gcode_file_3],
|
| 1641 |
+
outputs=[gcode_view_1, gcode_view_2, gcode_view_3],
|
| 1642 |
+
).then(
|
| 1643 |
+
# gr.Code's built-in download button hardcodes "file.txt"; stamp
|
| 1644 |
+
# the real filename (from each File value's orig_name) onto the
|
| 1645 |
+
# download link so it matches the Download G-Code Shape box.
|
| 1646 |
+
fn=None,
|
| 1647 |
+
inputs=[gcode_file_1, gcode_file_2, gcode_file_3],
|
| 1648 |
+
outputs=[],
|
| 1649 |
+
js="""(f1, f2, f3) => {
|
| 1650 |
+
const files = [f1, f2, f3];
|
| 1651 |
+
const nameOf = (f) => {
|
| 1652 |
+
if (!f) return null;
|
| 1653 |
+
if (f.orig_name) return f.orig_name;
|
| 1654 |
+
const p = f.path || f.url || "";
|
| 1655 |
+
return p ? p.split(/[\\\\/]/).pop() : null;
|
| 1656 |
+
};
|
| 1657 |
+
const apply = (tries) => {
|
| 1658 |
+
let pending = false;
|
| 1659 |
+
files.forEach((f, i) => {
|
| 1660 |
+
const name = nameOf(f);
|
| 1661 |
+
if (!name) return;
|
| 1662 |
+
const a = document.querySelector(`#gcode-view-${i + 1} a[download]`);
|
| 1663 |
+
if (a) {
|
| 1664 |
+
if (a.getAttribute("download") !== name) a.setAttribute("download", name);
|
| 1665 |
+
} else {
|
| 1666 |
+
pending = true;
|
| 1667 |
+
}
|
| 1668 |
+
});
|
| 1669 |
+
if (pending && tries < 20) setTimeout(() => apply(tries + 1), 150);
|
| 1670 |
+
};
|
| 1671 |
+
apply(0);
|
| 1672 |
+
return [];
|
| 1673 |
+
}""",
|
| 1674 |
)
|
| 1675 |
|
| 1676 |
with gr.Tab("G-Code Visualization"):
|