forked from 1b-agent/opencadstudio-upstream
Merge pull request #1788 from ramox81/codex/keytips-followups
Key tips: reference quick-access numbers, shared codes and placement Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
commit
abbd8365e0
4 files changed
+300
-76
No files matched your search
@@ -302,9 +302,11 @@ pub(super) fn group_title<'a>(
|
||||
active_tool: Option<&str>,
|
||||
) -> Element<'a, Message> {
|
||||
let Some(panel) = panel_for_group(title, group_ids) else {
|
||||
return container(text(t!(title)).size(9).style(muted_text_style))
|
||||
.padding([1, 4])
|
||||
.into();
|
||||
let label = keytips::label_anchor(
|
||||
|| format!("title:{title}"),
|
||||
text(t!(title)).size(9).style(muted_text_style),
|
||||
);
|
||||
return container(label).padding([1, 4]).into();
|
||||
};
|
||||
let expanded = open.as_deref().and_then(parent_panel) == Some(panel.id);
|
||||
// A command running from the closed slide-out lights its title, the way a
|
||||
@@ -323,7 +325,10 @@ pub(super) fn group_title<'a>(
|
||||
panel.id,
|
||||
button(
|
||||
row![
|
||||
PosReport::new(panel.title_id, text(t!(title)).size(9)),
|
||||
keytips::label_anchor(
|
||||
|| keytips::label_id(panel.id),
|
||||
PosReport::new(panel.title_id, text(t!(title)).size(9)),
|
||||
),
|
||||
arrow
|
||||
]
|
||||
.spacing(4)
|
||||
@@ -417,7 +422,10 @@ fn reference_overlay<'a>(ribbon: &Ribbon, panel: Panel, win: (f32, f32)) -> Elem
|
||||
let edit = button(
|
||||
row![
|
||||
make_icon(IconKind::Svg(tool.icon), 16.0),
|
||||
text(t!(tool.label)).size(11)
|
||||
keytips::label_anchor(
|
||||
|| keytips::label_id(&keytips::item_anchor(panel.id, tool.command)),
|
||||
text(t!(tool.label)).size(11),
|
||||
),
|
||||
]
|
||||
.spacing(6)
|
||||
.align_y(iced::Center),
|
||||
@@ -457,7 +465,10 @@ fn reference_overlay<'a>(ribbon: &Ribbon, panel: Panel, win: (f32, f32)) -> Elem
|
||||
);
|
||||
let fading = row![
|
||||
switch,
|
||||
text(t!("Xref fading")).size(11),
|
||||
keytips::label_anchor(
|
||||
|| keytips::label_id(&keytips::item_anchor(panel.id, keytips::XREF_FADE)),
|
||||
text(t!("Xref fading")).size(11),
|
||||
),
|
||||
iced::widget::slider(0..=90u8, amount, Message::XrefFadeSlide)
|
||||
.on_release(Message::XrefFadeCommit)
|
||||
.width(Fill),
|
||||
|
||||
+223
-41
@@ -86,6 +86,9 @@ static ALT_ALONE: AtomicBool = AtomicBool::new(false);
|
||||
thread_local! {
|
||||
/// Anchors that carried a code in the last drawn frame.
|
||||
static SHOWN: RefCell<Vec<String>> = const { RefCell::new(Vec::new()) };
|
||||
/// Label and panel-title widgets a code must not cover.
|
||||
static OBSTACLES: RefCell<rustc_hash::FxHashSet<String>> =
|
||||
RefCell::new(rustc_hash::FxHashSet::default());
|
||||
}
|
||||
|
||||
/// Id of the whole ribbon (tab row and tools), for the hint bar.
|
||||
@@ -121,6 +124,27 @@ pub(super) fn anchor_with<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Record the bounds of a label or panel title under `id` while key tips
|
||||
/// show, so no code is drawn over it.
|
||||
pub(super) fn label_anchor<'a>(
|
||||
id: impl FnOnce() -> String,
|
||||
el: impl Into<Element<'a, Message>>,
|
||||
) -> Element<'a, Message> {
|
||||
if !active() {
|
||||
return el.into();
|
||||
}
|
||||
let id = id();
|
||||
OBSTACLES.with(|ids| {
|
||||
ids.borrow_mut().insert(id.clone());
|
||||
});
|
||||
PosReport::owned(id, el).into()
|
||||
}
|
||||
|
||||
/// Id of the label (or panel title) of the widget with anchor `anchor`.
|
||||
pub(super) fn label_id(anchor: &str) -> String {
|
||||
format!("label:{anchor}")
|
||||
}
|
||||
|
||||
/// Anchor id of item `cmd` in dropdown or slide-out `dropdown`.
|
||||
pub(super) fn item_anchor(dropdown: &str, cmd: &str) -> String {
|
||||
format!("{dropdown}/{cmd}")
|
||||
@@ -193,22 +217,25 @@ fn tab_code(module: &str) -> Option<&'static str> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Quick-access buttons in order; their codes are their positions.
|
||||
const QUICK_ACCESS: &[&str] = &[
|
||||
"QNEW",
|
||||
"OPEN",
|
||||
"SAVE",
|
||||
"SAVEAS",
|
||||
"PRINT",
|
||||
super::widgets::UNDO_HISTORY_ID,
|
||||
super::widgets::REDO_HISTORY_ID,
|
||||
/// Quick-access buttons with the number the reference toolbar gives the same
|
||||
/// button (its 5 and 9, the web and mobile and workspace items, have no
|
||||
/// counterpart here).
|
||||
const QUICK_ACCESS: &[(&str, &str)] = &[
|
||||
("QNEW", "1"),
|
||||
("OPEN", "2"),
|
||||
("SAVE", "3"),
|
||||
("SAVEAS", "4"),
|
||||
("PRINT", "6"),
|
||||
(super::widgets::UNDO_HISTORY_ID, "7"),
|
||||
(super::widgets::REDO_HISTORY_ID, "8"),
|
||||
];
|
||||
|
||||
/// Reference codes as (scope, target, code). In a tab's scope (its module id)
|
||||
/// the target is a tool id, a dropdown id or a group title; a group title's
|
||||
/// code opens the panel's slide-out or, while the panel is collapsed, its
|
||||
/// flyout. In a dropdown's or slide-out's scope the target is an item's
|
||||
/// command.
|
||||
/// command. When two buttons share a code the earlier entry runs, as the
|
||||
/// reference's command for that code.
|
||||
const CODES: &[(&str, &str, &str)] = &[
|
||||
// Draw (the reference Home tab).
|
||||
("draw", "Draw", "DW"),
|
||||
@@ -395,12 +422,17 @@ const CODES: &[(&str, &str, &str)] = &[
|
||||
("annotate", "DATALINK", "DL"),
|
||||
("annotate", "WIPEOUT", "WI"),
|
||||
("annotate", "REVCLOUD", "AC"),
|
||||
// The reference shows AC here too; typing it runs Revision Cloud.
|
||||
("annotate", "ANNOTATION_CURRENT_SCALE", "AC"),
|
||||
("annotate", "SCALELISTEDIT", "SL"),
|
||||
("annotate", "OBJECTSCALE", "AS"),
|
||||
("annotate", "ANNORESET", "SS"),
|
||||
// View.
|
||||
("view", "Viewport Tools", "VT"),
|
||||
("view", "UCSICON", "UI"),
|
||||
// The reference shows VC on Viewport Configuration and on the ViewCube;
|
||||
// typing it runs Viewport Configuration.
|
||||
("view", "VPORTS", "VC"),
|
||||
("view", "NAVVCUBE", "VC"),
|
||||
("view", "PAN", "PA"),
|
||||
("view", "3DORBIT", "OR"),
|
||||
@@ -442,8 +474,10 @@ const CODES: &[(&str, &str, &str)] = &[
|
||||
("block_editor", "CCONSTRAINT", "CI"),
|
||||
("block_editor", "PCONSTRAINT", "PA"),
|
||||
("block_editor", "TCONSTRAINT", "TA"),
|
||||
// The reference gives Concentric the same code; Collinear comes first.
|
||||
// Collinear and Concentric share CO in the reference; typing it runs
|
||||
// Collinear.
|
||||
("block_editor", "LCONSTRAINT", "CO"),
|
||||
("block_editor", "GCCONCENTRIC", "CO"),
|
||||
("block_editor", "QCONSTRAINT", "PE"),
|
||||
("block_editor", "GCSMOOTH", "SM"),
|
||||
("block_editor", "GCHORIZONTAL", "HO"),
|
||||
@@ -555,7 +589,24 @@ impl Ribbon {
|
||||
return KeyTipStep::Ignore;
|
||||
};
|
||||
let codes = || tips.iter().filter_map(|tip| tip.code.as_deref());
|
||||
let exact = |typed: &str| tips.iter().find(|tip| tip.code.as_deref() == Some(typed));
|
||||
let scope = if state.top {
|
||||
""
|
||||
} else {
|
||||
self.open_dropdown
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| self.modules.get(self.active).map_or("", |m| m.id()))
|
||||
};
|
||||
let rank = |tip: &Tip| {
|
||||
CODES
|
||||
.iter()
|
||||
.position(|(s, t, _)| *s == scope && *t == tip.target)
|
||||
.unwrap_or(usize::MAX)
|
||||
};
|
||||
let exact = |typed: &str| {
|
||||
tips.iter()
|
||||
.filter(|tip| tip.code.as_deref() == Some(typed))
|
||||
.min_by_key(|tip| rank(tip))
|
||||
};
|
||||
let longer = |typed: &str| codes().any(|code| code.len() > typed.len() && code.starts_with(typed));
|
||||
let typed = ch.map(|ch| format!("{}{ch}", state.typed));
|
||||
let chosen = match typed {
|
||||
@@ -614,10 +665,10 @@ impl Ribbon {
|
||||
action: Action::Tab(index),
|
||||
})
|
||||
.collect();
|
||||
tips.extend(QUICK_ACCESS.iter().enumerate().map(|(index, &id)| Tip {
|
||||
tips.extend(QUICK_ACCESS.iter().map(|&(id, code)| Tip {
|
||||
anchor: quick_access_anchor(id),
|
||||
target: id,
|
||||
code: Some((index + 1).to_string()),
|
||||
code: Some(code.to_string()),
|
||||
action: Action::Run(match id {
|
||||
super::widgets::UNDO_HISTORY_ID => Message::Undo,
|
||||
super::widgets::REDO_HISTORY_ID => Message::Redo,
|
||||
@@ -811,12 +862,21 @@ impl Ribbon {
|
||||
/// The hint bar layer and the codes layer.
|
||||
pub fn keytip_layers(&self) -> Option<(Element<'_, Message>, Element<'_, Message>)> {
|
||||
let state = self.keytips.as_ref()?;
|
||||
let tips: Vec<(String, String)> = self
|
||||
let tips: Vec<(String, String, bool, f32)> = self
|
||||
.keytip_list()
|
||||
.into_iter()
|
||||
.filter_map(|tip| {
|
||||
let code = tip.code?;
|
||||
code.starts_with(&state.typed).then_some((tip.anchor, code))
|
||||
let dropdown = matches!(tip.action, Action::Open(Message::ToggleRibbonDropdown(_)));
|
||||
// A collapsed panel's title is centred in a wider box: its
|
||||
// text width places the code beside the words.
|
||||
let title_w = if tip.anchor.starts_with(COLLAPSED_PREFIX) {
|
||||
text_width(&crate::t!(tip.target), 9.0, iced::Font::default())
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
code.starts_with(&state.typed)
|
||||
.then_some((tip.anchor, code, dropdown, title_w))
|
||||
})
|
||||
.collect();
|
||||
let mut path = state.path.join(" › ");
|
||||
@@ -862,7 +922,8 @@ impl Ribbon {
|
||||
/// they sit above flyouts and dropdowns, after their widgets reported where
|
||||
/// they are.
|
||||
struct KeyTipLayer {
|
||||
tips: Vec<(String, String)>,
|
||||
/// (anchor, code, opens a dropdown, collapsed panel title width).
|
||||
tips: Vec<(String, String, bool, f32)>,
|
||||
/// Characters of a partial code, shown dimmed on matching tips.
|
||||
typed: usize,
|
||||
bar: Option<[String; 3]>,
|
||||
@@ -1017,35 +1078,58 @@ impl overlay::Overlay<Message, Theme, Renderer> for KeyTipOverlay<'_> {
|
||||
let font = bold(renderer);
|
||||
let mut shown = Vec::new();
|
||||
renderer.with_layer(window, |renderer| {
|
||||
for (anchor, code) in &self.layer.tips {
|
||||
// Place every code at the first spot, nearest the reference
|
||||
// place first, that covers no label, panel title or code placed
|
||||
// before it.
|
||||
// A collapsed panel's title counts only where its words are.
|
||||
let narrow = |id: &str, rect: Rectangle| {
|
||||
let title_w = self.layer.tips.iter().find_map(|(anchor, _, _, title_w)| {
|
||||
(*title_w > 0.0 && label_id(anchor) == id).then_some(*title_w)
|
||||
});
|
||||
match title_w {
|
||||
Some(w) if w < rect.width => Rectangle::new(
|
||||
Point::new(rect.center_x() - w / 2.0, rect.y),
|
||||
Size::new(w, rect.height),
|
||||
),
|
||||
_ => rect,
|
||||
}
|
||||
};
|
||||
let mut blocked: Vec<Rectangle> = OBSTACLES.with(|ids| {
|
||||
ids.borrow()
|
||||
.iter()
|
||||
.filter_map(|id| fresh_bounds(id).map(|rect| narrow(id, rect)))
|
||||
.collect()
|
||||
});
|
||||
let free = |rect: &Rectangle, blocked: &[Rectangle]| {
|
||||
// Touching edges do not count.
|
||||
!blocked.iter().any(|other| {
|
||||
other.intersection(rect).is_some_and(|r| r.width > 1.0 && r.height > 1.0)
|
||||
})
|
||||
};
|
||||
let mut pills: Vec<(&String, &String, Rectangle)> = Vec::new();
|
||||
for (anchor, code, dropdown, title_w) in &self.layer.tips {
|
||||
let Some(b) = fresh_bounds(anchor) else {
|
||||
continue;
|
||||
};
|
||||
let width = text_width(code, PILL_TEXT, font) + 10.0;
|
||||
let top_row = anchor.starts_with("tab:")
|
||||
|| anchor.starts_with("qa:")
|
||||
|| anchor == super::widgets::UNDO_HISTORY_ID
|
||||
|| anchor == super::widgets::REDO_HISTORY_ID;
|
||||
let center = if top_row {
|
||||
// Tabs and quick-access buttons: on the lower edge, so the
|
||||
// label stays readable.
|
||||
Point::new(b.center_x(), b.y + b.height - 2.0)
|
||||
} else if anchor.contains('/') && b.width >= 60.0 {
|
||||
// Menu rows: at the right end, clear of the label.
|
||||
Point::new(b.x + b.width - width / 2.0 - 4.0, b.center_y())
|
||||
} else if anchor.contains('/') {
|
||||
// Slide-out icons: on the lower edge.
|
||||
Point::new(b.center_x(), b.y + b.height - 2.0)
|
||||
} else if b.height >= 40.0 {
|
||||
// Large buttons: over the label.
|
||||
Point::new(b.center_x(), b.y + b.height - PILL_H / 2.0 - 2.0)
|
||||
} else {
|
||||
// Small buttons: at the lower left, over the icon.
|
||||
Point::new(b.x + width / 2.0, b.y + b.height - PILL_H / 2.0 + 3.0)
|
||||
let rects: Vec<Rectangle> = pill_candidates(anchor, b, width, *dropdown, *title_w)
|
||||
.into_iter()
|
||||
.map(|center| {
|
||||
let x = (center.x - width / 2.0)
|
||||
.clamp(window.x, (window.width - width).max(window.x));
|
||||
let y = (center.y - PILL_H / 2.0)
|
||||
.clamp(window.y, (window.height - PILL_H).max(window.y));
|
||||
Rectangle::new(Point::new(x, y), Size::new(width, PILL_H))
|
||||
})
|
||||
.collect();
|
||||
let Some(&first) = rects.first() else {
|
||||
continue;
|
||||
};
|
||||
let x = (center.x - width / 2.0).clamp(window.x, (window.width - width).max(window.x));
|
||||
let y = (center.y - PILL_H / 2.0).clamp(window.y, (window.height - PILL_H).max(window.y));
|
||||
let pill = Rectangle::new(Point::new(x, y), Size::new(width, PILL_H));
|
||||
let pill = rects.iter().copied().find(|rect| free(rect, &blocked)).unwrap_or(first);
|
||||
blocked.push(pill);
|
||||
pills.push((anchor, code, pill));
|
||||
}
|
||||
for (anchor, code, pill) in pills {
|
||||
renderer.fill_quad(
|
||||
renderer::Quad {
|
||||
bounds: pill,
|
||||
@@ -1135,3 +1219,101 @@ fn draw_bar(renderer: &mut Renderer, theme: &Theme, parts: &[String; 3]) {
|
||||
pub(super) fn ribbon_area<'a>(el: impl Into<Element<'a, Message>>) -> Element<'a, Message> {
|
||||
anchor(RIBBON_AREA, el)
|
||||
}
|
||||
|
||||
/// Spots for a code on its widget, nearest the reference ribbon's place
|
||||
/// first: under a tab's label; with its corner at the icon's centre on
|
||||
/// quick-access, small and slide-out buttons; under a large button's label or
|
||||
/// on a large dropdown's arrow strip; beside a panel title (the reference
|
||||
/// centres it on the title) or on the corner launcher. Menu rows of dropdown
|
||||
/// lists, which the reference gives no codes, carry it at their right end.
|
||||
/// Later spots move off a label: the icon's other corners, a combo box's
|
||||
/// arrow, above the label, beside the widget.
|
||||
fn pill_candidates(
|
||||
anchor: &str,
|
||||
b: Rectangle,
|
||||
width: f32,
|
||||
dropdown: bool,
|
||||
title_w: f32,
|
||||
) -> Vec<Point> {
|
||||
let corner = |x: f32, y: f32| Point::new(x + width / 2.0, y + PILL_H / 2.0);
|
||||
let left_corner = |x: f32, y: f32| Point::new(x - width / 2.0, y + PILL_H / 2.0);
|
||||
let label = fresh_bounds(&label_id(anchor));
|
||||
if anchor.starts_with("tab:") {
|
||||
return vec![Point::new(b.center_x(), b.y + b.height - 4.0 + PILL_H / 2.0)];
|
||||
}
|
||||
if anchor.starts_with("qa:")
|
||||
|| anchor == super::widgets::UNDO_HISTORY_ID
|
||||
|| anchor == super::widgets::REDO_HISTORY_ID
|
||||
{
|
||||
return vec![corner(b.x + 14.0, b.center_y()), Point::new(b.x + 14.0, b.center_y())];
|
||||
}
|
||||
if anchor == XREF_LAUNCHER {
|
||||
return vec![
|
||||
b.center(),
|
||||
Point::new(b.x + b.width + 2.0 + width / 2.0, b.center_y()),
|
||||
Point::new(b.center_x(), b.y - 1.0 - PILL_H / 2.0),
|
||||
Point::new(b.x - 2.0 - width / 2.0, b.center_y()),
|
||||
];
|
||||
}
|
||||
if anchor.ends_with("_extension") || anchor.starts_with(COLLAPSED_PREFIX) {
|
||||
let mut title = label.unwrap_or(b);
|
||||
if title_w > 0.0 && title_w < title.width {
|
||||
title = Rectangle::new(
|
||||
Point::new(title.center_x() - title_w / 2.0, title.y),
|
||||
Size::new(title_w, title.height),
|
||||
);
|
||||
}
|
||||
let mut spots = vec![
|
||||
Point::new(title.x + title.width + 3.0 + width / 2.0, title.center_y()),
|
||||
Point::new(title.x - 3.0 - width / 2.0, title.center_y()),
|
||||
Point::new(title.center_x(), title.y - PILL_H / 2.0 - 1.0),
|
||||
];
|
||||
if b.height >= 40.0 {
|
||||
spots.insert(0, Point::new(b.center_x(), b.y + b.height + 1.0));
|
||||
}
|
||||
return spots;
|
||||
}
|
||||
let slide_out_item = anchor
|
||||
.split_once('/')
|
||||
.is_some_and(|(parent, _)| parent.ends_with("_extension"));
|
||||
if anchor.contains('/') && !slide_out_item && b.width >= 60.0 {
|
||||
return vec![
|
||||
Point::new(b.x + b.width - width / 2.0 - 4.0, b.center_y()),
|
||||
Point::new(b.x + width / 2.0 + 2.0, b.center_y()),
|
||||
];
|
||||
}
|
||||
if b.height >= 40.0 {
|
||||
let label = label.unwrap_or(Rectangle::new(
|
||||
Point::new(b.x, b.y + b.height - 18.0),
|
||||
Size::new(b.width, 14.0),
|
||||
));
|
||||
let icon = Point::new(b.center_x(), (b.y + label.y) / 2.0);
|
||||
let mut spots = Vec::new();
|
||||
if dropdown {
|
||||
// The arrow strip lies under the label.
|
||||
spots.push(Point::new(b.center_x(), b.y + b.height - super::widgets::LARGE_ARR / 2.0));
|
||||
}
|
||||
spots.extend([
|
||||
Point::new(b.center_x(), label.y + label.height + 1.0 + PILL_H / 2.0),
|
||||
corner(icon.x, icon.y),
|
||||
left_corner(icon.x, icon.y),
|
||||
Point::new(b.center_x(), label.y - 1.0 - PILL_H / 2.0),
|
||||
icon,
|
||||
]);
|
||||
return spots;
|
||||
}
|
||||
let icon = Point::new(b.x + (b.width / 2.0).min(15.0), b.center_y());
|
||||
let mut spots = vec![corner(icon.x, icon.y), icon, left_corner(icon.x, icon.y)];
|
||||
if b.width >= 60.0 {
|
||||
// A combo box: on its arrow, at the right end.
|
||||
spots.push(Point::new(b.x + b.width - width / 2.0 - 2.0, b.center_y()));
|
||||
}
|
||||
spots.extend([
|
||||
corner(icon.x, icon.y - PILL_H),
|
||||
left_corner(icon.x, icon.y - PILL_H),
|
||||
Point::new(b.x - 2.0 - width / 2.0, b.center_y()),
|
||||
Point::new(b.x + b.width + 2.0 + width / 2.0, b.center_y()),
|
||||
Point::new(icon.x, b.y + b.height + PILL_H / 2.0 - 2.0),
|
||||
]);
|
||||
spots
|
||||
}
|
||||
+20
-12
@@ -1012,6 +1012,8 @@ impl Ribbon {
|
||||
color: (!is_current || disabled)
|
||||
.then_some(theme.palette().background.base.text.scale_alpha(0.72)),
|
||||
});
|
||||
let label_el =
|
||||
keytips::label_anchor(|| keytips::label_id(&keytips::item_anchor(dd_id, cmd)), label_el);
|
||||
|
||||
let item = button(
|
||||
row![checkmark, icon_el, label_el]
|
||||
@@ -1593,12 +1595,15 @@ fn collapse_button<'a>(
|
||||
column![
|
||||
icon,
|
||||
row![
|
||||
text(localized_title.clone())
|
||||
.size(9)
|
||||
.width(Fill)
|
||||
.align_x(iced::Center)
|
||||
.wrapping(iced::advanced::text::Wrapping::Word)
|
||||
.style(muted_text_style),
|
||||
keytips::label_anchor(
|
||||
|| keytips::label_id(&keytips::collapsed_anchor(title)),
|
||||
text(localized_title.clone())
|
||||
.size(9)
|
||||
.width(Fill)
|
||||
.align_x(iced::Center)
|
||||
.wrapping(iced::advanced::text::Wrapping::Word)
|
||||
.style(muted_text_style),
|
||||
),
|
||||
crate::ui::icons::themed_secondary_arrow_down(8.0),
|
||||
]
|
||||
.spacing(3)
|
||||
@@ -1665,12 +1670,15 @@ fn collapse_button<'a>(
|
||||
|
||||
let opener = button(
|
||||
row![
|
||||
text(localized_title.clone())
|
||||
.size(9)
|
||||
.width(Fill)
|
||||
.align_x(iced::Center)
|
||||
.wrapping(iced::advanced::text::Wrapping::Word)
|
||||
.style(muted_text_style),
|
||||
keytips::label_anchor(
|
||||
|| keytips::label_id(&keytips::collapsed_anchor(title)),
|
||||
text(localized_title.clone())
|
||||
.size(9)
|
||||
.width(Fill)
|
||||
.align_x(iced::Center)
|
||||
.wrapping(iced::advanced::text::Wrapping::Word)
|
||||
.style(muted_text_style),
|
||||
),
|
||||
crate::ui::icons::themed_secondary_arrow_down(8.0),
|
||||
]
|
||||
.spacing(3)
|
||||
|
||||
+40
-17
@@ -560,7 +560,10 @@ pub(super) fn render_small<'a>(
|
||||
let tip_text = tool_tip_text(&label, t.id);
|
||||
let content = row![
|
||||
container(make_icon(t.icon, SMALL_ICON)).width(Length::Fixed(SMALL_W)),
|
||||
text(label).size(10).wrapping(advanced_text::Wrapping::None),
|
||||
super::keytips::label_anchor(
|
||||
|| super::keytips::label_id(t.id),
|
||||
text(label).size(10).wrapping(advanced_text::Wrapping::None),
|
||||
),
|
||||
]
|
||||
.spacing(3)
|
||||
.align_y(iced::Center);
|
||||
@@ -699,9 +702,12 @@ pub(super) fn render_small<'a>(
|
||||
};
|
||||
let face = row![
|
||||
container(make_icon(cur_icon, SMALL_ICON)).width(Length::Fixed(SMALL_W)),
|
||||
text(localized_label.clone())
|
||||
.size(10)
|
||||
.wrapping(advanced_text::Wrapping::None),
|
||||
super::keytips::label_anchor(
|
||||
|| super::keytips::label_id(id),
|
||||
text(localized_label.clone())
|
||||
.size(10)
|
||||
.wrapping(advanced_text::Wrapping::None),
|
||||
),
|
||||
]
|
||||
.spacing(3)
|
||||
.align_y(iced::Center);
|
||||
@@ -832,11 +838,14 @@ pub(super) fn render_large_dropdown<'a>(
|
||||
.height(Fill)
|
||||
.align_x(iced::Center)
|
||||
.align_y(iced::Center),
|
||||
text(label.clone())
|
||||
.size(10)
|
||||
.width(Fill)
|
||||
.align_x(iced::Center)
|
||||
.wrapping(advanced_text::Wrapping::Word),
|
||||
super::keytips::label_anchor(
|
||||
|| super::keytips::label_id(id),
|
||||
text(label.clone())
|
||||
.size(10)
|
||||
.width(Fill)
|
||||
.align_x(iced::Center)
|
||||
.wrapping(advanced_text::Wrapping::Word),
|
||||
),
|
||||
]
|
||||
.align_x(iced::Center)
|
||||
.spacing(0)
|
||||
@@ -957,11 +966,14 @@ pub(super) fn render_large<'a>(item: &RibbonItem, ctx: &RenderCtx<'_>) -> Elemen
|
||||
.height(Fill)
|
||||
.align_x(iced::Center)
|
||||
.align_y(iced::Center),
|
||||
text(label.clone())
|
||||
.size(10)
|
||||
.width(Fill)
|
||||
.align_x(iced::Center)
|
||||
.wrapping(advanced_text::Wrapping::Word),
|
||||
super::keytips::label_anchor(
|
||||
|| super::keytips::label_id(t.id),
|
||||
text(label.clone())
|
||||
.size(10)
|
||||
.width(Fill)
|
||||
.align_x(iced::Center)
|
||||
.wrapping(advanced_text::Wrapping::Word),
|
||||
),
|
||||
]
|
||||
.align_x(iced::Center)
|
||||
.spacing(0)
|
||||
@@ -1087,7 +1099,10 @@ pub(super) fn render_large<'a>(item: &RibbonItem, ctx: &RenderCtx<'_>) -> Elemen
|
||||
freeze_icon,
|
||||
lock_icon,
|
||||
swatch,
|
||||
container(text(active_layer_label).size(11))
|
||||
container(super::keytips::label_anchor(
|
||||
|| super::keytips::label_id(LAYER_COMBO_ID),
|
||||
text(active_layer_label).size(11),
|
||||
))
|
||||
.width(name_w)
|
||||
.clip(true),
|
||||
icons::themed_arrow_down(9.0),
|
||||
@@ -1157,7 +1172,12 @@ pub(super) fn render_large<'a>(item: &RibbonItem, ctx: &RenderCtx<'_>) -> Elemen
|
||||
button(
|
||||
row![
|
||||
swatch_el,
|
||||
container(text(label).size(10)).width(Fill).clip(true),
|
||||
container(super::keytips::label_anchor(
|
||||
|| super::keytips::label_id(dd_id),
|
||||
text(label).size(10),
|
||||
))
|
||||
.width(Fill)
|
||||
.clip(true),
|
||||
if is_open {
|
||||
icons::themed_arrow_up(8.0)
|
||||
} else {
|
||||
@@ -1226,7 +1246,10 @@ pub(super) fn render_large<'a>(item: &RibbonItem, ctx: &RenderCtx<'_>) -> Elemen
|
||||
// ── combo button ──
|
||||
let combo_btn = button(
|
||||
row![
|
||||
container(text(active.clone()).size(11))
|
||||
container(super::keytips::label_anchor(
|
||||
|| super::keytips::label_id(combo_id),
|
||||
text(active.clone()).size(11),
|
||||
))
|
||||
.width(Fill)
|
||||
.clip(true),
|
||||
if is_open {
|
||||
|
||||
Reference in new issue
Block a user