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