use day_core::RNode;
use day_pieces::Decorate;
use objc2::MainThreadMarker;
use objc2::rc::Retained;
use objc2_app_kit::NSView;
pub fn with_native<R>(
node: RNode,
f: impl FnOnce(&Retained<NSView>, &str, MainThreadMarker) -> R,
) -> Option<R> {
let mtm = MainThreadMarker::new()?;
let h = day_core::with_tree(|t| t.node_handle_any(node))?
.downcast::<crate::Handle>()
.ok()?;
let class = h.class().name().to_str().unwrap_or("");
Some(f(&h, class, mtm))
}
pub fn with_native_subcontrol<R>(
node: RNode,
sub: day_spec::Subcontrol,
f: impl FnOnce(&Retained<NSView>, &str, MainThreadMarker) -> R,
) -> Option<R> {
with_native(node, |host, _class, mtm| {
let target: Option<Retained<NSView>> = match sub {
day_spec::Subcontrol::Host => Some(host.clone()),
day_spec::Subcontrol::Content => host
.downcast_ref::<objc2_app_kit::NSScrollView>()
.and_then(|sv| unsafe { sv.documentView() }),
day_spec::Subcontrol::Header => host
.downcast_ref::<objc2_app_kit::NSScrollView>()
.and_then(|sv| unsafe { sv.documentView() })
.and_then(|dv| dv.downcast::<objc2_app_kit::NSTableView>().ok())
.and_then(|tv| unsafe { tv.headerView() })
.map(|hv| unsafe { objc2::rc::Retained::cast_unchecked::<NSView>(hv) }),
};
target.map(|view| {
let class = view.class().name().to_str().unwrap_or("").to_owned();
f(&view, &class, mtm)
})
})
.flatten()
}
pub trait AppKitExt: Decorate + Sized {
fn appkit(
self,
f: impl FnOnce(&Retained<NSView>, &str, MainThreadMarker) + 'static,
) -> day_pieces::Decorated<Self> {
self.tweak(move |n| {
let _ = with_native(n, f);
})
}
fn appkit_subcontrol(
self,
sub: day_spec::Subcontrol,
f: impl FnOnce(&Retained<NSView>, &str, MainThreadMarker) + 'static,
) -> day_pieces::Decorated<Self> {
self.tweak(move |n| {
let _ = with_native_subcontrol(n, sub, f);
})
}
}
impl<P: Decorate> AppKitExt for P {}