diff --git a/examples/responsive/src/main.rs b/examples/responsive/src/main.rs index d6c1a698..2fd4fb36 100644 --- a/examples/responsive/src/main.rs +++ b/examples/responsive/src/main.rs @@ -1,33 +1,67 @@ use floem::{ peniko::Color, + reactive::create_signal, responsive::{range, ScreenSize}, + style::TextOverflow, unit::UnitExt, view::View, - views::{label, stack, Decorators}, + views::{h_stack, label, stack, text, Decorators}, }; fn app_view() -> impl View { + let (is_text_overflown, set_is_text_overflown) = create_signal(false); + stack({ - (label(|| "Resize the window to see the magic").style(|s| { - s.border(1.0) - .border_radius(10.0) - .padding(10.0) - .margin_horiz(10.0) - .responsive(ScreenSize::XS, |s| s.background(Color::CYAN)) - .responsive(ScreenSize::SM, |s| s.background(Color::PURPLE)) - .responsive(ScreenSize::MD, |s| s.background(Color::ORANGE)) - .responsive(ScreenSize::LG, |s| s.background(Color::GREEN)) - .responsive(ScreenSize::XL, |s| s.background(Color::PINK)) - .responsive(ScreenSize::XXL, |s| s.background(Color::RED)) - .responsive(range(ScreenSize::XS..ScreenSize::LG), |s| { - s.width(90.0.pct()).max_width(500.0) - }) - .responsive( - // equivalent to: range(ScreenSize::LG..) - ScreenSize::LG | ScreenSize::XL | ScreenSize::XXL, - |s| s.width(300.0), - ) - }),) + ( + label(|| "Resize the window to see the magic").style(|s| { + s.border(1.0) + .border_radius(10.0) + .padding(10.0) + .margin_horiz(10.0) + .responsive(ScreenSize::XS, |s| s.background(Color::CYAN)) + .responsive(ScreenSize::SM, |s| s.background(Color::PURPLE)) + .responsive(ScreenSize::MD, |s| s.background(Color::ORANGE)) + .responsive(ScreenSize::LG, |s| s.background(Color::GREEN)) + .responsive(ScreenSize::XL, |s| s.background(Color::PINK)) + .responsive(ScreenSize::XXL, |s| s.background(Color::RED)) + .responsive(range(ScreenSize::XS..ScreenSize::LG), |s| { + s.width(90.0.pct()).max_width(500.0) + }) + .responsive( + // equivalent to: range(ScreenSize::LG..) + ScreenSize::LG | ScreenSize::XL | ScreenSize::XXL, + |s| s.width(300.0), + ) + }), + text( + "Long text that will overflow on smaller screens since the available width is less", + ) + .on_text_overflow(move |is_overflown| { + set_is_text_overflown.update(|overflown| *overflown = is_overflown); + }) + .style(move |s| { + s.background(Color::DIM_GRAY) + .padding(10.0) + .color(Color::WHITE_SMOKE) + .margin_top(30.) + .width_pct(70.0) + .font_size(20.0) + .max_width(800.) + .text_overflow(TextOverflow::Ellipsis) + }), + h_stack(( + text("The text fits in the available width?:"), + label(move || if is_text_overflown.get() { "No" } else { "Yes" }.to_string()) + .style(move |s| { + s.color(if is_text_overflown.get() { + Color::RED + } else { + Color::GREEN + }) + .font_bold() + }), + )), + ) }) .style(|s| { s.size(100.pct(), 100.pct()) diff --git a/src/views/label.rs b/src/views/label.rs index f7f294c1..79436747 100644 --- a/src/views/label.rs +++ b/src/views/label.rs @@ -24,6 +24,11 @@ prop_extracter! { } } +struct TextOverflowListener { + last_is_overflown: Option, + on_change_fn: Box, +} + pub struct Label { data: ViewData, label: String, @@ -32,6 +37,7 @@ pub struct Label { available_text: Option, available_width: Option, available_text_layout: Option, + text_overflow_listener: Option, font: FontProps, style: Extracter, } @@ -46,6 +52,7 @@ impl Label { available_text: None, available_width: None, available_text_layout: None, + text_overflow_listener: None, font: FontProps::default(), style: Default::default(), } @@ -70,6 +77,14 @@ pub fn label(label: impl Fn() -> S + 'static) -> Label { } impl Label { + pub fn on_text_overflow(mut self, is_text_overflown_fn: impl Fn(bool) + 'static) -> Self { + self.text_overflow_listener = Some(TextOverflowListener { + on_change_fn: Box::new(is_text_overflown_fn), + last_is_overflown: None, + }); + self + } + fn get_attrs_list(&self) -> AttrsList { let mut attrs = Attrs::new().color(self.style.color().unwrap_or(Color::BLACK)); if let Some(font_size) = self.font.size() { @@ -245,6 +260,16 @@ impl View for Label { self.available_text_layout = None; } } + + if let Some(listener) = self.text_overflow_listener.as_mut() { + let was_overflown = listener.last_is_overflown; + let now_overflown = width > available_width; + + if was_overflown != Some(now_overflown) { + (listener.on_change_fn)(now_overflown); + listener.last_is_overflown = Some(now_overflown); + } + } None }