1use gpui::{
2 App, Application, Context, Corner, Div, Hsla, Stateful, Window, WindowOptions, anchored,
3 deferred, div, prelude::*, px,
4};
5
6/// An example show use deferred to create a floating layers.
7struct HelloWorld {
8 open: bool,
9 secondary_open: bool,
10}
11
12fn button(id: &'static str) -> Stateful<Div> {
13 div()
14 .id(id)
15 .bg(gpui::black())
16 .text_color(gpui::white())
17 .px_3()
18 .py_1()
19}
20
21fn popover() -> Div {
22 div()
23 .flex()
24 .flex_col()
25 .items_center()
26 .justify_center()
27 .shadow_lg()
28 .p_3()
29 .rounded_md()
30 .bg(gpui::white())
31 .text_color(gpui::black())
32 .border_1()
33 .text_sm()
34 .border_color(gpui::black().opacity(0.1))
35}
36
37fn line(color: Hsla) -> Div {
38 div().w(px(480.)).h_2().bg(color.opacity(0.25))
39}
40
41impl HelloWorld {
42 fn render_secondary_popover(
43 &mut self,
44 _window: &mut Window,
45 cx: &mut Context<Self>,
46 ) -> impl IntoElement {
47 button("secondary-btn")
48 .mt_2()
49 .child("Child Popover")
50 .on_click(cx.listener(|this, _, _, cx| {
51 this.secondary_open = true;
52 cx.notify();
53 }))
54 .when(self.secondary_open, |this| {
55 this.child(
56 // GPUI can't support deferred here yet,
57 // it was inside another deferred element.
58 anchored()
59 .anchor(Corner::TopLeft)
60 .snap_to_window_with_margin(px(8.))
61 .child(
62 popover()
63 .child("This is second level Popover")
64 .bg(gpui::white())
65 .border_color(gpui::blue())
66 .on_mouse_down_out(cx.listener(|this, _, _, cx| {
67 this.secondary_open = false;
68 cx.notify();
69 })),
70 ),
71 )
72 })
73 }
74}
75
76impl Render for HelloWorld {
77 fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
78 div()
79 .flex()
80 .flex_col()
81 .gap_3()
82 .size_full()
83 .bg(gpui::white())
84 .text_color(gpui::black())
85 .justify_center()
86 .items_center()
87 .child(
88 div()
89 .flex()
90 .flex_row()
91 .gap_4()
92 .child(
93 button("popover0").child("Opened Popover").child(
94 deferred(
95 anchored()
96 .anchor(Corner::TopLeft)
97 .snap_to_window_with_margin(px(8.))
98 .child(popover().w_96().gap_3().child(
99 "This is a default opened Popover, \
100 we can use deferred to render it \
101 in a floating layer.",
102 )),
103 )
104 .priority(0),
105 ),
106 )
107 .child(
108 button("popover1")
109 .child("Open Popover")
110 .on_click(cx.listener(|this, _, _, cx| {
111 this.open = true;
112 cx.notify();
113 }))
114 .when(self.open, |this| {
115 this.child(
116 deferred(
117 anchored()
118 .anchor(Corner::TopLeft)
119 .snap_to_window_with_margin(px(8.))
120 .child(
121 popover()
122 .w_96()
123 .gap_3()
124 .child(
125 "This is first level Popover, \
126 we can use deferred to render it \
127 in a floating layer.\n\
128 Click outside to close.",
129 )
130 .when(!self.secondary_open, |this| {
131 this.on_mouse_down_out(cx.listener(
132 |this, _, _, cx| {
133 this.open = false;
134 cx.notify();
135 },
136 ))
137 })
138 // Here we need render popover after the content
139 // to ensure it will be on top layer.
140 .child(
141 self.render_secondary_popover(window, cx),
142 ),
143 ),
144 )
145 .priority(1),
146 )
147 }),
148 ),
149 )
150 .child(
151 "Here is an example text rendered, \
152 to ensure the Popover will float above this contents.",
153 )
154 .children([
155 line(gpui::red()),
156 line(gpui::yellow()),
157 line(gpui::blue()),
158 line(gpui::green()),
159 ])
160 }
161}
162
163fn main() {
164 Application::new().run(|cx: &mut App| {
165 cx.open_window(WindowOptions::default(), |_, cx| {
166 cx.new(|_| HelloWorld {
167 open: false,
168 secondary_open: false,
169 })
170 })
171 .unwrap();
172 cx.activate(true);
173 });
174}