Tooltip on tabs
Co-Authored-By: Julia <julia@zed.dev>
This commit is contained in:
parent
26e64fb843
commit
33245d119e
6 changed files with 77 additions and 7 deletions
|
@ -157,6 +157,7 @@ pub struct AppContext {
|
||||||
flushing_effects: bool,
|
flushing_effects: bool,
|
||||||
pending_updates: usize,
|
pending_updates: usize,
|
||||||
pub(crate) active_drag: Option<AnyDrag>,
|
pub(crate) active_drag: Option<AnyDrag>,
|
||||||
|
pub(crate) active_tooltip: Option<AnyView>,
|
||||||
pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>,
|
pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>,
|
||||||
pub(crate) frame_consumers: HashMap<DisplayId, Task<()>>,
|
pub(crate) frame_consumers: HashMap<DisplayId, Task<()>>,
|
||||||
pub(crate) background_executor: BackgroundExecutor,
|
pub(crate) background_executor: BackgroundExecutor,
|
||||||
|
@ -215,6 +216,7 @@ impl AppContext {
|
||||||
flushing_effects: false,
|
flushing_effects: false,
|
||||||
pending_updates: 0,
|
pending_updates: 0,
|
||||||
active_drag: None,
|
active_drag: None,
|
||||||
|
active_tooltip: None,
|
||||||
next_frame_callbacks: HashMap::default(),
|
next_frame_callbacks: HashMap::default(),
|
||||||
frame_consumers: HashMap::default(),
|
frame_consumers: HashMap::default(),
|
||||||
background_executor: executor,
|
background_executor: executor,
|
||||||
|
|
|
@ -358,7 +358,7 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
||||||
self.stateful_interaction().tooltip_builder.is_none(),
|
self.stateful_interaction().tooltip_builder.is_none(),
|
||||||
"calling tooltip more than once on the same element is not supported"
|
"calling tooltip more than once on the same element is not supported"
|
||||||
);
|
);
|
||||||
self.stateful_interaction().tooltip_builder = Some(Box::new(move |view_state, cx| {
|
self.stateful_interaction().tooltip_builder = Some(Arc::new(move |view_state, cx| {
|
||||||
build_tooltip(view_state, cx).into()
|
build_tooltip(view_state, cx).into()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -602,6 +602,10 @@ pub trait ElementInteraction<V: 'static>: 'static {
|
||||||
if let Some(hover_listener) = stateful.hover_listener.take() {
|
if let Some(hover_listener) = stateful.hover_listener.take() {
|
||||||
let was_hovered = element_state.hover_state.clone();
|
let was_hovered = element_state.hover_state.clone();
|
||||||
let has_mouse_down = element_state.pending_mouse_down.lock().is_some();
|
let has_mouse_down = element_state.pending_mouse_down.lock().is_some();
|
||||||
|
|
||||||
|
let active_tooltip = element_state.active_tooltip.clone();
|
||||||
|
let tooltip_builder = stateful.tooltip_builder.clone();
|
||||||
|
|
||||||
cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| {
|
cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| {
|
||||||
if phase != DispatchPhase::Bubble {
|
if phase != DispatchPhase::Bubble {
|
||||||
return;
|
return;
|
||||||
|
@ -612,11 +616,26 @@ pub trait ElementInteraction<V: 'static>: 'static {
|
||||||
if is_hovered != was_hovered.clone() {
|
if is_hovered != was_hovered.clone() {
|
||||||
*was_hovered = is_hovered;
|
*was_hovered = is_hovered;
|
||||||
drop(was_hovered);
|
drop(was_hovered);
|
||||||
|
if let Some(tooltip_builder) = &tooltip_builder {
|
||||||
|
let mut active_tooltip = active_tooltip.lock();
|
||||||
|
if is_hovered && active_tooltip.is_none() {
|
||||||
|
*active_tooltip = Some(tooltip_builder(view_state, cx));
|
||||||
|
} else if !is_hovered {
|
||||||
|
active_tooltip.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hover_listener(view_state, is_hovered, cx);
|
hover_listener(view_state, is_hovered, cx);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(active_tooltip) = element_state.active_tooltip.lock().as_ref() {
|
||||||
|
if *element_state.hover_state.lock() {
|
||||||
|
cx.active_tooltip = Some(active_tooltip.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let active_state = element_state.active_state.clone();
|
let active_state = element_state.active_state.clone();
|
||||||
if active_state.lock().is_none() {
|
if active_state.lock().is_none() {
|
||||||
let active_group_bounds = stateful
|
let active_group_bounds = stateful
|
||||||
|
@ -804,6 +823,7 @@ pub struct InteractiveElementState {
|
||||||
hover_state: Arc<Mutex<bool>>,
|
hover_state: Arc<Mutex<bool>>,
|
||||||
pending_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
|
pending_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||||
scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
|
scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
|
||||||
|
active_tooltip: Arc<Mutex<Option<AnyView>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InteractiveElementState {
|
impl InteractiveElementState {
|
||||||
|
@ -1155,7 +1175,7 @@ pub(crate) type DragListener<V> =
|
||||||
|
|
||||||
pub(crate) type HoverListener<V> = Box<dyn Fn(&mut V, bool, &mut ViewContext<V>) + 'static>;
|
pub(crate) type HoverListener<V> = Box<dyn Fn(&mut V, bool, &mut ViewContext<V>) + 'static>;
|
||||||
|
|
||||||
pub(crate) type TooltipBuilder<V> = Box<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>;
|
pub(crate) type TooltipBuilder<V> = Arc<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>;
|
||||||
|
|
||||||
pub type KeyListener<V> = Box<
|
pub type KeyListener<V> = Box<
|
||||||
dyn Fn(
|
dyn Fn(
|
||||||
|
|
|
@ -987,6 +987,14 @@ impl<'a> WindowContext<'a> {
|
||||||
cx.active_drag = Some(active_drag);
|
cx.active_drag = Some(active_drag);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
} else if let Some(active_tooltip) = self.app.active_tooltip.take() {
|
||||||
|
self.stack(1, |cx| {
|
||||||
|
cx.with_element_offset(Some(cx.mouse_position()), |cx| {
|
||||||
|
let available_space =
|
||||||
|
size(AvailableSpace::MinContent, AvailableSpace::MinContent);
|
||||||
|
active_tooltip.draw(available_space, cx);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.window.root_view = Some(root_view);
|
self.window.root_view = Some(root_view);
|
||||||
|
|
|
@ -31,6 +31,7 @@ mod theme_selector;
|
||||||
mod title_bar;
|
mod title_bar;
|
||||||
mod toast;
|
mod toast;
|
||||||
mod toolbar;
|
mod toolbar;
|
||||||
|
mod tooltip;
|
||||||
mod traffic_lights;
|
mod traffic_lights;
|
||||||
mod workspace;
|
mod workspace;
|
||||||
|
|
||||||
|
@ -67,5 +68,6 @@ pub use theme_selector::*;
|
||||||
pub use title_bar::*;
|
pub use title_bar::*;
|
||||||
pub use toast::*;
|
pub use toast::*;
|
||||||
pub use toolbar::*;
|
pub use toolbar::*;
|
||||||
|
pub use tooltip::*;
|
||||||
pub use traffic_lights::*;
|
pub use traffic_lights::*;
|
||||||
pub use workspace::*;
|
pub use workspace::*;
|
||||||
|
|
36
crates/ui2/src/components/tooltip.rs
Normal file
36
crates/ui2/src/components/tooltip.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use gpui2::{
|
||||||
|
div, px, Div, ParentElement, Render, SharedString, Styled, View, ViewContext, VisualContext,
|
||||||
|
};
|
||||||
|
use theme2::ActiveTheme;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct TextTooltip {
|
||||||
|
title: SharedString,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextTooltip {
|
||||||
|
pub fn new(str: SharedString) -> Self {
|
||||||
|
Self { title: str }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_view<C: VisualContext>(str: SharedString, cx: &mut C) -> C::Result<View<Self>> {
|
||||||
|
cx.build_view(|cx| TextTooltip::new(str))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for TextTooltip {
|
||||||
|
type Element = Div<Self>;
|
||||||
|
|
||||||
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||||
|
let theme = cx.theme();
|
||||||
|
div()
|
||||||
|
.bg(theme.colors().background)
|
||||||
|
.rounded(px(8.))
|
||||||
|
.border()
|
||||||
|
.border_color(theme.colors().border)
|
||||||
|
.text_color(theme.colors().text)
|
||||||
|
.pl_2()
|
||||||
|
.pr_2()
|
||||||
|
.child(self.title.clone())
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,9 +9,8 @@ use crate::{
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use collections::{HashMap, HashSet, VecDeque};
|
use collections::{HashMap, HashSet, VecDeque};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AppContext, AsyncWindowContext, Component, CursorStyle, Div, EntityId, EventEmitter,
|
AnyView, AppContext, AsyncWindowContext, Component, Div, EntityId, EventEmitter, FocusHandle,
|
||||||
FocusHandle, Model, PromptLevel, Render, Task, View, ViewContext, VisualContext, WeakView,
|
Model, PromptLevel, Render, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
|
||||||
WindowContext,
|
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use project2::{Project, ProjectEntryId, ProjectPath};
|
use project2::{Project, ProjectEntryId, ProjectPath};
|
||||||
|
@ -27,7 +26,7 @@ use std::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use ui::v_stack;
|
use ui::v_stack;
|
||||||
use ui::{prelude::*, Icon, IconButton, IconColor, IconElement};
|
use ui::{prelude::*, Icon, IconButton, IconColor, IconElement, TextTooltip};
|
||||||
use util::truncate_and_remove_front;
|
use util::truncate_and_remove_front;
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Copy, Deserialize, Debug)]
|
#[derive(PartialEq, Clone, Copy, Deserialize, Debug)]
|
||||||
|
@ -1402,7 +1401,10 @@ impl Pane {
|
||||||
.on_hover(|_, hovered, _| {
|
.on_hover(|_, hovered, _| {
|
||||||
dbg!(hovered);
|
dbg!(hovered);
|
||||||
})
|
})
|
||||||
// .tooltip(|pane, cx| cx.create_view( tooltip.child("Hovering the tab"))
|
.when_some(item.tab_tooltip_text(cx), |div, text| {
|
||||||
|
div.tooltip(move |_, cx| TextTooltip::build_view(text.clone(), cx))
|
||||||
|
})
|
||||||
|
// .tooltip(|pane, cx| cx.build_view(|cx| div().child(title)))
|
||||||
// .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx))
|
// .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx))
|
||||||
// .drag_over::<DraggedTab>(|d| d.bg(cx.theme().colors().element_drop_target))
|
// .drag_over::<DraggedTab>(|d| d.bg(cx.theme().colors().element_drop_target))
|
||||||
// .on_drop(|_view, state: View<DraggedTab>, cx| {
|
// .on_drop(|_view, state: View<DraggedTab>, cx| {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue