Fix #789: every align button aligns to the Align To choice

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 <noreply@anthropic.com>
This commit is contained in:
bflatastic
2026-10-10 10:27:54 +07:00
co-authored by Claude Opus 5.5
parent 79c81d754c
commit 82dc5f8182
12 changed files with 65 additions and 32 deletions
+1 -17
View File
@@ -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.
+1
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -1639,6 +1639,7 @@
Monochrome images モノクロイメージ
More 多く
More Pathfinder options その他のパスファインダーオプション
More Align options その他の整列オプション
More Settings その他の設定
Move 移動
Move Anchors アンカーポイントを移動
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -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
Can't render this file because it contains an unexpected character in line 6 and column 47.
+1
View File
@@ -1495,6 +1495,7 @@
Monospaced Моноширинный
More Больше
More Pathfinder options Дополнительные параметры обработки контуров
More Align options Дополнительные параметры выравнивания
More Settings Дополнительные настройки
Move Переместить
Move All Objects Переместить все объекты
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -1491,6 +1491,7 @@
Monospaced Моноширинний
More Більше
More Pathfinder options Додаткові параметри обробки контурів
More Align options Додаткові параметри вирівнювання
More Settings Додаткові налаштування
Move Перемістити
Move All Objects Перемістити всі об’єкти
Can't render this file because it contains an unexpected character in line 632 and column 40.
+1
View File
@@ -1455,6 +1455,7 @@
Monochrome images 单色图像
More 较多
More Pathfinder options 更多路径查找器选项
More Align options 更多对齐选项
More Settings 更多设置
Move 移动
Move All Objects 移动所有对象
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -1497,6 +1497,7 @@
Monospaced 等寬
More 更多
More Pathfinder options 更多路徑管理員選項
More Align options 更多對齊選項
More Settings 更多設定
Move 移動
Move All Objects 移動所有物件
Can't render this file because it contains an unexpected character in line 6 and column 47.
+51
View File
@@ -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<egui::Event>| {
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");
}
}
+4 -15
View File
@@ -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 {