diff --git a/crates/ui-egui/src/last_color_tests.rs b/crates/ui-egui/src/last_color_tests.rs index 4a90587f..511a52c4 100644 --- a/crates/ui-egui/src/last_color_tests.rs +++ b/crates/ui-egui/src/last_color_tests.rs @@ -3,7 +3,7 @@ #![allow(clippy::unwrap_used, clippy::expect_used)] use deckcraft_engine::Session; -use deckcraft_model::{ColorBase, ColorRef, Fill, ShapeId}; +use deckcraft_model::{ColorBase, ColorRef, Fill, SchemeSlot, ShapeId}; use egui::{Event, Key, Modifiers, PointerButton}; use egui_kittest::Harness; use egui_kittest::kittest::Queryable; @@ -53,11 +53,14 @@ fn pick_hex(h: &mut Harness<'static, SlideApp>, button: &str, hex: &str) { h.run_steps(2); } h.run_steps(2); - // The ribbon has text fields of its own; the open menu hangs below them. - let lowest = |h: &Harness<'static, SlideApp>| { - h.get_all_by_role(egui::accesskit::Role::TextInput).max_by(|a, b| a.rect().min.y.total_cmp(&b.rect().min.y)).unwrap().rect().center() - }; - let field = lowest(h); + // The hex field is the text input on the "More Colors… #" label's row, to its right. + let label = h.get_by_label("More Colors… #").rect(); + let field = h + .get_all_by_role(egui::accesskit::Role::TextInput) + .filter(|n| n.rect().min.x >= label.max.x - 1.0 && (n.rect().center().y - label.center().y).abs() < 6.0) + .map(|n| n.rect().center()) + .next() + .expect("the More Colors hex field"); for pressed in [true, false] { h.input_mut().events.push(Event::PointerButton { pos: field, button: PointerButton::Primary, pressed, modifiers: Modifiers::NONE }); h.run_steps(2); @@ -87,6 +90,10 @@ fn line_rgb(h: &Harness<'static, SlideApp>, id: ShapeId) -> Option { } } +fn line_width(h: &Harness<'static, SlideApp>, id: ShapeId) -> Option { + h.state().session.active().unwrap().shape(id).unwrap().line.as_ref()?.width +} + fn fill_reapplies(tab: &str) { let (mut h, [a, b]) = harness(tab); pick_hex(&mut h, "Shape Fill", "00AA55"); @@ -107,6 +114,7 @@ fn outline_reapplies(tab: &str) { h.get_by_label("Shape Outline").click(); h.run_steps(3); assert_eq!(line_rgb(&h, b).as_deref(), Some("AA5500"), "the button applies the last colour, not Text 1"); + assert_eq!(line_width(&h, b), Some(3.0), "recolouring leaves the weight alone"); } #[test] @@ -137,6 +145,10 @@ fn before_any_pick_the_buttons_still_apply_accent_1_and_text_1() { h.get_by_label("Shape Outline").click(); h.run_steps(3); let sh = h.state().session.active().unwrap().shape(a).unwrap(); - assert!(matches!(&sh.fill, Some(Fill::Solid { color: ColorRef { base: ColorBase::Scheme { .. }, .. } }))); - assert!(sh.line.is_some()); + let slot = |f: &Option| match f { + Some(Fill::Solid { color: ColorRef { base: ColorBase::Scheme { slot }, .. } }) => Some(*slot), + _ => None, + }; + assert_eq!(slot(&sh.fill), Some(SchemeSlot::Accent1)); + assert_eq!(slot(&sh.line.as_ref().unwrap().fill), Some(SchemeSlot::Tx1)); } diff --git a/crates/ui-egui/src/ribbon.rs b/crates/ui-egui/src/ribbon.rs index 7007f674..995b9386 100644 --- a/crates/ui-egui/src/ribbon.rs +++ b/crates/ui-egui/src/ribbon.rs @@ -944,7 +944,7 @@ fn drawing_group(app: &mut SlideApp, ui: &mut Ui) { let (m, a) = small_button_ex(ui, Icon::ShapeOutline, "Shape Outline", sel, false, true); if m.clicked() { let c = app.last_outline.clone(); - run(app, "shape.line", json!({"color": c, "width": 1})); + run(app, "shape.line", json!({"color": c})); } if let Some(a) = a { widgets::color_popup(&a).show(|ui| outline_menu(app, ui, &sc)); @@ -2467,7 +2467,7 @@ fn shape_format(app: &mut SlideApp, ui: &mut Ui) { let (m, a) = small_button_ex(ui, Icon::ShapeOutline, "Shape Outline", sel, false, true); if m.clicked() { let c = app.last_outline.clone(); - run(app, "shape.line", json!({"color": c, "width": 1})); + run(app, "shape.line", json!({"color": c})); } if let Some(a) = a { widgets::color_popup(&a).show(|ui| outline_menu(app, ui, &sc)); diff --git a/docs/ui-parity.md b/docs/ui-parity.md index 96ec3935..555d231d 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -18,7 +18,6 @@ ends and are omitted from thumbnails, slide shows and exports. | Element | PowerPoint for Mac | DeckCraft | Gap | |---|---|---|---| -| 2026-10-23 | minor | Shape Fill and Shape Outline (Home and Shape Format): the button applies the last colour picked from its menu, Accent 1 and Text 1 until one is picked. Line weight and dashes, Font Color and Highlight stay as they were (#1080) | | Title bar: AutoSave, Home, Save, Undo/Redo, document title, Share, search | yes | yes, plus Export; no Share (cloud) | #71 macOS window controls misaligned | | Native macOS menu bar (File, Edit, View, Insert, Format, Arrange, Tools, Slide Show, Window, Help) | yes | **no** (`menus::menu_tree()` is defined but not installed) | 3–5 h | | Menu-bar items with a DeckCraft equivalent | 217 app-specific items | 128 matched by name (59%, heuristic lower bound) | See [target-app-parity.md](target-app-parity.md) | @@ -166,6 +165,7 @@ consistency is open (#73, #56). | Date | Change | Summary | |---|---|---| +| 2026-10-23 | minor | Shape Fill and Shape Outline (Home and Shape Format): the button applies the last colour picked from its menu, Accent 1 and Text 1 until one is picked. Line weight and dashes are not changed by the button; Font Color and Highlight stay as they were (#1080) | | 2026-10-16 | minor | Export › Change File Type › PNG and the Export… dialog offer a transparent background (#784) | | 2026-10-14 | minor | Gray list markers on empty paragraphs while editing; caret keeps the list indent before typing | | 2026-10-14 | minor | Community PR wave folded: one row each for Format Shape, Dialogs (41, listed from `dialogs.rs`), Animation Pane (timeline is in), window, Quick Access Toolbar, Format Background, rulers, image paste, context menus, exact size and edit points; estimates re-totalled (~26–46 h) |