Ongoing cleaning efforts

This commit is contained in:
Ryan McGrath 2020-03-28 22:05:40 -07:00
parent 6891e83019
commit 4266c4c8dc
No known key found for this signature in database
GPG key ID: 811674B62B666830
11 changed files with 171 additions and 63 deletions

View file

@ -1,9 +1,44 @@
//! Wraps the application lifecycle across platforms.
//!
//! This is where the bulk of your application logic starts out from. macOS and iOS are driven
//! heavily by lifecycle events - in this case, your boilerplate would look something like this:
//!
//! ```rust,no_run
//! use cacao::app::{App, AppDelegate};
//! use cacao::window::Window;
//! //!
//! #[derive(Default)]
//! struct BasicApp;
//!
//! impl AppDelegate for BasicApp {
//! fn did_finish_launching(&self) {
//! // Your program in here
//! }
//! }
//!
//! fn main() {
//! App::new("com.my.app", BasicApp::default()).run();
//! }
//! ```
//!
//! ## Why do I need to do this?
//! A good question. Cocoa does many things for you (e.g, setting up and managing a runloop,
//! handling the view/window heirarchy, and so on). This requires certain things happen before your
//! code can safely run, which `App` in this framework does for you.
//!
//! - It ensures that the `sharedApplication` is properly initialized with your delegate.
//! - It ensures that Cocoa is put into multi-threaded mode, so standard POSIX threads work as they
//! should.
//!
//! ### Platform specificity
//! Certain lifecycle events are specific to certain platforms. Where this is the case, the
//! documentation makes every effort to note.
use objc_id::Id; use objc_id::Id;
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel, sel_impl};
use crate::dispatcher::Dispatcher;
use crate::foundation::{id, YES, NO, NSUInteger, AutoReleasePool}; use crate::foundation::{id, YES, NO, NSUInteger, AutoReleasePool};
use crate::menu::Menu; use crate::menu::Menu;
@ -14,10 +49,10 @@ mod delegate;
use delegate::register_app_delegate_class; use delegate::register_app_delegate_class;
pub mod enums; pub mod enums;
pub use enums::AppDelegateResponse; use enums::AppDelegateResponse;
pub mod traits; pub mod traits;
pub use traits::{AppDelegate, Dispatcher}; use traits::AppDelegate;
pub(crate) static APP_PTR: &str = "rstAppPtr"; pub(crate) static APP_PTR: &str = "rstAppPtr";

View file

@ -13,14 +13,6 @@ use crate::user_activity::UserActivity;
#[cfg(feature = "cloudkit")] #[cfg(feature = "cloudkit")]
use crate::cloudkit::share::CKShareMetaData; use crate::cloudkit::share::CKShareMetaData;
/// Controllers interested in processing messages can implement this to respond to messages as
/// they're dispatched. All messages come in on the main thread.
pub trait Dispatcher {
type Message: Send + Sync;
fn on_message(&self, _message: Self::Message) {}
}
/// `AppDelegate` is more or less `NSAppDelegate` from the Objective-C/Swift side, just named /// `AppDelegate` is more or less `NSAppDelegate` from the Objective-C/Swift side, just named
/// differently to fit in with the general naming scheme found within this framework. You can /// differently to fit in with the general naming scheme found within this framework. You can
/// implement methods from this trait in order to respond to lifecycle events that the system will /// implement methods from this trait in order to respond to lifecycle events that the system will

View file

@ -1,6 +0,0 @@
//! Traits used for `CollectionView` controllers. More or less maps to the iOS/macOS routines,
//! mapping over the differences between them where appropriate.
pub trait CollectionViewController {
}

8
src/dispatcher.rs Normal file
View file

@ -0,0 +1,8 @@
/// Controllers interested in processing messages can implement this to respond to messages as
/// they're dispatched. All messages come in on the main thread.
pub trait Dispatcher {
type Message: Send + Sync;
fn on_message(&self, _message: Self::Message) {}
}

View file

@ -80,8 +80,8 @@ pub mod button;
pub mod cloudkit; pub mod cloudkit;
pub mod color; pub mod color;
pub mod collection_view;
pub mod constants; pub mod constants;
pub mod dispatcher;
pub mod dragdrop; pub mod dragdrop;
pub mod error; pub mod error;
pub mod events; pub mod events;
@ -107,28 +107,4 @@ pub mod webview;
pub mod window; pub mod window;
pub mod prelude { pub mod prelude;
pub use crate::app::{App, AppDelegate, Dispatcher};
pub use crate::layout::LayoutConstraint;
pub use crate::menu::{Menu, MenuItem};
#[cfg(feature = "user-notifications")]
pub use crate::notifications::{Notification, NotificationCenter, NotificationAuthOption};
pub use crate::toolbar::{Toolbar, ToolbarController, ToolbarHandle};
pub use crate::networking::URLRequest;
pub use crate::window::{
Window, WindowConfig, WindowDelegate
};
#[cfg(feature = "webview")]
pub use crate::webview::{
WebView, WebViewConfig, WebViewDelegate
};
pub use crate::view::{View, ViewDelegate};
}

