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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
// 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 in the LICENSE-APACHE file or at:
// https://www.apache.org/licenses/LICENSE-2.0
//! Adapt widget
use super::{AdaptConfigCx, AdaptEventCx};
use kas::prelude::*;
use linear_map::LinearMap;
use std::fmt::Debug;
use std::marker::PhantomData;
impl_scope! {
/// Data adaption node
///
/// Where [`Map`] allows mapping to a sub-set of input data, `Adapt` allows
/// mapping to a super-set (including internal storage). Further, `Adapt`
/// supports message handlers which mutate internal storage.
#[autoimpl(Deref, DerefMut using self.inner)]
#[autoimpl(Scrollable using self.inner where W: trait)]
#[widget {
layout = self.inner;
}]
pub struct Adapt<A, W: Widget<Data = S>, S: Debug> {
core: widget_core!(),
state: S,
#[widget(&self.state)]
inner: W,
configure_handler: Option<Box<dyn Fn(&mut AdaptConfigCx, &mut S)>>,
update_handler: Option<Box<dyn Fn(&mut AdaptConfigCx, &mut S, &A)>>,
timer_handlers: LinearMap<u64, Box<dyn Fn(&mut AdaptEventCx, &mut S, &A) -> bool>>,
message_handlers: Vec<Box<dyn Fn(&mut AdaptEventCx, &mut S, &A) -> bool>>,
}
impl Self {
/// Construct over `inner` with additional `state`
#[inline]
pub fn new(inner: W, state: S) -> Self {
Adapt {
core: Default::default(),
state,
inner,
configure_handler: None,
update_handler: None,
timer_handlers: LinearMap::new(),
message_handlers: vec![],
}
}
/// Add a handler to be called on configuration
pub fn on_configure<F>(mut self, handler: F) -> Self
where
F: Fn(&mut AdaptConfigCx, &mut S) + 'static,
{
debug_assert!(self.configure_handler.is_none());
self.configure_handler = Some(Box::new(handler));
self
}
/// Add a handler to be called on update of input data
///
/// Children will be updated after the handler is called.
pub fn on_update<F>(mut self, handler: F) -> Self
where
F: Fn(&mut AdaptConfigCx, &mut S, &A) + 'static,
{
debug_assert!(self.update_handler.is_none());
self.update_handler = Some(Box::new(handler));
self
}
/// Set a timer handler
///
/// The closure should return `true` if state was updated.
pub fn on_timer<H>(mut self, timer_id: u64, handler: H) -> Self
where
H: Fn(&mut AdaptEventCx, &mut S, &A) -> bool + 'static,
{
debug_assert!(self.timer_handlers.get(&timer_id).is_none());
self.timer_handlers.insert(timer_id, Box::new(handler));
self
}
/// Add a handler on message of type `M`
///
/// Children will be updated whenever this handler is invoked.
///
/// Where access to input data (from parent widgets) is required,
/// use [`Self::on_messages`] instead.
pub fn on_message<M, H>(self, handler: H) -> Self
where
M: Debug + 'static,
H: Fn(&mut AdaptEventCx, &mut S, M) + 'static,
{
self.on_messages(move |cx, state, _data| {
if let Some(m) = cx.try_pop() {
handler(cx, state, m);
true
} else {
false
}
})
}
/// Add a generic message handler
///
/// The closure should return `true` if state was updated.
pub fn on_messages<H>(mut self, handler: H) -> Self
where
H: Fn(&mut AdaptEventCx, &mut S, &A) -> bool + 'static,
{
self.message_handlers.push(Box::new(handler));
self
}
}
impl Events for Self {
type Data = A;
fn configure(&mut self, cx: &mut ConfigCx) {
if let Some(handler) = self.configure_handler.as_ref() {
let mut cx = AdaptConfigCx::new(cx, self.id());
handler(&mut cx, &mut self.state);
}
}
fn update(&mut self, cx: &mut ConfigCx, data: &A) {
if let Some(handler) = self.update_handler.as_ref() {
let mut cx = AdaptConfigCx::new(cx, self.id());
handler(&mut cx, &mut self.state, data);
}
}
fn handle_event(&mut self, cx: &mut EventCx, data: &Self::Data, event: Event) -> IsUsed {
match event {
Event::Timer(timer_id) => {
if let Some(handler) = self.timer_handlers.get(&timer_id) {
let mut cx = AdaptEventCx::new(cx, self.id());
if handler(&mut cx, &mut self.state, data) {
cx.update(self.as_node(data));
}
Used
} else {
Unused
}
}
_ => Unused,
}
}
fn handle_messages(&mut self, cx: &mut EventCx, data: &A) {
let mut update = false;
let mut cx = AdaptEventCx::new(cx, self.id());
for handler in self.message_handlers.iter() {
update |= handler(&mut cx, &mut self.state, data);
}
if update {
cx.update(self.as_node(data));
}
}
}
}
impl_scope! {
/// Data mapping
///
/// This is a generic data-mapping widget. See also [`Adapt`], [`MapAny`](super::MapAny).
#[autoimpl(Deref, DerefMut using self.inner)]
#[autoimpl(Scrollable using self.inner where W: trait)]
#[widget {
Data = A;
layout = self.inner;
}]
pub struct Map<A, W: Widget, F>
where
F: for<'a> Fn(&'a A) -> &'a W::Data,
{
core: widget_core!(),
#[widget((self.map_fn)(data))]
inner: W,
map_fn: F,
_data: PhantomData<A>,
}
impl Self {
/// Construct
///
/// - Over an `inner` widget
/// - And `map_fn` mapping to the inner widget's data type
pub fn new(inner: W, map_fn: F) -> Self {
Map {
core: Default::default(),
inner,
map_fn,
_data: PhantomData,
}
}
}
}