popover.rs

  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}