use crate::{State, Tone}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Act<'a> { /// What the control says. pub label: &'a str, /// The key that reaches it where a host has keys. /// /// The one member written for a terminal before there was one. A webview /// hangs it off `accesskey` or ignores it; a terminal has nothing else to /// offer, so this is the whole of how a control is reached there. pub key: Option<&'a str>, /// What pressing it means. [`Tone::Danger`] is the destructive one. pub tone: Tone, /// Disabled, or nothing said. /// /// [`State::Disabled`] is what changes what a renderer may do: see /// [`State::suppresses_interaction`], which is what says a disabled control /// is drawn and not reachable. A control's focus is not sayable here at /// all: see the crate header, "Reach, focus and the focus ring". pub state: Option, /// A sentence that is always true of this control, shown rather than hunted /// for. /// /// Standing help, not a message and not a tooltip. Half the hosts that read /// this have no pointer: a hover is one spelling of it, and the shipped /// apps reached for that spelling only because egui and a browser both had /// one. What is being said is that the sentence is true, never that it is /// hidden until a pointer arrives. /// /// # Why it is here rather than a layer up /// /// A hint left to `quasi_router::Act` alone means each renderer draws it /// for itself: `makeover_tui` had no hint to read, so quasi-tui built /// the muted line, and quasi-immediate called `on_hover_text` outside /// [`crate::Act`] rather than inside it. `Field::hint` was here the whole /// time, so the same idea sat at two layers depending on which thing /// carried it, and a host that was not quasi could say it of a field and /// not of a control. /// /// What kept it out was price rather than doubt: this crate declares /// `links`, so a member here moves 25 manifests across 12 repos. That is a /// release's forward-fix pass, which is a cost and was being read as a /// barrier. /// /// # What a renderer owes it /// /// Somewhere to put it, or nothing. Dropping it is legitimate; drawing it /// *instead of* the label is not, and neither is drawing it in a way that /// takes it out of the accessible tree, which is the failure `title` alone /// has on a browser. Nothing may live only in a hint. /// /// `None` is a control whose label is the whole of it, which is nearly all /// of them. pub hint: Option<&'a str>, } impl<'a> Act<'a> { /// An ordinary control, reachable, with no key. #[must_use] pub const fn new(label: &'a str) -> Self { Self { label, key: None, tone: Tone::Neutral, state: None, hint: None, } } /// The sentence that is always true of it; see [`hint`](Self::hint). /// /// A renderer with nowhere to put it drops it, so this must never be the /// only place a fact appears. #[must_use] pub const fn hinted(mut self, hint: &'a str) -> Self { self.hint = Some(hint); self } /// The key that reaches it. #[must_use] pub const fn key(mut self, key: &'a str) -> Self { self.key = Some(key); self } /// What pressing it means. #[must_use] pub const fn tone(mut self, tone: Tone) -> Self { self.tone = tone; self } /// Focus, or disabled. #[must_use] pub const fn state(mut self, state: State) -> Self { self.state = Some(state); self } /// Whether the control is drawn and does not answer. #[must_use] pub fn disabled(&self) -> bool { self.state.is_some_and(State::suppresses_interaction) } }