Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions crates/ui-egui/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1433,6 +1433,23 @@ impl NoteCraftApp {
}
}

/// Keys for the pens, so a tablet's express keys or a keyboard can change tools without
/// reaching for the ribbon (issue #44): Alt+1 to Alt+9 pick up that pen on the Draw tab's
/// rack, and Alt+0 puts the pens down and goes back to typing. On a Mac, where Option and a
/// digit also type a character, the character is dropped so it does not land in the note.
fn pen_keys(&mut self, ctx: &Context) {
const DIGITS: [Key; 10] = [Key::Num0, Key::Num1, Key::Num2, Key::Num3, Key::Num4, Key::Num5, Key::Num6, Key::Num7, Key::Num8, Key::Num9];
let Some(n) = ctx.input_mut(|i| DIGITS.iter().position(|key| i.consume_key(Modifiers::ALT, *key))) else { return };
ctx.input_mut(|i| i.events.retain(|e| !matches!(e, egui::Event::Text(_))));
if n == 0 {
self.ribbon_act(ribbon::Act::InkPointer(ribbon::Pointer::Write));
self.say(crate::tl_id!("ui.pen_keys_typing"));
} else if n <= self.rack.len() {
self.ribbon_act(ribbon::Act::InkPen(n - 1));
self.say(crate::i18n::format_message_id("ui.pen_keys_picked", &[("number", &n.to_string())]));
}
}

/// The keys and buttons that move through the pages that were opened. Undo and Redo keys
/// are the page history's own, taken below.
fn nav_keys(&mut self, ctx: &Context) {
Expand Down Expand Up @@ -8569,6 +8586,7 @@ impl NoteCraftApp {
self.focus_search = true;
}
self.nav_keys(ctx);
self.pen_keys(ctx);
self.direction_keys(ctx);
self.hierarchy_keys(ctx);
self.restore_last_page();
Expand Down
2 changes: 2 additions & 0 deletions crates/ui-egui/src/ribbon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2197,6 +2197,8 @@ fn pen_on_rack(ui: &mut Ui, i: usize, nib: Nib, chosen: bool, rack_len: usize, t
open = false;
}
ui.data_mut(|d| d.insert_temp(open_id, open));
// The first nine pens answer Alt and their number (issue #44).
let name = if i < 9 { format!("{name} (Alt+{})", i + 1) } else { name };
resp.on_hover_text(name);
picked_up
}
Expand Down
47 changes: 47 additions & 0 deletions crates/ui-egui/tests/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9551,3 +9551,50 @@ fn content_wider_than_the_view_gets_a_horizontal_scroll_bar() {
assert_eq!(state.pointer("/ink/strokes").and_then(Value::as_u64), Some(0), "the bar took the press, not the pen: {state}");
}
}

/// Issue #44: Alt and a number pick up that pen on the rack, from anywhere, so a tablet's express
/// keys can be bound to pens; Alt+0 goes back to typing. A Mac's Option+digit character is not
/// typed into the note.
#[test]
fn alt_and_a_number_pick_up_a_pen_and_alt_zero_goes_back_to_typing() {
let (_t, mut app, s) = sample_app("ui-pen-keys");
app.open_path(&s.md_page.to_string_lossy());
let mut h = harness(app, LIGHT);
settle(&mut h);
let ink = |h: &mut Harness<'_, NoteCraftApp>| {
let v = ask(h, "ui.inspect", json!({})).expect("inspect");
(v.pointer("/ink/pointer").and_then(Value::as_str).unwrap_or_default().to_string(), v.pointer("/ink/nib").and_then(Value::as_u64))
};
assert_eq!(ink(&mut h).0, "write");
ask(&mut h, "ui.key", json!({"key": "2", "alt": true})).expect("Alt+2");
settle(&mut h);
assert_eq!(ink(&mut h), ("draw".to_string(), Some(1)), "the second pen on the rack is in hand");
ask(&mut h, "ui.key", json!({"key": "5", "alt": true})).expect("Alt+5");
settle(&mut h);
assert_eq!(ink(&mut h), ("draw".to_string(), Some(4)));
ask(&mut h, "ui.key", json!({"key": "0", "alt": true})).expect("Alt+0");
settle(&mut h);
assert_eq!(ink(&mut h).0, "write", "Alt+0 puts the pen down");
// A number past the end of the rack picks up nothing.
ask(&mut h, "ui.key", json!({"key": "9", "alt": true})).expect("Alt+9");
settle(&mut h);
assert_eq!(ink(&mut h).0, "write", "there is no ninth pen on the starting rack");
// A plain digit is still typing, not a pen.
ask(&mut h, "ui.key", json!({"key": "3"})).expect("3");
settle(&mut h);
assert_eq!(ink(&mut h).0, "write");

// With the caret in the note, the character a Mac types for Option+1 does not reach it.
ask(&mut h, "ui.caret", json!({"block": 1})).expect("caret");
pump(&mut h);
let before = h.state().body().unwrap_or_default().to_string();
let alt = egui::Modifiers { alt: true, ..Default::default() };
h.input_mut().events.push(egui::Event::Key { key: egui::Key::Num1, physical_key: None, pressed: true, repeat: false, modifiers: alt });
h.input_mut().events.push(egui::Event::Text("\u{a1}".to_string()));
h.step();
settle(&mut h);
assert_eq!(ink(&mut h), ("draw".to_string(), Some(0)), "Alt+1 picks up the first pen");
let after = h.state().body().unwrap_or_default().to_string();
assert!(!after.contains('\u{a1}'), "the Option character was not typed");
assert_eq!(before, after, "the note is unchanged");
}
4 changes: 3 additions & 1 deletion docs/gaps.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,9 @@ Playground hosts with the Files API continue using their existing persistence pa
ellipse, circle, diamond, triangle and star - drawn by dragging out the two corners they
sit between. A drawn shape is ink like any other stroke, so the eraser, Select and Undo
Stroke all work on it; it is not kept as a shape that can be turned back into a perfect
circle later, and the file does not say which shape it was.
circle later, and the file does not say which shape it was. Alt+1 to Alt+9 pick up the
pen in that place on the rack, from anywhere, so a tablet's express keys can be bound to
pens; Alt+0 puts the pen down and goes back to typing. OneNote has no such keys.
**Not built:** automatic shapes; the ruler and other stencils;
ink replay; ink to text and ink to math; laser pointer; More Colours and the eyedropper
in the tool editor. Pressure is real and measured on Windows (hardest 0.930 over 1223
Expand Down
2 changes: 2 additions & 0 deletions i18n/ar-XB.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -882,3 +882,5 @@
@id ui.no_tagged_notes_here [[RLI]]$$$No tagged notes here.@@@[[PDI]]
@id ui.tags_empty_line [[RLI]]$$$(an empty line)@@@[[PDI]]
@id ui.scroll_the_page_sideways [[RLI]]$$$Scroll the page sideways@@@[[PDI]]
@id ui.pen_keys_typing [[RLI]]$$$Typing (Alt+0)@@@[[PDI]]
@id ui.pen_keys_picked [[RLI]]$$$Pen {number} (Alt+{number})@@@[[PDI]]
2 changes: 2 additions & 0 deletions i18n/en-XA.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -882,3 +882,5 @@
@id ui.no_tagged_notes_here $$$No tagged notes here.@@@
@id ui.tags_empty_line $$$(an empty line)@@@
@id ui.scroll_the_page_sideways $$$Scroll the page sideways@@@
@id ui.pen_keys_typing $$$Typing (Alt+0)@@@
@id ui.pen_keys_picked $$$Pen {number} (Alt+{number})@@@
2 changes: 2 additions & 0 deletions i18n/en.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -882,3 +882,5 @@
@id ui.no_tagged_notes_here No tagged notes here.
@id ui.tags_empty_line (an empty line)
@id ui.scroll_the_page_sideways Scroll the page sideways
@id ui.pen_keys_typing Typing (Alt+0)
@id ui.pen_keys_picked Pen {number} (Alt+{number})
Loading