29
src/prelude.rs Normal file
View file

@ -0,0 +1,29 @@
//! The prelude imports a large amount of useful widgets and traits. You're of course free to
//! thread imports yourself, but for many smaller applications this module can be quite a time
//! saver.
pub use crate::app::{App, traits::AppDelegate};
pub use crate::dispatcher::Dispatcher;
pub use crate::layout::LayoutConstraint;
pub use crate::menu::{Menu, MenuItem};
#[cfg(feature = "user-notifications")]
pub use crate::notifications::{Notification, NotificationCenter, NotificationAuthOption};
pub use crate::toolbar::{Toolbar, ToolbarController, ToolbarHandle};
pub use crate::networking::URLRequest;
pub use crate::window::{
Window, config::WindowConfig, traits::WindowDelegate
};
#[cfg(feature = "webview")]
pub use crate::webview::{
WebView, WebViewConfig, WebViewDelegate
};
pub use crate::view::{View, traits::ViewDelegate};

View file

@ -1,9 +1,45 @@
//! A `ViewHandle` represents an underlying `NSView`. You're passed a reference to one during your //! Wraps `NSView` and `UIView` across platforms.
//! `ViewController::did_load()` method. This method is safe to store and use, however as it's
//! UI-specific it's not thread safe.
//! //!
//! You can use this struct to configure how a view should look and layout. It implements //! This implementation errs towards the `UIView` side of things, and mostly acts as a wrapper to
//! AutoLayout - for more information, see the AutoLayout tutorial. //! bring `NSView` to the modern era. It does this by flipping the coordinate system to be what
//! people expect in 2020, and layer-backing all views by default.
//!
//! Views implement Autolayout, which enable you to specify how things should appear on the screen.
//!
//! ```rust,no_run
//! use cacao::color::rgb;
//! use cacao::layout::{Layout, LayoutConstraint};
//! use cacao::view::View;
//! use cacao::window::{Window, WindowDelegate};
//!
//! #[derive(Default)]
//! struct AppWindow {
//! content: View,
//! red: View,
//! window: Window
//! }
//!
//! impl WindowDelegate for AppWindow {
//! fn did_load(&mut self, window: Window) {
//! window.set_minimum_content_size(300., 300.);
//! self.window = window;
//!
//! self.red.set_background_color(rgb(224, 82, 99));
//! self.content.add_subview(&self.red);
//!
//! self.window.set_content_view(&self.content);
//!
//! LayoutConstraint::activate(&[
//! self.red.top.constraint_equal_to(&self.content.top).offset(16.),
//! self.red.leading.constraint_equal_to(&self.content.leading).offset(16.),
//! self.red.trailing.constraint_equal_to(&self.content.trailing).offset(-16.),
//! self.red.bottom.constraint_equal_to(&self.content.bottom).offset(-16.),
//! ]);
//! }
//! }
//! ```
//!
//! For more information on Autolayout, view the module or check out the examples folder.
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
@ -21,10 +57,9 @@ mod class;
use class::{register_view_class, register_view_class_with_delegate}; use class::{register_view_class, register_view_class_with_delegate};
pub mod controller; pub mod controller;
pub use controller::ViewController;
pub mod traits; pub mod traits;
pub use traits::ViewDelegate; use traits::ViewDelegate;
pub(crate) static VIEW_DELEGATE_PTR: &str = "rstViewDelegatePtr"; pub(crate) static VIEW_DELEGATE_PTR: &str = "rstViewDelegatePtr";

View file

@ -1,9 +1,17 @@
//! Implements a WebView, which wraps a number of different classes/delegates/controllers into one //! Wraps `WKWebView` across all platforms.
//!
//! Wraps a number of different classes/delegates/controllers into one
//! useful interface. This encompasses... //! useful interface. This encompasses...
//! //!
//! - `WKWebView` //! - `WKWebView`
//! - `WKUIDelegate` //! - `WKUIDelegate`
//! - `WKScriptMessageHandler` //! - `WKScriptMessageHandler`
//!
//! This is, thankfully, a pretty similar class across platforms.
//!
//! ### WebView is not available for tvOS
//! Apple does not ship `WKWebView` on tvOS, and as a result this control is not provided on that
//! platform.
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;

View file

