use super::*;
use crate::abi;
use crate::resolve;
use core::ffi::c_void;
use crate::mangle;
use crate::mangle::swift_type;
mangle::result_types! {
pub(crate) BUTTON_T = ty("Button").of(vec![ty("Text")]);
pub(crate) BUTTON_LABEL_T = ty("Button").of(vec![ty("AnyView")]);
}
pub(crate) unsafe extern "C" fn invoke_action(_out: *mut u8, payload: *mut c_void) {
let f = unsafe { boxed_ref::<dyn Fn()>(payload) };
f();
}
swift_statics! {
pub enum ButtonRole {
Destructive = c"$s7SwiftUI10ButtonRoleV11destructiveACvgZ",
Cancel = c"$s7SwiftUI10ButtonRoleV6cancelACvgZ",
Confirm = c"$s7SwiftUI10ButtonRoleV7confirmACvgZ",
Close = c"$s7SwiftUI10ButtonRoleV5closeACvgZ",
}
}
pub fn button_role(
label: &str,
role: Option<ButtonRole>,
callback: impl Fn() + 'static,
) -> ViewHandle {
unsafe {
let ss = abi::swift_string(label);
let s0 = u64::from_le_bytes(ss[..8].try_into().expect("lo"));
let s1 = u64::from_le_bytes(ss[8..].try_into().expect("hi"));
let (k0, k1, k2, k3) = localized_string_key(s0, s1);
let boxed: Box<dyn Fn()> = Box::new(callback);
let payload = Box::into_raw(Box::new(boxed)) as *mut c_void;
let ctx = Box::leak(Box::new(abi::ClosureCtx::new(run_boxed_action, payload)))
as *mut abi::ClosureCtx;
let role_meta = abi::metadata0(resolve::button_role_ma());
assert!(!role_meta.is_null(), "ButtonRole metadata");
let value = role.map(|r| {
super::static_getter_indirect(r.resolved(), role_meta, abi::type_bytes(role_meta))
});
let mut arg = super::opt_resilient_bytes(
role_meta,
swift_type!(opt SwiftUI.ButtonRole).as_bytes(),
value.as_deref(),
);
let (meta, wt, size) = result_type(&BUTTON_T);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::button_role_init(),
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") arg.as_mut_ptr(),
in("x5") abi::swift_closure_thunk as *const c_void,
in("x6") ctx,
in("x8") result.as_mut_ptr(),
in("x20") meta,
lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _,
lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn button(label: &str, callback: impl Fn() + 'static) -> ViewHandle {
unsafe {
let ss = abi::swift_string(label);
let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
let (k0, k1, k2, k3) = localized_string_key(s0, s1);
let boxed: Box<dyn Fn()> = Box::new(callback);
let payload = Box::into_raw(Box::new(boxed)) as *mut c_void;
let ctx = Box::leak(Box::new(abi::ClosureCtx::new(run_boxed_action, payload)))
as *mut abi::ClosureCtx;
let (meta, wt, size) = result_type(&BUTTON_T);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::button_init(),
in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
in("x4") abi::swift_closure_thunk as *const c_void,
in("x5") ctx,
in("x8") result.as_mut_ptr(),
in("x20") meta,
lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _,
lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn button_raw(
label: &str,
_callback: unsafe extern "C" fn(*mut c_void),
_userdata: *mut c_void,
) -> ViewHandle {
text(label)
}
pub fn scroll(view: &ViewHandle) -> ViewHandle {
unsafe {
let content_meta = view.meta;
let content_wt = view.wt;
let sv_meta = abi::generic_metadata2(resolve::scrollview_ma(), content_meta, content_wt);
assert!(!sv_meta.is_null(), "ScrollView metadata");
let sv_wt = abi::get_view_wt(sv_meta);
assert!(!sv_wt.is_null(), "ScrollView !: View");
let child = view.clone();
let kid_handles = Child::new(&child, Content::Concrete);
let handles = kid_handles.element();
let payload = TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx = abi::ClosureCtx::new(emit_tuple, &payload as *const TuplePayload as *mut c_void);
let mut result = vec![0u8; abi::type_bytes(sv_meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::scrollview_init(),
in("x0") 2u64,
in("x1") 1u64,
in("x2") abi::swift_closure_thunk as *const c_void,
in("x3") &mut ctx as *mut abi::ClosureCtx,
in("x4") content_meta,
in("x5") content_wt,
in("x8") result.as_mut_ptr(),
lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _,
lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
lateout("x16") _, lateout("x17") _, lateout("lr") _,
lateout("x20") _, lateout("x21") _,
clobber_abi("C"),
);
wrap_owned(result, sv_meta, sv_wt)
}
}
#[cfg(any(target_os = "macos", feature = "uikit-entry"))]
pub fn show_window(view: &ViewHandle, title: &str, width: f64, height: f64) {
crate::window::show_window(view, title, width, height);
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ProgressStyle {
Automatic,
Circular,
Linear,
}
impl ProgressStyle {
fn parts(self) -> (*const c_void, *const c_void, *const c_void) {
match self {
Self::Automatic => (
resolve::default_progress_ma(),
resolve::default_progress_init(),
resolve::default_progress_wt(),
),
Self::Circular => (
resolve::circular_progress_ma(),
resolve::circular_progress_init(),
resolve::circular_progress_wt(),
),
Self::Linear => (
resolve::linear_progress_ma(),
resolve::linear_progress_init(),
resolve::linear_progress_wt(),
),
}
}
}
pub fn progress_view_style(view: &ViewHandle, style: ProgressStyle) -> ViewHandle {
unsafe {
let (ma, init, wt) = style.parts();
let style_meta = abi::metadata0(ma);
assert!(!style_meta.is_null(), "ProgressViewStyle metadata");
let mut style_buf = vec![0u8; abi::type_bytes(style_meta)];
core::arch::asm!("blr {f}", f = in(reg) init,
in("x8") style_buf.as_mut_ptr(),
in("x20") style_meta,
lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
let subst = [view.meta, style_meta, view.wt, wt];
let (meta, rwt, size) =
super::opaque_result_type(resolve::progress_view_style_oret(), &subst);
let mut result = vec![0u8; size];
let this = view.value_ptr();
core::arch::asm!("blr {f}", f = in(reg) resolve::progress_view_style_fn(),
in("x0") style_buf.as_mut_ptr(),
in("x1") subst[0], in("x2") subst[1], in("x3") subst[2], in("x4") subst[3],
in("x8") result.as_mut_ptr(),
in("x20") this,
lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
wrap_owned(result, meta, rwt)
}
}
pub fn progress_view_style_circular(view: &ViewHandle) -> ViewHandle {
progress_view_style(view, ProgressStyle::Circular)
}
pub fn button_style_glass_clear(view: &ViewHandle) -> ViewHandle {
unsafe {
let glass_meta = abi::metadata0(resolve::glass_ma());
assert!(!glass_meta.is_null(), "Glass metadata");
let mut glass = super::static_getter_indirect(
resolve::glass_clear(),
glass_meta,
abi::type_bytes(glass_meta),
);
let style_meta = abi::metadata0(resolve::glass_button_style_ma());
assert!(!style_meta.is_null(), "GlassButtonStyle metadata");
let mut style = vec![0u8; abi::type_bytes(style_meta)];
core::arch::asm!("blr {f}", f = in(reg) resolve::glass_button_style_of(),
in("x0") glass.as_mut_ptr(),
in("x8") style.as_mut_ptr(),
in("x20") style_meta,
lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
let style_wt = resolve::glass_button_style_wt();
let subst = [view.meta, style_meta, view.wt, style_wt];
let (meta, wt, size) = super::opaque_result_type(resolve::button_style_oret(), &subst);
let mut result = vec![0u8; size];
let this = view.value_ptr();
core::arch::asm!("blr {f}", f = in(reg) resolve::button_style_fn(),
in("x0") style.as_mut_ptr(),
in("x1") subst[0], in("x2") subst[1], in("x3") subst[2], in("x4") subst[3],
in("x8") result.as_mut_ptr(),
in("x20") this,
lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub fn button_labelled(label: &ViewHandle, action: impl Fn() + 'static) -> ViewHandle {
unsafe {
let boxed: Box<dyn Fn()> = Box::new(action);
let payload = Box::into_raw(Box::new(boxed)) as *mut c_void;
let act = Box::leak(Box::new(abi::ClosureCtx::new(run_boxed_action, payload)))
as *mut abi::ClosureCtx;
let (known_meta, known_wt, known_size) = result_type(&BUTTON_LABEL_T);
let typed = super::substitute_content(known_meta, 2, 0, 1, label.meta, label.wt);
let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
let (label_meta, label_wt) = match typed {
Some(_) => (label.meta, label.wt),
None => (resolve::anyview_meta(), resolve::anyview_wt()),
};
let kind = if typed.is_some() { super::Content::Concrete } else { super::Content::Erased };
let kid_handles = super::Child::new(label, kind);
let handles = kid_handles.element();
let tuple = super::TuplePayload { children: handles.as_ptr(), count: 1 };
let mut ctx = abi::ClosureCtx::new(
super::emit_tuple,
&tuple as *const super::TuplePayload as *mut c_void,
);
let mut result = vec![0u8; size];
core::arch::asm!("blr {f}", f = in(reg) resolve::button_label_init(),
in("x0") abi::swift_closure_thunk as *const c_void,
in("x1") act,
in("x2") abi::swift_closure_thunk as *const c_void,
in("x3") &mut ctx as *mut abi::ClosureCtx,
in("x4") label_meta,
in("x5") label_wt,
in("x8") result.as_mut_ptr(),
lateout("x6") _, lateout("x7") _, lateout("x9") _, lateout("x10") _,
lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
lateout("x20") _, lateout("x21") _, clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub(crate) unsafe extern "C" fn run_boxed_action(_out: *mut u8, payload: *mut c_void) {
unsafe { (*(payload as *const Box<dyn Fn()>))() };
}