1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2020 The Druid Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A [`Widget`] that uses a [`Lens`] to change the [`Data`] of its child.

use std::marker::PhantomData;

use crate::debug_state::DebugState;
use crate::widget::prelude::*;
use crate::widget::WidgetWrapper;
use crate::{Data, Lens};

use tracing::{instrument, trace};

/// A wrapper for its widget subtree to have access to a part
/// of its parent's data.
///
/// Every widget in Druid is instantiated with access to data of some
/// type; the root widget has access to the entire application data.
/// Often, a part of the widget hierarchy is only concerned with a part
/// of that data. The `LensWrap` widget is a way to "focus" the data
/// reference down, for the subtree. One advantage is performance;
/// data changes that don't intersect the scope of the lens aren't
/// propagated.
///
/// Another advantage is generality and reuse. If a widget (or tree of
/// widgets) is designed to work with some chunk of data, then with a
/// lens that same code can easily be reused across all occurrences of
/// that chunk within the application state.
///
/// This wrapper takes a [`Lens`] as an argument, which is a specification
/// of a struct field, or some other way of narrowing the scope.
pub struct LensWrap<T, U, L, W> {
    child: W,
    lens: L,
    // The following is a workaround for otherwise getting E0207.
    // the 'in' data type of the lens
    phantom_u: PhantomData<U>,
    // the 'out' data type of the lens
    phantom_t: PhantomData<T>,
}

impl<T, U, L, W> LensWrap<T, U, L, W> {
    /// Wrap a widget with a lens.
    ///
    /// When the lens has type `Lens<T, U>`, the child widget has data
    /// of type `U`, and the wrapped widget has data of type `T`.
    pub fn new(child: W, lens: L) -> LensWrap<T, U, L, W> {
        LensWrap {
            child,
            lens,
            phantom_u: Default::default(),
            phantom_t: Default::default(),
        }
    }

    /// Get a reference to the lens.
    pub fn lens(&self) -> &L {
        &self.lens
    }

    /// Get a mutable reference to the lens.
    pub fn lens_mut(&mut self) -> &mut L {
        &mut self.lens
    }
}

impl<T, U, L, W> Widget<T> for LensWrap<T, U, L, W>
where
    T: Data,
    U: Data,
    L: Lens<T, U>,
    W: Widget<U>,
{
    #[instrument(name = "LensWrap", level = "trace", skip(self, ctx, event, data, env))]
    fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env) {
        let child = &mut self.child;
        self.lens
            .with_mut(data, |data| child.event(ctx, event, data, env))
    }

    #[instrument(name = "LensWrap", level = "trace", skip(self, ctx, event, data, env))]
    fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &T, env: &Env) {
        let child = &mut self.child;
        self.lens
            .with(data, |data| child.lifecycle(ctx, event, data, env))
    }

    #[instrument(
        name = "LensWrap",
        level = "trace",
        skip(self, ctx, old_data, data, env)
    )]
    fn update(&mut self, ctx: &mut UpdateCtx, old_data: &T, data: &T, env: &Env) {
        let child = &mut self.child;
        let lens = &self.lens;
        lens.with(old_data, |old_data| {
            lens.with(data, |data| {
                if ctx.has_requested_update() || !old_data.same(data) || ctx.env_changed() {
                    child.update(ctx, old_data, data, env);
                } else {
                    trace!("skipping child update");
                }
            })
        })
    }

    #[instrument(name = "LensWrap", level = "trace", skip(self, ctx, bc, data, env))]
    fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &T, env: &Env) -> Size {
        let child = &mut self.child;
        self.lens
            .with(data, |data| child.layout(ctx, bc, data, env))
    }

    #[instrument(name = "LensWrap", level = "trace", skip(self, ctx, data, env))]
    fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) {
        let child = &mut self.child;
        self.lens.with(data, |data| child.paint(ctx, data, env));
    }

    fn id(&self) -> Option<WidgetId> {
        self.child.id()
    }

    fn debug_state(&self, data: &T) -> DebugState {
        let child_state = self.lens.with(data, |data| self.child.debug_state(data));
        DebugState {
            display_name: "LensWrap".to_string(),
            children: vec![child_state],
            ..Default::default()
        }
    }
}

impl<T, U, L, W> WidgetWrapper for LensWrap<T, U, L, W> {
    widget_wrapper_body!(W, child);
}