Merge pull request #1734 from AyberkA0/fix/1661-paintbrush-brackets

Part of #1661: [ and ] reach the tools that take them
This commit is contained in:
BFlat authored and GitHub committed 2026-10-14 04:26:29 +07:00
commit 3298c5088c
3 files changed
+69

No files matched your search

+4
View File
@@ -249,6 +249,10 @@ impl Tool for GestureTool {
_ => vec![],
}
}
/// `[` and `]` are the Blob Brush's and the Eraser's: their size (#1661).
fn claims_key(&self, _cx: &ToolContext, key: ToolKey) -> bool {
matches!(key, ToolKey::BracketLeft | ToolKey::BracketRight) && matches!(self.id, "blobBrush" | "eraser")
}
fn key(&mut self, _cx: &ToolContext, key: ToolKey, _m: Mods) -> Vec<Action> {
match key {
ToolKey::Escape if self.active => {
+6
View File
@@ -138,6 +138,9 @@ impl Tool for SymbolismTool {
_ => vec![],
}
}
fn claims_key(&self, _cx: &ToolContext, key: ToolKey) -> bool {
matches!(key, ToolKey::BracketLeft | ToolKey::BracketRight)
}
fn key(&mut self, _cx: &ToolContext, key: ToolKey, m: Mods) -> Vec<Action> {
match key {
ToolKey::BracketLeft if m.shift => self.intensity = (self.intensity - 1.0).max(1.0),
@@ -223,6 +226,9 @@ impl Tool for BrushPaintTool {
let acts = self.inner.pointer(cx, ev);
self.map(cx, acts)
}
fn claims_key(&self, cx: &ToolContext, key: ToolKey) -> bool {
self.inner.claims_key(cx, key)
}
fn key(&mut self, cx: &ToolContext, key: ToolKey, m: Mods) -> Vec<Action> {
let acts = self.inner.key(cx, key, m);
self.map(cx, acts)
+59
View File
@@ -391,6 +391,38 @@ pub fn handle(app: &mut VectorcraftApp, ctx: &egui::Context) {
}
}
}
// `[` and `]` the active tool takes (the Blob Brush's and the Eraser's size, the Symbolism
// tools' diameter, with Shift their intensity). Read as typed, so
// layouts where a bracket takes Option or AltGr count too; `{` and `}` are Shift's.
if !(m.command || m.ctrl) {
let typed: Vec<(String, ToolKey, bool)> = ctx.input(|i| {
i.events
.iter()
.filter_map(|e| match e {
egui::Event::Text(t) => match t.as_str() {
"[" => Some((t.clone(), ToolKey::BracketLeft, false)),
"]" => Some((t.clone(), ToolKey::BracketRight, false)),
"{" => Some((t.clone(), ToolKey::BracketLeft, true)),
"}" => Some((t.clone(), ToolKey::BracketRight, true)),
_ => None,
},
_ => None,
})
.collect()
});
let mut taken = false;
for (text, key, shift) in typed {
if app.session.tool_claims_key(key, view) {
ctx.input_mut(|i| i.events.retain(|e| !matches!(e, egui::Event::Text(t) if *t == text)));
let r = app.session.tool_key(key, Mods { shift, ..Mods::default() }, view);
crate::canvas::apply_requests(app, r);
taken = true;
}
}
if taken {
return;
}
}
// Command shortcuts.
let mut fire = None;
for (sc, id, p) in all_shortcuts() {
@@ -699,6 +731,33 @@ mod tests {
assert_eq!(kind(&app), None, "another tool has its own Enter");
}
/// #1661: typed `[` and `]` reach the tool that takes them: the Blob Brush's and the Eraser's
/// size (Option or AltGr brackets too), the stroke weight left as it is; other tools leave them
/// alone.
#[test]
fn brackets_size_the_blob_brush_and_the_eraser() {
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());
app.session.execute("file.new", &json!({"width": 200, "height": 200})).unwrap();
app.session.execute("stroke.set", &json!({"weight": 3})).unwrap();
let size = |app: &mut VectorcraftApp| app.session.tool_options()["size"].as_f64().unwrap();
let text = |t: &str| egui::Event::Text(t.into());
for tool in ["blobBrush", "eraser"] {
app.select_tool(tool);
let before = size(&mut app);
frame(&mut app, vec![text("]")]);
frame(&mut app, vec![text("]")]);
assert_eq!(size(&mut app), before + 2.0, "{tool}");
// Option-8 types `[` on a Turkish Mac keyboard.
let option_8 = egui::Event::Key { key: Key::Num8, physical_key: None, pressed: true, repeat: false, modifiers: Modifiers::ALT };
frame(&mut app, vec![option_8, text("[")]);
assert_eq!(size(&mut app), before + 1.0, "{tool}: a bracket typed with Option");
}
assert_eq!(app.session.paint.stroke_width, 3.0, "the stroke weight stays");
app.select_tool("rectangle");
frame(&mut app, vec![text("[")]);
assert_eq!(app.session.paint.stroke_width, 3.0);
}
#[test]
fn comma_and_period_reapply_the_last_colour_and_gradient() {
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());