Support Cmd+A ^W ^U ^K and shift-click
This commit is contained in:
parent
b920822b6b
commit
fe0d159324
8 changed files with 174 additions and 77 deletions
|
@ -17,7 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
* You must now be explicit when creating a `TextEdit` if you want it to be singeline or multiline.
|
||||
* Improved automatic `Id` generation, making `Id` clashes less likely.
|
||||
* Egui now requires modifier key state from the integration
|
||||
* Renamed and removed some keys in the `Key` enum.
|
||||
* Added, renamed and removed some keys in the `Key` enum.
|
||||
|
||||
### Fixed 🐛
|
||||
|
||||
|
|
15
TODO.md
15
TODO.md
|
@ -4,7 +4,6 @@ TODO-list for the Egui project. If you looking for something to do, look here.
|
|||
|
||||
## Top priority
|
||||
|
||||
* Text input: text selection etc
|
||||
* Refactor graphics layers and areas so one don't have to register LayerId:s.
|
||||
|
||||
## Other
|
||||
|
@ -18,8 +17,9 @@ TODO-list for the Egui project. If you looking for something to do, look here.
|
|||
* [x] Input
|
||||
* [x] Text focus
|
||||
* [x] Cursor movement
|
||||
* [ ] Text selection
|
||||
* [ ] Clipboard copy/paste
|
||||
* [x] Text selection
|
||||
* [x] Clipboard copy/paste
|
||||
* [ ] Text edit undo
|
||||
* [ ] Move focus with tab
|
||||
* [ ] Vertical slider
|
||||
* [/] Color picker
|
||||
|
@ -43,15 +43,16 @@ TODO-list for the Egui project. If you looking for something to do, look here.
|
|||
* [x] Distinguish between clicks and drags
|
||||
* [x] Double-click
|
||||
* [x] Text
|
||||
* [x] Get modifier keys
|
||||
* [ ] Support all mouse buttons
|
||||
* [ ] Distinguish between touch input and mouse input
|
||||
* [ ] Get modifier keys
|
||||
* [ ] Keyboard shortcuts
|
||||
* [ ] Copy, paste, undo, ...
|
||||
* [ ] Keyboard shortcuts (copy, paste, undo, select-all, ...?)
|
||||
* Text
|
||||
* [/] Unicode
|
||||
* [x] Shared mutable expanding texture map
|
||||
* [ ] Text editing of unicode
|
||||
* [/] Text editing of unicode (needs more testing)
|
||||
* [ ] Font with some more unicode characters
|
||||
* [ ] Emoji support (great for things like ▶️⏸⏹⚠︎)
|
||||
* [ ] Change text style/color and continue in same layout
|
||||
* Menu bar (File, Edit, etc)
|
||||
* [ ] Sub-menus
|
||||
|
|
|
@ -33,6 +33,9 @@ pub struct RawInput {
|
|||
/// Time in seconds. Relative to whatever. Used for animations.
|
||||
pub time: f64,
|
||||
|
||||
/// Which modifier keys are down at the start of the frame?
|
||||
pub modifiers: Modifiers,
|
||||
|
||||
/// In-order events received this frame
|
||||
pub events: Vec<Event>,
|
||||
}
|
||||
|
@ -47,6 +50,7 @@ impl RawInput {
|
|||
screen_size: self.screen_size,
|
||||
pixels_per_point: self.pixels_per_point,
|
||||
time: self.time,
|
||||
modifiers: self.modifiers,
|
||||
events: std::mem::take(&mut self.events),
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +84,9 @@ pub struct InputState {
|
|||
/// Should be set to the expected time between frames when painting at vsync speeds.
|
||||
pub predicted_dt: f32,
|
||||
|
||||
/// Which modifier keys are down at the start of the frame?
|
||||
pub modifiers: Modifiers,
|
||||
|
||||
/// In-order events received this frame
|
||||
pub events: Vec<Event>,
|
||||
}
|
||||
|
@ -200,6 +207,12 @@ pub enum Key {
|
|||
PageDown,
|
||||
PageUp,
|
||||
Tab,
|
||||
|
||||
A, // Used for cmd+A (select All)
|
||||
K, // Used for ctrl+K (delete text after cursor)
|
||||
U, // Used for ctrl+U (delete text before cursor)
|
||||
W, // Used for ctrl+W (delete previous word)
|
||||
Z, // Used for cmd+Z (undo)
|
||||
}
|
||||
|
||||
impl InputState {
|
||||
|
@ -214,7 +227,8 @@ impl InputState {
|
|||
pixels_per_point: new.pixels_per_point.or(self.pixels_per_point),
|
||||
time: new.time,
|
||||
unstable_dt,
|
||||
predicted_dt: 1.0 / 60.0, // TODO: remove this hack
|
||||
predicted_dt: 1.0 / 60.0, // TODO: remove this hack
|
||||
modifiers: new.modifiers,
|
||||
events: new.events.clone(), // TODO: remove clone() and use raw.events
|
||||
raw: new,
|
||||
}
|
||||
|
@ -357,6 +371,7 @@ impl RawInput {
|
|||
screen_size,
|
||||
pixels_per_point,
|
||||
time,
|
||||
modifiers,
|
||||
events,
|
||||
} = self;
|
||||
|
||||
|
@ -371,6 +386,7 @@ impl RawInput {
|
|||
"Also called HDPI factor.\nNumber of physical pixels per each logical pixel.",
|
||||
);
|
||||
ui.label(format!("time: {:.3} s", time));
|
||||
ui.label(format!("modifiers: {:#?}", modifiers));
|
||||
ui.label(format!("events: {:?}", events))
|
||||
.on_hover_text("key presses etc");
|
||||
}
|
||||
|
@ -387,6 +403,7 @@ impl InputState {
|
|||
time,
|
||||
unstable_dt,
|
||||
predicted_dt,
|
||||
modifiers,
|
||||
events,
|
||||
} = self;
|
||||
|
||||
|
@ -411,6 +428,7 @@ impl InputState {
|
|||
1e3 * unstable_dt
|
||||
));
|
||||
ui.label(format!("expected dt: {:.1} ms", 1e3 * predicted_dt));
|
||||
ui.label(format!("modifiers: {:#?}", modifiers));
|
||||
ui.label(format!("events: {:?}", events))
|
||||
.on_hover_text("key presses etc");
|
||||
}
|
||||
|
|
|
@ -192,6 +192,10 @@ impl Row {
|
|||
*self.x_offsets.last().unwrap()
|
||||
}
|
||||
|
||||
pub fn height(&self) -> f32 {
|
||||
self.y_max - self.y_min
|
||||
}
|
||||
|
||||
/// Closest char at the desired x coordinate.
|
||||
/// Returns something in the range `[0, char_count_excluding_newline()]`.
|
||||
pub fn char_at(&self, desired_x: f32) -> usize {
|
||||
|
@ -233,7 +237,7 @@ impl Galley {
|
|||
fn end_pos(&self) -> Rect {
|
||||
if let Some(row) = self.rows.last() {
|
||||
let x = row.max_x();
|
||||
return Rect::from_min_max(pos2(x, row.y_min), pos2(x, row.y_max));
|
||||
Rect::from_min_max(pos2(x, row.y_min), pos2(x, row.y_max))
|
||||
} else {
|
||||
// Empty galley
|
||||
Rect::from_min_max(pos2(0.0, 0.0), pos2(0.0, 0.0))
|
||||
|
@ -636,6 +640,13 @@ impl Galley {
|
|||
|
||||
#[test]
|
||||
fn test_text_layout() {
|
||||
impl PartialEq for Cursor {
|
||||
fn eq(&self, other: &Cursor) -> bool {
|
||||
(self.ccursor, self.rcursor, self.pcursor)
|
||||
== (other.ccursor, other.rcursor, other.pcursor)
|
||||
}
|
||||
}
|
||||
|
||||
use crate::mutex::Mutex;
|
||||
use crate::paint::{font::Font, *};
|
||||
|
||||
|
|
|
@ -267,7 +267,15 @@ impl<'t> Widget for TextEdit<'t> {
|
|||
});
|
||||
} else if response.hovered && ui.input().mouse.pressed {
|
||||
ui.memory().request_kb_focus(id);
|
||||
state.cursorp = Some(CursorPair::one(cursor_at_mouse));
|
||||
if ui.input().modifiers.shift {
|
||||
if let Some(cursorp) = &mut state.cursorp {
|
||||
cursorp.primary = cursor_at_mouse;
|
||||
} else {
|
||||
state.cursorp = Some(CursorPair::one(cursor_at_mouse));
|
||||
}
|
||||
} else {
|
||||
state.cursorp = Some(CursorPair::one(cursor_at_mouse));
|
||||
}
|
||||
} else if ui.input().mouse.down && response.active {
|
||||
if let Some(cursorp) = &mut state.cursorp {
|
||||
cursorp.primary = cursor_at_mouse;
|
||||
|
@ -332,7 +340,7 @@ impl<'t> Widget for TextEdit<'t> {
|
|||
&& text_to_insert != "\n"
|
||||
&& text_to_insert != "\r"
|
||||
{
|
||||
let mut ccursor = delete_selected(text, &cursorp).into();
|
||||
let mut ccursor = delete_selected(text, &cursorp);
|
||||
insert_text(&mut ccursor, text, text_to_insert);
|
||||
Some(CCursorPair::one(ccursor))
|
||||
} else {
|
||||
|
@ -345,7 +353,7 @@ impl<'t> Widget for TextEdit<'t> {
|
|||
..
|
||||
} => {
|
||||
if multiline {
|
||||
let mut ccursor = delete_selected(text, &cursorp).into();
|
||||
let mut ccursor = delete_selected(text, &cursorp);
|
||||
insert_text(&mut ccursor, text, "\n");
|
||||
Some(CCursorPair::one(ccursor))
|
||||
} else {
|
||||
|
@ -452,7 +460,12 @@ fn paint_cursor_selection(
|
|||
let right = if ri == max.row {
|
||||
row.x_offset(max.column)
|
||||
} else {
|
||||
row.max_x()
|
||||
let newline_size = if row.ends_with_newline {
|
||||
row.height() / 2.0 // visualize that we select the newline
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
row.max_x() + newline_size
|
||||
};
|
||||
let rect = Rect::from_min_max(pos + vec2(left, row.y_min), pos + vec2(right, row.y_max));
|
||||
ui.painter().rect_filled(rect, 0.0, color);
|
||||
|
@ -499,7 +512,7 @@ fn byte_index_from_char_index(s: &str, char_index: usize) -> usize {
|
|||
return bi;
|
||||
}
|
||||
}
|
||||
return s.len();
|
||||
s.len()
|
||||
}
|
||||
|
||||
fn insert_text(ccursor: &mut CCursor, text: &mut String, text_to_insert: &str) {
|
||||
|
@ -555,12 +568,12 @@ fn delete_next_char(text: &mut String, ccursor: CCursor) -> CCursor {
|
|||
}
|
||||
|
||||
fn delete_previous_word(text: &mut String, max_ccursor: CCursor) -> CCursor {
|
||||
let min_ccursor = ccursor_previous_word(&text, max_ccursor);
|
||||
let min_ccursor = ccursor_previous_word(text, max_ccursor);
|
||||
delete_selected_ccursor_range(text, [min_ccursor, max_ccursor])
|
||||
}
|
||||
|
||||
fn delete_next_word(text: &mut String, min_ccursor: CCursor) -> CCursor {
|
||||
let max_ccursor = ccursor_next_word(&text, min_ccursor);
|
||||
let max_ccursor = ccursor_next_word(text, min_ccursor);
|
||||
delete_selected_ccursor_range(text, [min_ccursor, max_ccursor])
|
||||
}
|
||||
|
||||
|
@ -610,10 +623,6 @@ fn on_key_press(
|
|||
key: Key,
|
||||
modifiers: &Modifiers,
|
||||
) -> Option<CCursorPair> {
|
||||
// TODO: ctrl-U to clear paragraph before the cursor
|
||||
// TODO: ctrl-W to delete previous word
|
||||
// TODO: cmd-A to select all
|
||||
|
||||
match key {
|
||||
Key::Backspace => {
|
||||
let ccursor = if modifiers.mac_cmd {
|
||||
|
@ -650,6 +659,31 @@ fn on_key_press(
|
|||
Some(CCursorPair::one(ccursor))
|
||||
}
|
||||
|
||||
Key::A if modifiers.command => {
|
||||
// select all
|
||||
*cursorp = CursorPair::two(Cursor::default(), galley.end());
|
||||
None
|
||||
}
|
||||
|
||||
Key::K if modifiers.ctrl => {
|
||||
let ccursor = delete_paragraph_after_cursor(text, galley, cursorp);
|
||||
Some(CCursorPair::one(ccursor))
|
||||
}
|
||||
|
||||
Key::U if modifiers.ctrl => {
|
||||
let ccursor = delete_paragraph_before_cursor(text, galley, cursorp);
|
||||
Some(CCursorPair::one(ccursor))
|
||||
}
|
||||
|
||||
Key::W if modifiers.ctrl => {
|
||||
let ccursor = if let Some(cursor) = cursorp.single() {
|
||||
delete_previous_word(text, cursor.ccursor)
|
||||
} else {
|
||||
delete_selected(text, cursorp)
|
||||
};
|
||||
Some(CCursorPair::one(ccursor))
|
||||
}
|
||||
|
||||
Key::ArrowLeft | Key::ArrowRight | Key::ArrowUp | Key::ArrowDown | Key::Home | Key::End => {
|
||||
move_single_cursor(&mut cursorp.primary, galley, key, modifiers);
|
||||
if !modifiers.shift {
|
||||
|
@ -658,9 +692,7 @@ fn on_key_press(
|
|||
None
|
||||
}
|
||||
|
||||
Key::Enter | Key::Escape => unreachable!("Handled outside this function"),
|
||||
|
||||
Key::Insert | Key::PageDown | Key::PageUp | Key::Tab => None,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ pub use clipboard::ClipboardContext; // TODO: remove
|
|||
|
||||
pub struct GliumInputState {
|
||||
raw: egui::RawInput,
|
||||
modifiers: egui::Modifiers,
|
||||
}
|
||||
|
||||
impl GliumInputState {
|
||||
|
@ -30,7 +29,6 @@ impl GliumInputState {
|
|||
pixels_per_point: Some(pixels_per_point),
|
||||
..Default::default()
|
||||
},
|
||||
modifiers: Default::default(), // cmd: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +58,10 @@ pub fn input_to_egui(
|
|||
input_state.raw.mouse_pos = None;
|
||||
}
|
||||
ReceivedCharacter(ch) => {
|
||||
if printable_char(ch) && !input_state.modifiers.ctrl && !input_state.modifiers.mac_cmd {
|
||||
if printable_char(ch)
|
||||
&& !input_state.raw.modifiers.ctrl
|
||||
&& !input_state.raw.modifiers.mac_cmd
|
||||
{
|
||||
input_state.raw.events.push(Event::Text(ch.to_string()));
|
||||
}
|
||||
}
|
||||
|
@ -69,27 +70,27 @@ pub fn input_to_egui(
|
|||
let pressed = input.state == glutin::event::ElementState::Pressed;
|
||||
|
||||
if matches!(keycode, VirtualKeyCode::LAlt | VirtualKeyCode::RAlt) {
|
||||
input_state.modifiers.alt = pressed;
|
||||
input_state.raw.modifiers.alt = pressed;
|
||||
}
|
||||
if matches!(keycode, VirtualKeyCode::LControl | VirtualKeyCode::RControl) {
|
||||
input_state.modifiers.ctrl = pressed;
|
||||
input_state.raw.modifiers.ctrl = pressed;
|
||||
if !cfg!(target_os = "macos") {
|
||||
input_state.modifiers.command = pressed;
|
||||
input_state.raw.modifiers.command = pressed;
|
||||
}
|
||||
}
|
||||
if matches!(keycode, VirtualKeyCode::LShift | VirtualKeyCode::RShift) {
|
||||
input_state.modifiers.shift = pressed;
|
||||
input_state.raw.modifiers.shift = pressed;
|
||||
}
|
||||
if cfg!(target_os = "macos")
|
||||
&& matches!(keycode, VirtualKeyCode::LWin | VirtualKeyCode::RWin)
|
||||
{
|
||||
input_state.modifiers.mac_cmd = pressed;
|
||||
input_state.modifiers.command = pressed;
|
||||
input_state.raw.modifiers.mac_cmd = pressed;
|
||||
input_state.raw.modifiers.command = pressed;
|
||||
}
|
||||
|
||||
if pressed {
|
||||
if cfg!(target_os = "macos")
|
||||
&& input_state.modifiers.mac_cmd
|
||||
&& input_state.raw.modifiers.mac_cmd
|
||||
&& keycode == VirtualKeyCode::Q
|
||||
{
|
||||
*control_flow = ControlFlow::Exit;
|
||||
|
@ -97,11 +98,11 @@ pub fn input_to_egui(
|
|||
|
||||
// VirtualKeyCode::Paste etc in winit are broken/untrustworthy,
|
||||
// so we detect these things manually:
|
||||
if input_state.modifiers.command && keycode == VirtualKeyCode::X {
|
||||
if input_state.raw.modifiers.command && keycode == VirtualKeyCode::X {
|
||||
input_state.raw.events.push(Event::Cut);
|
||||
} else if input_state.modifiers.command && keycode == VirtualKeyCode::C {
|
||||
} else if input_state.raw.modifiers.command && keycode == VirtualKeyCode::C {
|
||||
input_state.raw.events.push(Event::Copy);
|
||||
} else if input_state.modifiers.command && keycode == VirtualKeyCode::V {
|
||||
} else if input_state.raw.modifiers.command && keycode == VirtualKeyCode::V {
|
||||
if let Some(clipboard) = clipboard {
|
||||
match clipboard.get_contents() {
|
||||
Ok(contents) => {
|
||||
|
@ -116,7 +117,7 @@ pub fn input_to_egui(
|
|||
input_state.raw.events.push(Event::Key {
|
||||
key,
|
||||
pressed,
|
||||
modifiers: input_state.modifiers,
|
||||
modifiers: input_state.raw.modifiers,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -170,6 +171,13 @@ pub fn translate_virtual_key_code(key: VirtualKeyCode) -> Option<egui::Key> {
|
|||
Back => Key::Backspace,
|
||||
Return => Key::Enter,
|
||||
Tab => Key::Tab,
|
||||
|
||||
A => Key::A,
|
||||
K => Key::K,
|
||||
U => Key::U,
|
||||
W => Key::W,
|
||||
Z => Key::Z,
|
||||
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -92,16 +92,18 @@ impl egui::app::TextureAllocator for webgl::Painter {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// TODO: Just use RawInput?
|
||||
/// Data gathered between frames.
|
||||
/// Is translated to `egui::RawInput` at the start of each frame.
|
||||
#[derive(Default)]
|
||||
pub struct WebInput {
|
||||
/// In native points (not same as Egui points)
|
||||
pub mouse_pos: Option<egui::Pos2>,
|
||||
pub mouse_down: bool, // TODO: which button
|
||||
/// Is this a touch screen? If so, we ignore mouse events.
|
||||
pub is_touch: bool,
|
||||
/// In native points (not same as Egui points)
|
||||
pub scroll_delta: egui::Vec2,
|
||||
pub events: Vec<egui::Event>,
|
||||
|
||||
pub raw: egui::RawInput,
|
||||
}
|
||||
|
||||
impl WebInput {
|
||||
|
@ -111,13 +113,12 @@ impl WebInput {
|
|||
let scroll_delta = std::mem::take(&mut self.scroll_delta) * scale;
|
||||
let mouse_pos = self.mouse_pos.map(|mp| pos2(mp.x * scale, mp.y * scale));
|
||||
egui::RawInput {
|
||||
mouse_down: self.mouse_down,
|
||||
mouse_pos,
|
||||
scroll_delta,
|
||||
screen_size: screen_size_in_native_points().unwrap() * scale,
|
||||
pixels_per_point: Some(pixels_per_point),
|
||||
time: now_sec(),
|
||||
events: std::mem::take(&mut self.events),
|
||||
..self.raw.take()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +128,7 @@ impl WebInput {
|
|||
pub struct AppRunner {
|
||||
pixels_per_point: f32,
|
||||
pub web_backend: WebBackend,
|
||||
pub web_input: WebInput,
|
||||
pub input: WebInput,
|
||||
pub app: Box<dyn App>,
|
||||
pub needs_repaint: bool, // TODO: move
|
||||
}
|
||||
|
@ -138,7 +139,7 @@ impl AppRunner {
|
|||
Ok(Self {
|
||||
pixels_per_point: native_pixels_per_point(),
|
||||
web_backend,
|
||||
web_input: Default::default(),
|
||||
input: Default::default(),
|
||||
app,
|
||||
needs_repaint: true, // TODO: move
|
||||
})
|
||||
|
@ -151,7 +152,7 @@ impl AppRunner {
|
|||
pub fn logic(&mut self) -> Result<(egui::Output, egui::PaintJobs), JsValue> {
|
||||
resize_canvas_to_screen_size(self.web_backend.canvas_id());
|
||||
|
||||
let raw_input = self.web_input.new_frame(self.pixels_per_point);
|
||||
let raw_input = self.input.new_frame(self.pixels_per_point);
|
||||
self.web_backend.begin_frame(raw_input);
|
||||
|
||||
let mut integration_context = egui::app::IntegrationContext {
|
||||
|
|
|
@ -195,14 +195,30 @@ fn should_ignore_key(key: &str) -> bool {
|
|||
|| matches!(
|
||||
key,
|
||||
"Alt"
|
||||
| "ArrowDown"
|
||||
| "ArrowLeft"
|
||||
| "ArrowRight"
|
||||
| "ArrowUp"
|
||||
| "Backspace"
|
||||
| "CapsLock"
|
||||
| "ContextMenu"
|
||||
| "Control"
|
||||
| "Delete"
|
||||
| "End"
|
||||
| "Enter"
|
||||
| "Esc"
|
||||
| "Escape"
|
||||
| "Help"
|
||||
| "Home"
|
||||
| "Insert"
|
||||
| "Meta"
|
||||
| "NumLock"
|
||||
| "PageDown"
|
||||
| "PageUp"
|
||||
| "Pause"
|
||||
| "ScrollLock"
|
||||
| "Shift"
|
||||
| "Tab"
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -224,6 +240,11 @@ pub fn translate_key(key: &str) -> Option<egui::Key> {
|
|||
"PageDown" => Some(egui::Key::PageDown),
|
||||
"PageUp" => Some(egui::Key::PageUp),
|
||||
"Tab" => Some(egui::Key::Tab),
|
||||
"a" | "A" => Some(egui::Key::A),
|
||||
"k" | "K" => Some(egui::Key::K),
|
||||
"u" | "U" => Some(egui::Key::U),
|
||||
"w" | "W" => Some(egui::Key::W),
|
||||
"z" | "Z" => Some(egui::Key::Z),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -271,20 +292,24 @@ fn install_document_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
|
|||
// https://www.fxsitecompat.dev/en-CA/docs/2018/keydown-and-keyup-events-are-now-fired-during-ime-composition/
|
||||
return;
|
||||
}
|
||||
|
||||
let mut runner_lock = runner_ref.0.lock();
|
||||
let modifiers = modifiers_from_event(&event);
|
||||
runner_lock.input.raw.modifiers = modifiers;
|
||||
|
||||
let key = event.key();
|
||||
|
||||
if let Some(key) = translate_key(&key) {
|
||||
runner_lock.web_input.events.push(egui::Event::Key {
|
||||
runner_lock.input.raw.events.push(egui::Event::Key {
|
||||
key,
|
||||
pressed: true,
|
||||
modifiers: modifiers_from_event(&event),
|
||||
modifiers,
|
||||
});
|
||||
runner_lock.needs_repaint = true;
|
||||
} else if !should_ignore_key(&key) {
|
||||
runner_lock.web_input.events.push(egui::Event::Text(key));
|
||||
runner_lock.needs_repaint = true;
|
||||
}
|
||||
if !modifiers.ctrl && !modifiers.command && !should_ignore_key(&key) {
|
||||
runner_lock.input.raw.events.push(egui::Event::Text(key));
|
||||
}
|
||||
runner_lock.needs_repaint = true;
|
||||
}) as Box<dyn FnMut(_)>);
|
||||
document.add_event_listener_with_callback("keydown", closure.as_ref().unchecked_ref())?;
|
||||
closure.forget();
|
||||
|
@ -295,15 +320,16 @@ fn install_document_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
|
|||
let runner_ref = runner_ref.clone();
|
||||
let closure = Closure::wrap(Box::new(move |event: web_sys::KeyboardEvent| {
|
||||
let mut runner_lock = runner_ref.0.lock();
|
||||
let key = event.key();
|
||||
if let Some(key) = translate_key(&key) {
|
||||
runner_lock.web_input.events.push(egui::Event::Key {
|
||||
let modifiers = modifiers_from_event(&event);
|
||||
runner_lock.input.raw.modifiers = modifiers;
|
||||
if let Some(key) = translate_key(&event.key()) {
|
||||
runner_lock.input.raw.events.push(egui::Event::Key {
|
||||
key,
|
||||
pressed: false,
|
||||
modifiers: modifiers_from_event(&event),
|
||||
modifiers,
|
||||
});
|
||||
runner_lock.needs_repaint = true;
|
||||
}
|
||||
runner_lock.needs_repaint = true;
|
||||
}) as Box<dyn FnMut(_)>);
|
||||
document.add_event_listener_with_callback("keyup", closure.as_ref().unchecked_ref())?;
|
||||
closure.forget();
|
||||
|
@ -346,10 +372,10 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
|
|||
let runner_ref = runner_ref.clone();
|
||||
let closure = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| {
|
||||
let mut runner_lock = runner_ref.0.lock();
|
||||
if !runner_lock.web_input.is_touch {
|
||||
runner_lock.web_input.mouse_pos =
|
||||
if !runner_lock.input.is_touch {
|
||||
runner_lock.input.mouse_pos =
|
||||
Some(pos_from_mouse_event(runner_lock.canvas_id(), &event));
|
||||
runner_lock.web_input.mouse_down = true;
|
||||
runner_lock.input.raw.mouse_down = true;
|
||||
runner_lock.logic().unwrap(); // in case we get "mouseup" the same frame. TODO: handle via events instead
|
||||
runner_lock.needs_repaint = true;
|
||||
event.stop_propagation();
|
||||
|
@ -365,8 +391,8 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
|
|||
let runner_ref = runner_ref.clone();
|
||||
let closure = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| {
|
||||
let mut runner_lock = runner_ref.0.lock();
|
||||
if !runner_lock.web_input.is_touch {
|
||||
runner_lock.web_input.mouse_pos =
|
||||
if !runner_lock.input.is_touch {
|
||||
runner_lock.input.mouse_pos =
|
||||
Some(pos_from_mouse_event(runner_lock.canvas_id(), &event));
|
||||
runner_lock.needs_repaint = true;
|
||||
event.stop_propagation();
|
||||
|
@ -382,10 +408,10 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
|
|||
let runner_ref = runner_ref.clone();
|
||||
let closure = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| {
|
||||
let mut runner_lock = runner_ref.0.lock();
|
||||
if !runner_lock.web_input.is_touch {
|
||||
runner_lock.web_input.mouse_pos =
|
||||
if !runner_lock.input.is_touch {
|
||||
runner_lock.input.mouse_pos =
|
||||
Some(pos_from_mouse_event(runner_lock.canvas_id(), &event));
|
||||
runner_lock.web_input.mouse_down = false;
|
||||
runner_lock.input.raw.mouse_down = false;
|
||||
runner_lock.needs_repaint = true;
|
||||
event.stop_propagation();
|
||||
event.prevent_default();
|
||||
|
@ -400,8 +426,8 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
|
|||
let runner_ref = runner_ref.clone();
|
||||
let closure = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| {
|
||||
let mut runner_lock = runner_ref.0.lock();
|
||||
if !runner_lock.web_input.is_touch {
|
||||
runner_lock.web_input.mouse_pos = None;
|
||||
if !runner_lock.input.is_touch {
|
||||
runner_lock.input.mouse_pos = None;
|
||||
runner_lock.needs_repaint = true;
|
||||
event.stop_propagation();
|
||||
event.prevent_default();
|
||||
|
@ -416,9 +442,9 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
|
|||
let runner_ref = runner_ref.clone();
|
||||
let closure = Closure::wrap(Box::new(move |event: web_sys::TouchEvent| {
|
||||
let mut runner_lock = runner_ref.0.lock();
|
||||
runner_lock.web_input.is_touch = true;
|
||||
runner_lock.web_input.mouse_pos = Some(pos_from_touch_event(&event));
|
||||
runner_lock.web_input.mouse_down = true;
|
||||
runner_lock.input.is_touch = true;
|
||||
runner_lock.input.mouse_pos = Some(pos_from_touch_event(&event));
|
||||
runner_lock.input.raw.mouse_down = true;
|
||||
runner_lock.needs_repaint = true;
|
||||
event.stop_propagation();
|
||||
event.prevent_default();
|
||||
|
@ -432,8 +458,8 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
|
|||
let runner_ref = runner_ref.clone();
|
||||
let closure = Closure::wrap(Box::new(move |event: web_sys::TouchEvent| {
|
||||
let mut runner_lock = runner_ref.0.lock();
|
||||
runner_lock.web_input.is_touch = true;
|
||||
runner_lock.web_input.mouse_pos = Some(pos_from_touch_event(&event));
|
||||
runner_lock.input.is_touch = true;
|
||||
runner_lock.input.mouse_pos = Some(pos_from_touch_event(&event));
|
||||
runner_lock.needs_repaint = true;
|
||||
event.stop_propagation();
|
||||
event.prevent_default();
|
||||
|
@ -447,10 +473,10 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
|
|||
let runner_ref = runner_ref.clone();
|
||||
let closure = Closure::wrap(Box::new(move |event: web_sys::TouchEvent| {
|
||||
let mut runner_lock = runner_ref.0.lock();
|
||||
runner_lock.web_input.is_touch = true;
|
||||
runner_lock.web_input.mouse_down = false; // First release mouse to click...
|
||||
runner_lock.input.is_touch = true;
|
||||
runner_lock.input.raw.mouse_down = false; // First release mouse to click...
|
||||
runner_lock.logic().unwrap(); // ...do the clicking... (TODO: handle via events instead)
|
||||
runner_lock.web_input.mouse_pos = None; // ...remove hover effect
|
||||
runner_lock.input.mouse_pos = None; // ...remove hover effect
|
||||
runner_lock.needs_repaint = true;
|
||||
event.stop_propagation();
|
||||
event.prevent_default();
|
||||
|
@ -464,8 +490,8 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
|
|||
let runner_ref = runner_ref.clone();
|
||||
let closure = Closure::wrap(Box::new(move |event: web_sys::WheelEvent| {
|
||||
let mut runner_lock = runner_ref.0.lock();
|
||||
runner_lock.web_input.scroll_delta.x -= event.delta_x() as f32;
|
||||
runner_lock.web_input.scroll_delta.y -= event.delta_y() as f32;
|
||||
runner_lock.input.scroll_delta.x -= event.delta_x() as f32;
|
||||
runner_lock.input.scroll_delta.y -= event.delta_y() as f32;
|
||||
runner_lock.needs_repaint = true;
|
||||
event.stop_propagation();
|
||||
event.prevent_default();
|
||||
|
|
Loading…
Reference in a new issue