Merge branch 'master' into beacon
This commit is contained in:
commit
ebfcb65841
41 changed files with 805 additions and 589 deletions
|
|
@ -130,6 +130,9 @@ pub enum SurfaceError {
|
|||
/// There is no more memory left to allocate a new frame.
|
||||
#[error("There is no more memory left to allocate a new frame")]
|
||||
OutOfMemory,
|
||||
/// Acquiring a texture failed with a generic error.
|
||||
#[error("Acquiring a texture failed with a generic error")]
|
||||
Other,
|
||||
}
|
||||
|
||||
/// Contains information about the graphics (e.g. graphics adapter, graphics backend).
|
||||
|
|
|
|||
|
|
@ -10,11 +10,14 @@ pub struct Text {
|
|||
/// The contents of the text
|
||||
pub content: String,
|
||||
/// The position of the text relative to the alignment properties.
|
||||
///
|
||||
/// By default, this position will be relative to the top-left corner coordinate meaning that
|
||||
/// if the horizontal and vertical alignments are unchanged, this property will tell where the
|
||||
/// top-left corner of the text should be placed.
|
||||
///
|
||||
/// By changing the horizontal_alignment and vertical_alignment properties, you are are able to
|
||||
/// change what part of text is placed at this positions.
|
||||
///
|
||||
/// For example, when the horizontal_alignment and vertical_alignment are set to Center, the
|
||||
/// center of the text will be placed at the given position NOT the top-left coordinate.
|
||||
pub position: Point,
|
||||
|
|
@ -27,9 +30,9 @@ pub struct Text {
|
|||
/// The font of the text
|
||||
pub font: Font,
|
||||
/// The horizontal alignment of the text
|
||||
pub horizontal_alignment: alignment::Horizontal,
|
||||
pub align_x: alignment::Horizontal,
|
||||
/// The vertical alignment of the text
|
||||
pub vertical_alignment: alignment::Vertical,
|
||||
pub align_y: alignment::Vertical,
|
||||
/// The shaping strategy of the text.
|
||||
pub shaping: Shaping,
|
||||
}
|
||||
|
|
@ -57,7 +60,7 @@ impl Text {
|
|||
4,
|
||||
);
|
||||
|
||||
let translation_x = match self.horizontal_alignment {
|
||||
let translation_x = match self.align_x {
|
||||
alignment::Horizontal::Left => self.position.x,
|
||||
alignment::Horizontal::Center | alignment::Horizontal::Right => {
|
||||
let mut line_width = 0.0f32;
|
||||
|
|
@ -66,7 +69,7 @@ impl Text {
|
|||
line_width = line_width.max(line.w);
|
||||
}
|
||||
|
||||
if self.horizontal_alignment == alignment::Horizontal::Center {
|
||||
if self.align_x == alignment::Horizontal::Center {
|
||||
self.position.x - line_width / 2.0
|
||||
} else {
|
||||
self.position.x - line_width
|
||||
|
|
@ -77,7 +80,7 @@ impl Text {
|
|||
let translation_y = {
|
||||
let line_height = self.line_height.to_absolute(self.size);
|
||||
|
||||
match self.vertical_alignment {
|
||||
match self.align_y {
|
||||
alignment::Vertical::Top => self.position.y,
|
||||
alignment::Vertical::Center => {
|
||||
self.position.y - line_height.0 / 2.0
|
||||
|
|
@ -177,8 +180,8 @@ impl Default for Text {
|
|||
size: Pixels(16.0),
|
||||
line_height: LineHeight::Relative(1.2),
|
||||
font: Font::default(),
|
||||
horizontal_alignment: alignment::Horizontal::Left,
|
||||
vertical_alignment: alignment::Vertical::Top,
|
||||
align_x: alignment::Horizontal::Left,
|
||||
align_y: alignment::Vertical::Top,
|
||||
shaping: Shaping::Basic,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ pub use cosmic_text;
|
|||
|
||||
use crate::core::alignment;
|
||||
use crate::core::font::{self, Font};
|
||||
use crate::core::text::{Shaping, Wrapping};
|
||||
use crate::core::text::{Alignment, Shaping, Wrapping};
|
||||
use crate::core::{Color, Pixels, Point, Rectangle, Size, Transformation};
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
|
@ -54,9 +54,9 @@ pub enum Text {
|
|||
/// The font of the text.
|
||||
font: Font,
|
||||
/// The horizontal alignment of the text.
|
||||
horizontal_alignment: alignment::Horizontal,
|
||||
align_x: Alignment,
|
||||
/// The vertical alignment of the text.
|
||||
vertical_alignment: alignment::Vertical,
|
||||
align_y: alignment::Vertical,
|
||||
/// The shaping strategy of the text.
|
||||
shaping: Shaping,
|
||||
/// The clip bounds of the text.
|
||||
|
|
@ -73,7 +73,7 @@ pub enum Text {
|
|||
impl Text {
|
||||
/// Returns the visible bounds of the [`Text`].
|
||||
pub fn visible_bounds(&self) -> Option<Rectangle> {
|
||||
let (bounds, horizontal_alignment, vertical_alignment) = match self {
|
||||
let (bounds, align_x, align_y) = match self {
|
||||
Text::Paragraph {
|
||||
position,
|
||||
paragraph,
|
||||
|
|
@ -84,8 +84,8 @@ impl Text {
|
|||
Rectangle::new(*position, paragraph.min_bounds)
|
||||
.intersection(clip_bounds)
|
||||
.map(|bounds| bounds * *transformation),
|
||||
Some(paragraph.horizontal_alignment),
|
||||
Some(paragraph.vertical_alignment),
|
||||
paragraph.align_x,
|
||||
Some(paragraph.align_y),
|
||||
),
|
||||
Text::Editor {
|
||||
editor,
|
||||
|
|
@ -97,38 +97,38 @@ impl Text {
|
|||
Rectangle::new(*position, editor.bounds)
|
||||
.intersection(clip_bounds)
|
||||
.map(|bounds| bounds * *transformation),
|
||||
None,
|
||||
Alignment::Default,
|
||||
None,
|
||||
),
|
||||
Text::Cached {
|
||||
bounds,
|
||||
clip_bounds,
|
||||
horizontal_alignment,
|
||||
vertical_alignment,
|
||||
align_x: horizontal_alignment,
|
||||
align_y: vertical_alignment,
|
||||
..
|
||||
} => (
|
||||
bounds.intersection(clip_bounds),
|
||||
Some(*horizontal_alignment),
|
||||
*horizontal_alignment,
|
||||
Some(*vertical_alignment),
|
||||
),
|
||||
Text::Raw { raw, .. } => (Some(raw.clip_bounds), None, None),
|
||||
Text::Raw { raw, .. } => {
|
||||
(Some(raw.clip_bounds), Alignment::Default, None)
|
||||
}
|
||||
};
|
||||
|
||||
let mut bounds = bounds?;
|
||||
|
||||
if let Some(alignment) = horizontal_alignment {
|
||||
match alignment {
|
||||
alignment::Horizontal::Left => {}
|
||||
alignment::Horizontal::Center => {
|
||||
bounds.x -= bounds.width / 2.0;
|
||||
}
|
||||
alignment::Horizontal::Right => {
|
||||
bounds.x -= bounds.width;
|
||||
}
|
||||
match align_x {
|
||||
Alignment::Default | Alignment::Left | Alignment::Justified => {}
|
||||
Alignment::Center => {
|
||||
bounds.x -= bounds.width / 2.0;
|
||||
}
|
||||
Alignment::Right => {
|
||||
bounds.x -= bounds.width;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(alignment) = vertical_alignment {
|
||||
if let Some(alignment) = align_y {
|
||||
match alignment {
|
||||
alignment::Vertical::Top => {}
|
||||
alignment::Vertical::Center => {
|
||||
|
|
@ -242,15 +242,19 @@ impl PartialEq for Raw {
|
|||
}
|
||||
|
||||
/// Measures the dimensions of the given [`cosmic_text::Buffer`].
|
||||
pub fn measure(buffer: &cosmic_text::Buffer) -> Size {
|
||||
let (width, height) =
|
||||
buffer
|
||||
.layout_runs()
|
||||
.fold((0.0, 0.0), |(width, height), run| {
|
||||
(run.line_w.max(width), height + run.line_height)
|
||||
});
|
||||
pub fn measure(buffer: &cosmic_text::Buffer) -> (Size, bool) {
|
||||
let (width, height, has_rtl) = buffer.layout_runs().fold(
|
||||
(0.0, 0.0, false),
|
||||
|(width, height, has_rtl), run| {
|
||||
(
|
||||
run.line_w.max(width),
|
||||
height + run.line_height,
|
||||
has_rtl || run.rtl,
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
Size::new(width, height)
|
||||
(Size::new(width, height), has_rtl)
|
||||
}
|
||||
|
||||
/// Returns the attributes of the given [`Font`].
|
||||
|
|
@ -309,6 +313,16 @@ fn to_style(style: font::Style) -> cosmic_text::Style {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_align(alignment: Alignment) -> Option<cosmic_text::Align> {
|
||||
match alignment {
|
||||
Alignment::Default => None,
|
||||
Alignment::Left => Some(cosmic_text::Align::Left),
|
||||
Alignment::Center => Some(cosmic_text::Align::Center),
|
||||
Alignment::Right => Some(cosmic_text::Align::Right),
|
||||
Alignment::Justified => Some(cosmic_text::Align::Justified),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts some [`Shaping`] strategy to a [`cosmic_text::Shaping`] strategy.
|
||||
pub fn to_shaping(shaping: Shaping) -> cosmic_text::Shaping {
|
||||
match shaping {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,16 @@ impl Cache {
|
|||
text::to_shaping(key.shaping),
|
||||
);
|
||||
|
||||
let bounds = text::measure(&buffer);
|
||||
let (bounds, has_rtl) = text::measure(&buffer);
|
||||
|
||||
if has_rtl {
|
||||
buffer.set_size(
|
||||
font_system,
|
||||
Some(bounds.width),
|
||||
Some(bounds.height),
|
||||
);
|
||||
}
|
||||
|
||||
let _ = entry.insert(Entry {
|
||||
buffer,
|
||||
min_bounds: bounds,
|
||||
|
|
|
|||
|
|
@ -178,10 +178,8 @@ impl editor::Editor for Editor {
|
|||
.get(cursor.line)
|
||||
.expect("Cursor line should be present");
|
||||
|
||||
let layout = line
|
||||
.layout_opt()
|
||||
.as_ref()
|
||||
.expect("Line layout should be cached");
|
||||
let layout =
|
||||
line.layout_opt().expect("Line layout should be cached");
|
||||
|
||||
let mut lines = layout.iter().enumerate();
|
||||
|
||||
|
|
@ -452,7 +450,10 @@ impl editor::Editor for Editor {
|
|||
fn min_bounds(&self) -> Size {
|
||||
let internal = self.internal();
|
||||
|
||||
text::measure(buffer_from_editor(&internal.editor))
|
||||
let (bounds, _has_rtl) =
|
||||
text::measure(buffer_from_editor(&internal.editor));
|
||||
|
||||
bounds
|
||||
}
|
||||
|
||||
fn update(
|
||||
|
|
@ -706,11 +707,7 @@ fn highlight_line(
|
|||
from: usize,
|
||||
to: usize,
|
||||
) -> impl Iterator<Item = (f32, f32)> + '_ {
|
||||
let layout = line
|
||||
.layout_opt()
|
||||
.as_ref()
|
||||
.map(Vec::as_slice)
|
||||
.unwrap_or_default();
|
||||
let layout = line.layout_opt().map(Vec::as_slice).unwrap_or_default();
|
||||
|
||||
layout.iter().map(move |visual_line| {
|
||||
let start = visual_line
|
||||
|
|
@ -761,9 +758,7 @@ fn visual_lines_offset(line: usize, buffer: &cosmic_text::Buffer) -> i32 {
|
|||
let visual_lines_offset: usize = buffer.lines[start..]
|
||||
.iter()
|
||||
.take(end - start)
|
||||
.map(|line| {
|
||||
line.layout_opt().as_ref().map(Vec::len).unwrap_or_default()
|
||||
})
|
||||
.map(|line| line.layout_opt().map(Vec::len).unwrap_or_default())
|
||||
.sum();
|
||||
|
||||
visual_lines_offset as i32 * if scroll.line < line { 1 } else { -1 }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Draw paragraphs.
|
||||
use crate::core;
|
||||
use crate::core::alignment;
|
||||
use crate::core::text::{Hit, Shaping, Span, Text, Wrapping};
|
||||
use crate::core::text::{Alignment, Hit, Shaping, Span, Text, Wrapping};
|
||||
use crate::core::{Font, Point, Rectangle, Size};
|
||||
use crate::text;
|
||||
|
||||
|
|
@ -18,8 +18,8 @@ struct Internal {
|
|||
font: Font,
|
||||
shaping: Shaping,
|
||||
wrapping: Wrapping,
|
||||
horizontal_alignment: alignment::Horizontal,
|
||||
vertical_alignment: alignment::Vertical,
|
||||
align_x: Alignment,
|
||||
align_y: alignment::Vertical,
|
||||
bounds: Size,
|
||||
min_bounds: Size,
|
||||
version: text::Version,
|
||||
|
|
@ -47,8 +47,8 @@ impl Paragraph {
|
|||
Weak {
|
||||
raw: Arc::downgrade(paragraph),
|
||||
min_bounds: paragraph.min_bounds,
|
||||
horizontal_alignment: paragraph.horizontal_alignment,
|
||||
vertical_alignment: paragraph.vertical_alignment,
|
||||
align_x: paragraph.align_x,
|
||||
align_y: paragraph.align_y,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,13 +89,13 @@ impl core::text::Paragraph for Paragraph {
|
|||
text::to_shaping(text.shaping),
|
||||
);
|
||||
|
||||
let min_bounds = text::measure(&buffer);
|
||||
let min_bounds = align(&mut buffer, &mut font_system, text.align_x);
|
||||
|
||||
Self(Arc::new(Internal {
|
||||
buffer,
|
||||
font: text.font,
|
||||
horizontal_alignment: text.horizontal_alignment,
|
||||
vertical_alignment: text.vertical_alignment,
|
||||
align_x: text.align_x,
|
||||
align_y: text.align_y,
|
||||
shaping: text.shaping,
|
||||
wrapping: text.wrapping,
|
||||
bounds: text.bounds,
|
||||
|
|
@ -156,15 +156,16 @@ impl core::text::Paragraph for Paragraph {
|
|||
}),
|
||||
text::to_attributes(text.font),
|
||||
text::to_shaping(text.shaping),
|
||||
None,
|
||||
);
|
||||
|
||||
let min_bounds = text::measure(&buffer);
|
||||
let min_bounds = align(&mut buffer, &mut font_system, text.align_x);
|
||||
|
||||
Self(Arc::new(Internal {
|
||||
buffer,
|
||||
font: text.font,
|
||||
horizontal_alignment: text.horizontal_alignment,
|
||||
vertical_alignment: text.vertical_alignment,
|
||||
align_x: text.align_x,
|
||||
align_y: text.align_y,
|
||||
shaping: text.shaping,
|
||||
wrapping: text.wrapping,
|
||||
bounds: text.bounds,
|
||||
|
|
@ -185,8 +186,10 @@ impl core::text::Paragraph for Paragraph {
|
|||
Some(new_bounds.height),
|
||||
);
|
||||
|
||||
let (min_bounds, _has_rtl) = text::measure(¶graph.buffer);
|
||||
|
||||
paragraph.bounds = new_bounds;
|
||||
paragraph.min_bounds = text::measure(¶graph.buffer);
|
||||
paragraph.min_bounds = min_bounds;
|
||||
}
|
||||
|
||||
fn compare(&self, text: Text<()>) -> core::text::Difference {
|
||||
|
|
@ -200,8 +203,8 @@ impl core::text::Paragraph for Paragraph {
|
|||
|| paragraph.font != text.font
|
||||
|| paragraph.shaping != text.shaping
|
||||
|| paragraph.wrapping != text.wrapping
|
||||
|| paragraph.horizontal_alignment != text.horizontal_alignment
|
||||
|| paragraph.vertical_alignment != text.vertical_alignment
|
||||
|| paragraph.align_x != text.align_x
|
||||
|| paragraph.align_y != text.align_y
|
||||
{
|
||||
core::text::Difference::Shape
|
||||
} else if paragraph.bounds != text.bounds {
|
||||
|
|
@ -211,12 +214,12 @@ impl core::text::Paragraph for Paragraph {
|
|||
}
|
||||
}
|
||||
|
||||
fn horizontal_alignment(&self) -> alignment::Horizontal {
|
||||
self.internal().horizontal_alignment
|
||||
fn align_x(&self) -> Alignment {
|
||||
self.internal().align_x
|
||||
}
|
||||
|
||||
fn vertical_alignment(&self) -> alignment::Vertical {
|
||||
self.internal().vertical_alignment
|
||||
fn align_y(&self) -> alignment::Vertical {
|
||||
self.internal().align_y
|
||||
}
|
||||
|
||||
fn min_bounds(&self) -> Size {
|
||||
|
|
@ -353,6 +356,43 @@ impl core::text::Paragraph for Paragraph {
|
|||
}
|
||||
}
|
||||
|
||||
fn align(
|
||||
buffer: &mut cosmic_text::Buffer,
|
||||
font_system: &mut text::FontSystem,
|
||||
alignment: Alignment,
|
||||
) -> Size {
|
||||
let (min_bounds, has_rtl) = text::measure(buffer);
|
||||
let mut needs_relayout = has_rtl;
|
||||
|
||||
if let Some(align) = text::to_align(alignment) {
|
||||
let has_multiple_lines = buffer.lines.len() > 1
|
||||
|| buffer.lines.first().is_some_and(|line| {
|
||||
line.layout_opt().is_some_and(|layout| layout.len() > 1)
|
||||
});
|
||||
|
||||
if has_multiple_lines {
|
||||
for line in &mut buffer.lines {
|
||||
let _ = line.set_align(Some(align));
|
||||
}
|
||||
|
||||
needs_relayout = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Avoid relayout with some changes to `cosmic-text` (?)
|
||||
if needs_relayout {
|
||||
log::trace!("Relayouting paragraph...");
|
||||
|
||||
buffer.set_size(
|
||||
font_system.raw(),
|
||||
Some(min_bounds.width),
|
||||
Some(min_bounds.height),
|
||||
);
|
||||
}
|
||||
|
||||
min_bounds
|
||||
}
|
||||
|
||||
impl Default for Paragraph {
|
||||
fn default() -> Self {
|
||||
Self(Arc::new(Internal::default()))
|
||||
|
|
@ -366,8 +406,8 @@ impl fmt::Debug for Paragraph {
|
|||
f.debug_struct("Paragraph")
|
||||
.field("font", ¶graph.font)
|
||||
.field("shaping", ¶graph.shaping)
|
||||
.field("horizontal_alignment", ¶graph.horizontal_alignment)
|
||||
.field("vertical_alignment", ¶graph.vertical_alignment)
|
||||
.field("horizontal_alignment", ¶graph.align_x)
|
||||
.field("vertical_alignment", ¶graph.align_y)
|
||||
.field("bounds", ¶graph.bounds)
|
||||
.field("min_bounds", ¶graph.min_bounds)
|
||||
.finish()
|
||||
|
|
@ -378,8 +418,8 @@ impl PartialEq for Internal {
|
|||
fn eq(&self, other: &Self) -> bool {
|
||||
self.font == other.font
|
||||
&& self.shaping == other.shaping
|
||||
&& self.horizontal_alignment == other.horizontal_alignment
|
||||
&& self.vertical_alignment == other.vertical_alignment
|
||||
&& self.align_x == other.align_x
|
||||
&& self.align_y == other.align_y
|
||||
&& self.bounds == other.bounds
|
||||
&& self.min_bounds == other.min_bounds
|
||||
&& self.buffer.metrics() == other.buffer.metrics()
|
||||
|
|
@ -396,8 +436,8 @@ impl Default for Internal {
|
|||
font: Font::default(),
|
||||
shaping: Shaping::default(),
|
||||
wrapping: Wrapping::default(),
|
||||
horizontal_alignment: alignment::Horizontal::Left,
|
||||
vertical_alignment: alignment::Vertical::Top,
|
||||
align_x: Alignment::Default,
|
||||
align_y: alignment::Vertical::Top,
|
||||
bounds: Size::ZERO,
|
||||
min_bounds: Size::ZERO,
|
||||
version: text::Version::default(),
|
||||
|
|
@ -412,9 +452,9 @@ pub struct Weak {
|
|||
/// The minimum bounds of the [`Paragraph`].
|
||||
pub min_bounds: Size,
|
||||
/// The horizontal alignment of the [`Paragraph`].
|
||||
pub horizontal_alignment: alignment::Horizontal,
|
||||
pub align_x: Alignment,
|
||||
/// The vertical alignment of the [`Paragraph`].
|
||||
pub vertical_alignment: alignment::Vertical,
|
||||
pub align_y: alignment::Vertical,
|
||||
}
|
||||
|
||||
impl Weak {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue