mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Merge pull request #3167 from sungjea713/assets-tab-scrolls-to-checked
Export for Screens: the Assets tab scrolls to the assets it opens on
This commit is contained in:
@@ -133,6 +133,10 @@ pub(crate) fn open_assets(app: &mut VectorcraftApp, checked: Option<&[u64]>) {
|
||||
d.fields.insert("tab".into(), json!("assets"));
|
||||
if let Some(c) = checked {
|
||||
d.fields.insert("assets".into(), json!(c));
|
||||
// The list scrolls to the first of them once: new assets land at its end.
|
||||
if let Some(first) = c.first() {
|
||||
d.fields.insert("__scrollTo".into(), json!(first));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -544,9 +548,12 @@ fn assets(app: &VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
on.clear();
|
||||
}
|
||||
});
|
||||
// Asked for until the row is in view: the dialog's first frame only measures it.
|
||||
let scroll_to = d.fields.get("__scrollTo").and_then(Value::as_u64).filter(|id| st.doc.assets.iter().any(|a| a.id == *id));
|
||||
let mut in_view = scroll_to.is_none();
|
||||
egui::ScrollArea::vertical().max_height(330.0).show(ui, |ui| {
|
||||
for a in &st.doc.assets {
|
||||
ui.horizontal(|ui| {
|
||||
let row = ui.horizontal(|ui| {
|
||||
let (r, _) = ui.allocate_exact_size(egui::vec2(46.0, 46.0), egui::Sense::hover());
|
||||
crate::panels::asset_export::paint_thumb(ui, st, a, r);
|
||||
let checked = on.contains(&a.id);
|
||||
@@ -557,8 +564,18 @@ fn assets(app: &VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
}
|
||||
}
|
||||
});
|
||||
if scroll_to == Some(a.id) {
|
||||
if ui.clip_rect().contains_rect(row.response.rect) {
|
||||
in_view = true;
|
||||
} else {
|
||||
row.response.scroll_to_me(Some(egui::Align::Center));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if in_view {
|
||||
d.fields.remove("__scrollTo");
|
||||
}
|
||||
if on != before {
|
||||
d.fields.insert("assets".into(), json!(on));
|
||||
}
|
||||
|
||||
@@ -145,3 +145,38 @@ fn the_menus_reach_asset_export() {
|
||||
app.run("assets.add", json!({"multiple": false})).unwrap();
|
||||
assert_eq!(assets(&mut app).len(), 1);
|
||||
}
|
||||
|
||||
/// The Assets tab opened on new assets scrolls its list to the first checked one, once: they land
|
||||
/// at the end of a long list.
|
||||
#[test]
|
||||
fn the_assets_tab_scrolls_to_the_new_asset() {
|
||||
let (mut app, _, ids) = app(true);
|
||||
for i in 0..30 {
|
||||
let id = app.run("shape.rectangle", json!({"x": 5 * i, "y": 50, "width": 4, "height": 4})).unwrap()["id"].clone();
|
||||
app.run("assets.add", json!({"ids": [id]})).unwrap();
|
||||
}
|
||||
app.run("select.set", json!({"ids": ids})).unwrap();
|
||||
let r = app.run("file.exportSelection", json!({"multiple": false})).unwrap();
|
||||
let new = r["assets"][0].clone();
|
||||
assert_eq!(assets(&mut app).len(), 31);
|
||||
assert_eq!(assets(&mut app).last().unwrap()["id"], new);
|
||||
assert_eq!(field(&app, "__scrollTo"), new);
|
||||
let name = assets(&mut app).last().unwrap()["name"].as_str().unwrap().to_string();
|
||||
// The rows below the list's visible part are painted but clipped away: the new one is inside
|
||||
// its clip once the frame after the opening one has scrolled.
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let mut shown = false;
|
||||
// Scrolling is animated: a second of frames lets it land.
|
||||
for i in 0..60 {
|
||||
let input = egui::RawInput { time: Some(f64::from(i) / 60.0), ..egui::RawInput::default() };
|
||||
let mut out = ctx.run_ui(input, |ui| super::show(&mut app, ui.ctx()));
|
||||
out.textures_delta.clear();
|
||||
shown = out.shapes.iter().any(|c| match &c.shape {
|
||||
egui::Shape::Text(t) => t.galley.text() == name && c.clip_rect.contains_rect(t.visual_bounding_rect()),
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
assert!(shown, "{name} is clipped out of the list");
|
||||
assert_eq!(field(&app, "__scrollTo"), Value::Null, "scrolled once");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user