All notable changes to HabitatView documented by version.
0.1.1
Fixed
Floor removal not updating JSON config: When a floor was deleted using the "-" button, the floor was removed from project.floors but remained in project.config.floors, causing the JSON configuration to become out of sync. Now both are updated together and the JSON editor is refreshed to reflect the change.
Floor rename not updating JSON config: Editing a floor's name via the text field only updated floor.name but not the corresponding FloorConfig.name in the configuration. The rename now propagates to the config and the JSON editor is refreshed to reflect the change immediately.
Keyboard shortcuts interfering with JSON editor: Tool shortcuts (V, R, P, L, B, H) were triggering while typing in the JSON editor, making it impossible to type these characters on Windows and causing annoyances on Linux. The detection method was changed from unreliable debug string matching to using ctx.wants_keyboard_input() which properly detects when any text widget has focus.
JSON editor panel expanding with long lines: When the JSON contained long lines, the editor panel would grow horizontally and consume space from the shape editor. Changed ScrollArea::vertical() to ScrollArea::both() and constrained the TextEdit width to the available panel width, enabling horizontal scrolling instead of panel expansion.
Potential panic in config application: In Project::apply_config(), replaced self.floors.last_mut().unwrap() with direct index access using the already-calculated index variable, eliminating a potential panic if the floors vector was in an unexpected state.
Potential panic in floor access:current_floor() and current_floor_mut() in Project used direct array indexing without bounds checking. If selected_floor_index became out of sync with floors.len() (e.g., after deletion or deserialization), the application would panic. Added index clamping using min() and saturating_sub() to always return a valid floor reference.
Potential panic in bezier preview: In draw_bezier_preview(), the code used canvas_points.last().unwrap() which could panic if the points vector was empty due to edge cases. Replaced with safe pattern matching using if let Some(last) = canvas_points.last(). Also fixed potential integer underflow by using saturating_sub() for the remaining points calculation.
Bezier curve silently dropping points: In finish_bezier(), extra points that didn't form a complete cubic segment (which requires exactly 3 points: control1, control2, end) were silently ignored. Now logs a warning when points are dropped so users know their input wasn't fully captured.
Polygon impossible to close at extreme zoom levels: The polygon close detection used 15.0 / scale as the threshold distance, which became impractically small at high zoom (< 1 pixel) or too large at low zoom (> 100 viewbox units). Added clamping to keep the close distance between 5-50 viewbox units regardless of zoom level.
Potential panic on mutex poison in preview: All .lock().unwrap() calls on shared Mutex objects in the preview module would panic if a thread panicked while holding the lock (mutex poisoning). Replaced with .lock().unwrap_or_else(|e| e.into_inner()) to recover the data from poisoned mutexes and continue operation.
Selection state desync between single and multi-select: The add_to_selection() method added elements to selected_element_ids but didn't update selected_element_id when it was None, causing operations that depended on selected_element_id to fail even when elements were selected. Now ensures selected_element_id is set to the first added element if currently empty.
Silent failure when selecting invalid floor index:Project::select_floor() silently ignored out-of-bounds indices with no indication that the selection failed. Added a warning log message when an invalid index is provided to aid debugging.
Room ID collision risk:Floor::next_room_id() calculated the next ID based on the maximum existing room number, but didn't verify the generated ID was actually unique. This could cause collisions if room IDs were manually created in the JSON config with non-sequential numbers. Now checks that the generated ID doesn't already exist and increments until finding a unique one.
Malformed URL port silently ignored: When testing a sensor URL with an invalid port (e.g., http://host:abc/path), the port parsing would silently fail and default to port 80/443, causing the test to connect to the wrong port with no indication of the error. Now returns a clear error message: "Invalid port 'abc': must be a number between 1-65535".
SVG import silently dropping elements: When importing an SVG file, unsupported elements like <text> and <image> were silently discarded with no feedback. Users could import an SVG thinking all elements loaded when text labels were actually missing. Now logs each skipped element type and shows a warning summary (e.g., "SVG import: 3 element(s) skipped (text/images not supported)").
Invalid polygons created without warning:Element::new_polygon() accepted any number of points without validation, allowing invalid polygons (< 3 points) to be created from imported data or JSON config without any indication. Now logs a warning when attempting to create a polygon with fewer than 3 points.
Element names illegible on complex shapes: Element names were rendered as plain text at the shape's center, making them hard to read when overlapping with shape edges or on dark backgrounds. Added a semi-transparent rounded background behind element names for better readability on all shape types.
Removed
src/document/floor.rs:
get_element() method - immutable element lookup, unused
elements_in_layer() method - layer-filtered element iterator, unused