ailloli_ui_text/
params.rs

1//! Value types that describe layout requests and results.
2
3use core::ops::Range;
4
5use ailloli_ui_core::style::TextStyle;
6
7/// Line breaking strategy for layout.
8///
9/// # Examples
10///
11/// ```
12/// use ailloli_ui_text::WrapMode;
13/// assert_ne!(WrapMode::NoWrap, WrapMode::WordOrAnywhere);
14/// ```
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16pub enum WrapMode {
17    /// Do not wrap; [`TextLayoutParams::max_width`] is ignored.
18    NoWrap,
19    /// Prefer word boundaries when wrapping to the requested maximum width.
20    Word,
21    /// Prefer words, but split an otherwise overflowing word at shaped clusters.
22    WordOrAnywhere,
23}
24
25/// Inputs for text layout (content, style, width, wrap).
26///
27/// # Examples
28///
29/// ```
30/// use ailloli_ui_core::{Color, FontId, TextStyle};
31/// use ailloli_ui_text::{TextLayoutParams, WrapMode};
32///
33/// let params = TextLayoutParams::new("hello", TextStyle::new(FontId::Ui, 16, Color::WHITE));
34/// assert_eq!(params.max_width, None);
35/// assert_eq!(params.wrap_mode, WrapMode::Word);
36/// ```
37#[derive(Debug, Clone, Copy)]
38pub struct TextLayoutParams<'a> {
39    /// UTF-8 text to shape; an empty string is valid.
40    pub text: &'a str,
41    /// Base font, logical-pixel size, color, and paint decoration.
42    pub style: TextStyle,
43    /// Optional wrap width in logical pixels; `None` means unconstrained.
44    ///
45    /// This value is ignored when [`Self::wrap_mode`] is [`WrapMode::NoWrap`].
46    pub max_width: Option<f32>,
47    /// Line-breaking policy.
48    pub wrap_mode: WrapMode,
49}
50
51impl<'a> TextLayoutParams<'a> {
52    /// Creates an unconstrained request using [`WrapMode::Word`].
53    ///
54    /// # Examples
55    ///
56    /// ```
57    /// use ailloli_ui_core::{Color, FontId, TextStyle};
58    /// use ailloli_ui_text::{TextLayoutParams, WrapMode};
59    ///
60    /// let params = TextLayoutParams::new("Ailloli", TextStyle::new(FontId::Mono, 13, Color::BLACK));
61    /// assert_eq!(params.text, "Ailloli");
62    /// assert_eq!(params.wrap_mode, WrapMode::Word);
63    /// ```
64    pub fn new(text: &'a str, style: TextStyle) -> Self {
65        Self {
66            text,
67            style,
68            max_width: None,
69            wrap_mode: WrapMode::Word,
70        }
71    }
72}
73
74/// Style override for a UTF-8 byte range in a text layout.
75///
76/// The range must be ordered, lie within the associated text, and use UTF-8
77/// boundaries when submitted to the layout engine. This value type does not
78/// validate those invariants itself.
79///
80/// # Examples
81///
82/// ```
83/// use ailloli_ui_core::{Color, FontId, TextStyle};
84/// use ailloli_ui_text::StyledTextSpan;
85///
86/// let span = StyledTextSpan {
87///     range: 0..4,
88///     style: TextStyle::new(FontId::Mono, 14, Color::WHITE),
89/// };
90/// assert_eq!(span.range, 0..4);
91/// ```
92#[derive(Debug, Clone, PartialEq)]
93pub struct StyledTextSpan {
94    /// Half-open UTF-8 byte range receiving the override.
95    pub range: Range<usize>,
96    /// Complete replacement style for the range.
97    pub style: TextStyle,
98}
99
100/// Inputs for styled text layout. Spans affect cache invalidation and prepare
101/// the pipeline for syntax-colored runs while preserving a single layout pass.
102///
103/// Overlapping spans are forwarded in slice order to Parley. Every span range
104/// must be a valid UTF-8 range in `text`; callers should not rely on this data
105/// structure to clip or repair invalid ranges.
106///
107/// # Examples
108///
109/// ```
110/// use ailloli_ui_core::{Color, FontId, TextStyle};
111/// use ailloli_ui_text::{StyledTextLayoutParams, StyledTextSpan, WrapMode};
112///
113/// let base = TextStyle::new(FontId::Mono, 14, Color::WHITE);
114/// let spans = [StyledTextSpan { range: 0..2, style: base.underline() }];
115/// let params = StyledTextLayoutParams {
116///     text: "fn main",
117///     base_style: base,
118///     spans: &spans,
119///     max_width: Some(120.0),
120///     wrap_mode: WrapMode::Word,
121/// };
122/// assert_eq!(params.spans.len(), 1);
123/// ```
124#[derive(Debug, Clone, Copy)]
125pub struct StyledTextLayoutParams<'a> {
126    /// UTF-8 text to shape; an empty string is valid.
127    pub text: &'a str,
128    /// Style used outside overridden ranges.
129    pub base_style: TextStyle,
130    /// Ordered range overrides, borrowed for the duration of the request.
131    pub spans: &'a [StyledTextSpan],
132    /// Optional wrap width in logical pixels; `None` means unconstrained.
133    pub max_width: Option<f32>,
134    /// Line-breaking policy.
135    pub wrap_mode: WrapMode,
136}
137
138/// Metrics for one laid-out line.
139///
140/// Distances are logical pixels. `text_range` is a half-open UTF-8 byte range
141/// in the original string. `descent` follows Parley's metric convention and is
142/// normally non-negative.
143///
144/// # Examples
145///
146/// ```
147/// use ailloli_ui_text::LaidOutLine;
148/// let line = LaidOutLine {
149///     text_range: 0..5,
150///     width: 40.0,
151///     ascent: 12.0,
152///     descent: 4.0,
153///     baseline_y: 12.0,
154/// };
155/// assert_eq!(line.text_range, 0..5);
156/// ```
157#[derive(Debug, Clone, PartialEq)]
158pub struct LaidOutLine {
159    /// Half-open UTF-8 byte range covered by the line.
160    pub text_range: Range<usize>,
161    /// Advance excluding trailing whitespace, in logical pixels.
162    pub width: f32,
163    /// Distance above the baseline, in logical pixels.
164    pub ascent: f32,
165    /// Distance below the baseline, in logical pixels.
166    pub descent: f32,
167    /// Baseline Y coordinate relative to the layout origin, in logical pixels.
168    pub baseline_y: f32,
169}
170
171/// Overall width and height of laid-out text.
172///
173/// Both dimensions are logical pixels and come directly from Parley.
174///
175/// # Examples
176///
177/// ```
178/// use ailloli_ui_text::TextMetrics;
179/// let metrics = TextMetrics { width: 80.0, height: 24.0 };
180/// assert_eq!(metrics.width, 80.0);
181/// ```
182#[derive(Debug, Clone, Copy, PartialEq)]
183pub struct TextMetrics {
184    /// Layout width in logical pixels, including Parley's layout extent.
185    pub width: f32,
186    /// Layout height in logical pixels.
187    pub height: f32,
188}