Skip to main content

rosace_widgets/tree/
hero_tag.rs

1use super::hero;
2use super::{Children, LayoutCtx, PaintCtx, Widget};
3
4/// Wraps a widget with a stable tag for Hero/shared-element morphing across
5/// a screen transition (D108/Phase 26 Step 5). Outside an active transition
6/// this is a total pass-through — same paint output as not wrapping at all.
7/// While `ScreenTransitionView` has a transition in flight, a `Hero` on the
8/// outgoing screen and one with the SAME tag on the incoming screen morph
9/// into a single floating copy that flies between their two rects; see
10/// `hero.rs` for the mechanism.
11pub struct Hero<W: Widget> {
12    tag: String,
13    inner: W,
14}
15
16impl<W: Widget> Hero<W> {
17    pub fn new(tag: impl Into<String>, inner: W) -> Self {
18        Self { tag: tag.into(), inner }
19    }
20}
21
22impl<W: Widget + Send + Sync + 'static> Widget for Hero<W> {
23    fn children(&self) -> Children<'_> {
24        Children::One(&self.inner)
25    }
26
27    fn layout(&self, ctx: &LayoutCtx) -> rosace_core::types::Size {
28        self.inner.layout(ctx)
29    }
30
31    fn paint(&self, ctx: &mut PaintCtx) {
32        let rect = ctx.rect;
33        match hero::active_role() {
34            Some(role) => {
35                // Suppressed here — captured instead. `ScreenTransitionView`
36                // paints the morphed floating copy on top once both sides
37                // of the transition have painted.
38                let picture = ctx.capture(rect, |cctx| self.inner.paint(cctx));
39                hero::register(self.tag.clone(), role, rect, picture);
40            }
41            None => {
42                self.inner.paint(&mut ctx.child(rect));
43            }
44        }
45    }
46}
47
48/// Builder sugar: `.hero_tag("id")` on any widget. Blanket-implemented,
49/// same shape as [`super::OverlayApi`]/[`super::PressApi`].
50pub trait HeroApi: Widget + Sized + Send + Sync + 'static {
51    fn hero_tag(self, tag: impl Into<String>) -> Hero<Self> {
52        Hero::new(tag, self)
53    }
54}
55
56impl<W: Widget + Send + Sync + 'static> HeroApi for W {}