window.rs

  1use gpui::{
  2    App, Application, Bounds, Context, KeyBinding, PromptButton, PromptLevel, SharedString, Timer,
  3    Window, WindowBounds, 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("Unresizable", move |_, cx| {
156                cx.open_window(
157                    WindowOptions {
158                        is_resizable: false,
159                        window_bounds: Some(window_bounds),
160                        ..Default::default()
161                    },
162                    |_, cx| {
163                        cx.new(|_| SubWindow {
164                            custom_titlebar: false,
165                        })
166                    },
167                )
168                .unwrap();
169            }))
170            .child(button("Unminimizable", move |_, cx| {
171                cx.open_window(
172                    WindowOptions {
173                        is_minimizable: false,
174                        window_bounds: Some(window_bounds),
175                        ..Default::default()
176                    },
177                    |_, cx| {
178                        cx.new(|_| SubWindow {
179                            custom_titlebar: false,
180                        })
181                    },
182                )
183                .unwrap();
184            }))
185            .child(button("Hide Application", |window, cx| {
186                cx.hide();
187
188                // Restore the application after 3 seconds
189                window
190                    .spawn(cx, async move |cx| {
191                        Timer::after(std::time::Duration::from_secs(3)).await;
192                        cx.update(|_, cx| {
193                            cx.activate(false);
194                        })
195                    })
196                    .detach();
197            }))
198            .child(button("Resize", |window, _| {
199                let content_size = window.bounds().size;
200                window.resize(size(content_size.height, content_size.width));
201            }))
202            .child(button("Prompt", |window, cx| {
203                let answer = window.prompt(
204                    PromptLevel::Info,
205                    "Are you sure?",
206                    None,
207                    &["Ok", "Cancel"],
208                    cx,
209                );
210
211                cx.spawn(async move |_| {
212                    if answer.await.unwrap() == 0 {
213                        println!("You have clicked Ok");
214                    } else {
215                        println!("You have clicked Cancel");
216                    }
217                })
218                .detach();
219            }))
220            .child(button("Prompt (non-English)", |window, cx| {
221                let answer = window.prompt(
222                    PromptLevel::Info,
223                    "Are you sure?",
224                    None,
225                    &[PromptButton::ok("确定"), PromptButton::cancel("取消")],
226                    cx,
227                );
228
229                cx.spawn(async move |_| {
230                    if answer.await.unwrap() == 0 {
231                        println!("You have clicked Ok");
232                    } else {
233                        println!("You have clicked Cancel");
234                    }
235                })
236                .detach();
237            }))
238    }
239}
240
241actions!(window, [Quit]);
242
243fn main() {
244    Application::new().run(|cx: &mut App| {
245        let bounds = Bounds::centered(None, size(px(800.0), px(600.0)), cx);
246
247        cx.open_window(
248            WindowOptions {
249                window_bounds: Some(WindowBounds::Windowed(bounds)),
250                ..Default::default()
251            },
252            |window, cx| {
253                cx.new(|cx| {
254                    cx.observe_window_bounds(window, move |_, window, _| {
255                        println!("Window bounds changed: {:?}", window.bounds());
256                    })
257                    .detach();
258
259                    WindowDemo {}
260                })
261            },
262        )
263        .unwrap();
264
265        cx.activate(true);
266        cx.on_action(|_: &Quit, cx| cx.quit());
267        cx.bind_keys([KeyBinding::new("cmd-q", Quit, None)]);
268    });
269}