Merge pull request #48 from simlay/simlay/add-image-support-and-simple-unit-test
Add image support for uikit feature backends
This commit is contained in:
commit
6b69c1db94
52
.github/workflows/ci.yml
vendored
52
.github/workflows/ci.yml
vendored
|
@ -58,9 +58,49 @@ jobs:
|
||||||
with:
|
with:
|
||||||
command: build
|
command: build
|
||||||
args: --features webview --example webview_custom_protocol
|
args: --features webview --example webview_custom_protocol
|
||||||
# fails because it needs uikit, which is not
|
- uses: actions-rs/toolchain@v1
|
||||||
# building for me
|
with:
|
||||||
#- uses: actions-rs/cargo@v1
|
toolchain: stable
|
||||||
# with:
|
override: true
|
||||||
# command: build
|
target: x86_64-apple-ios
|
||||||
# args: --example ios-beta
|
# Since it's all Objective-C message passing under the hood, we're
|
||||||
|
# really just looking for whether we've broken the iOS build. It is likely
|
||||||
|
# that more robust tests/checking infrastructure should exist for this side
|
||||||
|
# of things as the iOS portion gets iterated on.
|
||||||
|
#
|
||||||
|
# (e.g, this at the moment will not catch invalid selector calls, like if an appkit-specific
|
||||||
|
# selector is used for something on iOS)
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: build
|
||||||
|
args: --target x86_64-apple-ios --example ios-beta --no-default-features --features uikit,autolayout
|
||||||
|
|
||||||
|
ios:
|
||||||
|
name: Check that iOS tests pass via dinghy.
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Install cargo-dinghy
|
||||||
|
uses: baptiste0928/cargo-install@v1
|
||||||
|
with:
|
||||||
|
crate: cargo-dinghy
|
||||||
|
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
target: x86_64-apple-ios
|
||||||
|
|
||||||
|
- name: Launch XCode Simulator and prepare Dinghy
|
||||||
|
run: |
|
||||||
|
# Get system info
|
||||||
|
xcrun simctl list runtimes
|
||||||
|
# Launch the simulator
|
||||||
|
RUNTIME_ID=$(xcrun simctl list runtimes | grep iOS | cut -d ' ' -f 7 | tail -1)
|
||||||
|
SIM_ID=$(xcrun simctl create My-iphone-se com.apple.CoreSimulator.SimDeviceType.iPhone-SE $RUNTIME_ID)
|
||||||
|
xcrun simctl boot $SIM_ID
|
||||||
|
|
||||||
|
- name: Dinghy test
|
||||||
|
run: |
|
||||||
|
cargo dinghy --platform auto-ios-x86_64 test --no-default-features --features uikit,autolayout
|
||||||
|
|
34
Cargo.toml
34
Cargo.toml
|
@ -65,3 +65,37 @@ required-features = ["webview"]
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "ios-beta"
|
name = "ios-beta"
|
||||||
required-features = ["uikit", "autolayout"]
|
required-features = ["uikit", "autolayout"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "calculator"
|
||||||
|
required-features = ["appkit"]
|
||||||
|
[[example]]
|
||||||
|
name = "todos_list"
|
||||||
|
required-features = ["appkit"]
|
||||||
|
[[example]]
|
||||||
|
name = "animation"
|
||||||
|
required-features = ["appkit"]
|
||||||
|
[[example]]
|
||||||
|
name = "autolayout"
|
||||||
|
required-features = ["appkit"]
|
||||||
|
[[example]]
|
||||||
|
name = "custom_image_drawing"
|
||||||
|
required-features = ["appkit"]
|
||||||
|
[[example]]
|
||||||
|
name = "text_input"
|
||||||
|
required-features = ["appkit"]
|
||||||
|
[[example]]
|
||||||
|
name = "defaults"
|
||||||
|
required-features = ["appkit"]
|
||||||
|
[[example]]
|
||||||
|
name = "frame_layout"
|
||||||
|
required-features = ["appkit"]
|
||||||
|
[[example]]
|
||||||
|
name = "window"
|
||||||
|
required-features = ["appkit"]
|
||||||
|
[[example]]
|
||||||
|
name = "window_delegate"
|
||||||
|
required-features = ["appkit"]
|
||||||
|
[[example]]
|
||||||
|
name = "window_controller"
|
||||||
|
required-features = ["appkit"]
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::sync::RwLock;
|
||||||
use cacao::uikit::{App, AppDelegate, Scene, SceneConfig, SceneConnectionOptions, SceneSession, Window, WindowSceneDelegate};
|
use cacao::uikit::{App, AppDelegate, Scene, SceneConfig, SceneConnectionOptions, SceneSession, Window, WindowSceneDelegate};
|
||||||
|
|
||||||
use cacao::color::Color;
|
use cacao::color::Color;
|
||||||
|
use cacao::image::{Image, ImageView};
|
||||||
use cacao::layout::{Layout, LayoutConstraint};
|
use cacao::layout::{Layout, LayoutConstraint};
|
||||||
use cacao::view::{View, ViewController, ViewDelegate};
|
use cacao::view::{View, ViewController, ViewDelegate};
|
||||||
|
|
||||||
|
@ -19,7 +20,8 @@ impl AppDelegate for TestApp {
|
||||||
pub struct RootView {
|
pub struct RootView {
|
||||||
pub red: View,
|
pub red: View,
|
||||||
pub green: View,
|
pub green: View,
|
||||||
pub blue: View
|
pub blue: View,
|
||||||
|
pub image: ImageView
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ViewDelegate for RootView {
|
impl ViewDelegate for RootView {
|
||||||
|
@ -36,6 +38,11 @@ impl ViewDelegate for RootView {
|
||||||
self.blue.set_background_color(Color::SystemBlue);
|
self.blue.set_background_color(Color::SystemBlue);
|
||||||
view.add_subview(&self.blue);
|
view.add_subview(&self.blue);
|
||||||
|
|
||||||
|
let image_bytes = include_bytes!("../../test-data/favicon.ico");
|
||||||
|
self.image = ImageView::new();
|
||||||
|
self.image.set_image(&Image::with_data(image_bytes));
|
||||||
|
view.add_subview(&self.image);
|
||||||
|
|
||||||
LayoutConstraint::activate(&[
|
LayoutConstraint::activate(&[
|
||||||
self.red.top.constraint_equal_to(&view.top).offset(16.),
|
self.red.top.constraint_equal_to(&view.top).offset(16.),
|
||||||
self.red.leading.constraint_equal_to(&view.leading).offset(16.),
|
self.red.leading.constraint_equal_to(&view.leading).offset(16.),
|
||||||
|
|
|
@ -7,7 +7,7 @@ Since this needs to run in an iOS simulator or on a device, you can't run it lik
|
||||||
- Start a simulator (Simulator.app).
|
- Start a simulator (Simulator.app).
|
||||||
- `cargo install cargo-bundle`
|
- `cargo install cargo-bundle`
|
||||||
- `cargo bundle --example ios-beta --no-default-features --features uikit,autolayout --target x86_64-apple-ios`
|
- `cargo bundle --example ios-beta --no-default-features --features uikit,autolayout --target x86_64-apple-ios`
|
||||||
- `xcrun simctl install booted target/x86_64-apple-ios/debug/examples/bundle/ios/cacao-ios-beta.app`
|
- `xcrun simctl install booted target/x86_64-apple-ios/debug/examples/bundle/ios/ios-beta.app`
|
||||||
- `xcrun simctl launch --console booted com.cacao.ios-test`
|
- `xcrun simctl launch --console booted com.cacao.ios-test`
|
||||||
|
|
||||||
## Current Support
|
## Current Support
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use objc::runtime::Object;
|
use objc::runtime::{Class, Object};
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
|
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
@ -122,6 +122,15 @@ pub struct DrawConfig {
|
||||||
pub struct Image(pub ShareId<Object>);
|
pub struct Image(pub ShareId<Object>);
|
||||||
|
|
||||||
impl Image {
|
impl Image {
|
||||||
|
fn class() -> &'static Class {
|
||||||
|
#[cfg(feature = "appkit")]
|
||||||
|
let class = class!(NSImage);
|
||||||
|
#[cfg(all(feature = "uikit", not(feature = "appkit")))]
|
||||||
|
let class = class!(UIImage);
|
||||||
|
|
||||||
|
class
|
||||||
|
}
|
||||||
|
|
||||||
/// Wraps a system-returned image, e.g from QuickLook previews.
|
/// Wraps a system-returned image, e.g from QuickLook previews.
|
||||||
pub fn with(image: id) -> Self {
|
pub fn with(image: id) -> Self {
|
||||||
Image(unsafe { ShareId::from_ptr(image) })
|
Image(unsafe { ShareId::from_ptr(image) })
|
||||||
|
@ -132,7 +141,7 @@ impl Image {
|
||||||
let file_path = NSString::new(path);
|
let file_path = NSString::new(path);
|
||||||
|
|
||||||
Image(unsafe {
|
Image(unsafe {
|
||||||
let alloc: id = msg_send![class!(NSImage), alloc];
|
let alloc: id = msg_send![Self::class(), alloc];
|
||||||
ShareId::from_ptr(msg_send![alloc, initWithContentsOfFile: file_path])
|
ShareId::from_ptr(msg_send![alloc, initWithContentsOfFile: file_path])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -143,7 +152,7 @@ impl Image {
|
||||||
let data = NSData::with_slice(data);
|
let data = NSData::with_slice(data);
|
||||||
|
|
||||||
Image(unsafe {
|
Image(unsafe {
|
||||||
let alloc: id = msg_send![class!(NSImage), alloc];
|
let alloc: id = msg_send![Self::class(), alloc];
|
||||||
ShareId::from_ptr(msg_send![alloc, initWithData: data])
|
ShareId::from_ptr(msg_send![alloc, initWithData: data])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -157,7 +166,7 @@ impl Image {
|
||||||
Image(unsafe {
|
Image(unsafe {
|
||||||
ShareId::from_ptr({
|
ShareId::from_ptr({
|
||||||
let icon = icon.to_id();
|
let icon = icon.to_id();
|
||||||
msg_send![class!(NSImage), imageNamed: icon]
|
msg_send![Self::class(), imageNamed: icon]
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -179,13 +188,13 @@ impl Image {
|
||||||
true => {
|
true => {
|
||||||
let icon = NSString::new(icon.to_sfsymbol_str());
|
let icon = NSString::new(icon.to_sfsymbol_str());
|
||||||
let desc = NSString::new(accessibility_description);
|
let desc = NSString::new(accessibility_description);
|
||||||
msg_send![class!(NSImage), imageWithSystemSymbolName:&*icon
|
msg_send![Self::class(), imageWithSystemSymbolName:&*icon
|
||||||
accessibilityDescription:&*desc]
|
accessibilityDescription:&*desc]
|
||||||
},
|
},
|
||||||
|
|
||||||
false => {
|
false => {
|
||||||
let icon = icon.to_id();
|
let icon = icon.to_id();
|
||||||
msg_send![class!(NSImage), imageNamed: icon]
|
msg_send![Self::class(), imageNamed: icon]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -213,7 +222,7 @@ impl Image {
|
||||||
true => {
|
true => {
|
||||||
let icon = NSString::new(symbol.to_str());
|
let icon = NSString::new(symbol.to_str());
|
||||||
let desc = NSString::new(accessibility_description);
|
let desc = NSString::new(accessibility_description);
|
||||||
msg_send![class!(NSImage), imageWithSystemSymbolName:&*icon
|
msg_send![Self::class(), imageWithSystemSymbolName:&*icon
|
||||||
accessibilityDescription:&*desc]
|
accessibilityDescription:&*desc]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -267,7 +276,7 @@ impl Image {
|
||||||
let block = block.copy();
|
let block = block.copy();
|
||||||
|
|
||||||
Image(unsafe {
|
Image(unsafe {
|
||||||
let img: id = msg_send![class!(NSImage), imageWithSize:target_frame.size
|
let img: id = msg_send![Self::class(), imageWithSize:target_frame.size
|
||||||
flipped:YES
|
flipped:YES
|
||||||
drawingHandler:block
|
drawingHandler:block
|
||||||
];
|
];
|
||||||
|
@ -276,3 +285,15 @@ impl Image {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_image_from_bytes() {
|
||||||
|
let image_bytes = include_bytes!("../../test-data/favicon.ico");
|
||||||
|
let image = Image::with_data(image_bytes);
|
||||||
|
}
|
||||||
|
// It's unclear where the file is on the ios simulator.
|
||||||
|
#[test]
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn test_image_from_file() {
|
||||||
|
let image = Image::with_contents_of_file("./test-data/favicon.ico");
|
||||||
|
}
|
||||||
|
|
|
@ -17,11 +17,11 @@ mod appkit;
|
||||||
#[cfg(feature = "appkit")]
|
#[cfg(feature = "appkit")]
|
||||||
use appkit::register_image_view_class;
|
use appkit::register_image_view_class;
|
||||||
|
|
||||||
//#[cfg(feature = "uikit")]
|
#[cfg(feature = "uikit")]
|
||||||
//mod uikit;
|
mod uikit;
|
||||||
|
|
||||||
//#[cfg(feature = "uikit")]
|
#[cfg(all(feature = "uikit", not(feature = "appkit")))]
|
||||||
//use uikit::register_image_view_class;
|
use uikit::register_image_view_class;
|
||||||
|
|
||||||
mod image;
|
mod image;
|
||||||
pub use image::{DrawConfig, Image, ResizeBehavior};
|
pub use image::{DrawConfig, Image, ResizeBehavior};
|
||||||
|
@ -194,3 +194,12 @@ impl Drop for ImageView {
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_image() {
|
||||||
|
let image_view = ImageView::new();
|
||||||
|
image_view.set_background_color(Color::SystemBlue);
|
||||||
|
let image_bytes = include_bytes!("../../test-data/favicon.ico");
|
||||||
|
let image = Image::with_data(image_bytes);
|
||||||
|
image_view.set_image(&image);
|
||||||
|
}
|
||||||
|
|
|
@ -5,41 +5,22 @@ use objc::runtime::{Class, Object, Sel, BOOL};
|
||||||
use objc::{class, sel, sel_impl};
|
use objc::{class, sel, sel_impl};
|
||||||
use objc_id::Id;
|
use objc_id::Id;
|
||||||
|
|
||||||
use crate::foundation::{id, YES, NO, NSUInteger};
|
use crate::foundation::{id, NSUInteger, NO, YES};
|
||||||
use crate::dragdrop::DragInfo;
|
|
||||||
use crate::view::{VIEW_DELEGATE_PTR, ViewDelegate};
|
|
||||||
use crate::utils::load;
|
use crate::utils::load;
|
||||||
|
use crate::view::{ViewDelegate, VIEW_DELEGATE_PTR};
|
||||||
|
|
||||||
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
|
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
|
||||||
/// have separate classes here since we don't want to waste cycles on methods that will never be
|
/// have separate classes here since we don't want to waste cycles on methods that will never be
|
||||||
/// used if there's no delegates.
|
/// used if there's no delegates.
|
||||||
pub(crate) fn register_view_class() -> *const Class {
|
pub(crate) fn register_image_view_class() -> *const Class {
|
||||||
static mut VIEW_CLASS: *const Class = 0 as *const Class;
|
static mut VIEW_CLASS: *const Class = 0 as *const Class;
|
||||||
static INIT: Once = Once::new();
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
INIT.call_once(|| unsafe {
|
INIT.call_once(|| unsafe {
|
||||||
let superclass = class!(UIView);
|
let superclass = class!(UIImageView);
|
||||||
let mut decl = ClassDecl::new("RSTView", superclass).unwrap();
|
let mut decl = ClassDecl::new("RSTImageView", superclass).expect("Failed to get RSTVIEW");
|
||||||
VIEW_CLASS = decl.register();
|
VIEW_CLASS = decl.register();
|
||||||
});
|
});
|
||||||
|
|
||||||
unsafe { VIEW_CLASS }
|
unsafe { VIEW_CLASS }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Injects an `NSView` subclass, with some callback and pointer ivars for what we
|
|
||||||
/// need to do.
|
|
||||||
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>() -> *const Class {
|
|
||||||
static mut VIEW_CLASS: *const Class = 0 as *const Class;
|
|
||||||
static INIT: Once = Once::new();
|
|
||||||
|
|
||||||
INIT.call_once(|| unsafe {
|
|
||||||
let superclass = class!(UIView);
|
|
||||||
let mut decl = ClassDecl::new("RSTViewWithDelegate", superclass).unwrap();
|
|
||||||
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
|
|
||||||
VIEW_CLASS = decl.register();
|
|
||||||
});
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
VIEW_CLASS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ use objc_id::ShareId;
|
||||||
|
|
||||||
use crate::foundation::{id, NO, YES};
|
use crate::foundation::{id, NO, YES};
|
||||||
|
|
||||||
|
#[cfg(all(feature = "appkit", target_os = "macos"))]
|
||||||
use super::LayoutConstraintAnimatorProxy;
|
use super::LayoutConstraintAnimatorProxy;
|
||||||
|
|
||||||
/// A wrapper for `NSLayoutConstraint`. This both acts as a central path through which to activate
|
/// A wrapper for `NSLayoutConstraint`. This both acts as a central path through which to activate
|
||||||
|
@ -31,6 +32,8 @@ pub struct LayoutConstraint {
|
||||||
pub priority: f64,
|
pub priority: f64,
|
||||||
|
|
||||||
/// An animator proxy that can be used inside animation contexts.
|
/// An animator proxy that can be used inside animation contexts.
|
||||||
|
/// This is currently only supported on macOS with the `appkit` feature.
|
||||||
|
#[cfg(all(feature = "appkit", target_os = "macos"))]
|
||||||
pub animator: LayoutConstraintAnimatorProxy
|
pub animator: LayoutConstraintAnimatorProxy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +41,9 @@ impl LayoutConstraint {
|
||||||
/// An internal method for wrapping existing constraints.
|
/// An internal method for wrapping existing constraints.
|
||||||
pub(crate) fn new(object: id) -> Self {
|
pub(crate) fn new(object: id) -> Self {
|
||||||
LayoutConstraint {
|
LayoutConstraint {
|
||||||
|
#[cfg(all(feature = "appkit", target_os = "macos"))]
|
||||||
animator: LayoutConstraintAnimatorProxy::new(object),
|
animator: LayoutConstraintAnimatorProxy::new(object),
|
||||||
|
|
||||||
constraint: unsafe { ShareId::from_ptr(object) },
|
constraint: unsafe { ShareId::from_ptr(object) },
|
||||||
offset: 0.0,
|
offset: 0.0,
|
||||||
multiplier: 0.0,
|
multiplier: 0.0,
|
||||||
|
@ -55,7 +60,9 @@ impl LayoutConstraint {
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutConstraint {
|
LayoutConstraint {
|
||||||
|
#[cfg(all(feature = "appkit", target_os = "macos"))]
|
||||||
animator: self.animator,
|
animator: self.animator,
|
||||||
|
|
||||||
constraint: self.constraint,
|
constraint: self.constraint,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
multiplier: self.multiplier,
|
multiplier: self.multiplier,
|
||||||
|
@ -94,18 +101,16 @@ impl LayoutConstraint {
|
||||||
//
|
//
|
||||||
// I regret nothing, lol. If you have a better solution I'm all ears.
|
// I regret nothing, lol. If you have a better solution I'm all ears.
|
||||||
pub fn activate(constraints: &[LayoutConstraint]) {
|
pub fn activate(constraints: &[LayoutConstraint]) {
|
||||||
unsafe {
|
|
||||||
let ids: Vec<&Object> = constraints.into_iter().map(|constraint| &*constraint.constraint).collect();
|
let ids: Vec<&Object> = constraints.into_iter().map(|constraint| &*constraint.constraint).collect();
|
||||||
|
unsafe {
|
||||||
let constraints: id = msg_send![class!(NSArray), arrayWithObjects:ids.as_ptr() count:ids.len()];
|
let constraints: id = msg_send![class!(NSArray), arrayWithObjects:ids.as_ptr() count:ids.len()];
|
||||||
let _: () = msg_send![class!(NSLayoutConstraint), activateConstraints: constraints];
|
let _: () = msg_send![class!(NSLayoutConstraint), activateConstraints: constraints];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deactivate(constraints: &[LayoutConstraint]) {
|
pub fn deactivate(constraints: &[LayoutConstraint]) {
|
||||||
unsafe {
|
|
||||||
let ids: Vec<&Object> = constraints.into_iter().map(|constraint| &*constraint.constraint).collect();
|
let ids: Vec<&Object> = constraints.into_iter().map(|constraint| &*constraint.constraint).collect();
|
||||||
|
unsafe {
|
||||||
let constraints: id = msg_send![class!(NSArray), arrayWithObjects:ids.as_ptr() count:ids.len()];
|
let constraints: id = msg_send![class!(NSArray), arrayWithObjects:ids.as_ptr() count:ids.len()];
|
||||||
let _: () = msg_send![class!(NSLayoutConstraint), deactivateConstraints: constraints];
|
let _: () = msg_send![class!(NSLayoutConstraint), deactivateConstraints: constraints];
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,10 @@
|
||||||
mod traits;
|
mod traits;
|
||||||
pub use traits::Layout;
|
pub use traits::Layout;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "appkit", target_os = "macos"))]
|
||||||
mod animator;
|
mod animator;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "appkit", target_os = "macos"))]
|
||||||
pub use animator::LayoutConstraintAnimatorProxy;
|
pub use animator::LayoutConstraintAnimatorProxy;
|
||||||
|
|
||||||
#[cfg(feature = "autolayout")]
|
#[cfg(feature = "autolayout")]
|
||||||
|
|
|
@ -137,7 +137,7 @@ pub mod filesystem;
|
||||||
pub mod foundation;
|
pub mod foundation;
|
||||||
pub mod geometry;
|
pub mod geometry;
|
||||||
|
|
||||||
#[cfg(feature = "appkit")]
|
#[cfg(any(feature = "appkit", feature = "uikit"))]
|
||||||
pub mod image;
|
pub mod image;
|
||||||
|
|
||||||
#[cfg(feature = "appkit")]
|
#[cfg(feature = "appkit")]
|
||||||
|
|
|
@ -58,7 +58,10 @@ use crate::layout::{LayoutAnchorDimension, LayoutAnchorX, LayoutAnchorY, SafeAre
|
||||||
#[cfg(feature = "appkit")]
|
#[cfg(feature = "appkit")]
|
||||||
use crate::pasteboard::PasteboardType;
|
use crate::pasteboard::PasteboardType;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "appkit", target_os = "macos"))]
|
||||||
mod animator;
|
mod animator;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "appkit", target_os = "macos"))]
|
||||||
pub use animator::ViewAnimatorProxy;
|
pub use animator::ViewAnimatorProxy;
|
||||||
|
|
||||||
#[cfg_attr(feature = "appkit", path = "appkit.rs")]
|
#[cfg_attr(feature = "appkit", path = "appkit.rs")]
|
||||||
|
@ -94,6 +97,9 @@ pub struct View<T = ()> {
|
||||||
pub objc: ObjcProperty,
|
pub objc: ObjcProperty,
|
||||||
|
|
||||||
/// An object that supports limited animations. Can be cloned into animation closures.
|
/// An object that supports limited animations. Can be cloned into animation closures.
|
||||||
|
///
|
||||||
|
/// This is currently only supported on macOS with the `appkit` feature.
|
||||||
|
#[cfg(all(feature = "appkit", target_os = "macos"))]
|
||||||
pub animator: ViewAnimatorProxy,
|
pub animator: ViewAnimatorProxy,
|
||||||
|
|
||||||
/// References the underlying layer. This is consistent across AppKit & UIKit - in AppKit
|
/// References the underlying layer. This is consistent across AppKit & UIKit - in AppKit
|
||||||
|
@ -209,6 +215,7 @@ impl View {
|
||||||
|
|
||||||
layer: Layer::wrap(unsafe { msg_send![view, layer] }),
|
layer: Layer::wrap(unsafe { msg_send![view, layer] }),
|
||||||
|
|
||||||
|
#[cfg(all(feature = "appkit", target_os = "macos"))]
|
||||||
animator: ViewAnimatorProxy::new(view),
|
animator: ViewAnimatorProxy::new(view),
|
||||||
objc: ObjcProperty::retain(view)
|
objc: ObjcProperty::retain(view)
|
||||||
}
|
}
|
||||||
|
@ -256,6 +263,8 @@ impl<T> View<T> {
|
||||||
is_handle: true,
|
is_handle: true,
|
||||||
layer: self.layer.clone(),
|
layer: self.layer.clone(),
|
||||||
objc: self.objc.clone(),
|
objc: self.objc.clone(),
|
||||||
|
|
||||||
|
#[cfg(all(feature = "appkit", target_os = "macos"))]
|
||||||
animator: self.animator.clone(),
|
animator: self.animator.clone(),
|
||||||
|
|
||||||
#[cfg(feature = "autolayout")]
|
#[cfg(feature = "autolayout")]
|
||||||
|
|
BIN
test-data/favicon.ico
Normal file
BIN
test-data/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
Loading…
Reference in a new issue