[text] surrender keyboard focus by clicking outside text edit area
This commit is contained in:
parent
2861bc956a
commit
2f161dd3d4
4 changed files with 42 additions and 26 deletions
|
@ -308,7 +308,7 @@ impl Context {
|
|||
|
||||
/// If true, Egui is currently listening on text input (e.g. typing text in a `TextEdit`).
|
||||
pub fn wants_keyboard_input(&self) -> bool {
|
||||
self.memory().kb_focus_id.is_some()
|
||||
self.memory().interaction.kb_focus_id.is_some()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
|
|
@ -18,10 +18,6 @@ pub struct Memory {
|
|||
#[cfg_attr(feature = "with_serde", serde(skip))]
|
||||
pub(crate) interaction: Interaction,
|
||||
|
||||
/// The widget with keyboard focus (i.e. a text input field).
|
||||
#[cfg_attr(feature = "with_serde", serde(skip))]
|
||||
pub(crate) kb_focus_id: Option<Id>,
|
||||
|
||||
// states of various types of widgets
|
||||
pub(crate) collapsing_headers: HashMap<Id, collapsing_header::State>,
|
||||
pub(crate) menu_bar: HashMap<Id, menu::BarState>,
|
||||
|
@ -50,6 +46,9 @@ pub struct Interaction {
|
|||
/// A widget interested in drags that has a mouse press on it.
|
||||
pub drag_id: Option<Id>,
|
||||
|
||||
/// The widget with keyboard focus (i.e. a text input field).
|
||||
pub kb_focus_id: Option<Id>,
|
||||
|
||||
/// HACK: windows have low priority on dragging.
|
||||
/// This is so that if you drag a slider in a window,
|
||||
/// the slider will steal the drag away from the window.
|
||||
|
@ -70,6 +69,21 @@ impl Interaction {
|
|||
pub fn is_using_mouse(&self) -> bool {
|
||||
self.click_id.is_some() || self.drag_id.is_some()
|
||||
}
|
||||
|
||||
fn begin_frame(&mut self, prev_input: &crate::input::InputState) {
|
||||
self.click_interest = false;
|
||||
self.drag_interest = false;
|
||||
|
||||
if !prev_input.mouse.could_be_click {
|
||||
self.click_id = None;
|
||||
}
|
||||
|
||||
if !prev_input.mouse.down || prev_input.mouse.pos.is_none() {
|
||||
// mouse was not down last frame
|
||||
self.click_id = None;
|
||||
self.drag_id = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
@ -92,17 +106,10 @@ pub struct Areas {
|
|||
|
||||
impl Memory {
|
||||
pub(crate) fn begin_frame(&mut self, prev_input: &crate::input::InputState) {
|
||||
self.interaction.click_interest = false;
|
||||
self.interaction.drag_interest = false;
|
||||
|
||||
if !prev_input.mouse.could_be_click {
|
||||
self.interaction.click_id = None;
|
||||
}
|
||||
self.interaction.begin_frame(prev_input);
|
||||
|
||||
if !prev_input.mouse.down || prev_input.mouse.pos.is_none() {
|
||||
// mouse was not down last frame
|
||||
self.interaction.click_id = None;
|
||||
self.interaction.drag_id = None;
|
||||
|
||||
let window_interaction = self.window_interaction.take();
|
||||
if let Some(window_interaction) = window_interaction {
|
||||
|
@ -120,12 +127,26 @@ impl Memory {
|
|||
}
|
||||
|
||||
pub(crate) fn end_frame(&mut self) {
|
||||
self.areas.end_frame()
|
||||
self.areas.end_frame();
|
||||
}
|
||||
|
||||
pub fn layer_at(&self, pos: Pos2, resize_interact_radius_side: f32) -> Option<Layer> {
|
||||
self.areas.layer_at(pos, resize_interact_radius_side)
|
||||
}
|
||||
|
||||
pub fn has_kb_focus(&self, id: Id) -> bool {
|
||||
self.interaction.kb_focus_id == Some(id)
|
||||
}
|
||||
|
||||
pub fn request_kb_focus(&mut self, id: Id) {
|
||||
self.interaction.kb_focus_id = Some(id);
|
||||
}
|
||||
|
||||
pub fn surrender_kb_focus(&mut self, id: Id) {
|
||||
if self.interaction.kb_focus_id == Some(id) {
|
||||
self.interaction.kb_focus_id = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Areas {
|
||||
|
|
|
@ -259,14 +259,6 @@ impl Ui {
|
|||
self.ctx()
|
||||
.contains_mouse(self.layer(), self.clip_rect(), rect)
|
||||
}
|
||||
|
||||
pub fn has_kb_focus(&self, id: Id) -> bool {
|
||||
self.memory().kb_focus_id == Some(id)
|
||||
}
|
||||
|
||||
pub fn request_kb_focus(&self, id: Id) {
|
||||
self.memory().kb_focus_id = Some(id);
|
||||
}
|
||||
}
|
||||
|
||||
/// # `Id` creation
|
||||
|
|
|
@ -76,17 +76,20 @@ impl<'t> Widget for TextEdit<'t> {
|
|||
let interact = ui.interact(rect, id, Sense::click_and_drag()); // TODO: implement drag-select
|
||||
|
||||
if interact.clicked {
|
||||
ui.request_kb_focus(id);
|
||||
ui.memory().request_kb_focus(id);
|
||||
if let Some(mouse_pos) = ui.input().mouse.pos {
|
||||
state.cursor = Some(galley.char_at(mouse_pos - interact.rect.min).char_idx);
|
||||
}
|
||||
} else if ui.input().mouse.click {
|
||||
// User clicked somewhere else
|
||||
ui.memory().surrender_kb_focus(id);
|
||||
}
|
||||
|
||||
if interact.hovered {
|
||||
ui.output().cursor_icon = CursorIcon::Text;
|
||||
}
|
||||
let has_kb_focus = ui.has_kb_focus(id);
|
||||
|
||||
if has_kb_focus {
|
||||
if ui.memory().has_kb_focus(id) {
|
||||
let mut cursor = state.cursor.unwrap_or_else(|| text.chars().count());
|
||||
cursor = clamp(cursor, 0..=text.chars().count());
|
||||
|
||||
|
@ -141,7 +144,7 @@ impl<'t> Widget for TextEdit<'t> {
|
|||
});
|
||||
}
|
||||
|
||||
if has_kb_focus {
|
||||
if ui.memory().has_kb_focus(id) {
|
||||
let cursor_blink_hz = ui.style().cursor_blink_hz;
|
||||
let show_cursor =
|
||||
(ui.input().time * cursor_blink_hz as f64 * 3.0).floor() as i64 % 3 != 0;
|
||||
|
|
Loading…
Reference in a new issue