mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-31 21:27:00 -06:00
Merge pull request #4561 from adambelis/fork/feat/control-bar-distribute
feat: show six Distribute Objects buttons in Control bar when 2+ objects selected (Illustrator parity)
This commit is contained in:
@@ -244,6 +244,12 @@ pub fn control_bar(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
return;
|
||||
}
|
||||
crate::panels::align::align_buttons(app, ui, 24.0);
|
||||
// Two or more objects get the six Distribute Objects buttons too; a single
|
||||
// object keeps the bar as it was.
|
||||
if sel.len() > 1 {
|
||||
ui.add_space(4.0);
|
||||
crate::panels::align::distribute_buttons(app, ui, 24.0);
|
||||
}
|
||||
ui.separator();
|
||||
// The Transform link opens the whole Transform panel (reference point, rotate,
|
||||
// shear, options) in a popover; X/Y/W/H follow inline while the bar has room.
|
||||
|
||||
@@ -1633,3 +1633,56 @@ fn full_screen_modes_fill_the_screen_and_normal_mode_restores_the_window() {
|
||||
app.ui.screen_mode = 0;
|
||||
assert!(sent(&mut app, true).is_empty(), "still full screen, as the user had it");
|
||||
}
|
||||
|
||||
/// Two or more selected objects show all six Distribute Objects buttons in the Control bar;
|
||||
/// a single object keeps the bar as it was. A click distributes as the Align panel's button does.
|
||||
#[test]
|
||||
fn the_control_bar_shows_the_distribute_buttons_for_two_or_more_objects() {
|
||||
crate::i18n::set_current(crate::i18n::Lang::EN);
|
||||
let mut app = crate::VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 400, "height": 200})).unwrap();
|
||||
let rect = |app: &mut crate::VectorcraftApp, x: f64| {
|
||||
app.run("shape.rectangle", json!({"x": x, "y": 10, "width": 30, "height": 20})).unwrap()["id"].clone()
|
||||
};
|
||||
let (a, b, c) = (rect(&mut app, 10.0), rect(&mut app, 100.0), rect(&mut app, 200.0));
|
||||
let ctx = egui::Context::default();
|
||||
ctx.enable_accesskit();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let screen = egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1600.0, 300.0));
|
||||
let frame = |app: &mut crate::VectorcraftApp, events: Vec<egui::Event>| {
|
||||
let mut out = ctx.run_ui(egui::RawInput { events, screen_rect: Some(screen), ..Default::default() }, |ui| super::control_bar(app, ui));
|
||||
out.textures_delta.clear();
|
||||
out.platform_output.accesskit_update.map(|u| u.nodes).unwrap_or_default()
|
||||
};
|
||||
const DISTRIBUTE: [&str; 6] = [
|
||||
"Vertical Distribute Top",
|
||||
"Vertical Distribute Center",
|
||||
"Vertical Distribute Bottom",
|
||||
"Horizontal Distribute Left",
|
||||
"Horizontal Distribute Center",
|
||||
"Horizontal Distribute Right",
|
||||
];
|
||||
let rects = |app: &mut crate::VectorcraftApp| {
|
||||
frame(app, vec![]);
|
||||
let nodes = frame(app, vec![]);
|
||||
DISTRIBUTE.map(|name| {
|
||||
let n = nodes.iter().find(|(_, n)| n.label() == Some(name)).map(|(_, n)| n)?;
|
||||
n.bounds().map(|b| egui::Rect::from_min_max(egui::pos2(b.x0 as f32, b.y0 as f32), egui::pos2(b.x1 as f32, b.y1 as f32)))
|
||||
})
|
||||
};
|
||||
app.run("select.set", json!({"ids": [a]})).unwrap();
|
||||
assert!(rects(&mut app).iter().all(Option::is_none), "one object: no distribute buttons");
|
||||
app.run("select.set", json!({"ids": [a, b, c]})).unwrap();
|
||||
let rects = rects(&mut app);
|
||||
assert!(rects.iter().all(Option::is_some), "three objects: {rects:?}");
|
||||
let r = rects[3].expect("Horizontal Distribute Left");
|
||||
let press =
|
||||
|pressed| egui::Event::PointerButton { pos: r.center(), button: egui::PointerButton::Primary, pressed, modifiers: Default::default() };
|
||||
for events in [vec![egui::Event::PointerMoved(r.center()), press(true)], vec![press(false)]] {
|
||||
frame(&mut app, events);
|
||||
}
|
||||
let left = |app: &crate::VectorcraftApp, id: &serde_json::Value| {
|
||||
app.session.active().unwrap().doc.node(vectorcraft_doc::NodeId(id.as_u64().unwrap())).unwrap().geometric_bounds().unwrap().x0
|
||||
};
|
||||
assert_eq!((left(&app, &a), left(&app, &b), left(&app, &c)), (10.0, 105.0, 200.0), "{}", app.ui.status);
|
||||
}
|
||||
|
||||
@@ -192,6 +192,16 @@ pub fn align_buttons(app: &mut VectorcraftApp, ui: &mut Ui, size: f32) {
|
||||
}
|
||||
}
|
||||
|
||||
/// The six Distribute Objects buttons of the Control bar, `size` points square. They distribute
|
||||
/// what the Align panel's buttons do, to what its Align To says.
|
||||
pub(crate) fn distribute_buttons(app: &mut VectorcraftApp, ui: &mut Ui, size: f32) {
|
||||
for (icon, tip, axis, v) in DISTRIBUTE {
|
||||
if widgets::icon_button(ui, icon, tl!(tip), false, size).clicked() {
|
||||
run_button(app, Button::Distribute(axis, v)).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the selection has a key object or a key guide.
|
||||
fn has_key(app: &VectorcraftApp) -> bool {
|
||||
app.session.active().is_some_and(|st| st.selection.has_key())
|
||||
|
||||
Reference in New Issue
Block a user