From 7aa456407b5b772faa62dd9729265f7d598107e4 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 8 Oct 2026 18:39:00 +0000 Subject: [PATCH] Context menu: trailing check mark, faded icons on disabled rows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Checked rows (Properties, grip Stretch/Copy) drew a leading "✓ " that pushed their label out of line with the other rows. The check mark now sits in the trailing column where submenu headers draw their caret. Disabled Undo/Redo rows had grey text but full-strength icons: themed_disabled faded the icon through the SVG tint colour's alpha, which iced ignores (the tint only replaces RGB). Fade via the widget's opacity instead, which fixes every themed_disabled icon. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KeV3kCDBWCrpYaJEs8CRQU --- src/app/view/overlay.rs | 27 ++++++++++++++++++--------- src/ui/icons.rs | 7 +++++-- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/app/view/overlay.rs b/src/app/view/overlay.rs index bf61cc394..10d7afe5f 100644 --- a/src/app/view/overlay.rs +++ b/src/app/view/overlay.rs @@ -1127,6 +1127,8 @@ const MENU_CURSOR_INSET_X: f32 = 24.0; /// not the row carries a glyph (object snaps, command icons). const MENU_GUTTER_W: f32 = 18.0; const MENU_ICON_SIZE: f32 = 14.0; +/// Trailing check mark of checked rows; sits in the submenu caret column. +const MENU_CHECK_SIZE: f32 = 10.0; /// The gutter cell: the row's glyph, faded with a disabled row, or empty /// space of the same width. @@ -1264,16 +1266,13 @@ pub(super) fn viewport_context_menu_overlay( position_canvas_overlay_clamped(pos, bottom_inset, offset, panel.into()) } -/// One menu row: label (bold for the default row, "✓ "-prefixed when -/// checked), and the keyword hint right-aligned and dimmed. Disabled rows -/// render without a press handler and with faded text. +/// One menu row: label (bold for the default row), the keyword hint +/// right-aligned and dimmed, and a check mark in the trailing column (where +/// submenu headers draw their caret) when checked, so checked labels stay +/// aligned with the others. Disabled rows render without a press handler and +/// with faded text and icons. fn context_menu_row(item: &MenuItem, indent: f32, highlighted: bool) -> Element<'static, Message> { - let label = if item.checked { - format!("✓ {}", item.label) - } else { - item.label.clone() - }; - let mut label_text = text(label).size(12); + let mut label_text = text(item.label.clone()).size(12); if item.default { label_text = label_text.font(iced::Font { weight: iced::font::Weight::Bold, @@ -1303,6 +1302,16 @@ fn context_menu_row(item: &MenuItem, indent: f32, highlighted: bool) -> Element< }), ); } + if item.checked { + if item.hint.is_none() { + content = content.push(iced::widget::Space::new().width(Fill)); + } + content = content.push(if enabled { + crate::ui::icons::themed(crate::ui::icons::CHECK, MENU_CHECK_SIZE) + } else { + crate::ui::icons::themed_disabled(crate::ui::icons::CHECK, MENU_CHECK_SIZE) + }); + } let mut btn = button(content) .padding(iced::Padding { top: 3.0, diff --git a/src/ui/icons.rs b/src/ui/icons.rs index 694b98a07..eaf0c2f41 100644 --- a/src/ui/icons.rs +++ b/src/ui/icons.rs @@ -509,13 +509,16 @@ pub fn themed_secondary<'a, M: 'a>(bytes: &'static [u8], size: f32) -> Element<' .into() } -/// Render disabled chrome with the active Iced theme's text color. +/// Render disabled chrome with the active Iced theme's text color, faded +/// like disabled text. The fade goes through the widget's opacity: an SVG +/// tint only replaces RGB, so alpha on the style colour would be ignored. pub fn themed_disabled<'a, M: 'a>(bytes: &'static [u8], size: f32) -> Element<'a, M> { svg(themed_handle(bytes)) .width(size) .height(size) + .opacity(0.42_f32) .style(|theme: &Theme, _| svg::Style { - color: Some(theme.palette().background.base.text.scale_alpha(0.42)), + color: Some(theme.palette().background.base.text), }) .into() }