Skip to main content

Module decorator

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 Widget defaults are derived from another method (tooltip_target_at calls tooltip, collect_damage calls needs_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, draw and handle_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 with register_node.
  • Method calls. A decorator is both a Decorator and, through the blanket impl, a Widget. 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 Widget methods and forwarding the rest. See the module docs.

Functions§

register_node
Point node at widget in the host’s node map, replacing the inner widget’s own registration. For a Decorator that overrides a hook the host reaches through the node map (a cursor shape, a tooltip, undo status); call it from build_layout after the inner widget built its node.