added ghosts for tool placements

This commit is contained in:
grimsace
2026-05-12 13:40:11 -05:00
parent ea340c558b
commit ef76e2af3e
+204
View File
@@ -309,6 +309,7 @@ impl eframe::App for DungeonApp {
);
}
self.draw_add_overlay(&painter, &geometry);
self.draw_add_tool_ghost(&painter, &geometry);
self.draw_resize_overlay(&painter, &geometry);
self.draw_corridor_hover_overlay(&painter, &geometry);
self.draw_door_hover_overlay(&painter, &geometry);
@@ -993,6 +994,209 @@ impl DungeonApp {
draw_dashed_line(painter, start, end, stroke, 8.0, 6.0);
}
// Draw ghost preview for the currently active add tool.
fn draw_add_tool_ghost(&self, painter: &egui::Painter, geometry: &GridGeometry) {
let tool = self.settings.add_tool;
if tool == AddTool::None || tool == AddTool::Corridor {
return;
}
let Some(pointer_pos) = painter.ctx().pointer_hover_pos() else {
return;
};
let Some((grid_x, grid_y)) = pointer_to_grid(pointer_pos, geometry) else {
return;
};
let cell = (grid_x.floor() as usize, grid_y.floor() as usize);
let ghost_alpha = 0.35;
match tool {
AddTool::Room => {
let width = self.settings.add_room_width.max(1);
let height = self.settings.add_room_height.max(1);
let max_x = self.settings.cols.saturating_sub(cell.0);
let max_y = self.settings.rows.saturating_sub(cell.1);
let w = width.min(max_x).max(1);
let h = height.min(max_y).max(1);
let left = geometry.rect.left() + cell.0 as f32 * geometry.cell_size;
let top = geometry.rect.top() + cell.1 as f32 * geometry.cell_size;
let right = left + w as f32 * geometry.cell_size;
let bottom = top + h as f32 * geometry.cell_size;
let rect =
egui::Rect::from_min_max(egui::pos2(left, top), egui::pos2(right, bottom));
let fill = Color32::from_rgb(70, 120, 160).gamma_multiply(ghost_alpha);
painter.rect_filled(rect, 4.0, fill);
painter.rect_stroke(
rect,
4.0,
Stroke::new(
1.5,
Color32::from_rgb(150, 200, 240).gamma_multiply(ghost_alpha + 0.3),
),
egui::StrokeKind::Middle,
);
}
AddTool::Text => {
let text = self.settings.add_text_value.trim();
if text.is_empty() {
return;
}
let font_size = self.settings.add_text_font_size.max(8);
let rect = text_label_rect(
geometry,
&layout::TextLabel {
cell,
text: text.to_string(),
font_size,
},
);
let fill = Color32::from_rgb(50, 50, 70).gamma_multiply(ghost_alpha);
painter.rect_filled(rect.expand(4.0), 4.0, fill);
painter.rect_stroke(
rect.expand(4.0),
4.0,
Stroke::new(
1.0,
Color32::from_rgb(180, 180, 220).gamma_multiply(ghost_alpha + 0.2),
),
egui::StrokeKind::Middle,
);
let color = Color32::WHITE.gamma_multiply(ghost_alpha + 0.1);
painter.text(
rect.center(),
egui::Align2::CENTER_CENTER,
text,
egui::FontId::proportional(font_size as f32),
color,
);
}
AddTool::StartMarker
| AddTool::EndMarker
| AddTool::TrapMarker
| AddTool::MonsterMarker => {
let size = self.settings.add_marker_size.max(1);
let origin =
centered_marker_origin(cell, size, self.settings.cols, self.settings.rows);
let rect = marker_rect(&layout::AreaMarker { cell: origin, size }, geometry);
let base_color = match tool {
AddTool::StartMarker => Color32::from_rgb(60, 220, 200),
AddTool::EndMarker => Color32::from_rgb(240, 90, 90),
AddTool::TrapMarker => Color32::from_rgb(150, 80, 230),
AddTool::MonsterMarker => Color32::from_rgb(200, 50, 50),
_ => Color32::WHITE,
};
let fill = base_color.gamma_multiply(ghost_alpha);
painter.rect_filled(rect, 4.0, fill);
painter.rect_stroke(
rect,
4.0,
Stroke::new(
1.5,
Color32::from_rgb(255, 255, 255).gamma_multiply(ghost_alpha + 0.2),
),
egui::StrokeKind::Middle,
);
let label = match tool {
AddTool::StartMarker => "S",
AddTool::EndMarker => "E",
AddTool::TrapMarker => "T",
AddTool::MonsterMarker => "M",
_ => "?",
};
let text_color = Color32::WHITE.gamma_multiply(ghost_alpha + 0.15);
let font_size = (geometry.cell_size * size as f32 * 0.5).clamp(14.0, 72.0);
painter.text(
rect.center(),
egui::Align2::CENTER_CENTER,
label,
egui::FontId::proportional(font_size),
text_color,
);
}
AddTool::Staircase => {
let width = self.settings.add_stair_width.max(1);
let height = self.settings.add_stair_height.max(1);
let max_x = self.settings.cols.saturating_sub(width);
let max_y = self.settings.rows.saturating_sub(height);
let w = width.min(max_x).max(1);
let h = height.min(max_y).max(1);
let left = geometry.rect.left() + cell.0 as f32 * geometry.cell_size;
let top = geometry.rect.top() + cell.1 as f32 * geometry.cell_size;
let right = left + w as f32 * geometry.cell_size;
let bottom = top + h as f32 * geometry.cell_size;
let rect =
egui::Rect::from_min_max(egui::pos2(left, top), egui::pos2(right, bottom));
let fill = Color32::from_rgb(200, 150, 50).gamma_multiply(ghost_alpha);
painter.rect_filled(rect, 4.0, fill);
painter.rect_stroke(
rect,
4.0,
Stroke::new(
1.5,
Color32::from_rgb(220, 180, 80).gamma_multiply(ghost_alpha + 0.2),
),
egui::StrokeKind::Middle,
);
let steps = (h as f32 * 2.0).round() as usize;
let step_height = (rect.height() / (steps as f32)).max(1.0);
let line_color = Color32::from_rgb(150, 100, 30).gamma_multiply(ghost_alpha + 0.15);
for i in 0..steps {
let y = rect.top() + (i as f32 * step_height) + step_height * 0.5;
painter.line_segment(
[
egui::pos2(rect.left() + 2.0, y),
egui::pos2(rect.right() - 2.0, y),
],
Stroke::new(1.5, line_color),
);
}
}
AddTool::Archway | AddTool::Door | AddTool::LockedDoor | AddTool::SecretDoor => {
// Show ghost preview on the hovered door edge.
if let Some((edge_a, edge_b)) = self.door_edge_at_pointer(pointer_pos, geometry) {
let door_width_cells = 1;
let style = match tool {
AddTool::Archway => DoorLineStyle::Dotted,
AddTool::Door => DoorLineStyle::LongDash,
AddTool::LockedDoor => DoorLineStyle::ShortDash,
AddTool::SecretDoor => DoorLineStyle::DashDotDot,
_ => DoorLineStyle::Solid,
};
let color = match tool {
AddTool::Archway => Color32::from_rgb(230, 140, 60),
AddTool::Door => Color32::from_rgb(80, 200, 120),
AddTool::LockedDoor => Color32::from_rgb(220, 70, 70),
AddTool::SecretDoor => Color32::from_rgb(170, 80, 170),
_ => Color32::WHITE,
};
let ghost_color = color.gamma_multiply(ghost_alpha);
draw_door_line(
painter,
geometry,
edge_a,
edge_b,
door_width_cells,
Stroke::new((geometry.cell_size / 5.0).max(1.0), ghost_color),
style,
);
}
}
AddTool::None | AddTool::Corridor => {}
}
}
// Add a room anchored to the given grid cell if space allows.
fn add_room_at_cell(&mut self, cell: (usize, usize)) {
self.push_undo_snapshot();