use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use crate::color::Color;
use crate::foundation::{id, nil, NSArray, NSString, NO, YES};
use crate::layout::Layout;
use crate::objc_access::ObjcAccess;
use crate::pasteboard::PasteboardType;
use crate::utils::properties::ObjcProperty;
#[cfg(feature = "autolayout")]
use crate::layout::{LayoutAnchorDimension, LayoutAnchorX, LayoutAnchorY};
#[cfg(feature = "appkit")]
mod appkit;
#[cfg(feature = "appkit")]
use appkit::{register_scrollview_class, register_scrollview_class_with_delegate};
mod traits;
pub use traits::ScrollViewDelegate;
pub(crate) static SCROLLVIEW_DELEGATE_PTR: &str = "rstScrollViewDelegatePtr";
fn allocate_view(registration_fn: fn() -> *const Class) -> id {
unsafe {
let view: id = msg_send![registration_fn(), new];
#[cfg(feature = "autolayout")]
let _: () = msg_send![view, setTranslatesAutoresizingMaskIntoConstraints: NO];
#[cfg(feature = "appkit")]
{
let _: () = msg_send![view, setDrawsBackground: NO];
let _: () = msg_send![view, setWantsLayer: YES];
let _: () = msg_send![view, setBorderType:0];
let _: () = msg_send![view, setHorizontalScrollElasticity:1];
let _: () = msg_send![view, setHasVerticalScroller: YES];
}
view
}
}
#[derive(Debug)]
pub struct ScrollView<T = ()> {
pub objc: ObjcProperty,
pub delegate: Option<Box<T>>,
#[cfg(feature = "autolayout")]
pub top: LayoutAnchorY,
#[cfg(feature = "autolayout")]
pub leading: LayoutAnchorX,
#[cfg(feature = "autolayout")]
pub left: LayoutAnchorX,
#[cfg(feature = "autolayout")]
pub trailing: LayoutAnchorX,
#[cfg(feature = "autolayout")]
pub right: LayoutAnchorX,
#[cfg(feature = "autolayout")]
pub bottom: LayoutAnchorY,
#[cfg(feature = "autolayout")]
pub width: LayoutAnchorDimension,
#[cfg(feature = "autolayout")]
pub height: LayoutAnchorDimension,
#[cfg(feature = "autolayout")]
pub center_x: LayoutAnchorX,
#[cfg(feature = "autolayout")]
pub center_y: LayoutAnchorY
}
impl Default for ScrollView {
fn default() -> Self {
ScrollView::new()
}
}
impl ScrollView {
pub fn new() -> Self {
let view = allocate_view(register_scrollview_class);
ScrollView {
delegate: None,
#[cfg(feature = "autolayout")]
top: LayoutAnchorY::top(view),
#[cfg(feature = "autolayout")]
left: LayoutAnchorX::left(view),
#[cfg(feature = "autolayout")]
leading: LayoutAnchorX::leading(view),
#[cfg(feature = "autolayout")]
right: LayoutAnchorX::right(view),
#[cfg(feature = "autolayout")]
trailing: LayoutAnchorX::trailing(view),
#[cfg(feature = "autolayout")]
bottom: LayoutAnchorY::bottom(view),
#[cfg(feature = "autolayout")]
width: LayoutAnchorDimension::width(view),
#[cfg(feature = "autolayout")]
height: LayoutAnchorDimension::height(view),
#[cfg(feature = "autolayout")]
center_x: LayoutAnchorX::center(view),
#[cfg(feature = "autolayout")]
center_y: LayoutAnchorY::center(view),
objc: ObjcProperty::retain(view)
}
}
}
impl<T> ScrollView<T>
where
T: ScrollViewDelegate + 'static
{
pub fn with(delegate: T) -> ScrollView<T> {
let mut delegate = Box::new(delegate);
let view = allocate_view(register_scrollview_class_with_delegate::<T>);
unsafe {
let ptr: *const T = &*delegate;
(&mut *view).set_ivar(SCROLLVIEW_DELEGATE_PTR, ptr as usize);
};
let mut view = ScrollView {
delegate: None,
#[cfg(feature = "autolayout")]
top: LayoutAnchorY::top(view),
#[cfg(feature = "autolayout")]
left: LayoutAnchorX::left(view),
#[cfg(feature = "autolayout")]
leading: LayoutAnchorX::leading(view),
#[cfg(feature = "autolayout")]
right: LayoutAnchorX::right(view),
#[cfg(feature = "autolayout")]
trailing: LayoutAnchorX::trailing(view),
#[cfg(feature = "autolayout")]
bottom: LayoutAnchorY::bottom(view),
#[cfg(feature = "autolayout")]
width: LayoutAnchorDimension::width(view),
#[cfg(feature = "autolayout")]
height: LayoutAnchorDimension::height(view),
#[cfg(feature = "autolayout")]
center_x: LayoutAnchorX::center(view),
#[cfg(feature = "autolayout")]
center_y: LayoutAnchorY::center(view),
objc: ObjcProperty::retain(view)
};
(&mut delegate).did_load(view.clone_as_handle());
view.delegate = Some(delegate);
view
}
}
impl<T> ScrollView<T> {
pub(crate) fn clone_as_handle(&self) -> ScrollView {
ScrollView {
delegate: None,
#[cfg(feature = "autolayout")]
top: self.top.clone(),
#[cfg(feature = "autolayout")]
leading: self.leading.clone(),
#[cfg(feature = "autolayout")]
left: self.left.clone(),
#[cfg(feature = "autolayout")]
trailing: self.trailing.clone(),
#[cfg(feature = "autolayout")]
right: self.right.clone(),
#[cfg(feature = "autolayout")]
bottom: self.bottom.clone(),
#[cfg(feature = "autolayout")]
width: self.width.clone(),
#[cfg(feature = "autolayout")]
height: self.height.clone(),
#[cfg(feature = "autolayout")]
center_x: self.center_x.clone(),
#[cfg(feature = "autolayout")]
center_y: self.center_y.clone(),
objc: self.objc.clone()
}
}
pub fn set_background_color<C: AsRef<Color>>(&self, color: C) {
self.objc.with_mut(|obj| unsafe {
let color = color.as_ref().cg_color();
let layer: id = msg_send![obj, layer];
let _: () = msg_send![layer, setBackgroundColor: color];
});
}
}
impl<T> ObjcAccess for ScrollView<T> {
fn with_backing_obj_mut<F: Fn(id)>(&self, handler: F) {
self.objc.with_mut(handler);
}
fn get_from_backing_obj<F: Fn(&Object) -> R, R>(&self, handler: F) -> R {
self.objc.get(handler)
}
}
impl<T> Layout for ScrollView<T> {}
impl<T> Drop for ScrollView<T> {
fn drop(&mut self) {
}
}