Skip to content

Commit

Permalink
Remove dependency on core-graphics
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Sep 11, 2023
1 parent 5eed4f6 commit 978ab3d
Show file tree
Hide file tree
Showing 12 changed files with 73 additions and 43 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"]
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
10 changes: 9 additions & 1 deletion examples/custom_image_drawing.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! 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 cacao::appkit::menu::{Menu, MenuItem};
use cacao::appkit::window::Window;
use cacao::appkit::{App, AppDelegate};
Expand Down Expand Up @@ -30,7 +33,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(context.cast()) };

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.);
Expand Down
8 changes: 3 additions & 5 deletions src/color/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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]
}
}
}
Expand Down
26 changes: 26 additions & 0 deletions src/image/graphics_context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use std::ffi::c_void;

use objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, msg_send_id};

#[derive(Debug)]
pub(crate) struct GraphicsContext(pub Id<Object, Shared>);

impl GraphicsContext {
pub(crate) fn current() -> Self {
Self(unsafe { msg_send_id![class!(NSGraphicsContext), currentContext] })
}

pub(crate) fn save(&self) {
unsafe { msg_send![&self.0, saveGraphicsState] }
}

pub(crate) fn restore(&self) {
unsafe { msg_send![&self.0, restoreGraphicsState] }
}

pub(crate) fn cg_context(&self) -> *mut c_void {
unsafe { msg_send![&self.0, CGContext] }
}
}
40 changes: 23 additions & 17 deletions src/image/image.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use std::ffi::c_void;

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::graphics_context::GraphicsContext;
use super::icons::*;
use crate::foundation::{id, NSData, NSString, NSURL};
use crate::geometry::Rect;
use crate::utils::os;

/// Specifies resizing behavior for image drawing.
Expand Down Expand Up @@ -251,29 +252,34 @@ impl Image {
#[cfg(feature = "appkit")]
pub fn draw<F>(config: DrawConfig, handler: F) -> Self
where
F: Fn(NSRect, &CGContextRef) -> bool + 'static
F: Fn(Rect, (f64, f64), *mut c_void) -> 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 resized_frame: Rect = config.resize.apply(source_frame, target_frame).into();

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 block = ConcreteBlock::new(move |_destination: NSRect| {
let context = GraphicsContext::current();
context.save();

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 cg_context_ptr: *mut c_void = context.cg_context();

// TODO: Automatically scale for the user
// cg_context_ptr.translate(resized_frame.origin.x, resized_frame.origin.y);
// cg_context_ptr.scale(
// resized_frame.size.width() / config.source.0,
// resized_frame.size.height() / config.source.1
// );

let result = handler(resized_frame, &context);
let result = handler(
resized_frame,
(config.source.0 as f64, config.source.1 as f64),
cg_context_ptr
);

let _: () = msg_send![class!(NSGraphicsContext), restoreGraphicsState];
context.restore();

Bool::new(result)
});
Expand Down
6 changes: 3 additions & 3 deletions src/image/mod.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -26,6 +24,8 @@ mod uikit;
#[cfg(all(feature = "uikit", not(feature = "appkit")))]
use uikit::register_image_view_class;

mod graphics_context;

mod image;
pub use image::{DrawConfig, Image, ResizeBehavior};

Expand Down Expand Up @@ -151,7 +151,7 @@ impl ImageView {
/// Call this to set the background color for the backing layer.
pub fn set_background_color<C: AsRef<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];
});
Expand Down
4 changes: 1 addition & 3 deletions src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -308,7 +306,7 @@ impl<T> TextField<T> {
/// Call this to set the background color for the backing layer.
pub fn set_background_color<C: AsRef<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];
});
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 2 additions & 4 deletions src/listview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -441,7 +439,7 @@ impl<T> ListView<T> {
pub fn set_background_color<C: AsRef<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];
});
Expand Down
4 changes: 1 addition & 3 deletions src/scrollview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -298,7 +296,7 @@ impl<T> ScrollView<T> {
pub fn set_background_color<C: AsRef<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];
});
Expand Down
4 changes: 1 addition & 3 deletions src/text/label/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -326,7 +324,7 @@ impl<T> Label<T> {
// @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];
});
Expand Down

0 comments on commit 978ab3d

Please sign in to comment.