mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-02 18:16:19 +00:00
Parameters: show one rename tooltip per name (#10309)
Keep full names in the tooltip only when the name cell clips them, and keep the double-click rename hint without stacking a second popup. Cover short and long names, favorites, and double-click input with a regression test. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -527,8 +527,8 @@ fn table(app: &mut SolveApp, ui: &mut egui::Ui, d: &mut ParamsDialog, rows: &[&R
|
||||
}
|
||||
_ => {
|
||||
let rename = crate::i18n::tr_label("Double-click to rename");
|
||||
// Always tip the full name: the Name cell clips long identifiers (#8533).
|
||||
let response = ui_kit::text(ui, &r.name, ui_kit::Text::NameCell(false)).on_hover_text(format!("{}\n{rename}", r.name));
|
||||
// Keep long identifiers readable (#8533) without stacking the cell's own tooltip.
|
||||
let response = ui_kit::name_cell_with_hint(ui, &r.name, false, rename);
|
||||
crate::scenario::publish_handle(&format!("param:name:{}", r.name), response.rect.center());
|
||||
if response.double_clicked() {
|
||||
d.renaming = Some((r.name.clone(), r.name.clone()));
|
||||
@@ -953,6 +953,54 @@ pub fn complete(ui: &mut egui::Ui, resp: &egui::Response, text: &mut String) ->
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parameter_names_show_one_tooltip_and_only_repeat_clipped_names() {
|
||||
fn text_in(shape: &egui::Shape, within: egui::Rect, texts: &mut Vec<String>) {
|
||||
match shape {
|
||||
egui::Shape::Text(text) if within.contains(text.pos) => texts.push(text.galley.text().to_owned()),
|
||||
egui::Shape::Vec(shapes) => {
|
||||
for shape in shapes {
|
||||
text_in(shape, within, texts);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let long = "Driver_MountHole_pitch_diameter_".repeat(2);
|
||||
for name in ["rip_length", long.as_str()] {
|
||||
for favorite in [false, true] {
|
||||
let mut h = crate::scenario::Harness::new();
|
||||
h.app.home.open = false;
|
||||
h.app.run("parameters.add", json!({"name":name,"expression":"140 mm"})).unwrap();
|
||||
h.app.run("parameters.favorite", json!({"name":name,"favorite":favorite})).unwrap();
|
||||
h.step(&json!({"start":"parameters.change"})).unwrap();
|
||||
h.frames(6);
|
||||
let at = crate::scenario::handle_at(&format!("param:name:{name}")).unwrap();
|
||||
h.step(&json!({"move":[at.x,at.y]})).unwrap();
|
||||
h.frames(90);
|
||||
let tooltips: Vec<_> = h.ctx.memory(|m| {
|
||||
m.areas()
|
||||
.visible_layer_ids()
|
||||
.into_iter()
|
||||
.filter(|layer| layer.order == egui::Order::Tooltip)
|
||||
.filter_map(|layer| m.area_rect(layer.id))
|
||||
.collect()
|
||||
});
|
||||
assert_eq!(tooltips.len(), 1, "one name must not stack tooltips: {name}, favorite={favorite}");
|
||||
let mut texts = Vec::new();
|
||||
for shape in &h.shapes {
|
||||
text_in(&shape.shape, tooltips[0], &mut texts);
|
||||
}
|
||||
let hint = crate::i18n::tr_label("Double-click to rename");
|
||||
let expected = if name == "rip_length" { hint.to_owned() } else { format!("{name}\n{hint}") };
|
||||
assert_eq!(texts, [expected], "only a clipped name needs repeating");
|
||||
h.step(&json!({"click":{"handle":format!("param:name:{name}")},"double":true})).unwrap();
|
||||
assert!(h.app.params.as_ref().unwrap().renaming.is_some(), "the name still renames by double-click");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn escape_dialog() -> crate::scenario::Harness {
|
||||
let mut h = crate::scenario::Harness::new();
|
||||
h.app.home.open = false;
|
||||
|
||||
@@ -1156,6 +1156,9 @@ const ELEMENTS: &[Element] = &[
|
||||
element!("text", "dialog:report:gallery", Some("dialog:report:gallery"), |ui, _| {
|
||||
text(ui, "Validation report with retained units: 10 mm", Text::Report("gallery", false));
|
||||
}),
|
||||
element!("name_cell_with_hint", "dialog:cell:Width", Some("dialog:cell:Width"), |ui, _| {
|
||||
name_cell_with_hint(ui, "Width", false, "Double-click to rename");
|
||||
}),
|
||||
element!("search_field", |ui, s| {
|
||||
search_field(ui, ui.id().with("search"), &mut s.value, "Search");
|
||||
}),
|
||||
|
||||
@@ -678,6 +678,15 @@ pub(crate) fn note_height(ui: &Ui, text: &str) -> f32 {
|
||||
}
|
||||
|
||||
pub(crate) fn text(ui: &mut Ui, text: &str, style: Text<'_>) -> Response {
|
||||
text_impl(ui, text, style, None)
|
||||
}
|
||||
|
||||
/// One name-cell tooltip: the action hint, with the full name only if the cell clips it.
|
||||
pub(crate) fn name_cell_with_hint(ui: &mut Ui, name: &str, strong: bool, hint: &str) -> Response {
|
||||
text_impl(ui, name, Text::NameCell(strong), Some(hint))
|
||||
}
|
||||
|
||||
fn text_impl(ui: &mut Ui, text: &str, style: Text<'_>, hover_hint: Option<&str>) -> Response {
|
||||
if crate::prefs_search::querying(ui) {
|
||||
let heading = matches!(style, Text::Heading(_));
|
||||
if heading {
|
||||
@@ -718,9 +727,16 @@ pub(crate) fn text(ui: &mut Ui, text: &str, style: Text<'_>) -> Response {
|
||||
vec2(dimension(ui.available_width()), row_height()),
|
||||
if matches!(style, Text::Value(_, _)) { egui::Sense::hover() } else { egui::Sense::click() },
|
||||
);
|
||||
let tooltip = hover_hint.map(|hint| {
|
||||
if ui.painter().layout_no_wrap(text.to_owned(), font.clone(), ink).size().x > rect.width() {
|
||||
format!("{text}\n{hint}")
|
||||
} else {
|
||||
hint.to_owned()
|
||||
}
|
||||
});
|
||||
paint_text(ui, rect, text, font, ink, false);
|
||||
response.widget_info(|| egui::WidgetInfo::labeled(egui::WidgetType::Label, ui.is_enabled(), text));
|
||||
response.on_hover_text(text)
|
||||
response.on_hover_text(tooltip.as_deref().unwrap_or(text))
|
||||
} else if matches!(style, Text::Error(_)) {
|
||||
egui::Frame::NONE
|
||||
.fill(t.form_error_fill)
|
||||
|
||||
@@ -319,6 +319,11 @@ board test captures both strip widths with expanded and collapsed browsers
|
||||
| `Text::Inline` | Native truncated label; rect/handle `dialog:inline:TEXT` |
|
||||
| `Text::Cell` | Fixed-height clipped clickable cell with tooltip; rect/handle `dialog:cell:TEXT` |
|
||||
|
||||
`name_cell_with_hint(ui, name, strong, hint)` keeps the name cell's allocation and
|
||||
scenario identity, but owns its single tooltip: the action hint alone when the
|
||||
name fits, or the full name followed by the hint when it is clipped. Use it instead
|
||||
of adding a second hover tooltip to `Text::NameCell`.
|
||||
|
||||
Examples:
|
||||
|
||||
```rust
|
||||
|
||||
Reference in New Issue
Block a user