Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -5,8 +5,7 @@ import os
|
|
5 |
import json
|
6 |
import pandas as pd
|
7 |
import uuid
|
8 |
-
from PIL import Image, ImageDraw #
|
9 |
-
# Corrected import: removed 'sync'
|
10 |
from streamlit_js_eval import streamlit_js_eval # For JS communication
|
11 |
|
12 |
# --- Constants ---
|
@@ -24,7 +23,15 @@ def load_plot_metadata():
|
|
24 |
"""Scans save dir, sorts plots, calculates metadata."""
|
25 |
plots = []
|
26 |
# Ensure consistent sorting, e.g., alphabetically which often aligns with plot_001, plot_002 etc.
|
27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
current_x_offset = 0.0
|
30 |
for i, filename in enumerate(plot_files):
|
@@ -54,11 +61,10 @@ def load_plot_objects(filename, x_offset):
|
|
54 |
st.warning(f"CSV '{filename}' missing essential columns (type, pos_x/y/z). Skipping.")
|
55 |
return []
|
56 |
# Ensure optional columns default to something sensible if missing
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
if 'rot_order' not in df.columns: df['rot_order'] = 'XYZ'
|
62 |
|
63 |
|
64 |
for _, row in df.iterrows():
|
@@ -171,7 +177,10 @@ with st.sidebar:
|
|
171 |
if cols[col_idx].button(button_label, key=f"nav_{plot['filename']}"):
|
172 |
# Send command to JS to move the player
|
173 |
target_x = plot['x_offset']
|
174 |
-
|
|
|
|
|
|
|
175 |
# No rerun needed here, JS handles the move instantly
|
176 |
|
177 |
col_idx = (col_idx + 1) % max_cols # Cycle through columns
|
@@ -196,10 +205,13 @@ with st.sidebar:
|
|
196 |
key="selected_object_widget" # Use a distinct key for the widget
|
197 |
)
|
198 |
# Update session state only if the widget's value actually changes
|
|
|
|
|
199 |
if selected_object_type_widget != st.session_state.selected_object:
|
200 |
st.session_state.selected_object = selected_object_type_widget
|
201 |
-
#
|
202 |
-
#
|
|
|
203 |
|
204 |
|
205 |
st.markdown("---")
|
@@ -264,7 +276,7 @@ if save_data_from_js is not None: # Process only if data is present
|
|
264 |
st.session_state.new_plot_name = ""
|
265 |
# Reset newly placed objects in JS AFTER successful save
|
266 |
try:
|
267 |
-
# This call tells JS to clear its internal 'newlyPlacedObjects' array
|
268 |
streamlit_js_eval(js_code="resetNewlyPlacedObjects();", key="reset_js_state")
|
269 |
except Exception as js_e:
|
270 |
st.warning(f"Could not reset JS state after save: {js_e}")
|
|
|
5 |
import json
|
6 |
import pandas as pd
|
7 |
import uuid
|
8 |
+
from PIL import Image, ImageDraw # Not used for minimap anymore, but kept just in case
|
|
|
9 |
from streamlit_js_eval import streamlit_js_eval # For JS communication
|
10 |
|
11 |
# --- Constants ---
|
|
|
23 |
"""Scans save dir, sorts plots, calculates metadata."""
|
24 |
plots = []
|
25 |
# Ensure consistent sorting, e.g., alphabetically which often aligns with plot_001, plot_002 etc.
|
26 |
+
try:
|
27 |
+
plot_files = sorted([f for f in os.listdir(SAVE_DIR) if f.endswith(".csv")])
|
28 |
+
except FileNotFoundError:
|
29 |
+
st.error(f"Save directory '{SAVE_DIR}' not found.")
|
30 |
+
return [], 0.0 # Return empty if dir doesn't exist
|
31 |
+
except Exception as e:
|
32 |
+
st.error(f"Error listing save directory '{SAVE_DIR}': {e}")
|
33 |
+
return [], 0.0
|
34 |
+
|
35 |
|
36 |
current_x_offset = 0.0
|
37 |
for i, filename in enumerate(plot_files):
|
|
|
61 |
st.warning(f"CSV '{filename}' missing essential columns (type, pos_x/y/z). Skipping.")
|
62 |
return []
|
63 |
# Ensure optional columns default to something sensible if missing
|
64 |
+
# Use vectorized operations for defaults where possible
|
65 |
+
df['obj_id'] = df.get('obj_id', pd.Series([str(uuid.uuid4()) for _ in range(len(df))]))
|
66 |
+
for col, default in [('rot_x', 0.0), ('rot_y', 0.0), ('rot_z', 0.0), ('rot_order', 'XYZ')]:
|
67 |
+
if col not in df.columns: df[col] = default
|
|
|
68 |
|
69 |
|
70 |
for _, row in df.iterrows():
|
|
|
177 |
if cols[col_idx].button(button_label, key=f"nav_{plot['filename']}"):
|
178 |
# Send command to JS to move the player
|
179 |
target_x = plot['x_offset']
|
180 |
+
try:
|
181 |
+
streamlit_js_eval(js_code=f"teleportPlayer({target_x});", key=f"teleport_{plot['filename']}")
|
182 |
+
except Exception as e:
|
183 |
+
st.error(f"Failed to send teleport command: {e}")
|
184 |
# No rerun needed here, JS handles the move instantly
|
185 |
|
186 |
col_idx = (col_idx + 1) % max_cols # Cycle through columns
|
|
|
205 |
key="selected_object_widget" # Use a distinct key for the widget
|
206 |
)
|
207 |
# Update session state only if the widget's value actually changes
|
208 |
+
# This change WILL trigger a rerun because Streamlit tracks widget state.
|
209 |
+
# The JS side now handles preserving its state across the resulting reload via sessionStorage.
|
210 |
if selected_object_type_widget != st.session_state.selected_object:
|
211 |
st.session_state.selected_object = selected_object_type_widget
|
212 |
+
# We don't *need* to force a rerun here, Streamlit handles it.
|
213 |
+
# The important part is that the NEXT run will inject the new selected type,
|
214 |
+
# and the JS will restore placed objects from sessionStorage.
|
215 |
|
216 |
|
217 |
st.markdown("---")
|
|
|
276 |
st.session_state.new_plot_name = ""
|
277 |
# Reset newly placed objects in JS AFTER successful save
|
278 |
try:
|
279 |
+
# This call tells JS to clear its internal 'newlyPlacedObjects' array AND sessionStorage
|
280 |
streamlit_js_eval(js_code="resetNewlyPlacedObjects();", key="reset_js_state")
|
281 |
except Exception as js_e:
|
282 |
st.warning(f"Could not reset JS state after save: {js_e}")
|