use std::collections::HashMap;
use gpui_kit::{
App, ElementId, Entity, Global, WeakEntity, Window, WindowId, base::TooltipOverlay,
};
#[derive(Default)]
pub struct TooltipHost {
overlays: HashMap<WindowId, WeakEntity<TooltipOverlay>>,
requesters: HashMap<WindowId, ElementId>,
}
impl Global for TooltipHost {}
impl TooltipHost {
pub fn register(window: &Window, overlay: &Entity<TooltipOverlay>, cx: &mut App) {
let id = window.window_handle().window_id();
let overlays = &mut cx.default_global::<Self>().overlays;
overlays.retain(|_, overlay| overlay.upgrade().is_some());
overlays.insert(id, overlay.downgrade());
}
pub fn overlay(window: &Window, cx: &App) -> Option<Entity<TooltipOverlay>> {
let id = window.window_handle().window_id();
cx.try_global::<Self>()?.overlays.get(&id)?.upgrade()
}
pub(crate) fn note_requester(window: &Window, trigger: &ElementId, cx: &mut App) {
let id = window.window_handle().window_id();
cx.default_global::<Self>()
.requesters
.insert(id, trigger.clone());
}
pub(crate) fn is_requester(window: &Window, trigger: &ElementId, cx: &App) -> bool {
let id = window.window_handle().window_id();
cx.try_global::<Self>()
.and_then(|host| host.requesters.get(&id))
.is_some_and(|requester| requester == trigger)
}
}
#[cfg(test)]
mod tests {
use super::*;
use gpui_kit::{AppContext as _, Context, IntoElement, Render, TestAppContext, div};
struct Empty;
impl Render for Empty {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
div()
}
}
#[gpui_kit::test]
fn registry_is_per_window_and_weak(cx: &mut TestAppContext) {
cx.update(|cx| {
gpui_kit::init(cx);
crate::init(cx);
});
let (_, cx) = cx.add_window_view(|_, _| Empty);
cx.update(|window, cx| {
assert!(TooltipHost::overlay(window, cx).is_none());
let overlay = cx.new(|_| TooltipOverlay::new());
TooltipHost::register(window, &overlay, cx);
assert_eq!(
TooltipHost::overlay(window, cx).map(|o| o.entity_id()),
Some(overlay.entity_id())
);
drop(overlay);
});
cx.update(|window, cx| {
assert!(TooltipHost::overlay(window, cx).is_none());
});
}
}