content.rs
raw
//! [`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<dyn Fn(&mut WidgetTree, WidgetId)>);
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(..)")
}
}