mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 06:10:06 -04:00
Support Cmd+A ^W ^U ^K and shift-click
This commit is contained in:
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user