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
// 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 //! Widget extension traits use super::Widget; use crate::adapter::{MapResponse, Reserve, WithLabel}; use crate::dir::Directional; use crate::draw::SizeHandle; use crate::event::{Manager, Response}; use crate::layout::{AxisInfo, SizeRules}; use crate::text::AccelString; #[allow(unused)] use kas::Layout; /// Provides some convenience methods on widgets pub trait WidgetExt: Widget { /// Construct a wrapper widget which maps messages from this widget /// /// Responses from this widget with a message payload are mapped with `f`. fn map_msg<F, M>(self, f: F) -> MapResponse<Self, M> where F: Fn(&mut Manager, Self::Msg) -> M + 'static, Self: Sized, { MapResponse::new(self, move |mgr, msg| Response::Msg(f(mgr, msg))) } /// Construct a wrapper widget which discards messages from this widget /// /// Responses from this widget with a message payload are mapped to /// [`Response::None`]. fn map_msg_discard<M>(self) -> MapResponse<Self, M> where Self: Sized, { MapResponse::new(self, |_, _| Response::None) } /// Construct a wrapper widget which maps message responses from this widget /// /// Responses from this widget with a message payload are mapped with `f`. fn map_response<F, M>(self, f: F) -> MapResponse<Self, M> where F: Fn(&mut Manager, Self::Msg) -> Response<M> + 'static, Self: Sized, { MapResponse::new(self, f) } /// Construct a wrapper widget which reserves extra space /// /// The closure `reserve` should generate `SizeRules` on request, just like /// [`Layout::size_rules`]. This can be done by instantiating a temporary /// widget, for example: ///``` /// use kas::widget::Label; /// use kas::prelude::*; /// /// let label = Label::new("0").with_reserve(|size_handle, axis| { /// Label::new("00000").size_rules(size_handle, axis) /// }); ///``` /// Alternatively one may use virtual pixels: ///``` /// use kas::widget::Filler; /// use kas::prelude::*; /// /// let label = Filler::new().with_reserve(|size_handle, axis| { /// let size = size_handle.pixels_from_em(5.0); /// SizeRules::fixed(size.cast_nearest(), (0, 0)) /// }); ///``` /// The resulting `SizeRules` will be the max of those for the inner widget /// and the result of the `reserve` closure. fn with_reserve<R>(self, r: R) -> Reserve<Self, R> where R: FnMut(&mut dyn SizeHandle, AxisInfo) -> SizeRules + 'static, Self: Sized, { Reserve::new(self, r) } /// Construct a wrapper widget adding a label fn with_label<D, T>(self, direction: D, label: T) -> WithLabel<Self, D> where D: Directional, T: Into<AccelString>, Self: Sized, { WithLabel::new_with_direction(direction, self, label) } } impl<W: Widget + ?Sized> WidgetExt for W {} /// Provides a convenient `.boxed()` method on implementors // // Note: this is distinct from WidgetExt to allow this variant on M: Menu + Sized: // fn boxed(self) -> Box<dyn Menu<Msg = M::Msg>> pub trait Boxed<T: ?Sized> { /// Boxing method fn boxed(self) -> Box<T>; } impl<W: Widget + Sized> Boxed<dyn Widget<Msg = W::Msg>> for W { fn boxed(self) -> Box<dyn Widget<Msg = W::Msg>> { Box::new(self) } }