window.rs

  1use gpui::{
  2    App, Application, Bounds, Context, KeyBinding, PromptButton, PromptLevel, Window, WindowBounds,
  3    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                        cx.background_executor()
255                            .timer(std::time::Duration::from_secs(3))
256                            .await;
257                        cx.update(|_, cx| {
258                            cx.activate(false);
259                        })
260                    })
261                    .detach();
262            }))
263            .child(button("Resize", |window, _| {
264                let content_size = window.bounds().size;
265                window.resize(size(content_size.height, content_size.width));
266            }))
267            .child(button("Prompt", |window, cx| {
268                let answer = window.prompt(
269                    PromptLevel::Info,
270                    "Are you sure?",
271                    None,
272                    &["Ok", "Cancel"],
273                    cx,
274                );
275
276                cx.spawn(async move |_| {
277                    if answer.await.unwrap() == 0 {
278                        println!("You have clicked Ok");
279                    } else {
280                        println!("You have clicked Cancel");
281                    }
282                })
283                .detach();
284            }))
285            .child(button("Prompt (non-English)", |window, cx| {
286                let answer = window.prompt(
287                    PromptLevel::Info,
288                    "Are you sure?",
289                    None,
290                    &[PromptButton::ok("确定"), PromptButton::cancel("取消")],
291                    cx,
292                );
293
294                cx.spawn(async move |_| {
295                    if answer.await.unwrap() == 0 {
296                        println!("You have clicked Ok");
297                    } else {
298                        println!("You have clicked Cancel");
299                    }
300                })
301                .detach();
302            }))
303    }
304}
305
306actions!(window, [Quit]);
307
308fn main() {
309    Application::new().run(|cx: &mut App| {
310        let bounds = Bounds::centered(None, size(px(800.0), px(600.0)), cx);
311
312        cx.open_window(
313            WindowOptions {
314                window_bounds: Some(WindowBounds::Windowed(bounds)),
315                ..Default::default()
316            },
317            |window, cx| {
318                cx.new(|cx| {
319                    cx.observe_window_bounds(window, move |_, window, _| {
320                        println!("Window bounds changed: {:?}", window.bounds());
321                    })
322                    .detach();
323
324                    WindowDemo {}
325                })
326            },
327        )
328        .unwrap();
329
330        cx.activate(true);
331        cx.on_action(|_: &Quit, cx| cx.quit());
332        cx.bind_keys([KeyBinding::new("cmd-q", Quit, None)]);
333    });
334}