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
// 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::{AdaptConfigCx, AdaptEventCx, AdaptEvents, Map, MapAny, Reserve, WithLabel};
use kas::cast::{Cast, CastFloat};
use kas::dir::Directional;
use kas::geom::Vec2;
use kas::layout::{AxisInfo, SizeRules};
use kas::text::AccessString;
use kas::theme::SizeCx;
#[allow(unused)] use kas::Events;
use kas::Widget;
use std::fmt::Debug;
/// Provides `.map_any()`
///
/// TODO: move to `AdaptWidget` with `where Self::Data == ()` constraint
/// once supported (Rust#20041).
pub trait AdaptWidgetAny: Widget<Data = ()> + Sized {
/// Map any input data to `()`
///
/// Returns a wrapper around the input widget.
#[must_use]
fn map_any<A>(self) -> MapAny<A, Self> {
MapAny::new(self)
}
}
impl<W: Widget<Data = ()>> AdaptWidgetAny for W {}
/// Provides some convenience methods on widgets
pub trait AdaptWidget: Widget + Sized {
/// Map data type via a function
///
/// Returns a wrapper around the input widget.
#[must_use]
fn map<A, F>(self, f: F) -> Map<A, Self, F>
where
F: for<'a> Fn(&'a A) -> &'a Self::Data,
{
Map::new(self, f)
}
/// Call the given closure on [`Events::configure`]
///
/// Returns a wrapper around the input widget.
#[must_use]
fn on_configure<F>(self, f: F) -> AdaptEvents<Self>
where
F: Fn(&mut AdaptConfigCx, &mut Self) + 'static,
{
AdaptEvents::new(self).on_configure(f)
}
/// Call the given closure on [`Events::update`]
///
/// Returns a wrapper around the input widget.
#[must_use]
fn on_update<F>(self, f: F) -> AdaptEvents<Self>
where
F: Fn(&mut AdaptConfigCx, &mut Self, &Self::Data) + 'static,
{
AdaptEvents::new(self).on_update(f)
}
/// Add a handler on message of type `M`
///
/// Where access to input data is required, use [`Self::on_messages`] instead.
///
/// Returns a wrapper around the input widget.
#[must_use]
fn on_message<M, H>(self, handler: H) -> AdaptEvents<Self>
where
M: Debug + 'static,
H: Fn(&mut AdaptEventCx, &mut Self, M) + 'static,
{
AdaptEvents::new(self).on_message(handler)
}
/// Add a generic message handler
///
/// Returns a wrapper around the input widget.
#[must_use]
fn on_messages<H>(self, handler: H) -> AdaptEvents<Self>
where
H: Fn(&mut AdaptEventCx, &mut Self, &Self::Data) + 'static,
{
AdaptEvents::new(self).on_messages(handler)
}
/// Construct a wrapper, setting minimum size in pixels
///
/// The input size is scaled by the scale factor.
///
/// Returns a wrapper around the input widget.
#[must_use]
fn with_min_size_px(self, w: i32, h: i32) -> Reserve<Self> {
let size = Vec2(w.cast(), h.cast());
Reserve::new(self, move |sizer: SizeCx, axis: AxisInfo| {
let size = size.extract(axis) * sizer.scale_factor();
SizeRules::fixed(size.cast_ceil(), (0, 0))
})
}
/// Construct a wrapper, setting minimum size in Em
///
/// This depends on the font size, though not the exact font in use.
///
/// Returns a wrapper around the input widget.
#[must_use]
fn with_min_size_em(self, w: f32, h: f32) -> Reserve<Self> {
let size = Vec2(w, h);
Reserve::new(self, move |sizer: SizeCx, axis: AxisInfo| {
let size = size.extract(axis) * sizer.dpem();
SizeRules::fixed(size.cast_ceil(), (0, 0))
})
}
/// Construct a wrapper widget adding a label
///
/// Returns a wrapper around the input widget.
#[must_use]
fn with_label<D, T>(self, direction: D, label: T) -> WithLabel<Self, D>
where
D: Directional,
T: Into<AccessString>,
{
WithLabel::new_dir(self, direction, label)
}
}
impl<W: Widget> AdaptWidget for W {}