@ -1,3 +1,31 @@
//! A `WindowController` is useful for handling certain document patterns on macOS.
//!
//! (iOS has no equivalent, as `UIWindowController` is private there).
//!
//! In particular, this is useful for certain situations regarding document handling
//! (which this framework does not yet cover, but may eventually). Note that this control can only
//! be created by providing a `WindowDelegate`.
//!
//! >If your application only uses a single `Window`, you may not even need this - just set the
//! autosave name on your `Window` to get the benefit of cached window location across restarts.
//!
//! # How to use
//!
//! ```rust,no_run
//! use cacao::app::AppDelegate;
//! use cacao::window::{WindowController, WindowDelegate};
//!
//! #[derive(Default)]
//! struct MyWindow;
//!
//! impl WindowDelegate for MyWindow {
//! // Your implementation here...
//! }
//!
//! struct MyApp {
//! pub window: WindowController<MyWindow>
//! }
//! ```
use objc::runtime::Object; use objc::runtime::Object;
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, sel, sel_impl};
@ -10,10 +38,13 @@ use crate::window::{Window, WindowConfig, WindowDelegate, WINDOW_DELEGATE_PTR};
mod class; mod class;
use class::register_window_controller_class; use class::register_window_controller_class;
/// A `Window` represents your way of interacting with an `NSWindow`. It wraps the various moving /// A `WindowController` wraps your `WindowDelegate` into an underlying `Window`, and
/// pieces to enable you to focus on reacting to lifecycle methods and doing your thing. /// provides some extra lifecycle methods.
pub struct WindowController<T> { pub struct WindowController<T> {
/// A handler to the underlying `NSWindowController`.
pub objc: ShareId<Object>, pub objc: ShareId<Object>,
/// The underlying `Window` that this controller wraps.
pub window: Window<T> pub window: Window<T>
} }

View file

@ -1,11 +1,12 @@
//! Implements an `NSWindow` wrapper for MacOS, backed by Cocoa and associated widgets. //! Wraps `NSWindow` on macOS and `UIWindow` on iOS.
//! //!
//! This also handles looping back lifecycle events, such as window resizing or close events. It //! Using `WindowDelegate`, you're able to handle lifecycle events on your `Window` (such as
//! currently implements a good chunk of the API, however it should be noted that in places where //! resizing, closing, and so on). Note that interaction patterns are different between macOS and
//! things are outright deprecated, this framework will opt to not bother providing access to them. //! iOS windows, so your codebase may need to differ quite a bit here.
//! //!
//! If you require functionality like that, you're free to use the `objc` field on a `Window` to //! Of note: on macOS, in places where things are outright deprecated, this framework will opt to
//! instrument it with the Objective-C runtime on your own. //! not bother providing access to them. If you require functionality like that, you're free to use
//! the `objc` field on a `Window` to instrument it with the Objective-C runtime on your own.
use std::unreachable; use std::unreachable;
use std::rc::Rc; use std::rc::Rc;
@ -28,16 +29,15 @@ mod class;
use class::{register_window_class, register_window_class_with_delegate}; use class::{register_window_class, register_window_class_with_delegate};
pub mod config; pub mod config;
pub use config::WindowConfig; use config::WindowConfig;
pub mod controller; pub mod controller;
pub use controller::WindowController;
pub mod enums; pub mod enums;
use enums::TitleVisibility; use enums::TitleVisibility;
pub mod traits; pub mod traits;
pub use traits::WindowDelegate; use traits::WindowDelegate;
pub(crate) static WINDOW_DELEGATE_PTR: &str = "rstWindowDelegate"; pub(crate) static WINDOW_DELEGATE_PTR: &str = "rstWindowDelegate";
@ -45,10 +45,10 @@ pub(crate) static WINDOW_DELEGATE_PTR: &str = "rstWindowDelegate";
/// pieces to enable you to focus on reacting to lifecycle methods and doing your thing. /// pieces to enable you to focus on reacting to lifecycle methods and doing your thing.
#[derive(Debug)] #[derive(Debug)]
pub struct Window<T = ()> { pub struct Window<T = ()> {
/// A pointer to the Objective-C `NSWindow`. Used in callback orchestration. /// A pointer to the Objective-C `NS/UIWindow`. Used in callback orchestration.
pub(crate) internal_callback_ptr: Option<*const RefCell<T>>, pub(crate) internal_callback_ptr: Option<*const RefCell<T>>,
/// Represents an `NSWindow` in the Objective-C runtime. /// Represents an `NS/UIWindow` in the Objective-C runtime.
pub objc: ShareId<Object>, pub objc: ShareId<Object>,
/// A delegate for this window. /// A delegate for this window.