@effindomv2/fui-rs 0.1.22 → 0.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +1 -1
- package/README.md +12 -0
- package/package.json +1 -1
- package/src/controls/anti_selection_area.rs +0 -18
- package/src/controls/button.rs +14 -42
- package/src/controls/checkbox.rs +7 -0
- package/src/controls/combobox.rs +7 -6
- package/src/controls/context_menu.rs +38 -5
- package/src/controls/dialog.rs +41 -3
- package/src/controls/dropdown.rs +2 -2
- package/src/controls/form.rs +16 -20
- package/src/controls/internal/button_presenter.rs +5 -5
- package/src/controls/internal/checkbox_indicator_presenter.rs +1 -1
- package/src/controls/internal/pressable_labeled_control.rs +21 -7
- package/src/controls/internal/selectable_popup_list.rs +2 -2
- package/src/controls/internal/text_input_core.rs +38 -68
- package/src/controls/internal/text_input_presenter.rs +4 -4
- package/src/controls/mod.rs +11 -4
- package/src/controls/popup.rs +35 -20
- package/src/controls/radio_button.rs +7 -0
- package/src/controls/radio_group.rs +17 -0
- package/src/controls/selection_area.rs +0 -18
- package/src/controls/shared.rs +2 -17
- package/src/controls/switch.rs +7 -0
- package/src/controls/tests.rs +230 -6
- package/src/controls/text_area.rs +28 -142
- package/src/controls/text_editor_surface.rs +167 -0
- package/src/controls/text_input.rs +30 -144
- package/src/lib.rs +26 -20
- package/src/mobile_text_selection_toolbar.rs +2 -2
- package/src/node/core.rs +451 -60
- package/src/node/custom_drawable.rs +20 -0
- package/src/node/flex_box.rs +39 -47
- package/src/node/grid.rs +43 -128
- package/src/node/helpers.rs +34 -43
- package/src/node/image.rs +47 -56
- package/src/node/mod.rs +398 -73
- package/src/node/scroll_bar.rs +6 -0
- package/src/node/scroll_box.rs +8 -21
- package/src/node/scroll_view.rs +144 -13
- package/src/node/svg_node.rs +47 -66
- package/src/node/text_node.rs +358 -79
- package/src/node/virtual_list.rs +17 -0
- package/src/popup_presenter.rs +31 -0
- package/src/text.rs +59 -0
- package/src/text_indices.rs +48 -0
package/src/text.rs
CHANGED
|
@@ -251,6 +251,34 @@ impl HasTextNode for RichText {
|
|
|
251
251
|
fn text_node(&self) -> &TextNode {
|
|
252
252
|
&self.node
|
|
253
253
|
}
|
|
254
|
+
|
|
255
|
+
fn set_text_surface_content(&self, content: String) {
|
|
256
|
+
self.text(content);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
fn set_text_surface_font_stack(&self, stack: FontStack, size: f32) {
|
|
260
|
+
self.font_stack(stack, size);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
fn set_text_surface_font_family(&self, family: FontFamily) {
|
|
264
|
+
self.font_family(family);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
fn set_text_surface_font_weight(&self, weight: FontWeight) {
|
|
268
|
+
self.font_weight(weight);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
fn set_text_surface_font_style(&self, style: FontStyle) {
|
|
272
|
+
self.font_style(style);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
fn set_text_surface_font_size(&self, size: f32) {
|
|
276
|
+
self.font_size(size);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
fn set_text_surface_color(&self, color: u32) {
|
|
280
|
+
self.text_color(color);
|
|
281
|
+
}
|
|
254
282
|
}
|
|
255
283
|
|
|
256
284
|
impl ThemeBindable for RichText {
|
|
@@ -1011,6 +1039,37 @@ mod tests {
|
|
|
1011
1039
|
)));
|
|
1012
1040
|
}
|
|
1013
1041
|
|
|
1042
|
+
#[test]
|
|
1043
|
+
fn rich_text_shared_surface_preserves_spans_and_rebuilds_base_typography() {
|
|
1044
|
+
ffi::test::reset();
|
|
1045
|
+
let node = RichText::new(vec![span("Bold").bold(), span(" plain")]);
|
|
1046
|
+
crate::node::TextTypographySurface::font_size(&node, 23.0);
|
|
1047
|
+
crate::node::TextLayoutSurface::wrapping(&node, true);
|
|
1048
|
+
crate::node::TextSelectionSurface::selection_range(&node, 1, 4);
|
|
1049
|
+
node.build();
|
|
1050
|
+
|
|
1051
|
+
let calls = ffi::test::take_calls();
|
|
1052
|
+
assert!(calls.iter().any(|call| matches!(
|
|
1053
|
+
call,
|
|
1054
|
+
Call::SetText { text, .. } if text == "Bold plain"
|
|
1055
|
+
)));
|
|
1056
|
+
assert!(calls
|
|
1057
|
+
.iter()
|
|
1058
|
+
.any(|call| matches!(call, Call::SetTextStyleRuns { run_count: 2, .. })));
|
|
1059
|
+
assert!(calls.iter().any(|call| matches!(
|
|
1060
|
+
call,
|
|
1061
|
+
Call::SetFont { size, .. } if (*size - 23.0).abs() < f32::EPSILON
|
|
1062
|
+
)));
|
|
1063
|
+
assert!(calls.iter().any(|call| matches!(
|
|
1064
|
+
call,
|
|
1065
|
+
Call::SetTextSelectionRange {
|
|
1066
|
+
start: 1,
|
|
1067
|
+
end: 4,
|
|
1068
|
+
..
|
|
1069
|
+
}
|
|
1070
|
+
)));
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1014
1073
|
#[test]
|
|
1015
1074
|
fn text_layout_waits_for_loaded_and_fonts_before_reporting_ready() {
|
|
1016
1075
|
ffi::test::reset();
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
pub(crate) fn scalar_count(text: &str) -> u32 {
|
|
2
|
+
text.chars().count() as u32
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
pub(crate) fn scalar_to_byte(text: &str, scalar_index: u32) -> u32 {
|
|
6
|
+
let target = scalar_index.min(scalar_count(text)) as usize;
|
|
7
|
+
if target == 0 {
|
|
8
|
+
return 0;
|
|
9
|
+
}
|
|
10
|
+
text.char_indices()
|
|
11
|
+
.nth(target)
|
|
12
|
+
.map(|(byte, _)| byte as u32)
|
|
13
|
+
.unwrap_or(text.len() as u32)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
pub(crate) fn byte_to_scalar(text: &str, byte_index: u32) -> u32 {
|
|
17
|
+
let target = (byte_index as usize).min(text.len());
|
|
18
|
+
let mut scalar_index = 0;
|
|
19
|
+
for (byte, character) in text.char_indices() {
|
|
20
|
+
if target <= byte || target < byte + character.len_utf8() {
|
|
21
|
+
return scalar_index;
|
|
22
|
+
}
|
|
23
|
+
scalar_index += 1;
|
|
24
|
+
}
|
|
25
|
+
scalar_index
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#[cfg(test)]
|
|
29
|
+
mod tests {
|
|
30
|
+
use super::*;
|
|
31
|
+
|
|
32
|
+
#[test]
|
|
33
|
+
fn scalar_and_utf8_byte_offsets_round_trip_at_character_boundaries() {
|
|
34
|
+
let text = "A你😀Z";
|
|
35
|
+
let expected_bytes = [0, 1, 4, 8, 9];
|
|
36
|
+
for (scalar, byte) in expected_bytes.into_iter().enumerate() {
|
|
37
|
+
assert_eq!(scalar_to_byte(text, scalar as u32), byte);
|
|
38
|
+
assert_eq!(byte_to_scalar(text, byte), scalar as u32);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#[test]
|
|
43
|
+
fn byte_offsets_inside_a_multibyte_scalar_clamp_to_its_leading_boundary() {
|
|
44
|
+
let text = "A你😀Z";
|
|
45
|
+
assert_eq!(byte_to_scalar(text, 2), 1);
|
|
46
|
+
assert_eq!(byte_to_scalar(text, 6), 2);
|
|
47
|
+
}
|
|
48
|
+
}
|