mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Fix New Document orientation on category tabs and preset cards
Fixes #2084 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
committed by
bflatastic
co-authored by
Claude Haiku 5.5
parent
62ab3bd797
commit
5162f830d0
@@ -213,6 +213,10 @@ fn presets(app: &VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
|
||||
let cat = names.iter().position(|n| n.eq_ignore_ascii_case(&d.str("category"))).unwrap_or(0);
|
||||
if let Some(i) = widgets::tab_bar(ui, &names, cat) {
|
||||
d.fields.insert("category".into(), json!(names[i]));
|
||||
// A tab opens on its first preset, so the details match its cards.
|
||||
if let Some(first) = names.get(i).and_then(|c| newdoc::category(&app.session, c)).and_then(|v| v.into_iter().next()) {
|
||||
apply(d, &first);
|
||||
}
|
||||
}
|
||||
let list = names.get(cat).and_then(|c| newdoc::category(&app.session, c)).unwrap_or_default();
|
||||
ui.add_space(14.0);
|
||||
@@ -236,10 +240,15 @@ fn presets(app: &VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
|
||||
ui.spacing_mut().item_spacing = egui::vec2(12.0, 12.0);
|
||||
let (w, h, preset) = (d.f64("width", 0.0), d.f64("height", 0.0), d.str("preset"));
|
||||
for s in &list {
|
||||
// The cards show the chosen orientation (square sizes have none).
|
||||
let mut s = s.clone();
|
||||
if (w > h && s.height > s.width) || (h > w && s.width > s.height) {
|
||||
std::mem::swap(&mut s.width, &mut s.height);
|
||||
}
|
||||
let selected = d.fields.contains_key(APPLIED) && s.name == preset && s.width == w && s.height == h;
|
||||
let card = preset_card(ui, s, selected);
|
||||
let card = preset_card(ui, &s, selected);
|
||||
if card.clicked() || card.double_clicked() {
|
||||
apply(d, s);
|
||||
apply(d, &s);
|
||||
}
|
||||
create |= card.double_clicked();
|
||||
}
|
||||
@@ -391,7 +400,8 @@ fn units_dropdown(ui: &mut egui::Ui, d: &mut Dialog, width: f32) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Portrait and landscape: choosing the other one swaps width and height.
|
||||
/// Portrait and landscape: choosing the other one swaps width and height (a turned preset is still
|
||||
/// that preset).
|
||||
fn orientation(ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
let (w, h) = (d.f64("width", 612.0), d.f64("height", 792.0));
|
||||
let landscape = w > h;
|
||||
@@ -401,6 +411,13 @@ fn orientation(ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
if widgets::orientation_button(ui, is_landscape, landscape == is_landscape, tip) && landscape != is_landscape {
|
||||
d.fields.insert("width".into(), json!(h));
|
||||
d.fields.insert("height".into(), json!(w));
|
||||
if let Some(Value::Object(a)) = d.fields.get_mut(APPLIED)
|
||||
&& a.get("width") == Some(&json!(w))
|
||||
&& a.get("height") == Some(&json!(h))
|
||||
{
|
||||
a.insert("width".into(), json!(h));
|
||||
a.insert("height".into(), json!(w));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -662,6 +679,90 @@ mod tests {
|
||||
assert_eq!(app.session.documents().len(), 1);
|
||||
}
|
||||
|
||||
/// A category tab opens on its first preset, so Orientation matches its (landscape) cards, and
|
||||
/// the orientation buttons turn the cards, keeping the chosen one selected (#2084).
|
||||
#[test]
|
||||
fn the_web_tab_is_landscape_and_orientation_turns_the_cards() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.newDialog", json!({})).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let mut time = 0.0;
|
||||
let mut run = |app: &mut VectorcraftApp, events| {
|
||||
time += 0.5;
|
||||
let screen_rect = Some(egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1400.0, 1000.0)));
|
||||
let raw = egui::RawInput { screen_rect, events, time: Some(time), ..Default::default() };
|
||||
let mut out = ctx.run_ui(raw, |ui| crate::dialogs::show(app, ui.ctx()));
|
||||
out.textures_delta.clear();
|
||||
out
|
||||
};
|
||||
fn walk(s: &egui::Shape, out: &mut Vec<egui::Shape>) {
|
||||
match s {
|
||||
egui::Shape::Vec(v) => v.iter().for_each(|s| walk(s, out)),
|
||||
s => out.push(s.clone()),
|
||||
}
|
||||
}
|
||||
let shapes = |out: &egui::FullOutput| {
|
||||
let mut v = vec![];
|
||||
out.shapes.iter().for_each(|c| walk(&c.shape, &mut v));
|
||||
v
|
||||
};
|
||||
let click = |app: &mut VectorcraftApp, run: &mut dyn FnMut(&mut VectorcraftApp, Vec<egui::Event>) -> egui::FullOutput, at: egui::Pos2| {
|
||||
let press =
|
||||
|pressed| egui::Event::PointerButton { pos: at, button: egui::PointerButton::Primary, pressed, modifiers: Default::default() };
|
||||
run(app, vec![egui::Event::PointerMoved(at), press(true)]);
|
||||
run(app, vec![press(false)]);
|
||||
run(app, vec![egui::Event::PointerGone]);
|
||||
run(app, vec![])
|
||||
};
|
||||
run(&mut app, vec![]);
|
||||
let out = run(&mut app, vec![]);
|
||||
let web = shapes(&out)
|
||||
.into_iter()
|
||||
.find_map(|s| match s {
|
||||
egui::Shape::Text(t) if t.galley.text() == "Web" => Some(t.visual_bounding_rect().center()),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap();
|
||||
let out = click(&mut app, &mut run, web);
|
||||
assert_eq!(field(&app, "category"), json!("Web"));
|
||||
let (w, h) = (field(&app, "width").as_f64().unwrap(), field(&app, "height").as_f64().unwrap());
|
||||
assert!(w > h, "the Web tab reads landscape like its cards: {w}×{h} ({:?})", field(&app, "preset"));
|
||||
// The page thumbnails (white, 60 on their long side) and the selected card's outline.
|
||||
let thumbs = |out: &egui::FullOutput| -> Vec<egui::Vec2> {
|
||||
shapes(out)
|
||||
.into_iter()
|
||||
.filter_map(|s| match s {
|
||||
egui::Shape::Rect(r) if r.fill == egui::Color32::WHITE && (r.rect.width().max(r.rect.height()) - 60.0).abs() < 0.01 => {
|
||||
Some(r.rect.size())
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
let selected = |out: &egui::FullOutput| {
|
||||
shapes(out).iter().any(|s| matches!(s, egui::Shape::Rect(r) if r.stroke.width == 2.0 && r.rect.size() == egui::vec2(146.0, 150.0)))
|
||||
};
|
||||
assert!(thumbs(&out).iter().all(|s| s.x >= s.y) && selected(&out));
|
||||
// Portrait: the outlined sheet 12 wide, 16 tall.
|
||||
let portrait = shapes(&out)
|
||||
.into_iter()
|
||||
.find_map(|s| match s {
|
||||
egui::Shape::Path(p) if p.closed && p.points.len() == 5 => {
|
||||
let r = egui::Rect::from_points(&p.points);
|
||||
((r.width() - 12.0).abs() < 0.01 && (r.height() - 16.0).abs() < 0.01).then(|| r.center())
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.unwrap();
|
||||
let out = click(&mut app, &mut run, portrait);
|
||||
let (w, h) = (field(&app, "width").as_f64().unwrap(), field(&app, "height").as_f64().unwrap());
|
||||
assert!(h > w, "portrait: {w}×{h}");
|
||||
let t = thumbs(&out);
|
||||
assert!(!t.is_empty() && t.iter().all(|s| s.y >= s.x), "the cards turned: {t:?}");
|
||||
assert!(selected(&out), "the turned preset stays chosen: {:?}", field(&app, "preset"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_preset_fills_the_details_and_create_makes_the_document() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
|
||||
Reference in New Issue
Block a user