Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add trait to get layout anchors for a view #108

Open
wants to merge 6 commits into
base: trunk
Choose a base branch
from
2 changes: 1 addition & 1 deletion examples/frame_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use cacao::color::Color;
use cacao::geometry::Rect;
use cacao::layout::Layout;
use cacao::layout::{Frame, Layout};
use cacao::view::View;

use cacao::appkit::menu::{Menu, MenuItem};
Expand Down
16 changes: 8 additions & 8 deletions src/appkit/segmentedcontrol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
use std::fmt;
use std::sync::Once;

use std::cell::RefCell;
use std::cell::{Ref, RefCell};
use std::rc::Rc;

use objc::declare::ClassDecl;
use objc::rc::{Id, Shared};
use objc::rc::{Id, Owned, Shared};
use objc::runtime::{Class, Object, Sel};
use objc::{class, msg_send, msg_send_id, sel};

Expand Down Expand Up @@ -293,25 +293,25 @@ impl SegmentedControl {
}

impl ObjcAccess for SegmentedControl {
fn with_backing_obj_mut<F: Fn(id)>(&self, handler: F) {
fn with_backing_obj_mut(&self, handler: &dyn Fn(id)) {
self.objc.with_mut(handler);
}

fn get_from_backing_obj<F: Fn(&Object) -> R, R>(&self, handler: F) -> R {
self.objc.get(handler)
fn get_backing_obj(&self) -> Ref<'_, Id<Object, Owned>> {
self.objc.get_ref()
}
}

impl Layout for SegmentedControl {}
impl Control for SegmentedControl {}

impl ObjcAccess for &SegmentedControl {
fn with_backing_obj_mut<F: Fn(id)>(&self, handler: F) {
fn with_backing_obj_mut(&self, handler: &dyn Fn(id)) {
self.objc.with_mut(handler);
}

fn get_from_backing_obj<F: Fn(&Object) -> R, R>(&self, handler: F) -> R {
self.objc.get(handler)
fn get_backing_obj(&self) -> Ref<'_, Id<Object, Owned>> {
self.objc.get_ref()
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/appkit/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ impl<T> Window<T> {
}
/// Given a view, sets it as the content view for this window.
pub fn set_content_view<L: Layout + 'static>(&self, view: &L) {
view.with_backing_obj_mut(|backing_node| unsafe {
view.with_backing_obj_mut(&|backing_node| unsafe {
let _: () = msg_send![&*self.objc, setContentView:&*backing_node];
});
}
Expand Down
16 changes: 9 additions & 7 deletions src/button/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
//! my_view.add_subview(&button);
//! ```

use objc::rc::{Id, Shared};
use std::cell::Ref;

use objc::rc::{Id, Owned, Shared};
use objc::runtime::{Class, Object};
use objc::{msg_send, msg_send_id, sel};

Expand Down Expand Up @@ -311,12 +313,12 @@ impl Button {
}

impl ObjcAccess for Button {
fn with_backing_obj_mut<F: Fn(id)>(&self, handler: F) {
fn with_backing_obj_mut(&self, handler: &dyn Fn(id)) {
self.objc.with_mut(handler);
}

fn get_from_backing_obj<F: Fn(&Object) -> R, R>(&self, handler: F) -> R {
self.objc.get(handler)
fn get_backing_obj(&self) -> Ref<'_, Id<Object, Owned>> {
self.objc.get_ref()
}
}

Expand All @@ -325,12 +327,12 @@ impl Layout for Button {}
impl Control for Button {}

impl ObjcAccess for &Button {
fn with_backing_obj_mut<F: Fn(id)>(&self, handler: F) {
fn with_backing_obj_mut(&self, handler: &dyn Fn(id)) {
self.objc.with_mut(handler);
}

fn get_from_backing_obj<F: Fn(&Object) -> R, R>(&self, handler: F) -> R {
self.objc.get(handler)
fn get_backing_obj(&self) -> Ref<'_, Id<Object, Owned>> {
self.objc.get_ref()
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/control/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub enum ControlSize {
pub trait Control: ObjcAccess {
/// Whether this control is enabled or not.
fn set_enabled(&self, is_enabled: bool) {
self.with_backing_obj_mut(|obj| unsafe {
self.with_backing_obj_mut(&|obj| unsafe {
let _: () = msg_send![obj, setEnabled:match is_enabled {
true => YES,
false => NO
Expand All @@ -48,7 +48,7 @@ pub trait Control: ObjcAccess {
}
};

self.with_backing_obj_mut(|obj| unsafe {
self.with_backing_obj_mut(&|obj| unsafe {
let _: () = msg_send![obj, setControlSize: control_size];
});
}
Expand Down
10 changes: 6 additions & 4 deletions src/image/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::cell::Ref;

use core_foundation::base::TCFType;

use objc::rc::{Id, Shared};
use objc::rc::{Id, Owned, Shared};
use objc::runtime::{Class, Object};
use objc::{msg_send, msg_send_id, sel};

Expand Down Expand Up @@ -174,12 +176,12 @@ impl ImageView {
}

impl ObjcAccess for ImageView {
fn with_backing_obj_mut<F: Fn(id)>(&self, handler: F) {
fn with_backing_obj_mut(&self, handler: &dyn Fn(id)) {
self.objc.with_mut(handler);
}

fn get_from_backing_obj<F: Fn(&Object) -> R, R>(&self, handler: F) -> R {
self.objc.get(handler)
fn get_backing_obj(&self) -> Ref<'_, Id<Object, Owned>> {
self.objc.get_ref()
}
}

Expand Down
10 changes: 6 additions & 4 deletions src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@
//!
//! For more information on Autolayout, view the module or check out the examples folder.

use std::cell::Ref;

use core_foundation::base::TCFType;

use objc::rc::{Id, Shared};
use objc::rc::{Id, Owned, Shared};
use objc::runtime::{Class, Object};
use objc::{class, msg_send, sel};

Expand Down Expand Up @@ -389,12 +391,12 @@ impl<T> TextField<T> {
}

impl<T> ObjcAccess for TextField<T> {
fn with_backing_obj_mut<F: Fn(id)>(&self, handler: F) {
fn with_backing_obj_mut(&self, handler: &dyn Fn(id)) {
self.objc.with_mut(handler);
}

fn get_from_backing_obj<F: Fn(&Object) -> R, R>(&self, handler: F) -> R {
self.objc.get(handler)
fn get_backing_obj(&self) -> Ref<'_, Id<Object, Owned>> {
self.objc.get_ref()
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! more complicated views that need to deal with differing screen sizes.

mod traits;
pub use traits::Layout;
pub use traits::{Frame, Layout};

#[cfg(all(feature = "appkit", target_os = "macos"))]
mod animator;
Expand Down
85 changes: 58 additions & 27 deletions src/layout/traits.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Various traits related to controllers opting in to autolayout routines and support for view
//! heirarchies.

use objc::msg_send_id;

use core_graphics::base::CGFloat;
use core_graphics::geometry::{CGPoint, CGRect, CGSize};

Expand All @@ -15,6 +17,8 @@ use crate::objc_access::ObjcAccess;
#[cfg(feature = "appkit")]
use crate::pasteboard::PasteboardType;

use super::{LayoutAnchorX, LayoutAnchorY};

/// A trait that view wrappers must conform to. Enables managing the subview tree.
#[allow(unused_variables)]
pub trait Layout: ObjcAccess {
Expand All @@ -24,7 +28,7 @@ pub trait Layout: ObjcAccess {
/// pass from the system will redraw it accordingly, and set the underlying value back to
/// `false`.
fn set_needs_display(&self, needs_display: bool) {
self.with_backing_obj_mut(|obj| unsafe {
self.with_backing_obj_mut(&|obj| unsafe {
let _: () = msg_send![obj, setNeedsDisplay:match needs_display {
true => YES,
false => NO
Expand All @@ -33,42 +37,29 @@ pub trait Layout: ObjcAccess {
}

/// Adds another Layout-backed control or view as a subview of this view.
fn add_subview<V: Layout>(&self, view: &V) {
self.with_backing_obj_mut(|backing_node| {
view.with_backing_obj_mut(|subview_node| unsafe {
fn add_subview(&self, view: &dyn Layout) {
self.with_backing_obj_mut(&|backing_node| {
view.with_backing_obj_mut(&|subview_node| unsafe {
let _: () = msg_send![backing_node, addSubview: subview_node];
});
});
}

/// Removes a control or view from the superview.
fn remove_from_superview(&self) {
self.with_backing_obj_mut(|backing_node| unsafe {
self.with_backing_obj_mut(&|backing_node| unsafe {
let _: () = msg_send![backing_node, removeFromSuperview];
});
}

/// Sets the `frame` for the view this trait is applied to.
///
/// Note that Cacao, by default, opts into autolayout - you need to call
/// `set_translates_autoresizing_mask_into_constraints` to enable frame-based layout calls (or
/// use an appropriate initializer for a given view type).
fn set_frame<R: Into<CGRect>>(&self, rect: R) {
let frame: CGRect = rect.into();

self.with_backing_obj_mut(move |backing_node| unsafe {
let _: () = msg_send![backing_node, setFrame: frame];
});
}

/// Sets whether the view for this trait should translate autoresizing masks into layout
/// constraints.
///
/// Cacao defaults this to `false`; if you need to set frame-based layout pieces,
/// then you should set this to `true` (or use an appropriate initializer that does it for you).
#[cfg(feature = "autolayout")]
fn set_translates_autoresizing_mask_into_constraints(&self, translates: bool) {
self.with_backing_obj_mut(|backing_node| unsafe {
self.with_backing_obj_mut(&|backing_node| unsafe {
let _: () = msg_send![backing_node, setTranslatesAutoresizingMaskIntoConstraints:match translates {
true => YES,
false => NO
Expand All @@ -80,7 +71,7 @@ pub trait Layout: ObjcAccess {
///
/// When hidden, widgets don't receive events and is not visible.
fn set_hidden(&self, hide: bool) {
self.with_backing_obj_mut(|obj| unsafe {
self.with_backing_obj_mut(&|obj| unsafe {
let _: () = msg_send![obj, setHidden:match hide {
true => YES,
false => NO
Expand All @@ -93,13 +84,15 @@ pub trait Layout: ObjcAccess {
/// Note that this can report `false` if an ancestor widget is hidden, thus hiding this - to check in
/// that case, you may want `is_hidden_or_ancestor_is_hidden()`.
fn is_hidden(&self) -> bool {
self.get_from_backing_obj(|obj| to_bool(unsafe { msg_send![obj, isHidden] }))
let obj = self.get_backing_obj();
to_bool(unsafe { msg_send![&**obj, isHidden] })
}

/// Returns whether this is hidden, *or* whether an ancestor view is hidden.
#[cfg(feature = "appkit")]
fn is_hidden_or_ancestor_is_hidden(&self) -> bool {
self.get_from_backing_obj(|obj| to_bool(unsafe { msg_send![obj, isHiddenOrHasHiddenAncestor] }))
let obj = self.get_backing_obj();
to_bool(unsafe { msg_send![&**obj, isHiddenOrHasHiddenAncestor] })
}

/// Register this view for drag and drop operations.
Expand All @@ -118,7 +111,7 @@ pub trait Layout: ObjcAccess {
.collect::<Vec<id>>()
.into();

self.with_backing_obj_mut(|obj| unsafe {
self.with_backing_obj_mut(&|obj| unsafe {
let _: () = msg_send![obj, registerForDraggedTypes:&*types];
});
}
Expand All @@ -129,7 +122,7 @@ pub trait Layout: ObjcAccess {
/// currently to avoid compile issues.
#[cfg(feature = "appkit")]
fn unregister_dragged_types(&self) {
self.with_backing_obj_mut(|obj| unsafe {
self.with_backing_obj_mut(&|obj| unsafe {
let _: () = msg_send![obj, unregisterDraggedTypes];
});
}
Expand All @@ -140,7 +133,7 @@ pub trait Layout: ObjcAccess {
/// can be helpful - but always test!
#[cfg(feature = "appkit")]
fn set_posts_frame_change_notifications(&self, posts: bool) {
self.with_backing_obj_mut(|obj| unsafe {
self.with_backing_obj_mut(&|obj| unsafe {
let _: () = msg_send![obj, setPostsFrameChangedNotifications:match posts {
true => YES,
false => NO
Expand All @@ -154,7 +147,7 @@ pub trait Layout: ObjcAccess {
/// can be helpful - but always test!
#[cfg(feature = "appkit")]
fn set_posts_bounds_change_notifications(&self, posts: bool) {
self.with_backing_obj_mut(|obj| unsafe {
self.with_backing_obj_mut(&|obj| unsafe {
let _: () = msg_send![obj, setPostsBoundsChangedNotifications:match posts {
true => YES,
false => NO
Expand All @@ -168,8 +161,46 @@ pub trait Layout: ObjcAccess {
fn set_alpha(&self, value: f64) {
let value: CGFloat = value.into();

self.with_backing_obj_mut(|obj| unsafe {
self.with_backing_obj_mut(&|obj| unsafe {
let _: () = msg_send![obj, setAlphaValue: value];
});
}

#[cfg(feature = "appkit")]
fn get_top(&self) -> LayoutAnchorY {
let id = self.get_backing_obj();
LayoutAnchorY::Top(unsafe { msg_send_id![&**id, topAnchor] })
}
#[cfg(feature = "appkit")]
fn get_bottom(&self) -> LayoutAnchorY {
let id = self.get_backing_obj();
LayoutAnchorY::Bottom(unsafe { msg_send_id![&**id, bottomAnchor] })
}
#[cfg(feature = "appkit")]
fn get_leading(&self) -> LayoutAnchorX {
let id = self.get_backing_obj();
LayoutAnchorX::Leading(unsafe { msg_send_id![&**id, leadingAnchor] })
}
#[cfg(feature = "appkit")]
fn get_trailing(&self) -> LayoutAnchorX {
let id = self.get_backing_obj();
LayoutAnchorX::Trailing(unsafe { msg_send_id![&**id, trailingAnchor] })
}
}

pub trait Frame: Layout {
/// Sets the `frame` for the view this trait is applied to.
///
/// Note that Cacao, by default, opts into autolayout - you need to call
/// `set_translates_autoresizing_mask_into_constraints` to enable frame-based layout calls (or
/// use an appropriate initializer for a given view type).
fn set_frame<R: Into<CGRect>>(&self, rect: R) {
let frame: CGRect = rect.into();

self.with_backing_obj_mut(&move |backing_node| unsafe {
let _: () = msg_send![backing_node, setFrame: frame];
});
}
}

impl<T: Layout> Frame for T {}
Loading