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}