Navigation · Tabs on_context: a right click on a tab reports that tab and the pointer, not the chosen one
This commit is contained in:
2 files changed
+63
-1
No files matched your search
+25
-1
@@ -2,7 +2,7 @@ use std::rc::Rc;
|
||||
|
||||
use gpui::{
|
||||
Animation, AnimationExt, AnyElement, App, ElementId, FontWeight, InteractiveElement,
|
||||
IntoElement, MouseButton, ParentElement, RenderOnce, Role, SharedString,
|
||||
IntoElement, MouseButton, ParentElement, Pixels, Point, RenderOnce, Role, SharedString,
|
||||
StatefulInteractiveElement, Styled, Window, div, prelude::*,
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@ pub enum TabPlacement {
|
||||
}
|
||||
|
||||
type OnValue = Rc<dyn Fn(&SharedString, &mut Window, &mut App)>;
|
||||
type OnContext = Rc<dyn Fn(&SharedString, Point<Pixels>, &mut Window, &mut App)>;
|
||||
|
||||
/// A strip of tabs and the chosen tab's panel. A line slides to the chosen tab; arrows move it.
|
||||
#[derive(IntoElement)]
|
||||
@@ -33,6 +34,7 @@ pub struct Tabs {
|
||||
placement: TabPlacement,
|
||||
panel: Option<AnyElement>,
|
||||
on_change: Option<OnValue>,
|
||||
on_context: Option<OnContext>,
|
||||
}
|
||||
|
||||
impl Tabs {
|
||||
@@ -48,6 +50,7 @@ impl Tabs {
|
||||
placement: TabPlacement::default(),
|
||||
panel: None,
|
||||
on_change: None,
|
||||
on_context: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +74,17 @@ impl Tabs {
|
||||
}
|
||||
}
|
||||
|
||||
impl Tabs {
|
||||
/// A right click on a tab: its value and the pointer.
|
||||
pub fn on_context(
|
||||
mut self,
|
||||
handler: impl Fn(&SharedString, Point<Pixels>, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
self.on_context = Some(Rc::new(handler));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for Tabs {
|
||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let values: Vec<SharedString> = self.tabs.iter().map(|tab| tab.value.clone()).collect();
|
||||
@@ -148,6 +162,8 @@ impl RenderOnce for Tabs {
|
||||
(false, false) => colors.fg_muted,
|
||||
};
|
||||
let pick = pick.clone();
|
||||
let context = self.on_context.clone().filter(|_| !tab.disabled);
|
||||
let value = tab.value.clone();
|
||||
div()
|
||||
.id(("tab", ix))
|
||||
.role(Role::Tab)
|
||||
@@ -185,6 +201,14 @@ impl RenderOnce for Tabs {
|
||||
}
|
||||
})
|
||||
})
|
||||
.when_some(context, |item, context| {
|
||||
item.on_mouse_down(MouseButton::Right, move |event, window, cx| {
|
||||
window.prevent_default();
|
||||
cx.stop_propagation();
|
||||
log::info!("tabs: context on {value}");
|
||||
context(&value, event.position, window, cx);
|
||||
})
|
||||
})
|
||||
.when_some(tab.icon, |item, icon| {
|
||||
item.child(Icon::new(icon).size(IconSize::Sm).color(fg))
|
||||
})
|
||||
|
||||
@@ -470,3 +470,41 @@ fn steps_fill_a_column_their_block_measures_by_content(cx: &mut TestAppContext)
|
||||
"the steps span the card inside its padding"
|
||||
);
|
||||
}
|
||||
|
||||
struct Context_ {
|
||||
chosen: SharedString,
|
||||
asked: Option<SharedString>,
|
||||
}
|
||||
|
||||
impl Render for Context_ {
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let view = cx.entity();
|
||||
let tabs = [Choice::new("a", "A"), Choice::new("c", "C")];
|
||||
Tabs::new("tabs", tabs, self.chosen.clone()).on_context(move |value, _, _, cx| {
|
||||
view.update(cx, |view, cx| {
|
||||
view.asked = Some(value.clone());
|
||||
cx.notify();
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn a_right_click_names_its_tab_and_keeps_the_choice(cx: &mut TestAppContext) {
|
||||
setup(cx);
|
||||
let (view, cx) = cx.add_window_view(|_, _| Context_ {
|
||||
chosen: "c".into(),
|
||||
asked: None,
|
||||
});
|
||||
settle(cx);
|
||||
let at = point(px(12.0), px(16.0));
|
||||
cx.simulate_mouse_move(at, None, Modifiers::none());
|
||||
cx.simulate_mouse_down(at, gpui::MouseButton::Right, Modifiers::none());
|
||||
let (chosen, asked) = view.read_with(cx, |view, _| (view.chosen.clone(), view.asked.clone()));
|
||||
assert_eq!(
|
||||
asked.as_deref(),
|
||||
Some("a"),
|
||||
"the clicked tab, not the chosen one"
|
||||
);
|
||||
assert_eq!(chosen, "c");
|
||||
}
|
||||
Reference in new issue
Block a user