Skip to content

Commit ee88cf7

Browse files
authored
Merge branch 'main' into feature/include-file-input
2 parents 918ac2e + bb5d38a commit ee88cf7

File tree

2 files changed

+143
-12
lines changed

2 files changed

+143
-12
lines changed

src/fourc_webviewer/fourc_webserver.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,10 @@ def init_pyvista_render_objects(self):
310310
)
311311
self.state.vtu_path = fourc_geometry.vtu_file_path
312312

313+
# render window initialization: to be done only once while starting the webviewer, otherwise no proper binding within the current setup!
314+
if "render_window" not in self._server_vars:
315+
self._server_vars["render_window"] = pv.Plotter()
316+
313317
if self.state.vtu_path == "":
314318
self.state.read_in_status = self.state.all_read_in_statuses[
315319
"vtu_conversion_error"
@@ -491,6 +495,7 @@ def init_general_sections_state_and_server_vars(self):
491495

492496
# loop through input file sections
493497
self.state.general_sections = {}
498+
self.state.add_section = ""
494499
self.state.add_key = "" # key for the add property row
495500
self.state.add_value = "" # value for the add property row
496501
for section_name, section_data in self._server_vars[
@@ -1243,6 +1248,97 @@ def change_export_fourc_yaml_path(self, export_fourc_yaml_path, **kwargs):
12431248
#################################################
12441249
# SELECTION CHANGES #################################
12451250
################################################
1251+
@controller.set("click_delete_section_button")
1252+
def click_delete_section_button(self, **kwargs):
1253+
"""Deletes the currently selected section; if it was the last
1254+
subsection, delete the main too."""
1255+
if self.state.selected_section_name in self.state.json_schema.get(
1256+
"required", []
1257+
):
1258+
return
1259+
1260+
cur_main = self.state.selected_main_section_name
1261+
cur_section = self.state.selected_section_name
1262+
if not cur_main or not cur_section:
1263+
return
1264+
1265+
general_sections = copy.deepcopy(self.state.general_sections) or {}
1266+
sections_names = copy.deepcopy(self.state.section_names) or {}
1267+
1268+
# delete the subsection's data
1269+
del general_sections[cur_main][cur_section]
1270+
self.state.general_sections = general_sections
1271+
1272+
# rebuild subsections list (new list ref -> reactive)
1273+
subs_before = sections_names[cur_main]["subsections"]
1274+
new_subs = [s for s in subs_before if s != cur_section]
1275+
sections_names[cur_main] = {**sections_names[cur_main], "subsections": new_subs}
1276+
1277+
if cur_section == cur_main:
1278+
# last one -> delete the main group immediately
1279+
sections_names.pop(cur_main, None)
1280+
general_sections.pop(cur_main, None)
1281+
self.state.section_names = sections_names
1282+
self.state.general_sections = general_sections
1283+
1284+
# choose a new valid selection
1285+
new_main = next(iter(sections_names.keys()), "")
1286+
self.state.selected_main_section_name = new_main
1287+
self.state.selected_section_name = (
1288+
sections_names[new_main]["subsections"][0]
1289+
if new_main and sections_names[new_main]["subsections"]
1290+
else ""
1291+
)
1292+
return
1293+
1294+
self.state.section_names = sections_names
1295+
self.state.selected_main_section_name = cur_main
1296+
self.state.selected_section_name = new_subs[0] if new_subs else ""
1297+
1298+
@change("add_section")
1299+
def change_add_section(self, **kwargs):
1300+
"""Reaction to section selection."""
1301+
add_section = self.state.add_section
1302+
main_section_name = add_section.split("/")[0] or ""
1303+
1304+
if add_section not in self.state.json_schema.get("properties", {}):
1305+
return
1306+
1307+
general_sections = copy.deepcopy(self.state.general_sections) or {}
1308+
section_names = copy.deepcopy(self.state.section_names) or {}
1309+
1310+
# Ensure main buckets exist
1311+
if main_section_name not in section_names:
1312+
section_names[main_section_name] = {
1313+
"subsections": [main_section_name],
1314+
"content_mode": self.state.all_content_modes["general_section"],
1315+
}
1316+
if main_section_name not in general_sections:
1317+
general_sections[main_section_name] = {main_section_name: {}}
1318+
1319+
# Store data under main -> sub
1320+
if add_section not in general_sections[main_section_name]:
1321+
general_sections[main_section_name][add_section] = {}
1322+
1323+
# Replace subsections list with a NEW list object
1324+
subs = section_names[main_section_name]["subsections"]
1325+
if add_section not in subs:
1326+
subs = subs + [add_section] # new list ref
1327+
section_names[main_section_name] = {
1328+
**section_names[main_section_name], # keep content_mode
1329+
"subsections": subs, # new list ref
1330+
}
1331+
1332+
# Commit (new references -> reactive)
1333+
self.state.general_sections = general_sections
1334+
self.state.section_names = section_names
1335+
1336+
# Set a valid selection so VSelect updates
1337+
self.state.selected_main_section_name = main_section_name
1338+
self.state.selected_section_name = add_section
1339+
1340+
self.state.add_section = ""
1341+
12461342
@change("selected_main_section_name")
12471343
def change_selected_main_section_name(self, selected_main_section_name, **kwargs):
12481344
"""Reaction to change of state.selected_main_section_name."""

src/fourc_webviewer/gui_utils.py

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,9 @@ def _sections_dropdown():
301301
items=("Object.keys(section_names)",),
302302
)
303303
vuetify.VSelect(
304-
v_if=("section_names[selected_main_section_name]['subsections'].length>1"),
304+
v_if=(
305+
"selected_main_section_name!=selected_section_name || section_names[selected_main_section_name]['subsections'].length>1",
306+
),
305307
v_model=("selected_section_name",),
306308
items=("section_names[selected_main_section_name]['subsections']",),
307309
)
@@ -628,6 +630,39 @@ def _functions_panel(server):
628630
)
629631

630632

633+
def _top_row(server):
634+
"""Top row layout (edit mode switch and add section)."""
635+
# EDIT MODE switch
636+
with html.Div(classes="d-flex align-center flex-nowrap w-100", style="gap: 12px;"):
637+
vuetify.VSwitch(
638+
v_model=("edit_mode", "all_edit_modes['view_mode']"),
639+
label=("edit_mode", "VIEW"),
640+
true_value=("all_edit_modes['edit_mode']",),
641+
false_value=("all_edit_modes['view_mode']",),
642+
color="primary",
643+
inset=True,
644+
classes="ma-0",
645+
)
646+
# add sections on the right
647+
with html.Div(
648+
classes="d-inline-flex align-center ml-auto",
649+
style="gap: 8px;",
650+
v_if="edit_mode == all_edit_modes['edit_mode']",
651+
):
652+
html.Span("Add Section:", classes="text-h6 font-weight-medium mr-3")
653+
vuetify.VAutocomplete(
654+
v_model=("add_section",),
655+
items=(
656+
"Object.keys(json_schema['properties']).filter(key => !new Set(['MATERIALS', 'TITLE', 'CLONING MATERIAL MAP', 'RESULT DESCRIPTION']).has(key) && !(['DESIGN', 'TOPOLOGY', 'ELEMENTS', 'NODE', 'FUNCT', 'GEOMETRY'].some(n => key.includes(n))))",
657+
),
658+
dense=True,
659+
solo=True,
660+
filterable=True,
661+
classes="ma-0 flex-grow-0",
662+
style="width: 200px;",
663+
)
664+
665+
631666
def _prop_value_table(server):
632667
"""Table (property - value) layout (for general sections)."""
633668

@@ -1467,24 +1502,24 @@ def create_gui(server, render_window):
14671502
with layout.drawer as drawer:
14681503
drawer.width = 800
14691504
with html.Div(v_if=("vtu_path != ''",)):
1470-
# EDIT MODE switch
1471-
vuetify.VSwitch(
1472-
v_model=("edit_mode", "all_edit_modes['view_mode']"),
1473-
label=("edit_mode", "VIEW"),
1474-
true_value=("all_edit_modes['edit_mode']",),
1475-
false_value=("all_edit_modes['view_mode']",),
1476-
color="primary",
1477-
inset=True,
1478-
classes="ml-5",
1479-
)
1480-
14811505
# Further elements with conditional rendering (see above)
1506+
_top_row(server)
14821507
_sections_dropdown()
14831508
_prop_value_table(server)
14841509
_materials_panel()
14851510
_functions_panel(server)
14861511
_design_conditions_panel()
14871512
_result_description_panel()
1513+
vuetify.VBtn(
1514+
text="DELETE SECTION",
1515+
classes="mx-auto d-block mt-10",
1516+
outlined=True,
1517+
color="red",
1518+
v_if=(
1519+
"!json_schema['required'].includes(selected_section_name) && Object.keys(general_sections).includes(selected_main_section_name)",
1520+
),
1521+
click=server.controller.click_delete_section_button,
1522+
)
14881523
with html.Div(classes="flex-column justify-start"):
14891524
vuetify.VCard(
14901525
title="No input file content available",

0 commit comments

Comments
 (0)