mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 06:11:16 +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.
|
/// 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
|
/// 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;
|
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")]
|
#[cfg(feature = "ffi")]
|
||||||
|
|
|
@ -302,16 +302,9 @@ impl Item for TextInput {
|
||||||
if !self.enabled() {
|
if !self.enabled() {
|
||||||
return InputEventResult::EventIgnored;
|
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 {
|
match event {
|
||||||
MouseEvent::MousePressed { pos } => {
|
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().pressed.set(true);
|
||||||
self.as_ref().anchor_position.set(clicked_offset);
|
self.as_ref().anchor_position.set(clicked_offset);
|
||||||
self.as_ref().cursor_position.set(clicked_offset);
|
self.as_ref().cursor_position.set(clicked_offset);
|
||||||
|
@ -325,7 +318,7 @@ impl Item for TextInput {
|
||||||
MouseEvent::MouseMoved { pos } => {
|
MouseEvent::MouseMoved { pos } => {
|
||||||
if self.as_ref().pressed.get() {
|
if self.as_ref().pressed.get() {
|
||||||
let clicked_offset =
|
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);
|
self.as_ref().cursor_position.set(clicked_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,16 @@ pub trait PlatformWindow {
|
||||||
reference_text: Pin<&crate::properties::Property<SharedString>>,
|
reference_text: Pin<&crate::properties::Property<SharedString>>,
|
||||||
) -> Box<dyn crate::graphics::FontMetrics>;
|
) -> 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
|
/// Return self as any so the backend can upcast
|
||||||
fn as_any(&self) -> &dyn core::any::Any;
|
fn as_any(&self) -> &dyn core::any::Any;
|
||||||
}
|
}
|
||||||
|
|
|
@ -348,23 +348,6 @@ impl FontMetricsTrait for FontMetrics {
|
||||||
max_width.map(|x| x * self.scale_factor),
|
max_width.map(|x| x * self.scale_factor),
|
||||||
) / 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 {
|
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 {
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
@ -1316,6 +1316,28 @@ impl PlatformWindow for QtWindow {
|
||||||
Box::new(get_font(unresolved_font_request_getter().merge(&self.default_font_properties())))
|
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 {
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -1369,28 +1391,6 @@ impl sixtyfps_corelib::graphics::FontMetrics for QFont {
|
||||||
}};
|
}};
|
||||||
sixtyfps_corelib::graphics::Size::new(size.width as _, size.height as _)
|
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! {
|
thread_local! {
|
||||||
|
|
|
@ -18,7 +18,7 @@ You should use the `sixtyfps` crate instead.
|
||||||
|
|
||||||
use image::GenericImageView;
|
use image::GenericImageView;
|
||||||
use sixtyfps_corelib::component::ComponentRc;
|
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::slice::Slice;
|
||||||
use sixtyfps_corelib::window::{PlatformWindow, Window};
|
use sixtyfps_corelib::window::{PlatformWindow, Window};
|
||||||
use sixtyfps_corelib::{ImageInner, Property};
|
use sixtyfps_corelib::{ImageInner, Property};
|
||||||
|
@ -149,6 +149,14 @@ impl PlatformWindow for TestingWindow {
|
||||||
Box::new(TestingFontMetrics::default())
|
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 {
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -161,14 +169,6 @@ impl FontMetrics for TestingFontMetrics {
|
||||||
fn text_size(&self, text: &str, _max_width: Option<f32>) -> Size {
|
fn text_size(&self, text: &str, _max_width: Option<f32>) -> Size {
|
||||||
Size::new(text.len() as f32 * 10., 10.)
|
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.
|
/// Initialize the testing backend.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue