mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-01 06:06:49 -06:00
Merge pull request #2047 from MarekSpodBiedry/issue-2042
Spellcheck squiggles follow the text frame rotation (#2042)
This commit is contained in:
@@ -370,17 +370,31 @@ pub(super) fn draw_dynamic_spelling(app: &DesignApp, ctx: &egui::Context, painte
|
||||
};
|
||||
let y = l.baseline + l.descent * 0.5;
|
||||
let (p0, p1) = (xf.to_screen(m * Point::new(x0, y)), xf.to_screen(m * Point::new(x1, y)));
|
||||
// A zigzag 2 px high, 4 px per wave.
|
||||
let n = ((p1.x - p0.x) / 2.0).max(1.0) as usize;
|
||||
let pts: Vec<Pos2> =
|
||||
(0..=n).map(|k| pos2(p0.x + (p1.x - p0.x) * k as f32 / n as f32, p0.y + if k % 2 == 0 { 0.0 } else { 2.0 })).collect();
|
||||
painter.add(egui::Shape::line(pts, red));
|
||||
// Screen direction of the text's own "down", so the wave hangs below the baseline in rotated, flipped and vertical frames.
|
||||
let down = xf.to_screen(m * Point::new(x0, y + 1.0)) - p0;
|
||||
painter.add(egui::Shape::line(squiggle_points(p0, p1, down), red));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Zigzag points for a spelling squiggle from `p0` to `p1` (screen space): 2 px high, 4 px per wave,
|
||||
/// offset along `down` (the screen direction of the text's own "down") so it follows the text frame's
|
||||
/// rotation and flips.
|
||||
pub(super) fn squiggle_points(p0: Pos2, p1: Pos2, down: egui::Vec2) -> Vec<Pos2> {
|
||||
let d = p1 - p0;
|
||||
let n = (d.length() / 2.0).max(1.0) as usize;
|
||||
let len = down.length();
|
||||
let off = if len > 1e-6 { down / len } else { egui::vec2(0.0, 1.0) };
|
||||
(0..=n)
|
||||
.map(|k| {
|
||||
let wave = if k % 2 == 0 { 0.0 } else { 2.0 };
|
||||
p0 + d * (k as f32 / n as f32) + off * wave
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Plain text of the current text selection (story markers resolved to readable characters).
|
||||
pub fn selected_text(app: &DesignApp) -> Option<String> {
|
||||
let st = app.session.active()?;
|
||||
@@ -392,3 +406,38 @@ pub fn selected_text(app: &DesignApp) -> Option<String> {
|
||||
}
|
||||
Some(s.replace(designcraft_doc::story::FORCED_LINE_BREAK, "\n"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn squiggle_horizontal_offsets_down() {
|
||||
let pts = squiggle_points(pos2(0.0, 10.0), pos2(20.0, 10.0), egui::vec2(0.0, 1.0));
|
||||
assert_eq!(pts.len(), 11);
|
||||
assert!((pts[0].y - 10.0).abs() < 1e-4);
|
||||
assert!((pts[1].y - 12.0).abs() < 1e-4);
|
||||
assert!((pts[1].x - 2.0).abs() < 1e-4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn squiggle_follows_rotation() {
|
||||
// Frame rotated 90 degrees: the line runs down the screen and the text's "down" points left,
|
||||
// so the wave must move sideways, not along y.
|
||||
let pts = squiggle_points(pos2(10.0, 0.0), pos2(10.0, 20.0), egui::vec2(-3.0, 0.0));
|
||||
assert_eq!(pts.len(), 11);
|
||||
assert!((pts[1].y - 2.0).abs() < 1e-4);
|
||||
assert!((pts[1].x - 8.0).abs() < 1e-4);
|
||||
assert!((pts[0].x - 10.0).abs() < 1e-4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn squiggle_follows_horizontal_flip() {
|
||||
// A horizontally flipped frame runs the word right to left; the wave still hangs below it.
|
||||
let pts = squiggle_points(pos2(20.0, 10.0), pos2(0.0, 10.0), egui::vec2(0.0, 1.0));
|
||||
assert_eq!(pts.len(), 11);
|
||||
assert!((pts[1].x - 18.0).abs() < 1e-4);
|
||||
assert!((pts[1].y - 12.0).abs() < 1e-4);
|
||||
assert!(pts[10].x.abs() < 1e-4);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user