From ebec770581abce81484349ae076c29eaa0a82f2e Mon Sep 17 00:00:00 2001 From: Ryan McGrath Date: Thu, 26 Mar 2020 19:02:53 -0700 Subject: [PATCH] Bringing Window to a usable point --- src/lib.rs | 7 +-- src/window/mod.rs | 155 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 156 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0d1839c..a0dc152 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -//! This crate provides pieces necessary for interfacing with `AppKit` (`Cocoa`, on macOS). It +//! This crate provides pieces necessary for interfacing with `AppKit` on macOS and (eventually) `UIKit` on iOS. It //! tries to do so in a way that, if you've done programming for the framework before (in Swift or //! Objective-C), will feel familiar. This is tricky in Rust due to the ownership model, but some //! creative coding and assumptions can get us pretty far. @@ -9,12 +9,9 @@ //! controls. This does _not_ mean you can't assess, review, or question unsafe usage - just know //! it's happening, and in large part it's not going away. //! -//! It's best to look at this crate as a bridge to the future: you can write your own (safe) Rust -//! code, and have it intermix in the (existing, unsafe) world. -//! //! This crate is also, currently, _very_ early stage and may have bugs. Your usage of it is at //! your own risk. With that said, provided you follow the rules (regarding memory/ownership) it's -//! already fine for some apps. Check the README for more info! +//! already fine for some apps. pub mod alert; pub mod app; diff --git a/src/window/mod.rs b/src/window/mod.rs index 98c0be7..0a616a4 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -1,15 +1,18 @@ //! Implements an `NSWindow` wrapper for MacOS, backed by Cocoa and associated widgets. This also handles looping back //! lifecycle events, such as window resizing or close events. +use std::unreachable; use std::rc::Rc; use std::cell::RefCell; +use core_graphics::base::CGFloat; use core_graphics::geometry::{CGRect, CGSize}; use objc::{msg_send, sel, sel_impl}; use objc::runtime::Object; use objc_id::ShareId; +use crate::color::Color; use crate::foundation::{id, nil, YES, NO, NSString, NSUInteger}; use crate::layout::traits::Layout; use crate::toolbar::{Toolbar, ToolbarController}; @@ -138,7 +141,15 @@ impl Window { pub fn set_minimum_content_size>(&self, width: F, height: F) { unsafe { let size = CGSize::new(width.into(), height.into()); - let _: () = msg_send![&*self.objc, setMinSize:size]; + let _: () = msg_send![&*self.objc, setContentMinSize:size]; + } + } + + /// Sets the maximum size this window can shrink to. + pub fn set_maximum_content_size>(&self, width: F, height: F) { + unsafe { + let size = CGSize::new(width.into(), height.into()); + let _: () = msg_send![&*self.objc, setContentMaxSize:size]; } } @@ -183,6 +194,148 @@ impl Window { let _: () = msg_send![&*self.objc, close]; } } + + /// Toggles a Window being full screen or not. + pub fn toggle_full_screen(&self) { + unsafe { + let _: () = msg_send![&*self.objc, toggleFullScreen:nil]; + } + } + + /// Sets the background color for the window. You generally don't want to do this often. + pub fn set_background_color(&self, color: Color) { + unsafe { + let _: () = msg_send![&*self.objc, setBackgroundColor:color.into_platform_specific_color()]; + } + } + + pub fn is_opaque(&self) -> bool { + unsafe { + match msg_send![&*self.objc, isOpaque] { + YES => true, + NO => false, + _ => unreachable!() + } + } + } + + /// Indicates whether the window is on a currently active space. + /// + /// From Apple's documentation: + /// + /// _The value of this property is YES if the window is on the currently active space; otherwise, NO. + /// For visible windows, this property indicates whether the window is currently visible on the active + /// space. For nonvisible windows, it indicates whether ordering the window onscreen would cause it to + /// be on the active space._ + pub fn is_on_active_space(&self) -> bool { + unsafe { + match msg_send![&*self.objc, isOnActiveSpace] { + YES => true, + NO => false, + _ => unreachable!() + } + } + } + + pub fn is_visible(&self) -> bool { + unsafe { + match msg_send![&*self.objc, isVisible] { + YES => true, + NO => false, + _ => unreachable!() + } + } + } + + pub fn is_key(&self) -> bool { + unsafe { + match msg_send![&*self.objc, isKeyWindow] { + YES => true, + NO => false, + _ => unreachable!() + } + } + } + + pub fn can_become_key(&self) -> bool { + unsafe { + match msg_send![&*self.objc, canBecomeKeyWindow] { + YES => true, + NO => false, + _ => unreachable!() + } + } + } + + pub fn make_key_window(&self) { + unsafe { + let _: () = msg_send![&*self.objc, makeKeyWindow]; + } + } + + pub fn make_key_and_order_front(&self) { + unsafe { + let _: () = msg_send![&*self.objc, makeKeyAndOrderFront:nil]; + } + } + + pub fn is_main_window(&self) -> bool { + unsafe { + match msg_send![&*self.objc, isMainWindow] { + YES => true, + NO => false, + _ => unreachable!() + } + } + } + + pub fn can_become_main_window(&self) -> bool { + unsafe { + match msg_send![&*self.objc, canBecomeMainWindow] { + YES => true, + NO => false, + _ => unreachable!() + } + } + } + + pub fn toggle_toolbar_shown(&self) { + unsafe { + let _: () = msg_send![&*self.objc, toggleToolbarShown:nil]; + } + } + + pub fn set_excluded_from_windows_menu(&self, excluded: bool) { + unsafe { + let _: () = msg_send![&*self.objc, setExcludedFromWindowsMenu:match excluded { + true => YES, + false => NO + }]; + } + } + + pub fn set_shows_toolbar_button(&self, shows: bool) { + unsafe { + let _: () = msg_send![&*self.objc, setShowsToolbarButton:match shows { + true => YES, + false => NO + }]; + } + } + + /// Returns the backing scale (e.g, `1.0` for non retina, `2.0` for retina) used on this + /// window. + /// + /// Note that Apple recommends AGAINST using this in most cases. It's exposed here for the rare + /// cases where you DO need it. + pub fn backing_scale_factor(&self) -> f64 { + unsafe { + let scale: CGFloat = msg_send![&*self.objc, backingScaleFactor]; + scale as f64 + } + } + + } impl Window where T: WindowDelegate + 'static {