window.rs

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