Editor layout fixes from a visual check
No fog while painting, readable tool bars, a two-row spawn block, a dialog that keeps the clicks to itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
abe01ff23e
commit
aacc6a00b2
3 files changed
+77
-41
No files matched your search
+23
-9
@@ -169,7 +169,6 @@ impl BlockEdit {
|
||||
if im.button(gfx, Rect::new(CW(), CH() * 0.7, CW() * 12.0, CH() * 1.7), &tr("ed.back")) || (is_key_pressed(KeyCode::Escape) && !im.typing && self.drag.is_none()) {
|
||||
back = true;
|
||||
}
|
||||
gfx.text(&title, CW() * 14.0, CH() * 1.0, S(), FRAME_HI);
|
||||
let mut bx = w - CW();
|
||||
let buttons = [tr("ed.delete"), tr("ed.paste"), tr("ed.copy"), tr("ed.redo"), tr("ed.undo")];
|
||||
let mut pressed_btn = None;
|
||||
@@ -184,6 +183,10 @@ impl BlockEdit {
|
||||
let sw_ = CW() * 18.0;
|
||||
bx -= sw_ + CW();
|
||||
im.text_field(gfx, id("bsearch", 0), Rect::new(bx, CH() * 0.7, sw_, CH() * 1.7), &mut self.search, 24);
|
||||
// the script's name, as much as fits before the search field
|
||||
let room = ((bx - CW() * 15.0) / CW()).max(4.0) as usize;
|
||||
let title: String = title.chars().take(room).collect();
|
||||
gfx.text(&title, CW() * 14.0, CH() * 1.0, S(), FRAME_HI);
|
||||
if self.search.is_empty() && im.focus != Some(id("bsearch", 0)) {
|
||||
gfx.text(&tr("ed.search"), bx + CW() * 0.5, CH() * 1.0, S(), DIM);
|
||||
}
|
||||
@@ -294,7 +297,9 @@ impl BlockEdit {
|
||||
}
|
||||
y += CH() * 2.2;
|
||||
}
|
||||
gfx.text(&tr("ed.blocks_hint"), CW() * 0.5, h - CH() * 6.0, SMALL(), DIM);
|
||||
for (k, l) in wrap(&tr("ed.blocks_hint"), ((pal_w - CW()) / (GW * SMALL())) as usize).iter().enumerate() {
|
||||
gfx.text(l, CW() * 0.5, h - CH() * 6.0 + k as f32 * GH * SMALL() * 1.2, SMALL(), DIM);
|
||||
}
|
||||
|
||||
// ---- the script
|
||||
let ws = Rect::new(pal_w, top, w - pal_w, h - top - CH() * 2.0);
|
||||
@@ -418,13 +423,15 @@ impl BlockEdit {
|
||||
path.push(k);
|
||||
let cat = list[k].category();
|
||||
let col = cat_color(cat);
|
||||
let header = Rect::new(x, y, w, CH() * ROW);
|
||||
// the spawn block has many fields: two rows
|
||||
let rows = if matches!(list[k], Block::Spawn { .. }) { 2.0 } else { 1.0 };
|
||||
let header = Rect::new(x, y, w, CH() * ROW * rows);
|
||||
let problem = ctx.problems.iter().find(|(p, _)| *p == path).map(|(_, k)| *k);
|
||||
let selected = self.selected.as_ref() == Some(&path);
|
||||
let found = !ctx.search.is_empty() && (tr(&format!("blk.{}", list[k].kind_name())).to_lowercase().contains(&ctx.search) || block_text(&list[k]).to_lowercase().contains(&ctx.search));
|
||||
// slots: upper half before this block, lower half after it
|
||||
slots.push((Rect::new(x, y - CH() * 0.3, w, CH() * ROW * 0.5 + CH() * 0.3), lp.to_vec(), k));
|
||||
slots.push((Rect::new(x, y + CH() * ROW * 0.5, w, CH() * ROW * 0.5), lp.to_vec(), k + 1));
|
||||
slots.push((Rect::new(x, y - CH() * 0.3, w, header.h * 0.5 + CH() * 0.3), lp.to_vec(), k));
|
||||
slots.push((Rect::new(x, y + header.h * 0.5, w, header.h * 0.5), lp.to_vec(), k + 1));
|
||||
let nested = matches!(list[k], Block::If { .. } | Block::Repeat { .. });
|
||||
// the block: header row with its fields
|
||||
draw_block_shape(header, col, selected, found);
|
||||
@@ -433,7 +440,7 @@ impl BlockEdit {
|
||||
im.tip(header, &tr(p));
|
||||
}
|
||||
// grip: drag the block from here
|
||||
let grip = Rect::new(x, y, CW() * 1.4, CH() * ROW);
|
||||
let grip = Rect::new(x, y, CW() * 1.4, header.h);
|
||||
gfx.text("≡", x + CW() * 0.3, y + CH() * 0.6, S(), Color::new(1.0, 1.0, 1.0, 0.6));
|
||||
if im.pressed && im.over(grip) {
|
||||
im.pressed = false;
|
||||
@@ -441,7 +448,7 @@ impl BlockEdit {
|
||||
}
|
||||
let fy = y + (CH() * ROW - CH() * 1.5) * 0.5;
|
||||
let mut cx = x + CW() * 1.8;
|
||||
self.block_fields(im, gfx, &mut list[k], &path, &mut cx, fy, ctx);
|
||||
self.block_fields(im, gfx, &mut list[k], &path, &mut cx, fy, x + CW() * 3.0, ctx);
|
||||
// a click on the block's free area selects it
|
||||
if im.clicked(header) {
|
||||
ops.push(Op::Select(path.clone()));
|
||||
@@ -455,7 +462,7 @@ impl BlockEdit {
|
||||
}
|
||||
self.help = tr(&format!("blk.help.{}", list[k].kind_name()));
|
||||
}
|
||||
y += CH() * ROW;
|
||||
y += header.h;
|
||||
if nested {
|
||||
// the C shape: bodies indented, with an "else" bar for if
|
||||
let inner_x = x + CW() * 2.5;
|
||||
@@ -496,7 +503,7 @@ impl BlockEdit {
|
||||
|
||||
// the fields inside a block's header row
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn block_fields(&mut self, im: &mut Im, gfx: &Gfx, b: &mut Block, path: &[usize], cx: &mut f32, y: f32, ctx: &Ctx) {
|
||||
fn block_fields(&mut self, im: &mut Im, gfx: &Gfx, b: &mut Block, path: &[usize], cx: &mut f32, y: f32, x2: f32, ctx: &Ctx) {
|
||||
let word = |cx: &mut f32, s: &str| {
|
||||
gfx.text(s, *cx, y + CH() * 0.25, S(), TXT);
|
||||
*cx += gfx.measure(s, S()) + CW() * 0.6;
|
||||
@@ -517,6 +524,13 @@ impl BlockEdit {
|
||||
word(cx, &tr("blk.w_level"));
|
||||
self.value(im, gfx, level, Ty::Num, path, 3, cx, y, ctx);
|
||||
self.side_dd(im, gfx, side, false, path, 4, cx, y);
|
||||
// second row: where, and the name
|
||||
let y = y + CH() * ROW;
|
||||
*cx = x2;
|
||||
let word = |cx: &mut f32, s: &str| {
|
||||
gfx.text(s, *cx, y + CH() * 0.25, S(), TXT);
|
||||
*cx += gfx.measure(s, S()) + CW() * 0.6;
|
||||
};
|
||||
word(cx, &tr("blk.w_at"));
|
||||
let mut opts = vec![tr("blk.place_core"), tr("blk.place_event")];
|
||||
opts.extend(ctx.zones.iter().map(|z| trf("blk.place_zone", &[z.clone()])));
|
||||
|
||||
+12
-7
@@ -91,6 +91,9 @@ impl MapEdit {
|
||||
game.map.activate();
|
||||
game.recount();
|
||||
game.ents.retain(|e| e.alive);
|
||||
// no fog of war while painting (it is worked out again when the map is stored)
|
||||
game.map.explored.clear();
|
||||
game.map.visible.clear();
|
||||
let (cx, cy) = game.map.core;
|
||||
let mut cam = Cam::new(cx as f32 + 1.5, cy as f32 + 1.5);
|
||||
cam.zoom = 28.0;
|
||||
@@ -653,16 +656,16 @@ impl MapEdit {
|
||||
}
|
||||
y += CH() * 2.3;
|
||||
// categories as a grid of buttons
|
||||
let cw = (bar_w - CW() * 2.5) / 3.0;
|
||||
let cw = (bar_w - CW() * 2.25) / 2.0;
|
||||
for (k, c) in CATS.iter().enumerate() {
|
||||
let r = Rect::new(x + (k % 3) as f32 * (cw + CW() * 0.25), y + (k / 3) as f32 * CH() * 1.9, cw, CH() * 1.7);
|
||||
let r = Rect::new(x + (k % 2) as f32 * (cw + CW() * 0.25), y + (k / 2) as f32 * CH() * 1.8, cw, CH() * 1.6);
|
||||
let name = tr(&format!("ed.cat.{:?}", c).to_lowercase());
|
||||
if im.select(gfx, r, &name, self.cat == *c, TXT) {
|
||||
self.cat = *c;
|
||||
self.item = 0;
|
||||
}
|
||||
}
|
||||
y += CH() * 6.0;
|
||||
y += CH() * 1.8 * ((CATS.len() + 1) / 2) as f32 + CH() * 0.4;
|
||||
// the items of the category
|
||||
let items: Vec<String> = match self.cat {
|
||||
Cat::Terrain => TERRAIN.iter().map(|t| tr(&format!("ed.terrain.{}", t))).collect(),
|
||||
@@ -780,14 +783,16 @@ impl MapEdit {
|
||||
self.mirror = c as u8;
|
||||
}
|
||||
bx += CW() * 19.0;
|
||||
if im.button(gfx, Rect::new(bx, by, CW() * 8.0, CH() * 1.7), &tr("ed.undo")) {
|
||||
let uw = gfx.measure(&tr("ed.undo"), S()) + CW() * 2.0;
|
||||
if im.button(gfx, Rect::new(bx, by, uw, CH() * 1.7), &tr("ed.undo")) {
|
||||
self.undo();
|
||||
}
|
||||
bx += CW() * 8.5;
|
||||
if im.button(gfx, Rect::new(bx, by, CW() * 8.0, CH() * 1.7), &tr("ed.redo")) {
|
||||
bx += uw + CW() * 0.5;
|
||||
let rw = gfx.measure(&tr("ed.redo"), S()) + CW() * 2.0;
|
||||
if im.button(gfx, Rect::new(bx, by, rw, CH() * 1.7), &tr("ed.redo")) {
|
||||
self.redo();
|
||||
}
|
||||
bx += CW() * 9.0;
|
||||
bx += rw + CW();
|
||||
let info = trf("ed.map_info", &[self.game.map.w.to_string(), self.game.map.h.to_string(), self.game.ents.iter().filter(|e| e.alive).count().to_string(), self.game.towers.len().to_string()]);
|
||||
gfx.text(&info, bx, by + CH() * 0.3, SMALL(), DIM);
|
||||
gfx.text(&tr("ed.map_hint"), bar_w + CW(), sh() - CH() * 1.5, SMALL(), DIM);
|
||||
|
||||
+42
-25
@@ -207,6 +207,13 @@ impl Editor {
|
||||
pub fn frame(&mut self, gfx: &Gfx, r3d: &mut R3d, dt: f32, now: f64) -> EdAction {
|
||||
clear_background(Color::from_rgba(4, 3, 5, 255));
|
||||
self.im.begin();
|
||||
// an open dialog takes the clicks: the page behind it only draws
|
||||
let held = (self.im.pressed, self.im.released, self.im.wheel);
|
||||
if self.open_dialog {
|
||||
self.im.pressed = false;
|
||||
self.im.released = false;
|
||||
self.im.wheel = 0.0;
|
||||
}
|
||||
let mut act = EdAction::None;
|
||||
match self.screen {
|
||||
Screen::Map(i) => {
|
||||
@@ -236,6 +243,7 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
if self.open_dialog {
|
||||
(self.im.pressed, self.im.released, self.im.wheel) = held;
|
||||
begin_ui();
|
||||
if let Some(a) = self.open_screen(gfx) {
|
||||
act = a;
|
||||
@@ -263,30 +271,18 @@ impl Editor {
|
||||
let mut act = EdAction::None;
|
||||
let (w, h) = (sw(), sh());
|
||||
let im = &mut self.im;
|
||||
// top bar: name, author, language, file and server buttons
|
||||
// top bar: the title and the buttons, then name, author, language
|
||||
let bar_h = CH() * 5.0;
|
||||
panel(gfx, Rect::new(0.0, 0.0, w, bar_h), "");
|
||||
gfx.text(&tr("ed.campaign"), CW(), CH() * 0.4, S(), FRAME_HI);
|
||||
let fw = (CW() * 24.0).min(w * 0.25);
|
||||
label(gfx, CW(), CH() * 2.0, &tr("ed.name"), DIM);
|
||||
im.text_field(gfx, id("cname", 0), Rect::new(CW() * 8.0, CH() * 1.7, fw, CH() * 1.5), &mut self.doc.name, 40);
|
||||
label(gfx, CW(), CH() * 3.5, &tr("ed.author"), DIM);
|
||||
im.text_field(gfx, id("cauthor", 0), Rect::new(CW() * 8.0, CH() * 3.3, fw, CH() * 1.5), &mut self.doc.author, 32);
|
||||
let lx = CW() * 9.0 + fw;
|
||||
label(gfx, lx, CH() * 2.0, &tr("ed.language"), DIM);
|
||||
let langs = languages();
|
||||
let names: Vec<String> = langs.iter().map(|(_, n)| n.clone()).collect();
|
||||
let cur = langs.iter().find(|(c, _)| *c == self.doc.language).map(|(_, n)| n.clone()).unwrap_or_else(|| self.doc.language.clone());
|
||||
if let Some(k) = im.dropdown(gfx, id("clang", 0), Rect::new(lx, CH() * 3.3, CW() * 14.0, CH() * 1.5), &cur, &names) {
|
||||
self.doc.language = langs[k].0.clone();
|
||||
}
|
||||
// buttons on the right
|
||||
gfx.text(&tr("ed.campaign"), CW(), CH() * 0.8, S(), FRAME_HI);
|
||||
let labels = [tr("ed.play"), tr("ed.new"), tr("ed.open"), tr("ed.save_file"), tr("ed.save_server"), tr("ed.close")];
|
||||
let bw = labels.iter().map(|l| gfx.measure(l, S())).fold(0.0, f32::max) + CW() * 2.0;
|
||||
let mut bx = w - CW() - bw;
|
||||
let mut bx = w - CW();
|
||||
for k in (0..labels.len()).rev() {
|
||||
let r = Rect::new(bx, CH() * 0.6, bw, CH() * 1.7);
|
||||
if im.button(gfx, r, &labels[k]) {
|
||||
let bw = gfx.measure(&labels[k], S()) + CW() * 2.0;
|
||||
bx -= bw;
|
||||
let r = Rect::new(bx, CH() * 0.5, bw, CH() * 1.7);
|
||||
let clicked = if k == 0 { im.button_c(gfx, r, &labels[k], GREEN) } else { im.button(gfx, r, &labels[k]) };
|
||||
if clicked {
|
||||
match k {
|
||||
0 => act = EdAction::Play,
|
||||
1 => {
|
||||
@@ -303,18 +299,39 @@ impl Editor {
|
||||
_ => act = EdAction::Close,
|
||||
}
|
||||
}
|
||||
bx -= bw + CW() * 0.5;
|
||||
bx -= CW() * 0.5;
|
||||
}
|
||||
let y2 = CH() * 2.9;
|
||||
let fw = (CW() * 22.0).min(w * 0.2);
|
||||
let mut x = CW();
|
||||
label(gfx, x, y2 + CH() * 0.25, &tr("ed.name"), DIM);
|
||||
x += gfx.measure(&tr("ed.name"), S()) + CW();
|
||||
im.text_field(gfx, id("cname", 0), Rect::new(x, y2, fw, CH() * 1.5), &mut self.doc.name, 40);
|
||||
x += fw + CW() * 1.5;
|
||||
label(gfx, x, y2 + CH() * 0.25, &tr("ed.author"), DIM);
|
||||
x += gfx.measure(&tr("ed.author"), S()) + CW();
|
||||
im.text_field(gfx, id("cauthor", 0), Rect::new(x, y2, fw * 0.8, CH() * 1.5), &mut self.doc.author, 32);
|
||||
x += fw * 0.8 + CW() * 1.5;
|
||||
label(gfx, x, y2 + CH() * 0.25, &tr("ed.language"), DIM);
|
||||
x += gfx.measure(&tr("ed.language"), S()) + CW();
|
||||
let langs = languages();
|
||||
let names: Vec<String> = langs.iter().map(|(_, n)| n.clone()).collect();
|
||||
let cur = langs.iter().find(|(c, _)| *c == self.doc.language).map(|(_, n)| n.clone()).unwrap_or_else(|| self.doc.language.clone());
|
||||
if let Some(k) = im.dropdown(gfx, id("clang", 0), Rect::new(x, y2, CW() * 14.0, CH() * 1.5), &cur, &names) {
|
||||
self.doc.language = langs[k].0.clone();
|
||||
}
|
||||
x += CW() * 15.5;
|
||||
let mut publ = self.published;
|
||||
if self.server_id.is_some() && im.toggle(gfx, w - CW() * 2.0 - bw * 3.5, CH() * 3.1, &tr("ed.published"), &mut publ) {
|
||||
if self.server_id.is_some() && im.toggle(gfx, x, y2, &tr("ed.published"), &mut publ) {
|
||||
self.published = publ;
|
||||
act = EdAction::Publish(publ);
|
||||
}
|
||||
let add = Rect::new(w - CW() - bw, CH() * 3.0, bw, CH() * 1.7);
|
||||
if im.button(gfx, add, &tr("ed.add_mission")) {
|
||||
let al = tr("ed.add_mission");
|
||||
let aw = gfx.measure(&al, S()) + CW() * 2.0;
|
||||
if im.button(gfx, Rect::new(w - CW() - aw, y2 - CH() * 0.1, aw, CH() * 1.7), &al) {
|
||||
let n = self.doc.missions.len();
|
||||
self.doc.add_mission();
|
||||
self.doc.missions[n].pos = (-self.graph.pan.x / CW() * 0.0 + 40.0 + (n % 5) as f32 * 220.0, 40.0 + (n / 5) as f32 * 140.0);
|
||||
self.doc.missions[n].pos = (40.0 + (n % 5) as f32 * 220.0, 40.0 + (n / 5) as f32 * 140.0);
|
||||
}
|
||||
|
||||
// the canvas: cards and arrows
|
||||
|
||||
Reference in new issue
Block a user