use crate::reply::convs::ConvRow;
use crate::ui::{Aim, Model, theme};
use theme::paint;
pub(crate) const STEP: f32 = 16.0;
const DEEPEST: u64 = 8;
pub const SHOW: &str = "show";
pub const HIDE: &str = "hide";
pub const SUBTREE_HELP: &str = "shows or hides the conversations under this one";
use super::SELECT_HELP;
pub(super) fn conversation(
ui: &mut egui::Ui,
model: &mut Model,
aim: &Aim,
row: &ConvRow,
rails: &[u64],
reveal: bool,
) {
let selected = model.conversation.as_ref() == Some(&row.root_id);
let state = super::rule(row);
let (glyph, ink) = super::mark(row);
let tone = theme::tone_ink(&row.tone);
let beneath = [
row.failure.clone().map(|failure| (failure, tone)),
Some(row.preview.clone())
.filter(|preview| !preview.is_empty())
.map(|preview| (preview, theme::INK_WEAK)),
]
.into_iter()
.flatten()
.map(|(said, ink)| (said, ink, egui::TextStyle::Body))
.collect();
let seat = paint::Row {
mark: (glyph, ink),
words: super::words(row),
ink: tone,
state,
chosen: selected,
indent: indent(row.depth),
aside: None,
beneath,
door: None,
help: SELECT_HELP.to_owned(),
}
.paint(ui);
crate::ui::act::tag(
&seat,
&[crate::verbs::TRANSCRIPT.word, crate::verbs::FOLLOW.word],
);
if selected && reveal {
seat.scroll_to_me(None);
}
if seat.clicked() {
model.select(&row.root_id.clone());
model.chose();
}
super::menu::show(&seat, model, aim, row);
subtree(ui, model, row);
connectors(ui, row, rails, seat.rect);
}
fn subtree(ui: &mut egui::Ui, model: &mut Model, row: &ConvRow) {
let Some(under) = row.members.checked_sub(1).filter(|under| *under > 0) else {
return;
};
let word = if model.subtree_open(&row.root_id) {
format!("{HIDE} {under}")
} else {
format!("{SHOW} {under}")
};
let seat = paint::row(
ui,
&word,
theme::INK_WEAK,
None,
false,
indent(row.depth) + STEP,
SUBTREE_HELP,
);
if seat.clicked() {
model.toggle_subtree(&row.root_id.clone());
}
}
fn connectors(ui: &egui::Ui, row: &ConvRow, rails: &[u64], seat: egui::Rect) {
let bottom = ui.cursor().min.y;
for level in rails {
paint::rail(ui, at_level(seat.min.x, *level), seat.min.y, bottom);
}
if row.depth > 0 {
paint::elbow(
ui,
at_level(seat.min.x, row.depth),
seat.min.y,
seat.min.y + theme::ROW / 2.0,
seat.min.x + theme::RULE + indent(row.depth) + theme::space::M,
);
}
}
fn at_level(left: f32, level: u64) -> f32 {
left + indent(level.saturating_sub(1)) + STEP / 2.0
}
pub(crate) fn indent(depth: u64) -> f32 {
(0..depth.min(DEEPEST)).fold(STEP, |at, _| at + STEP)
}