Merge pull request #4229 from nrq6993-a11y/stream/vc-feat3-g4-loaded-text-cursor

G4: draw loaded-text cursor for threaded overflow
This commit is contained in:
BFlat
2026-10-26 13:09:43 +07:00
committed by GitHub
5 changed files with 31 additions and 7 deletions
+1 -1
View File
@@ -300,7 +300,7 @@ fn disagreeing_option(p: &Value, svg: bool) -> std::result::Result<Option<(Strin
.as_object()
.into_iter()
.flatten()
.filter(|(k, v)| !v.is_null() && !matches!(k.as_str(), "path" | "format" | "options") && !(svg && k.as_str() == "svg"))
.filter(|(k, v)| !(v.is_null() || matches!(k.as_str(), "path" | "format" | "options") || (svg && k.as_str() == "svg")))
.map(|(k, v)| (k.clone(), v.clone()))
.collect();
if svg {
+1 -1
View File
@@ -133,7 +133,7 @@ shown_when = [
"The Selection tool after a click on the out port or the in port of selected area type or type on a path, threaded, overflowing or not: the pointer carries that text until a click threads it into a closed path, area type or type on a path, a click on empty canvas makes a new frame of the same kind and shape there, or a drag draws the new frame; from the in port the frame placed comes before the clicked one. Escape or another tool drops it.",
]
hotspot = "Where the new frame's top-left corner goes (the click), or the path clicked."
look = "A small block of text lines: the overflow text the pointer carries. Until it is drawn it borrows the I-beam (Text)."
look = "A small block of text lines: the overflow text the pointer carries."
# ── Pen family ────────────────────────────────────────────────────────────────────────────────────
+2 -2
View File
@@ -741,7 +741,7 @@ impl Cursor {
}
/// The cursor this one borrows until it's drawn: the generic crosshair for the
/// tools, the I-beam for vertical type and loaded text, the Pen's add cursor for the Mesh tool and Puppet
/// tools, the I-beam for vertical type, the Pen's add cursor for the Mesh tool and Puppet
/// Warp, not-allowed for the Scissors away from a path. `None` for a cursor with a look of
/// its own.
pub fn stand_in(self) -> Option<Self> {
@@ -770,7 +770,7 @@ impl Cursor {
| Cursor::SymbolScreener
| Cursor::SymbolStyler
| Cursor::Scissors => Some(Cursor::Crosshair),
Cursor::TypeVertical | Cursor::LoadedText => Some(Cursor::Text),
Cursor::TypeVertical => Some(Cursor::Text),
Cursor::MeshAdd | Cursor::PuppetPin => Some(Cursor::PenAdd),
Cursor::ScissorsNotAllowed => Some(Cursor::NotAllowed),
_ => None,
+3 -3
View File
@@ -878,7 +878,8 @@ fn cursor_icon(c: Cursor) -> egui::CursorIcon {
| Cursor::GroupSelection
| Cursor::CornerRadius
| Cursor::PathBracket
| Cursor::TypeWidget => C::Default,
| Cursor::TypeWidget
| Cursor::LoadedText => C::Default,
Cursor::SelectionCopy => C::Copy,
Cursor::Move => C::Move,
Cursor::Crosshair => C::Crosshair,
@@ -942,8 +943,7 @@ fn cursor_icon(c: Cursor) -> egui::CursorIcon {
| Cursor::Scissors
| Cursor::ScissorsNotAllowed
| Cursor::MeshAdd
| Cursor::PuppetPin
| Cursor::LoadedText => cursor_icon(c.stand_in().unwrap_or(Cursor::Crosshair)),
| Cursor::PuppetPin => cursor_icon(c.stand_in().unwrap_or(Cursor::Crosshair)),
}
}
+24
View File
@@ -294,6 +294,18 @@ fn type_widget(p: &mut Ink, o: Pos2) {
line(p, b + vec2(4.0, 0.0), b + vec2(4.0, 9.0));
}
/// Overflow text the Selection tool carries after a click on the red out port: a small block of
/// lines at the hotspot (where a new frame's top-left would go).
fn loaded_text(p: &mut Ink, o: Pos2) {
let tl = o;
let br = o + vec2(14.0, 11.0);
let frame = vec![tl, pos2(br.x, tl.y), br, pos2(tl.x, br.y)];
poly(p, frame, HALO, INK);
for y in [3.0, 6.5, 10.0] {
line(p, tl + vec2(2.0, y), tl + vec2(12.0, y));
}
}
/// The gradient annotator's stop cursors: the arrow with a plus (add a stop) or minus (delete it)
/// badge.
fn stop_badge(p: &mut Ink, o: Pos2, add: bool) {
@@ -593,6 +605,7 @@ fn glyph(c: Cursor, p: Pos2) -> Option<Vec<Shape>> {
Cursor::Blend | Cursor::BlendObject | Cursor::BlendAnchor => blend(ink, p, c),
Cursor::PathBracket => path_bracket(ink, p),
Cursor::TypeWidget => type_widget(ink, p),
Cursor::LoadedText => loaded_text(ink, p),
Cursor::ShapeBuilder => shape_builder(ink, p, false),
Cursor::ShapeBuilderErase => shape_builder(ink, p, true),
Cursor::Hand => hand(ink, p, false),
@@ -825,6 +838,17 @@ mod tests {
}
}
/// Loaded text after a click on the overflow out port is a text-block glyph, not the I-beam.
#[test]
fn loaded_text_cursor_is_not_the_text_i_beam() {
assert!(Cursor::LoadedText.stand_in().is_none());
let loaded = rasterize(Cursor::LoadedText, 2.0).expect("loaded text bitmap");
let ibeam = rasterize(Cursor::Text, 2.0).expect("text bitmap");
assert_ne!(loaded.rgba, ibeam.rgba);
let [hx, hy] = loaded.hotspot.map(usize::from);
assert!(pixel(&loaded, hx, hy)[3] > 200, "hotspot lies on the drawn frame");
}
#[test]
fn every_glyph_becomes_a_bitmap_with_its_hotspot_inside() {
for ppp in [1.0, 1.25, 1.5, 2.0, 3.0] {