Align opens a menu with Left, Center and Right, not just center (#3242)

The Picture Format / Shape Format Align button ran arrange.align with
no value, which defaults to "center" — there was no way to reach Left
or Right from the ribbon short of dragging the object manually. It now
opens a menu, like Word's own Align dropdown.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Michael
2026-10-20 16:14:32 +08:00
co-authored by Claude Sonnet 5
parent 9b4b948c6e
commit 0a93c0edd4
+39 -3
View File
@@ -1730,7 +1730,7 @@ fn layout(app: &mut WordApp, ui: &mut Ui) {
small(ui, app, "selectionPane", Some("Selection Pane"), "Selection Pane", "arrange.selectionPane", json!({}), false);
});
stack(ui, |ui| {
small(ui, app, "align", None, "Align", "arrange.align", json!({}), false);
align_menu(ui, app, None);
group_menu(ui, app, None);
rotate_menu(ui, app, None);
});
@@ -1802,6 +1802,16 @@ fn group_menu(ui: &mut Ui, app: &mut WordApp, label: Option<&str>) {
});
}
/// Arrange › Align: horizontal position relative to the margin (#3242 — a plain button ran
/// `arrange.align` with no `value`, which always centers; a menu reaches Left and Right too).
fn align_menu(ui: &mut Ui, app: &mut WordApp, label: Option<&str>) {
menu_button(ui, app, "align", label, "Align", false, "arrange.align", |ui, app| {
mi(ui, app, "Align Left", "arrange.align", json!({"value": "left"}));
mi(ui, app, "Align Center", "arrange.align", json!({"value": "center"}));
mi(ui, app, "Align Right", "arrange.align", json!({"value": "right"}));
});
}
fn references(app: &mut WordApp, ui: &mut Ui) {
group(ui, "Table of Contents", None, app, |ui, app| {
menu_button(ui, app, "toc", Some("Table of\nContents"), "Table of Contents", true, "references.toc", |ui, app| {
@@ -2418,7 +2428,7 @@ fn shape_format(app: &mut WordApp, ui: &mut Ui) {
wrap_menu(ui, app);
stack(ui, |ui| {
rotate_menu(ui, app, Some("Rotate"));
small(ui, app, "align", Some("Align"), "Align", "arrange.align", json!({}), false);
align_menu(ui, app, Some("Align"));
});
});
group(ui, "Size", None, app, |ui, app| {
@@ -2594,7 +2604,7 @@ fn picture_format(app: &mut WordApp, ui: &mut Ui) {
wrap_menu(ui, app);
stack(ui, |ui| {
rotate_menu(ui, app, Some("Rotate"));
small(ui, app, "align", Some("Align"), "Align", "arrange.align", json!({}), false);
align_menu(ui, app, Some("Align"));
group_menu(ui, app, Some("Group"));
});
});
@@ -3400,6 +3410,32 @@ mod tests {
assert_eq!(h.state().session.undo_depth(), undo, "no undo step");
}
/// #3242: Align used to run `arrange.align` directly with no `value`, which always centers
/// (`crates/engine/src/cmd/objects.rs`) — there was no way to reach Left or Right from the
/// ribbon short of dragging. Align now opens a menu, like Word's own Align dropdown.
#[test]
fn align_menu_reaches_left_and_right_not_just_center() {
use egui_kittest::kittest::{By, Queryable};
let item = |label: &'static str| By::new().label_contains(label);
let mut a = crate::WordApp::new(Session::new(wordcraft_doc::Document::new()), crate::Services::default());
a.run("insert.picture", json!({"data": png_data()})).unwrap();
let frame =
|a: &crate::WordApp| wordcraft_engine::cmd::objects::selected(&a.session).and_then(|(_, o)| o.frame().map(|(_, _, f)| (f.wrap, f.x)));
assert!(matches!(frame(&a), Some((wordcraft_doc::para::Wrap::Inline, _))), "a freshly inserted picture is inline");
let mut h = egui_kittest::Harness::builder()
.with_size(egui::vec2(300.0, 300.0))
.build_ui_state(|ui, app: &mut crate::WordApp| align_menu(ui, app, None), a);
h.run();
h.get(item("Align")).click();
h.run();
assert!(h.query(item("Align Left")).is_some(), "Align opens a menu, instead of running arrange.align with no value");
h.get(item("Align Right")).click();
h.run();
let (wrap, x) = frame(h.state()).unwrap();
assert_eq!(wrap, wordcraft_doc::para::Wrap::Square, "aligning floats an inline picture, as arrange.align already does");
assert!(x > 0.0, "Align Right moved it right of the left margin, not centered under it: x={x}");
}
/// #2573 review: Shape Format and Chart Design leave sizes outside their fields' ranges alone
/// too (a 0.5 pt high line; a chart narrower than 36 pt), as Picture Format does.
#[test]