mabuseif commited on
Commit
df4c54c
·
verified ·
1 Parent(s): f692fa0

Update app/materials_library.py

Browse files
Files changed (1) hide show
  1. app/materials_library.py +239 -182
app/materials_library.py CHANGED
@@ -348,7 +348,7 @@ def categorize_thermal_mass(thermal_mass: float) -> str:
348
  def get_stable_button_key(prefix: str, name: str, action: str, unique_id: str = None) -> str:
349
  """Generate a stable button key based on prefix, name, action, and optional unique identifier."""
350
  import hashlib
351
- unique_id = unique_id or str(uuid.uuid4())[:8] # Generate unique ID if not provided
352
  key_string = f"{prefix}_{name}_{action}_{unique_id}"
353
  hash_key = hashlib.md5(key_string.encode()).hexdigest()[:8]
354
  return f"{prefix}_{action}_{name}_{hash_key}"
@@ -359,20 +359,25 @@ def display_materials_page():
359
  This is the main function called by main.py when the Material Library page is selected.
360
  """
361
  # Initialize session state
362
- if "rerun_pending" not in st.session_state:
363
- st.session_state.rerun_pending = False
364
  if "active_tab" not in st.session_state:
365
  st.session_state.active_tab = "Materials"
366
  if "material_action" not in st.session_state:
367
  st.session_state.material_action = {"action": None, "id": None}
368
  if "fenestration_action" not in st.session_state:
369
  st.session_state.fenestration_action = {"action": None, "id": None}
370
- if "rerun_trigger" not in st.session_state:
371
- st.session_state.rerun_trigger = None
372
 
373
- # Check for rerun trigger
374
- if st.session_state.rerun_pending:
375
- st.session_state.rerun_pending = False
 
 
 
 
 
 
 
376
  st.rerun()
377
 
378
  # Apply custom CSS for button styling
@@ -395,26 +400,186 @@ def display_materials_page():
395
  tab1, tab2 = st.tabs(["Materials", "Fenestrations"])
396
 
397
  with tab1:
398
- if st.session_state.active_tab == "Materials":
399
- st.session_state.active_tab = "Materials"
400
  display_materials_tab()
401
 
402
  with tab2:
403
- if st.session_state.active_tab == "Fenestrations":
404
- st.session_state.active_tab = "Fenestrations"
405
  display_fenestrations_tab()
406
 
407
  col1, col2 = st.columns(2)
408
 
409
  with col1:
410
  if st.button("Back to Climate Data", key="back_to_climate"):
411
- st.session_state.current_page = "Climate Data"
412
- st.session_state.rerun_pending = True
413
 
414
  with col2:
415
  if st.button("Continue to Construction", key="continue_to_construction"):
416
- st.session_state.current_page = "Construction"
417
- st.session_state.rerun_pending = True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
 
419
  def display_materials_tab():
420
  """Display the materials tab content."""
@@ -458,50 +623,21 @@ def display_materials_tab():
458
  copy_key = get_stable_button_key("lib_mat", name, "copy")
459
 
460
  if cols[3].button("Preview", key=preview_key):
461
- if st.session_state.rerun_trigger != f"preview_mat_{name}":
462
- st.session_state.rerun_trigger = f"preview_mat_{name}"
463
- st.session_state.material_editor = {
464
- "name": name,
465
- "category": material["category"],
466
- "thermal_conductivity": material["thermal_conductivity"],
467
- "density": material["density"],
468
- "specific_heat": material["specific_heat"],
469
- "default_thickness": material["default_thickness"],
470
- "embodied_carbon": material["embodied_carbon"],
471
- "cost": material["cost"],
472
- "absorptivity": material["absorptivity"],
473
- "emissivity": material["emissivity"],
474
- "colour": material["colour"],
475
- "edit_mode": False,
476
- "original_name": name,
477
- "is_library": True
478
- }
479
- st.session_state.material_form_state = {
480
- "name": name,
481
- "category": material["category"],
482
- "thermal_conductivity": float(material["thermal_conductivity"]),
483
- "density": float(material["density"]),
484
- "specific_heat": float(material["specific_heat"]),
485
- "default_thickness": float(material["default_thickness"]),
486
- "embodied_carbon": float(material["embodied_carbon"]),
487
- "cost": float(material["cost"]),
488
- "absorptivity": float(material["absorptivity"]),
489
- "emissivity": float(material["emissivity"]),
490
- "colour": material["colour"]
491
- }
492
- st.session_state.active_tab = "Materials"
493
- st.session_state.rerun_pending = True
494
-
495
  if cols[4].button("Copy", key=copy_key):
496
- new_name = f"{name}_Project"
497
- counter = 1
498
- while new_name in st.session_state.project_data["materials"]["project"] or new_name in library_materials:
499
- new_name = f"{name}_Project_{counter}"
500
- counter += 1
501
- st.session_state.project_data["materials"]["project"][new_name] = material.copy()
502
- st.success(f"Material '{new_name}' copied to project.")
503
- logger.info(f"Copied library material '{name}' as '{new_name}' to project")
504
- st.session_state.rerun_pending = True
505
 
506
  else:
507
  st.info("No materials found in the selected category.")
@@ -538,49 +674,19 @@ def display_materials_tab():
538
  delete_key = get_stable_button_key("proj_mat", name, "delete")
539
 
540
  if cols[3].button("Edit", key=edit_key):
541
- if st.session_state.rerun_trigger != f"edit_mat_{name}":
542
- st.session_state.rerun_trigger = f"edit_mat_{name}"
543
- st.session_state.material_editor = {
544
- "name": name,
545
- "category": material["category"],
546
- "thermal_conductivity": material["thermal_conductivity"],
547
- "density": material["density"],
548
- "specific_heat": material["specific_heat"],
549
- "default_thickness": material["default_thickness"],
550
- "embodied_carbon": material["embodied_carbon"],
551
- "cost": material["cost"],
552
- "absorptivity": material["absorptivity"],
553
- "emissivity": material["emissivity"],
554
- "colour": material["colour"],
555
- "edit_mode": True,
556
- "original_name": name,
557
- "is_library": False
558
- }
559
- st.session_state.material_form_state = {
560
- "name": name,
561
- "category": material["category"],
562
- "thermal_conductivity": float(material["thermal_conductivity"]),
563
- "density": float(material["density"]),
564
- "specific_heat": float(material["specific_heat"]),
565
- "default_thickness": float(material["default_thickness"]),
566
- "embodied_carbon": float(material["embodied_carbon"]),
567
- "cost": float(material["cost"]),
568
- "absorptivity": float(material["absorptivity"]),
569
- "emissivity": float(material["emissivity"]),
570
- "colour": material["colour"]
571
- }
572
- st.session_state.active_tab = "Materials"
573
- st.session_state.rerun_pending = True
574
-
575
  if cols[4].button("Delete", key=delete_key):
576
- is_in_use = check_material_in_use(name)
577
- if is_in_use:
578
- st.error(f"Cannot delete material '{name}' because it is in use in constructions.")
579
- else:
580
- del st.session_state.project_data["materials"]["project"][name]
581
- st.success(f"Material '{name}' deleted from project.")
582
- logger.info(f"Deleted material '{name}' from project")
583
- st.session_state.rerun_pending = True
584
 
585
  else:
586
  st.info("No project materials in the selected category.")
@@ -657,44 +763,21 @@ def display_fenestrations_tab():
657
  copy_key = get_stable_button_key("lib_fen", name, "copy")
658
 
659
  if cols[3].button("Preview", key=preview_key):
660
- if st.session_state.rerun_trigger != f"preview_fen_{name}":
661
- st.session_state.rerun_trigger = f"preview_fen_{name}"
662
- st.session_state.fenestration_editor = {
663
- "name": name,
664
- "type": fenestration["type"],
665
- "u_value": fenestration["u_value"],
666
- "shgc": fenestration["shgc"],
667
- "visible_trans": fenestration["visible_transmittance"],
668
- "thickness": fenestration["thickness"],
669
- "embodied_carbon": fenestration["embodied_carbon"],
670
- "cost": fenestration["cost"],
671
- "edit_mode": False,
672
- "original_name": name,
673
- "is_library": True
674
- }
675
- st.session_state.fenestration_form_state = {
676
- "name": name,
677
- "type": fenestration["type"],
678
- "u_value": float(fenestration["u_value"]),
679
- "shgc": float(fenestration["shgc"]),
680
- "visible_trans": float(fenestration["visible_transmittance"]),
681
- "thickness": float(fenestration["thickness"]),
682
- "embodied_carbon": float(fenestration["embodied_carbon"]),
683
- "cost": float(fenestration["cost"])
684
- }
685
- st.session_state.active_tab = "Fenestrations"
686
- st.session_state.rerun_pending = True
687
-
688
  if cols[4].button("Copy", key=copy_key):
689
- new_name = f"{name}_Project"
690
- counter = 1
691
- while new_name in st.session_state.project_data["fenestrations"]["project"] or new_name in library_fenestrations:
692
- new_name = f"{name}_Project_{counter}"
693
- counter += 1
694
- st.session_state.project_data["fenestrations"]["project"][new_name] = fenestration.copy()
695
- st.success(f"Fenestration '{new_name}' copied to project.")
696
- logger.info(f"Copied library fenestration '{name}' as '{new_name}' to project")
697
- st.session_state.rerun_pending = True
698
 
699
  else:
700
  st.info("No fenestrations found in the selected type.")
@@ -728,43 +811,19 @@ def display_fenestrations_tab():
728
  delete_key = get_stable_button_key("proj_fen", name, "delete")
729
 
730
  if cols[3].button("Edit", key=edit_key):
731
- if st.session_state.rerun_trigger != f"edit_fen_{name}":
732
- st.session_state.rerun_trigger = f"edit_fen_{name}"
733
- st.session_state.fenestration_editor = {
734
- "name": name,
735
- "type": fenestration["type"],
736
- "u_value": fenestration["u_value"],
737
- "shgc": fenestration["shgc"],
738
- "visible_trans": fenestration["visible_transmittance"],
739
- "thickness": fenestration["thickness"],
740
- "embodied_carbon": fenestration["embodied_carbon"],
741
- "cost": fenestration["cost"],
742
- "edit_mode": True,
743
- "original_name": name,
744
- "is_library": False
745
- }
746
- st.session_state.fenestration_form_state = {
747
- "name": name,
748
- "type": fenestration["type"],
749
- "u_value": float(fenestration["u_value"]),
750
- "shgc": float(fenestration["shgc"]),
751
- "visible_trans": float(fenestration["visible_transmittance"]),
752
- "thickness": float(fenestration["thickness"]),
753
- "embodied_carbon": float(fenestration["embodied_carbon"]),
754
- "cost": float(fenestration["cost"])
755
- }
756
- st.session_state.active_tab = "Fenestrations"
757
- st.session_state.rerun_pending = True
758
-
759
  if cols[4].button("Delete", key=delete_key):
760
- is_in_use = check_fenestration_in_use(name)
761
- if is_in_use:
762
- st.error(f"Cannot delete fenestration '{name}' because it is in use in components.")
763
- else:
764
- del st.session_state.project_data["fenestrations"]["project"][name]
765
- st.success(f"Fenestration '{name}' deleted from project.")
766
- logger.info(f"Deleted fenestration '{name}' from project")
767
- st.session_state.rerun_pending = True
768
 
769
  else:
770
  st.info("No project fenestrations in the selected type.")
@@ -880,7 +939,7 @@ def initialize_fenestrations():
880
 
881
  def display_material_editor():
882
  """Display the material editor form."""
883
- with st.form("material_editor_form"):
884
  editor_state = st.session_state.material_editor
885
  form_state = st.session_state.material_form_state
886
  is_library = editor_state.get("is_library", False)
@@ -1061,15 +1120,15 @@ def display_material_editor():
1061
  st.success(f"Material '{name}' added to your project.")
1062
  logger.info(f"Added new material '{name}' to project")
1063
  reset_material_editor()
1064
- st.session_state.rerun_pending = True
1065
 
1066
  if clear_button:
1067
  reset_material_editor()
1068
- st.session_state.rerun_pending = True
1069
 
1070
  def display_fenestration_editor():
1071
  """Display the fenestration editor form."""
1072
- with st.form("fenestration_editor_form"):
1073
  editor_state = st.session_state.fenestration_editor
1074
  form_state = st.session_state.fenestration_form_state
1075
  is_library = editor_state.get("is_library", False)
@@ -1210,11 +1269,11 @@ def display_fenestration_editor():
1210
  st.success(f"Fenestration '{name}' added to your project.")
1211
  logger.info(f"Added new fenestration '{name}' to project")
1212
  reset_fenestration_editor()
1213
- st.session_state.rerun_pending = True
1214
 
1215
  if clear_button:
1216
  reset_fenestration_editor()
1217
- st.session_state.rerun_pending = True
1218
 
1219
  def validate_material(
1220
  name: str, category: str, thermal_conductivity: float, density: float,
@@ -1344,7 +1403,6 @@ def reset_material_editor():
1344
  "is_library": False
1345
  }
1346
  st.session_state.material_action = {"action": None, "id": None}
1347
- st.session_state.rerun_trigger = None
1348
 
1349
  def reset_fenestration_editor():
1350
  """Reset the fenestration editor and form state."""
@@ -1372,7 +1430,6 @@ def reset_fenestration_editor():
1372
  "is_library": False
1373
  }
1374
  st.session_state.fenestration_action = {"action": None, "id": None}
1375
- st.session_state.rerun_trigger = None
1376
 
1377
  def check_material_in_use(material_name: str) -> bool:
1378
  """
 
