added ghosts for tool placements
This commit is contained in:
+204
@@ -309,6 +309,7 @@ impl eframe::App for DungeonApp {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.draw_add_overlay(&painter, &geometry);
|
self.draw_add_overlay(&painter, &geometry);
|
||||||
|
self.draw_add_tool_ghost(&painter, &geometry);
|
||||||
self.draw_resize_overlay(&painter, &geometry);
|
self.draw_resize_overlay(&painter, &geometry);
|
||||||
self.draw_corridor_hover_overlay(&painter, &geometry);
|
self.draw_corridor_hover_overlay(&painter, &geometry);
|
||||||
self.draw_door_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_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.
|
// Add a room anchored to the given grid cell if space allows.
|
||||||
fn add_room_at_cell(&mut self, cell: (usize, usize)) {
|
fn add_room_at_cell(&mut self, cell: (usize, usize)) {
|
||||||
self.push_undo_snapshot();
|
self.push_undo_snapshot();
|
||||||
|
|||||||
Reference in New Issue
Block a user