From a0b084209338386f7b50b4268af89118a4635e0d Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Tue, 7 May 2024 22:56:58 +0200 Subject: [PATCH] Implement underlining for IME areas (#284) ![image](https://github.com/linebender/xilem/assets/36049421/5378dc8c-bb2a-4dba-bbb1-352d827a617b) --- crates/masonry/src/text2/edit.rs | 11 ++++++++++- crates/masonry/src/text2/selection.rs | 19 +++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/crates/masonry/src/text2/edit.rs b/crates/masonry/src/text2/edit.rs index 4a11c2ae4..c1a8e3627 100644 --- a/crates/masonry/src/text2/edit.rs +++ b/crates/masonry/src/text2/edit.rs @@ -71,7 +71,16 @@ impl TextEditor { pub fn rebuild(&mut self, fcx: &mut FontContext) { // TODO: Add the pre-edit range as an underlined region in the text attributes - self.inner.rebuild(fcx); + + self.inner.rebuild_with_attributes(fcx, |mut builder| { + if let Some(range) = self.preedit_range.as_ref() { + builder.push( + &parley::style::StyleProperty::Underline(true), + range.clone(), + ); + } + builder + }); } pub fn draw(&mut self, scene: &mut Scene, point: impl Into) { diff --git a/crates/masonry/src/text2/selection.rs b/crates/masonry/src/text2/selection.rs index 4f578f593..f5335154b 100644 --- a/crates/masonry/src/text2/selection.rs +++ b/crates/masonry/src/text2/selection.rs @@ -7,6 +7,7 @@ use std::borrow::Cow; use std::ops::{Deref, DerefMut, Range}; use kurbo::{Affine, Line, Point, Stroke}; +use parley::context::RangedBuilder; use parley::FontContext; use unicode_segmentation::{GraphemeCursor, UnicodeSegmentation}; use vello::peniko::{Brush, Color}; @@ -210,15 +211,21 @@ impl TextWithSelection { self.needs_selection_update = true; } - // Intentionally aliases the method on - pub fn rebuild(&mut self, fcx: &mut FontContext) { + // Intentionally aliases the method on `TextLayout` + pub fn rebuild_with_attributes( + &mut self, + fcx: &mut FontContext, + attributes: impl for<'b> FnOnce( + RangedBuilder<'b, TextBrush, &'b str>, + ) -> RangedBuilder<'b, TextBrush, &'b str>, + ) { // In theory, we could be clever here and only rebuild the layout if the // selected range was previously or currently non-zero size (i.e. there is a selected range) if self.needs_selection_update || self.layout.needs_rebuild() { self.layout.invalidate(); self.layout.rebuild_with_attributes(fcx, |mut builder| { if let Some(selection) = self.selection { - let range = selection.min()..selection.max(); + let range = selection.range(); if !range.is_empty() { builder.push( &parley::style::StyleProperty::Brush(self.highlight_brush.clone()), @@ -226,12 +233,16 @@ impl TextWithSelection { ); } } - builder + attributes(builder) }); self.needs_selection_update = false; } } + pub fn rebuild(&mut self, fcx: &mut FontContext) { + self.rebuild_with_attributes(fcx, |builder| builder); + } + pub fn draw(&mut self, scene: &mut Scene, point: impl Into) { // TODO: Calculate the location for this in layout lazily? if let Some(selection) = self.selection {