Added image to uikit support and integration test

This commit is contained in:
Sebastian Imlay 2022-08-21 01:03:56 -04:00
parent 968843e79b
commit bab9e7d847
9 changed files with 105 additions and 33 deletions

View file

@ -70,3 +70,32 @@ jobs:
command: build command: build
target: x86_64-apple-ios target: x86_64-apple-ios
args: --example ios-beta --no-default-features --features uikit,autolayout args: --example ios-beta --no-default-features --features uikit,autolayout
ios:
name: Check that examples build
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
target: x86_64-apple-ios
- uses: actions-rs/install@v0.1
with:
crate: cargo-dinghy
version: latest
use-tool-cache: true
- 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-iphone7 com.apple.CoreSimulator.SimDeviceType.iPhone-SE-3rd-generation $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

View file

@ -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"]

View file

@ -5,6 +5,7 @@ use cacao::uikit::{App, AppDelegate, Scene, SceneConfig, SceneConnectionOptions,
use cacao::color::Color; use cacao::color::Color;
use cacao::layout::{Layout, LayoutConstraint}; use cacao::layout::{Layout, LayoutConstraint};
use cacao::view::{View, ViewController, ViewDelegate}; use cacao::view::{View, ViewController, ViewDelegate};
use cacao::image::{ImageView, Image};
#[derive(Default)] #[derive(Default)]
struct TestApp; struct TestApp;
@ -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.),

View file

@ -1,4 +1,4 @@
use objc::runtime::Object; use objc::runtime::{Object, Class};
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) })
@ -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])
}) })
} }

View file

@ -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);
}

View file

@ -13,33 +13,15 @@ use crate::utils::load;
/// 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
}
}

View file

@ -101,8 +101,8 @@ 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]) {
let ids: Vec<&Object> = constraints.into_iter().map(|constraint| &*constraint.constraint).collect();
unsafe { unsafe {
let ids: Vec<&Object> = constraints.into_iter().map(|constraint| &*constraint.constraint).collect();
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];
@ -110,8 +110,8 @@ impl LayoutConstraint {
} }
pub fn deactivate(constraints: &[LayoutConstraint]) { pub fn deactivate(constraints: &[LayoutConstraint]) {
let ids: Vec<&Object> = constraints.into_iter().map(|constraint| &*constraint.constraint).collect();
unsafe { unsafe {
let ids: Vec<&Object> = constraints.into_iter().map(|constraint| &*constraint.constraint).collect();
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];

View file

@ -121,7 +121,7 @@ pub mod color;
#[cfg(feature = "appkit")] #[cfg(feature = "appkit")]
pub mod control; pub mod control;
#[cfg(feature = "appkit")] #[cfg(any(feature = "appkit", feature = "uikit"))]
pub mod dragdrop; pub mod dragdrop;
pub mod error; pub mod error;
@ -137,12 +137,14 @@ 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")]
pub mod input; pub mod input;
pub(crate) mod invoker; pub(crate) mod invoker;
#[cfg(test)]
mod tests;
pub mod keys; pub mod keys;
@ -155,7 +157,7 @@ pub mod networking;
pub mod notification_center; pub mod notification_center;
pub(crate) mod objc_access; pub(crate) mod objc_access;
#[cfg(feature = "appkit")] #[cfg(any(feature = "appkit", feature = "uikit"))]
pub mod pasteboard; pub mod pasteboard;
#[cfg(feature = "appkit")] #[cfg(feature = "appkit")]

BIN
test-data/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB