drawer: support ESC to close it by on_action and call on_close (#341)
Fix #263 
This commit is contained in:
parent
9b8240c6bc
commit
51df8f2f04
3 changed files with 44 additions and 13 deletions
|
|
@ -1,10 +1,10 @@
|
||||||
use std::{rc::Rc, time::Duration};
|
use std::{rc::Rc, time::Duration};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
anchored, div, point, prelude::FluentBuilder as _, px, Animation, AnimationExt as _,
|
actions, anchored, div, point, prelude::FluentBuilder as _, px, Animation, AnimationExt as _,
|
||||||
AnyElement, ClickEvent, DefiniteLength, DismissEvent, Div, EventEmitter, FocusHandle,
|
AnyElement, AppContext, ClickEvent, DefiniteLength, DismissEvent, Div, EventEmitter,
|
||||||
InteractiveElement as _, IntoElement, MouseButton, ParentElement, Pixels, RenderOnce, Styled,
|
FocusHandle, InteractiveElement as _, IntoElement, KeyBinding, MouseButton, ParentElement,
|
||||||
WindowContext,
|
Pixels, RenderOnce, Styled, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -17,9 +17,16 @@ use crate::{
|
||||||
v_flex, IconName, Placement, Sizable, StyledExt as _,
|
v_flex, IconName, Placement, Sizable, StyledExt as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
actions!(drawer, [Escape]);
|
||||||
|
|
||||||
|
const CONTEXT: &str = "Drawer";
|
||||||
|
pub fn init(cx: &mut AppContext) {
|
||||||
|
cx.bind_keys([KeyBinding::new("escape", Escape, Some(CONTEXT))])
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub struct Drawer {
|
pub struct Drawer {
|
||||||
focus_handle: FocusHandle,
|
pub(crate) focus_handle: FocusHandle,
|
||||||
placement: Placement,
|
placement: Placement,
|
||||||
size: DefiniteLength,
|
size: DefiniteLength,
|
||||||
resizable: bool,
|
resizable: bool,
|
||||||
|
|
@ -120,7 +127,6 @@ impl Styled for Drawer {
|
||||||
|
|
||||||
impl RenderOnce for Drawer {
|
impl RenderOnce for Drawer {
|
||||||
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||||
let focus_handle = self.focus_handle.clone();
|
|
||||||
let placement = self.placement;
|
let placement = self.placement;
|
||||||
let titlebar_height = self.margin_top;
|
let titlebar_height = self.margin_top;
|
||||||
let size = cx.viewport_size();
|
let size = cx.viewport_size();
|
||||||
|
|
@ -146,8 +152,16 @@ impl RenderOnce for Drawer {
|
||||||
})
|
})
|
||||||
.child(
|
.child(
|
||||||
v_flex()
|
v_flex()
|
||||||
.id("")
|
.id("drawer")
|
||||||
.track_focus(&focus_handle)
|
.key_context(CONTEXT)
|
||||||
|
.track_focus(&self.focus_handle)
|
||||||
|
.on_action({
|
||||||
|
let on_close = self.on_close.clone();
|
||||||
|
move |_: &Escape, cx| {
|
||||||
|
on_close(&ClickEvent::default(), cx);
|
||||||
|
cx.close_drawer();
|
||||||
|
}
|
||||||
|
})
|
||||||
.absolute()
|
.absolute()
|
||||||
.occlude()
|
.occlude()
|
||||||
.bg(cx.theme().background)
|
.bg(cx.theme().background)
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ pub fn init(cx: &mut gpui::AppContext) {
|
||||||
context_menu::init(cx);
|
context_menu::init(cx);
|
||||||
date_picker::init(cx);
|
date_picker::init(cx);
|
||||||
dock::init(cx);
|
dock::init(cx);
|
||||||
|
drawer::init(cx);
|
||||||
dropdown::init(cx);
|
dropdown::init(cx);
|
||||||
input::init(cx);
|
input::init(cx);
|
||||||
list::init(cx);
|
list::init(cx);
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,14 @@ impl<'a> ContextModal for WindowContext<'a> {
|
||||||
if root.active_drawer.is_none() {
|
if root.active_drawer.is_none() {
|
||||||
root.previous_focus_handle = cx.focused();
|
root.previous_focus_handle = cx.focused();
|
||||||
}
|
}
|
||||||
root.active_drawer = Some(Rc::new(build));
|
|
||||||
|
let focus_handle = cx.focus_handle();
|
||||||
|
focus_handle.focus(cx);
|
||||||
|
|
||||||
|
root.active_drawer = Some(ActiveDrawer {
|
||||||
|
focus_handle,
|
||||||
|
builder: Rc::new(build),
|
||||||
|
});
|
||||||
cx.notify();
|
cx.notify();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -199,12 +206,18 @@ pub struct Root {
|
||||||
/// Used to store the focus handle of the previus revious view.
|
/// Used to store the focus handle of the previus revious view.
|
||||||
/// When the Modal, Drawer closes, we will focus back to the previous view.
|
/// When the Modal, Drawer closes, we will focus back to the previous view.
|
||||||
previous_focus_handle: Option<FocusHandle>,
|
previous_focus_handle: Option<FocusHandle>,
|
||||||
active_drawer: Option<Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>>,
|
active_drawer: Option<ActiveDrawer>,
|
||||||
active_modals: Vec<ActiveModal>,
|
active_modals: Vec<ActiveModal>,
|
||||||
pub notification: View<NotificationList>,
|
pub notification: View<NotificationList>,
|
||||||
child: AnyView,
|
child: AnyView,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ActiveDrawer {
|
||||||
|
focus_handle: FocusHandle,
|
||||||
|
builder: Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct ActiveModal {
|
struct ActiveModal {
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
|
|
@ -270,9 +283,12 @@ impl Root {
|
||||||
.and_then(|w| w.root_view(cx).ok())
|
.and_then(|w| w.root_view(cx).ok())
|
||||||
.expect("The window root view should be of type `ui::Root`.");
|
.expect("The window root view should be of type `ui::Root`.");
|
||||||
|
|
||||||
if let Some(builder) = root.read(cx).active_drawer.clone() {
|
if let Some(active_drawer) = root.read(cx).active_drawer.clone() {
|
||||||
let drawer = Drawer::new(cx);
|
let mut drawer = Drawer::new(cx);
|
||||||
return Some(builder(drawer, cx));
|
drawer = (active_drawer.builder)(drawer, cx);
|
||||||
|
drawer.focus_handle = active_drawer.focus_handle.clone();
|
||||||
|
|
||||||
|
return Some(div().child(drawer));
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue