vizia_core/views/badge.rs
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
use crate::prelude::*;
/// Enum which represents the placement of a badge on its parent.
#[derive(Default, Debug, Clone, Copy, Data, PartialEq)]
pub enum BadgePlacement {
/// The badge should be placed at the top-left of the view.
TopLeft,
/// The badge should be placed at the top of the view.
Top,
/// The badge should be placed at the top-right of the view.
#[default]
TopRight,
/// The badge should be placed at the left of the view.
Left,
/// The badge should be placed at the right of the view.
Right,
/// The badge should be placed at the bottom-left of the view.
BottomLeft,
/// The badge should be placed at the bottom of the view.
Bottom,
/// The badge should be placed at the bottom-right of the view.
BottomRight,
}
impl_res_simple!(BadgePlacement);
/// A Badge view for showing notifications, counts, or status information.
#[derive(Lens)]
pub struct Badge {
placement: Option<BadgePlacement>,
}
impl Badge {
fn common<F>(cx: &mut Context, content: F) -> Handle<Self>
where
F: FnOnce(&mut Context),
{
Self { placement: None }.build(cx, content).bind(
Badge::placement,
|mut handle, placement| {
if let Some(placement) = placement.get(&handle) {
let (t, b) = match placement {
BadgePlacement::TopLeft | BadgePlacement::TopRight => {
(Stretch(1.0), Percentage(85.35))
}
BadgePlacement::Top => (Stretch(1.0), Percentage(100.0)),
BadgePlacement::Bottom => (Percentage(100.0), Stretch(1.0)),
BadgePlacement::BottomLeft | BadgePlacement::BottomRight => {
(Percentage(85.35), Stretch(1.0))
}
BadgePlacement::Left | BadgePlacement::Right => {
(Stretch(1.0), Stretch(1.0))
}
};
let (l, r) = match placement {
BadgePlacement::TopLeft | BadgePlacement::BottomLeft => {
(Stretch(1.0), Percentage(85.35))
}
BadgePlacement::TopRight | BadgePlacement::BottomRight => {
(Percentage(85.35), Stretch(1.0))
}
BadgePlacement::Left => (Stretch(1.0), Percentage(100.0)),
BadgePlacement::Right => (Percentage(100.0), Stretch(1.0)),
BadgePlacement::Top | BadgePlacement::Bottom => {
(Stretch(1.0), Stretch(1.0))
}
};
handle = handle.top(t).bottom(b).left(l).right(r);
let translate = match placement {
BadgePlacement::TopLeft => (Percentage(50.0), Percentage(50.0)),
BadgePlacement::Top => (Percentage(0.0), Percentage(50.0)),
BadgePlacement::TopRight => (Percentage(-50.0), Percentage(50.0)),
BadgePlacement::BottomLeft => (Percentage(50.0), Percentage(-50.0)),
BadgePlacement::Bottom => (Percentage(0.0), Percentage(-50.0)),
BadgePlacement::BottomRight => (Percentage(-50.0), Percentage(-50.0)),
BadgePlacement::Left => (Percentage(50.0), Percentage(0.0)),
BadgePlacement::Right => (Percentage(-50.0), Percentage(0.0)),
};
handle.translate(translate);
}
},
)
}
/// Creates an empty badge.
///
/// ```
/// # use vizia_core::prelude::*;
/// # let cx = &mut Context::default();
/// Avatar::new(cx, |cx|{
/// Svg::new(cx, ICON_USER);
/// })
/// .badge(|cx| Badge::empty(cx).class("error"));
/// ```
pub fn empty(cx: &mut Context) -> Handle<Self> {
Self::common(cx, |_| {})
}
/// Creates a new badge with the provided content.
///
/// ```
/// # use vizia_core::prelude::*;
/// # let cx = &mut Context::default();
/// Avatar::new(cx, |cx|{
/// Svg::new(cx, ICON_USER);
/// })
/// .badge(|cx| Badge::new(|cx| Label::new("2")));
/// ```
pub fn new<F, V>(cx: &mut Context, content: F) -> Handle<Self>
where
F: FnOnce(&mut Context) -> Handle<V>,
V: View,
{
Self::common(cx, |cx| {
(content)(cx);
})
}
}
impl View for Badge {
fn element(&self) -> Option<&'static str> {
Some("badge")
}
}
impl Handle<'_, Badge> {
/// Sets the placement of a badge relative to its parent. Accepts a value of, or lens to, a [BadgePlacement].
pub fn placement<U: Into<BadgePlacement>>(self, placement: impl Res<U>) -> Self {
self.bind(placement, |handle, val| {
let placement = val.get(&handle).into();
handle.modify(|badge| badge.placement = Some(placement));
})
}
}