cacao/src/view/appkit.rs

164 lines
5.5 KiB
Rust
Raw Normal View History

//! This module does one specific thing: register a custom `NSView` class that's... brought to the
//! modern era.
//!
//! I kid, I kid.
//!
//! It just enforces that coordinates are judged from the top-left, which is what most people look
//! for in the modern era. It also implements a few helpers for things like setting a background
//! color, and enforcing layer backing by default.
use std::sync::Once;
use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel, BOOL};
Begin reworking many internals to push for v0.1. - Beginning to transition View types to use Rc/RefCell internally, which should provide better guarantees about ownership on the Rust side. This is also important for certain Objective-C side scenarios where we may need to set an ivar after creation, which requires some level of mutability. This may also possibly help bring down the unsafe usage, which would be cool. - Rewrote the Color module; this now handles system colors better, and provides support for dynamic color creation. Supporting combinations of dark/light/contrast is now possible with handler passed in via `Color::dynamic`. This still has work to do in terms of some accessor methods and such, but it works well for now. The `to_platform...` method should be removed before v0.1. - Added a new feature for enabling fallback color usage on older macOS versions that don't support system colors. This may honestly never be used, but it cost nothing to implement. - Fixed a bug in the Autolayout wrapper where dereferencing could cause constraints to crash at runtime. - Support setting text color on labels. - Support setting text color on buttons, albeit very hacky right now. This needs to be extracted and/or cleaned up, but getting it sketched out was important for this commit. - Support setting a key equivalent on buttons. - Creating a local event monitor is now possible. - Examples updated; Calculator clone example added. The only API breaking change in this commit from earlier commits should be `color::rgb` needing to be `color::Color` followed by a `Color::rgb(...)` call.
2021-02-12 17:57:06 -08:00
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
Begin reworking many internals to push for v0.1. - Beginning to transition View types to use Rc/RefCell internally, which should provide better guarantees about ownership on the Rust side. This is also important for certain Objective-C side scenarios where we may need to set an ivar after creation, which requires some level of mutability. This may also possibly help bring down the unsafe usage, which would be cool. - Rewrote the Color module; this now handles system colors better, and provides support for dynamic color creation. Supporting combinations of dark/light/contrast is now possible with handler passed in via `Color::dynamic`. This still has work to do in terms of some accessor methods and such, but it works well for now. The `to_platform...` method should be removed before v0.1. - Added a new feature for enabling fallback color usage on older macOS versions that don't support system colors. This may honestly never be used, but it cost nothing to implement. - Fixed a bug in the Autolayout wrapper where dereferencing could cause constraints to crash at runtime. - Support setting text color on labels. - Support setting text color on buttons, albeit very hacky right now. This needs to be extracted and/or cleaned up, but getting it sketched out was important for this commit. - Support setting a key equivalent on buttons. - Creating a local event monitor is now possible. - Examples updated; Calculator clone example added. The only API breaking change in this commit from earlier commits should be `color::rgb` needing to be `color::Color` followed by a `Color::rgb(...)` call.
2021-02-12 17:57:06 -08:00
use crate::foundation::{load_or_register_class, id, nil, YES, NO, NSUInteger};
use crate::dragdrop::DragInfo;
Begin reworking many internals to push for v0.1. - Beginning to transition View types to use Rc/RefCell internally, which should provide better guarantees about ownership on the Rust side. This is also important for certain Objective-C side scenarios where we may need to set an ivar after creation, which requires some level of mutability. This may also possibly help bring down the unsafe usage, which would be cool. - Rewrote the Color module; this now handles system colors better, and provides support for dynamic color creation. Supporting combinations of dark/light/contrast is now possible with handler passed in via `Color::dynamic`. This still has work to do in terms of some accessor methods and such, but it works well for now. The `to_platform...` method should be removed before v0.1. - Added a new feature for enabling fallback color usage on older macOS versions that don't support system colors. This may honestly never be used, but it cost nothing to implement. - Fixed a bug in the Autolayout wrapper where dereferencing could cause constraints to crash at runtime. - Support setting text color on labels. - Support setting text color on buttons, albeit very hacky right now. This needs to be extracted and/or cleaned up, but getting it sketched out was important for this commit. - Support setting a key equivalent on buttons. - Creating a local event monitor is now possible. - Examples updated; Calculator clone example added. The only API breaking change in this commit from earlier commits should be `color::rgb` needing to be `color::Color` followed by a `Color::rgb(...)` call.
2021-02-12 17:57:06 -08:00
use crate::view::{VIEW_DELEGATE_PTR, BACKGROUND_COLOR, ViewDelegate};
use crate::utils::load;
/// Enforces normalcy, or: a needlessly cruel method in terms of the name. You get the idea though.
extern fn enforce_normalcy(_: &Object, _: Sel) -> BOOL {
return YES;
}
/// Called when a drag/drop operation has entered this view.
extern fn dragging_entered<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
let view = load::<T>(this, VIEW_DELEGATE_PTR);
view.dragging_entered(DragInfo {
info: unsafe { Id::from_ptr(info) }
}).into()
}
/// Called when a drag/drop operation has entered this view.
extern fn prepare_for_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL {
let view = load::<T>(this, VIEW_DELEGATE_PTR);
match view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
}
/// Called when a drag/drop operation has entered this view.
extern fn perform_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL {
let view = load::<T>(this, VIEW_DELEGATE_PTR);
match view.perform_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
}
/// Called when a drag/drop operation has entered this view.
extern fn conclude_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) {
let view = load::<T>(this, VIEW_DELEGATE_PTR);
view.conclude_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
});
}
/// Called when a drag/drop operation has entered this view.
extern fn dragging_exited<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) {
let view = load::<T>(this, VIEW_DELEGATE_PTR);
view.dragging_exited(DragInfo {
info: unsafe { Id::from_ptr(info) }
});
}
Begin reworking many internals to push for v0.1. - Beginning to transition View types to use Rc/RefCell internally, which should provide better guarantees about ownership on the Rust side. This is also important for certain Objective-C side scenarios where we may need to set an ivar after creation, which requires some level of mutability. This may also possibly help bring down the unsafe usage, which would be cool. - Rewrote the Color module; this now handles system colors better, and provides support for dynamic color creation. Supporting combinations of dark/light/contrast is now possible with handler passed in via `Color::dynamic`. This still has work to do in terms of some accessor methods and such, but it works well for now. The `to_platform...` method should be removed before v0.1. - Added a new feature for enabling fallback color usage on older macOS versions that don't support system colors. This may honestly never be used, but it cost nothing to implement. - Fixed a bug in the Autolayout wrapper where dereferencing could cause constraints to crash at runtime. - Support setting text color on labels. - Support setting text color on buttons, albeit very hacky right now. This needs to be extracted and/or cleaned up, but getting it sketched out was important for this commit. - Support setting a key equivalent on buttons. - Creating a local event monitor is now possible. - Examples updated; Calculator clone example added. The only API breaking change in this commit from earlier commits should be `color::rgb` needing to be `color::Color` followed by a `Color::rgb(...)` call.
2021-02-12 17:57:06 -08:00
/// Called for layer updates.
extern fn update_layer(this: &Object, _: Sel) {
unsafe {
let background_color: id = *this.get_ivar(BACKGROUND_COLOR);
if background_color != nil {
let layer: id = msg_send![this, layer];
let cg: id = msg_send![background_color, CGColor];
let _: () = msg_send![layer, setBackgroundColor:cg];
}
}
}
/// 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
/// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
static INIT: Once = Once::new();
INIT.call_once(|| unsafe {
let superclass = class!(NSView);
let mut decl = ClassDecl::new("RSTView", superclass).unwrap();
decl.add_method(sel!(isFlipped), enforce_normalcy as extern fn(&Object, _) -> BOOL);
Begin reworking many internals to push for v0.1. - Beginning to transition View types to use Rc/RefCell internally, which should provide better guarantees about ownership on the Rust side. This is also important for certain Objective-C side scenarios where we may need to set an ivar after creation, which requires some level of mutability. This may also possibly help bring down the unsafe usage, which would be cool. - Rewrote the Color module; this now handles system colors better, and provides support for dynamic color creation. Supporting combinations of dark/light/contrast is now possible with handler passed in via `Color::dynamic`. This still has work to do in terms of some accessor methods and such, but it works well for now. The `to_platform...` method should be removed before v0.1. - Added a new feature for enabling fallback color usage on older macOS versions that don't support system colors. This may honestly never be used, but it cost nothing to implement. - Fixed a bug in the Autolayout wrapper where dereferencing could cause constraints to crash at runtime. - Support setting text color on labels. - Support setting text color on buttons, albeit very hacky right now. This needs to be extracted and/or cleaned up, but getting it sketched out was important for this commit. - Support setting a key equivalent on buttons. - Creating a local event monitor is now possible. - Examples updated; Calculator clone example added. The only API breaking change in this commit from earlier commits should be `color::rgb` needing to be `color::Color` followed by a `Color::rgb(...)` call.
2021-02-12 17:57:06 -08:00
decl.add_method(sel!(updateLayer), update_layer as extern fn(&Object, _));
decl.add_method(sel!(wantsUpdateLayer), enforce_normalcy as extern fn(&Object, _) -> BOOL);
decl.add_ivar::<id>(BACKGROUND_COLOR);
VIEW_CLASS = decl.register();
});
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>(instance: &T) -> *const Class {
load_or_register_class("NSView", instance.subclass_name(), |decl| unsafe {
// A pointer to the ViewDelegate instance on the Rust side.
// It's expected that this doesn't move.
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
Begin reworking many internals to push for v0.1. - Beginning to transition View types to use Rc/RefCell internally, which should provide better guarantees about ownership on the Rust side. This is also important for certain Objective-C side scenarios where we may need to set an ivar after creation, which requires some level of mutability. This may also possibly help bring down the unsafe usage, which would be cool. - Rewrote the Color module; this now handles system colors better, and provides support for dynamic color creation. Supporting combinations of dark/light/contrast is now possible with handler passed in via `Color::dynamic`. This still has work to do in terms of some accessor methods and such, but it works well for now. The `to_platform...` method should be removed before v0.1. - Added a new feature for enabling fallback color usage on older macOS versions that don't support system colors. This may honestly never be used, but it cost nothing to implement. - Fixed a bug in the Autolayout wrapper where dereferencing could cause constraints to crash at runtime. - Support setting text color on labels. - Support setting text color on buttons, albeit very hacky right now. This needs to be extracted and/or cleaned up, but getting it sketched out was important for this commit. - Support setting a key equivalent on buttons. - Creating a local event monitor is now possible. - Examples updated; Calculator clone example added. The only API breaking change in this commit from earlier commits should be `color::rgb` needing to be `color::Color` followed by a `Color::rgb(...)` call.
2021-02-12 17:57:06 -08:00
decl.add_ivar::<id>(BACKGROUND_COLOR);
Begin reworking many internals to push for v0.1. - Beginning to transition View types to use Rc/RefCell internally, which should provide better guarantees about ownership on the Rust side. This is also important for certain Objective-C side scenarios where we may need to set an ivar after creation, which requires some level of mutability. This may also possibly help bring down the unsafe usage, which would be cool. - Rewrote the Color module; this now handles system colors better, and provides support for dynamic color creation. Supporting combinations of dark/light/contrast is now possible with handler passed in via `Color::dynamic`. This still has work to do in terms of some accessor methods and such, but it works well for now. The `to_platform...` method should be removed before v0.1. - Added a new feature for enabling fallback color usage on older macOS versions that don't support system colors. This may honestly never be used, but it cost nothing to implement. - Fixed a bug in the Autolayout wrapper where dereferencing could cause constraints to crash at runtime. - Support setting text color on labels. - Support setting text color on buttons, albeit very hacky right now. This needs to be extracted and/or cleaned up, but getting it sketched out was important for this commit. - Support setting a key equivalent on buttons. - Creating a local event monitor is now possible. - Examples updated; Calculator clone example added. The only API breaking change in this commit from earlier commits should be `color::rgb` needing to be `color::Color` followed by a `Color::rgb(...)` call.
2021-02-12 17:57:06 -08:00
decl.add_method(
sel!(updateLayer),
update_layer as extern fn(&Object, _)
);
decl.add_method(
sel!(wantsUpdateLayer),
enforce_normalcy as extern fn(&Object, _) -> BOOL
);
decl.add_method(
sel!(isFlipped),
enforce_normalcy as extern fn(&Object, _) -> BOOL
);
// Drag and drop operations (e.g, accepting files)
decl.add_method(
sel!(draggingEntered:),
dragging_entered::<T> as extern fn (&mut Object, _, _) -> NSUInteger
);
decl.add_method(
sel!(prepareForDragOperation:),
prepare_for_drag_operation::<T> as extern fn (&mut Object, _, _) -> BOOL
);
decl.add_method(
sel!(performDragOperation:),
perform_drag_operation::<T> as extern fn (&mut Object, _, _) -> BOOL
);
decl.add_method(
sel!(concludeDragOperation:),
conclude_drag_operation::<T> as extern fn (&mut Object, _, _)
);
decl.add_method(
sel!(draggingExited:),
dragging_exited::<T> as extern fn (&mut Object, _, _)
);
})
}