diff --git a/ASSETS.md b/ASSETS.md
index bf15723ac..1003a0e02 100644
--- a/ASSETS.md
+++ b/ASSETS.md
@@ -83,6 +83,7 @@ Generated-in-code art is original and has no file to list. This covers the defau
| `assets/icons/copy.svg` | Lucide Icons and Contributors | https://lucide.dev (lucide-static v1.49.0; header kept in file) | ISC (`assets/icons/LICENSE-lucide.txt`) | |
| `assets/icons/dc-actions.svg` | VectorCraft contributors | Original work, drawn for VectorCraft | MIT OR Apache-2.0 | |
| `assets/icons/dc-al-bottom.svg` | VectorCraft contributors | Original work, drawn for VectorCraft | MIT OR Apache-2.0 | |
+| `assets/icons/dc-al-center.svg` | VectorCraft contributors | Original work, drawn for VectorCraft | MIT OR Apache-2.0 | |
| `assets/icons/dc-al-hcenter.svg` | VectorCraft contributors | Original work, drawn for VectorCraft | MIT OR Apache-2.0 | |
| `assets/icons/dc-al-left.svg` | VectorCraft contributors | Original work, drawn for VectorCraft | MIT OR Apache-2.0 | |
| `assets/icons/dc-al-right.svg` | VectorCraft contributors | Original work, drawn for VectorCraft | MIT OR Apache-2.0 | |
diff --git a/assets/icons/dc-al-center.svg b/assets/icons/dc-al-center.svg
new file mode 100644
index 000000000..2e8e9e978
--- /dev/null
+++ b/assets/icons/dc-al-center.svg
@@ -0,0 +1 @@
+
diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs
index 8071a7edd..6a66ad1ab 100644
--- a/crates/engine/src/tests.rs
+++ b/crates/engine/src/tests.rs
@@ -506,6 +506,19 @@ fn align_to_artboard_uses_the_artboard_named() {
assert_eq!(x0(&s, c), boards[0].x0, "off every artboard: the first");
}
+#[test]
+fn align_both_centers() {
+ let mut s = session();
+ let a = rect(&mut s, 0.0, 0.0, 100.0, 100.0);
+ let b = rect(&mut s, 20.0, 40.0, 20.0, 20.0);
+ s.execute("select.set", &json!({"ids": [a.0, b.0]})).unwrap();
+ s.execute("object.align", &json!({"horizontal": "center", "vertical": "center"})).unwrap();
+ let gb_a = s.doc().unwrap().doc.node(a).unwrap().geometric_bounds().unwrap();
+ let gb_b = s.doc().unwrap().doc.node(b).unwrap().geometric_bounds().unwrap();
+ assert!((gb_a.center().x - gb_b.center().x).abs() < 1e-6);
+ assert!((gb_a.center().y - gb_b.center().y).abs() < 1e-6);
+}
+
/// #541: with the Selection tool, a click on one object of the selection makes it the key object:
/// aligning to the key moves the others to it, Distribute Spacing spaces them from it, and a click
/// on the key again lets it go.
diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv
index 4b081573a..0028e1b96 100644
--- a/crates/ui-egui/src/i18n/cs.tsv
+++ b/crates/ui-egui/src/i18n/cs.tsv
@@ -133,6 +133,7 @@
Horizontal Align Right Vodorovně zarovnat doprava
Vertical Align Top Svisle zarovnat nahoru
Vertical Align Center Svisle zarovnat na střed
+ Horizontal & Vertical Align Center Vodorovně a svisle zarovnat na střed
Vertical Align Bottom Svisle zarovnat dolů
Group Seskupit
Ungroup Oddělit
diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv
index b5eff51c8..ed0e6e6b7 100644
--- a/crates/ui-egui/src/i18n/de.tsv
+++ b/crates/ui-egui/src/i18n/de.tsv
@@ -3037,6 +3037,7 @@ effect Points Punkte
Vertical % Vertikal %
Vertical Align Bottom Vertikal unten ausrichten
Vertical Align Center Vertikal zentriert ausrichten
+ Horizontal & Vertical Align Center Horizontal und vertikal zentriert ausrichten
Vertical Align Top Vertikal oben ausrichten
Vertical Area Type Tool Vertikaler-Flächentext-Werkzeug
Vertical Distribute Bottom Vertikal unten verteilen
diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv
index 709155b3a..ef53c9455 100644
--- a/crates/ui-egui/src/i18n/es.tsv
+++ b/crates/ui-egui/src/i18n/es.tsv
@@ -3137,6 +3137,7 @@
Vertical % % vertical
Vertical Align Bottom Alinear abajo verticalmente
Vertical Align Center Alinear centros verticalmente
+ Horizontal & Vertical Align Center Alinear centros horizontal y verticalmente
Vertical Align Top Alinear arriba verticalmente
Vertical Area Type Tool Herramienta Texto de área vertical
Vertical Distribute Bottom Distribuir abajo verticalmente
diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv
index 304db7db5..facbc9465 100644
--- a/crates/ui-egui/src/i18n/fr.tsv
+++ b/crates/ui-egui/src/i18n/fr.tsv
@@ -3134,6 +3134,7 @@
Vertical % % vertical
Vertical Align Bottom Alignement vertical en bas
Vertical Align Center Alignement vertical au centre
+ Horizontal & Vertical Align Center Alignement centré horizontal et vertical
Vertical Align Top Alignement vertical en haut
Vertical Area Type Tool Outil Texte captif vertical
Vertical Distribute Bottom Répartition verticale en bas
diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv
index d897e5446..2b9111282 100644
--- a/crates/ui-egui/src/i18n/it.tsv
+++ b/crates/ui-egui/src/i18n/it.tsv
@@ -3137,6 +3137,7 @@
Vertical % % verticale
Vertical Align Bottom Allinea verticalmente in basso
Vertical Align Center Allinea verticalmente al centro
+ Horizontal & Vertical Align Center Allinea centri orizzontalmente e verticalmente
Vertical Align Top Allinea verticalmente in alto
Vertical Area Type Tool Strumento Testo in area verticale
Vertical Distribute Bottom Distribuisci verticalmente i bordi inferiori
diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv
index 601504ce5..7657db854 100644
--- a/crates/ui-egui/src/i18n/ja.tsv
+++ b/crates/ui-egui/src/i18n/ja.tsv
@@ -173,6 +173,7 @@
Horizontal Align Right 水平方向右に整列
Vertical Align Top 垂直方向上に整列
Vertical Align Center 垂直方向中央に整列
+ Horizontal & Vertical Align Center 水平方向および垂直方向中央に整列
Vertical Align Bottom 垂直方向下に整列
Group グループ
Ungroup グループ解除
diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv
index 40eb16d53..1312a8ea4 100644
--- a/crates/ui-egui/src/i18n/pt-br.tsv
+++ b/crates/ui-egui/src/i18n/pt-br.tsv
@@ -2566,6 +2566,7 @@
Vertical Vertical
Vertical Align Bottom Alinhar Inferior Verticalmente
Vertical Align Center Alinhar Centro Verticalmente
+ Horizontal & Vertical Align Center Alinhar Centro Horizontal e Verticalmente
Vertical Align Top Alinhar Superior Verticalmente
Vertical Area Type Tool Ferramenta Texto Vertical de Área
Vertical Distribute Space Distribuir Espaço Verticalmente
diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv
index 1c39b1954..db352d378 100644
--- a/crates/ui-egui/src/i18n/ru.tsv
+++ b/crates/ui-egui/src/i18n/ru.tsv
@@ -3133,6 +3133,7 @@
Vertical % По вертикали, %
Vertical Align Bottom Выровнять по нижнему краю по вертикали
Vertical Align Center Выровнять по центру по вертикали
+ Horizontal & Vertical Align Center Выровнять по центру по горизонтали и вертикали
Vertical Align Top Выровнять по верхнему краю по вертикали
Vertical Area Type Tool Инструмент «Вертикальный текст в области»
Vertical Distribute Bottom Распределить по нижнему краю по вертикали
diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv
index 1cc41bcbc..ff91b1c00 100644
--- a/crates/ui-egui/src/i18n/uk.tsv
+++ b/crates/ui-egui/src/i18n/uk.tsv
@@ -3130,6 +3130,7 @@ effect Points Точки
Vertical % По вертикалі, %
Vertical Align Bottom Вирівняти по нижньому краю по вертикалі
Vertical Align Center Вирівняти по центру по вертикалі
+ Horizontal & Vertical Align Center Вирівняти по центру по горизонталі й вертикалі
Vertical Align Top Вирівняти по верхньому краю по вертикалі
Vertical Area Type Tool Інструмент «Вертикальний текст в області»
Vertical Distribute Bottom Розподілити по нижньому краю по вертикалі
diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv
index 84bbf15ba..13f8093fd 100644
--- a/crates/ui-egui/src/i18n/zh-hans.tsv
+++ b/crates/ui-egui/src/i18n/zh-hans.tsv
@@ -3028,6 +3028,7 @@
Vertical % 垂直 %
Vertical Align Bottom 垂直底对齐
Vertical Align Center 垂直居中对齐
+ Horizontal & Vertical Align Center 水平和垂直居中对齐
Vertical Align Top 垂直顶对齐
Vertical Area Type Tool 直排区域文字工具
Vertical Distribute Bottom 垂直分布下缘
diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv
index adf8089ba..bde581475 100644
--- a/crates/ui-egui/src/i18n/zh-hant.tsv
+++ b/crates/ui-egui/src/i18n/zh-hant.tsv
@@ -3121,6 +3121,7 @@
Vertical % 垂直 %
Vertical Align Bottom 垂直靠下對齊
Vertical Align Center 垂直置中對齊
+ Horizontal & Vertical Align Center 水平和垂直置中對齊
Vertical Align Top 垂直靠上對齊
Vertical Area Type Tool 垂直區域文字工具
Vertical Distribute Bottom 垂直均分下緣
diff --git a/crates/ui-egui/src/icon_data.rs b/crates/ui-egui/src/icon_data.rs
index f2a97a7c2..016b47227 100644
--- a/crates/ui-egui/src/icon_data.rs
+++ b/crates/ui-egui/src/icon_data.rs
@@ -31,6 +31,7 @@ pub static ICONS: &[(&str, &[u8])] = &[
("copy", include_bytes!("../../../assets/icons/copy.svg")),
("dc-actions", include_bytes!("../../../assets/icons/dc-actions.svg")),
("dc-al-bottom", include_bytes!("../../../assets/icons/dc-al-bottom.svg")),
+ ("dc-al-center", include_bytes!("../../../assets/icons/dc-al-center.svg")),
("dc-al-hcenter", include_bytes!("../../../assets/icons/dc-al-hcenter.svg")),
("dc-al-left", include_bytes!("../../../assets/icons/dc-al-left.svg")),
("dc-al-right", include_bytes!("../../../assets/icons/dc-al-right.svg")),
diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs
index 6bf171aec..2072d292b 100644
--- a/crates/ui-egui/src/menus.rs
+++ b/crates/ui-egui/src/menus.rs
@@ -2151,6 +2151,9 @@ pub fn menu_tree_named(english_names: bool) -> Vec<(&'static str, Vec- )> {
cp("Horizontal Align Left", "object.align", json!({"horizontal": "left"})),
cp("Horizontal Align Center", "object.align", json!({"horizontal": "center"})),
cp("Horizontal Align Right", "object.align", json!({"horizontal": "right"})),
+ Sep,
+ cp("Horizontal & Vertical Align Center", "object.align", json!({"horizontal": "center", "vertical": "center"})),
+ Sep,
cp("Vertical Align Top", "object.align", json!({"vertical": "top"})),
cp("Vertical Align Center", "object.align", json!({"vertical": "center"})),
cp("Vertical Align Bottom", "object.align", json!({"vertical": "bottom"})),
diff --git a/crates/ui-egui/src/panels/align.rs b/crates/ui-egui/src/panels/align.rs
index 40b9d23a4..a24f191f1 100644
--- a/crates/ui-egui/src/panels/align.rs
+++ b/crates/ui-egui/src/panels/align.rs
@@ -58,14 +58,20 @@ pub const DISTRIBUTE: [(&str, &str, &str, &str); 6] = [
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 [
+ for (i, (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"),
- ] {
+ ]
+ .into_iter()
+ .enumerate()
+ {
+ if i == 3 && widgets::icon_button(ui, "dc-al-center", tl!("Horizontal & Vertical Align Center"), false, size).clicked() {
+ app.run("object.align", align_params(json!({"horizontal": "center", "vertical": "center"}), to, n)).ok();
+ }
if widgets::icon_button(ui, icon, tl!(tip), false, size).clicked() {
app.run("object.align", align_params(json!({axis: v}), to, n)).ok();
}
@@ -98,6 +104,10 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
for (i, (icon, tip, axis, v)) in ALIGN.iter().enumerate() {
if i == 3 {
ui.add_space(6.0);
+ if widgets::icon_button_enabled(ui, "dc-al-center", tl!("Horizontal & Vertical Align Center"), false, n >= 1, 32.0).clicked() {
+ app.run("object.align", align_params(json!({"horizontal": "center", "vertical": "center"}), to, n)).ok();
+ }
+ ui.add_space(6.0);
}
if widgets::icon_button_enabled(ui, icon, tl!(tip), false, n >= 1, 32.0).clicked() {
app.run("object.align", align_params(json!({*axis: v}), to, n)).ok();
@@ -247,6 +257,14 @@ mod tests {
assert_eq!(bounds(&app).x0, 0.0, "the artboard's left edge");
}
+ #[test]
+ fn align_both_centers_params() {
+ let p = align_params(json!({"horizontal": "center", "vertical": "center"}), AlignTo::Selection, 2);
+ assert_eq!(p["horizontal"], "center");
+ assert_eq!(p["vertical"], "center");
+ assert_eq!(p["to"], "selection");
+ }
+
/// #541: while the selection has a key object Align aligns to it, whatever Align To says;
/// choosing Align to Selection lets the key go.
#[test]