Links: a nested row's tooltip names the symbol, graph design, pattern or mask holding it

Two rows of the same file in different symbols showed the same name,
thumbnail and status. The tooltip of a row outside the layer tree now
adds the symbol, graph design or pattern whose art holds the image, and
the object whose opacity mask holds it.
This commit is contained in:
dotCooCoo
2026-11-12 22:50:22 -08:00
parent 072b68583a
commit 64241978ec
2 changed files with 49 additions and 2 deletions
+31 -2
View File
@@ -344,7 +344,31 @@ fn badge(ui: &Ui, r: egui::Rect, status: &str) {
}
}
fn status_tip(r: &Value) -> String {
/// The tooltip of row `r`. A row outside the layer tree also names where it is stored
/// (`links.list`'s `owner`): the symbol, graph design or pattern whose art holds it, and the object
/// whose opacity mask holds it, by `mask` (that object's name) or else by its id.
pub(super) fn status_tip(r: &Value, mask: Option<String>) -> String {
let tip = file_tip(r);
let owner = &r["owner"];
let name = owner["name"].as_str().unwrap_or_default();
let art = match owner["kind"].as_str() {
Some("symbol") => Some(tl!("Symbols")),
Some("graphDesign") => Some(tl!("Graph Design")),
Some("pattern") => Some(tl!("Pattern")),
_ => None,
};
let tip = match art {
Some(kind) => format!("{tip}\n{kind}: {name}"),
None => tip,
};
match owner["maskOf"].as_u64() {
Some(id) => format!("{tip}\n{}: {}", tl!("Opacity Mask"), mask.unwrap_or_else(|| id.to_string())),
None => tip,
}
}
/// The file, status and notes part of [`status_tip`].
fn file_tip(r: &Value) -> String {
let path = r["found"].as_str().or(r["path"].as_str()).unwrap_or_default();
let tip = match r["status"].as_str().unwrap_or_default() {
"missing" => crate::i18n::fmt(tl!("Missing: {path}"), &[("path", path)]),
@@ -495,7 +519,12 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
egui::FontId::proportional(12.5),
t.text,
);
let resp = resp.on_hover_text(status_tip(r));
let mask = r["owner"]["maskOf"]
.as_u64()
.and_then(|m| doc.stored_node(NodeId(m)))
.map(|(n, _)| n)
.map(|n| super::layers::shown_name(app, n, crate::i18n::current()));
let resp = resp.on_hover_text(status_tip(r, mask));
if resp.double_clicked() {
clicked = Some((id, egui::Modifiers::NONE, true));
} else if resp.clicked() {
+18
View File
@@ -178,6 +178,24 @@ fn a_link_inside_a_symbol_is_listed_and_picked_in_the_panel() {
assert!(selected(&app).is_empty(), "the image in the layers is no longer selected");
}
/// The tooltip of a row outside the layer tree says where the image is stored, so two rows of the
/// same file in different symbols or masks can be told apart.
#[test]
fn a_nested_rows_tooltip_names_what_holds_it() {
let tip = |owner: serde_json::Value, mask: Option<&str>| {
let row = json!({"id": 9, "name": "a.png", "status": "ok", "path": "/x/a.png", "owner": owner});
super::links::status_tip(&row, mask.map(str::to_string))
};
assert_eq!(tip(json!({"kind": "symbol", "name": "Mark"}), None), "/x/a.png\nSymbols: Mark");
assert_eq!(tip(json!({"kind": "pattern", "name": "Dots"}), None), "/x/a.png\nPattern: Dots");
assert_eq!(tip(json!({"kind": "graphDesign", "name": "Bar"}), None), "/x/a.png\nGraph Design: Bar");
assert_eq!(tip(json!({"kind": "layers", "maskOf": 7}), Some("<Ellipse>")), "/x/a.png\nOpacity Mask: <Ellipse>");
assert_eq!(tip(json!({"kind": "symbol", "name": "Mark", "maskOf": 7}), None), "/x/a.png\nSymbols: Mark\nOpacity Mask: 7");
// A row in the layers says only its file.
let row = json!({"id": 9, "name": "a.png", "status": "ok", "path": "/x/a.png"});
assert_eq!(super::links::status_tip(&row, None), "/x/a.png");
}
#[test]
fn an_empty_document_shows_how_to_add_images() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());