Layout › Arrange › Group stays on while a group is selected, so Ungroup is reachable (#4229) (#4440)

Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
Lucien
2026-10-29 22:34:01 -04:00
committed by GitHub
co-authored by Brandon Thomas
parent 41d5284fa8
commit 4a12ab9a19
3 changed files with 38 additions and 1 deletions
+8 -1
View File
@@ -90,9 +90,16 @@ pub(super) fn rotation_field(ui: &mut Ui, app: &mut WordApp) {
}
}
/// The command the Group menu button follows: Ungroup while a group is selected (Group is off
/// then, as one object has nothing to group), Group otherwise (#4229).
pub(super) fn group_menu_command(app: &WordApp) -> &'static str {
if crate::widgets::enabled(app, "arrange.ungroup") { "arrange.ungroup" } else { "arrange.group" }
}
/// Arrange › Group: Group (Shift+click objects to select several) and Ungroup.
pub(super) fn group_menu(ui: &mut Ui, app: &mut WordApp, label: Option<&str>) {
menu_button(ui, app, crate::widgets::MenuButtonOptions::new("group", label, "Group", false, "arrange.group"), |ui, app| {
let id = group_menu_command(app);
menu_button(ui, app, crate::widgets::MenuButtonOptions::new("group", label, "Group", false, id), |ui, app| {
mi(ui, app, "Group", "arrange.group", json!({}));
mi(ui, app, "Ungroup", "arrange.ungroup", json!({}));
});
+29
View File
@@ -1,3 +1,4 @@
use super::arrange::group_menu_command;
use super::*;
use wordcraft_engine::Session;
@@ -117,6 +118,34 @@ fn menu_buttons_follow_their_command() {
}
}
/// #4229: with a group selected the Group button stays on, so Ungroup in its menu can be
/// reached; with nothing selected it is off, and with two objects it offers Group.
#[test]
fn the_group_menu_stays_on_for_a_selected_group() {
use crate::widgets::{enabled, menu_enabled};
let mut a = crate::WordApp::new(
Session::new(wordcraft_doc::Document::from_text(
"one
two
three",
)),
crate::Services::default(),
);
assert!(!menu_enabled(&a, group_menu_command(&a)), "nothing selected");
a.run("insert.shape", json!({"kind": "rectangle", "width": 80, "height": 40})).unwrap();
a.run("arrange.bounds", json!({"page": 0, "x": 100, "y": 150})).unwrap();
a.run("select.collapse", json!({"end": true})).unwrap();
a.run("insert.shape", json!({"kind": "ellipse", "width": 80, "height": 40})).unwrap();
a.run("arrange.bounds", json!({"page": 0, "x": 300, "y": 150})).unwrap();
a.run("select.addObject", json!({"index": 0})).unwrap();
assert_eq!(group_menu_command(&a), "arrange.group");
assert!(menu_enabled(&a, group_menu_command(&a)), "two objects to group");
a.run("arrange.group", json!({})).unwrap();
assert!(!enabled(&a, "arrange.group"), "one group: nothing to group");
assert_eq!(group_menu_command(&a), "arrange.ungroup");
assert!(menu_enabled(&a, group_menu_command(&a)), "the menu reaches Ungroup");
}
/// #1206: Margins, Orientation, Size and Columns mark the caret section's setting, as Word
/// does. Every value differs from a new document's, so a default can't satisfy it.
#[test]
+1
View File
@@ -88,6 +88,7 @@ Labels → New Document with “One label per recipient” includes all filtered
| 2026-10-29 | trivial | Window sizing uses the screen rectangle when the inner rectangle is missing, empty or not finite; an Equation symbol tooltip shows a missing glyph's linear name or code point once instead of twice |
| 2026-10-29 | trivial | Displayed document titles and suggested file names omit NUL characters (X11 panicked on them) and use the localized untitled name when nothing remains (#3634) |
| 2026-10-29 | trivial | Recipient labels continue across product-sized sheets instead of stopping after the first sheet (#4880). Filtered/sorted order, product geometry and single-label mode retained; readiness estimates unchanged. |
| 2026-10-26 | trivial | Layout › Arrange › Group stays on while a group is selected, so Ungroup in its menu can be reached; it was greyed out because one object has nothing to group (#4229) |
| 2026-10-22 | trivial | View › Window › New Window opens another window on the document, focused and cascaded; two windows on one document are titled `Name:1` and `Name:2` (one window: the plain name). Each window keeps its own selection, scroll position, zoom, view mode, ruler and panes; the text, undo history, unsaved state and file are the document's, so an edit or Undo in either window shows in both, and a caret in text the other window deleted moves to the nearest place left. Closing one of a document's windows asks nothing; closing its last asks about unsaved changes, and quitting asks once per document. Switch Windows lists every window. The web app keeps one window |
| 2026-10-22 | trivial | One native window per open document on the desktop (the web app keeps one window): New and Open open the document in a window of its own, focused and cascaded from the last; Open replaces an untouched blank document in its window and brings an already-open file's window forward; each window keeps its own ribbon tab, File page, dialogs, panes and composition; View › Window › Switch Windows lists the windows and brings the chosen one forward; File › Close and the window's close button close the window (asking about unsaved changes) and the window focused before comes forward, while the last window stays open with no document; quitting asks Save / Don't Save / Cancel about each document in its own window |
| 2026-10-22 | trivial | Several open documents in one window (one window per document comes next): View › Window › Switch Windows lists the open documents, the shown one marked and unsaved ones dotted, and shows the one chosen, with its own scroll position, zoom, comment drafts and AutoSave file; File › New, Open, Envelopes, Labels, Finish & Merge and personal templates open beside the open documents without asking about unsaved changes; File › Close shows the next open document; the window's close button asks Save / Don't Save / Cancel about each document with unsaved changes, showing it, and Cancel keeps the app open. Untitled documents are numbered (Document2) in the interface language |