iris: add positioned text overflow

This commit is contained in:
iris committed 2026-09-12 19:58:02 -04:00
1 parent 1f15125992
commit a475ae772f
14 files changed
+735 -31

No files matched your search

+90 -6
View File
@@ -1,5 +1,5 @@
use crate::{
Align, GlyphAtlas, GlyphKey, PaintId, PlacedGlyph, RegionAlign, Textures, WidgetId,
Align, GlyphAtlas, GlyphKey, Len, PaintId, PlacedGlyph, RegionAlign, Textures, WidgetId,
util::{Resources, RscHandle, StrongRscId, Vec2, WeakRscId},
};
use parley::{
@@ -584,10 +584,39 @@ pub struct TextAttrs {
pub font_size: f32,
pub line_height: f32,
pub family: String,
pub wrap: bool,
pub overflow: TextOverflow,
pub overflow_position: Len,
pub align: RegionAlign,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum TextOverflow {
#[default]
Visible,
Wrap,
Hidden,
Ellipsis,
}
#[derive(Clone, PartialEq)]
struct TextShapeAttrs {
color: PaintId,
font_size: f32,
line_height: f32,
family: String,
}
impl From<&TextAttrs> for TextShapeAttrs {
fn from(attrs: &TextAttrs) -> Self {
Self {
color: attrs.color.clone(),
font_size: attrs.font_size,
line_height: attrs.line_height,
family: attrs.family.clone(),
}
}
}
pub const LINE_HEIGHT_MULT: f32 = 1.1;
impl Default for TextAttrs {
@@ -598,7 +627,8 @@ impl Default for TextAttrs {
font_size: size,
line_height: size * LINE_HEIGHT_MULT,
family: SANS_SERIF.to_owned(),
wrap: false,
overflow: TextOverflow::Visible,
overflow_position: Len::ZERO,
align: Align::CENTER_LEFT,
}
}
@@ -611,7 +641,7 @@ pub struct TextBuffer {
text: String,
layout: Layout<PaintId>,
spans: Vec<SpanStyle>,
shaped: Option<(TextAttrs, Option<f32>, f32)>,
shaped: Option<(TextShapeAttrs, Option<f32>, f32)>,
}
impl TextBuffer {
@@ -671,7 +701,8 @@ impl TextBuffer {
width: Option<f32>,
density: f32,
) {
if self.shaped.as_ref() == Some(&(attrs.clone(), width, density)) {
let shape_attrs = TextShapeAttrs::from(attrs);
if self.shaped.as_ref() == Some(&(shape_attrs.clone(), width, density)) {
return;
}
let base_family = data.resolve_family(&attrs.family);
@@ -719,7 +750,7 @@ impl TextBuffer {
self.layout.break_all_lines(width);
self.layout
.align(Alignment::Start, AlignmentOptions::default());
self.shaped = Some((attrs.clone(), width, density));
self.shaped = Some((shape_attrs, width, density));
}
fn invalidate(&mut self) {
@@ -762,8 +793,10 @@ pub struct RenderedText {
pub struct TextRsc {
buffer: TextBuffer,
ellipsis_buffer: TextBuffer,
attrs: TextAttrs,
rendered: Option<RenderedText>,
ellipsis_rendered: Option<(TextShapeAttrs, f32, RenderedText)>,
width: Option<f32>,
density: f32,
owner: Option<WidgetId>,
@@ -773,8 +806,10 @@ impl TextRsc {
fn new(buffer: TextBuffer, attrs: TextAttrs) -> Self {
Self {
buffer,
ellipsis_buffer: TextBuffer::new(""),
attrs,
rendered: None,
ellipsis_rendered: None,
width: None,
density: 0.0,
owner: None,
@@ -784,6 +819,8 @@ impl TextRsc {
fn invalidate(&mut self) {
self.buffer.invalidate();
self.rendered = None;
self.ellipsis_buffer.invalidate();
self.ellipsis_rendered = None;
}
}
@@ -885,6 +922,34 @@ impl TextResources {
resource.rendered = Some(rendered.clone());
(rendered, true)
}
fn render_ellipsis(
&mut self,
resource: &mut TextRsc,
owner: WidgetId,
textures: &mut Textures,
density: f32,
) -> (RenderedText, bool) {
let shape_attrs = TextShapeAttrs::from(&resource.attrs);
let atlas_generation = self.data.atlas.generation();
resource.owner = Some(owner);
if let Some((cached_attrs, cached_density, rendered)) = &resource.ellipsis_rendered
&& cached_attrs == &shape_attrs
&& *cached_density == density
&& rendered.generation == atlas_generation
{
return (rendered.clone(), false);
}
let rendered = self.data.render(
&mut resource.ellipsis_buffer,
&resource.attrs,
None,
textures,
density,
);
resource.ellipsis_rendered = Some((shape_attrs, density, rendered.clone()));
(rendered, true)
}
}
impl Default for TextResources {
@@ -961,6 +1026,14 @@ impl TextHandle {
RefMut::map(resource, |resource| &mut resource.attrs)
}
pub fn set_overflow_position(&mut self, position: Len) {
self.rsc.get_mut().attrs.overflow_position = position;
}
pub fn set_overflow(&mut self, overflow: TextOverflow) {
self.rsc.get_mut().attrs.overflow = overflow;
}
pub fn rendered(&self) -> Option<RenderedText> {
self.rsc.get().rendered.clone()
}
@@ -996,6 +1069,17 @@ impl TextHandle {
let mut resource = self.rsc.get_mut_shared();
resources.render(&mut resource, width, owner, textures, density)
}
pub fn render_ellipsis(
&self,
owner: WidgetId,
textures: &mut Textures,
density: f32,
) -> (RenderedText, bool) {
let mut resources = self.resources.borrow_mut();
let mut resource = self.rsc.get_mut_shared();
resources.render_ellipsis(&mut resource, owner, textures, density)
}
}
#[cfg(test)]
+8
View File
@@ -422,6 +422,14 @@ impl<'a> Painter<'a> {
rendered
}
pub fn render_ellipsis(&mut self, text: &TextHandle) -> RenderedText {
let density = self.render_state.density;
let ui: &mut UiData = self.rsc.ui_mut();
let (rendered, prepared) = text.render_ellipsis(self.id, &mut ui.textures, density);
self.render_state.shape_count += u64::from(prepared);
rendered
}
fn atlas_generation(&self) -> u64 {
self.rsc.ui().text.borrow().atlas.generation()
}