//! [`ContentBuilder`]: a subtree that is built on demand, into a parent //! chosen at build time, as many times as it is asked for. //! //! This is what "deferred content" means concretely. A menu's rows are //! declared where the menu is written but must not exist until it opens, and //! must be built into the popup's overlay rather than under the title — so //! the consumers hand the widget one of these instead of mounting anything, //! and the tree calls it when the popup opens. //! //! It is deliberately not menu-private. A dropdown's list, a tooltip's body, //! and a dialog's content are the same problem, and a widget opts in through //! its [`Widget::defers_content`](crate::widget::Widget::defers_content) trait //! method rather than through new machinery — so an application's own widget //! can host deferred content exactly as a builtin does, and the `.gdw` need not //! mention it. //! //! The laziness is the point, and it is recursive: only the opened *path* //! exists. A submenu's rows are not built, do not lay out, shape no text, and //! subscribe to no signals until that submenu is opened — so a closed menu //! over a long list costs nothing, and does not make that list's updates more //! expensive for anything else. use std::rc::Rc; use crate::widget::{WidgetId, WidgetTree}; /// Builds a subtree under a given parent. /// /// Cloneable and callable repeatedly: a menu reopens, and each open builds /// fresh content. Both consumers produce one — the typed build closes over /// `Copy` signal handles and an `Rc` logic registry, the interpreter over its /// dynamic context — so neither needs to keep the subtree alive to keep the /// ability to rebuild it. #[derive(Clone)] pub struct ContentBuilder(Rc); impl ContentBuilder { pub fn new(build: impl Fn(&mut WidgetTree, WidgetId) + 'static) -> Self { Self(Rc::new(build)) } /// Build the content under `parent`. pub fn build(&self, tree: &mut WidgetTree, parent: WidgetId) { (self.0)(tree, parent); } } impl Default for ContentBuilder { /// Builds nothing — the standing-in value for a widget whose content has /// not been supplied (a `Menu` constructed directly in Rust, say). fn default() -> Self { Self::new(|_, _| {}) } } impl std::fmt::Debug for ContentBuilder { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("ContentBuilder(..)") } }