mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Merge pull request #2599 from dotCooCoo/fix/appearance-inline-text-typing
Appearance: the inline effect editor's text fields keep what is typed
This commit is contained in:
@@ -782,10 +782,8 @@ fn effect_editor(app: &mut VectorcraftApp, ui: &mut Ui, item: Option<usize>, k:
|
||||
widgets::dim_label(ui, &size.map_or_else(String::new, |(w, h)| format!("{w} × {h} px")));
|
||||
}
|
||||
Value::String(s) => {
|
||||
let mut buf = s.clone();
|
||||
let r = ui.add(egui::TextEdit::singleline(&mut buf).desired_width(90.0));
|
||||
if r.lost_focus() && buf != *s {
|
||||
change = Some((key.clone(), json!(buf)));
|
||||
if let Some(typed) = widgets::exact_text_field(ui, ("fx", item, k, key.as_str()), s, 90.0) {
|
||||
change = Some((key.clone(), json!(typed)));
|
||||
}
|
||||
}
|
||||
// Free Distort's corners are dragged in its dialog.
|
||||
@@ -1059,6 +1057,72 @@ mod tests {
|
||||
assert_eq!(editor_params(&e).get("angle"), Some(&json!(270)));
|
||||
}
|
||||
|
||||
/// A text field of the inline editor keeps what is typed from one frame to the next: a Drop
|
||||
/// Shadow's color typed a character a frame and confirmed with Enter is set in one undo step.
|
||||
/// Escape drops what is typed.
|
||||
#[test]
|
||||
fn the_effect_editor_keeps_text_typed_across_frames() {
|
||||
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 100, "height": 100})).unwrap();
|
||||
let id = app.run("shape.rectangle", json!({"x": 0, "y": 0, "width": 20, "height": 20})).unwrap()["id"].as_u64().unwrap();
|
||||
app.run("effect.apply", json!({"effect": "stylize.dropShadow"})).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
set_pstate(&ctx, "ap-fx-open-None-0", true);
|
||||
let mut time = 0.0;
|
||||
let mut run = |app: &mut VectorcraftApp, events: Vec<egui::Event>| {
|
||||
time += 0.1;
|
||||
let mut out = ctx.run_ui(egui::RawInput { events, time: Some(time), ..Default::default() }, |ui| show(app, ui));
|
||||
out.textures_delta.clear();
|
||||
out
|
||||
};
|
||||
// Every text drawn, with its center.
|
||||
fn texts(s: &egui::Shape, out: &mut Vec<(String, egui::Pos2)>) {
|
||||
match s {
|
||||
egui::Shape::Text(t) => out.push((t.galley.text().to_string(), t.visual_bounding_rect().center())),
|
||||
egui::Shape::Vec(v) => v.iter().for_each(|s| texts(s, out)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let drawn = |out: &egui::FullOutput| {
|
||||
let mut v = vec![];
|
||||
out.shapes.iter().for_each(|c| texts(&c.shape, &mut v));
|
||||
v
|
||||
};
|
||||
run(&mut app, vec![]);
|
||||
let shown = drawn(&run(&mut app, vec![]));
|
||||
let at = shown.iter().find(|(t, _)| t == "#000000").map(|(_, p)| *p);
|
||||
let Some(at) = at else { panic!("no color field: {shown:?}") };
|
||||
let button = |pressed| egui::Event::PointerButton { pos: at, button: egui::PointerButton::Primary, pressed, modifiers: Default::default() };
|
||||
let key = |key, modifiers| egui::Event::Key { key, physical_key: None, pressed: true, repeat: false, modifiers };
|
||||
for events in [vec![egui::Event::PointerMoved(at)], vec![button(true)], vec![button(false)]] {
|
||||
run(&mut app, events);
|
||||
}
|
||||
run(&mut app, vec![key(egui::Key::A, egui::Modifiers::COMMAND)]);
|
||||
let undo = app.session.active().unwrap().history.undo.len();
|
||||
for ch in "#ff0000".chars() {
|
||||
run(&mut app, vec![egui::Event::Text(ch.to_string())]);
|
||||
}
|
||||
let shown = drawn(&run(&mut app, vec![]));
|
||||
assert!(shown.iter().any(|(t, _)| t == "#ff0000"), "the field shows what was typed: {shown:?}");
|
||||
run(&mut app, vec![key(egui::Key::Enter, egui::Modifiers::NONE)]);
|
||||
run(&mut app, vec![]);
|
||||
let color = |app: &VectorcraftApp| app.session.active().unwrap().doc.node(NodeId(id)).unwrap().appearance.effects[0].params["color"].clone();
|
||||
assert_eq!(color(&app), json!("#ff0000"));
|
||||
assert_eq!(app.session.active().unwrap().history.undo.len(), undo + 1, "one undo step");
|
||||
// Escape drops what is typed.
|
||||
for events in [vec![button(true)], vec![button(false)]] {
|
||||
run(&mut app, events);
|
||||
}
|
||||
run(&mut app, vec![egui::Event::Text("0".into())]);
|
||||
let shown = drawn(&run(&mut app, vec![]));
|
||||
assert!(shown.iter().any(|(t, _)| t.len() == 8 && t.starts_with('#')), "a 0 typed into the color: {shown:?}");
|
||||
run(&mut app, vec![key(egui::Key::Escape, egui::Modifiers::NONE)]);
|
||||
run(&mut app, vec![]);
|
||||
assert_eq!(color(&app), json!("#ff0000"));
|
||||
assert_eq!(app.session.active().unwrap().history.undo.len(), undo + 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drops_pick_the_command() {
|
||||
use vectorcraft_doc::{Appearance, FillLayer};
|
||||
|
||||
Reference in New Issue
Block a user