Brackets: keep to the tools whose size the keys are documented for

The typed [ and ] now reach the Blob Brush, the Eraser and the Symbolism
tools, whose bracket keys are in the public shortcut lists. A size of the
Paintbrush's own (and path.freehand's scale) is left out until its
behaviour is decided: #1661 stays open for that.
This commit is contained in:
bflatastic committed 2026-10-14 03:55:41 +07:00
1 parent 3f1e72d983
commit 3152436020
4 files changed
+28 -94

No files matched your search

+2 -5
View File
@@ -24,7 +24,7 @@ pub fn specs() -> Vec<CommandSpec> {
"Pencil",
[],
None,
"{points: [[x,y]…] or [[x,y,pressure]…] (pen pressure 0..1: the stroke keeps it, for Calligraphic brushes with Pressure variation; a point without one presses fully), fidelity?: pt (1.5), closed?, style?: \"pencil\"|\"brush\", fill?: bool, extend?: {id, end: \"start\"|\"end\"}, scale?: number (1; the Paintbrush's size, set with [ and ]: a new stroke drawn at this times the stroke weight, which stays as it is)} fit a freehand stroke → {id}",
"{points: [[x,y]…] or [[x,y,pressure]…] (pen pressure 0..1: the stroke keeps it, for Calligraphic brushes with Pressure variation; a point without one presses fully), fidelity?: pt (1.5), closed?, style?: \"pencil\"|\"brush\", fill?: bool, extend?: {id, end: \"start\"|\"end\"}} fit a freehand stroke → {id}",
has_doc,
freehand
),
@@ -618,10 +618,7 @@ fn freehand(s: &mut Session, p: &Value) -> Result<Value> {
// A pencil path with a fill keeps a stroke of None (#1679); only one that would show nothing
// gets black. A brush is its stroke.
let stroke = if brush || fill.is_none() { stroke_paint(s) } else { s.paint.stroke.clone() };
// The Paintbrush's own size scales the stroke it draws, not the weight new art takes.
let scale = f64_or(p, "scale", 1.0);
let scale = if scale.is_finite() { scale.clamp(0.1, 100.0) } else { 1.0 };
let mut look = s.new_art_look(fill, stroke, s.paint.stroke_width.max(0.1) * scale);
let mut look = s.new_art_look(fill, stroke, s.paint.stroke_width.max(0.1));
if let Some(st) = look.appearance.stroke_mut() {
st.pressure = pressure;
}
+1 -29
View File
@@ -3,7 +3,7 @@
use serde_json::{Value, json};
use vectorcraft_doc::{Document, Node, NodeKind};
use vectorcraft_geom::Rect;
use vectorcraft_tools::{Mods, PointerEvent, PointerKind, ToolKey};
use vectorcraft_tools::{Mods, PointerEvent, PointerKind};
use super::*;
@@ -590,31 +590,3 @@ fn brushes_and_symbols_survive_vectorcraft_round_trip() {
let b = s2.doc().unwrap().doc.node(NodeId(r["id"].as_u64().unwrap())).unwrap().geometric_bounds().unwrap();
assert!(close(b, Rect::new(60.0, 80.0, 140.0, 120.0), 1e-9));
}
/// #1661: with the Paintbrush, `]` and `[` size the brush itself, a tenth a press: the stroke
/// weight new art takes stays, the selected path keeps its stroke, nothing goes on the undo list,
/// and the next stroke is drawn at the new size.
#[test]
fn paintbrush_brackets_size_the_next_stroke_and_leave_the_weight() {
let mut s = session();
let v = ViewInfo::default();
let selected = rect(&mut s, 0.0, 0.0, 50.0, 50.0);
s.execute("stroke.set", &json!({"weight": 3})).unwrap();
let before = node(&s, selected);
let undo = s.doc().unwrap().history.undo.len();
s.select_tool("paintbrush", v).unwrap();
for _ in 0..2 {
s.tool_key(ToolKey::BracketRight, Mods::default(), v).unwrap();
}
s.tool_key(ToolKey::BracketLeft, Mods::default(), v).unwrap();
assert_eq!(s.paint.stroke_width, 3.0, "the weight stays");
assert_eq!(node(&s, selected), before, "the selection keeps its stroke");
assert_eq!(s.doc().unwrap().history.undo.len(), undo, "nothing to undo");
for (k, x, y) in [(PointerKind::Down, 100.0, 100.0), (PointerKind::Drag, 150.0, 130.0), (PointerKind::Up, 200.0, 110.0)] {
s.pointer(&PointerEvent::new(k, x, y), v).unwrap();
}
let drawn = s.doc().unwrap().selection.objects[0];
assert_ne!(drawn, selected);
assert!((node(&s, drawn).appearance.stroke().unwrap().width - 3.0 * 1.1).abs() < 1e-12);
assert_eq!(s.paint.stroke_width, 3.0);
}