348
  def get_stable_button_key(prefix: str, name: str, action: str, unique_id: str = None) -> str:
349
  """Generate a stable button key based on prefix, name, action, and optional unique identifier."""
350
  import hashlib
351
+ unique_id = unique_id or str(uuid.uuid4())[:8]
352
  key_string = f"{prefix}_{name}_{action}_{unique_id}"
353
  hash_key = hashlib.md5(key_string.encode()).hexdigest()[:8]
354
  return f"{prefix}_{action}_{name}_{hash_key}"
 
359
  This is the main function called by main.py when the Material Library page is selected.
360
  """
361
  # Initialize session state
362
+ if "action_queue" not in st.session_state:
363
+ st.session_state.action_queue = []
364
  if "active_tab" not in st.session_state:
365
  st.session_state.active_tab = "Materials"
366
  if "material_action" not in st.session_state:
367
  st.session_state.material_action = {"action": None, "id": None}
368
  if "fenestration_action" not in st.session_state:
369
  st.session_state.fenestration_action = {"action": None, "id": None}
 
 
370
 
371
+ # Process action queue
372
+ if st.session_state.action_queue:
373
+ action = st.session_state.action_queue.pop(0)
374
+ if action["type"] == "page_change":
375
+ st.session_state.current_page = action["page"]
376
+ st.rerun()
377
+ elif action["type"] == "material_action":
378
+ handle_material_action(action)
379
+ elif action["type"] == "fenestration_action":
380
+ handle_fenestration_action(action)
381
  st.rerun()
382
 
383
  # Apply custom CSS for button styling
 
400
  tab1, tab2 = st.tabs(["Materials", "Fenestrations"])
401
 
402
  with tab1:
403
+ st.session_state.active_tab = "Materials"
 
404
  display_materials_tab()
405
 
406
  with tab2:
407
+ st.session_state.active_tab = "Fenestrations"
 
408
  display_fenestrations_tab()
409
 
410
  col1, col2 = st.columns(2)
411
 
412
  with col1:
413
  if st.button("Back to Climate Data", key="back_to_climate"):
414
+ st.session_state.action_queue.append({"type": "page_change", "page": "Climate Data"})
 
415
 
416
  with col2:
417
  if st.button("Continue to Construction", key="continue_to_construction"):
418
+ st.session_state.action_queue.append({"type": "page_change", "page": "Construction"})
419
+
420
+ def handle_material_action(action: Dict[str, Any]):
421
+ """Handle material-related actions."""
422
+ if action["action"] == "preview":
423
+ material = action["material"]
424
+ name = action["name"]
425
+ st.session_state.material_editor = {
426
+ "name": name,
427
+ "category": material["category"],
428
+ "thermal_conductivity": material["thermal_conductivity"],
429
+ "density": material["density"],
430
+ "specific_heat": material["specific_heat"],
431
+ "default_thickness": material["default_thickness"],
432
+ "embodied_carbon": material["embodied_carbon"],
433
+ "cost": material["cost"],
434
+ "absorptivity": material["absorptivity"],
435
+ "emissivity": material["emissivity"],
436
+ "colour": material["colour"],
437
+ "edit_mode": False,
438
+ "original_name": name,
439
+ "is_library": action["is_library"]
440
+ }
441
+ st.session_state.material_form_state = {
442
+ "name": name,
443
+ "category": material["category"],
444
+ "thermal_conductivity": float(material["thermal_conductivity"]),
445
+ "density": float(material["density"]),
446
+ "specific_heat": float(material["specific_heat"]),
447
+ "default_thickness": float(material["default_thickness"]),
448
+ "embodied_carbon": float(material["embodied_carbon"]),
449
+ "cost": float(material["cost"]),
450
+ "absorptivity": float(material["absorptivity"]),
451
+ "emissivity": float(material["emissivity"]),
452
+ "colour": material["colour"]
453
+ }
454
+ elif action["action"] == "copy":
455
+ name = action["name"]
456
+ material = action["material"]
457
+ new_name = f"{name}_Project"
458
+ counter = 1
459
+ library_materials = st.session_state.project_data["materials"]["library"]
460
+ while new_name in st.session_state.project_data["materials"]["project"] or new_name in library_materials:
461
+ new_name = f"{name}_Project_{counter}"
462
+ counter += 1
463
+ st.session_state.project_data["materials"]["project"][new_name] = material.copy()
464
+ st.success(f"Material '{new_name}' copied to project.")
465
+ logger.info(f"Copied library material '{name}' as '{new_name}' to project")
466
+ elif action["action"] == "edit":
467
+ material = action["material"]
468
+ name = action["name"]
469
+ st.session_state.material_editor = {
470
+ "name": name,
471
+ "category": material["category"],
472
+ "thermal_conductivity": material["thermal_conductivity"],
473
+ "density": material["density"],
474
+ "specific_heat": material["specific_heat"],
475
+ "default_thickness": material["default_thickness"],
476
+ "embodied_carbon": material["embodied_carbon"],
477
+ "cost": material["cost"],
478
+ "absorptivity": material["absorptivity"],
479
+ "emissivity": material["emissivity"],
480
+ "colour": material["colour"],
481
+ "edit_mode": True,
482
+ "original_name": name,
483
+ "is_library": False
484
+ }
485
+ st.session_state.material_form_state = {
486
+ "name": name,
487
+ "category": material["category"],
488
+ "thermal_conductivity": float(material["thermal_conductivity"]),
489
+ "density": float(material["density"]),
490
+ "specific_heat": float(material["specific_heat"]),
491
+ "default_thickness": float(material["default_thickness"]),
492
+ "embodied_carbon": float(material["embodied_carbon"]),
493
+ "cost": float(material["cost"]),
494
+ "absorptivity": float(material["absorptivity"]),
495
+ "emissivity": float(material["emissivity"]),
496
+ "colour": material["colour"]
497
+ }
498
+ elif action["action"] == "delete":
499
+ name = action["name"]
500
+ is_in_use = check_material_in_use(name)
501
+ if is_in_use:
502
+ st.error(f"Cannot delete material '{name}' because it is in use in constructions.")
503
+ else:
504
+ del st.session_state.project_data["materials"]["project"][name]
505
+ st.success(f"Material '{name}' deleted from project.")
506
+ logger.info(f"Deleted material '{name}' from project")
507
+
508
+ def handle_fenestration_action(action: Dict[str, Any]):
509
+ """Handle fenestration-related actions."""
510
+ if action["action"] == "preview":
511
+ fenestration = action["fenestration"]
512
+ name = action["name"]
513
+ st.session_state.fenestration_editor = {
514
+ "name": name,
515
+ "type": fenestration["type"],
516
+ "u_value": fenestration["u_value"],
517
+ "shgc": fenestration["shgc"],
518
+ "visible_trans": fenestration["visible_transmittance"],
519
+ "thickness": fenestration["thickness"],
520
+ "embodied_carbon": fenestration["embodied_carbon"],
521
+ "cost": fenestration["cost"],
522
+ "edit_mode": False,
523
+ "original_name": name,
524
+ "is_library": action["is_library"]
525
+ }
526
+ st.session_state.fenestration_form_state = {
527
+ "name": name,
528
+ "type": fenestration["type"],
529
+ "u_value": float(fenestration["u_value"]),
530
+ "shgc": float(fenestration["shgc"]),
531
+ "visible_trans": float(fenestration["visible_transmittance"]),
532
+ "thickness": float(fenestration["thickness"]),
533
+ "embodied_carbon": float(fenestration["embodied_carbon"]),
534
+ "cost": float(fenestration["cost"])
535
+ }
536
+ elif action["action"] == "copy":
537
+ name = action["name"]
538
+ fenestration = action["fenestration"]
539
+ new_name = f"{name}_Project"
540
+ counter = 1
541
+ library_fenestrations = st.session_state.project_data["fenestrations"]["library"]
542
+ while new_name in st.session_state.project_data["fenestrations"]["project"] or new_name in library_fenestrations:
543
+ new_name = f"{name}_Project_{counter}"
544
+ counter += 1
545
+ st.session_state.project_data["fenestrations"]["project"][new_name] = fenestration.copy()
546
+ st.success(f"Fenestration '{new_name}' copied to project.")
547
+ logger.info(f"Copied library fenestration '{name}' as '{new_name}' to project")
548
+ elif action["action"] == "edit":
549
+ fenestration = action["fenestration"]
550
+ name = action["name"]
551
+ st.session_state.fenestration_editor = {
552
+ "name": name,
553
+ "type": fenestration["type"],
554
+ "u_value": fenestration["u_value"],
555
+ "shgc": fenestration["shgc"],
556
+ "visible_trans": fenestration["visible_transmittance"],
557
+ "thickness": fenestration["thickness"],
558
+ "embodied_carbon": fenestration["embodied_carbon"],
559
+ "cost": fenestration["cost"],
560
+ "edit_mode": True,
561
+ "original_name": name,
562
+ "is_library": False
563
+ }
564
+ st.session_state.fenestration_form_state = {
565
+ "name": name,
566
+ "type": fenestration["type"],
567
+ "u_value": float(fenestration["u_value"]),
568
+ "shgc": float(fenestration["shgc"]),
569
+ "visible_trans": float(fenestration["visible_transmittance"]),
570
+ "thickness": float(fenestration["thickness"]),
571
+ "embodied_carbon": float(fenestration["embodied_carbon"]),
572
+ "cost": float(fenestration["cost"])
573
+ }
574
+ elif action["action"] == "delete":
575
+ name = action["name"]
576
+ is_in_use = check_fenestration_in_use(name)
577
+ if is_in_use:
578
+ st.error(f"Cannot delete fenestration '{name}' because it is in use in components.")
579
+ else:
580
+ del st.session_state.project_data["fenestrations"]["project"][name]
581
+ st.success(f"Fenestration '{name}' deleted from project.")
582
+ logger.info(f"Deleted fenestration '{name}' from project")
583
 
584
  def display_materials_tab():
585
  """Display the materials tab content."""
 
623
  copy_key = get_stable_button_key("lib_mat", name, "copy")
624
 
625
  if cols[3].button("Preview", key=preview_key):
626
+ st.session_state.action_queue.append({
627
+ "type": "material_action",
628
+ "action": "preview",
629
+ "name": name,
630
+ "material": material,
631
+ "is_library": True
632
+ })
633
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
634
  if cols[4].button("Copy", key=copy_key):
635
+ st.session_state.action_queue.append({
636
+ "type": "material_action",
637
+ "action": "copy",
638
+ "name": name,
639
+ "material": material
640
+ })
 
 
 
641
 
642
  else:
643
  st.info("No materials found in the selected category.")
 
674
  delete_key = get_stable_button_key("proj_mat", name, "delete")
675
 
676
  if cols[3].button("Edit", key=edit_key):
677
+ st.session_state.action_queue.append({
678
+ "type": "material_action",
679
+ "action": "edit",
680
+ "name": name,
681
+ "material": material
682
+ })
683
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
684
  if cols[4].button("Delete", key=delete_key):
685
+ st.session_state.action_queue.append({
686
+ "type": "material_action",
687
+ "action": "delete",
688
+ "name": name
689
+ })
 
 
 
690
 
691
  else:
692
  st.info("No project materials in the selected category.")
 
763
  copy_key = get_stable_button_key("lib_fen", name, "copy")
764
 
765
  if cols[3].button("Preview", key=preview_key):
766
+ st.session_state.action_queue.append({
767
+ "type": "fenestration_action",
768
+ "action": "preview",
769
+ "name": name,
770
+ "fenestration": fenestration,
771
+ "is_library": True
772
+ })
773
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
774
  if cols[4].button("Copy", key=copy_key):
775
+ st.session_state.action_queue.append({
776
+ "type": "fenestration_action",
777
+ "action": "copy",
778
+ "name": name,
779
+ "fenestration": fenestration
780
+ })
 
 
 
781
 
782
  else:
783
  st.info("No fenestrations found in the selected type.")
 
811
  delete_key = get_stable_button_key("proj_fen", name, "delete")
812
 
813
  if cols[3].button("Edit", key=edit_key):
814
+ st.session_state.action_queue.append({
815
+ "type": "fenestration_action",
816
+ "action": "edit",
817
+ "name": name,
818
+ "fenestration": fenestration
819
+ })
820
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
821
  if cols[4].button("Delete", key=delete_key):
822
+ st.session_state.action_queue.append({
823
+ "type": "fenestration_action",
824
+ "action": "delete",
825
+ "name": name
826
+ })
 
 
 
827
 
828
  else:
829
  st.info("No project fenestrations in the selected type.")
 
939
 
940
  def display_material_editor():
941
  """Display the material editor form."""
942
+ with st.form("material_editor_form", clear_on_submit=True):
943
  editor_state = st.session_state.material_editor
944
  form_state = st.session_state.material_form_state
945
  is_library = editor_state.get("is_library", False)
 
1120
  st.success(f"Material '{name}' added to your project.")
1121
  logger.info(f"Added new material '{name}' to project")
1122
  reset_material_editor()
1123
+ st.session_state.action_queue.append({"type": "refresh"})
1124
 
1125
  if clear_button:
1126
  reset_material_editor()
1127
+ st.session_state.action_queue.append({"type": "refresh"})
1128
 
1129
  def display_fenestration_editor():
1130
  """Display the fenestration editor form."""
1131
+ with st.form("fenestration_editor_form", clear_on_submit=True):
1132
  editor_state = st.session_state.fenestration_editor
1133
  form_state = st.session_state.fenestration_form_state
1134
  is_library = editor_state.get("is_library", False)
 
1269
  st.success(f"Fenestration '{name}' added to your project.")
1270
  logger.info(f"Added new fenestration '{name}' to project")
1271
  reset_fenestration_editor()
1272
+ st.session_state.action_queue.append({"type": "refresh"})
1273
 
1274
  if clear_button:
1275
  reset_fenestration_editor()
1276
+ st.session_state.action_queue.append({"type": "refresh"})
1277
 
1278
  def validate_material(
1279
  name: str, category: str, thermal_conductivity: float, density: float,
 
1403
  "is_library": False
1404
  }
1405
  st.session_state.material_action = {"action": None, "id": None}
 
1406
 
1407
  def reset_fenestration_editor():
1408
  """Reset the fenestration editor and form state."""
 
1430
  "is_library": False
1431
  }
1432
  st.session_state.fenestration_action = {"action": None, "id": None}
 
1433
 
1434
  def check_material_in_use(material_name: str) -> bool:
1435
  """