diff --git a/src/exporter.rs b/src/exporter.rs index 6144128..470f742 100644 --- a/src/exporter.rs +++ b/src/exporter.rs @@ -276,12 +276,22 @@ fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result Result { Ok(pixmap) } +fn fill_marker_mask(pixmap: &mut Pixmap, g: &ExportGeometry, markers: &[AreaMarker]) { + for marker in markers { + fill_rect_marker(pixmap, g, marker, WHITE); + } +} + // Write a single mask image to disk. fn save_mask_image( folder: &std::path::Path, @@ -684,12 +696,22 @@ fn build_svg(layout: &DungeonLayout, settings: &UiSettings) -> String { } } - for marker in &layout.start_markers { - append_svg_area_marker(&mut s, &g, marker, "S", START_MARKER, settings.colorblind_mode); - } - for marker in &layout.end_markers { - append_svg_area_marker(&mut s, &g, marker, "E", END_MARKER, settings.colorblind_mode); - } + append_svg_area_marker_group( + &mut s, + &g, + &layout.start_markers, + "S", + START_MARKER, + settings.colorblind_mode, + ); + append_svg_area_marker_group( + &mut s, + &g, + &layout.end_markers, + "E", + END_MARKER, + settings.colorblind_mode, + ); s.push_str("\n"); s @@ -854,6 +876,19 @@ fn draw_area_marker( } } +fn draw_area_marker_group( + pixmap: &mut Pixmap, + g: &ExportGeometry, + markers: &[AreaMarker], + label: &str, + color: (u8, u8, u8, u8), + colorblind_mode: bool, +) { + for marker in markers { + draw_area_marker(pixmap, g, marker, label, color, colorblind_mode); + } +} + // Draw a filled circle for dot patterns. fn draw_dot(pixmap: &mut Pixmap, cx: f32, cy: f32, radius: f32, color: (u8, u8, u8, u8)) { let mut pb = PathBuilder::new(); @@ -1165,6 +1200,19 @@ fn append_svg_area_marker( } } +fn append_svg_area_marker_group( + out: &mut String, + g: &ExportGeometry, + markers: &[AreaMarker], + label: &str, + color: (u8, u8, u8, u8), + colorblind_mode: bool, +) { + for marker in markers { + append_svg_area_marker(out, g, marker, label, color, colorblind_mode); + } +} + // Draw a door line onto the pixmap. fn draw_door( pixmap: &mut Pixmap, diff --git a/src/main.rs b/src/main.rs index c13d362..f73cab4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -285,6 +285,22 @@ fn clamp_dependent_settings(settings: &mut UiSettings) { } impl DungeonApp { + fn clear_hover_targets(&mut self) { + self.hover_room_idx = None; + self.hover_corridor_idx = None; + self.hover_door_idx = None; + self.hover_text_idx = None; + self.hover_marker = None; + } + + fn reset_transient_state(&mut self) { + self.drag_state = None; + self.add_corridor_drag = None; + self.resize_state = None; + self.clear_hover_targets(); + self.pending_delete = false; + } + fn snapshot(&self) -> AppSnapshot { AppSnapshot { settings: self.settings.clone(), @@ -309,15 +325,7 @@ impl DungeonApp { self.settings = snapshot.settings; self.layout = snapshot.layout; self.suppressed_auto_door_edges = snapshot.suppressed_auto_door_edges; - self.drag_state = None; - self.add_corridor_drag = None; - self.resize_state = None; - self.hover_room_idx = None; - self.hover_corridor_idx = None; - self.hover_door_idx = None; - self.hover_text_idx = None; - self.hover_marker = None; - self.pending_delete = false; + self.reset_transient_state(); } fn undo(&mut self) { @@ -343,15 +351,7 @@ impl DungeonApp { ..DungeonLayout::default() }; self.suppressed_auto_door_edges.clear(); - self.drag_state = None; - self.add_corridor_drag = None; - self.resize_state = None; - self.hover_room_idx = None; - self.hover_corridor_idx = None; - self.hover_door_idx = None; - self.hover_text_idx = None; - self.hover_marker = None; - self.pending_delete = false; + self.reset_transient_state(); } // Regenerate the dungeon layout from current settings and reset drag state. @@ -868,11 +868,7 @@ impl DungeonApp { // Update which room/corridor/door is currently hovered. fn update_hover_targets(&mut self, ctx: &egui::Context, geometry: &GridGeometry) { let Some(pointer_pos) = ctx.pointer_hover_pos() else { - self.hover_room_idx = None; - self.hover_corridor_idx = None; - self.hover_door_idx = None; - self.hover_text_idx = None; - self.hover_marker = None; + self.clear_hover_targets(); return; }; if let Some(edge) = self.door_edge_at_pointer(pointer_pos, geometry) { @@ -1941,28 +1937,26 @@ fn draw_layout( ); } - for (idx, marker) in layout.start_markers.iter().enumerate() { - draw_area_marker( - painter, - geometry, - marker, - "S", - Color32::from_rgb(60, 220, 200), - colorblind_mode, - hover_marker == Some(HoverMarker::Start(idx)), - ); - } - for (idx, marker) in layout.end_markers.iter().enumerate() { - draw_area_marker( - painter, - geometry, - marker, - "E", - Color32::from_rgb(240, 90, 90), - colorblind_mode, - hover_marker == Some(HoverMarker::End(idx)), - ); - } + draw_area_marker_group( + painter, + geometry, + &layout.start_markers, + "S", + Color32::from_rgb(60, 220, 200), + colorblind_mode, + hover_marker, + MarkerKind::Start, + ); + draw_area_marker_group( + painter, + geometry, + &layout.end_markers, + "E", + Color32::from_rgb(240, 90, 90), + colorblind_mode, + hover_marker, + MarkerKind::End, + ); } // Compute the rectangle for a given grid cell. @@ -2051,6 +2045,34 @@ fn draw_area_marker( ); } +fn draw_area_marker_group( + painter: &egui::Painter, + geometry: &GridGeometry, + markers: &[layout::AreaMarker], + label: &str, + base_color: Color32, + colorblind_mode: bool, + hover_marker: Option, + kind: MarkerKind, +) { + for (idx, marker) in markers.iter().enumerate() { + let hovered = match (kind, hover_marker) { + (MarkerKind::Start, Some(HoverMarker::Start(hover_idx))) => hover_idx == idx, + (MarkerKind::End, Some(HoverMarker::End(hover_idx))) => hover_idx == idx, + _ => false, + }; + draw_area_marker( + painter, + geometry, + marker, + label, + base_color, + colorblind_mode, + hovered, + ); + } +} + // Draw a rectangular wall segment between two points. fn draw_wall_segment( painter: &egui::Painter, diff --git a/src/startend.rs b/src/startend.rs index eff59e5..b0dea6e 100644 --- a/src/startend.rs +++ b/src/startend.rs @@ -59,37 +59,30 @@ pub fn populate_random_markers( consume_room(&mut available_end_rooms, end_room_idx); } - for idx in pair_count..start_count { - let room_idx = pick_room_index( - &available_start_rooms, - layout.rooms.len(), - seed::derive_seed(settings.seed, EXTRA_START_ROOM_STREAM_BASE + idx as u64), - ); - let room = &layout.rooms[room_idx]; - layout.start_markers.push(marker_in_room( - room, - settings.min_start_marker_size, - settings.max_start_marker_size, - seed::derive_seed(settings.seed, EXTRA_START_MARKER_STREAM_BASE + idx as u64), - )); - consume_room(&mut available_start_rooms, room_idx); - } - - for idx in pair_count..end_count { - let room_idx = pick_room_index( - &available_end_rooms, - layout.rooms.len(), - seed::derive_seed(settings.seed, EXTRA_END_ROOM_STREAM_BASE + idx as u64), - ); - let room = &layout.rooms[room_idx]; - layout.end_markers.push(marker_in_room( - room, - settings.min_end_marker_size, - settings.max_end_marker_size, - seed::derive_seed(settings.seed, EXTRA_END_MARKER_STREAM_BASE + idx as u64), - )); - consume_room(&mut available_end_rooms, room_idx); - } + assign_extra_markers( + &mut layout.start_markers, + &layout.rooms, + &mut available_start_rooms, + pair_count, + start_count, + settings.min_start_marker_size, + settings.max_start_marker_size, + settings.seed, + EXTRA_START_ROOM_STREAM_BASE, + EXTRA_START_MARKER_STREAM_BASE, + ); + assign_extra_markers( + &mut layout.end_markers, + &layout.rooms, + &mut available_end_rooms, + pair_count, + end_count, + settings.min_end_marker_size, + settings.max_end_marker_size, + settings.seed, + EXTRA_END_ROOM_STREAM_BASE, + EXTRA_END_MARKER_STREAM_BASE, + ); layout } @@ -142,6 +135,34 @@ fn marker_in_room( layout::AreaMarker { cell: (x, y), size } } +fn assign_extra_markers( + markers: &mut Vec, + rooms: &[layout::Room], + available_rooms: &mut Vec, + start_idx: usize, + end_idx: usize, + min_size: usize, + max_size: usize, + seed_base: u64, + room_stream_base: u64, + marker_stream_base: u64, +) { + for idx in start_idx..end_idx { + let room_idx = pick_room_index( + available_rooms, + rooms.len(), + seed::derive_seed(seed_base, room_stream_base + idx as u64), + ); + markers.push(marker_in_room( + &rooms[room_idx], + min_size, + max_size, + seed::derive_seed(seed_base, marker_stream_base + idx as u64), + )); + consume_room(available_rooms, room_idx); + } +} + // Match each start/end pair to the farthest available room combination. fn farthest_room_pair( rooms: &[layout::Room],