window.rs

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