use crate::{Bounds, FontRun, Hsla, Pixels, Point, Result, ShapedRun, Size, Window};
use std::sync::Arc;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TextAffinity {
Upstream,
Downstream,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ParagraphPosition {
pub byte_index: usize,
pub affinity: TextAffinity,
}
#[derive(Clone, Copy, Debug)]
pub enum VisualDirection {
Left,
Right,
}
pub trait PlatformParagraphShape: Send + Sync {
fn layout(&self, width: Pixels) -> Result<Arc<dyn PlatformParagraphLayout>>;
}
pub trait PlatformParagraphLayout: Send + Sync {
fn source(&self) -> &str;
fn font_size(&self) -> Pixels;
fn size(&self) -> Size<Pixels>;
fn runs(&self) -> &[ShapedRun];
fn hit_test(&self, point: Point<Pixels>) -> Result<ParagraphPosition>;
fn caret_bounds(&self, position: ParagraphPosition) -> Result<Bounds<Pixels>>;
fn move_visual(
&self,
position: ParagraphPosition,
direction: VisualDirection,
) -> Result<ParagraphPosition>;
fn selection_bounds(
&self,
anchor: ParagraphPosition,
focus: ParagraphPosition,
) -> Result<Vec<Bounds<Pixels>>>;
}
pub fn paint_paragraph(
layout: &dyn PlatformParagraphLayout,
origin: Point<Pixels>,
color_for_index: impl Fn(usize) -> Hsla,
window: &mut Window,
) -> Result<()> {
for run in layout.runs() {
for glyph in &run.glyphs {
let position = origin + glyph.position;
if glyph.is_emoji {
window.paint_emoji(position, run.font_id, glyph.id, layout.font_size())?;
} else {
window.paint_glyph(
position,
run.font_id,
glyph.id,
layout.font_size(),
color_for_index(glyph.index),
)?;
}
}
}
Ok(())
}
pub struct ParagraphRequest<'a> {
pub text: &'a str,
pub font_size: Pixels,
pub runs: &'a [FontRun],
}