mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-30 22:01:13 +00:00
Move the text_input_byte_offset_for_position from the FontMetrics to the Window
In preparation of having mutiple-lines TextInput, we will need to give more data to this function so it no longer belong in FontMetrics Also remove the unused FontMetric::line_height()
This commit is contained in:
parent
e1be599bc0
commit
c1fc242a9a
7 changed files with 77 additions and 64 deletions
|
@ -156,13 +156,6 @@ pub trait FontMetrics {
|
|||
/// Returns the size of the given string in logical pixels.
|
||||
/// When set, `max_width` means that one need to wrap the text so it does not go further than that
|
||||
fn text_size(&self, text: &str, max_width: Option<f32>) -> Size;
|
||||
/// Returns the height of a line of text.
|
||||
fn line_height(&self) -> f32;
|
||||
/// Returns the (UTF-8) byte offset in the given text that refers to the character that contributed to
|
||||
/// the glyph cluster that's visually nearest to the given x coordinate. This is used for hit-testing,
|
||||
/// for example when receiving a mouse click into a text field. Then this function returns the "cursor"
|
||||
/// position.
|
||||
fn text_offset_for_x_position(&self, text: &str, x: f32) -> usize;
|
||||
}
|
||||
|
||||
#[cfg(feature = "ffi")]
|
||||
|
|
|
@ -302,16 +302,9 @@ impl Item for TextInput {
|
|||
if !self.enabled() {
|
||||
return InputEventResult::EventIgnored;
|
||||
}
|
||||
|
||||
let text = self.text();
|
||||
let font_metrics = window.font_metrics(
|
||||
&self.cached_rendering_data,
|
||||
&|| self.unresolved_font_request(),
|
||||
Self::FIELD_OFFSETS.text.apply_pin(self),
|
||||
);
|
||||
match event {
|
||||
MouseEvent::MousePressed { pos } => {
|
||||
let clicked_offset = font_metrics.text_offset_for_x_position(&text, pos.x) as i32;
|
||||
let clicked_offset = window.text_input_byte_offset_for_position(self, pos) as i32;
|
||||
self.as_ref().pressed.set(true);
|
||||
self.as_ref().anchor_position.set(clicked_offset);
|
||||
self.as_ref().cursor_position.set(clicked_offset);
|
||||
|
@ -325,7 +318,7 @@ impl Item for TextInput {
|
|||
MouseEvent::MouseMoved { pos } => {
|
||||
if self.as_ref().pressed.get() {
|
||||
let clicked_offset =
|
||||
font_metrics.text_offset_for_x_position(&text, pos.x) as i32;
|
||||
window.text_input_byte_offset_for_position(self, pos) as i32;
|
||||
self.as_ref().cursor_position.set(clicked_offset);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,6 +66,16 @@ pub trait PlatformWindow {
|
|||
reference_text: Pin<&crate::properties::Property<SharedString>>,
|
||||
) -> Box<dyn crate::graphics::FontMetrics>;
|
||||
|
||||
/// Returns the (UTF-8) byte offset in the text property that refers to the character that contributed to
|
||||
/// the glyph cluster that's visually nearest to the given coordinate. This is used for hit-testing,
|
||||
/// for example when receiving a mouse click into a text field. Then this function returns the "cursor"
|
||||
/// position.
|
||||
fn text_input_byte_offset_for_position(
|
||||
&self,
|
||||
text_input: Pin<&crate::items::TextInput>,
|
||||
pos: Point,
|
||||
) -> usize;
|
||||
|
||||
/// Return self as any so the backend can upcast
|
||||
fn as_any(&self) -> &dyn core::any::Any;
|
||||
}
|
||||
|
|
|
@ -348,23 +348,6 @@ impl FontMetricsTrait for FontMetrics {
|
|||
max_width.map(|x| x * self.scale_factor),
|
||||
) / self.scale_factor
|
||||
}
|
||||
|
||||
fn line_height(&self) -> f32 {
|
||||
self.font.height()
|
||||
}
|
||||
|
||||
fn text_offset_for_x_position(&self, text: &str, x: f32) -> usize {
|
||||
let x = x * self.scale_factor;
|
||||
let metrics = self.font.measure(self.letter_spacing.unwrap_or_default(), text);
|
||||
let mut current_x = 0.;
|
||||
for glyph in metrics.glyphs {
|
||||
if current_x + glyph.advance_x / 2. >= x {
|
||||
return glyph.byte_index;
|
||||
}
|
||||
current_x += glyph.advance_x;
|
||||
}
|
||||
text.len()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FontCache {
|
||||
|
|
|
@ -556,6 +556,40 @@ impl PlatformWindow for GraphicsWindow {
|
|||
))
|
||||
}
|
||||
|
||||
fn text_input_byte_offset_for_position(
|
||||
&self,
|
||||
text_input: Pin<&sixtyfps_corelib::items::TextInput>,
|
||||
pos: Point,
|
||||
) -> usize {
|
||||
let scale_factor = self.scale_factor();
|
||||
let cache_data = text_input
|
||||
.cached_rendering_data
|
||||
.get_or_update(&self.graphics_cache, || {
|
||||
Some(crate::ItemGraphicsCacheEntry::Font(crate::fonts::FONT_CACHE.with(|cache| {
|
||||
cache.borrow_mut().font(
|
||||
text_input
|
||||
.unresolved_font_request()
|
||||
.merge(&self.default_font_properties.as_ref().get()),
|
||||
scale_factor,
|
||||
&text_input.text(),
|
||||
)
|
||||
})))
|
||||
})
|
||||
.unwrap();
|
||||
let font = cache_data.as_font();
|
||||
let x = pos.x * scale_factor;
|
||||
let text = text_input.text();
|
||||
let metrics = font.measure(text_input.letter_spacing(), &text);
|
||||
let mut current_x = 0.;
|
||||
for glyph in metrics.glyphs {
|
||||
if current_x + glyph.advance_x / 2. >= x {
|
||||
return glyph.byte_index;
|
||||
}
|
||||
current_x += glyph.advance_x;
|
||||
}
|
||||
text.len()
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
|
|
@ -1316,6 +1316,28 @@ impl PlatformWindow for QtWindow {
|
|||
Box::new(get_font(unresolved_font_request_getter().merge(&self.default_font_properties())))
|
||||
}
|
||||
|
||||
fn text_input_byte_offset_for_position(
|
||||
&self,
|
||||
text_input: Pin<&sixtyfps_corelib::items::TextInput>,
|
||||
pos: Point,
|
||||
) -> usize {
|
||||
let font: QFont =
|
||||
get_font(text_input.unresolved_font_request().merge(&self.default_font_properties()));
|
||||
let string = qttypes::QString::from(text_input.text().as_str());
|
||||
let x: f32 = pos.x;
|
||||
cpp! { unsafe [font as "QFont", string as "QString", x as "float"] -> usize as "long long" {
|
||||
QTextLayout layout(string, font);
|
||||
layout.beginLayout();
|
||||
layout.createLine();
|
||||
layout.endLayout();
|
||||
if (layout.lineCount() == 0)
|
||||
return 0;
|
||||
auto cur = layout.lineAt(0).xToCursor(x);
|
||||
// convert to an utf8 pos;
|
||||
return QStringView(string).left(cur).toUtf8().size();
|
||||
}}
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
@ -1369,28 +1391,6 @@ impl sixtyfps_corelib::graphics::FontMetrics for QFont {
|
|||
}};
|
||||
sixtyfps_corelib::graphics::Size::new(size.width as _, size.height as _)
|
||||
}
|
||||
|
||||
fn line_height(&self) -> f32 {
|
||||
cpp! { unsafe [self as "const QFont*"]
|
||||
-> f32 as "float"{
|
||||
return QFontMetricsF(*self).height();
|
||||
}}
|
||||
}
|
||||
|
||||
fn text_offset_for_x_position(&self, text: &str, x: f32) -> usize {
|
||||
let string = qttypes::QString::from(text);
|
||||
cpp! { unsafe [self as "const QFont*", string as "QString", x as "float"] -> usize as "long long" {
|
||||
QTextLayout layout(string, *self);
|
||||
layout.beginLayout();
|
||||
layout.createLine();
|
||||
layout.endLayout();
|
||||
if (layout.lineCount() == 0)
|
||||
return 0;
|
||||
auto cur = layout.lineAt(0).xToCursor(x);
|
||||
// convert to an utf8 pos;
|
||||
return QStringView(string).left(cur).toUtf8().size();
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
|
|
|
@ -18,7 +18,7 @@ You should use the `sixtyfps` crate instead.
|
|||
|
||||
use image::GenericImageView;
|
||||
use sixtyfps_corelib::component::ComponentRc;
|
||||
use sixtyfps_corelib::graphics::{FontMetrics, Image, Size};
|
||||
use sixtyfps_corelib::graphics::{FontMetrics, Image, Point, Size};
|
||||
use sixtyfps_corelib::slice::Slice;
|
||||
use sixtyfps_corelib::window::{PlatformWindow, Window};
|
||||
use sixtyfps_corelib::{ImageInner, Property};
|
||||
|
@ -149,6 +149,14 @@ impl PlatformWindow for TestingWindow {
|
|||
Box::new(TestingFontMetrics::default())
|
||||
}
|
||||
|
||||
fn text_input_byte_offset_for_position(
|
||||
&self,
|
||||
_text_input: Pin<&sixtyfps_corelib::items::TextInput>,
|
||||
_pos: Point,
|
||||
) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
@ -161,14 +169,6 @@ impl FontMetrics for TestingFontMetrics {
|
|||
fn text_size(&self, text: &str, _max_width: Option<f32>) -> Size {
|
||||
Size::new(text.len() as f32 * 10., 10.)
|
||||
}
|
||||
|
||||
fn line_height(&self) -> f32 {
|
||||
10.
|
||||
}
|
||||
|
||||
fn text_offset_for_x_position(&self, _text: &str, _x: f32) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize the testing backend.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue