Fix bug where clicking a TextEdit frame would not give it focus

Closes https://github.com/emilk/egui/issues/506
This commit is contained in:
Emil Ernerfeldt 2021-06-23 16:49:07 +02:00
parent 6e7e88ba80
commit c03caa663b
4 changed files with 23 additions and 14 deletions

View file

@ -108,11 +108,14 @@ impl CtxRef {
/// If the given [`Id`] is not unique, an error will be printed at the given position. /// If the given [`Id`] is not unique, an error will be printed at the given position.
/// Call this for [`Id`]:s that need interaction or persistence. /// Call this for [`Id`]:s that need interaction or persistence.
pub(crate) fn register_interaction_id(&self, id: Id, new_pos: Pos2) { pub(crate) fn register_interaction_id(&self, id: Id, new_rect: Rect) {
let prev_pos = self.frame_state().used_ids.insert(id, new_pos); let prev_rect = self.frame_state().used_ids.insert(id, new_rect);
if let Some(prev_pos) = prev_pos { if let Some(prev_rect) = prev_rect {
if prev_pos.distance(new_pos) < 0.1 { // it is ok to reuse the same ID for e.g. a frame around a widget,
// Likely same Widget being interacted with twice, which is fine. // or to check for interaction with the same widget twice:
if prev_rect.expand(0.1).contains_rect(new_rect)
|| new_rect.expand(0.1).contains_rect(prev_rect)
{
return; return;
} }
@ -132,11 +135,11 @@ impl CtxRef {
let id_str = id.short_debug_format(); let id_str = id.short_debug_format();
if prev_pos.distance(new_pos) < 4.0 { if prev_rect.min.distance(new_rect.min) < 4.0 {
show_error(new_pos, format!("Double use of ID {}", id_str)); show_error(new_rect.min, format!("Double use of ID {}", id_str));
} else { } else {
show_error(prev_pos, format!("First use of ID {}", id_str)); show_error(prev_rect.min, format!("First use of ID {}", id_str));
show_error(new_pos, format!("Second use of ID {}", id_str)); show_error(new_rect.min, format!("Second use of ID {}", id_str));
} }
// TODO: a tooltip explaining this. // TODO: a tooltip explaining this.
@ -218,7 +221,7 @@ impl CtxRef {
response.clicked[PointerButton::Primary as usize] = true; response.clicked[PointerButton::Primary as usize] = true;
} }
self.register_interaction_id(id, rect.min); self.register_interaction_id(id, rect);
if sense.click || sense.drag { if sense.click || sense.drag {
let mut memory = self.memory(); let mut memory = self.memory();

View file

@ -7,7 +7,7 @@ use epaint::ahash;
pub(crate) struct FrameState { pub(crate) struct FrameState {
/// All `Id`s that were used this frame. /// All `Id`s that were used this frame.
/// Used to debug `Id` clashes of widgets. /// Used to debug `Id` clashes of widgets.
pub(crate) used_ids: ahash::AHashMap<Id, Pos2>, pub(crate) used_ids: ahash::AHashMap<Id, Rect>,
/// Starts off as the screen_rect, shrinks as panels are added. /// Starts off as the screen_rect, shrinks as panels are added.
/// The `CentralPanel` does not change this. /// The `CentralPanel` does not change this.

View file

@ -230,7 +230,7 @@ impl Focus {
} }
} }
pub(crate) fn end_frame(&mut self, used_ids: &epaint::ahash::AHashMap<Id, Pos2>) { pub(crate) fn end_frame(&mut self, used_ids: &epaint::ahash::AHashMap<Id, Rect>) {
if let Some(id) = self.id { if let Some(id) = self.id {
// Allow calling `request_focus` one frame and not using it until next frame // Allow calling `request_focus` one frame and not using it until next frame
let recently_gained_focus = self.id_previous_frame != Some(id); let recently_gained_focus = self.id_previous_frame != Some(id);
@ -284,7 +284,7 @@ impl Memory {
pub(crate) fn end_frame( pub(crate) fn end_frame(
&mut self, &mut self,
input: &InputState, input: &InputState,
used_ids: &epaint::ahash::AHashMap<Id, Pos2>, used_ids: &epaint::ahash::AHashMap<Id, Rect>,
) { ) {
self.areas.end_frame(); self.areas.end_frame();
self.interaction.focus.end_frame(used_ids); self.interaction.focus.end_frame(used_ids);

View file

@ -381,8 +381,14 @@ impl<'t, S: TextBuffer> Widget for TextEdit<'t, S> {
let max_rect = ui.available_rect_before_wrap().shrink2(margin); let max_rect = ui.available_rect_before_wrap().shrink2(margin);
let mut content_ui = ui.child_ui(max_rect, *ui.layout()); let mut content_ui = ui.child_ui(max_rect, *ui.layout());
let response = self.content_ui(&mut content_ui); let response = self.content_ui(&mut content_ui);
let id = response.id;
let frame_rect = response.rect.expand2(margin); let frame_rect = response.rect.expand2(margin);
let response = response | ui.allocate_rect(frame_rect, Sense::hover()); ui.allocate_rect(frame_rect, Sense::hover());
let frame_response = ui.interact(frame_rect, id, Sense::click());
let response = response | frame_response;
if response.clicked() {
ui.memory().request_focus(response.id);
}
if frame { if frame {
let visuals = ui.style().interact(&response); let visuals = ui.style().interact(&response);