Merge pull request #1013 from Ni-zav/fix/991-shift-stepper-s20261010T1758Z-a74b
fix(widgets): apply Shift and Ctrl modifiers to numeric stepper buttons
This commit is contained in:
commit
c403e57d2a
|
|
@ -123,7 +123,7 @@ Ranked; detail in [docs/roadmap.md](docs/roadmap.md) and [docs/gaps.md](docs/gap
|
|||
|
||||
| Date | What landed |
|
||||
|---|---|
|
||||
| 2026-10-11 | Effect › Brush Strokes: Accented Edges, Angled Strokes, Crosshatch, Dark Strokes, Ink Outlines, Spatter, Sprayed Strokes, Sumi-e (G2) |
|
||||
| 2026-10-11 | Effect › Brush Strokes: Accented Edges, Angled Strokes, Crosshatch, Dark Strokes, Ink Outlines, Spatter, Sprayed Strokes, Sumi-e (G2) Command parameters from agents and files checked before anything changes (paint, place, cuts, dashes, crop, asset ids, anchors, paths, distort; #984–#999); command dialogs keep whole numbers whole, so Create Object Mosaic takes the tiles typed (#1000); stepper arrows take Shift (×10) and Ctrl/Cmd (÷10) like the arrow keys (#991). |
|
||||
| 2026-10-10 | Initial live Revolve (Effect › 3D and Materials, #846, #605), in its own `three-d` crate. Progress docs re-measured and restructured to the craftrules standard (this page, `docs/target-app-parity.md`, `gaps.md`, `ui-parity.md`, the format, hardware, localization, effects and type checklists). Same day: v0.8.0; Effect › Distort, Pixelate and Texture filters (13); German interface; Variables (data merge); Graph Type value axes and tick marks; restart when the first frame never reaches the screen (#964) |
|
||||
| 2026-10-09 | Radial Blur, Smart Blur, Unsharp Mask (gap 2 begins); 340 commits, the busiest day |
|
||||
| 2026-10-08 | v0.5.0–v0.7.0; community contributions: Pen and shape-tool modifiers, Layers, Artboards, Japanese composition, Hebrew/Arabic type, interface languages, saved selections |
|
||||
|
|
|
|||
|
|
@ -139,3 +139,37 @@ fn weight_presets_display_cleanly_in_their_native_unit() {
|
|||
// Units no stroke is measured in keep the pt ladder, in points.
|
||||
assert_eq!(stroke::weight_presets(Unit::Meters), stroke::weight_presets(Unit::Points));
|
||||
}
|
||||
|
||||
/// #991: the spinner left of the Stroke Weight field steps ten with Shift on both arrows and a
|
||||
/// tenth with Ctrl/Cmd, as ↑/↓ do in the focused field, while a plain click steps one point.
|
||||
#[test]
|
||||
fn stroke_weight_stepper_uses_ten_point_shift_steps() {
|
||||
use super::tests_appearance::frame_raw;
|
||||
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let mut app = app_with_rect();
|
||||
run(&mut app, "stroke.set", json!({"weight": 14}));
|
||||
let t = texts(&ctx, &mut app, stroke::show);
|
||||
// The 16 px spinner sits just left of the field's text.
|
||||
let r = text_rect(&t, "14 pt");
|
||||
let x = r.left() - 14.0;
|
||||
let click_step = |app: &mut VectorcraftApp, y: f32, modifiers: egui::Modifiers| {
|
||||
let pos = egui::pos2(x, y);
|
||||
let button = |pressed| egui::Event::PointerButton { pos, button: egui::PointerButton::Primary, pressed, modifiers };
|
||||
for event in [egui::Event::PointerMoved(pos), button(true), button(false)] {
|
||||
let events = vec![egui::Event::ModifiersChanged(modifiers), event];
|
||||
frame_raw(&ctx, app, egui::RawInput { events, ..Default::default() }, stroke::show);
|
||||
}
|
||||
};
|
||||
|
||||
click_step(&mut app, r.center().y - 5.0, egui::Modifiers::SHIFT);
|
||||
assert_eq!(app.session.shown_stroke().unwrap().width, 24.0);
|
||||
click_step(&mut app, r.center().y + 5.0, egui::Modifiers::NONE);
|
||||
assert_eq!(app.session.shown_stroke().unwrap().width, 23.0);
|
||||
click_step(&mut app, r.center().y + 5.0, egui::Modifiers::SHIFT);
|
||||
assert_eq!(app.session.shown_stroke().unwrap().width, 13.0);
|
||||
// Ctrl/Cmd steps a tenth, as ↑/↓ and the wheel do in the field.
|
||||
click_step(&mut app, r.center().y + 5.0, egui::Modifiers::COMMAND);
|
||||
assert!((app.session.shown_stroke().unwrap().width - 12.9).abs() < 1e-6);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1170,8 +1170,8 @@ fn spin_generic(
|
|||
&& let Some(p) = sresp.interact_pointer_pos()
|
||||
&& let Some(v) = value
|
||||
{
|
||||
let nv = if up.contains(p) { v + step } else { v - step };
|
||||
out = Some(SpinPick::Value(nv.max(min)));
|
||||
let modifiers = ui.input(|i| i.modifiers);
|
||||
out = Some(SpinPick::Value(spinner_step(v, step, min, up.contains(p), modifiers)));
|
||||
}
|
||||
let fw = if presets.is_empty() { width - 15.0 } else { width - 34.0 };
|
||||
if let Some(v) = field(ui, fw) {
|
||||
|
|
@ -1198,6 +1198,14 @@ fn spin_generic(
|
|||
out
|
||||
}
|
||||
|
||||
/// Spinner buttons follow the same modifier sizes as ↑/↓ in a focused number field:
|
||||
/// Shift ×10, Ctrl/Cmd ÷10, otherwise the caller's normal step.
|
||||
fn spinner_step(value: f64, step: f64, min: f64, up: bool, modifiers: egui::Modifiers) -> f64 {
|
||||
let multiplier = STEPS.iter().find(|(m, _)| modifiers.matches_logically(*m)).map_or(1.0, |(_, factor)| *factor);
|
||||
let delta = step * multiplier;
|
||||
(value + if up { delta } else { -delta }).max(min)
|
||||
}
|
||||
|
||||
/// Drag phase of a live slider/handle: previews while dragging, commits on release.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Live {
|
||||
|
|
@ -1826,3 +1834,21 @@ pub fn text_presets(ui: &mut Ui, id: impl std::hash::Hash + std::fmt::Debug, val
|
|||
});
|
||||
out
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod spinner_modifier_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn shift_steps_stroke_weight_by_ten_points() {
|
||||
assert_eq!(spinner_step(14.0, 1.0, 0.0, true, egui::Modifiers::SHIFT), 24.0);
|
||||
assert_eq!(spinner_step(14.0, 1.0, 0.0, false, egui::Modifiers::SHIFT), 4.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unmodified_and_command_steps_keep_existing_behavior() {
|
||||
assert_eq!(spinner_step(14.0, 1.0, 0.0, true, egui::Modifiers::NONE), 15.0);
|
||||
assert_eq!(spinner_step(14.0, 1.0, 0.0, false, egui::Modifiers::COMMAND), 13.9);
|
||||
assert_eq!(spinner_step(0.0, 1.0, 0.0, false, egui::Modifiers::SHIFT), 0.0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue