Ribbon key tips: Alt shows codes on tabs, buttons and menu items

A lone Alt shows a code on every ribbon tab and quick-access button.
Typing a tab code opens the tab and shows the codes of its buttons,
dropdowns, slide-outs and collapsed panels; a button code runs it, a
dropdown or slide-out code opens it and shows its item codes, Esc goes
back one level. Codes follow the reference ribbon; buttons without a
reference counterpart get none and unnamed menu items are numbered.

Codes are drawn as accent pills over the widgets that reported their
bounds in the current frame, with a hint bar under the ribbon. While
the tips are open keys go to them only. The automation gets a keytips
action and read operation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-10-14 11:18:58 +03:00
1 parent 592289f4fd
commit 86429bf439
34 files changed
+1569 -53

No files matched your search

+49 -15
View File
@@ -9,7 +9,7 @@ use super::widgets::{
make_icon, make_tip, muted_text_style, popup_panel_style, popup_row_style, tip_style,
tool_btn_style, LARGE_DROPDOWN_ARROW_SIZE,
};
use super::{dropdown_backdrop, position_ribbon_dropdown, Ribbon};
use super::{dropdown_backdrop, keytips, position_ribbon_dropdown, Ribbon};
use crate::app::Message;
use crate::modules::IconKind;
use crate::t;
@@ -248,6 +248,32 @@ fn panel_for_group(title: &str, group_ids: &[&'static str]) -> Option<Panel> {
})
}
/// The slide-out under the group `title`, if it has one.
pub(super) fn slide_out_id(title: &str, group_ids: &[&'static str]) -> Option<&'static str> {
panel_for_group(title, group_ids).map(|panel| panel.id)
}
/// What the open slide-out or tool submenu `id` offers, as (dropdown id,
/// command, opens a submenu) in display order.
pub(super) fn keytip_items(id: &str) -> Vec<(&'static str, &'static str, bool)> {
let Some(panel) = panel_for_dropdown(id) else {
return Vec::new();
};
if panel.id == id {
return panel
.tools
.iter()
.map(|tool| (panel.id, tool.command, !tool.options.is_empty()))
.collect();
}
panel
.tools
.iter()
.filter(|tool| tool.command == id)
.flat_map(|tool| tool.options.iter().map(|(cmd, _)| (tool.command, *cmd, false)))
.collect()
}
/// Every command the slide-out of the group `title` offers: each tool and
/// each of its submenu options.
pub(super) fn slide_out_commands(
@@ -337,6 +363,7 @@ pub(super) fn group_title<'a>(
.delay(Duration::from_millis(400))
.style(tip_style);
// Shrink-sized: a Fill here would make the panel claim the whole row.
let launcher = keytips::anchor(keytips::XREF_LAUNCHER, launcher);
row![title_button, launcher]
.spacing(6)
.align_y(iced::Center)
@@ -362,6 +389,7 @@ fn tool_button(tool: &Tool, active: bool, panel_id: &'static str) -> Element<'st
.delay(Duration::from_millis(400))
.style(tip_style)
.into();
let face = keytips::anchor_with(|| keytips::item_anchor(panel_id, tool.command), face);
if !tool.options.is_empty() {
row![
face,
@@ -401,6 +429,7 @@ fn reference_overlay<'a>(ribbon: &Ribbon, panel: Panel, win: (f32, f32)) -> Elem
.style(popup_row_style)
.width(Fill)
.padding([3, 6]);
let edit = keytips::anchor_with(|| keytips::item_anchor(panel.id, tool.command), edit);
let fade = ribbon.xref_fade;
let on = fade > 0;
let switch = button(make_icon(
@@ -411,18 +440,23 @@ fn reference_overlay<'a>(ribbon: &Ribbon, panel: Panel, win: (f32, f32)) -> Elem
.style(move |theme: &Theme, status| tool_btn_style(theme, on, status))
.padding(3);
let amount = fade.unsigned_abs().min(90) as u8;
let switch = tooltip(
switch,
make_tip(format!(
"{}\n{} XDWGFADECTL",
t!("Xref fading"),
t!("Command:")
)),
tooltip::Position::Bottom,
)
.delay(Duration::from_millis(400))
.style(tip_style);
let switch = keytips::anchor_with(
|| keytips::item_anchor(panel.id, keytips::XREF_FADE),
switch,
);
let fading = row![
tooltip(
switch,
make_tip(format!(
"{}\n{} XDWGFADECTL",
t!("Xref fading"),
t!("Command:")
)),
tooltip::Position::Bottom
)
.delay(Duration::from_millis(400))
.style(tip_style),
switch,
text(t!("Xref fading")).size(11),
iced::widget::slider(0..=90u8, amount, Message::XrefFadeSlide)
.on_release(Message::XrefFadeCommit)
@@ -468,7 +502,7 @@ pub(super) fn overlay<'a>(ribbon: &Ribbon, id: &str, win: (f32, f32)) -> Element
tool.options
.iter()
.map(|&(cmd, label)| {
button(text(t!(label)).size(11))
let item = button(text(t!(label)).size(11))
.on_press(Message::DropdownSelectItem {
dropdown_id: tool.command,
cmd,
@@ -476,8 +510,8 @@ pub(super) fn overlay<'a>(ribbon: &Ribbon, id: &str, win: (f32, f32)) -> Element
.style(popup_row_style)
.width(Fill)
.height(OPTION_HEIGHT)
.padding([3, 7])
.into()
.padding([3, 7]);
keytips::anchor_with(|| keytips::item_anchor(tool.command, cmd), item)
})
.collect::<Vec<Element<'static, Message>>>(),
)