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
// 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. //! //! [`Widget`]: ../trait.Widget.html //! [`Lens`]: ../trait.Lens.html //! [`Data`]: ../trait.Data.html use std::marker::PhantomData; use crate::widget::prelude::*; use crate::{Data, Lens}; /// 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. /// /// [`Lens`]: trait.Lens.html pub struct LensWrap<T, U, L, W> { inner: 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 inner widget has data /// of type `U`, and the wrapped widget has data of type `T`. pub fn new(inner: W, lens: L) -> LensWrap<T, U, L, W> { LensWrap { inner, lens, phantom_u: Default::default(), phantom_t: Default::default(), } } } 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>, { fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env) { let inner = &mut self.inner; self.lens .with_mut(data, |data| inner.event(ctx, event, data, env)) } fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &T, env: &Env) { let inner = &mut self.inner; self.lens .with(data, |data| inner.lifecycle(ctx, event, data, env)) } fn update(&mut self, ctx: &mut UpdateCtx, old_data: &T, data: &T, env: &Env) { let inner = &mut self.inner; 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() { inner.update(ctx, old_data, data, env); } }) }) } fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &T, env: &Env) -> Size { let inner = &mut self.inner; self.lens .with(data, |data| inner.layout(ctx, bc, data, env)) } fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) { let inner = &mut self.inner; self.lens.with(data, |data| inner.paint(ctx, data, env)); } fn id(&self) -> Option<WidgetId> { self.inner.id() } }