use crate::rail::{ChildCard, Cohort, Notch};
use crate::theme;
const RULE_FAINT: f32 = 0.45;
const RULE_HEIGHT: f32 = 6.0;
const CARD_WIDTH: f32 = 320.0;
const RULE_HOVER: &str = "a commit boundary — the id is the commit the next turn's model call read. \
Click to see this conversation as it stood then, and to fork from here. No key of \
its own: Tab reaches the rule, Space pins it.";
const PINNED_HOVER: &str = "this conversation as it stood here. Click to come back to now — or Tab to the rule \
and press Space, which is the same release.";
const CARD_HOVER: &str = "An agent dispatched from this point. Its label says what it inherited: \
`from here` carries this conversation's history, `from config/…` starts clean. Click to open it, \
or walk the roster onto it with ↑ / ↓.";
const COHORT_HOVER: &str = "Candidates tried from this same mark. Nothing groups them but where they were born — \
compare them side by side and open whichever you want, by click or by the ↑ / ↓ \
roster walk.";
pub(super) fn rule(ui: &mut egui::Ui, index: usize, notch: &Notch, selected: &mut Option<usize>) {
let pinned = *selected == Some(index);
let hue = if pinned { theme::BRAZEN } else { theme::ASH };
let hover = if pinned { PINNED_HOVER } else { RULE_HOVER };
let hit = ui
.horizontal(|ui| {
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
let id = ui
.add(
egui::Label::new(egui::RichText::new(notch.short()).monospace().color(hue))
.sense(egui::Sense::click()),
)
.on_hover_text(hover);
let (rect, line) = ui.allocate_exact_size(
egui::vec2(ui.available_width(), RULE_HEIGHT),
egui::Sense::click(),
);
ui.painter().hline(
rect.x_range(),
rect.center().y,
egui::Stroke::new(1.0, hue.gamma_multiply(RULE_FAINT)),
);
id.clicked() || line.on_hover_text(hover).clicked()
})
.inner
})
.inner;
if hit {
*selected = if pinned { None } else { Some(index) };
}
}
pub(super) fn cohort(ui: &mut egui::Ui, cohort: &Cohort) -> Option<String> {
let mut follow = None;
if cohort.fanned() {
let shared = cohort.common.clone().unwrap_or_else(|| "mixed".to_owned());
ui.horizontal(|ui| {
ui.colored_label(theme::SIGIL, format!("×{}", cohort.members.len()));
ui.weak(shared);
})
.response
.on_hover_text(COHORT_HOVER);
}
for member in &cohort.members {
if let Some(id) = card(ui, member, cohort.common.is_none() || !cohort.fanned()) {
follow = Some(id);
}
}
follow
}
fn card(ui: &mut egui::Ui, card: &ChildCard, own_fork: bool) -> Option<String> {
let (glyph, hue, phrase) = theme::state_badge(card.state);
let mut follow = None;
egui::Frame::group(ui.style())
.show(ui, |ui| {
ui.set_width(CARD_WIDTH);
let clicked = ui
.add(egui::Label::new(&card.name).sense(egui::Sense::click()))
.on_hover_text(CARD_HOVER)
.clicked();
if clicked {
follow = Some(card.agent_id.clone());
}
if own_fork {
ui.weak(&card.fork);
}
ui.horizontal(|ui| {
ui.colored_label(hue, glyph).on_hover_text(phrase);
ui.weak(format!("{} tokens", card.tokens));
});
if let Some(tail) = &card.tail {
ui.colored_label(theme::SPECTRE, tail);
}
})
.response
.on_hover_text(CARD_HOVER);
follow
}