use core::marker::PhantomData;
use crate::{
environment::LayoutEnvironment,
event::{EventContext, EventResult},
layout::ResolvedLayout,
primitives::{Dimensions, Frame, ProposedDimensions, Size},
render::Container,
transition::Opacity,
view::{Event, ViewLayout, ViewMarker},
};
#[derive(Debug, Clone)]
pub struct GeometryReader<ViewFn, Inner> {
inner: ViewFn,
_view_marker: PhantomData<Inner>,
}
impl<ViewFn: Fn(Size) -> Inner, Inner: ViewMarker> GeometryReader<ViewFn, Inner> {
#[allow(missing_docs)]
#[must_use]
pub fn new(inner: ViewFn) -> Self {
Self {
inner,
_view_marker: PhantomData,
}
}
}
impl<ViewFn, Inner: ViewMarker> ViewMarker for GeometryReader<ViewFn, Inner> {
type Renderables = Container<Inner::Renderables>;
type Transition = Opacity;
}
impl<Captures, Inner, ViewFn> ViewLayout<Captures> for GeometryReader<ViewFn, Inner>
where
Captures: ?Sized,
Inner: ViewLayout<Captures>,
ViewFn: Fn(Size) -> Inner,
{
type State = Option<Inner::State>;
type Sublayout = Dimensions;
fn transition(&self) -> Self::Transition {
Opacity
}
fn build_state(&self, _captures: &mut Captures) -> Self::State {
None
}
fn layout(
&self,
offer: &ProposedDimensions,
_env: &impl LayoutEnvironment,
_captures: &mut Captures,
_state: &mut Self::State,
) -> ResolvedLayout<Self::Sublayout> {
let size = offer.resolve_most_flexible(0, 1);
ResolvedLayout {
resolved_size: size,
sublayouts: size,
}
}
fn render_tree(
&self,
layout: &Self::Sublayout,
origin: crate::primitives::Point,
env: &impl LayoutEnvironment,
captures: &mut Captures,
state: &mut Self::State,
) -> Self::Renderables {
let size = (*layout).into();
let view = (self.inner)(size);
let proposal = (*layout).into();
let frame = Frame::new(origin, size);
if let Some(inner_state) = state {
let layout = view.layout(&proposal, env, captures, inner_state);
Container::new(
frame,
view.render_tree(&layout.sublayouts, origin, env, captures, inner_state),
)
} else {
let mut inner_state = view.build_state(captures);
let layout = view.layout(&proposal, env, captures, &mut inner_state);
let renderables =
view.render_tree(&layout.sublayouts, origin, env, captures, &mut inner_state);
*state = Some(inner_state);
Container::new(frame, renderables)
}
}
fn handle_event(
&self,
event: &Event,
context: &EventContext,
render_tree: &mut Self::Renderables,
captures: &mut Captures,
state: &mut Self::State,
) -> EventResult {
let view = (self.inner)(render_tree.frame.size);
if let Some(inner_state) = state {
view.handle_event(
event,
context,
&mut render_tree.child,
captures,
inner_state,
)
} else {
let mut inner_state = view.build_state(captures);
let result = view.handle_event(
event,
context,
&mut render_tree.child,
captures,
&mut inner_state,
);
*state = Some(inner_state);
result
}
}
}