Merge pull request #3339 from dotCooCoo/fix/artboards-panel-convert-to-artboards

Artboards: the panel menu's Convert to Artboards converts the selected objects
This commit is contained in:
BFlat
2026-10-21 16:15:42 +07:00
committed by GitHub
2 changed files with 50 additions and 1 deletions
+49 -1
View File
@@ -472,7 +472,9 @@ pub fn menu(app: &mut VectorcraftApp, ui: &mut Ui) {
}
menu_item(ui, tl!("Delete Empty Artboards"), false, false);
ui.separator();
menu_item(ui, tl!("Convert to Artboards"), false, false);
if menu_item(ui, tl!("Convert to Artboards"), crate::menus::enabled(app, "artboard.convertToArtboards"), false) {
crate::menus::invoke(app, "artboard.convertToArtboards", json!({}));
}
if menu_item(ui, tl!("Artboard Options…"), n > 0, false) {
app.run("tool.options", json!({ "tool": "artboard" })).ok();
}
@@ -869,6 +871,52 @@ mod tests {
assert_eq!((d.artboards.len(), d.layers[0].children().unwrap().len()), (3, 2), "one undo step");
}
/// The panel menu's Convert to Artboards turns the geometric bounds of each selected rectangle
/// into a new artboard and removes the rectangles, in one undo step, as Object › Artboards ›
/// Convert to Artboards does; with nothing selected it is off.
#[test]
fn the_panel_menus_convert_to_artboards_converts_the_selected_objects() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.session.execute("file.new", &json!({"width": 200, "height": 150})).unwrap();
for x in [10, 60] {
app.session.execute("shape.rectangle", &json!({"x": x, "y": 10, "width": 20, "height": 30})).unwrap();
}
let ctx = egui::Context::default();
let screen = Some(egui::Rect::from_min_size(egui::Pos2::ZERO, vec2(240.0, 400.0)));
let frame = |app: &mut VectorcraftApp, events: Vec<egui::Event>| {
let mut out = ctx.run_ui(egui::RawInput { events, screen_rect: screen, ..Default::default() }, |ui| menu(app, ui));
out.textures_delta.clear();
out.shapes
};
let item = frame(&mut app, vec![])
.iter()
.find_map(|c| match &c.shape {
egui::Shape::Text(t) if t.galley.text().trim_start() == "Convert to Artboards" => Some(t.visual_bounding_rect().center()),
_ => None,
})
.unwrap();
let button = |pressed| egui::Event::PointerButton { pos: item, button: egui::PointerButton::Primary, pressed, modifiers: Default::default() };
let click = |app: &mut VectorcraftApp| frame(app, vec![egui::Event::PointerMoved(item), button(true), button(false)]);
let boards = |app: &VectorcraftApp| app.session.active().unwrap().doc.artboards.iter().map(|a| a.rect).collect::<Vec<_>>();
let first = boards(&app)[0];
app.session.execute("select.none", &json!({})).unwrap();
frame(&mut app, vec![]);
click(&mut app);
// An enabled item would run the command, and its refusal would show in the status bar.
assert_eq!((boards(&app), app.ui.status.as_str()), (vec![first], ""), "off with nothing selected");
app.session.execute("select.all", &json!({})).unwrap();
// Draw one frame with the item enabled, as the app redraws the panel after the selection changes.
frame(&mut app, vec![]);
click(&mut app);
let rect = vectorcraft_geom::Rect::new;
assert_eq!(boards(&app), [first, rect(10.0, 10.0, 30.0, 40.0), rect(60.0, 10.0, 80.0, 40.0)]);
let d = app.session.active().unwrap();
assert_eq!((d.doc.layers[0].children().unwrap().len(), d.selection.objects.len()), (0, 0), "the rectangles are removed");
app.run("edit.undo", json!({})).unwrap();
let d = &app.session.active().unwrap().doc;
assert_eq!((d.artboards.len(), d.layers[0].children().unwrap().len()), (1, 2), "one undo step");
}
/// One headless frame of the Control bar, 2,000 points wide, with `events` → the texts painted,
/// with their rects.
fn bar_frame(app: &mut VectorcraftApp, ctx: &egui::Context, events: Vec<egui::Event>) -> Vec<(String, egui::Rect)> {
+1
View File
@@ -609,6 +609,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
Object › Artboards › Fit to Selected Art resizes the active artboard (`artboard.fitToSelection {index}`). It used to resize artboard 1 whichever artboard was active. When an action plays, its Fit to Artwork Bounds and Fit to Selected Art steps that name no artboard resize the artboard that is active then.
Object › Artboards › Fit to Artwork Bounds and the Artboards panel menu's Fit to Artwork Bounds fit each selected artboard (those the Artboard tool has selected, else the active one) to the art on it, as the public [Use the artboard context menu](https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/organize-manage-artboards/use-artboard-context-menu.html) page describes (`artboard.fitToArt {indices}`). An object partly on an artboard counts for each artboard it overlaps, and an artboard with no art on it keeps its size and place. They used to fit the active artboard to all the art in the document.
The Artboards panel menu's Duplicate Artboards copies each selected artboard (those the Artboard tool has selected, else the active one) with its art, in one undo step, and the copies are then selected, as the public [Use the artboard context menu](https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/organize-manage-artboards/use-artboard-context-menu.html) page describes. With the Artboard tool, Copy and Cut take every selected artboard with its art, as the public [Cut, copy, and paste artboards](https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/organize-manage-artboards/cut-copy-and-paste-artboards.html) page describes, and Paste brings them all back in one undo step (`artboard.duplicate`, `artboard.copy` and `artboard.cut` with `indices`). The copies keep their places relative to each other, together right of the last artboard. All three used to act on the active artboard only.
The Artboards panel menu's Convert to Artboards turns the geometric bounds of each selected object that has an area into a new artboard and removes those objects, in one undo step, as Object › Artboards › Convert to Artboards does (`artboard.convertToArtboards`). It is disabled when nothing is selected. It used to be disabled always.
The canvas draws the active artboard's edge in black, as the public [Select artboards](https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/add-edit-artboards/select-artboards.html) page describes. It draws the other artboards' edges in gray. With several artboards selected by the Artboard tool, the canvas draws the black edge around the active one, which the tool shows with handles and its name. It used to draw artboard 1's edge in black whichever artboard was active.
View › Rotate View turns the view to the status bar's preset angles (`view.rotate {angle}`, which takes any angle). View › Rotate View to Selection turns the view to the angle of the selected objects' bounding box, so the box is square to the window (`view.rotateToSelection`).
When the view angle changes (a Rotate View drag, the status bar's angle menu, Reset Rotate View or a saved view) and the desktop app renders the frame at the new angle on the render worker, the canvas draws the last frame turned to the new angle until that frame is ready. It used to draw no art until then.