use std::marker::PhantomData;
use crate::widget::prelude::*;
use crate::widget::WidgetWrapper;
use crate::{Data, Lens, Point, WidgetPod};
use tracing::instrument;
pub trait ScopePolicy {
type In: Data;
type State: Data;
type Transfer: ScopeTransfer<In = Self::In, State = Self::State>;
fn create(self, inner: &Self::In) -> (Self::State, Self::Transfer);
}
pub trait ScopeTransfer {
type In: Data;
type State: Data;
fn read_input(&self, state: &mut Self::State, input: &Self::In);
fn write_back_input(&self, state: &Self::State, input: &mut Self::In);
}
pub struct DefaultScopePolicy<F: FnOnce(Transfer::In) -> Transfer::State, Transfer: ScopeTransfer> {
make_state: F,
transfer: Transfer,
}
impl<F: FnOnce(Transfer::In) -> Transfer::State, Transfer: ScopeTransfer>
DefaultScopePolicy<F, Transfer>
{
pub fn new(make_state: F, transfer: Transfer) -> Self {
DefaultScopePolicy {
make_state,
transfer,
}
}
}
impl<F: FnOnce(In) -> State, L: Lens<State, In>, In: Data, State: Data>
DefaultScopePolicy<F, LensScopeTransfer<L, In, State>>
{
pub fn from_lens(make_state: F, lens: L) -> Self {
Self::new(make_state, LensScopeTransfer::new(lens))
}
}
impl<F: FnOnce(Transfer::In) -> Transfer::State, Transfer: ScopeTransfer> ScopePolicy
for DefaultScopePolicy<F, Transfer>
{
type In = Transfer::In;
type State = Transfer::State;
type Transfer = Transfer;
fn create(self, input: &Self::In) -> (Self::State, Self::Transfer) {
let state = (self.make_state)(input.clone());
(state, self.transfer)
}
}
pub struct LensScopeTransfer<L: Lens<State, In>, In, State> {
lens: L,
phantom_in: PhantomData<In>,
phantom_state: PhantomData<State>,
}
impl<L: Lens<State, In>, In, State> LensScopeTransfer<L, In, State> {
pub fn new(lens: L) -> Self {
LensScopeTransfer {
lens,
phantom_in: PhantomData::default(),
phantom_state: PhantomData::default(),
}
}
}
impl<L: Lens<State, In>, In: Data, State: Data> ScopeTransfer for LensScopeTransfer<L, In, State> {
type In = In;
type State = State;
fn read_input(&self, state: &mut State, data: &In) {
self.lens.with_mut(state, |inner| {
if !inner.same(data) {
*inner = data.clone()
}
});
}
fn write_back_input(&self, state: &State, data: &mut In) {
self.lens.with(state, |inner| {
if !inner.same(data) {
*data = inner.clone();
}
});
}
}
enum ScopeContent<SP: ScopePolicy> {
Policy {
policy: Option<SP>,
},
Transfer {
state: SP::State,
transfer: SP::Transfer,
},
}
pub struct Scope<SP: ScopePolicy, W: Widget<SP::State>> {
content: ScopeContent<SP>,
inner: WidgetPod<SP::State, W>,
}
impl<SP: ScopePolicy, W: Widget<SP::State>> Scope<SP, W> {
pub fn new(policy: SP, inner: W) -> Self {
Scope {
content: ScopeContent::Policy {
policy: Some(policy),
},
inner: WidgetPod::new(inner),
}
}
pub fn state(&self) -> Option<&SP::State> {
if let ScopeContent::Transfer { ref state, .. } = &self.content {
Some(state)
} else {
None
}
}
pub fn state_mut(&mut self) -> Option<&mut SP::State> {
if let ScopeContent::Transfer { ref mut state, .. } = &mut self.content {
Some(state)
} else {
None
}
}
fn with_state<V>(
&mut self,
data: &SP::In,
mut f: impl FnMut(&mut SP::State, &mut WidgetPod<SP::State, W>) -> V,
) -> V {
match &mut self.content {
ScopeContent::Policy { policy } => {
let (mut state, policy) = policy.take().unwrap().create(data);
let v = f(&mut state, &mut self.inner);
self.content = ScopeContent::Transfer {
state,
transfer: policy,
};
v
}
ScopeContent::Transfer {
ref mut state,
transfer,
} => {
transfer.read_input(state, data);
f(state, &mut self.inner)
}
}
}
fn write_back_input(&mut self, data: &mut SP::In) {
if let ScopeContent::Transfer { state, transfer } = &mut self.content {
transfer.write_back_input(state, data)
}
}
}
impl<
F: FnOnce(Transfer::In) -> Transfer::State,
Transfer: ScopeTransfer,
W: Widget<Transfer::State>,
> Scope<DefaultScopePolicy<F, Transfer>, W>
{
pub fn from_function(make_state: F, transfer: Transfer, inner: W) -> Self {
Self::new(DefaultScopePolicy::new(make_state, transfer), inner)
}
}
impl<In: Data, State: Data, F: Fn(In) -> State, L: Lens<State, In>, W: Widget<State>>
Scope<DefaultScopePolicy<F, LensScopeTransfer<L, In, State>>, W>
{
pub fn from_lens(make_state: F, lens: L, inner: W) -> Self {
Self::new(DefaultScopePolicy::from_lens(make_state, lens), inner)
}
}
impl<SP: ScopePolicy, W: Widget<SP::State>> Widget<SP::In> for Scope<SP, W> {
#[instrument(name = "Scope", level = "trace", skip(self, ctx, event, data, env))]
fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut SP::In, env: &Env) {
self.with_state(data, |state, inner| inner.event(ctx, event, state, env));
self.write_back_input(data);
ctx.request_update()
}
#[instrument(name = "Scope", level = "trace", skip(self, ctx, event, data, env))]
fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &SP::In, env: &Env) {
self.with_state(data, |state, inner| inner.lifecycle(ctx, event, state, env));
}
#[instrument(name = "Scope", level = "trace", skip(self, ctx, _old_data, data, env))]
fn update(&mut self, ctx: &mut UpdateCtx, _old_data: &SP::In, data: &SP::In, env: &Env) {
self.with_state(data, |state, inner| inner.update(ctx, state, env));
}
#[instrument(name = "Scope", level = "trace", skip(self, ctx, bc, data, env))]
fn layout(
&mut self,
ctx: &mut LayoutCtx,
bc: &BoxConstraints,
data: &SP::In,
env: &Env,
) -> Size {
self.with_state(data, |state, inner| {
let size = inner.layout(ctx, bc, state, env);
inner.set_origin(ctx, Point::ORIGIN);
size
})
}
#[instrument(name = "Scope", level = "trace", skip(self, ctx, data, env))]
fn paint(&mut self, ctx: &mut PaintCtx, data: &SP::In, env: &Env) {
self.with_state(data, |state, inner| inner.paint_raw(ctx, state, env));
}
}
impl<SP: ScopePolicy, W: Widget<SP::State>> WidgetWrapper for Scope<SP, W> {
widget_wrapper_pod_body!(W, inner);
}