From fdf791a8b2deadcb8206dc9bd1a80e580d3b9059 Mon Sep 17 00:00:00 2001 From: SlavenDj <53652906+SlavenDj@users.noreply.github.com> Date: Mon, 19 Oct 2026 09:05:41 +0200 Subject: [PATCH] #3045: the empty window's ribbon tabs stay live, so File reaches the Start screen (#3064) With no document open, the empty window greys the Share / Editing / Comments buttons out by disabling the whole right-to-left line, and the tab strip is a child of that line: egui gates interactions on a widget's enabled state, so every tab was dead. File did nothing, and the empty window had no way back to the Start screen, or to making a document. Only those three buttons are disabled now. The test presses Escape on the Start screen (the empty window, as #1129 has it), clicks the File tab and asserts the Start screen, with its Blank document, is back. --- crates/ui-egui/src/lib.rs | 23 +++++++++ crates/ui-egui/src/ribbon.rs | 93 +++++++++++++++++++----------------- 2 files changed, 71 insertions(+), 45 deletions(-) diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index ed4b62366..c7f687a4e 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -3004,6 +3004,29 @@ mod tests { assert!(!b.ui.backstage && b.has_document()); } + /// #3045: on the empty window (no document behind the Start screen) the ribbon is greyed + /// out, but the tab strip works: File reaches the Start screen again, where a document can + /// be made. Disabling the Share / Editing / Comments row disabled the whole line, the tab + /// strip with it: the tabs took clicks that did nothing. + #[test] + fn empty_window_ribbon_tabs_reach_the_start_screen() { + use egui_kittest::kittest::Queryable; + let mut a = app(); + a.start_screen(); + let mut h = harness(a); + h.run_steps(4); + // Esc (or the back arrow) leaves the Start screen for the empty window, as #1129 has it. + h.key_press(egui::Key::Escape); + h.run_steps(4); + assert!(!h.state().ui.backstage, "the empty window"); + assert!(!h.state().has_document(), "with no document"); + // File, the first tab, is live and reaches the Start screen. + h.get_by_label("File").click(); + h.run_steps(4); + assert!(h.state().ui.backstage && h.state().ui.backstage_page == "home", "File reaches the Start screen"); + assert!(h.query_by_label("Blank document").is_some(), "where a document can be made"); + } + /// #1908: with no document open the Home ribbon's split buttons grey out like the plain /// buttons beside them, and their drop-down arrow opens no menu. #[test] diff --git a/crates/ui-egui/src/ribbon.rs b/crates/ui-egui/src/ribbon.rs index 0b59780af..1c45f5f68 100644 --- a/crates/ui-egui/src/ribbon.rs +++ b/crates/ui-egui/src/ribbon.rs @@ -332,54 +332,57 @@ pub fn show(app: &mut WordApp, ui: &mut Ui) { .collect(); let plan = plan_strip(&specs, button_levels, ui.available_width(), MORE_TABS_W + 2.0); ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { - // No document open (#1129): nothing to share, edit or comment on. - if !app.has_document() { - ui.disable(); - } - let (share_size, share_text) = if plan.buttons < 2 { (((share_w + 36.0).max(74.0), 24.0), true) } else { ((30.0, 24.0), false) }; - let (r, resp) = ui.allocate_exact_size(vec2(share_size.0, share_size.1), Sense::click()); - ui.painter().rect_filled(r, 4.0, if resp.hovered() { t.accent_text } else { t.accent }); - let icon_x = if share_text { r.min.x + 14.0 } else { r.center().x }; - icons::paint( - ui.painter(), - Rect::from_center_size(pos2(icon_x, r.center().y), vec2(14.0, 14.0)), - "share", - t.on_accent, - t.on_accent, - ); - if share_text { - ui.painter().text(pos2(r.min.x + 26.0, r.center().y), Align2::LEFT_CENTER, share, medium(12.0), t.on_accent); - } - resp.widget_info(|| egui::WidgetInfo::labeled(egui::WidgetType::Button, true, share)); - if resp.on_hover_text(tl!("Export a copy to share (PDF, Word document)")).clicked() { - let _ = app.run("ui.backstage", json!({"value": true, "page": "export"})); - } - ui.add_space(6.0); - let track = app.session.doc.settings.track_changes; - let mode = if plan.buttons == 0 { - crate::widgets::icon_text_menu_button(ui, "pencil", editing_label, regular(12.0)) - } else { - crate::widgets::icon_only_button(ui, "pencil", editing_label, regular(12.0), true) - }; - egui::Popup::menu(&mode).show(|ui| { - if ui.selectable_label(!track, tl!(tl!("Editing — edit the document directly"))).clicked() { - let _ = app.run("review.trackChanges", json!({"value": false})); - ui.close(); + // No document open (#1129): nothing to share, edit or comment on — but only + // these buttons. Disabling the whole line took the tab strip with it: the + // tabs took clicks that did nothing, so the empty window had no way back to + // the Start screen (#3045). + ui.add_enabled_ui(app.has_document(), |ui| { + let (share_size, share_text) = + if plan.buttons < 2 { (((share_w + 36.0).max(74.0), 24.0), true) } else { ((30.0, 24.0), false) }; + let (r, resp) = ui.allocate_exact_size(vec2(share_size.0, share_size.1), Sense::click()); + ui.painter().rect_filled(r, 4.0, if resp.hovered() { t.accent_text } else { t.accent }); + let icon_x = if share_text { r.min.x + 14.0 } else { r.center().x }; + icons::paint( + ui.painter(), + Rect::from_center_size(pos2(icon_x, r.center().y), vec2(14.0, 14.0)), + "share", + t.on_accent, + t.on_accent, + ); + if share_text { + ui.painter().text(pos2(r.min.x + 26.0, r.center().y), Align2::LEFT_CENTER, share, medium(12.0), t.on_accent); } - if ui.selectable_label(track, tl!(tl!("Reviewing — edits become suggestions"))).clicked() { - let _ = app.run("review.trackChanges", json!({"value": true})); - ui.close(); + resp.widget_info(|| egui::WidgetInfo::labeled(egui::WidgetType::Button, true, share)); + if resp.on_hover_text(tl!("Export a copy to share (PDF, Word document)")).clicked() { + let _ = app.run("ui.backstage", json!({"value": true, "page": "export"})); + } + ui.add_space(6.0); + let track = app.session.doc.settings.track_changes; + let mode = if plan.buttons == 0 { + crate::widgets::icon_text_menu_button(ui, "pencil", editing_label, regular(12.0)) + } else { + crate::widgets::icon_only_button(ui, "pencil", editing_label, regular(12.0), true) + }; + egui::Popup::menu(&mode).show(|ui| { + if ui.selectable_label(!track, tl!(tl!("Editing — edit the document directly"))).clicked() { + let _ = app.run("review.trackChanges", json!({"value": false})); + ui.close(); + } + if ui.selectable_label(track, tl!(tl!("Reviewing — edits become suggestions"))).clicked() { + let _ = app.run("review.trackChanges", json!({"value": true})); + ui.close(); + } + }); + ui.add_space(4.0); + let comments_button = if plan.buttons == 0 { + crate::widgets::icon_text_button(ui, "comment", comments, regular(12.0)) + } else { + crate::widgets::icon_only_button(ui, "comment", comments, regular(12.0), false) + }; + if comments_button.clicked() { + let _ = app.run("view.commentsPane", json!({})); } }); - ui.add_space(4.0); - let comments_button = if plan.buttons == 0 { - crate::widgets::icon_text_button(ui, "comment", comments, regular(12.0)) - } else { - crate::widgets::icon_only_button(ui, "comment", comments, regular(12.0), false) - }; - if comments_button.clicked() { - let _ = app.run("view.commentsPane", json!({})); - } ui.add_space(8.0); ui.with_layout(egui::Layout::left_to_right(egui::Align::Center), |ui| { // The tabs that don't fit go into a » menu at the end of the strip (#897, #2026).