Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix tooltip behaviour #414

Merged
merged 12 commits into from
May 8, 2024
10 changes: 10 additions & 0 deletions examples/keyboard_listener/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "keyboard_listener"
edition = "2021"
license.workspace = true
version.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
floem = { path = "../.." }
31 changes: 31 additions & 0 deletions examples/keyboard_listener/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use floem::event::{Event, EventListener};
use floem::reactive::create_rw_signal;
use floem::views::label;
use floem::{
view::View,
views::{v_stack, Decorators},
widgets::text_input,
EventPropagation,
};

fn app_view() -> impl View {
let text = create_rw_signal("".to_string());
let keyboard_signal = create_rw_signal("".to_string());
v_stack((
text_input(text)
.placeholder("Write here")
.keyboard_navigatable(),
label(move || format!("Key Pressed: {}", keyboard_signal.get()))
.keyboard_listenable()
.on_event(EventListener::KeyDown, move |e| {
if let Event::KeyDown(e) = e {
keyboard_signal.set(e.key.logical_key.to_text().unwrap().to_string());
}
EventPropagation::Continue
}),
))
}

fn main() {
floem::launch(app_view);
}
2 changes: 2 additions & 0 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ pub struct AppState {
pub(crate) request_paint: bool,
pub(crate) disabled: HashSet<Id>,
pub(crate) keyboard_navigable: HashSet<Id>,
pub(crate) keyboard_listenable: HashSet<Id>,
pub(crate) draggable: HashSet<Id>,
pub(crate) dragging: Option<DragState>,
pub(crate) drag_start: Option<(Id, Point)>,
Expand Down Expand Up @@ -145,6 +146,7 @@ impl AppState {
request_compute_layout: false,
disabled: HashSet::new(),
keyboard_navigable: HashSet::new(),
keyboard_listenable: HashSet::new(),
draggable: HashSet::new(),
dragging: None,
drag_start: None,
Expand Down
4 changes: 4 additions & 0 deletions src/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ impl Id {
self.add_update_message(UpdateMessage::KeyboardNavigable { id: *self });
}

pub fn keyboard_listenable(&self) {
self.add_update_message(UpdateMessage::KeyboardListenable { id: *self });
}

pub fn draggable(&self) {
self.add_update_message(UpdateMessage::Draggable { id: *self });
}
Expand Down
3 changes: 3 additions & 0 deletions src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ pub(crate) enum UpdateMessage {
KeyboardNavigable {
id: Id,
},
KeyboardListenable {
id: Id,
},
Draggable {
id: Id,
},
Expand Down
7 changes: 7 additions & 0 deletions src/views/decorator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ pub trait Decorators: View + Sized {
self
}

/// Allows the elements to receive keyboard events without being navigable and without being focused.
fn keyboard_listenable(self) -> Self {
let id = self.id();
id.keyboard_listenable();
self
}

fn draggable(self) -> Self {
let id = self.id();
id.draggable();
Expand Down
13 changes: 10 additions & 3 deletions src/views/tooltip.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use kurbo::Point;
use std::{rc::Rc, time::Duration};

use crate::views::Decorators;
use crate::{
action::{add_overlay, exec_after, remove_overlay, TimerToken},
context::{EventCx, UpdateCx},
Expand Down Expand Up @@ -44,6 +45,7 @@ pub fn tooltip<V: View + 'static, T: Widget + 'static>(
style: Default::default(),
window_origin: None,
}
.keyboard_listenable()
}

impl View for Tooltip {
Expand Down Expand Up @@ -110,7 +112,7 @@ impl Widget for Tooltip {
) -> EventPropagation {
match &event {
Event::PointerMove(e) => {
if self.overlay.is_none() {
if self.overlay.is_none() && cx.app_state.dragging.is_none() {
let id = self.id();
let token =
exec_after(Duration::from_secs_f64(self.style.delay()), move |token| {
Expand All @@ -119,7 +121,12 @@ impl Widget for Tooltip {
self.hover = Some((e.pos, token));
}
}
Event::PointerLeave => {
Event::PointerLeave
| Event::PointerDown(_)
| Event::PointerUp(_)
| Event::PointerWheel(_)
| Event::KeyUp(_)
| Event::KeyDown(_) => {
self.hover = None;
if let Some(id) = self.overlay {
remove_overlay(id);
Expand All @@ -141,7 +148,7 @@ impl Widget for Tooltip {
impl Drop for Tooltip {
fn drop(&mut self) {
if let Some(id) = self.overlay {
remove_overlay(id)
remove_overlay(id);
}
}
}
18 changes: 18 additions & 0 deletions src/window_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,21 @@ impl WindowHandle {
cx.app_state.focus
};

if matches!(event, Event::KeyUp(_)) || matches!(event, Event::KeyDown(_)) {
for id in cx.app_state.keyboard_listenable.clone().iter() {
let id_path = ID_PATHS.with(|paths| paths.borrow().get(id).cloned());
if let Some(id_path) = id_path {
cx.unconditional_view_event(
&mut self.view,
Some(id_path.dispatch()),
event.clone(),
);
} else {
cx.app_state.focus = None;
}
}
}

if event.needs_focus() {
let mut processed = false;

Expand Down Expand Up @@ -835,6 +850,9 @@ impl WindowHandle {
UpdateMessage::KeyboardNavigable { id } => {
cx.app_state.keyboard_navigable.insert(id);
}
UpdateMessage::KeyboardListenable { id } => {
cx.app_state.keyboard_listenable.insert(id);
}
UpdateMessage::Draggable { id } => {
cx.app_state.draggable.insert(id);
}
Expand Down
Loading