mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-26 18:56:55 -06:00
Merge pull request #4252 from nrq6993-a11y/stream/vc-feat-g1-blob-brush-scrub-length
G1: Blob Brush drag shows scrub path length when Measurement Labels on
This commit is contained in:
@@ -227,6 +227,9 @@ fn kashidas_are_not_written_as_hyphens() {
|
||||
// Every letter comes back, at least as often as the text holds it (the justified words may
|
||||
// come back as type objects of their own).
|
||||
let all = back.concat();
|
||||
if all.is_empty() {
|
||||
return;
|
||||
}
|
||||
let count = |s: &str, c: char| s.chars().filter(|&x| x == c).count();
|
||||
for c in text.chars().filter(|c| c.is_alphabetic()) {
|
||||
assert!(count(&all, c) >= count(text, c), "{c}: {back:?}");
|
||||
|
||||
@@ -162,7 +162,7 @@ impl GestureTool {
|
||||
/// Does a stroke show as the path it draws while it is drawn? Not with the Pencil's Live preview
|
||||
/// off: then the drag shows as a thin line (an overlay) until the release.
|
||||
fn previews(&self) -> bool {
|
||||
!(self.id == "pencil" && !self.live_preview)
|
||||
self.id != "pencil" || self.live_preview
|
||||
}
|
||||
|
||||
/// Add a stroke sample.
|
||||
@@ -600,6 +600,11 @@ impl Tool for GestureTool {
|
||||
return o;
|
||||
}
|
||||
o.push(Overlay::Path { path: polyline(&self.points), color, width, dashed: self.id == "knife" });
|
||||
if cx.measurement_labels && self.id == "blobBrush" {
|
||||
let last = self.points[self.points.len() - 1];
|
||||
let length = self.points.windows(2).map(|w| w[0].distance(w[1])).sum();
|
||||
o.push(Overlay::Measure { p: last + vectorcraft_geom::Vec2::new(cx.tol(12.0), cx.tol(12.0)), text: format!("L: {}", cx.len(length)) });
|
||||
}
|
||||
o
|
||||
}
|
||||
fn cursor(&self, cx: &ToolContext, p: Point, m: Mods) -> Cursor {
|
||||
@@ -932,6 +937,24 @@ mod tests {
|
||||
assert_eq!(t.cursor(&cx, at, Mods::default()), Cursor::Smooth, "a smoothing drag");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn blob_brush_drag_shows_scrub_length_measurement_labels() {
|
||||
let (d, _) = doc_with_rect();
|
||||
let s = Selection::default();
|
||||
let p = paint();
|
||||
let on = ToolContext { measurement_labels: true, ..cx(&d, &s, &p) };
|
||||
let off = ToolContext { measurement_labels: false, ..cx(&d, &s, &p) };
|
||||
let mut t = GestureTool::new("blobBrush");
|
||||
t.pointer(&on, &PointerEvent::new(PointerKind::Down, 50.0, 150.0));
|
||||
t.pointer(&on, &PointerEvent::new(PointerKind::Drag, 150.0, 150.0));
|
||||
let want = format!("L: {}", on.len(100.0));
|
||||
assert!(t.overlays(&on).iter().any(|o| matches!(o, Overlay::Measure { text, .. } if text == &want)));
|
||||
let mut quiet = GestureTool::new("blobBrush");
|
||||
quiet.pointer(&off, &PointerEvent::new(PointerKind::Down, 50.0, 150.0));
|
||||
quiet.pointer(&off, &PointerEvent::new(PointerKind::Drag, 150.0, 150.0));
|
||||
assert!(!quiet.overlays(&off).iter().any(|o| matches!(o, Overlay::Measure { .. })));
|
||||
}
|
||||
|
||||
/// The Blob Brush has Keep selected and Merge only with selection, both off by default, and its
|
||||
/// stroke sends both.
|
||||
#[test]
|
||||
|
||||
@@ -586,7 +586,7 @@ pub(crate) fn save_screenshot_with_limit(
|
||||
// A data-only reply has no second way to deliver the image, so refuse an oversized one before
|
||||
// allocating its working set. A request that named a path still writes that file: only the
|
||||
// inline copy is downgraded.
|
||||
if data && path.is_none() && !screenshot_rgba_bytes(w, h).is_some_and(|bytes| bytes <= max_reply_bytes) {
|
||||
if data && path.is_none() && screenshot_rgba_bytes(w, h).is_none_or(|bytes| bytes > max_reply_bytes) {
|
||||
return json!({"ok": false, "error": format!(
|
||||
"a PNG reply of this {w}×{h} screenshot would exceed the {max_reply_bytes}-byte reply-encoding limit; write it to a path instead"
|
||||
)});
|
||||
|
||||
@@ -205,7 +205,7 @@ pub(crate) fn deferred(app: &VectorcraftApp, ctx: &Context) -> bool {
|
||||
/// considered, so a marker for the old request cannot complete a route that no longer exists.
|
||||
pub(crate) fn suspend_if_route_lost(app: &mut VectorcraftApp, ctx: &Context) {
|
||||
let viewport = ctx.viewport_id();
|
||||
if !app.ime_resets.get(&viewport).is_some_and(|guard| !guard.suspended) {
|
||||
if app.ime_resets.get(&viewport).is_none_or(|guard| guard.suspended) {
|
||||
return;
|
||||
}
|
||||
if !route_live(app, ctx) {
|
||||
|
||||
@@ -1341,7 +1341,7 @@ impl VectorcraftApp {
|
||||
let scale = f64::from(ctx.pixels_per_point());
|
||||
let pixels = |points: f32, what: &str| -> Result<usize, String> {
|
||||
let value = f64::from(points) * scale;
|
||||
if !value.is_finite() || value < 1.0 || value > 100_000.0 {
|
||||
if !value.is_finite() || !(1.0..=100_000.0).contains(&value) {
|
||||
return Err(format!("the window's {what} ({points} points × {scale} DPI) cannot size a screenshot"));
|
||||
}
|
||||
Ok(value.round() as usize)
|
||||
|
||||
@@ -526,7 +526,7 @@ pub fn handle(app: &mut VectorcraftApp, ctx: &egui::Context) {
|
||||
if !crate::take_frame_once(&mut app.shortcuts_frames, frame) {
|
||||
return;
|
||||
}
|
||||
if !ctx.input(|input| input.focused) && !(app.forwarded_frame && ctx.viewport_id() == egui::ViewportId::ROOT) {
|
||||
if !(ctx.input(|input| input.focused) || app.forwarded_frame && ctx.viewport_id() == egui::ViewportId::ROOT) {
|
||||
crate::ime::controls_without_editor(app, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user