summaryrefslogtreecommitdiffstats
path: root/graphics/src/text
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón <hector@hecrj.dev>2024-07-18 22:39:49 +0200
committerLibravatar GitHub <noreply@github.com>2024-07-18 22:39:49 +0200
commit23ad15391c88f562c90f4344d3949f76b6f9caf9 (patch)
tree883f5752e3cfe516ee22048015e9255b502bb04e /graphics/src/text
parent616689ca54942a13aac3615e571ae995ad4571b6 (diff)
parent06acb740fba1889c6a9fb48dfa3ae3aaac1df3ab (diff)
downloadiced-23ad15391c88f562c90f4344d3949f76b6f9caf9.tar.gz
iced-23ad15391c88f562c90f4344d3949f76b6f9caf9.tar.bz2
iced-23ad15391c88f562c90f4344d3949f76b6f9caf9.zip
Merge pull request #2508 from iced-rs/feature/rich-text
`rich_text` and `markdown` widgets
Diffstat (limited to 'graphics/src/text')
-rw-r--r--graphics/src/text/paragraph.rs160
1 files changed, 101 insertions, 59 deletions
diff --git a/graphics/src/text/paragraph.rs b/graphics/src/text/paragraph.rs
index a5fefe8f..37fa97f2 100644
--- a/graphics/src/text/paragraph.rs
+++ b/graphics/src/text/paragraph.rs
@@ -1,8 +1,8 @@
//! Draw paragraphs.
use crate::core;
use crate::core::alignment;
-use crate::core::text::{Hit, LineHeight, Shaping, Text};
-use crate::core::{Font, Pixels, Point, Size};
+use crate::core::text::{Hit, Shaping, Span, Text};
+use crate::core::{Font, Point, Size};
use crate::text;
use std::fmt;
@@ -10,11 +10,11 @@ use std::sync::{self, Arc};
/// A bunch of text.
#[derive(Clone, PartialEq)]
-pub struct Paragraph(Option<Arc<Internal>>);
+pub struct Paragraph(Arc<Internal>);
+#[derive(Clone)]
struct Internal {
buffer: cosmic_text::Buffer,
- content: String, // TODO: Reuse from `buffer` (?)
font: Font,
shaping: Shaping,
horizontal_alignment: alignment::Horizontal,
@@ -52,9 +52,7 @@ impl Paragraph {
}
fn internal(&self) -> &Arc<Internal> {
- self.0
- .as_ref()
- .expect("paragraph should always be initialized")
+ &self.0
}
}
@@ -62,7 +60,7 @@ impl core::text::Paragraph for Paragraph {
type Font = Font;
fn with_text(text: Text<&str>) -> Self {
- log::trace!("Allocating paragraph: {}", text.content);
+ log::trace!("Allocating plain paragraph: {}", text.content);
let mut font_system =
text::font_system().write().expect("Write font system");
@@ -90,9 +88,8 @@ impl core::text::Paragraph for Paragraph {
let min_bounds = text::measure(&buffer);
- Self(Some(Arc::new(Internal {
+ Self(Arc::new(Internal {
buffer,
- content: text.content.to_owned(),
font: text.font,
horizontal_alignment: text.horizontal_alignment,
vertical_alignment: text.vertical_alignment,
@@ -100,59 +97,107 @@ impl core::text::Paragraph for Paragraph {
bounds: text.bounds,
min_bounds,
version: font_system.version(),
- })))
+ }))
+ }
+
+ fn with_spans(text: Text<&[Span<'_>]>) -> Self {
+ log::trace!("Allocating rich paragraph: {:?}", text.content);
+
+ let mut font_system =
+ text::font_system().write().expect("Write font system");
+
+ let mut buffer = cosmic_text::Buffer::new(
+ font_system.raw(),
+ cosmic_text::Metrics::new(
+ text.size.into(),
+ text.line_height.to_absolute(text.size).into(),
+ ),
+ );
+
+ buffer.set_size(
+ font_system.raw(),
+ Some(text.bounds.width),
+ Some(text.bounds.height),
+ );
+
+ buffer.set_rich_text(
+ font_system.raw(),
+ text.content.iter().map(|span| {
+ let attrs = cosmic_text::Attrs::new();
+
+ let attrs = if let Some(font) = span.font {
+ attrs
+ .family(text::to_family(font.family))
+ .weight(text::to_weight(font.weight))
+ .stretch(text::to_stretch(font.stretch))
+ .style(text::to_style(font.style))
+ } else {
+ text::to_attributes(text.font)
+ };
+
+ let attrs = match (span.size, span.line_height) {
+ (None, None) => attrs,
+ _ => {
+ let size = span.size.unwrap_or(text.size);
+
+ attrs.metrics(cosmic_text::Metrics::new(
+ size.into(),
+ span.line_height
+ .unwrap_or(text.line_height)
+ .to_absolute(size)
+ .into(),
+ ))
+ }
+ };
+
+ let attrs = if let Some(color) = span.color {
+ attrs.color(text::to_color(color))
+ } else {
+ attrs
+ };
+
+ (span.text.as_ref(), attrs)
+ }),
+ text::to_attributes(text.font),
+ text::to_shaping(text.shaping),
+ );
+
+ let min_bounds = text::measure(&buffer);
+
+ Self(Arc::new(Internal {
+ buffer,
+ font: text.font,
+ horizontal_alignment: text.horizontal_alignment,
+ vertical_alignment: text.vertical_alignment,
+ shaping: text.shaping,
+ bounds: text.bounds,
+ min_bounds,
+ version: font_system.version(),
+ }))
}
fn resize(&mut self, new_bounds: Size) {
- let paragraph = self
- .0
- .take()
- .expect("paragraph should always be initialized");
-
- match Arc::try_unwrap(paragraph) {
- Ok(mut internal) => {
- let mut font_system =
- text::font_system().write().expect("Write font system");
-
- internal.buffer.set_size(
- font_system.raw(),
- Some(new_bounds.width),
- Some(new_bounds.height),
- );
-
- internal.bounds = new_bounds;
- internal.min_bounds = text::measure(&internal.buffer);
-
- self.0 = Some(Arc::new(internal));
- }
- Err(internal) => {
- let metrics = internal.buffer.metrics();
-
- // If there is a strong reference somewhere, we recompute the
- // buffer from scratch
- *self = Self::with_text(Text {
- content: &internal.content,
- bounds: internal.bounds,
- size: Pixels(metrics.font_size),
- line_height: LineHeight::Absolute(Pixels(
- metrics.line_height,
- )),
- font: internal.font,
- horizontal_alignment: internal.horizontal_alignment,
- vertical_alignment: internal.vertical_alignment,
- shaping: internal.shaping,
- });
- }
- }
+ let paragraph = Arc::make_mut(&mut self.0);
+
+ let mut font_system =
+ text::font_system().write().expect("Write font system");
+
+ paragraph.buffer.set_size(
+ font_system.raw(),
+ Some(new_bounds.width),
+ Some(new_bounds.height),
+ );
+
+ paragraph.bounds = new_bounds;
+ paragraph.min_bounds = text::measure(&paragraph.buffer);
}
- fn compare(&self, text: Text<&str>) -> core::text::Difference {
+ fn compare(&self, text: Text<()>) -> core::text::Difference {
let font_system = text::font_system().read().expect("Read font system");
let paragraph = self.internal();
let metrics = paragraph.buffer.metrics();
if paragraph.version != font_system.version
- || paragraph.content != text.content
|| metrics.font_size != text.size.0
|| metrics.line_height != text.line_height.to_absolute(text.size).0
|| paragraph.font != text.font
@@ -231,7 +276,7 @@ impl core::text::Paragraph for Paragraph {
impl Default for Paragraph {
fn default() -> Self {
- Self(Some(Arc::new(Internal::default())))
+ Self(Arc::new(Internal::default()))
}
}
@@ -240,7 +285,6 @@ impl fmt::Debug for Paragraph {
let paragraph = self.internal();
f.debug_struct("Paragraph")
- .field("content", &paragraph.content)
.field("font", &paragraph.font)
.field("shaping", &paragraph.shaping)
.field("horizontal_alignment", &paragraph.horizontal_alignment)
@@ -253,8 +297,7 @@ impl fmt::Debug for Paragraph {
impl PartialEq for Internal {
fn eq(&self, other: &Self) -> bool {
- self.content == other.content
- && self.font == other.font
+ self.font == other.font
&& self.shaping == other.shaping
&& self.horizontal_alignment == other.horizontal_alignment
&& self.vertical_alignment == other.vertical_alignment
@@ -271,7 +314,6 @@ impl Default for Internal {
font_size: 1.0,
line_height: 1.0,
}),
- content: String::new(),
font: Font::default(),
shaping: Shaping::default(),
horizontal_alignment: alignment::Horizontal::Left,
@@ -298,7 +340,7 @@ pub struct Weak {
impl Weak {
/// Tries to update the reference into a [`Paragraph`].
pub fn upgrade(&self) -> Option<Paragraph> {
- self.raw.upgrade().map(Some).map(Paragraph)
+ self.raw.upgrade().map(Paragraph)
}
}