diff --git a/Cargo.toml b/Cargo.toml index 639e96c1..703c2454 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,6 @@ block = { version = "=0.2.0-alpha.6", package = "block2" } # Temporary: Patched versions that implement `Encode` for common types # Branch: `objc2` core-foundation = { git = "https://github.com/madsmtm/core-foundation-rs.git", rev = "7d593d016175755e492a92ef89edca68ac3bd5cd" } -core-graphics = { git = "https://github.com/madsmtm/core-foundation-rs.git", rev = "7d593d016175755e492a92ef89edca68ac3bd5cd" } dispatch = "0.2.0" infer = { version = "0.15", optional = true } lazy_static = "1.4.0" @@ -36,6 +35,8 @@ uuid = { version = "1.1", features = ["v4"], optional = true } [dev-dependencies] eval = "0.4" +core-graphics = "0.23" +foreign-types = "0.5" [features] appkit = ["core-foundation/mac_os_10_8_features"] diff --git a/README.md b/README.md index 9a7d04f0..5ab3cfe3 100644 --- a/README.md +++ b/README.md @@ -106,8 +106,8 @@ The following are a list of [Cargo features][cargo-features] that can be enabled [cargo-features]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section ## General Notes -**Why not extend the existing cocoa-rs crate?** -A good question. At the end of the day, that crate (I believe, and someone can correct me if I'm wrong) is somewhat tied to Servo, and I wanted to experiment with what the best approach for representing the Cocoa UI model in Rust was. This crate doesn't ignore their work entirely, either - `core_foundation` and `core_graphics` are used internally and re-exported for general use. +**Why not extend the existing cocoa-rs crate?** +A good question. At the end of the day, that crate (I believe, and someone can correct me if I'm wrong) is somewhat tied to Servo, and I wanted to experiment with what the best approach for representing the Cocoa UI model in Rust was. This crate doesn't ignore their work entirely, either - `core_foundation` is used internally and re-exported for general use. **Why should I write in Rust, rather than X language?** In _my_ case, I want to be able to write native applications for my devices (and the platform I like to build products for) without being locked in to writing in Apple-specific languages... and without writing in C/C++ or JavaScript (note: the _toolchain_, not the language - ES6/Typescript are fine). I want to do this because I'm tired of hitting a mountain of work when I want to port my applications to other ecosystems. I think that Rust offers a (growing, but significant) viable model for sharing code across platforms and ecosystems without sacrificing performance. diff --git a/examples/custom_image_drawing.rs b/examples/custom_image_drawing.rs index 8dc6bee0..450d838e 100644 --- a/examples/custom_image_drawing.rs +++ b/examples/custom_image_drawing.rs @@ -1,6 +1,10 @@ //! This example showcases how to do custom drawing on an ImageView //! with CoreGraphics. Feel free to modify it and play around! +use core_graphics::context::CGContextRef; +use foreign_types::ForeignTypeRef; +use objc::rc::Id; + use cacao::appkit::menu::{Menu, MenuItem}; use cacao::appkit::window::Window; use cacao::appkit::{App, AppDelegate}; @@ -30,7 +34,12 @@ impl Default for BasicApp { window: Window::default(), content_view: View::new(), image_view: ImageView::new(), - image: Image::draw(config, |_cg_rect, context| { + image: Image::draw(config, |resized_frame, source, context| { + let context = unsafe { CGContextRef::from_ptr(Id::as_ptr(&context.0) as _) }; + + context.translate(resized_frame.top, resized_frame.left); + context.scale(resized_frame.width / source.0, resized_frame.height / source.1); + context.move_to_point(11.25, 8.19); context.add_line_to_point(11.25, 5.); context.add_line_to_point(6.56, 5.); diff --git a/src/color/mod.rs b/src/color/mod.rs index 6d35e0fe..caabac40 100644 --- a/src/color/mod.rs +++ b/src/color/mod.rs @@ -15,9 +15,6 @@ /// @TODO: bundle iOS/tvOS support. use std::sync::{Arc, RwLock}; -use core_foundation::base::TCFType; -use core_graphics::color::CGColor; - use objc::foundation::CGFloat; use objc::rc::{Id, Owned}; use objc::runtime::Object; @@ -392,10 +389,11 @@ impl Color { /// objects. If you're painting in a context that requires dark mode support, make sure /// you're not using a cached version of this unless you explicitly want the _same_ color /// in every context it's used in. - pub fn cg_color(&self) -> CGColor { + pub fn cg_color(&self) -> id { + // TODO: Better return type unsafe { let objc: id = self.into(); - CGColor::wrap_under_get_rule(msg_send![objc, CGColor]) + msg_send![objc, CGColor] } } } diff --git a/src/image/graphics_context.rs b/src/image/graphics_context.rs new file mode 100644 index 00000000..50963efd --- /dev/null +++ b/src/image/graphics_context.rs @@ -0,0 +1,20 @@ +use objc::rc::{Id, Shared}; +use objc::runtime::Object; +use objc::{class, msg_send, msg_send_id}; + +#[derive(Debug)] +pub struct GraphicsContext(pub Id); + +impl GraphicsContext { + pub fn current() -> Self { + Self(unsafe { msg_send_id![class!(NSGraphicsContext), currentContext] }) + } + + pub fn save(&self) { + unsafe { msg_send![&self.0, saveGraphicsState] } + } + + pub fn restore(&self) { + unsafe { msg_send![&self.0, restoreGraphicsState] } + } +} diff --git a/src/image/image.rs b/src/image/image.rs index fc9182df..d924dce8 100644 --- a/src/image/image.rs +++ b/src/image/image.rs @@ -1,15 +1,14 @@ use objc::foundation::{CGFloat, NSPoint, NSRect, NSSize}; use objc::rc::{Id, Shared}; use objc::runtime::{Bool, Class, Object}; - use objc::{class, msg_send, msg_send_id, sel}; use block::ConcreteBlock; -use core_graphics::context::{CGContext, CGContextRef}; - use super::icons::*; +use super::GraphicsContext; use crate::foundation::{id, NSData, NSString, NSURL}; +use crate::geometry::Rect; use crate::utils::os; /// Specifies resizing behavior for image drawing. @@ -251,29 +250,24 @@ impl Image { #[cfg(feature = "appkit")] pub fn draw(config: DrawConfig, handler: F) -> Self where - F: Fn(NSRect, &CGContextRef) -> bool + 'static + F: Fn(Rect, (f64, f64), GraphicsContext) -> bool + 'static { let source_frame = NSRect::new(NSPoint::new(0., 0.), NSSize::new(config.source.0, config.source.1)); let target_frame = NSRect::new(NSPoint::new(0., 0.), NSSize::new(config.target.0, config.target.1)); - let resized_frame = config.resize.apply(source_frame, target_frame); - - let block = ConcreteBlock::new(move |_destination: NSRect| unsafe { - let current_context: id = msg_send![class!(NSGraphicsContext), currentContext]; - let context_ptr: core_graphics::sys::CGContextRef = msg_send![current_context, CGContext]; - let context = CGContext::from_existing_context_ptr(context_ptr); - let _: () = msg_send![class!(NSGraphicsContext), saveGraphicsState]; + let resized_frame: Rect = config.resize.apply(source_frame, target_frame).into(); - context.translate(resized_frame.origin.x, resized_frame.origin.y); - context.scale( - resized_frame.size.width() / config.source.0, - resized_frame.size.height() / config.source.1 - ); + let block = ConcreteBlock::new(move |_destination: NSRect| { + let context = GraphicsContext::current(); - let result = handler(resized_frame, &context); + // context.translate(resized_frame.origin.x, resized_frame.origin.y); + // context.scale( + // resized_frame.size.width() / config.source.0, + // resized_frame.size.height() / config.source.1 + // ); - let _: () = msg_send![class!(NSGraphicsContext), restoreGraphicsState]; + let result = handler(resized_frame, (config.source.0 as f64, config.source.1 as f64), context); Bool::new(result) }); diff --git a/src/image/mod.rs b/src/image/mod.rs index 8b567235..6b5b6cff 100644 --- a/src/image/mod.rs +++ b/src/image/mod.rs @@ -1,5 +1,3 @@ -use core_foundation::base::TCFType; - use objc::rc::{Id, Shared}; use objc::runtime::{Class, Object}; use objc::{msg_send, msg_send_id, sel}; @@ -26,6 +24,9 @@ mod uikit; #[cfg(all(feature = "uikit", not(feature = "appkit")))] use uikit::register_image_view_class; +mod graphics_context; +pub use graphics_context::GraphicsContext; + mod image; pub use image::{DrawConfig, Image, ResizeBehavior}; @@ -151,7 +152,7 @@ impl ImageView { /// Call this to set the background color for the backing layer. pub fn set_background_color>(&self, color: C) { self.objc.with_mut(|obj| unsafe { - let cg = color.as_ref().cg_color().as_concrete_TypeRef(); + let cg = color.as_ref().cg_color(); let layer: id = msg_send![obj, layer]; let _: () = msg_send![layer, setBackgroundColor: cg]; }); diff --git a/src/input/mod.rs b/src/input/mod.rs index 3e1759e7..1e1bf911 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -43,8 +43,6 @@ //! //! For more information on Autolayout, view the module or check out the examples folder. -use core_foundation::base::TCFType; - use objc::rc::{Id, Shared}; use objc::runtime::{Class, Object}; use objc::{class, msg_send, sel}; @@ -308,7 +306,7 @@ impl TextField { /// Call this to set the background color for the backing layer. pub fn set_background_color>(&self, color: C) { self.objc.with_mut(|obj| unsafe { - let cg = color.as_ref().cg_color().as_concrete_TypeRef(); + let cg = color.as_ref().cg_color(); let layer: id = msg_send![obj, layer]; let _: () = msg_send![layer, setBackgroundColor: cg]; }); diff --git a/src/lib.rs b/src/lib.rs index cfe5f5e3..dec6c69d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,7 +93,6 @@ //! [cargo-features]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section pub use core_foundation; -pub use core_graphics; pub use lazy_static; pub use objc; pub use url; diff --git a/src/listview/mod.rs b/src/listview/mod.rs index 69df14a5..34d257b9 100644 --- a/src/listview/mod.rs +++ b/src/listview/mod.rs @@ -44,9 +44,7 @@ use std::collections::HashMap; -use core_foundation::base::TCFType; - -use objc::foundation::{CGFloat, NSSize}; +use objc::foundation::CGFloat; use objc::rc::{Id, Owned, Shared}; use objc::runtime::{Class, Object}; use objc::{class, msg_send, msg_send_id, sel}; @@ -441,7 +439,7 @@ impl ListView { pub fn set_background_color>(&self, color: C) { // @TODO: This is wrong. self.objc.with_mut(|obj| unsafe { - let color = color.as_ref().cg_color().as_concrete_TypeRef(); + let color = color.as_ref().cg_color(); let layer: id = msg_send![obj, layer]; let _: () = msg_send![layer, setBackgroundColor: color]; }); diff --git a/src/scrollview/mod.rs b/src/scrollview/mod.rs index e945c14d..6fb612c0 100644 --- a/src/scrollview/mod.rs +++ b/src/scrollview/mod.rs @@ -42,8 +42,6 @@ //! //! For more information on Autolayout, view the module or check out the examples folder. -use core_foundation::base::TCFType; - use objc::rc::{Id, Shared}; use objc::runtime::{Class, Object}; use objc::{msg_send, sel}; @@ -298,7 +296,7 @@ impl ScrollView { pub fn set_background_color>(&self, color: C) { // @TODO: This is wrong. self.objc.with_mut(|obj| unsafe { - let color = color.as_ref().cg_color().as_concrete_TypeRef(); + let color = color.as_ref().cg_color(); let layer: id = msg_send![obj, layer]; let _: () = msg_send![layer, setBackgroundColor: color]; }); diff --git a/src/text/label/mod.rs b/src/text/label/mod.rs index 23cb7de8..918a6913 100644 --- a/src/text/label/mod.rs +++ b/src/text/label/mod.rs @@ -43,8 +43,6 @@ //! //! For more information on Autolayout, view the module or check out the examples folder. -use core_foundation::base::TCFType; - use objc::rc::{Id, Shared}; use objc::runtime::{Class, Object}; use objc::{msg_send, msg_send_id, sel}; @@ -326,7 +324,7 @@ impl Label { // @TODO: This is wrong. // Needs to set ivar and such, akin to View. self.objc.with_mut(|obj| unsafe { - let color = color.as_ref().cg_color().as_concrete_TypeRef(); + let color = color.as_ref().cg_color(); let layer: id = msg_send![obj, layer]; let _: () = msg_send![layer, setBackgroundColor: color]; });