iris: add positioned text overflow
This commit is contained in:
1 parent
1f15125992
commit
a475ae772f
14 files changed
+735
-31
No files matched your search
@@ -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)]
|
||||
|
||||
Reference in new issue
Block a user