diff --git a/crates/ui-egui/src/popover.rs b/crates/ui-egui/src/popover.rs index d91558d46..82886227d 100644 --- a/crates/ui-egui/src/popover.rs +++ b/crates/ui-egui/src/popover.rs @@ -262,13 +262,13 @@ fn header_text(t: Tokens, dark: bool) -> Color32 { if dark { t.menu_text } else { t.text } } -/// The X: a 24-point button, its icon inset 6 (the colour picker's header). +/// The X: a 24-point button, its cross 16 points like every 24 pt icon button (the colour picker's header). fn close_button(ui: &mut Ui, id: Id, rect: Rect, dark: bool, t: Tokens) -> bool { let resp = ui.interact(rect, id, Sense::click()).tip(tr("Close")); if resp.hovered() { ui.painter().rect_filled(rect, CornerRadius::same(5), if dark { Color32::from_white_alpha(20) } else { t.hover }); } - icons::paint(ui.painter(), rect.shrink(6.0), Icon::Close, if dark { t.menu_text } else { t.icon }); + icons::paint(ui.painter(), crate::widgets::icon_glyph_rect(rect), Icon::Close, if dark { t.menu_text } else { t.icon }); resp.clicked() } diff --git a/crates/ui-egui/src/popover_tests.rs b/crates/ui-egui/src/popover_tests.rs index 06daca851..6c4e559ee 100644 --- a/crates/ui-egui/src/popover_tests.rs +++ b/crates/ui-egui/src/popover_tests.rs @@ -194,3 +194,24 @@ fn a_caller_can_put_it_where_it_likes() { draw(&ctx, &mut t, &mut p, at, Hold::default(), vec![]); assert!(near(p.rect.min, pos2(360.0, 300.0)), "dropped where the drag left it: {:?}", p.rect); } + +mod icon_size_tests { + use super::*; + use crate::header_icon_size_tests::paints_icon_at_button_size; + use crate::icons::Icon; + + /// The header's 24 pt X paints its cross at 16 pt, like every other 24 pt icon button (#2238). + #[test] + fn the_close_button_paints_a_16pt_cross() { + let ctx = context(); + let mut t = 0.0; + let mut p = Popover::new("popover_close_size", "Colour"); + let shapes = settle(&ctx, &mut t, &mut p, Open::At(pos2(160.0, 100.0))); + let painted: Vec = shapes + .iter() + .filter(|s| matches!(s, egui::Shape::Path(_) | egui::Shape::Mesh(_) | egui::Shape::LineSegment { .. } | egui::Shape::Circle(_))) + .map(|s| s.visual_bounding_rect()) + .collect(); + assert!(paints_icon_at_button_size(&painted, Icon::Close), "the popover's close cross is not 16 pt"); + } +} diff --git a/crates/ui-egui/src/widgets/style_picker.rs b/crates/ui-egui/src/widgets/style_picker.rs index 57e045a06..ca063abad 100644 --- a/crates/ui-egui/src/widgets/style_picker.rs +++ b/crates/ui-egui/src/widgets/style_picker.rs @@ -303,7 +303,11 @@ fn menu_icon(ui: &mut Ui, rect: Rect, icon: Icon, tip: &str, on: bool) -> Respon if on || resp.hovered() { ui.painter().rect_filled(rect, CornerRadius::same(5), t.menu_hover); } - let glyph = if rect.size() == vec2(24.0, 24.0) { crate::widgets::icon_glyph_rect(rect) } else { rect.shrink(5.0) }; + let glyph = if (rect.width() - 24.0).abs() < 0.5 && (rect.height() - 24.0).abs() < 0.5 { + crate::widgets::icon_glyph_rect(rect) + } else { + rect.shrink(5.0) + }; icons::paint(ui.painter(), glyph, icon, t.menu_text); resp } diff --git a/docs/ui-parity.md b/docs/ui-parity.md index 0c9f44d4c..524d64f03 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -241,7 +241,7 @@ This audit records candidates for subsequent fixes; their behaviour is unchanged | 2026-11-06 | patch | M7, #2032: closing a tab whose file has unsaved changes, by its X, a middle click, File ▸ Close tab or its shortcut, only showed a toast ("save first, or close again with Alt to discard") and left the tab open, so closing seemed not to work. It now asks the unsaved-changes question the window asks (`windows::TabClose`): Don't Save closes the tab, Cancel or Escape keeps it, Save saves the file and then closes it (a file without a path, or saved as .fig, asks where with Save as first and stays open if that is cancelled); Alt+close still drops the changes at once, and `file.close`'s `dialog.unsaved` request asks too. The three toasts left the catalogs. Tests: `titlebar_tests::closing_a_tab_with_unsaved_changes_asks`, `titlebar_tests::save_in_the_tab_question_saves_then_closes`. Reordering tabs by dragging, the issue's other half, landed on 2026-10-19 (`dragging_a_tab_along_the_bar_reorders_it_without_detaching`) | | 2026-11-05 | minor | M4, #1830: a paragraph's base direction can be forced (`TextDirection`: Auto, Ltr, Rtl on `ParaList`): Text ▸ Text direction ▸ Auto / Left to right / Right to left (`text.directionAuto` / `Ltr` / `Rtl`) and `text.direction {direction, ids?}` set the edited paragraphs while editing, else the layer's; `node.set textDirection`; the Type settings control once a right-to-left script is in the text; inspect `textDirection` / `lineDirections`; CSS `direction`; `.fig` lines' `sourceDirectionality` in and out. Layout gives each paragraph its base level (`Bidi::of` runs the algorithm per paragraph, as it starts over at each). Before, direction came from the letters only ("controls are available to override text direction per paragraph", Add right-to-left text). Tests: `text_behaviour_tests::text_direction_is_forced_per_paragraph`, `fig::text_direction_tests::a_lines_source_directionality_is_its_paragraphs_direction_both_ways`. | | 2026-11-02 | minor | M1, #1836: pick select. Tab while the keyboard selection box shows, or Alt/Ctrl+Space again, puts a pink outline on the first selected layer (the page's top layer with nothing selected); Tab and Shift+Tab move it between sibling layers as the Layers panel lists them, Enter into a frame's top child, Shift+Enter out to the parent (never the page), Space selects the layer under it, Escape or a press on the canvas ends it; the chord again while the pick cursor shows brings the box back (Accessibility at Figma). The control channel's `ui.key` sends the box's and the pick cursor's keys to them too. One documented row more (135, 134 bound); four gesture rows. Tests: `layers_keyboard_tests::tab_switches_the_selection_box_to_pick_select`. | -| 2026-11-12 | patch | M8, #2238: every 24 pt icon button outside the Design panel draws its glyph at 16 pt through `widgets::icon_glyph_rect`, not 14 pt: the Layers panel's Minimize, search and add page buttons, the Assets back button, the Versions panel's row menus, the Dev Mode status button, the Prototype panel's flow buttons, the preview pane's bar buttons, Home's Online row menus and the style picker's 24 pt buttons. Smaller buttons (the picker's 22 and 20 pt ones, the popover's 24 pt close button with its 12 pt cross) keep their smaller glyphs. Tests: `icon_button_size_tests` and the `icon_size_tests` beside the panels. Numbers unchanged. | +| 2026-11-12 | patch | M8, #2238: every 24 pt icon button outside the Design panel draws its glyph at 16 pt through `widgets::icon_glyph_rect`, not 14 pt: the Layers panel's Minimize, search and add page buttons, the Assets back button, the Versions panel's row menus, the Dev Mode status button, the Prototype panel's flow buttons, the preview pane's bar buttons, Home's Online row menus and the style picker's 24 pt buttons. The popover's 24 pt close button draws its cross at 16 pt too. Smaller buttons (the picker's 22 and 20 pt ones) keep their smaller glyphs. Tests: `icon_button_size_tests` and the `icon_size_tests` beside the panels. Numbers unchanged. | | 2026-11-10 | patch | M10, #2227: the Design panel's section header buttons (Appearance, Typography, Fill, Stroke, Effects) draw their icons at the size of the panel's other 24 pt icon buttons, 16 pt (the icons' native size, as a fill row's eye), not 12 pt; `icon_button_at` goes from 14 to 16 pt with them; the Close and Swap buttons of the assets and prototype panels and the Design panel's Swap orientation and quick-action buttons share the inset. Test: `header_icon_size_tests`. Numbers unchanged. | | 2026-11-05 | patch | M1, #2003: the Design panel's boolean operation menu leads Union, Subtract, Intersect and Exclude with original icons drawn in code (two offset squares, the result filled at reduced alpha). Numbers unchanged. | | 2026-11-02 | minor | M8, #1875: a fill per region. With regions of a vector selected in edit mode (a press inside one with the Move tool, `vector.edit.select {regions}`), the Fill section lists the regions' own fills (the layer's for a region that has none; mixed content when they differ) and its rows and the colour picker edit them: `fill.set`, `fill.add`, `fill.remove`, `fill.move` and `fill.paste` on the edited layer go to the selected regions' stacks (`Region.fills`, what the renderer already draws), the layer's fills and fill style untouched; `regions: [index, ...]` names them on any vector layer (Edit vector layers). Tests: `regions_tests::the_fill_commands_edit_the_selected_regions`. Numbers unchanged. |