use kas::prelude::*;
use kas::text::format::FormattableText;
use kas::theme::{self, TextClass};
#[impl_self]
mod Text {
#[widget]
#[layout(self.text)]
pub struct Text<A, T: Default + FormattableText + 'static = String> {
core: widget_core!(),
text: theme::Text<T>,
text_fn: Box<dyn Fn(&ConfigCx, &A, &mut T) -> bool>,
}
impl Default for Self
where
for<'a> &'a A: Into<T>,
{
fn default() -> Self {
Text {
core: Default::default(),
text: theme::Text::new(T::default(), TextClass::Standard, true),
text_fn: Box::new(|_, data, text| {
let new_text = data.into();
let changed = new_text != *text;
if changed {
*text = new_text;
}
changed
}),
}
}
}
impl<A> Text<A, String> {
pub fn new_str(as_str: impl Fn(&A) -> &str + 'static) -> Self {
Text {
core: Default::default(),
text: theme::Text::new(String::new(), TextClass::Standard, true),
text_fn: Box::new(move |_, data, text| {
let s = as_str(data);
let changed = *text != *s;
if changed {
*text = s.into();
}
changed
}),
}
}
}
impl Self {
pub fn new_gen(gen_text: impl Fn(&ConfigCx, &A) -> T + 'static) -> Self {
Text {
core: Default::default(),
text: theme::Text::new(T::default(), TextClass::Standard, true),
text_fn: Box::new(move |cx, data, text| {
let new_text = gen_text(cx, data);
let changed = new_text != *text;
if changed {
*text = new_text;
}
changed
}),
}
}
pub fn new_update(update_text: impl Fn(&ConfigCx, &A, &mut T) -> bool + 'static) -> Self {
Text {
core: Default::default(),
text: theme::Text::new(T::default(), TextClass::Standard, true),
text_fn: Box::new(update_text),
}
}
#[inline]
pub fn class(&self) -> TextClass {
self.text.class()
}
#[inline]
pub fn set_class(&mut self, class: TextClass) {
self.text.set_class(class);
}
#[inline]
pub fn with_class(mut self, class: TextClass) -> Self {
self.text.set_class(class);
self
}
#[inline]
pub fn wrap(&self) -> bool {
self.text.wrap()
}
#[inline]
pub fn set_wrap(&mut self, wrap: bool) {
self.text.set_wrap(wrap);
}
#[inline]
pub fn with_wrap(mut self, wrap: bool) -> Self {
self.text.set_wrap(wrap);
self
}
#[inline]
pub fn text(&self) -> &theme::Text<T> {
&self.text
}
#[inline]
pub fn as_str(&self) -> &str {
self.text.as_str()
}
}
impl Layout for Self {
fn set_rect(&mut self, cx: &mut SizeCx, rect: Rect, hints: AlignHints) {
self.text
.set_rect(cx, rect, hints.combine(AlignHints::VERT_CENTER));
}
}
impl Tile for Self {
fn role(&self, _: &mut dyn RoleCx) -> Role<'_> {
Role::Label(self.text.as_str())
}
}
impl Events for Self {
type Data = A;
fn configure(&mut self, cx: &mut ConfigCx) {
self.text.configure(&mut cx.size_cx());
}
fn update(&mut self, cx: &mut ConfigCx, data: &A) {
if (self.text_fn)(cx, data, self.text.text_mut()) {
self.text.require_reprepare();
self.text.reprepare_action(cx);
}
}
}
}
#[macro_export]
macro_rules! format_text {
($data:ident, $($arg:tt)*) => {
$crate::Text::new_gen(move |_, $data| format!($($arg)*))
};
($data:ident : $data_ty:ty , $($arg:tt)*) => {
$crate::Text::new_gen(move |_, $data : $data_ty| format!($($arg)*))
};
($lit:literal $(, $arg:tt)*) => {
$crate::Text::new_gen(move |_, data| format!($lit $(, $arg)*, data))
};
}
#[macro_export]
macro_rules! format_label {
($data:ident, $($arg:tt)*) => {
$crate::Text::new_gen(move |_, $data| format!($($arg)*))
.with_class(::kas::theme::TextClass::Label)
};
($data:ident : $data_ty:ty , $($arg:tt)*) => {
$crate::Text::new_gen(move |_, $data : $data_ty| format!($($arg)*))
.with_class(::kas::theme::TextClass::Label)
};
($lit:literal $(, $arg:tt)*) => {
$crate::Text::new_gen(move |_, data| format!($lit $(, $arg)*, data))
.with_class(::kas::theme::TextClass::Label)
};
}