From 82dc5f8182ed16ceb28a977c83c6a7f11b31d2e1 Mon Sep 17 00:00:00 2001 From: bflatastic Date: Sat, 10 Oct 2026 07:03:51 +0700 Subject: [PATCH] Fix #789: every align button aligns to the Align To choice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Align to Key Object and Align to Artboard worked only from the Align panel's own buttons: the Control bar's and the Properties panel's align buttons always aligned to the selection (one object to the artboard). They are now one set of buttons that follow Align To (and the key object), and the Properties panel's Align section gets the "…" button that opens the Align panel for Distribute and Align To. Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/chrome.rs | 18 +-------- crates/ui-egui/src/i18n/es.tsv | 1 + crates/ui-egui/src/i18n/fr.tsv | 1 + crates/ui-egui/src/i18n/it.tsv | 1 + crates/ui-egui/src/i18n/ja.tsv | 1 + crates/ui-egui/src/i18n/pt-br.tsv | 1 + crates/ui-egui/src/i18n/ru.tsv | 1 + crates/ui-egui/src/i18n/uk.tsv | 1 + crates/ui-egui/src/i18n/zh-hans.tsv | 1 + crates/ui-egui/src/i18n/zh-hant.tsv | 1 + crates/ui-egui/src/panels/align.rs | 51 +++++++++++++++++++++++++ crates/ui-egui/src/panels/properties.rs | 19 ++------- 12 files changed, 65 insertions(+), 32 deletions(-) diff --git a/crates/ui-egui/src/chrome.rs b/crates/ui-egui/src/chrome.rs index 00467ab2d..0176f97ef 100644 --- a/crates/ui-egui/src/chrome.rs +++ b/crates/ui-egui/src/chrome.rs @@ -265,23 +265,7 @@ pub fn control_bar(app: &mut VectorcraftApp, ui: &mut Ui) { } return; } - // Align buttons. - for (icon, tip, p) in [ - ("align-start-vertical", "Horizontal Align Left", json!({"horizontal": "left"})), - ("align-center-vertical", "Horizontal Align Center", json!({"horizontal": "center"})), - ("align-end-vertical", "Horizontal Align Right", json!({"horizontal": "right"})), - ("align-start-horizontal", "Vertical Align Top", json!({"vertical": "top"})), - ("align-center-horizontal", "Vertical Align Center", json!({"vertical": "center"})), - ("align-end-horizontal", "Vertical Align Bottom", json!({"vertical": "bottom"})), - ] { - if widgets::icon_button(ui, icon, tl!(tip), false, 24.0).clicked() { - let mut p = p; - if sel.len() == 1 { - p["to"] = json!("artboard"); - } - app.run("object.align", p).ok(); - } - } + crate::panels::align::align_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. diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 8476f913b..209992946 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -1497,6 +1497,7 @@ Monospaced Monoespaciada More Más More Pathfinder options Más opciones de Buscatrazos + More Align options Más opciones de alineación More Settings Más ajustes Move Mover Move All Objects Mover todos los objetos diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index b82601222..ab47b7f47 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -1496,6 +1496,7 @@ Monospaced À chasse fixe More Plus More Pathfinder options Plus d’options Pathfinder + More Align options Plus d’options d’alignement More Settings Plus de réglages Move Déplacer Move All Objects Déplacer tous les objets diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index aa5edeb5a..e23a10f54 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -1497,6 +1497,7 @@ Monospaced Monospaziato More Altro More Pathfinder options Altre opzioni di Elaborazione tracciati + More Align options Altre opzioni di allineamento More Settings Altre impostazioni Move Sposta Move All Objects Sposta tutti gli oggetti diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 80e8c16bc..75df70579 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -1639,6 +1639,7 @@ Monochrome images モノクロイメージ More 多く More Pathfinder options その他のパスファインダーオプション + More Align options その他の整列オプション More Settings その他の設定 Move 移動 Move Anchors アンカーポイントを移動 diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index e2e03f23e..09b12d794 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -1313,6 +1313,7 @@ Monochrome images Imagens monocromáticas More Mais More Pathfinder options Mais opções de Localizador de Caminhos + More Align options Mais opções de alinhamento More Settings Mais Configurações Move Mover Move Anchors Mover Âncoras diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index a3ebf7d47..504b52a97 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -1495,6 +1495,7 @@ Monospaced Моноширинный More Больше More Pathfinder options Дополнительные параметры обработки контуров + More Align options Дополнительные параметры выравнивания More Settings Дополнительные настройки Move Переместить Move All Objects Переместить все объекты diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index cb6f3a116..0f19a210c 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -1491,6 +1491,7 @@ Monospaced Моноширинний More Більше More Pathfinder options Додаткові параметри обробки контурів + More Align options Додаткові параметри вирівнювання More Settings Додаткові налаштування Move Перемістити Move All Objects Перемістити всі об’єкти diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index de889f02f..03119810c 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -1455,6 +1455,7 @@ Monochrome images 单色图像 More 较多 More Pathfinder options 更多路径查找器选项 + More Align options 更多对齐选项 More Settings 更多设置 Move 移动 Move All Objects 移动所有对象 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index f4dc6efc3..7aabf1416 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -1497,6 +1497,7 @@ Monospaced 等寬 More 更多 More Pathfinder options 更多路徑管理員選項 + More Align options 更多對齊選項 More Settings 更多設定 Move 移動 Move All Objects 移動所有物件 diff --git a/crates/ui-egui/src/panels/align.rs b/crates/ui-egui/src/panels/align.rs index 5aa6619ad..6c9c9e767 100644 --- a/crates/ui-egui/src/panels/align.rs +++ b/crates/ui-egui/src/panels/align.rs @@ -52,6 +52,26 @@ pub const DISTRIBUTE: [(&str, &str, &str, &str); 6] = [ ("dc-dist-right", "Horizontal Distribute Right", "horizontal", "right"), ]; +/// The six align buttons of the Control bar and the Properties panel, `size` points square. +/// They align to what the Align panel's Align To says (the key object while there is one), as +/// its own buttons do (#789). +pub fn align_buttons(app: &mut VectorcraftApp, ui: &mut Ui, size: f32) { + let n = selection_len(app); + let to = align_to(app, ui.ctx()); + for (icon, tip, axis, v) in [ + ("align-start-vertical", "Horizontal Align Left", "horizontal", "left"), + ("align-center-vertical", "Horizontal Align Center", "horizontal", "center"), + ("align-end-vertical", "Horizontal Align Right", "horizontal", "right"), + ("align-start-horizontal", "Vertical Align Top", "vertical", "top"), + ("align-center-horizontal", "Vertical Align Center", "vertical", "center"), + ("align-end-horizontal", "Vertical Align Bottom", "vertical", "bottom"), + ] { + if widgets::icon_button(ui, icon, tl!(tip), false, size).clicked() { + app.run("object.align", align_params(json!({axis: v}), to, n)).ok(); + } + } +} + /// Whether the selection has a key object. fn has_key(app: &VectorcraftApp) -> bool { app.session.active().is_some_and(|st| st.selection.key.is_some()) @@ -183,4 +203,35 @@ mod tests { app.run("select.key", json!({})).unwrap(); assert_eq!(align_to(&app, &ctx), AlignTo::Selection, "no key: the choice again"); } + + /// #789: the Control bar's and the Properties panel's align buttons follow Align To too. + #[test] + fn the_other_align_buttons_align_to_the_align_to_choice() { + let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default()); + app.run("file.new", json!({"width": 200, "height": 200})).unwrap(); + let a = app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 10, "height": 10})).unwrap()["id"].clone(); + let b = app.run("shape.rectangle", json!({"x": 80, "y": 50, "width": 30, "height": 30})).unwrap()["id"].clone(); + app.run("select.set", json!({"ids": [a, b]})).unwrap(); + let ctx = egui::Context::default(); + set_pstate(&ctx, "align-to", AlignTo::Artboard); + // One frame finds the first button (Horizontal Align Right is third); the next clicks it. + let at = std::cell::Cell::new(egui::Pos2::ZERO); + let frame = |app: &mut VectorcraftApp, events: Vec| { + let mut out = ctx.run_ui(egui::RawInput { events, ..Default::default() }, |ui| { + ui.horizontal(|ui| { + at.set(ui.cursor().min); + align_buttons(app, ui, 24.0); + }); + }); + out.textures_delta.clear(); + }; + frame(&mut app, vec![]); + let right = at.get() + egui::vec2(2.0 * (24.0 + ctx.global_style().spacing.item_spacing.x) + 12.0, 12.0); + let press = |pressed| egui::Event::PointerButton { pos: right, button: egui::PointerButton::Primary, pressed, modifiers: Default::default() }; + frame(&mut app, vec![egui::Event::PointerMoved(right), press(true)]); + frame(&mut app, vec![press(false)]); + let st = app.session.active().unwrap(); + let x1 = |id: &serde_json::Value| st.doc.bounds_of(&[vectorcraft_doc::NodeId(id.as_u64().unwrap())], false).unwrap().x1; + assert_eq!((x1(&a), x1(&b)), (200.0, 200.0), "both to the artboard's right edge"); + } } diff --git a/crates/ui-egui/src/panels/properties.rs b/crates/ui-egui/src/panels/properties.rs index ea27ebc80..88a636ae7 100644 --- a/crates/ui-egui/src/panels/properties.rs +++ b/crates/ui-egui/src/panels/properties.rs @@ -57,21 +57,10 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { divider(ui); section_header(ui, tl!("Align")); ui.horizontal(|ui| { - for (icon, tip, p) in [ - ("align-start-vertical", tl!("Horizontal Align Left"), json!({"horizontal": "left"})), - ("align-center-vertical", tl!("Horizontal Align Center"), json!({"horizontal": "center"})), - ("align-end-vertical", tl!("Horizontal Align Right"), json!({"horizontal": "right"})), - ("align-start-horizontal", tl!("Vertical Align Top"), json!({"vertical": "top"})), - ("align-center-horizontal", tl!("Vertical Align Center"), json!({"vertical": "center"})), - ("align-end-horizontal", tl!("Vertical Align Bottom"), json!({"vertical": "bottom"})), - ] { - if widgets::icon_button(ui, icon, tip, false, 26.0).clicked() { - let mut p = p; - if n_sel == 1 { - p["to"] = json!("artboard"); - } - app.run("object.align", p).ok(); - } + super::align::align_buttons(app, ui, 26.0); + // The rest (Distribute Objects, Distribute Spacing, Align To) is the Align panel's. + if widgets::icon_button(ui, "ellipsis", tl!("More Align options"), false, 26.0).clicked() { + app.ui.open_panel = Some("align".into()); } }); if n_sel > 1 {