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
// 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
//! Size reservation
use kas::prelude::*;
/// Requirements on parameter to [`Reserve`]
///
/// Note: this type is implemented for the expected [`FnMut`],
/// i.e. methods and closures are supported.
/// A trait is used to support custom *named* objects since currently closures
/// can't be named and trait methods cannot return unnamed objects (impl Trait
/// is only supported on functions and inherent methods).
pub trait FnSizeRules {
fn size_rules(&mut self, size_mgr: SizeMgr, axis: AxisInfo) -> SizeRules;
}
impl<F> FnSizeRules for F
where
for<'a> F: FnMut(SizeMgr<'a>, AxisInfo) -> SizeRules,
{
#[inline]
fn size_rules(&mut self, size_mgr: SizeMgr, axis: AxisInfo) -> SizeRules {
self(size_mgr, axis)
}
}
/// Parameterisation of [`Reserve`] using a function pointer
///
/// Since it is impossible to name closures, using [`Reserve`] where a type is
/// required (e.g. in a struct field) is only possible by making the containing
/// struct generic over this field, which may be undesirable. As an alternative
/// a function pointer may be preferred.
pub type ReserveP<W> = Reserve<W, fn(SizeMgr, AxisInfo) -> SizeRules>;
impl_scope! {
/// A generic widget for size reservations
///
/// In a few cases it is desirable to reserve more space for a widget than
/// required for the current content, e.g. if a label's text may change. This
/// widget can be used for this by wrapping the base widget.
///
/// Usually, this type will be constructed through one of the methods on
/// [`AdaptWidget`](crate::adapter::AdaptWidget).
#[autoimpl(Debug ignore self.reserve)]
#[autoimpl(Deref, DerefMut using self.inner)]
#[autoimpl(class_traits using self.inner where W: trait)]
#[derive(Clone, Default)]
#[widget{ derive = self.inner; }]
pub struct Reserve<W: Widget, R: FnSizeRules> {
pub inner: W,
reserve: R,
}
impl Self {
/// Construct a reserve
///
/// 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::Reserve;
/// use kas_widgets::Label;
/// use kas::prelude::*;
///
/// let label = Reserve::new(Label::new("0"), |size_mgr: SizeMgr<'_>, axis| {
/// Label::new("00000").size_rules(size_mgr, axis)
/// });
///```
/// Alternatively one may use virtual pixels:
///```
/// use kas_widgets::adapter::Reserve;
/// use kas_widgets::Filler;
/// use kas::prelude::*;
///
/// let label = Reserve::new(Filler::new(), |size_mgr: SizeMgr<'_>, axis| {
/// let size = i32::conv_ceil(size_mgr.scale_factor() * 100.0);
/// SizeRules::fixed(size, (0, 0))
/// });
///```
/// The resulting `SizeRules` will be the max of those for the inner widget
/// and the result of the `reserve` closure.
#[inline]
pub fn new(inner: W, reserve: R) -> Self {
Reserve { inner, reserve }
}
}
impl Layout for Self {
fn size_rules(&mut self, size_mgr: SizeMgr, axis: AxisInfo) -> SizeRules {
let inner_rules = self.inner.size_rules(size_mgr.re(), axis);
let reserve_rules = self.reserve.size_rules(size_mgr.re(), axis);
inner_rules.max(reserve_rules)
}
}
}