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
// 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::{FnSizeRules, MapMessage, Reserve, WithLabel};
use kas::cast::{Cast, CastFloat};
use kas::dir::Directional;
use kas::geom::Vec2;
use kas::layout::{AxisInfo, SizeRules};
use kas::text::AccelString;
use kas::theme::SizeMgr;
#[allow(unused)] use kas::Layout;
use kas::Widget;
use std::fmt::Debug;
/// Support type for [`AdaptWidget::with_min_size_px`]
pub struct WithMinSizePx(Vec2);
impl FnSizeRules for WithMinSizePx {
fn size_rules(&mut self, size_mgr: SizeMgr, axis: AxisInfo) -> SizeRules {
let size = self.0.extract(axis) * size_mgr.scale_factor();
SizeRules::fixed(size.cast_ceil(), (0, 0))
}
}
/// Support type for [`AdaptWidget::with_min_size_em`]
pub struct WithMinSizeEm(Vec2);
impl FnSizeRules for WithMinSizeEm {
fn size_rules(&mut self, size_mgr: SizeMgr, axis: AxisInfo) -> SizeRules {
let size = self.0.extract(axis) * size_mgr.dpem();
SizeRules::fixed(size.cast_ceil(), (0, 0))
}
}
/// Provides some convenience methods on widgets
pub trait AdaptWidget: Widget {
/// Construct a wrapper widget which maps a message of the given type
#[must_use]
fn map_msg<M: Debug, N: Debug, F>(self, f: F) -> MapMessage<Self, M, N, F>
where
Self: Sized,
F: FnMut(M) -> N,
{
MapMessage::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_widgets::adapter::AdaptWidget;
/// use kas::prelude::*;
/// use kas_widgets::Label;
///
/// let label = Label::new("0")
/// .with_reserve(|size_mgr, axis| Label::new("00000").size_rules(size_mgr, axis));
/// ```
/// Alternatively one may use virtual pixels:
///```
/// # use kas_widgets::adapter::AdaptWidget;
/// use kas::prelude::*;
/// use kas_widgets::Filler;
///
/// let label = Filler::new().with_reserve(|mgr, axis| {
/// kas::layout::LogicalSize(5.0, 5.0).to_rules(axis, mgr.scale_factor())
/// });
/// ```
/// The resulting `SizeRules` will be the max of those for the inner widget
/// and the result of the `reserve` closure.
#[must_use]
fn with_reserve<R>(self, r: R) -> Reserve<Self, R>
where
R: FnMut(SizeMgr, AxisInfo) -> SizeRules,
Self: Sized,
{
Reserve::new(self, r)
}
/// Construct a wrapper, setting minimum size in pixels
///
/// The input size is scaled by the scale factor.
#[must_use]
fn with_min_size_px(self, w: i32, h: i32) -> Reserve<Self, WithMinSizePx>
where
Self: Sized,
{
let size = Vec2(w.cast(), h.cast());
Reserve::new(self, WithMinSizePx(size))
}
/// Construct a wrapper, setting minimum size in Em
///
/// This depends on the font size, though not the exact font in use.
#[must_use]
fn with_min_size_em(self, w: f32, h: f32) -> Reserve<Self, WithMinSizeEm>
where
Self: Sized,
{
let size = Vec2(w, h);
Reserve::new(self, WithMinSizeEm(size))
}
/// Construct a wrapper widget adding a label
#[must_use]
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> AdaptWidget for W {}