mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 20:01:43 +00:00
5949: keep panel wheel turns out of canvas zoom glides
This commit is contained in:
@@ -202,7 +202,9 @@ fn wheel_view(
|
||||
) -> (egui::PointerState, egui::Modifiers, bool, Option<Pos2>) {
|
||||
let line = ui.ctx().options(|o| o.input_options.line_scroll_speed);
|
||||
let wheel_zooms = app.session.prefs.zoom_with_mouse_wheel;
|
||||
let animate = animated_zoom(&app.session.prefs);
|
||||
// A docked field may be drawn later and has not consumed its wheel event yet. Only canvas
|
||||
// hover may start a zoom glide; existing glides still decay outside the canvas in `wheel`.
|
||||
let animate = animated_zoom(&app.session.prefs) && resp.hovered();
|
||||
let turn_id = egui::Id::unique("canvas-wheel-turn");
|
||||
let turn_before: WheelTurn = ui.data(|d| d.get_temp(turn_id)).unwrap_or_default();
|
||||
let mut turn = turn_before;
|
||||
|
||||
@@ -4355,6 +4355,80 @@ fn zoom_with_mouse_wheel_preference() {
|
||||
assert!((zoom - 1.0).abs() < 1e-9 && scroll.x < -1.0 && scroll.y == 0.0, "on: Cmd-wheel scrolls sideways ({zoom}, {scroll:?})");
|
||||
}
|
||||
|
||||
/// A numeric panel drawn after the canvas owns its wheel turn even when the pointer enters the
|
||||
/// canvas on the next frame (#5949). Only a subsequent turn over the canvas starts a zoom glide.
|
||||
#[test]
|
||||
fn wheel_over_a_numeric_panel_field_does_not_start_a_canvas_zoom_glide() {
|
||||
use std::cell::Cell;
|
||||
for focused in [false, true] {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 400, "height": 300})).unwrap();
|
||||
for key in ["zoomWithMouseWheel", "animatedZoom", "gpuPerformance"] {
|
||||
app.run("prefs.set", json!({"key": key, "value": true})).unwrap();
|
||||
}
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let value = Cell::new(10.0);
|
||||
let field_rect = Cell::new(egui::Rect::NOTHING);
|
||||
let field_id = Cell::new(egui::Id::NULL);
|
||||
let mut time = 0.0;
|
||||
let mut run = |app: &mut VectorcraftApp, events| {
|
||||
time += 0.016;
|
||||
let raw = egui::RawInput {
|
||||
time: Some(time),
|
||||
screen_rect: Some(egui::Rect::from_min_size(Pos2::ZERO, vec2(800.0, 600.0))),
|
||||
events,
|
||||
..Default::default()
|
||||
};
|
||||
let mut out = ctx.run_ui(raw, |ui| {
|
||||
// Match dock rendering order: canvas first, the numeric panel afterward.
|
||||
let mut canvas_ui = ui.new_child(egui::UiBuilder::new().max_rect(egui::Rect::from_min_size(Pos2::ZERO, vec2(550.0, 500.0))));
|
||||
show(app, &mut canvas_ui);
|
||||
let mut panel_ui = ui.new_child(egui::UiBuilder::new().max_rect(egui::Rect::from_min_size(pos2(600.0, 20.0), vec2(150.0, 100.0))));
|
||||
field_id.set(panel_ui.scope_id().with("number"));
|
||||
if let Some(v) = crate::widgets::plain_field(&mut panel_ui, "number", value.get(), "", 0, 80.0) {
|
||||
value.set(v);
|
||||
}
|
||||
field_rect.set(panel_ui.min_rect());
|
||||
});
|
||||
out.textures_delta.clear();
|
||||
};
|
||||
run(&mut app, vec![]);
|
||||
if focused {
|
||||
ctx.memory_mut(|m| m.request_focus(field_id.get()));
|
||||
}
|
||||
let over_field = field_rect.get().center();
|
||||
run(&mut app, vec![egui::Event::PointerMoved(over_field)]);
|
||||
let before = *app.view().unwrap();
|
||||
let turn = || egui::Event::MouseWheel {
|
||||
unit: egui::MouseWheelUnit::Line,
|
||||
delta: vec2(0.0, 1.0),
|
||||
phase: egui::TouchPhase::Move,
|
||||
modifiers: egui::Modifiers::NONE,
|
||||
source: egui::MouseWheelSource::Unknown,
|
||||
};
|
||||
run(&mut app, vec![turn()]);
|
||||
assert_eq!(value.get(), 11.0, "the hovered field steps, focused: {focused}");
|
||||
assert_eq!(ctx.memory(|m| m.has_focus(field_id.get())), focused, "hover does not take focus");
|
||||
assert_eq!(app.view().unwrap().zoom, before.zoom);
|
||||
let over_canvas = app.canvas_rect.unwrap().center();
|
||||
run(&mut app, vec![egui::Event::PointerMoved(over_canvas)]);
|
||||
for _ in 0..20 {
|
||||
run(&mut app, vec![]);
|
||||
assert_eq!(app.view().unwrap().zoom, before.zoom, "a panel turn cannot leave a canvas glide, focused: {focused}");
|
||||
assert_eq!(app.view().unwrap().center, before.center);
|
||||
}
|
||||
run(&mut app, vec![turn()]);
|
||||
let first = app.view().unwrap().zoom;
|
||||
assert!(first > before.zoom, "a turn over the canvas still zooms");
|
||||
for _ in 0..20 {
|
||||
run(&mut app, vec![]);
|
||||
}
|
||||
assert!(app.view().unwrap().zoom > first, "the canvas turn still glides over subsequent frames");
|
||||
assert_eq!(value.get(), 11.0, "the canvas turn does not step the field");
|
||||
}
|
||||
}
|
||||
|
||||
/// #888: with Zoom with Mouse Wheel, a wheel notch's zoom glides in over a few frames, as a
|
||||
/// scroll does, instead of jumping on the frame it arrives; it ends at the same zoom.
|
||||
#[test]
|
||||
|
||||
@@ -732,6 +732,7 @@ fn the_wheel_scrolls_the_panel_unless_over_a_numeric_field() {
|
||||
}
|
||||
}
|
||||
|
||||
/// A wheel turn over an unfocused field steps it without consuming an arrow key in the same frame.
|
||||
#[test]
|
||||
fn hover_wheel_keeps_arrow_keys_for_the_keyboard_focus() {
|
||||
let mut f = Field::new();
|
||||
@@ -752,6 +753,7 @@ fn hover_wheel_keeps_arrow_keys_for_the_keyboard_focus() {
|
||||
assert!(!f.ctx.memory(|m| m.has_focus(f.id.get())));
|
||||
}
|
||||
|
||||
/// Hover steps stop at both bounds, leave mixed values blank, and never edit disabled fields.
|
||||
#[test]
|
||||
fn hover_wheel_preserves_limits_mixed_values_and_disabled_fields() {
|
||||
for (value, enabled, dy, want) in [
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Parity with Adobe Illustrator
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-07 · **Change:** minor (numeric wheel stepping on hover, #5949; the canvas keeps selection outlines and anchors between frames; Indian-language hyphenation review and license allowlist, #4947; Stroke gradients: an arrowhead aligned to the tip is painted to the corners of its base, #5964; Drop Shadow and glow dialogs: spinner arrows, #5367, #5368; Stroke Weight Up and Down shortcuts, #5797; Hindi catalog and contributor loanword preferences; full wording review in progress; Properties in Edit Artboards: a Transform section with the reference point above the Artboards section, #5219; the Control bar's Stroke: and Opacity: links scrub their fields, #4088; an image zoomed in on is separated, colorized or proofed only where it shows (#4155); a document's first frame renders on the render worker, so opening a heavy file no longer freezes the window, #4155; Control bar Paragraph section with type selected, #5372; translating unchanged type reuses its glyph and character-stroke outlines; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-08 · **Change:** minor (panel wheel turns cannot seed a later canvas zoom glide, #5949; numeric wheel stepping on hover, #5949; the canvas keeps selection outlines and anchors between frames; Indian-language hyphenation review and license allowlist, #4947; Stroke gradients: an arrowhead aligned to the tip is painted to the corners of its base, #5964; Drop Shadow and glow dialogs: spinner arrows, #5367, #5368; Stroke Weight Up and Down shortcuts, #5797; Hindi catalog and contributor loanword preferences; full wording review in progress; Properties in Edit Artboards: a Transform section with the reference point above the Artboards section, #5219; the Control bar's Stroke: and Opacity: links scrub their fields, #4088; an image zoomed in on is separated, colorized or proofed only where it shows (#4155); a document's first frame renders on the render worker, so opening a heavy file no longer freezes the window, #4155; Control bar Paragraph section with type selected, #5372; translating unchanged type reuses its glyph and character-stroke outlines; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
|
||||
|
||||
## Feature submission evidence
|
||||
|
||||
Numeric fields step on wheel hover without taking keyboard focus (#5949). Arrow keys still require focus; modifiers, units, limits, mixed values and existing rounding stay in the shared stepping path. Headless regressions in `tests/numfields.rs` cover hovered unfocused fields, focused fields, trackpad accumulation and panel scroll exclusion. Scores and estimates unchanged.
|
||||
Numeric fields step on wheel hover without taking keyboard focus (#5949). Arrow keys still require focus; modifiers, units, limits, mixed values and existing rounding stay in the shared stepping path. Headless regressions in `tests/numfields.rs` cover hovered unfocused fields, focused fields, trackpad accumulation and panel scroll exclusion. A canvas-first/panel-second regression also checks that a field turn cannot start a canvas zoom glide when the pointer enters the canvas on the next frame. Scores and estimates unchanged.
|
||||
|
||||
Raster rendering fits and preflattens curved stroke outlines more tightly only below four times the raster tolerance, retaining thin-band coverage without changing stroke weight or vector export geometry. Current cached character/object outlines, cropped long strokes, gradient clips and effect rasters share the helper; cropped-region reuse and guarded flattening remain. The unchanged `fractional_curved_strokes_retain_coverage_between_notches` regression covers fractional weights, rotation, phase, opacity and f32-rounded endpoints. This is a quality/cost tradeoff, not a speed claim. Scores and estimates unchanged.
|
||||
|
||||
@@ -725,7 +725,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
- Performance › Real-time Drawing and Editing off defers a drag's edits to its release, but a ruler guide dragged out of a ruler or moved still shows as it is dragged, where only its position label showed (#4646; `a_guide_dragged_out_of_a_ruler_shows_while_dragged`, `real_time_drawing_off_still_shows_a_dragged_guide`).
|
||||
- With Real-time Drawing and Editing off, a dragged selection whose outlines have more than 100,000 points shows its moved bounds instead, as the selection at rest does (#525, #2460; `real_time_drawing_off_draws_the_bounds_of_a_selection_too_big_to_outline`).
|
||||
- Dialogs move by dragging their heading (the band down from the top edge, as a title bar), stay on screen and keep where they were moved for the session; the form dialogs' choices are dropdowns (Offset Path's Joins, Average's and Shear's and Reflect's axis), and Offset Path lists Offset, Joins, Miter Limit and previews (#423).
|
||||
- Dialogs open with their first field focused and its value selected: type a value and press Enter (Move, Rotate, Scale…). A dialog opened from a menu takes the keyboard focus every time it opens, not only the first (#1367), and one whose first field starts greyed out (Blend Options on Smooth Color, Layers Panel Options) gives the focus to that field once it is enabled (#1395). Number fields in panels, the Control bar and dialogs (preferences too) step with Up/Down, or with the mouse wheel over the hovered field without requiring focus (#485: a notch a step; the panel under it then stays put, and an unfocused field leaves the wheel to scrolling) (Shift: ten, Ctrl/Cmd: a tenth of their unit), applied at once.
|
||||
- Dialogs open with their first field focused and its value selected: type a value and press Enter (Move, Rotate, Scale…). A dialog opened from a menu takes the keyboard focus every time it opens, not only the first (#1367), and one whose first field starts greyed out (Blend Options on Smooth Color, Layers Panel Options) gives the focus to that field once it is enabled (#1395). Number fields in panels, the Control bar and dialogs (preferences too) step with Up/Down, or with the mouse wheel over the hovered field without requiring focus (#485, #5949: a notch a step; the panel under it then stays put, and a disabled field leaves the wheel to scrolling) (Shift: ten, Ctrl/Cmd: a tenth of their unit), applied at once.
|
||||
- While Alt (Option on macOS) is held, the Flare Tool Options' Cancel button reads Reset, which puts every option back to the Flare tool's default and leaves the dialog open (`ui.dialogReset`).
|
||||
- A plain step of a number field (Up/Down or a wheel notch) goes to the next whole unit in its direction and a Ctrl/Cmd step goes to the next tenth, so 5.1 mm steps up to 6 mm and down to 5 mm (#2881). A Shift step adds or takes ten and keeps the fraction.
|
||||
- In the number, text and color fields of the panels and the Control bar, Shift+Enter (Shift+Return) applies the value and keeps the field active with its value selected; a text box of several lines takes it as a line break. In a dialog, Shift+Enter applies the value and confirms the dialog, as Enter does.
|
||||
@@ -1727,6 +1727,7 @@ Edit › Copy and Cut put the selected ruler guides on the clipboard, with the s
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-08 | minor | Panel numeric wheel turns do not seed canvas zoom glides; corrected the disabled-field scroll description (#5949). Scores and estimates unchanged. |
|
||||
| 2026-11-07 | minor | Numeric fields step on wheel hover without taking focus; keyboard focus and existing rounding rules remain (#5949). Scores and estimates unchanged. |
|
||||
| 2026-11-06 | minor | Direct Selection: with Snap to Grid, a dragged straight segment lands its anchors on the grid (#3835); evidence added; scores unchanged. |
|
||||
| 2026-11-06 | minor | Snap to Glyph › Glyph Bounds: the corners of each glyph's box are points a drawn point lands on, also on a curved side (`B`), and the box turns with rotated type, its edges then Angular Guides (#5112; [Snap to Glyph options](https://helpx.adobe.com/illustrator/desktop/design-with-text/special-characters-glyphs/snap-to-glyph-options.html)); scores and estimates unchanged. |
|
||||
|
||||
Reference in New Issue
Block a user