221 lines
7.1 KiB
Rust
221 lines
7.1 KiB
Rust
use super::*;
|
|
use crate::{
|
|
app::{App, Message},
|
|
style,
|
|
views::{action, short},
|
|
};
|
|
use iced::{
|
|
Element, Fill,
|
|
widget::{self, column, container, row, text, text_input, tooltip},
|
|
};
|
|
use std::collections::BTreeSet;
|
|
|
|
const PAGE_SIZE: usize = 6;
|
|
|
|
pub(crate) fn overlay<'a>(app: &'a App, base: Element<'a, Message>) -> Element<'a, Message> {
|
|
let Some(panel) = &app.diagram_usages else {
|
|
return base;
|
|
};
|
|
let p = app.project();
|
|
let token = panel.token;
|
|
let message = |event| Message::DiagramUsage(event);
|
|
let matched = panel.matches(p);
|
|
let mut surfaces = Vec::new();
|
|
let mut seen = BTreeSet::new();
|
|
for usage in &matched {
|
|
if seen.insert(usage.surface) {
|
|
surfaces.push(usage.surface);
|
|
}
|
|
}
|
|
let targets: Vec<_> = matched
|
|
.iter()
|
|
.copied()
|
|
.filter(|usage| Some(usage.surface) == panel.destination)
|
|
.collect();
|
|
let count = if panel.destination.is_some() {
|
|
targets.len()
|
|
} else {
|
|
surfaces.len()
|
|
};
|
|
let last = count.saturating_sub(1) / PAGE_SIZE;
|
|
let page = panel.page.min(last);
|
|
let total_surfaces = panel
|
|
.usages
|
|
.iter()
|
|
.map(|u| u.surface)
|
|
.collect::<BTreeSet<_>>()
|
|
.len();
|
|
let mut content = column![
|
|
row![
|
|
text("Show in diagrams").size(22).width(Fill),
|
|
action("Close", message(Event::Close(token)))
|
|
]
|
|
.spacing(12),
|
|
tooltip(
|
|
text(format!(
|
|
"{} · @{}",
|
|
short(p.named(panel.context.subject), 48),
|
|
short(alias(p, panel.context.subject), 48)
|
|
))
|
|
.size(14),
|
|
container(
|
|
widget::scrollable(
|
|
text(format!(
|
|
"{}\n@{}",
|
|
p.named(panel.context.subject),
|
|
alias(p, panel.context.subject)
|
|
))
|
|
.size(13)
|
|
)
|
|
.height(220)
|
|
)
|
|
.padding(10)
|
|
.width(620)
|
|
.style(style::card),
|
|
tooltip::Position::Bottom
|
|
),
|
|
text(if panel.loading {
|
|
"Searching rendered objects…".into()
|
|
} else {
|
|
format!(
|
|
"{} diagram destinations · {} representations",
|
|
total_surfaces,
|
|
panel.usages.len()
|
|
)
|
|
})
|
|
.size(12)
|
|
.color(style::MUTED),
|
|
text_input("Filter diagram, occurrence, or alias", &panel.search)
|
|
.id(format!("diagram-usage-filter-{}", panel.token))
|
|
.padding(9)
|
|
.on_input(move |value| Message::DiagramUsage(Event::Search(token, value)))
|
|
.on_submit(message(Event::Activate(token))),
|
|
]
|
|
.spacing(10);
|
|
if let Some(notice) = &panel.notice {
|
|
content = content.push(text(notice).size(13));
|
|
}
|
|
if let Some(surface) = panel.destination {
|
|
content = content.push(
|
|
row![
|
|
action("All diagrams", message(Event::Destination(token, None))),
|
|
text(short(p.named(surface.id()), 55)).size(15),
|
|
]
|
|
.spacing(10),
|
|
);
|
|
for (index, usage) in targets
|
|
.into_iter()
|
|
.enumerate()
|
|
.skip(page * PAGE_SIZE)
|
|
.take(PAGE_SIZE)
|
|
{
|
|
let name = target_name(p, usage);
|
|
content = content.push(tooltip(
|
|
action(
|
|
&format!("{} · {}", usage.role, short(&name, 70)),
|
|
message(Event::Choose(token, usage.clone())),
|
|
)
|
|
.width(Fill)
|
|
.style(if panel.cursor == index {
|
|
style::selected
|
|
} else {
|
|
style::nav
|
|
}),
|
|
container(text(name).size(13))
|
|
.padding(10)
|
|
.max_width(680)
|
|
.style(style::card),
|
|
tooltip::Position::Top,
|
|
));
|
|
}
|
|
} else {
|
|
for (index, surface) in surfaces
|
|
.into_iter()
|
|
.enumerate()
|
|
.skip(page * PAGE_SIZE)
|
|
.take(PAGE_SIZE)
|
|
{
|
|
let targets = matched.iter().filter(|u| u.surface == surface).count();
|
|
let name = format!(
|
|
"{} · {} (@{}) · {} representations",
|
|
surface.category(p),
|
|
p.named(surface.id()),
|
|
alias(p, surface.id()),
|
|
targets
|
|
);
|
|
let layer = p
|
|
.diagrams
|
|
.get(&surface.id())
|
|
.map(|d| d.layer)
|
|
.or_else(|| p.layer_of(surface.id()))
|
|
.map(|l| l.to_string())
|
|
.unwrap_or_default();
|
|
content = content.push(tooltip(
|
|
action(
|
|
&format!(
|
|
"{} · {} · {} · {}",
|
|
surface.category(p),
|
|
layer,
|
|
short(p.named(surface.id()), 34),
|
|
targets
|
|
),
|
|
message(Event::Destination(token, Some(surface))),
|
|
)
|
|
.width(Fill)
|
|
.style(if panel.cursor == index {
|
|
style::selected
|
|
} else {
|
|
style::nav
|
|
}),
|
|
container(text(name).size(13))
|
|
.padding(10)
|
|
.max_width(680)
|
|
.style(style::card),
|
|
tooltip::Position::Top,
|
|
));
|
|
}
|
|
}
|
|
if panel.loading {
|
|
content = content.push(text("Finding diagram representations…").size(13));
|
|
} else if count == 0 {
|
|
content = content.push(text(if panel.usages.is_empty() {
|
|
"No currently rendered representation found. Folded or filtered objects and unexpanded reuse contents are excluded."
|
|
} else { "No results match this filter." }).size(13));
|
|
}
|
|
let mut paging = row![
|
|
text(format!(
|
|
"Page {} of {} · {} matches",
|
|
page + 1,
|
|
last + 1,
|
|
count
|
|
))
|
|
.size(12)
|
|
.width(Fill)
|
|
]
|
|
.spacing(8);
|
|
if page > 0 {
|
|
paging = paging.push(action("Previous", message(Event::Page(token, page - 1))));
|
|
}
|
|
if page < last {
|
|
paging = paging.push(action("Next", message(Event::Page(token, page + 1))));
|
|
}
|
|
content = content.push(paging).push(text("↑ ↓ choose · Enter opens · Escape closes. Source and saved view settings are preserved.").size(12).color(style::MUTED));
|
|
widget::stack![
|
|
base,
|
|
widget::opaque(
|
|
container(
|
|
container(content)
|
|
.padding(22)
|
|
.width((app.window_size.width - 80.).clamp(620., 820.))
|
|
.style(style::card)
|
|
)
|
|
.center(Fill)
|
|
.style(|_| container::Style {
|
|
background: Some(iced::Color::from_rgba(0.08, 0.12, 0.18, 0.38).into()),
|
|
..Default::default()
|
|
})
|
|
)
|
|
]
|
|
.into()
|
|
}
|