Ported examples 00 and 01 to proc macro interface.

This commit is contained in:
2026-03-21 21:51:50 -04:00
parent 437b318ad9
commit c9966b79ef
8 changed files with 864 additions and 42 deletions

View File

@@ -114,7 +114,7 @@ impl PointerRouter {
match event.kind {
PointerEventKind::Move => {
if let Some(target) = hit_target.clone() {
if let Some(target) = self.pressed.clone().or(hit_target.clone()) {
routed.push(RoutedPointerEvent {
kind: RoutedPointerEventKind::Move,
target,
@@ -314,6 +314,36 @@ mod tests {
);
}
#[test]
fn router_prefers_pressed_target_on_pointer_move() {
let mut router = PointerRouter::new();
let tree = interaction_tree();
let _ = router.route(
&tree,
PointerEvent::new(
0,
Point::new(20.0, 20.0),
PointerEventKind::Down {
button: PointerButton::Primary,
},
),
);
let routed = router.route(
&tree,
PointerEvent::new(0, Point::new(160.0, 20.0), PointerEventKind::Move),
);
assert!(
routed
.iter()
.any(|event| event.kind == RoutedPointerEventKind::Move)
);
assert_eq!(
routed.last().unwrap().target.element_id,
Some(ElementId::new(1))
);
}
#[test]
fn router_routes_scroll_to_deepest_hover_target() {
let mut router = PointerRouter::new();

View File

@@ -585,6 +585,7 @@ impl SceneSnapshot {
mod tests {
use super::{Color, Point, PreparedText, Rect};
use crate::TextSelectionStyle;
use crate::{TextStyle, TextSystem, TextWrap};
#[test]
fn prepared_text_hit_testing_clamps_to_nearest_cluster_boundary() {
@@ -703,4 +704,22 @@ mod tests {
assert_eq!(text.line_start_offset(6), Some(4));
assert_eq!(text.line_end_offset(2), Some(4));
}
#[test]
fn prepared_text_multiline_selection_stays_on_target_line() {
let mut text_system = TextSystem::new();
let style = TextStyle::new(16.0, Color::rgb(0xFF, 0xFF, 0xFF)).with_wrap(TextWrap::None);
let text = text_system.prepare("ab\ncd\nef", Point::new(10.0, 20.0), &style);
assert_eq!(text.lines.len(), 3);
let target_line = &text.lines[1];
let y = target_line.rect.origin.y + target_line.rect.size.height * 0.5;
let start = text.byte_offset_for_position(Point::new(target_line.rect.origin.x, y));
let end = text.byte_offset_for_position(Point::new(target_line.rect.origin.x + 16.0, y));
let rects = text.selection_rects(start, end);
assert_eq!(rects.len(), 1);
assert_eq!(rects[0].origin.y, target_line.rect.origin.y);
}
}

View File

@@ -418,6 +418,7 @@ impl TextSystem {
}
self.frame_stats.buffer_build_ms += buffer_build_started.elapsed().as_secs_f64() * 1_000.0;
let line_starts = line_start_offsets(&combined_text(spans));
let mut measured_width: f32 = 0.0;
let mut measured_height: f32 = 0.0;
let mut lines = Vec::new();
@@ -430,6 +431,7 @@ impl TextSystem {
measured_width = measured_width.max(run.line_w);
measured_height = measured_height.max(run.line_top + run.line_height);
let x_offset = aligned_line_offset(style.align, width, run.line_w);
let line_offset = line_starts.get(run.line_i).copied().unwrap_or(0);
let glyph_start = glyphs.len();
glyphs.extend(run.glyphs.iter().map(move |glyph| {
let physical = glyph.physical((x_offset, run.line_y), 1.0);
@@ -438,13 +440,19 @@ impl TextSystem {
advance: glyph.w,
color: glyph.color_opt.map_or(style.color, color_from_cosmic),
cache_key: Some(physical.cache_key),
text_start: glyph.start,
text_end: glyph.end,
text_start: line_offset + glyph.start,
text_end: line_offset + glyph.end,
}
}));
let glyph_end = glyphs.len();
let text_start = run.glyphs.first().map_or(0, |glyph| glyph.start);
let text_end = run.glyphs.last().map_or(text_start, |glyph| glyph.end);
let text_start = run
.glyphs
.first()
.map_or(line_offset, |glyph| line_offset + glyph.start);
let text_end = run
.glyphs
.last()
.map_or(text_start, |glyph| line_offset + glyph.end);
lines.push(PreparedTextLine {
rect: Rect::new(x_offset, run.line_top, run.line_w.max(0.0), run.line_height),
text_start,
@@ -504,6 +512,28 @@ fn combined_text(spans: &[TextSpan]) -> String {
text
}
fn line_start_offsets(text: &str) -> Vec<usize> {
let mut starts = vec![0];
let bytes = text.as_bytes();
let mut index = 0;
while index < bytes.len() {
match bytes[index] {
b'\n' => starts.push(index + 1),
b'\r' => {
if bytes.get(index + 1) == Some(&b'\n') {
starts.push(index + 2);
index += 1;
} else {
starts.push(index + 1);
}
}
_ => {}
}
index += 1;
}
starts
}
fn layout_cache_key(
spans: &[TextSpan],
style: &TextStyle,