Editor: remove tiles from painted zones, scrollable zone list
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a8d1c4d6ea
commit
c11d281281
20 files changed
+92
-3
No files matched your search
+73
-2
@@ -61,6 +61,8 @@ pub struct MapEdit {
|
||||
zone: usize, // selected zone
|
||||
zone_shape: usize, // shape for a new zone
|
||||
zone_name: String,
|
||||
zone_erase: bool, // painting a tiles zone takes tiles out of it again
|
||||
zone_scroll: usize, // first zone shown in the list (usize::MAX: scroll to the end)
|
||||
last_mouse: Option<Vec2>,
|
||||
}
|
||||
|
||||
@@ -117,6 +119,8 @@ impl MapEdit {
|
||||
zone: 0,
|
||||
zone_shape: 0,
|
||||
zone_name: String::new(),
|
||||
zone_erase: false,
|
||||
zone_scroll: 0,
|
||||
last_mouse: None,
|
||||
}
|
||||
}
|
||||
@@ -460,9 +464,18 @@ impl MapEdit {
|
||||
}
|
||||
m.zones.push(z);
|
||||
self.zone = m.zones.len() - 1;
|
||||
self.zone_scroll = usize::MAX;
|
||||
self.zone_name.clear();
|
||||
}
|
||||
|
||||
// the brush takes tiles out of the selected tiles zone
|
||||
fn erase_zone_tiles(&mut self, m: &mut MissionDoc, x: i32, y: i32) {
|
||||
let targets = self.targets(x, y);
|
||||
if let Some(t) = m.zones.get_mut(self.zone).filter(|z| z.shape == "tiles").and_then(|z| z.tiles.as_mut()) {
|
||||
t.retain(|p| !targets.contains(p));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame(&mut self, im: &mut Im, gfx: &Gfx, r3d: &mut R3d, dt: f32, now: f64, m: &mut MissionDoc) -> MapResult {
|
||||
let (cssx, cssy) = mouse_position();
|
||||
let bar_w = CW() * 30.0;
|
||||
@@ -547,6 +560,15 @@ impl MapEdit {
|
||||
}
|
||||
im.pressed = false;
|
||||
}
|
||||
// a tiles zone is painted (or erased) all along the drag
|
||||
let tiles_zone = self.cat == Cat::Zones && ZONE_SHAPES[self.zone_shape] == "tiles";
|
||||
if tiles_zone && im.down && self.drag.is_some() {
|
||||
if self.zone_erase {
|
||||
self.erase_zone_tiles(m, x, y);
|
||||
} else {
|
||||
self.draw_zone(m, x, y, x, y);
|
||||
}
|
||||
}
|
||||
if self.stroke && im.down {
|
||||
for (tx, ty) in self.targets(x, y) {
|
||||
self.paint_tile(tx, ty);
|
||||
@@ -555,7 +577,11 @@ impl MapEdit {
|
||||
if im.released {
|
||||
if let Some((sx, sy)) = self.drag {
|
||||
if self.cat == Cat::Zones {
|
||||
self.draw_zone(m, sx, sy, x, y);
|
||||
if ZONE_SHAPES[self.zone_shape] == "tiles" && self.zone_erase {
|
||||
self.erase_zone_tiles(m, x, y);
|
||||
} else {
|
||||
self.draw_zone(m, sx, sy, x, y);
|
||||
}
|
||||
} else {
|
||||
for (tx, ty) in self.targets(x, y) {
|
||||
self.paint_tile(tx, ty);
|
||||
@@ -738,7 +764,24 @@ impl MapEdit {
|
||||
label(gfx, x, y, &tr("ed.zones"), FRAME_HI);
|
||||
y += CH() * 1.4;
|
||||
let mut remove = None;
|
||||
for k in 0..m.zones.len() {
|
||||
// the list scrolls (wheel over it) when there are more zones than room
|
||||
let row = CH() * 1.7;
|
||||
let room = (((h - CH() * 3.0 - y) / row).floor() as usize).max(1);
|
||||
let over_list = im.mx < bar_w && im.my >= y && im.my < y + room as f32 * row;
|
||||
if over_list && im.wheel != 0.0 {
|
||||
self.zone_scroll = if im.wheel > 0.0 { self.zone_scroll.min(m.zones.len()).saturating_sub(1) } else { self.zone_scroll.saturating_add(1) };
|
||||
}
|
||||
let max_scroll = m.zones.len().saturating_sub(room);
|
||||
if self.zone_scroll == usize::MAX {
|
||||
// a new zone: show it
|
||||
self.zone_scroll = self.zone.saturating_sub(room - 1);
|
||||
}
|
||||
self.zone_scroll = self.zone_scroll.min(max_scroll);
|
||||
if self.zone_scroll > 0 || max_scroll > 0 {
|
||||
let more = format!("{}-{} / {}", self.zone_scroll + 1, (self.zone_scroll + room).min(m.zones.len()), m.zones.len());
|
||||
gfx.text(&more, x + fw - gfx.measure(&more, SMALL()), y - CH() * 1.3, SMALL(), DIM);
|
||||
}
|
||||
for k in self.zone_scroll..m.zones.len() {
|
||||
if y > h - CH() * 3.0 {
|
||||
break;
|
||||
}
|
||||
@@ -778,6 +821,10 @@ impl MapEdit {
|
||||
}
|
||||
bx += gfx.measure(&tr("ed.fill"), S()) + CW() * 4.0;
|
||||
}
|
||||
if self.cat == Cat::Zones && ZONE_SHAPES[self.zone_shape] == "tiles" {
|
||||
im.toggle(gfx, bx, by + CH() * 0.15, &tr("ed.zone_erase"), &mut self.zone_erase);
|
||||
bx += gfx.measure(&tr("ed.zone_erase"), S()) + CW() * 4.0;
|
||||
}
|
||||
let mirrors: Vec<String> = (0..4).map(|k| tr(&format!("ed.mirror{}", k))).collect();
|
||||
if let Some(c) = im.dropdown(gfx, id("mirror", 0), Rect::new(bx, by, CW() * 23.0, CH() * 1.7), &mirrors[self.mirror as usize], &mirrors) {
|
||||
self.mirror = c as u8;
|
||||
@@ -799,3 +846,27 @@ impl MapEdit {
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn tiles_of_a_painted_zone_can_be_taken_out_again() {
|
||||
let mut ed = MapEdit::new(Game::new(3, 64, 64));
|
||||
let mut m = MissionDoc::default();
|
||||
ed.zone_shape = ZONE_SHAPES.iter().position(|s| *s == "tiles").unwrap();
|
||||
ed.brush = 2;
|
||||
ed.draw_zone(&mut m, 10, 10, 10, 10);
|
||||
ed.draw_zone(&mut m, 14, 10, 14, 10);
|
||||
assert_eq!(m.zones.len(), 1, "painting goes on in the selected tiles zone");
|
||||
let n = m.zones[0].tiles.as_ref().unwrap().len();
|
||||
assert!(n >= 2);
|
||||
ed.erase_zone_tiles(&mut m, 10, 10);
|
||||
let t = m.zones[0].tiles.as_ref().unwrap();
|
||||
assert!(!t.contains(&(10, 10)) && t.contains(&(14, 10)));
|
||||
assert!(t.len() < n);
|
||||
// a new zone scrolls the list to it
|
||||
assert_eq!(ed.zone_scroll, usize::MAX);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user