Module decorator
Expand description
Extending a widget without re-implementing it: the Decorator trait.
A widget that adds one behaviour to another — a diagnostic probe, an
app root that indexes its content for search, a surface host that
refreshes what it presents — should cost the hook it adds, not a hundred
lines of forwarding that silently go stale whenever Widget grows.
Implement Decorator instead of Widget: name the wrapped widget,
give the two accessors, and override only what changes. Every Widget
method has a default here that forwards to the inner widget, and a
blanket impl makes every decorator a Widget, so it can be boxed as an
Element, take part in any traversal, and implement
further traits that require Widget (such as
AppWidget).
struct Probe { content: Column }
impl ui::widget::Decorator for Probe {
type Inner = Column;
fn inner(&self) -> &Column { &self.content }
fn inner_mut(&mut self) -> &mut Column { &mut self.content }
fn native_input_snapshot(&self, doc: &AutoCommit, path: &ObjId) -> Option<serde_json::Value> {
Some(serde_json::json!({ "rect": format!("{:?}", self.content.get_rect()) }))
}
}§A decorator is its inner widget plus overrides
Nothing is forwarded “partly”: children forwards
too, so a host traversal meets the decorator in the inner widget’s place
and visits every node exactly once. The only methods that describe the
decorator rather than the inner widget are the identity ones:
concrete_type_name names the decorator’s type and
as_any and as_any_mut
downcast to the decorator itself unless overridden.
A boxed Element is wrapped with type Inner = dyn Widget; and accessors returning &(dyn Widget + 'static).
Four consequences are worth knowing:
- An override replaces the inner widget’s answer. Because the inner
widget is not visited separately, a decorator that adds to a
collecting hook (
resources,search_providers,take_control_invocation) includes the inner widget’s answer:let mut all = mine; all.extend(self.inner().resources(doc)); all. - Override the host’s entry point. Some
Widgetdefaults are derived from another method (tooltip_target_atcallstooltip,collect_damagecallsneeds_redraw). Here each forwards to the inner widget’s own method, so an override of the derived-from method alone is not what the host calls: override the entry point the host uses. Painting and input each have a single entry point,drawandhandle_event. - The decorator stands in for its inner widget’s layout node. The
inner widget registers itself in the node map during
build_layout; the decorator then takes that entry, so a host that reaches a widget through the map (an accessibility action, focused input, a cursor shape, a tooltip, undo status) meets the decorator in the inner widget’s place, and everything it does not override still reaches the inner widget. A node the inner widget handed to a widget of its own (a field it lays out as itself) stays that widget’s. A decorator that builds a node of its own around the inner one registers itself for it withregister_node. - Method calls. A decorator is both a
Decoratorand, through the blanket impl, aWidget. With both traits imported,self.get_rect()is ambiguous, so implement the trait by path (impl ui::widget::Decorator for ..) rather than importing it; the prelude deliberately does not export it.
Traits§
- Decorator
- A widget that extends another by overriding a few
Widgetmethods and forwarding the rest. See the module docs.
Functions§
- register_
node - Point
nodeatwidgetin the host’s node map, replacing the inner widget’s own registration. For aDecoratorthat overrides a hook the host reaches through the node map (a cursor shape, a tooltip, undo status); call it frombuild_layoutafter the inner widget built its node.