1use super::*;
7use crate::abi;
8use crate::resolve;
9use core::ffi::c_void;
10use crate::mangle;
11use crate::mangle::swift_type;
12
13mangle::result_types! {
16 pub(crate) BUTTON_T = ty("Button").of(vec![ty("Text")]);
19 pub(crate) BUTTON_LABEL_T = ty("Button").of(vec![ty("AnyView")]);
22}
23
24pub(crate) unsafe extern "C" fn invoke_action(_out: *mut u8, payload: *mut c_void) {
26 let f = unsafe { boxed_ref::<dyn Fn()>(payload) };
27 f();
28}
29
30swift_statics! {
31 pub enum ButtonRole {
38 Destructive = c"$s7SwiftUI10ButtonRoleV11destructiveACvgZ",
39 Cancel = c"$s7SwiftUI10ButtonRoleV6cancelACvgZ",
40 Confirm = c"$s7SwiftUI10ButtonRoleV7confirmACvgZ",
41 Close = c"$s7SwiftUI10ButtonRoleV5closeACvgZ",
42 }
43}
44
45pub fn button_role(
50 label: &str,
51 role: Option<ButtonRole>,
52 callback: impl Fn() + 'static,
53) -> ViewHandle {
54 unsafe {
55 let ss = abi::swift_string(label);
56 let s0 = u64::from_le_bytes(ss[..8].try_into().expect("lo"));
57 let s1 = u64::from_le_bytes(ss[8..].try_into().expect("hi"));
58 let (k0, k1, k2, k3) = localized_string_key(s0, s1);
59
60 let boxed: Box<dyn Fn()> = Box::new(callback);
61 let payload = Box::into_raw(Box::new(boxed)) as *mut c_void;
62 let ctx = Box::leak(Box::new(abi::ClosureCtx::new(run_boxed_action, payload)))
63 as *mut abi::ClosureCtx;
64
65 let role_meta = abi::metadata0(resolve::button_role_ma());
67 assert!(!role_meta.is_null(), "ButtonRole metadata");
68 let value = role.map(|r| {
69 super::static_getter_indirect(r.resolved(), role_meta, abi::type_bytes(role_meta))
70 });
71 let mut arg = super::opt_resilient_bytes(
72 role_meta,
73 swift_type!(opt SwiftUI.ButtonRole).as_bytes(),
74 value.as_deref(),
75 );
76
77 let (meta, wt, size) = result_type(&BUTTON_T);
78 let mut result = vec![0u8; size];
79 core::arch::asm!("blr {f}", f = in(reg) resolve::button_role_init(),
83 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
84 in("x4") arg.as_mut_ptr(),
85 in("x5") abi::swift_closure_thunk as *const c_void,
86 in("x6") ctx,
87 in("x8") result.as_mut_ptr(),
88 in("x20") meta,
89 lateout("x7") _,
90 lateout("x9") _, lateout("x10") _, lateout("x11") _,
91 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
92 lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x21") _,
93 clobber_abi("C"),
94 );
95 wrap_owned(result, meta, wt)
96 }
97}
98
99pub fn button(label: &str, callback: impl Fn() + 'static) -> ViewHandle {
107 unsafe {
108 let ss = abi::swift_string(label);
109 let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
110 let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
111 let (k0, k1, k2, k3) = localized_string_key(s0, s1);
112
113 let boxed: Box<dyn Fn()> = Box::new(callback);
116 let payload = Box::into_raw(Box::new(boxed)) as *mut c_void;
117 let ctx = Box::leak(Box::new(abi::ClosureCtx::new(run_boxed_action, payload)))
118 as *mut abi::ClosureCtx;
119
120 let (meta, wt, size) = result_type(&BUTTON_T);
121 let mut result = vec![0u8; size];
122 core::arch::asm!("blr {f}", f = in(reg) resolve::button_init(),
125 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
126 in("x4") abi::swift_closure_thunk as *const c_void,
127 in("x5") ctx,
128 in("x8") result.as_mut_ptr(),
129 in("x20") meta,
130 lateout("x6") _, lateout("x7") _,
131 lateout("x9") _, lateout("x10") _, lateout("x11") _,
132 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
133 lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x21") _,
134 clobber_abi("C"),
135 );
136 wrap_owned(result, meta, wt)
137 }
138}
139
140pub fn button_raw(
142 label: &str,
143 _callback: unsafe extern "C" fn(*mut c_void),
144 _userdata: *mut c_void,
145) -> ViewHandle {
146 text(label)
147}
148
149pub fn scroll(view: &ViewHandle) -> ViewHandle {
153 unsafe {
154 let content_meta = view.meta;
157 let content_wt = view.wt;
158 let sv_meta = abi::generic_metadata2(resolve::scrollview_ma(), content_meta, content_wt);
159 assert!(!sv_meta.is_null(), "ScrollView metadata");
160 let sv_wt = abi::get_view_wt(sv_meta);
161 assert!(!sv_wt.is_null(), "ScrollView !: View");
162
163 let child = view.clone();
164 let kid_handles = Child::new(&child, Content::Concrete);
165 let handles = kid_handles.element();
166 let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
167 let mut ctx = abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
168
169 let mut result = vec![0u8; abi::type_bytes(sv_meta)];
170 core::arch::asm!("blr {f}", f = in(reg) resolve::scrollview_init(),
175 in("x0") 2u64,
176 in("x1") 1u64,
177 in("x2") abi::swift_closure_thunk as *const c_void,
178 in("x3") &mut ctx as *mut abi::ClosureCtx,
179 in("x4") content_meta,
180 in("x5") content_wt,
181 in("x8") result.as_mut_ptr(),
182 lateout("x6") _, lateout("x7") _,
183 lateout("x9") _, lateout("x10") _, lateout("x11") _,
184 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
185 lateout("x16") _, lateout("x17") _, lateout("lr") _,
186 lateout("x20") _, lateout("x21") _,
187 clobber_abi("C"),
188 );
189 wrap_owned(result, sv_meta, sv_wt)
190 }
191}
192
193#[cfg(any(target_os = "macos", feature = "uikit-entry"))]
201pub fn show_window(view: &ViewHandle, title: &str, width: f64, height: f64) {
202 crate::window::show_window(view, title, width, height);
203}
204
205#[derive(Clone, Copy, Debug, PartialEq, Eq)]
210pub enum ProgressStyle {
211 Automatic,
213 Circular,
215 Linear,
217}
218
219impl ProgressStyle {
220 fn parts(self) -> (*const c_void, *const c_void, *const c_void) {
223 match self {
224 Self::Automatic => (
225 resolve::default_progress_ma(),
226 resolve::default_progress_init(),
227 resolve::default_progress_wt(),
228 ),
229 Self::Circular => (
230 resolve::circular_progress_ma(),
231 resolve::circular_progress_init(),
232 resolve::circular_progress_wt(),
233 ),
234 Self::Linear => (
235 resolve::linear_progress_ma(),
236 resolve::linear_progress_init(),
237 resolve::linear_progress_wt(),
238 ),
239 }
240 }
241}
242
243pub fn progress_view_style(view: &ViewHandle, style: ProgressStyle) -> ViewHandle {
255 unsafe {
256 let (ma, init, wt) = style.parts();
257 let style_meta = abi::metadata0(ma);
258 assert!(!style_meta.is_null(), "ProgressViewStyle metadata");
259 let mut style_buf = vec![0u8; abi::type_bytes(style_meta)];
260 core::arch::asm!("blr {f}", f = in(reg) init,
261 in("x8") style_buf.as_mut_ptr(),
262 in("x20") style_meta,
263 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
264 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
265 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
266 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
267 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
268 );
269
270 let subst = [view.meta, style_meta, view.wt, wt];
271 let (meta, rwt, size) =
272 super::opaque_result_type(resolve::progress_view_style_oret(), &subst);
273
274 let mut result = vec![0u8; size];
275 let this = view.value_ptr();
276 core::arch::asm!("blr {f}", f = in(reg) resolve::progress_view_style_fn(),
279 in("x0") style_buf.as_mut_ptr(),
280 in("x1") subst[0], in("x2") subst[1], in("x3") subst[2], in("x4") subst[3],
281 in("x8") result.as_mut_ptr(),
282 in("x20") this,
283 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
284 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
285 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
286 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
287 );
288 wrap_owned(result, meta, rwt)
289 }
290}
291
292pub fn progress_view_style_circular(view: &ViewHandle) -> ViewHandle {
294 progress_view_style(view, ProgressStyle::Circular)
295}
296
297pub fn button_style_glass_clear(view: &ViewHandle) -> ViewHandle {
303 unsafe {
304 let glass_meta = abi::metadata0(resolve::glass_ma());
305 assert!(!glass_meta.is_null(), "Glass metadata");
306 let mut glass = super::static_getter_indirect(
307 resolve::glass_clear(),
308 glass_meta,
309 abi::type_bytes(glass_meta),
310 );
311
312 let style_meta = abi::metadata0(resolve::glass_button_style_ma());
313 assert!(!style_meta.is_null(), "GlassButtonStyle metadata");
314 let mut style = vec![0u8; abi::type_bytes(style_meta)];
315 core::arch::asm!("blr {f}", f = in(reg) resolve::glass_button_style_of(),
316 in("x0") glass.as_mut_ptr(),
317 in("x8") style.as_mut_ptr(),
318 in("x20") style_meta,
319 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
320 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
321 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
322 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
323 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
324 );
325
326 let style_wt = resolve::glass_button_style_wt();
327 let subst = [view.meta, style_meta, view.wt, style_wt];
328 let (meta, wt, size) = super::opaque_result_type(resolve::button_style_oret(), &subst);
329 let mut result = vec![0u8; size];
330 let this = view.value_ptr();
331 core::arch::asm!("blr {f}", f = in(reg) resolve::button_style_fn(),
332 in("x0") style.as_mut_ptr(),
333 in("x1") subst[0], in("x2") subst[1], in("x3") subst[2], in("x4") subst[3],
334 in("x8") result.as_mut_ptr(),
335 in("x20") this,
336 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
337 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
338 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
339 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
340 );
341 wrap_owned(result, meta, wt)
342 }
343}
344
345pub fn button_labelled(label: &ViewHandle, action: impl Fn() + 'static) -> ViewHandle {
351 unsafe {
352 let boxed: Box<dyn Fn()> = Box::new(action);
353 let payload = Box::into_raw(Box::new(boxed)) as *mut c_void;
354 let act = Box::leak(Box::new(abi::ClosureCtx::new(run_boxed_action, payload)))
355 as *mut abi::ClosureCtx;
356
357 let (known_meta, known_wt, known_size) = result_type(&BUTTON_LABEL_T);
358 let typed = super::substitute_content(known_meta, 2, 0, 1, label.meta, label.wt);
360 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
361 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
362 let (label_meta, label_wt) = match typed {
363 Some(_) => (label.meta, label.wt),
364 None => (resolve::anyview_meta(), resolve::anyview_wt()),
365 };
366 let kind = if typed.is_some() { super::Content::Concrete } else { super::Content::Erased };
367
368 let kid_handles = super::Child::new(label, kind);
369 let handles = kid_handles.element();
370 let tuple = super::TuplePayload { children: handles.as_ptr(), count: 1 };
371 let mut ctx = abi::ClosureCtx::new(
372 super::emit_tuple,
373 &tuple as *const super::TuplePayload as *mut c_void,
374 );
375
376 let mut result = vec![0u8; size];
377 core::arch::asm!("blr {f}", f = in(reg) resolve::button_label_init(),
381 in("x0") abi::swift_closure_thunk as *const c_void,
382 in("x1") act,
383 in("x2") abi::swift_closure_thunk as *const c_void,
384 in("x3") &mut ctx as *mut abi::ClosureCtx,
385 in("x4") label_meta,
386 in("x5") label_wt,
387 in("x8") result.as_mut_ptr(),
388 lateout("x6") _, lateout("x7") _, lateout("x9") _, lateout("x10") _,
389 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
390 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
391 lateout("x20") _, lateout("x21") _, clobber_abi("C"),
392 );
393 wrap_owned(result, meta, wt)
394 }
395}
396
397pub(crate) unsafe extern "C" fn run_boxed_action(_out: *mut u8, payload: *mut c_void) {
403 unsafe { (*(payload as *const Box<dyn Fn()>))() };
404}