window.rs

  1#![cfg_attr(target_family = "wasm", no_main)]
  2
  3use gpui::{
  4    App, Bounds, Context, KeyBinding, PromptButton, PromptLevel, Window, WindowBounds, WindowKind,
  5    WindowOptions, actions, div, prelude::*, px, rgb, size,
  6};
  7use gpui_platform::application;
  8
  9struct SubWindow {
 10    custom_titlebar: bool,
 11    is_dialog: bool,
 12}
 13
 14fn button(text: &str, on_click: impl Fn(&mut Window, &mut App) + 'static) -> impl IntoElement {
 15    div()
 16        .id(text.to_string())
 17        .flex_none()
 18        .px_2()
 19        .bg(rgb(0xf7f7f7))
 20        .active(|this| this.opacity(0.85))
 21        .border_1()
 22        .border_color(rgb(0xe0e0e0))
 23        .rounded_sm()
 24        .cursor_pointer()
 25        .child(text.to_string())
 26        .on_click(move |_, window, cx| on_click(window, cx))
 27}
 28
 29impl Render for SubWindow {
 30    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 31        let window_bounds =
 32            WindowBounds::Windowed(Bounds::centered(None, size(px(250.0), px(200.0)), cx));
 33
 34        div()
 35            .flex()
 36            .flex_col()
 37            .bg(rgb(0xffffff))
 38            .size_full()
 39            .gap_2()
 40            .when(self.custom_titlebar, |cx| {
 41                cx.child(
 42                    div()
 43                        .flex()
 44                        .h(px(32.))
 45                        .px_4()
 46                        .bg(gpui::blue())
 47                        .text_color(gpui::white())
 48                        .w_full()
 49                        .child(
 50                            div()
 51                                .flex()
 52                                .items_center()
 53                                .justify_center()
 54                                .size_full()
 55                                .child("Custom Titlebar"),
 56                        ),
 57                )
 58            })
 59            .child(
 60                div()
 61                    .p_8()
 62                    .flex()
 63                    .flex_col()
 64                    .gap_2()
 65                    .child("SubWindow")
 66                    .when(self.is_dialog, |div| {
 67                        div.child(button("Open Nested Dialog", move |_, cx| {
 68                            cx.open_window(
 69                                WindowOptions {
 70                                    window_bounds: Some(window_bounds),
 71                                    kind: WindowKind::Dialog,
 72                                    ..Default::default()
 73                                },
 74                                |_, cx| {
 75                                    cx.new(|_| SubWindow {
 76                                        custom_titlebar: false,
 77                                        is_dialog: true,
 78                                    })
 79                                },
 80                            )
 81                            .unwrap();
 82                        }))
 83                    })
 84                    .child(button("Close", |window, _| {
 85                        window.remove_window();
 86                    })),
 87            )
 88    }
 89}
 90
 91struct WindowDemo {}
 92
 93impl Render for WindowDemo {
 94    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 95        let window_bounds =
 96            WindowBounds::Windowed(Bounds::centered(None, size(px(300.0), px(300.0)), cx));
 97
 98        div()
 99            .p_4()
100            .flex()
101            .flex_wrap()
102            .bg(rgb(0xffffff))
103            .size_full()
104            .justify_center()
105            .content_center()
106            .gap_2()
107            .child(button("Normal", move |_, cx| {
108                cx.open_window(
109                    WindowOptions {
110                        window_bounds: Some(window_bounds),
111                        ..Default::default()
112                    },
113                    |_, cx| {
114                        cx.new(|_| SubWindow {
115                            custom_titlebar: false,
116                            is_dialog: false,
117                        })
118                    },
119                )
120                .unwrap();
121            }))
122            .child(button("Popup", move |_, cx| {
123                cx.open_window(
124                    WindowOptions {
125                        window_bounds: Some(window_bounds),
126                        kind: WindowKind::PopUp,
127                        ..Default::default()
128                    },
129                    |_, cx| {
130                        cx.new(|_| SubWindow {
131                            custom_titlebar: false,
132                            is_dialog: false,
133                        })
134                    },
135                )
136                .unwrap();
137            }))
138            .child(button("Floating", move |_, cx| {
139                cx.open_window(
140                    WindowOptions {
141                        window_bounds: Some(window_bounds),
142                        kind: WindowKind::Floating,
143                        ..Default::default()
144                    },
145                    |_, cx| {
146                        cx.new(|_| SubWindow {
147                            custom_titlebar: false,
148                            is_dialog: false,
149                        })
150                    },
151                )
152                .unwrap();
153            }))
154            .child(button("Dialog", move |_, cx| {
155                cx.open_window(
156                    WindowOptions {
157                        window_bounds: Some(window_bounds),
158                        kind: WindowKind::Dialog,
159                        ..Default::default()
160                    },
161                    |_, cx| {
162                        cx.new(|_| SubWindow {
163                            custom_titlebar: false,
164                            is_dialog: true,
165                        })
166                    },
167                )
168                .unwrap();
169            }))
170            .child(button("Custom Titlebar", move |_, cx| {
171                cx.open_window(
172                    WindowOptions {
173                        titlebar: None,
174                        window_bounds: Some(window_bounds),
175                        ..Default::default()
176                    },
177                    |_, cx| {
178                        cx.new(|_| SubWindow {
179                            custom_titlebar: true,
180                            is_dialog: false,
181                        })
182                    },
183                )
184                .unwrap();
185            }))
186            .child(button("Invisible", move |_, cx| {
187                cx.open_window(
188                    WindowOptions {
189                        show: false,
190                        window_bounds: Some(window_bounds),
191                        ..Default::default()
192                    },
193                    |_, cx| {
194                        cx.new(|_| SubWindow {
195                            custom_titlebar: false,
196                            is_dialog: false,
197                        })
198                    },
199                )
200                .unwrap();
201            }))
202            .child(button("Unmovable", move |_, cx| {
203                cx.open_window(
204                    WindowOptions {
205                        is_movable: false,
206                        titlebar: None,
207                        window_bounds: Some(window_bounds),
208                        ..Default::default()
209                    },
210                    |_, cx| {
211                        cx.new(|_| SubWindow {
212                            custom_titlebar: false,
213                            is_dialog: false,
214                        })
215                    },
216                )
217                .unwrap();
218            }))
219            .child(button("Unresizable", move |_, cx| {
220                cx.open_window(
221                    WindowOptions {
222                        is_resizable: false,
223                        window_bounds: Some(window_bounds),
224                        ..Default::default()
225                    },
226                    |_, cx| {
227                        cx.new(|_| SubWindow {
228                            custom_titlebar: false,
229                            is_dialog: false,
230                        })
231                    },
232                )
233                .unwrap();
234            }))
235            .child(button("Unminimizable", move |_, cx| {
236                cx.open_window(
237                    WindowOptions {
238                        is_minimizable: false,
239                        window_bounds: Some(window_bounds),
240                        ..Default::default()
241                    },
242                    |_, cx| {
243                        cx.new(|_| SubWindow {
244                            custom_titlebar: false,
245                            is_dialog: false,
246                        })
247                    },
248                )
249                .unwrap();
250            }))
251            .child(button("Hide Application", |window, cx| {
252                cx.hide();
253
254                // Restore the application after 3 seconds
255                window
256                    .spawn(cx, async move |cx| {
257                        cx.background_executor()
258                            .timer(std::time::Duration::from_secs(3))
259                            .await;
260                        cx.update(|_, cx| {
261                            cx.activate(false);
262                        })
263                    })
264                    .detach();
265            }))
266            .child(button("Resize", |window, _| {
267                let content_size = window.bounds().size;
268                window.resize(size(content_size.height, content_size.width));
269            }))
270            .child(button("Prompt", |window, cx| {
271                let answer = window.prompt(
272                    PromptLevel::Info,
273                    "Are you sure?",
274                    None,
275                    &["Ok", "Cancel"],
276                    cx,
277                );
278
279                cx.spawn(async move |_| {
280                    if answer.await.unwrap() == 0 {
281                        println!("You have clicked Ok");
282                    } else {
283                        println!("You have clicked Cancel");
284                    }
285                })
286                .detach();
287            }))
288            .child(button("Prompt (non-English)", |window, cx| {
289                let answer = window.prompt(
290                    PromptLevel::Info,
291                    "Are you sure?",
292                    None,
293                    &[PromptButton::ok("确定"), PromptButton::cancel("取消")],
294                    cx,
295                );
296
297                cx.spawn(async move |_| {
298                    if answer.await.unwrap() == 0 {
299                        println!("You have clicked Ok");
300                    } else {
301                        println!("You have clicked Cancel");
302                    }
303                })
304                .detach();
305            }))
306    }
307}
308
309actions!(window, [Quit]);
310
311fn run_example() {
312    application().run(|cx: &mut App| {
313        let bounds = Bounds::centered(None, size(px(800.0), px(600.0)), cx);
314
315        cx.open_window(
316            WindowOptions {
317                window_bounds: Some(WindowBounds::Windowed(bounds)),
318                ..Default::default()
319            },
320            |window, cx| {
321                cx.new(|cx| {
322                    cx.observe_window_bounds(window, move |_, window, _| {
323                        println!("Window bounds changed: {:?}", window.bounds());
324                    })
325                    .detach();
326
327                    WindowDemo {}
328                })
329            },
330        )
331        .unwrap();
332
333        cx.activate(true);
334        cx.on_action(|_: &Quit, cx| cx.quit());
335        cx.bind_keys([KeyBinding::new("cmd-q", Quit, None)]);
336    });
337}
338
339#[cfg(not(target_family = "wasm"))]
340fn main() {
341    run_example();
342}
343
344#[cfg(target_family = "wasm")]
345#[wasm_bindgen::prelude::wasm_bindgen(start)]
346pub fn start() {
347    gpui_platform::web_init();
348    run_example();
349}