iOS works again, lol.
- Corrects `feature` -> `target_os` checks. - Updates the old iOS scene delegate pieces to use the new class structure. - Bundles in an iOS demo app. - Blocks off most things that should not even attempt to compile for iOS.
This commit is contained in:
parent
5f2f1f21b0
commit
f558f8e24d
11
Cargo.toml
11
Cargo.toml
|
@ -31,12 +31,17 @@ url = "2.1.1"
|
||||||
eval = "0.4"
|
eval = "0.4"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["macos"]
|
default = []
|
||||||
cloudkit = []
|
cloudkit = []
|
||||||
ios = []
|
|
||||||
macos = []
|
|
||||||
color_fallbacks = []
|
color_fallbacks = []
|
||||||
quicklook = []
|
quicklook = []
|
||||||
user-notifications = ["uuid"]
|
user-notifications = ["uuid"]
|
||||||
webview = []
|
webview = []
|
||||||
webview-downloading-macos = []
|
webview-downloading-macos = []
|
||||||
|
|
||||||
|
[package.metadata.bundle.example.ios-beta]
|
||||||
|
name = "ios-beta"
|
||||||
|
identifier = "com.cacao.ios-test"
|
||||||
|
category = "Developer Tool"
|
||||||
|
short_description = "An example Cacao iOS app."
|
||||||
|
long_description = "An example Cacao iOS app."
|
||||||
|
|
96
examples/ios-beta/main.rs
Normal file
96
examples/ios-beta/main.rs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
|
use cacao::ios::{
|
||||||
|
App, AppDelegate, Scene, SceneConfig, SceneSession,
|
||||||
|
SceneConnectionOptions, WindowSceneDelegate, Window
|
||||||
|
};
|
||||||
|
|
||||||
|
use cacao::color::Color;
|
||||||
|
use cacao::layout::{Layout, LayoutConstraint};
|
||||||
|
use cacao::view::{View, ViewController, ViewDelegate};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct TestApp;
|
||||||
|
|
||||||
|
impl AppDelegate for TestApp {
|
||||||
|
fn config_for_scene_session(&self, session: SceneSession, _options: SceneConnectionOptions) -> SceneConfig {
|
||||||
|
SceneConfig::new("Default Configuration", session.role())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct RootView {
|
||||||
|
pub red: View,
|
||||||
|
pub green: View,
|
||||||
|
pub blue: View
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ViewDelegate for RootView {
|
||||||
|
const NAME: &'static str = "RootView";
|
||||||
|
|
||||||
|
fn did_load(&mut self, view: View) {
|
||||||
|
self.red.set_background_color(Color::SystemRed);
|
||||||
|
self.red.layer.set_corner_radius(16.);
|
||||||
|
view.add_subview(&self.red);
|
||||||
|
|
||||||
|
self.green.set_background_color(Color::SystemGreen);
|
||||||
|
view.add_subview(&self.green);
|
||||||
|
|
||||||
|
self.blue.set_background_color(Color::SystemBlue);
|
||||||
|
view.add_subview(&self.blue);
|
||||||
|
|
||||||
|
LayoutConstraint::activate(&[
|
||||||
|
self.red.top.constraint_equal_to(&view.top).offset(16.),
|
||||||
|
self.red.leading.constraint_equal_to(&view.leading).offset(16.),
|
||||||
|
self.red.trailing.constraint_equal_to(&view.trailing).offset(-16.),
|
||||||
|
self.red.height.constraint_equal_to_constant(100.),
|
||||||
|
|
||||||
|
self.green.top.constraint_equal_to(&self.red.bottom).offset(16.),
|
||||||
|
self.green.leading.constraint_equal_to(&view.leading).offset(16.),
|
||||||
|
self.green.trailing.constraint_equal_to(&view.trailing).offset(-16.),
|
||||||
|
self.green.height.constraint_equal_to_constant(120.),
|
||||||
|
|
||||||
|
self.blue.top.constraint_equal_to(&self.green.bottom).offset(16.),
|
||||||
|
self.blue.leading.constraint_equal_to(&view.leading).offset(16.),
|
||||||
|
self.blue.trailing.constraint_equal_to(&view.trailing).offset(-16.),
|
||||||
|
self.blue.bottom.constraint_equal_to(&view.bottom).offset(-16.)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct WindowScene {
|
||||||
|
pub window: RwLock<Option<Window>>,
|
||||||
|
pub root_view_controller: RwLock<Option<ViewController<RootView>>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowSceneDelegate for WindowScene {
|
||||||
|
fn will_connect(
|
||||||
|
&self,
|
||||||
|
scene: Scene,
|
||||||
|
session: SceneSession,
|
||||||
|
options: SceneConnectionOptions
|
||||||
|
) {
|
||||||
|
let bounds = scene.get_bounds();
|
||||||
|
let mut window = Window::new(bounds);
|
||||||
|
window.set_window_scene(scene);
|
||||||
|
|
||||||
|
let root_view_controller = ViewController::new(RootView::default());
|
||||||
|
window.set_root_view_controller(&root_view_controller);
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut w = self.window.write().unwrap();
|
||||||
|
*w = Some(window);
|
||||||
|
|
||||||
|
let mut vc = self.root_view_controller.write().unwrap();
|
||||||
|
*vc = Some(root_view_controller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::new(TestApp::default(), || {
|
||||||
|
Box::new(WindowScene::default())
|
||||||
|
}).run();
|
||||||
|
}
|
14
examples/ios-beta/readme.md
Normal file
14
examples/ios-beta/readme.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Cacao iOS Support
|
||||||
|
This, unlike the macOS side of things, is much more alpha-quality. It does work, though - and this example will likely end up being a "kitchen sink" to figure things out with.
|
||||||
|
|
||||||
|
## To run
|
||||||
|
Since this needs to run in an iOS simulator or on a device, you can't run it like a typical example. Follow the instructions below to give it a go:
|
||||||
|
|
||||||
|
- Start a simulator (Simulator.app).
|
||||||
|
- `cargo install cargo-bundle`
|
||||||
|
- `cargo bundle --example ios-beta --target x86_64-apple-ios`
|
||||||
|
- `xcrun simctl install booted target/x86_64-apple-ios/debug/examples/bundle/ios/cacao-ios-test.app`
|
||||||
|
- `xcrun simctl launch --console booted com.cacao.ios-test`
|
||||||
|
|
||||||
|
## Current Support
|
||||||
|
Not much, but the basics of the scene delegate system work, along with view support, colors, and layout. Play around!
|
|
@ -2,7 +2,7 @@ use crate::foundation::NSUInteger;
|
||||||
|
|
||||||
/// Represents a bezel style for a button. This is a macOS-specific control, and has no effect
|
/// Represents a bezel style for a button. This is a macOS-specific control, and has no effect
|
||||||
/// under iOS or tvOS.
|
/// under iOS or tvOS.
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum BezelStyle {
|
pub enum BezelStyle {
|
||||||
/// A standard circular button.
|
/// A standard circular button.
|
||||||
|
@ -49,7 +49,7 @@ pub enum BezelStyle {
|
||||||
Unknown(NSUInteger)
|
Unknown(NSUInteger)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
impl From<BezelStyle> for NSUInteger {
|
impl From<BezelStyle> for NSUInteger {
|
||||||
fn from(style: BezelStyle) -> Self {
|
fn from(style: BezelStyle) -> Self {
|
||||||
match style {
|
match style {
|
||||||
|
@ -71,7 +71,7 @@ impl From<BezelStyle> for NSUInteger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
impl From<NSUInteger> for BezelStyle {
|
impl From<NSUInteger> for BezelStyle {
|
||||||
fn from(i: NSUInteger) -> Self {
|
fn from(i: NSUInteger) -> Self {
|
||||||
match i {
|
match i {
|
||||||
|
|
|
@ -36,7 +36,7 @@ use crate::layout::{Layout, LayoutAnchorX, LayoutAnchorY, LayoutAnchorDimension}
|
||||||
use crate::text::{AttributedString, Font};
|
use crate::text::{AttributedString, Font};
|
||||||
use crate::utils::{load, properties::ObjcProperty};
|
use crate::utils::{load, properties::ObjcProperty};
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use crate::macos::FocusRingType;
|
use crate::macos::FocusRingType;
|
||||||
|
|
||||||
mod enums;
|
mod enums;
|
||||||
|
@ -145,7 +145,7 @@ impl Button {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the bezel style for this button. Only supported on macOS.
|
/// Sets the bezel style for this button. Only supported on macOS.
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn set_bezel_style(&self, bezel_style: BezelStyle) {
|
pub fn set_bezel_style(&self, bezel_style: BezelStyle) {
|
||||||
let style: NSUInteger = bezel_style.into();
|
let style: NSUInteger = bezel_style.into();
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ impl Button {
|
||||||
pub fn set_background_color<C: AsRef<Color>>(&self, color: C) {
|
pub fn set_background_color<C: AsRef<Color>>(&self, color: C) {
|
||||||
let color: id = color.as_ref().into();
|
let color: id = color.as_ref().into();
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
self.objc.with_mut(|obj| unsafe {
|
self.objc.with_mut(|obj| unsafe {
|
||||||
let cell: id = msg_send![obj, cell];
|
let cell: id = msg_send![obj, cell];
|
||||||
let _: () = msg_send![cell, setBackgroundColor:color];
|
let _: () = msg_send![cell, setBackgroundColor:color];
|
||||||
|
@ -188,7 +188,7 @@ impl Button {
|
||||||
///
|
///
|
||||||
/// On macOS, this is done by way of an `AttributedString` under the hood.
|
/// On macOS, this is done by way of an `AttributedString` under the hood.
|
||||||
pub fn set_text_color<C: AsRef<Color>>(&self, color: C) {
|
pub fn set_text_color<C: AsRef<Color>>(&self, color: C) {
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
self.objc.with_mut(move |obj| unsafe {
|
self.objc.with_mut(move |obj| unsafe {
|
||||||
let text: id = msg_send![obj, attributedTitle];
|
let text: id = msg_send![obj, attributedTitle];
|
||||||
let len: isize = msg_send![text, length];
|
let len: isize = msg_send![text, length];
|
||||||
|
@ -202,7 +202,7 @@ impl Button {
|
||||||
|
|
||||||
// @TODO: Figure out how to handle oddities like this.
|
// @TODO: Figure out how to handle oddities like this.
|
||||||
/// For buttons on macOS, one might need to disable the border. This does that.
|
/// For buttons on macOS, one might need to disable the border. This does that.
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn set_bordered(&self, is_bordered: bool) {
|
pub fn set_bordered(&self, is_bordered: bool) {
|
||||||
self.objc.with_mut(|obj| unsafe {
|
self.objc.with_mut(|obj| unsafe {
|
||||||
let _: () = msg_send![obj, setBordered:match is_bordered {
|
let _: () = msg_send![obj, setBordered:match is_bordered {
|
||||||
|
@ -224,7 +224,7 @@ impl Button {
|
||||||
/// Sets how the control should draw a focus ring when a user is focused on it.
|
/// Sets how the control should draw a focus ring when a user is focused on it.
|
||||||
///
|
///
|
||||||
/// This is a macOS-only method.
|
/// This is a macOS-only method.
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn set_focus_ring_type(&self, focus_ring_type: FocusRingType) {
|
pub fn set_focus_ring_type(&self, focus_ring_type: FocusRingType) {
|
||||||
let ring_type: NSUInteger = focus_ring_type.into();
|
let ring_type: NSUInteger = focus_ring_type.into();
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
///
|
///
|
||||||
/// The goal here is to make sure that this can't reasonably break on OS's, as `Color` is kind of
|
/// The goal here is to make sure that this can't reasonably break on OS's, as `Color` is kind of
|
||||||
/// an important piece. It's not on the framework to make your app look good, though. To enable
|
/// an important piece. It's not on the framework to make your app look good, though. To enable
|
||||||
/// fallbacks, specify the `color_fallbacks` feature in your `Cargo.toml`.
|
/// fallbacks, specify the `color_fallbacks` target_os in your `Cargo.toml`.
|
||||||
///
|
///
|
||||||
/// @TODO: bundle iOS/tvOS support.
|
/// @TODO: bundle iOS/tvOS support.
|
||||||
|
|
||||||
|
@ -26,10 +26,10 @@ use objc_id::Id;
|
||||||
use crate::foundation::id;
|
use crate::foundation::id;
|
||||||
use crate::utils::os;
|
use crate::utils::os;
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
mod macos_dynamic_color;
|
mod macos_dynamic_color;
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use macos_dynamic_color::{
|
use macos_dynamic_color::{
|
||||||
AQUA_LIGHT_COLOR_NORMAL_CONTRAST, AQUA_LIGHT_COLOR_HIGH_CONTRAST,
|
AQUA_LIGHT_COLOR_NORMAL_CONTRAST, AQUA_LIGHT_COLOR_HIGH_CONTRAST,
|
||||||
AQUA_DARK_COLOR_NORMAL_CONTRAST, AQUA_DARK_COLOR_HIGH_CONTRAST
|
AQUA_DARK_COLOR_NORMAL_CONTRAST, AQUA_DARK_COLOR_HIGH_CONTRAST
|
||||||
|
@ -230,11 +230,11 @@ pub enum Color {
|
||||||
LightText,
|
LightText,
|
||||||
|
|
||||||
/// The background color for a given window in the system theme.
|
/// The background color for a given window in the system theme.
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
MacOSWindowBackgroundColor,
|
MacOSWindowBackgroundColor,
|
||||||
|
|
||||||
/// The background color that should appear under a page per the system theme.
|
/// The background color that should appear under a page per the system theme.
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
MacOSUnderPageBackgroundColor
|
MacOSUnderPageBackgroundColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,16 +246,13 @@ impl Color {
|
||||||
let g = green as CGFloat / 255.0;
|
let g = green as CGFloat / 255.0;
|
||||||
let b = blue as CGFloat / 255.0;
|
let b = blue as CGFloat / 255.0;
|
||||||
let a = alpha as CGFloat / 255.0;
|
let a = alpha as CGFloat / 255.0;
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
|
||||||
let color = class!(NSColor);
|
|
||||||
|
|
||||||
#[cfg(feature = "ios")]
|
|
||||||
let color = class!(UIColor);
|
|
||||||
|
|
||||||
Color::Custom(Arc::new(RwLock::new(unsafe {
|
Color::Custom(Arc::new(RwLock::new(unsafe {
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
Id::from_ptr(msg_send![color, colorWithCalibratedRed:r green:g blue:b alpha:a])
|
{ Id::from_ptr(msg_send![class!(NSColor), colorWithCalibratedRed:r green:g blue:b alpha:a]) }
|
||||||
|
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
|
{ Id::from_ptr(msg_send![class!(UIColor), colorWithRed:r green:g blue:b alpha:a]) }
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,15 +270,12 @@ impl Color {
|
||||||
let b = brightness as CGFloat / 255.0;
|
let b = brightness as CGFloat / 255.0;
|
||||||
let a = alpha as CGFloat / 255.0;
|
let a = alpha as CGFloat / 255.0;
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
|
||||||
let color = class!(NSColor);
|
|
||||||
|
|
||||||
#[cfg(feature = "ios")]
|
|
||||||
let color = class!(UIColor);
|
|
||||||
|
|
||||||
Color::Custom(Arc::new(RwLock::new(unsafe {
|
Color::Custom(Arc::new(RwLock::new(unsafe {
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
Id::from_ptr(msg_send![color, colorWithCalibratedHue:h saturation:s brightness:b alpha:a])
|
{ Id::from_ptr(msg_send![class!(NSColor), colorWithCalibratedHue:h saturation:s brightness:b alpha:a]) }
|
||||||
|
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
|
{ Id::from_ptr(msg_send![class!(UIColor), colorWithHue:h saturation:s brightness:b alpha:a]) }
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,15 +288,12 @@ impl Color {
|
||||||
/// Creates and returns a white color with the specified level or intensity, along with the
|
/// Creates and returns a white color with the specified level or intensity, along with the
|
||||||
/// specified alpha.
|
/// specified alpha.
|
||||||
pub fn white_alpha(level: CGFloat, alpha: CGFloat) -> Self {
|
pub fn white_alpha(level: CGFloat, alpha: CGFloat) -> Self {
|
||||||
#[cfg(feature = "macos")]
|
|
||||||
let color = class!(NSColor);
|
|
||||||
|
|
||||||
#[cfg(feature = "ios")]
|
|
||||||
let color = class!(UIColor);
|
|
||||||
|
|
||||||
Color::Custom(Arc::new(RwLock::new(unsafe {
|
Color::Custom(Arc::new(RwLock::new(unsafe {
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
Id::from_ptr(msg_send![color, colorWithCalibratedWhite:level alpha:alpha])
|
{ Id::from_ptr(msg_send![class!(NSColor), colorWithCalibratedWhite:level alpha:alpha]) }
|
||||||
|
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
|
{ Id::from_ptr(msg_send![class!(UIColor), colorWithWhite:level alpha:alpha]) }
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,6 +327,7 @@ impl Color {
|
||||||
/// "default" or "light" color.
|
/// "default" or "light" color.
|
||||||
///
|
///
|
||||||
/// Returning a dynamic color in your handler is unsupported and may panic.
|
/// Returning a dynamic color in your handler is unsupported and may panic.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub fn dynamic<F>(handler: F) -> Self
|
pub fn dynamic<F>(handler: F) -> Self
|
||||||
where
|
where
|
||||||
F: Fn(Style) -> Color + 'static
|
F: Fn(Style) -> Color + 'static
|
||||||
|
@ -345,7 +337,7 @@ impl Color {
|
||||||
// not entirely clear on how expensive the dynamic allocation would be pre-10.15/11.0 and
|
// not entirely clear on how expensive the dynamic allocation would be pre-10.15/11.0 and
|
||||||
// am happy to do this for now and let someone who needs true dynamic allocation look into
|
// am happy to do this for now and let someone who needs true dynamic allocation look into
|
||||||
// it and PR it.
|
// it and PR it.
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
Color::Custom(Arc::new(RwLock::new(unsafe {
|
Color::Custom(Arc::new(RwLock::new(unsafe {
|
||||||
let color: id = msg_send![macos_dynamic_color::register_class(), new];
|
let color: id = msg_send![macos_dynamic_color::register_class(), new];
|
||||||
|
|
||||||
|
@ -429,7 +421,7 @@ impl From<&Color> for id {
|
||||||
/// Handles color fallback for system-provided colors.
|
/// Handles color fallback for system-provided colors.
|
||||||
macro_rules! system_color_with_fallback {
|
macro_rules! system_color_with_fallback {
|
||||||
($class:ident, $color:ident, $fallback:ident) => ({
|
($class:ident, $color:ident, $fallback:ident) => ({
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
{
|
{
|
||||||
#[cfg(feature = "color-fallbacks")]
|
#[cfg(feature = "color-fallbacks")]
|
||||||
if os::minimum_semversion(10, 10, 0) {
|
if os::minimum_semversion(10, 10, 0) {
|
||||||
|
@ -441,6 +433,11 @@ macro_rules! system_color_with_fallback {
|
||||||
#[cfg(not(feature = "color-fallbacks"))]
|
#[cfg(not(feature = "color-fallbacks"))]
|
||||||
msg_send![$class, $color]
|
msg_send![$class, $color]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
|
{
|
||||||
|
msg_send![$class, $color]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,10 +450,10 @@ macro_rules! system_color_with_fallback {
|
||||||
/// The goal here is to make sure that this can't reasonably break on OS's, as `Color` is kind of
|
/// The goal here is to make sure that this can't reasonably break on OS's, as `Color` is kind of
|
||||||
/// an important piece. It's not on the framework to make your app look good, though.
|
/// an important piece. It's not on the framework to make your app look good, though.
|
||||||
unsafe fn to_objc(obj: &Color) -> id {
|
unsafe fn to_objc(obj: &Color) -> id {
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let color = class!(NSColor);
|
let color = class!(NSColor);
|
||||||
|
|
||||||
#[cfg(feature = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
let color = class!(UIColor);
|
let color = class!(UIColor);
|
||||||
|
|
||||||
match obj {
|
match obj {
|
||||||
|
@ -503,10 +500,10 @@ unsafe fn to_objc(obj: &Color) -> id {
|
||||||
Color::DarkText => system_color_with_fallback!(color, darkTextColor, blackColor),
|
Color::DarkText => system_color_with_fallback!(color, darkTextColor, blackColor),
|
||||||
Color::LightText => system_color_with_fallback!(color, lightTextColor, whiteColor),
|
Color::LightText => system_color_with_fallback!(color, lightTextColor, whiteColor),
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
Color::MacOSWindowBackgroundColor => system_color_with_fallback!(color, windowBackgroundColor, clearColor),
|
Color::MacOSWindowBackgroundColor => system_color_with_fallback!(color, windowBackgroundColor, clearColor),
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
Color::MacOSUnderPageBackgroundColor => system_color_with_fallback!(color, underPageBackgroundColor, clearColor),
|
Color::MacOSUnderPageBackgroundColor => system_color_with_fallback!(color, underPageBackgroundColor, clearColor),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
///
|
///
|
||||||
/// You can opt to include vector assets in your bundle, or draw icons with `Image::draw` by
|
/// You can opt to include vector assets in your bundle, or draw icons with `Image::draw` by
|
||||||
/// converting Core Graphics calls (e.g, PaintCode can work well for this).
|
/// converting Core Graphics calls (e.g, PaintCode can work well for this).
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum MacSystemIcon {
|
pub enum MacSystemIcon {
|
||||||
/// A standard "General" preferences icon. This is intended for usage in Preferences toolbars.
|
/// A standard "General" preferences icon. This is intended for usage in Preferences toolbars.
|
||||||
|
@ -26,7 +26,7 @@ pub enum MacSystemIcon {
|
||||||
Add
|
Add
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
impl MacSystemIcon {
|
impl MacSystemIcon {
|
||||||
/// Maps system icons to their pre-11.0 framework identifiers.
|
/// Maps system icons to their pre-11.0 framework identifiers.
|
||||||
pub fn to_str(&self) -> &'static str {
|
pub fn to_str(&self) -> &'static str {
|
||||||
|
|
|
@ -133,7 +133,7 @@ impl Image {
|
||||||
|
|
||||||
/// Returns a stock system icon. These are guaranteed to exist across all versions of macOS
|
/// Returns a stock system icon. These are guaranteed to exist across all versions of macOS
|
||||||
/// supported.
|
/// supported.
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn system_icon(icon: MacSystemIcon, accessibility_description: &str) -> Self {
|
pub fn system_icon(icon: MacSystemIcon, accessibility_description: &str) -> Self {
|
||||||
Image(unsafe {
|
Image(unsafe {
|
||||||
ShareId::from_ptr(match os::is_minimum_version(11) {
|
ShareId::from_ptr(match os::is_minimum_version(11) {
|
||||||
|
@ -166,7 +166,7 @@ impl Image {
|
||||||
},
|
},
|
||||||
|
|
||||||
false => {
|
false => {
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
panic!("SFSymbols are only supported on macOS 11.0 and up.");
|
panic!("SFSymbols are only supported on macOS 11.0 and up.");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -49,7 +49,7 @@ mod class;
|
||||||
use class::register_app_class;
|
use class::register_app_class;
|
||||||
|
|
||||||
mod delegate;
|
mod delegate;
|
||||||
use delegate::{register_app_delegate_class};
|
use delegate::register_app_delegate_class;
|
||||||
|
|
||||||
mod enums;
|
mod enums;
|
||||||
pub use enums::*;
|
pub use enums::*;
|
||||||
|
@ -95,6 +95,14 @@ pub struct App<
|
||||||
_w: std::marker::PhantomData<W>
|
_w: std::marker::PhantomData<W>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Temporary. ;P
|
||||||
|
impl<W, T, F> std::fmt::Debug for App<W, T, F> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("App<W, T, F>")
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T, W, F> App<T, W, F>
|
impl<T, W, F> App<T, W, F>
|
||||||
where
|
where
|
||||||
T: AppDelegate + 'static,
|
T: AppDelegate + 'static,
|
||||||
|
@ -134,8 +142,8 @@ where
|
||||||
|
|
||||||
App {
|
App {
|
||||||
delegate: app_delegate,
|
delegate: app_delegate,
|
||||||
vendor: vendor,
|
vendor,
|
||||||
pool: pool,
|
pool,
|
||||||
_w: std::marker::PhantomData
|
_w: std::marker::PhantomData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,14 +153,24 @@ impl<T, W, F> App<T, W, F> {
|
||||||
/// Handles calling through to `UIApplicationMain()`, ensuring that it's using our custom
|
/// Handles calling through to `UIApplicationMain()`, ensuring that it's using our custom
|
||||||
/// `UIApplication` and `UIApplicationDelegate` classes.
|
/// `UIApplication` and `UIApplicationDelegate` classes.
|
||||||
pub fn run(&self) {
|
pub fn run(&self) {
|
||||||
let args = std::env::args().map(|arg| CString::new(arg).unwrap() ).collect::<Vec<CString>>();
|
let args = std::env::args().map(|arg| {
|
||||||
let c_args = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<*const c_char>>();
|
CString::new(arg).unwrap()
|
||||||
|
}).collect::<Vec<CString>>();
|
||||||
|
|
||||||
|
let c_args = args.iter().map(|arg| {
|
||||||
|
arg.as_ptr()
|
||||||
|
}).collect::<Vec<*const c_char>>();
|
||||||
|
|
||||||
let s = NSString::no_copy("RSTApplication");
|
let mut s = NSString::new("RSTApplication");
|
||||||
let s2 = NSString::no_copy("RSTAppDelegate");
|
let mut s2 = NSString::new("RSTAppDelegate");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
UIApplicationMain(c_args.len() as c_int, c_args.as_ptr(), &*s, &*s2);
|
UIApplicationMain(
|
||||||
|
c_args.len() as c_int,
|
||||||
|
c_args.as_ptr(),
|
||||||
|
s.into(),
|
||||||
|
s2.into()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pool.drain();
|
self.pool.drain();
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
//! This module implements forwarding methods for standard `UIApplicationDelegate` calls. It also
|
|
||||||
//! creates a custom `UIApplication` subclass that currently does nothing; this is meant as a hook
|
|
||||||
//! for potential future use.
|
|
||||||
|
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
use std::unreachable;
|
use std::unreachable;
|
||||||
|
@ -39,7 +35,7 @@ extern fn init<
|
||||||
let factory: &F = &*scene_delegate_vendor;
|
let factory: &F = &*scene_delegate_vendor;
|
||||||
let scene_delegate = factory();
|
let scene_delegate = factory();
|
||||||
let scene_delegate_ptr = Box::into_raw(scene_delegate);
|
let scene_delegate_ptr = Box::into_raw(scene_delegate);
|
||||||
println!("scene ptr: {:p}", scene_delegate_ptr);
|
//println!("scene ptr: {:p}", scene_delegate_ptr);
|
||||||
this.set_ivar(WINDOW_SCENE_PTR, scene_delegate_ptr as usize);
|
this.set_ivar(WINDOW_SCENE_PTR, scene_delegate_ptr as usize);
|
||||||
|
|
||||||
this
|
this
|
||||||
|
|
|
@ -15,11 +15,11 @@ pub enum SessionRole {
|
||||||
|
|
||||||
impl From<SessionRole> for NSString<'_> {
|
impl From<SessionRole> for NSString<'_> {
|
||||||
fn from(role: SessionRole) -> Self {
|
fn from(role: SessionRole) -> Self {
|
||||||
NSString::new(match role {
|
match role {
|
||||||
SessionRole::Application => NSString::no_copy("UIWindowSceneSessionRoleApplication"),
|
SessionRole::Application => NSString::no_copy("UIWindowSceneSessionRoleApplication"),
|
||||||
SessionRole::ExternalDisplay => NSString::no_copy("UIWindowSceneSessionRoleExternalDisplay"),
|
SessionRole::ExternalDisplay => NSString::no_copy("UIWindowSceneSessionRoleExternalDisplay"),
|
||||||
//SessionRole::CarPlayApplication => ""
|
//SessionRole::CarPlayApplication => ""
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ impl SceneSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn role(&self) -> SessionRole {
|
pub fn role(&self) -> SessionRole {
|
||||||
NSString::wrap(unsafe {
|
NSString::from_retained(unsafe {
|
||||||
msg_send![&*self.0, role]
|
msg_send![&*self.0, role]
|
||||||
}).into()
|
}).into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ use objc_id::ShareId;
|
||||||
|
|
||||||
use crate::foundation::{id, nil, to_bool, YES, NO, NSArray, NSString};
|
use crate::foundation::{id, nil, to_bool, YES, NO, NSArray, NSString};
|
||||||
use crate::geometry::Rect;
|
use crate::geometry::Rect;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
use crate::pasteboard::PasteboardType;
|
use crate::pasteboard::PasteboardType;
|
||||||
|
|
||||||
/// A trait that view wrappers must conform to. Enables managing the subview tree.
|
/// A trait that view wrappers must conform to. Enables managing the subview tree.
|
||||||
|
@ -103,6 +105,7 @@ pub trait Layout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this is hidden, *or* whether an ancestor view is hidden.
|
/// Returns whether this is hidden, *or* whether an ancestor view is hidden.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
fn is_hidden_or_ancestor_is_hidden(&self) -> bool {
|
fn is_hidden_or_ancestor_is_hidden(&self) -> bool {
|
||||||
self.get_from_backing_node(|obj| {
|
self.get_from_backing_node(|obj| {
|
||||||
to_bool(unsafe {
|
to_bool(unsafe {
|
||||||
|
@ -112,6 +115,7 @@ pub trait Layout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register this view for drag and drop operations.
|
/// Register this view for drag and drop operations.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
fn register_for_dragged_types(&self, types: &[PasteboardType]) {
|
fn register_for_dragged_types(&self, types: &[PasteboardType]) {
|
||||||
let types: NSArray = types.into_iter().map(|t| {
|
let types: NSArray = types.into_iter().map(|t| {
|
||||||
let x: NSString = (*t).into();
|
let x: NSString = (*t).into();
|
||||||
|
@ -124,6 +128,7 @@ pub trait Layout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unregisters this as a target for drag and drop operations.
|
/// Unregisters this as a target for drag and drop operations.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
fn unregister_dragged_types(&self) {
|
fn unregister_dragged_types(&self) {
|
||||||
self.with_backing_node(|obj| unsafe {
|
self.with_backing_node(|obj| unsafe {
|
||||||
let _: () = msg_send![obj, unregisterDraggedTypes];
|
let _: () = msg_send![obj, unregisterDraggedTypes];
|
||||||
|
@ -134,6 +139,7 @@ pub trait Layout {
|
||||||
///
|
///
|
||||||
/// If you have a high performance tableview or collectionview that has issues, disabling these
|
/// If you have a high performance tableview or collectionview that has issues, disabling these
|
||||||
/// can be helpful - but always test!
|
/// can be helpful - but always test!
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
fn set_posts_frame_change_notifications(&self, posts: bool) {
|
fn set_posts_frame_change_notifications(&self, posts: bool) {
|
||||||
self.with_backing_node(|obj| unsafe {
|
self.with_backing_node(|obj| unsafe {
|
||||||
let _: () = msg_send![obj, setPostsFrameChangedNotifications:match posts {
|
let _: () = msg_send![obj, setPostsFrameChangedNotifications:match posts {
|
||||||
|
@ -147,6 +153,7 @@ pub trait Layout {
|
||||||
///
|
///
|
||||||
/// If you have a high performance tableview or collectionview that has issues, disabling these
|
/// If you have a high performance tableview or collectionview that has issues, disabling these
|
||||||
/// can be helpful - but always test!
|
/// can be helpful - but always test!
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
fn set_posts_bounds_change_notifications(&self, posts: bool) {
|
fn set_posts_bounds_change_notifications(&self, posts: bool) {
|
||||||
self.with_backing_node(|obj| unsafe {
|
self.with_backing_node(|obj| unsafe {
|
||||||
let _: () = msg_send![obj, setPostsBoundsChangedNotifications:match posts {
|
let _: () = msg_send![obj, setPostsBoundsChangedNotifications:match posts {
|
||||||
|
|
35
src/lib.rs
35
src/lib.rs
|
@ -96,14 +96,15 @@ pub use objc;
|
||||||
pub use url;
|
pub use url;
|
||||||
pub use lazy_static;
|
pub use lazy_static;
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "macos")))]
|
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
|
||||||
pub mod macos;
|
pub mod macos;
|
||||||
|
|
||||||
#[cfg(feature = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "ios")))]
|
#[cfg_attr(docsrs, doc(cfg(target_os = "ios")))]
|
||||||
pub mod ios;
|
pub mod ios;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub mod button;
|
pub mod button;
|
||||||
|
|
||||||
#[cfg(any(feature = "cloudkit", doc))]
|
#[cfg(any(feature = "cloudkit", doc))]
|
||||||
|
@ -111,25 +112,51 @@ pub mod button;
|
||||||
pub mod cloudkit;
|
pub mod cloudkit;
|
||||||
|
|
||||||
pub mod color;
|
pub mod color;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub mod dragdrop;
|
pub mod dragdrop;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub mod events;
|
pub mod events;
|
||||||
|
|
||||||
pub mod defaults;
|
pub mod defaults;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub mod filesystem;
|
pub mod filesystem;
|
||||||
|
|
||||||
pub mod foundation;
|
pub mod foundation;
|
||||||
pub mod geometry;
|
pub mod geometry;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub mod image;
|
pub mod image;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub mod input;
|
pub mod input;
|
||||||
|
|
||||||
pub mod layer;
|
pub mod layer;
|
||||||
pub(crate) mod invoker;
|
pub(crate) mod invoker;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub mod listview;
|
pub mod listview;
|
||||||
pub mod networking;
|
pub mod networking;
|
||||||
pub mod notification_center;
|
pub mod notification_center;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub mod pasteboard;
|
pub mod pasteboard;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub mod progress;
|
pub mod progress;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub mod scrollview;
|
pub mod scrollview;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub mod switch;
|
pub mod switch;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub mod text;
|
pub mod text;
|
||||||
|
|
||||||
#[cfg(feature = "quicklook")]
|
#[cfg(feature = "quicklook")]
|
||||||
|
|
|
@ -364,7 +364,7 @@ impl<T> ListView<T> {
|
||||||
|
|
||||||
/// Sets the style for the underlying NSTableView. This property is only supported on macOS
|
/// Sets the style for the underlying NSTableView. This property is only supported on macOS
|
||||||
/// 11.0+, and will always be `FullWidth` on anything older.
|
/// 11.0+, and will always be `FullWidth` on anything older.
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn set_style(&self, style: crate::foundation::NSInteger) {
|
pub fn set_style(&self, style: crate::foundation::NSInteger) {
|
||||||
if os::is_minimum_version(11) {
|
if os::is_minimum_version(11) {
|
||||||
self.objc.with_mut(|obj| unsafe {
|
self.objc.with_mut(|obj| unsafe {
|
||||||
|
@ -378,7 +378,7 @@ impl<T> ListView<T> {
|
||||||
/// This defaults to `true`, but some macOS pieces (e.g, a sidebar) may want this set to
|
/// This defaults to `true`, but some macOS pieces (e.g, a sidebar) may want this set to
|
||||||
/// `false`. This can be particularly useful when implementing a Source List style sidebar
|
/// `false`. This can be particularly useful when implementing a Source List style sidebar
|
||||||
/// view for navigation purposes.
|
/// view for navigation purposes.
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn set_allows_empty_selection(&self, allows: bool) {
|
pub fn set_allows_empty_selection(&self, allows: bool) {
|
||||||
self.objc.with_mut(|obj| unsafe {
|
self.objc.with_mut(|obj| unsafe {
|
||||||
let _: () = msg_send![obj, setAllowsEmptySelection:match allows {
|
let _: () = msg_send![obj, setAllowsEmptySelection:match allows {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use crate::foundation::{NSUInteger};
|
use crate::foundation::{NSUInteger};
|
||||||
|
|
||||||
/// Used to set whether and/or how a view or cell draws a focus ring.
|
/// Used to set whether and/or how a view or cell draws a focus ring.
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FocusRingType {
|
pub enum FocusRingType {
|
||||||
/// Whatever the default is.
|
/// Whatever the default is.
|
||||||
|
@ -20,7 +20,7 @@ pub enum FocusRingType {
|
||||||
Unknown(NSUInteger)
|
Unknown(NSUInteger)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
impl From<FocusRingType> for NSUInteger {
|
impl From<FocusRingType> for NSUInteger {
|
||||||
fn from(ring_type: FocusRingType) -> Self {
|
fn from(ring_type: FocusRingType) -> Self {
|
||||||
match ring_type {
|
match ring_type {
|
||||||
|
|
|
@ -79,11 +79,11 @@ impl ProgressIndicator {
|
||||||
/// need it to stay around.
|
/// need it to stay around.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let view = unsafe {
|
let view = unsafe {
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let view: id = msg_send![class!(NSProgressIndicator), new];
|
let view: id = msg_send![class!(NSProgressIndicator), new];
|
||||||
let _: () = msg_send![view, setTranslatesAutoresizingMaskIntoConstraints:NO];
|
let _: () = msg_send![view, setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||||
|
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let _: () = msg_send![view, setWantsLayer:YES];
|
let _: () = msg_send![view, setWantsLayer:YES];
|
||||||
|
|
||||||
view
|
view
|
||||||
|
|
|
@ -5,9 +5,10 @@ use objc::declare::ClassDecl;
|
||||||
use objc::runtime::{Class, Object, Sel};
|
use objc::runtime::{Class, Object, Sel};
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
|
||||||
use crate::foundation::{BOOL};
|
use crate::foundation::load_or_register_class;
|
||||||
|
use crate::foundation::{BOOL, to_bool};
|
||||||
use crate::view::{VIEW_DELEGATE_PTR, ViewDelegate};
|
use crate::view::{VIEW_DELEGATE_PTR, ViewDelegate};
|
||||||
use crate::utils::{load, as_bool};
|
use crate::utils::load;
|
||||||
|
|
||||||
/// Called when the view controller receives a `viewWillAppear:` message.
|
/// Called when the view controller receives a `viewWillAppear:` message.
|
||||||
extern fn will_appear<T: ViewDelegate>(this: &mut Object, _: Sel, animated: BOOL) {
|
extern fn will_appear<T: ViewDelegate>(this: &mut Object, _: Sel, animated: BOOL) {
|
||||||
|
@ -16,7 +17,7 @@ extern fn will_appear<T: ViewDelegate>(this: &mut Object, _: Sel, animated: BOOL
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = load::<T>(this, VIEW_DELEGATE_PTR);
|
let controller = load::<T>(this, VIEW_DELEGATE_PTR);
|
||||||
controller.will_appear(as_bool(animated));
|
controller.will_appear(to_bool(animated));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the view controller receives a `viewDidAppear:` message.
|
/// Called when the view controller receives a `viewDidAppear:` message.
|
||||||
|
@ -26,7 +27,7 @@ extern fn did_appear<T: ViewDelegate>(this: &mut Object, _: Sel, animated: BOOL)
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = load::<T>(this, VIEW_DELEGATE_PTR);
|
let controller = load::<T>(this, VIEW_DELEGATE_PTR);
|
||||||
controller.did_appear(as_bool(animated));
|
controller.did_appear(to_bool(animated));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the view controller receives a `viewWillDisappear:` message.
|
/// Called when the view controller receives a `viewWillDisappear:` message.
|
||||||
|
@ -36,7 +37,7 @@ extern fn will_disappear<T: ViewDelegate>(this: &mut Object, _: Sel, animated: B
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = load::<T>(this, VIEW_DELEGATE_PTR);
|
let controller = load::<T>(this, VIEW_DELEGATE_PTR);
|
||||||
controller.will_disappear(as_bool(animated));
|
controller.will_disappear(to_bool(animated));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the view controller receives a `viewDidDisappear:` message.
|
/// Called when the view controller receives a `viewDidDisappear:` message.
|
||||||
|
@ -46,27 +47,17 @@ extern fn did_disappear<T: ViewDelegate>(this: &mut Object, _: Sel, animated: BO
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = load::<T>(this, VIEW_DELEGATE_PTR);
|
let controller = load::<T>(this, VIEW_DELEGATE_PTR);
|
||||||
controller.did_disappear(as_bool(animated));
|
controller.did_disappear(to_bool(animated));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers an `NSViewDelegate`.
|
/// Registers an `NSViewDelegate`.
|
||||||
pub(crate) fn register_view_controller_class<T: ViewDelegate + 'static>() -> *const Class {
|
pub(crate) fn register_view_controller_class<T: ViewDelegate + 'static>(instance: &T) -> *const Class {
|
||||||
static mut VIEW_CLASS: *const Class = 0 as *const Class;
|
load_or_register_class("UIViewController", instance.subclass_name(), |decl| unsafe {
|
||||||
static INIT: Once = Once::new();
|
|
||||||
|
|
||||||
INIT.call_once(|| unsafe {
|
|
||||||
let superclass = class!(UIViewController);
|
|
||||||
let mut decl = ClassDecl::new("RSTViewController", superclass).unwrap();
|
|
||||||
|
|
||||||
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
|
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
|
||||||
|
|
||||||
decl.add_method(sel!(viewWillAppear:), will_appear::<T> as extern fn(&mut Object, _, BOOL));
|
decl.add_method(sel!(viewWillAppear:), will_appear::<T> as extern fn(&mut Object, _, BOOL));
|
||||||
decl.add_method(sel!(viewDidAppear:), did_appear::<T> as extern fn(&mut Object, _, BOOL));
|
decl.add_method(sel!(viewDidAppear:), did_appear::<T> as extern fn(&mut Object, _, BOOL));
|
||||||
decl.add_method(sel!(viewWillDisappear:), will_disappear::<T> as extern fn(&mut Object, _, BOOL));
|
decl.add_method(sel!(viewWillDisappear:), will_disappear::<T> as extern fn(&mut Object, _, BOOL));
|
||||||
decl.add_method(sel!(viewDidDisappear:), did_disappear::<T> as extern fn(&mut Object, _, BOOL));
|
decl.add_method(sel!(viewDidDisappear:), did_disappear::<T> as extern fn(&mut Object, _, BOOL));
|
||||||
|
})
|
||||||
VIEW_CLASS = decl.register();
|
|
||||||
});
|
|
||||||
|
|
||||||
unsafe { VIEW_CLASS }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ 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::load_or_register_class;
|
||||||
use crate::foundation::{id, YES, NO, NSUInteger};
|
use crate::foundation::{id, YES, NO, NSUInteger};
|
||||||
use crate::dragdrop::DragInfo;
|
|
||||||
use crate::view::{VIEW_DELEGATE_PTR, ViewDelegate};
|
use crate::view::{VIEW_DELEGATE_PTR, ViewDelegate};
|
||||||
use crate::utils::load;
|
use crate::utils::load;
|
||||||
|
|
||||||
|
@ -26,20 +26,10 @@ pub(crate) fn register_view_class() -> *const Class {
|
||||||
unsafe { VIEW_CLASS }
|
unsafe { VIEW_CLASS }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Injects an `NSView` subclass, with some callback and pointer ivars for what we
|
/// Injects a `UIView` subclass, with some callback and pointer ivars for what we
|
||||||
/// need to do.
|
/// need to do.
|
||||||
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>() -> *const Class {
|
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>(instance: &T) -> *const Class {
|
||||||
static mut VIEW_CLASS: *const Class = 0 as *const Class;
|
load_or_register_class("UIView", instance.subclass_name(), |decl| unsafe {
|
||||||
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);
|
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
|
||||||
VIEW_CLASS = decl.register();
|
})
|
||||||
});
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
VIEW_CLASS
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,9 +48,11 @@ use crate::foundation::{id, nil, YES, NO, NSArray, NSString};
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::layer::Layer;
|
use crate::layer::Layer;
|
||||||
use crate::layout::{Layout, LayoutAnchorX, LayoutAnchorY, LayoutAnchorDimension};
|
use crate::layout::{Layout, LayoutAnchorX, LayoutAnchorY, LayoutAnchorDimension};
|
||||||
use crate::pasteboard::PasteboardType;
|
|
||||||
use crate::utils::properties::ObjcProperty;
|
use crate::utils::properties::ObjcProperty;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
use crate::pasteboard::PasteboardType;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
mod macos;
|
mod macos;
|
||||||
|
|
||||||
|
@ -66,7 +68,9 @@ use ios::{register_view_class, register_view_class_with_delegate};
|
||||||
mod controller;
|
mod controller;
|
||||||
pub use controller::ViewController;
|
pub use controller::ViewController;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
mod splitviewcontroller;
|
mod splitviewcontroller;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
pub use splitviewcontroller::SplitViewController;
|
pub use splitviewcontroller::SplitViewController;
|
||||||
|
|
||||||
mod traits;
|
mod traits;
|
||||||
|
@ -227,9 +231,15 @@ impl<T> View<T> {
|
||||||
pub fn set_background_color<C: AsRef<Color>>(&self, color: C) {
|
pub fn set_background_color<C: AsRef<Color>>(&self, color: C) {
|
||||||
let color: id = color.as_ref().into();
|
let color: id = color.as_ref().into();
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
self.objc.with_mut(|obj| unsafe {
|
self.objc.with_mut(|obj| unsafe {
|
||||||
(&mut *obj).set_ivar(BACKGROUND_COLOR, color);
|
(&mut *obj).set_ivar(BACKGROUND_COLOR, color);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
|
self.objc.with_mut(|obj| unsafe {
|
||||||
|
let _: () = msg_send![&*obj, setBackgroundColor:color];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ where
|
||||||
/// You'd use this if, say, you wanted a border under one part of the `SplitViewController` but
|
/// You'd use this if, say, you wanted a border under one part of the `SplitViewController` but
|
||||||
/// not the other. This API was introduced in macOS 11.0 (Big Sur) and is a noop on anything
|
/// not the other. This API was introduced in macOS 11.0 (Big Sur) and is a noop on anything
|
||||||
/// prior.
|
/// prior.
|
||||||
#[cfg(feature = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn set_titlebar_separator_style(&self, style: crate::foundation::NSInteger) {
|
pub fn set_titlebar_separator_style(&self, style: crate::foundation::NSInteger) {
|
||||||
if os::is_minimum_version(11) {
|
if os::is_minimum_version(11) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
//! Various traits used for Views.
|
//! Various traits used for Views.
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
use crate::dragdrop::{DragInfo, DragOperation};
|
use crate::dragdrop::{DragInfo, DragOperation};
|
||||||
|
|
||||||
use crate::view::View;
|
use crate::view::View;
|
||||||
|
|
||||||
/// This trait can be used for implementing custom View behavior. You implement this trait on your
|
/// This trait can be used for implementing custom View behavior. You implement this trait on your
|
||||||
|
@ -41,22 +43,27 @@ pub trait ViewDelegate {
|
||||||
|
|
||||||
/// Invoked when the dragged image enters destination bounds or frame; returns dragging
|
/// Invoked when the dragged image enters destination bounds or frame; returns dragging
|
||||||
/// operation to perform.
|
/// operation to perform.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
fn dragging_entered(&self, info: DragInfo) -> DragOperation { DragOperation::None }
|
fn dragging_entered(&self, info: DragInfo) -> DragOperation { DragOperation::None }
|
||||||
|
|
||||||
/// Invoked when the image is released, allowing the receiver to agree to or refuse
|
/// Invoked when the image is released, allowing the receiver to agree to or refuse
|
||||||
/// drag operation.
|
/// drag operation.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
fn prepare_for_drag_operation(&self, info: DragInfo) -> bool { false }
|
fn prepare_for_drag_operation(&self, info: DragInfo) -> bool { false }
|
||||||
|
|
||||||
/// Invoked after the released image has been removed from the screen, signaling the
|
/// Invoked after the released image has been removed from the screen, signaling the
|
||||||
/// receiver to import the pasteboard data.
|
/// receiver to import the pasteboard data.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
fn perform_drag_operation(&self, info: DragInfo) -> bool { false }
|
fn perform_drag_operation(&self, info: DragInfo) -> bool { false }
|
||||||
|
|
||||||
/// Invoked when the dragging operation is complete, signaling the receiver to perform
|
/// Invoked when the dragging operation is complete, signaling the receiver to perform
|
||||||
/// any necessary clean-up.
|
/// any necessary clean-up.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
fn conclude_drag_operation(&self, info: DragInfo) {}
|
fn conclude_drag_operation(&self, info: DragInfo) {}
|
||||||
|
|
||||||
/// Invoked when the dragged image exits the destination’s bounds rectangle (in the case
|
/// Invoked when the dragged image exits the destination’s bounds rectangle (in the case
|
||||||
/// of a view) or its frame rectangle (in the case of a window object).
|
/// of a view) or its frame rectangle (in the case of a window object).
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
fn dragging_exited(&self, info: DragInfo) {}
|
fn dragging_exited(&self, info: DragInfo) {}
|
||||||
|
|
||||||
//fn perform_key_equivalent(&self, event: Event) -> bool { false }
|
//fn perform_key_equivalent(&self, event: Event) -> bool { false }
|
||||||
|
|
Loading…
Reference in a new issue