cushy/src/widgets/label.rs
Jonathan Johnson 6b8e5f886b
Update scroll example + work around cosmic_text
I decided scrolling a label would work better, so I loaded a source file
and noticed it wasn't rendering quite right in the label. It turns out
that the text wrapping was triggering despite the width in redraw being
the same as the measured amount. In short: sometimes the width I measure
can't be the width I set as the cosmic_text::Buffer size, because it
will cause it to wrap.

I've worked around it by caching the measured text for now. But it may
still show up in other situations and may require a more generalized
fix by seeing what else we can gleam from the glyphs being measured.
2023-11-01 15:43:56 -07:00

69 lines
2.1 KiB
Rust

use kludgine::figures::units::{Px, UPx};
use kludgine::figures::{Point, Size};
use kludgine::text::{MeasuredText, Text, TextOrigin};
use crate::context::GraphicsContext;
use crate::styles::components::TextColor;
use crate::value::{IntoValue, Value};
use crate::widget::Widget;
/// A read-only text widget.
#[derive(Debug)]
pub struct Label {
/// The contents of the label.
pub text: Value<String>,
prepared_text: Option<MeasuredText<Px>>,
}
impl Label {
/// Returns a new label that displays `text`.
pub fn new(text: impl IntoValue<String>) -> Self {
Self {
text: text.into_value(),
prepared_text: None,
}
}
}
impl Widget for Label {
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
self.text.redraw_when_changed(context);
let size = context.graphics.region().size;
let center = Point::from(size) / 2;
let styles = context.query_style(&[&TextColor]);
if let Some(measured) = &self.prepared_text {
context
.graphics
.draw_measured_text(measured, TextOrigin::Center, center, None, None);
} else {
self.text.map(|contents| {
context.graphics.draw_text(
Text::new(contents, styles.get_or_default(&TextColor))
.wrap_at(size.width)
.origin(TextOrigin::Center),
center,
None,
None,
);
});
}
}
fn measure(
&mut self,
available_space: Size<crate::ConstraintLimit>,
context: &mut GraphicsContext<'_, '_, '_, '_, '_>,
) -> Size<UPx> {
let width = available_space.width.max().try_into().unwrap_or(Px::MAX);
self.text.map(|contents| {
let measured = context
.graphics
.measure_text(Text::from(contents).wrap_at(width));
let size = measured.size.try_cast().unwrap_or_default();
self.prepared_text = Some(measured);
size
})
}
}