Skip to content

Commit 9eba97d

Browse files
authored
modal: Fix modal, drawer overlay position on Linux. (sentriz#515)
- Update `overlay` for Modal, still handle click out to dismiss, even it no overlay.
1 parent 6acbfb5 commit 9eba97d

File tree

4 files changed

+80
-67
lines changed

4 files changed

+80
-67
lines changed

crates/ui/src/drawer.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use crate::{
1515
scroll::ScrollbarAxis,
1616
theme::ActiveTheme,
1717
title_bar::TITLE_BAR_HEIGHT,
18-
v_flex, IconName, Placement, Sizable, StyledExt as _,
18+
v_flex,
19+
window_border::SHADOW_SIZE,
20+
IconName, Placement, Sizable, StyledExt as _,
1921
};
2022

2123
actions!(drawer, [Escape]);
@@ -119,11 +121,11 @@ impl RenderOnce for Drawer {
119121
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
120122
let placement = self.placement;
121123
let titlebar_height = self.margin_top;
122-
let size = cx.viewport_size();
124+
let size = cx.viewport_size() - gpui::size(SHADOW_SIZE * 2, SHADOW_SIZE * 2);
123125
let on_close = self.on_close.clone();
124126

125127
anchored()
126-
.position(point(px(0.), titlebar_height))
128+
.position(point(px(0.) + SHADOW_SIZE, titlebar_height + SHADOW_SIZE))
127129
.snap_to_window()
128130
.child(
129131
div()

crates/ui/src/modal.rs

Lines changed: 70 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::{rc::Rc, time::Duration};
22

33
use gpui::{
4-
actions, anchored, div, hsla, prelude::FluentBuilder, px, relative, Animation,
4+
actions, anchored, div, hsla, point, prelude::FluentBuilder, px, relative, Animation,
55
AnimationExt as _, AnyElement, AppContext, Bounds, ClickEvent, Div, FocusHandle, Hsla,
66
InteractiveElement, IntoElement, KeyBinding, MouseButton, ParentElement, Pixels, Point,
77
RenderOnce, SharedString, Styled, WindowContext,
@@ -11,7 +11,9 @@ use crate::{
1111
animation::cubic_bezier,
1212
button::{Button, ButtonVariants as _},
1313
theme::ActiveTheme as _,
14-
v_flex, ContextModal, IconName, Sizable as _,
14+
v_flex,
15+
window_border::SHADOW_SIZE,
16+
ContextModal, IconName, Sizable as _,
1517
};
1618

1719
actions!(modal, [Escape]);
@@ -162,7 +164,7 @@ impl RenderOnce for Modal {
162164
fn render(self, cx: &mut WindowContext) -> impl gpui::IntoElement {
163165
let layer_ix = self.layer_ix;
164166
let on_close = self.on_close.clone();
165-
let view_size = cx.viewport_size();
167+
let view_size = cx.viewport_size() - gpui::size(SHADOW_SIZE * 2, SHADOW_SIZE * 2);
166168
let bounds = Bounds {
167169
origin: Point::default(),
168170
size: view_size,
@@ -171,78 +173,83 @@ impl RenderOnce for Modal {
171173
let y = self.margin_top.unwrap_or(view_size.height / 10.) + offset_top;
172174
let x = bounds.center().x - self.width / 2.;
173175

174-
anchored().snap_to_window().child(
175-
div()
176-
.occlude()
177-
.w(view_size.width)
178-
.h(view_size.height)
179-
.when(self.overlay_visible, |this| {
180-
this.bg(overlay_color(self.overlay, cx))
181-
})
182-
.when(self.overlay, |this| {
183-
this.on_mouse_down(MouseButton::Left, {
176+
anchored()
177+
.position(point(SHADOW_SIZE, SHADOW_SIZE))
178+
.snap_to_window()
179+
.child(
180+
div()
181+
.occlude()
182+
.w(view_size.width)
183+
.h(view_size.height)
184+
.when(self.overlay_visible, |this| {
185+
this.bg(overlay_color(self.overlay, cx))
186+
})
187+
.on_mouse_down(MouseButton::Left, {
184188
let on_close = self.on_close.clone();
185189
move |_, cx| {
186190
on_close(&ClickEvent::default(), cx);
187191
cx.close_modal();
188192
}
189193
})
190-
})
191-
.child(
192-
self.base
193-
.id(SharedString::from(format!("modal-{layer_ix}")))
194-
.key_context(CONTEXT)
195-
.track_focus(&self.focus_handle)
196-
.when(self.keyboard, |this| {
197-
this.on_action({
198-
let on_close = self.on_close.clone();
199-
move |_: &Escape, cx| {
200-
// FIXME:
201-
//
202-
// Here some Modal have no focus_handle, so it will not work will Escape key.
203-
// But by now, we `cx.close_modal()` going to close the last active model, so the Escape is unexpected to work.
204-
on_close(&ClickEvent::default(), cx);
205-
cx.close_modal();
206-
}
194+
.child(
195+
self.base
196+
.id(SharedString::from(format!("modal-{layer_ix}")))
197+
.key_context(CONTEXT)
198+
.track_focus(&self.focus_handle)
199+
.when(self.keyboard, |this| {
200+
this.on_action({
201+
let on_close = self.on_close.clone();
202+
move |_: &Escape, cx| {
203+
// FIXME:
204+
//
205+
// Here some Modal have no focus_handle, so it will not work will Escape key.
206+
// But by now, we `cx.close_modal()` going to close the last active model, so the Escape is unexpected to work.
207+
on_close(&ClickEvent::default(), cx);
208+
cx.close_modal();
209+
}
210+
})
211+
})
212+
.absolute()
213+
.occlude()
214+
.relative()
215+
.left(x)
216+
.top(y)
217+
.w(self.width)
218+
.when_some(self.max_width, |this, w| this.max_w(w))
219+
.when_some(self.title, |this, title| {
220+
this.child(div().line_height(relative(1.)).child(title))
207221
})
208-
})
209-
.absolute()
210-
.occlude()
211-
.relative()
212-
.left(x)
213-
.top(y)
214-
.w(self.width)
215-
.when_some(self.max_width, |this, w| this.max_w(w))
216-
.when_some(self.title, |this, title| {
217-
this.child(div().line_height(relative(1.)).child(title))
218-
})
219-
.when(self.show_close, |this| {
220-
this.child(
221-
Button::new(SharedString::from(format!("modal-close-{layer_ix}")))
222+
.when(self.show_close, |this| {
223+
this.child(
224+
Button::new(SharedString::from(format!(
225+
"modal-close-{layer_ix}"
226+
)))
222227
.absolute()
223228
.top_2()
224229
.right_2()
225230
.small()
226231
.ghost()
227232
.icon(IconName::Close)
228-
.on_click(move |_, cx| {
229-
on_close(&ClickEvent::default(), cx);
230-
cx.close_modal();
231-
}),
232-
)
233-
})
234-
.child(self.content)
235-
.children(self.footer)
236-
.with_animation(
237-
"slide-down",
238-
Animation::new(Duration::from_secs_f64(0.25))
239-
.with_easing(cubic_bezier(0.32, 0.72, 0., 1.)),
240-
move |this, delta| {
241-
let y_offset = px(0.) + delta * px(30.);
242-
this.top(y + y_offset).opacity(delta)
243-
},
244-
),
245-
),
246-
)
233+
.on_click(
234+
move |_, cx| {
235+
on_close(&ClickEvent::default(), cx);
236+
cx.close_modal();
237+
},
238+
),
239+
)
240+
})
241+
.child(self.content)
242+
.children(self.footer)
243+
.with_animation(
244+
"slide-down",
245+
Animation::new(Duration::from_secs_f64(0.25))
246+
.with_easing(cubic_bezier(0.32, 0.72, 0., 1.)),
247+
move |this, delta| {
248+
let y_offset = px(0.) + delta * px(30.);
249+
this.top(y + y_offset).opacity(delta)
250+
},
251+
),
252+
),
253+
)
247254
}
248255
}

crates/ui/src/root.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ impl Render for Root {
405405
window_border().child(
406406
div()
407407
.id("root")
408+
.relative()
408409
.size_full()
409410
.font_family(".SystemUIFont")
410411
.bg(cx.theme().background)

crates/ui/src/window_border.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ use gpui::{
88

99
use crate::theme::ActiveTheme;
1010

11-
const SHADOW_SIZE: Pixels = Pixels(12.0);
11+
#[cfg(not(target_os = "linux"))]
12+
pub(crate) const SHADOW_SIZE: Pixels = Pixels(0.0);
13+
#[cfg(target_os = "linux")]
14+
pub(crate) const SHADOW_SIZE: Pixels = Pixels(12.0);
1215
const BORDER_SIZE: Pixels = Pixels(1.0);
1316
pub(crate) const BORDER_RADIUS: Pixels = Pixels(0.0);
1417

0 commit comments

Comments
 (0)