window.rs

  1use gpui::{
  2    App, Application, Bounds, Context, KeyBinding, SharedString, Timer, Window, WindowBounds,
  3    WindowKind, WindowOptions, actions, div, prelude::*, px, rgb, size,
  4};
  5
  6struct SubWindow {
  7    custom_titlebar: bool,
  8}
  9
 10fn button(text: &str, on_click: impl Fn(&mut Window, &mut App) + 'static) -> impl IntoElement {
 11    div()
 12        .id(SharedString::from(text.to_string()))
 13        .flex_none()
 14        .px_2()
 15        .bg(rgb(0xf7f7f7))
 16        .active(|this| this.opacity(0.85))
 17        .border_1()
 18        .border_color(rgb(0xe0e0e0))
 19        .rounded_sm()
 20        .cursor_pointer()
 21        .child(text.to_string())
 22        .on_click(move |_, window, cx| on_click(window, cx))
 23}
 24
 25impl Render for SubWindow {
 26    fn render(&mut self, _window: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
 27        div()
 28            .flex()
 29            .flex_col()
 30            .bg(rgb(0xffffff))
 31            .size_full()
 32            .gap_2()
 33            .when(self.custom_titlebar, |cx| {
 34                cx.child(
 35                    div()
 36                        .flex()
 37                        .h(px(32.))
 38                        .px_4()
 39                        .bg(gpui::blue())
 40                        .text_color(gpui::white())
 41                        .w_full()
 42                        .child(
 43                            div()
 44                                .flex()
 45                                .items_center()
 46                                .justify_center()
 47                                .size_full()
 48                                .child("Custom Titlebar"),
 49                        ),
 50                )
 51            })
 52            .child(
 53                div()
 54                    .p_8()
 55                    .gap_2()
 56                    .child("SubWindow")
 57                    .child(button("Close", |window, _| {
 58                        window.remove_window();
 59                    })),
 60            )
 61    }
 62}
 63
 64struct WindowDemo {}
 65
 66impl Render for WindowDemo {
 67    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 68        let window_bounds =
 69            WindowBounds::Windowed(Bounds::centered(None, size(px(300.0), px(300.0)), cx));
 70
 71        div()
 72            .p_4()
 73            .flex()
 74            .flex_wrap()
 75            .bg(rgb(0xffffff))
 76            .size_full()
 77            .justify_center()
 78            .content_center()
 79            .gap_2()
 80            .child(button("Normal", move |_, cx| {
 81                cx.open_window(
 82                    WindowOptions {
 83                        window_bounds: Some(window_bounds),
 84                        ..Default::default()
 85                    },
 86                    |_, cx| {
 87                        cx.new(|_| SubWindow {
 88                            custom_titlebar: false,
 89                        })
 90                    },
 91                )
 92                .unwrap();
 93            }))
 94            .child(button("Popup", move |_, cx| {
 95                cx.open_window(
 96                    WindowOptions {
 97                        window_bounds: Some(window_bounds),
 98                        kind: WindowKind::PopUp,
 99                        ..Default::default()
100                    },
101                    |_, cx| {
102                        cx.new(|_| SubWindow {
103                            custom_titlebar: false,
104                        })
105                    },
106                )
107                .unwrap();
108            }))
109            .child(button("Custom Titlebar", move |_, cx| {
110                cx.open_window(
111                    WindowOptions {
112                        titlebar: None,
113                        window_bounds: Some(window_bounds),
114                        ..Default::default()
115                    },
116                    |_, cx| {
117                        cx.new(|_| SubWindow {
118                            custom_titlebar: true,
119                        })
120                    },
121                )
122                .unwrap();
123            }))
124            .child(button("Invisible", move |_, cx| {
125                cx.open_window(
126                    WindowOptions {
127                        show: false,
128                        window_bounds: Some(window_bounds),
129                        ..Default::default()
130                    },
131                    |_, cx| {
132                        cx.new(|_| SubWindow {
133                            custom_titlebar: false,
134                        })
135                    },
136                )
137                .unwrap();
138            }))
139            .child(button("Unmovable", move |_, cx| {
140                cx.open_window(
141                    WindowOptions {
142                        is_movable: false,
143                        titlebar: None,
144                        window_bounds: Some(window_bounds),
145                        ..Default::default()
146                    },
147                    |_, cx| {
148                        cx.new(|_| SubWindow {
149                            custom_titlebar: false,
150                        })
151                    },
152                )
153                .unwrap();
154            }))
155            .child(button("Hide Application", |window, cx| {
156                cx.hide();
157
158                // Restore the application after 3 seconds
159                window
160                    .spawn(cx, async move |cx| {
161                        Timer::after(std::time::Duration::from_secs(3)).await;
162                        cx.update(|_, cx| {
163                            cx.activate(false);
164                        })
165                    })
166                    .detach();
167            }))
168            .child(button("Resize", |window, _| {
169                let content_size = window.bounds().size;
170                window.resize(size(content_size.height, content_size.width));
171            }))
172    }
173}
174
175actions!(window, [Quit]);
176
177fn main() {
178    Application::new().run(|cx: &mut App| {
179        let bounds = Bounds::centered(None, size(px(800.0), px(600.0)), cx);
180
181        cx.open_window(
182            WindowOptions {
183                window_bounds: Some(WindowBounds::Windowed(bounds)),
184                ..Default::default()
185            },
186            |window, cx| {
187                cx.new(|cx| {
188                    cx.observe_window_bounds(window, move |_, window, _| {
189                        println!("Window bounds changed: {:?}", window.bounds());
190                    })
191                    .detach();
192
193                    WindowDemo {}
194                })
195            },
196        )
197        .unwrap();
198        cx.activate(true);
199        cx.on_action(|_: &Quit, cx| cx.quit());
200        cx.bind_keys([KeyBinding::new("cmd-q", Quit, None)]);
201    });
202}