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