added click and drag for door objects

This commit is contained in:
grimsace
2026-05-19 14:22:19 -05:00
parent 66f77a177a
commit 8cc4cf4543
4 changed files with 115 additions and 30 deletions
+6 -1
View File
@@ -9,7 +9,9 @@ use std::sync::mpsc;
use std::thread;
use crate::exporter;
use crate::interact::{AddCorridorDrag, DragState, HoverMarker, ResizeState, draw_grid};
use crate::interact::{
AddCorridorDrag, AddDoorDrag, DragState, HoverMarker, ResizeState, draw_grid,
};
use crate::layout::{
self, DoorSettings, DungeonLayout, WindowSettings, populate_random_markers, populate_stairs,
};
@@ -45,6 +47,7 @@ pub struct DungeonApp {
pub export_progress: Option<exporter::ExportProgress>,
pub pending_delete: bool,
pub add_corridor_drag: Option<AddCorridorDrag>,
pub add_door_drag: Option<AddDoorDrag>,
pub resize_state: Option<ResizeState>,
pub hover_room_idx: Option<usize>,
pub hover_corridor_idx: Option<usize>,
@@ -70,6 +73,7 @@ impl Default for DungeonApp {
export_progress: None,
pending_delete: false,
add_corridor_drag: None,
add_door_drag: None,
resize_state: None,
hover_room_idx: None,
hover_corridor_idx: None,
@@ -398,6 +402,7 @@ impl DungeonApp {
pub fn reset_transient_state(&mut self) {
self.drag_state = None;
self.add_corridor_drag = None;
self.add_door_drag = None;
self.resize_state = None;
self.clear_hover_targets();
self.pending_delete = false;
+97 -28
View File
@@ -5,9 +5,10 @@
*/
use super::{
AddCorridorDrag, GridGeometry, HoverMarker, MarkerKind, cell_center, centered_marker_origin,
corridor_drag_at_pointer, door_edge_at_pointer, door_edges_for, marker_at_pointer, marker_rect,
normalized_edge, pointer_to_grid, room_at_pointer, stair_at_pointer, text_at_pointer,
AddCorridorDrag, AddDoorDrag, GridGeometry, HoverMarker, MarkerKind, cell_center,
centered_marker_origin, corridor_drag_at_pointer, door_edge_at_pointer, door_edges_for,
marker_at_pointer, marker_rect, normalized_edge, pointer_to_grid, room_at_pointer,
stair_at_pointer, text_at_pointer,
};
use crate::app::{DungeonApp, ManualDoorKind};
use crate::layout::{
@@ -23,12 +24,14 @@ pub fn handle_add_tool(app: &mut DungeonApp, response: &egui::Response, geometry
if app.settings.add_tool != AddTool::None && response.secondary_clicked() {
app.settings.add_tool = AddTool::None;
app.add_corridor_drag = None;
app.add_door_drag = None;
return;
}
match app.settings.add_tool {
AddTool::Room => {
app.add_corridor_drag = None;
app.add_door_drag = None;
if response.clicked()
&& let Some(pointer_pos) = response.interact_pointer_pos()
&& let Some((grid_x, grid_y)) = pointer_to_grid(pointer_pos, geometry)
@@ -38,6 +41,7 @@ pub fn handle_add_tool(app: &mut DungeonApp, response: &egui::Response, geometry
}
}
AddTool::Corridor => {
app.add_door_drag = None;
if response.drag_started()
&& let Some(pointer_pos) = response.interact_pointer_pos()
&& let Some((grid_x, grid_y)) = pointer_to_grid(pointer_pos, geometry)
@@ -65,6 +69,7 @@ pub fn handle_add_tool(app: &mut DungeonApp, response: &egui::Response, geometry
}
AddTool::Staircase => {
app.add_corridor_drag = None;
app.add_door_drag = None;
if response.clicked()
&& let Some(pointer_pos) = response.interact_pointer_pos()
&& let Some((grid_x, grid_y)) = pointer_to_grid(pointer_pos, geometry)
@@ -75,21 +80,11 @@ pub fn handle_add_tool(app: &mut DungeonApp, response: &egui::Response, geometry
}
AddTool::Archway | AddTool::Door | AddTool::LockedDoor | AddTool::SecretDoor => {
app.add_corridor_drag = None;
if response.clicked()
&& let Some(pointer_pos) = response.interact_pointer_pos()
{
let kind = match app.settings.add_tool {
AddTool::Archway => ManualDoorKind::Archway,
AddTool::Door => ManualDoorKind::Regular,
AddTool::LockedDoor => ManualDoorKind::Locked,
AddTool::SecretDoor => ManualDoorKind::Secret,
_ => unreachable!(),
};
add_door_at_pointer(app, pointer_pos, geometry, kind);
}
handle_add_door_tool(app, response, geometry);
}
AddTool::Text => {
app.add_corridor_drag = None;
app.add_door_drag = None;
if response.clicked()
&& let Some(pointer_pos) = response.interact_pointer_pos()
&& let Some((grid_x, grid_y)) = pointer_to_grid(pointer_pos, geometry)
@@ -103,6 +98,7 @@ pub fn handle_add_tool(app: &mut DungeonApp, response: &egui::Response, geometry
| AddTool::TrapMarker
| AddTool::MonsterMarker => {
app.add_corridor_drag = None;
app.add_door_drag = None;
if response.clicked()
&& let Some(pointer_pos) = response.interact_pointer_pos()
&& let Some((grid_x, grid_y)) = pointer_to_grid(pointer_pos, geometry)
@@ -120,10 +116,88 @@ pub fn handle_add_tool(app: &mut DungeonApp, response: &egui::Response, geometry
}
AddTool::None => {
app.add_corridor_drag = None;
app.add_door_drag = None;
}
}
}
// Handles click-and-drag painting for manual door tools.
pub fn handle_add_door_tool(
app: &mut DungeonApp,
response: &egui::Response,
geometry: &GridGeometry,
) {
let Some(kind) = manual_door_kind_from_tool(app.settings.add_tool) else {
app.add_door_drag = None;
return;
};
if response.drag_started() {
app.add_door_drag = Some(AddDoorDrag {
painted_edges: Default::default(),
snapshot_taken: false,
});
}
if (response.drag_started() || response.dragged() || response.clicked())
&& let Some(pointer_pos) = response.interact_pointer_pos()
{
paint_door_at_pointer(app, pointer_pos, geometry, kind);
}
if response.drag_stopped() {
app.add_door_drag = None;
}
}
// Converts the active add tool into a manual door kind.
pub fn manual_door_kind_from_tool(tool: AddTool) -> Option<ManualDoorKind> {
match tool {
AddTool::Archway => Some(ManualDoorKind::Archway),
AddTool::Door => Some(ManualDoorKind::Regular),
AddTool::LockedDoor => Some(ManualDoorKind::Locked),
AddTool::SecretDoor => Some(ManualDoorKind::Secret),
_ => None,
}
}
// Paints one door edge during a manual door drag.
pub fn paint_door_at_pointer(
app: &mut DungeonApp,
pointer_pos: egui::Pos2,
geometry: &GridGeometry,
kind: ManualDoorKind,
) {
let Some(edge) = door_edge_at_pointer(app, pointer_pos, geometry) else {
return;
};
let target = normalized_edge(edge.0, edge.1);
if let Some(drag) = &app.add_door_drag
&& drag.painted_edges.contains(&target)
{
return;
}
let needs_snapshot = app
.add_door_drag
.as_ref()
.map(|drag| !drag.snapshot_taken)
.unwrap_or(true);
if needs_snapshot {
app.push_undo_snapshot();
if let Some(drag) = &mut app.add_door_drag {
drag.snapshot_taken = true;
}
}
if add_door_at_edge(app, edge, kind)
&& let Some(drag) = &mut app.add_door_drag
{
drag.painted_edges.insert(target);
}
}
// Deletes at pointer.
pub fn delete_at_pointer(app: &mut DungeonApp, pointer_pos: egui::Pos2, geometry: &GridGeometry) {
if app.settings.active_level_index >= app.levels.len() {
@@ -450,22 +524,16 @@ pub fn delete_room(app: &mut DungeonApp, room_idx: usize) {
app.refresh_doors();
}
// Adds door at pointer.
pub fn add_door_at_pointer(
// Adds or updates a manual door on a specific cell edge.
pub fn add_door_at_edge(
app: &mut DungeonApp,
pointer_pos: egui::Pos2,
geometry: &GridGeometry,
edge: ((usize, usize), (usize, usize)),
kind: ManualDoorKind,
) {
) -> bool {
if app.settings.active_level_index >= app.levels.len() {
return;
return false;
}
let Some(edge) = door_edge_at_pointer(app, pointer_pos, geometry) else {
return;
};
app.push_undo_snapshot();
let layout = &mut app.levels[app.settings.active_level_index];
let target = normalized_edge(edge.0, edge.1);
@@ -509,7 +577,7 @@ pub fn add_door_at_pointer(
app.suppressed_auto_door_edges.remove(&edge);
}
layout.doors.extend(spawned);
return;
return true;
}
let corridor_cells = corridor_cells(layout, app.settings.cols, app.settings.rows);
@@ -519,7 +587,7 @@ pub fn add_door_at_pointer(
let b_in_corridor = corridor_cells.contains(&edge.1);
if !manual_door_edge_allowed(a_room, b_room, a_in_corridor, b_in_corridor) {
return;
return false;
}
layout.doors.push(layout::Door {
@@ -533,6 +601,7 @@ pub fn add_door_at_pointer(
manual: true,
});
app.suppressed_auto_door_edges.remove(&target);
true
}
// Checks whether manual door edge allowed.
+5 -1
View File
@@ -11,7 +11,11 @@ use eframe::egui;
// Handles update hover targets.
pub fn update_hover_targets(app: &mut DungeonApp, ctx: &egui::Context, geometry: &GridGeometry) {
if app.drag_state.is_some() || app.resize_state.is_some() || app.add_corridor_drag.is_some() {
if app.drag_state.is_some()
|| app.resize_state.is_some()
|| app.add_corridor_drag.is_some()
|| app.add_door_drag.is_some()
{
return;
}
+7
View File
@@ -4,6 +4,7 @@
*/
use crate::layout;
use std::collections::HashSet;
#[derive(Debug, Clone)]
pub struct RoomDragState {
@@ -38,6 +39,12 @@ pub struct AddCorridorDrag {
pub current_cell: (usize, usize),
}
#[derive(Debug, Clone)]
pub struct AddDoorDrag {
pub painted_edges: HashSet<((usize, usize), (usize, usize))>,
pub snapshot_taken: bool,
}
#[derive(Debug, Clone, Copy)]
pub enum ResizeCorner {
TopLeft,