fixed issues when resizing stairs in rooms

This commit is contained in:
grimsace
2026-04-28 14:23:37 -05:00
parent bd0d64b4af
commit 94d0a6db92
+127 -117
View File
@@ -588,6 +588,12 @@ impl DungeonApp {
{ {
self.push_undo_snapshot(); self.push_undo_snapshot();
self.drag_state = Some(DragState::Staircase(stair_drag)); self.drag_state = Some(DragState::Staircase(stair_drag));
} else if response.drag_started()
&& let Some(pointer_pos) = response.interact_pointer_pos()
&& let Some(corridor_drag) = self.corridor_drag_at_pointer(pointer_pos, geometry)
{
self.push_undo_snapshot();
self.drag_state = Some(DragState::Corridor(corridor_drag));
} else if response.drag_started() } else if response.drag_started()
&& let Some(pointer_pos) = response.interact_pointer_pos() && let Some(pointer_pos) = response.interact_pointer_pos()
&& let Some((room_idx, offset_x, offset_y)) = && let Some((room_idx, offset_x, offset_y)) =
@@ -599,12 +605,6 @@ impl DungeonApp {
offset_x, offset_x,
offset_y, offset_y,
})); }));
} else if response.drag_started()
&& let Some(pointer_pos) = response.interact_pointer_pos()
&& let Some(corridor_drag) = self.corridor_drag_at_pointer(pointer_pos, geometry)
{
self.push_undo_snapshot();
self.drag_state = Some(DragState::Corridor(corridor_drag));
} }
if response.dragged() if response.dragged()
@@ -1225,6 +1225,13 @@ impl DungeonApp {
// Update which room/corridor/door is currently hovered. // Update which room/corridor/door is currently hovered.
fn update_hover_targets(&mut self, ctx: &egui::Context, geometry: &GridGeometry) { fn update_hover_targets(&mut self, ctx: &egui::Context, geometry: &GridGeometry) {
if self.drag_state.is_some()
|| self.resize_state.is_some()
|| self.add_corridor_drag.is_some()
{
return;
}
let Some(pointer_pos) = ctx.pointer_hover_pos() else { let Some(pointer_pos) = ctx.pointer_hover_pos() else {
self.clear_hover_targets(); self.clear_hover_targets();
return; return;
@@ -1560,12 +1567,6 @@ impl DungeonApp {
self.resize_state = Some(ResizeState::Text(state)); self.resize_state = Some(ResizeState::Text(state));
return true; return true;
} }
} else if let Some(room_idx) = self.resize_room_at_pointer(pointer_pos, geometry) {
if let Some(state) = self.start_resize(room_idx, pointer_pos, geometry) {
self.push_undo_snapshot();
self.resize_state = Some(ResizeState::Room(state));
return true;
}
} else if let Some(stair_idx) = self.stair_at_pointer(pointer_pos, geometry) { } else if let Some(stair_idx) = self.stair_at_pointer(pointer_pos, geometry) {
if let Some(state) = if let Some(state) =
self.start_staircase_resize(stair_idx, pointer_pos, geometry) self.start_staircase_resize(stair_idx, pointer_pos, geometry)
@@ -1574,6 +1575,12 @@ impl DungeonApp {
self.resize_state = Some(ResizeState::Staircase(state)); self.resize_state = Some(ResizeState::Staircase(state));
return true; return true;
} }
} else if let Some(room_idx) = self.resize_room_at_pointer(pointer_pos, geometry) {
if let Some(state) = self.start_resize(room_idx, pointer_pos, geometry) {
self.push_undo_snapshot();
self.resize_state = Some(ResizeState::Room(state));
return true;
}
} }
} }
} }
@@ -1822,22 +1829,8 @@ impl DungeonApp {
return; return;
} }
// Check for collisions with other stairs or rooms on the current level. // Check for collisions with other stairs on the current level.
let active_layout = &self.levels[self.settings.active_level_index]; let active_layout = &self.levels[self.settings.active_level_index];
if active_layout.rooms.iter().any(|room| {
rects_overlap(
new_stair_cell.0,
new_stair_cell.1,
new_stair_width,
new_stair_height,
room.x,
room.y,
room.width,
room.height,
)
}) {
return;
}
if active_layout.stairs.iter().enumerate().any(|(idx, stair)| { if active_layout.stairs.iter().enumerate().any(|(idx, stair)| {
idx != state.stair_idx idx != state.stair_idx
&& rects_overlap( && rects_overlap(
@@ -1903,15 +1896,36 @@ impl DungeonApp {
} }
let layout = &self.levels[self.settings.active_level_index]; let layout = &self.levels[self.settings.active_level_index];
if let Some(text_idx) = self // 1. Check active ResizeState first to lock visual feedback to the being-resized object.
.resize_state if let Some(state) = &self.resize_state {
.as_ref() match state {
.and_then(|s| match s { ResizeState::Text(state) => {
ResizeState::Text(state) => Some(state.text_idx), if let Some(label) = layout.text_labels.get(state.text_idx) {
_ => None, let rect = text_label_rect(geometry, label).expand(3.0);
}) painter.rect_stroke(
.or(self.hover_text_idx) rect,
{ 0.0,
Stroke::new(2.0, Color32::from_gray(180)),
egui::StrokeKind::Middle,
);
}
}
ResizeState::Room(state) => {
if let Some(room) = layout.rooms.get(state.room_idx) {
self.draw_room_resize_visuals(painter, geometry, room, true);
}
}
ResizeState::Staircase(state) => {
if let Some(stair) = layout.stairs.get(state.stair_idx) {
self.draw_staircase_resize_visuals(painter, geometry, stair, true);
}
}
}
return;
}
// 2. Fall back to hover state if not resizing.
if let Some(text_idx) = self.hover_text_idx {
if let Some(label) = layout.text_labels.get(text_idx) { if let Some(label) = layout.text_labels.get(text_idx) {
let rect = text_label_rect(geometry, label).expand(3.0); let rect = text_label_rect(geometry, label).expand(3.0);
painter.rect_stroke( painter.rect_stroke(
@@ -1920,97 +1934,93 @@ impl DungeonApp {
Stroke::new(2.0, Color32::from_gray(180)), Stroke::new(2.0, Color32::from_gray(180)),
egui::StrokeKind::Middle, egui::StrokeKind::Middle,
); );
return;
} }
} } else if let Some(room_idx) = self.hover_room_idx {
let room_idx = self
.resize_state
.as_ref()
.and_then(|s| match s {
ResizeState::Room(state) => Some(state.room_idx),
_ => None,
})
.or(self.hover_room_idx);
if let Some(room_idx) = room_idx {
if let Some(room) = layout.rooms.get(room_idx) { if let Some(room) = layout.rooms.get(room_idx) {
let color = Color32::from_gray(170); self.draw_room_resize_visuals(painter, geometry, room, false);
let stroke = Stroke::new(1.5, color); }
} else if let Some(stair_idx) = self.hover_stair_idx {
let left = geometry.rect.left() + room.x as f32 * geometry.cell_size; if let Some(stair) = layout.stairs.get(stair_idx) {
let top = geometry.rect.top() + room.y as f32 * geometry.cell_size; self.draw_staircase_resize_visuals(painter, geometry, stair, false);
let right = left + room.width as f32 * geometry.cell_size;
let bottom = top + room.height as f32 * geometry.cell_size;
let tl = egui::pos2(left, top);
let tr = egui::pos2(right, top);
let br = egui::pos2(right, bottom);
let bl = egui::pos2(left, bottom);
draw_dashed_line(painter, tl, tr, stroke, 6.0, 6.0);
draw_dashed_line(painter, tr, br, stroke, 6.0, 6.0);
draw_dashed_line(painter, br, bl, stroke, 6.0, 6.0);
draw_dashed_line(painter, bl, tl, stroke, 6.0, 6.0);
let font = egui::FontId::proportional(12.0);
let center_top = egui::pos2((left + right) * 0.5, top - 10.0);
let center_left = egui::pos2(left - 12.0, (top + bottom) * 0.5);
painter.text(
center_top,
egui::Align2::CENTER_CENTER,
"<->",
font.clone(),
color,
);
painter.text(center_left, egui::Align2::CENTER_CENTER, "^v", font, color);
if matches!(self.resize_state, Some(ResizeState::Room(_))) {
draw_resize_handle(painter, tl, ResizeCorner::TopLeft, color);
draw_resize_handle(painter, tr, ResizeCorner::TopRight, color);
draw_resize_handle(painter, br, ResizeCorner::BottomRight, color);
draw_resize_handle(painter, bl, ResizeCorner::BottomLeft, color);
}
return;
} }
} }
}
let stair_idx = self fn draw_room_resize_visuals(
.resize_state &self,
.as_ref() painter: &egui::Painter,
.and_then(|s| match s { geometry: &GridGeometry,
ResizeState::Staircase(state) => Some(state.stair_idx), room: &layout::Room,
_ => None, show_handles: bool,
}) ) {
.or(self.hover_stair_idx); let color = Color32::from_gray(170);
let stroke = Stroke::new(1.5, color);
if let Some(stair_idx) = stair_idx { let left = geometry.rect.left() + room.x as f32 * geometry.cell_size;
if let Some(stair) = layout.stairs.get(stair_idx) { let top = geometry.rect.top() + room.y as f32 * geometry.cell_size;
let color = Color32::from_gray(170); let right = left + room.width as f32 * geometry.cell_size;
let stroke = Stroke::new(1.5, color); let bottom = top + room.height as f32 * geometry.cell_size;
let left = geometry.rect.left() + stair.cell.0 as f32 * geometry.cell_size; let tl = egui::pos2(left, top);
let top = geometry.rect.top() + stair.cell.1 as f32 * geometry.cell_size; let tr = egui::pos2(right, top);
let right = left + stair.width as f32 * geometry.cell_size; let br = egui::pos2(right, bottom);
let bottom = top + stair.height as f32 * geometry.cell_size; let bl = egui::pos2(left, bottom);
let tl = egui::pos2(left, top); draw_dashed_line(painter, tl, tr, stroke, 6.0, 6.0);
let tr = egui::pos2(right, top); draw_dashed_line(painter, tr, br, stroke, 6.0, 6.0);
let br = egui::pos2(right, bottom); draw_dashed_line(painter, br, bl, stroke, 6.0, 6.0);
let bl = egui::pos2(left, bottom); draw_dashed_line(painter, bl, tl, stroke, 6.0, 6.0);
draw_dashed_line(painter, tl, tr, stroke, 6.0, 6.0); let font = egui::FontId::proportional(12.0);
draw_dashed_line(painter, tr, br, stroke, 6.0, 6.0); let center_top = egui::pos2((left + right) * 0.5, top - 10.0);
draw_dashed_line(painter, br, bl, stroke, 6.0, 6.0); let center_left = egui::pos2(left - 12.0, (top + bottom) * 0.5);
draw_dashed_line(painter, bl, tl, stroke, 6.0, 6.0); painter.text(
center_top,
egui::Align2::CENTER_CENTER,
"<->",
font.clone(),
color,
);
painter.text(center_left, egui::Align2::CENTER_CENTER, "^v", font, color);
if matches!(self.resize_state, Some(ResizeState::Staircase(_))) { if show_handles {
draw_resize_handle(painter, tl, ResizeCorner::TopLeft, color); draw_resize_handle(painter, tl, ResizeCorner::TopLeft, color);
draw_resize_handle(painter, tr, ResizeCorner::TopRight, color); draw_resize_handle(painter, tr, ResizeCorner::TopRight, color);
draw_resize_handle(painter, br, ResizeCorner::BottomRight, color); draw_resize_handle(painter, br, ResizeCorner::BottomRight, color);
draw_resize_handle(painter, bl, ResizeCorner::BottomLeft, color); draw_resize_handle(painter, bl, ResizeCorner::BottomLeft, color);
} }
} }
fn draw_staircase_resize_visuals(
&self,
painter: &egui::Painter,
geometry: &GridGeometry,
stair: &layout::Staircase,
show_handles: bool,
) {
let color = Color32::from_gray(170);
let stroke = Stroke::new(1.5, color);
let left = geometry.rect.left() + stair.cell.0 as f32 * geometry.cell_size;
let top = geometry.rect.top() + stair.cell.1 as f32 * geometry.cell_size;
let right = left + stair.width as f32 * geometry.cell_size;
let bottom = top + stair.height as f32 * geometry.cell_size;
let tl = egui::pos2(left, top);
let tr = egui::pos2(right, top);
let br = egui::pos2(right, bottom);
let bl = egui::pos2(left, bottom);
draw_dashed_line(painter, tl, tr, stroke, 6.0, 6.0);
draw_dashed_line(painter, tr, br, stroke, 6.0, 6.0);
draw_dashed_line(painter, br, bl, stroke, 6.0, 6.0);
draw_dashed_line(painter, bl, tl, stroke, 6.0, 6.0);
if show_handles {
draw_resize_handle(painter, tl, ResizeCorner::TopLeft, color);
draw_resize_handle(painter, tr, ResizeCorner::TopRight, color);
draw_resize_handle(painter, br, ResizeCorner::BottomRight, color);
draw_resize_handle(painter, bl, ResizeCorner::BottomLeft, color);
} }
} }