Add in an autolayout example
This commit is contained in:
parent
e50bb25e9f
commit
fc53848ba2
|
@ -8,6 +8,7 @@ fn main() {
|
|||
println!("cargo:rustc-link-lib=framework=Foundation");
|
||||
println!("cargo:rustc-link-lib=framework=Cocoa");
|
||||
println!("cargo:rustc-link-lib=framework=CoreGraphics");
|
||||
println!("cargo:rustc-link-lib=framework=QuartzCore");
|
||||
|
||||
println!("cargo:rustc-link-lib=framework=Security");
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ pub mod printing;
|
|||
pub mod toolbar;
|
||||
pub mod user_activity;
|
||||
pub mod utils;
|
||||
//pub mod view;
|
||||
pub mod view;
|
||||
|
||||
#[cfg(feature = "webview")]
|
||||
pub mod webview;
|
||||
|
|
|
@ -134,8 +134,8 @@ pub(crate) fn register_view_class() -> *const Class {
|
|||
|
||||
decl.add_ivar::<id>(BACKGROUND_COLOR);
|
||||
decl.add_method(sel!(isFlipped), enforce_normalcy as extern fn(&Object, _) -> BOOL);
|
||||
decl.add_method(sel!(wantsUpdateLayer), enforce_normalcy as extern fn(&Object, _) -> BOOL);
|
||||
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!(updateLayer), update_layer as extern fn(&Object, _));
|
||||
|
||||
VIEW_CLASS = decl.register();
|
||||
});
|
||||
|
|
|
@ -16,7 +16,7 @@ use class::register_view_controller_class;
|
|||
//#[derive(Debug)]
|
||||
pub struct ViewController {
|
||||
pub objc: ShareId<Object>,
|
||||
pub view: Box<ViewDelegate>
|
||||
pub view: Box<dyn ViewDelegate>
|
||||
}
|
||||
|
||||
impl ViewController {
|
||||
|
|
|
@ -79,6 +79,7 @@ impl View {
|
|||
let view: id = unsafe {
|
||||
let view: id = msg_send![register_view_class(), new];
|
||||
let _: () = msg_send![view, setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
let _: () = msg_send![view, setWantsLayer:YES];
|
||||
view
|
||||
};
|
||||
|
||||
|
@ -93,45 +94,9 @@ impl View {
|
|||
height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }),
|
||||
center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }),
|
||||
center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }),
|
||||
objc: ShareId::from_ptr(view),
|
||||
objc: unsafe { ShareId::from_ptr(view) },
|
||||
}
|
||||
}
|
||||
|
||||
/// Call this to set the background color for the backing layer.
|
||||
pub fn set_background_color(&self, color: Color) {
|
||||
unsafe {
|
||||
//let view: id = msg_send![*self.objc, view];
|
||||
//(*view).set_ivar(BACKGROUND_COLOR, color.into_platform_specific_color());
|
||||
//let _: () = msg_send![view, setNeedsDisplay:YES];
|
||||
}
|
||||
}
|
||||
|
||||
/// Register this view for drag and drop operations.
|
||||
pub fn register_for_dragged_types(&self, types: &[PasteboardType]) {
|
||||
unsafe {
|
||||
let types: NSArray = types.into_iter().map(|t| {
|
||||
// This clone probably doesn't need to be here, but it should also be cheap as
|
||||
// this is just an enum... and this is not an oft called method.
|
||||
let x: NSString = t.clone().into();
|
||||
x.into_inner()
|
||||
}).collect::<Vec<id>>().into();
|
||||
|
||||
let _: () = msg_send![&*self.objc, registerForDraggedTypes:types.into_inner()];
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a subview, adds it to this view.
|
||||
pub fn add_subview<T: Layout>(&self, subview: &T) {
|
||||
/*if let Some(subview_controller) = subview.get_backing_node() {
|
||||
unsafe {
|
||||
let _: () = msg_send![*this, addChildViewController:&*subview_controller];
|
||||
|
||||
let subview: id = msg_send![&*subview_controller, view];
|
||||
let view: id = msg_send![*this, view];
|
||||
let _: () = msg_send![view, addSubview:subview];
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> View<T> where T: ViewDelegate + 'static {
|
||||
|
@ -152,9 +117,9 @@ impl<T> View<T> where T: ViewDelegate + 'static {
|
|||
view
|
||||
};
|
||||
|
||||
let view = View {
|
||||
let mut view = View {
|
||||
internal_callback_ptr: Some(internal_callback_ptr),
|
||||
delegate: Some(delegate),
|
||||
delegate: None,
|
||||
top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }),
|
||||
leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }),
|
||||
trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }),
|
||||
|
@ -163,7 +128,7 @@ impl<T> View<T> where T: ViewDelegate + 'static {
|
|||
height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }),
|
||||
center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }),
|
||||
center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }),
|
||||
objc: ShareId::from_ptr(view),
|
||||
objc: unsafe { ShareId::from_ptr(view) },
|
||||
};
|
||||
|
||||
{
|
||||
|
@ -183,16 +148,65 @@ impl<T> View<T> where T: ViewDelegate + 'static {
|
|||
});
|
||||
}
|
||||
|
||||
view.delegate = Some(delegate);
|
||||
view
|
||||
}
|
||||
}
|
||||
|
||||
impl Layout for View {
|
||||
impl<T> View<T> {
|
||||
/// Call this to set the background color for the backing layer.
|
||||
pub fn set_background_color(&self, color: Color) {
|
||||
let bg = color.into_platform_specific_color();
|
||||
|
||||
unsafe {
|
||||
let cg: id = msg_send![bg, CGColor];
|
||||
let layer: id = msg_send![&*self.objc, layer];
|
||||
let _: () = msg_send![layer, setBackgroundColor:cg];
|
||||
//let view: id = msg_send![*self.objc, view];
|
||||
//(*view).set_ivar(BACKGROUND_COLOR, color.into_platform_specific_color());
|
||||
//let _: () = msg_send![view, setNeedsDisplay:YES];
|
||||
}
|
||||
}
|
||||
|
||||
/// Register this view for drag and drop operations.
|
||||
pub fn register_for_dragged_types(&self, types: &[PasteboardType]) {
|
||||
unsafe {
|
||||
let types: NSArray = types.into_iter().map(|t| {
|
||||
// This clone probably doesn't need to be here, but it should also be cheap as
|
||||
// this is just an enum... and this is not an oft called method.
|
||||
let x: NSString = t.clone().into();
|
||||
x.into_inner()
|
||||
}).collect::<Vec<id>>().into();
|
||||
|
||||
let _: () = msg_send![&*self.objc, registerForDraggedTypes:types.into_inner()];
|
||||
}
|
||||
}
|
||||
|
||||
//pub fn add_subview<L: Layout>(&self, subview: &L) {
|
||||
/*if let Some(subview_controller) = subview.get_backing_node() {
|
||||
unsafe {
|
||||
let _: () = msg_send![*this, addChildViewController:&*subview_controller];
|
||||
|
||||
let subview: id = msg_send![&*subview_controller, view];
|
||||
let view: id = msg_send![*this, view];
|
||||
let _: () = msg_send![view, addSubview:subview];
|
||||
}
|
||||
}*/
|
||||
//}
|
||||
}
|
||||
|
||||
impl<T> Layout for View<T> {
|
||||
fn get_backing_node(&self) -> ShareId<Object> {
|
||||
self.objc.clone()
|
||||
}
|
||||
|
||||
fn add_subview<V: Layout>(&self, _: &V) {}
|
||||
fn add_subview<V: Layout>(&self, view: &V) {
|
||||
let backing_node = view.get_backing_node();
|
||||
|
||||
unsafe {
|
||||
let _: () = msg_send![&*self.objc, addSubview:backing_node];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for View<T> {
|
||||
|
|
|
@ -155,6 +155,15 @@ 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) {
|
||||
let backing_node = view.get_backing_node();
|
||||
|
||||
unsafe {
|
||||
let _: () = msg_send![&*self.objc, setContentView:&*backing_node];
|
||||
}
|
||||
}
|
||||
|
||||
/// Shows the window.
|
||||
pub fn show(&self) {
|
||||
unsafe {
|
||||
|
|
8
examples/autolayout/Cargo.toml
Normal file
8
examples/autolayout/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "autolayout"
|
||||
version = "0.1.0"
|
||||
authors = ["Ryan McGrath <ryan@rymc.io>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
appkit = { path = "../../appkit" }
|
69
examples/autolayout/src/main.rs
Normal file
69
examples/autolayout/src/main.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
//! This example showcases setting up a basic application and window, and setting up some views to
|
||||
//! work with autolayout.
|
||||
|
||||
use appkit::app::{App, AppDelegate};
|
||||
use appkit::color::rgb;
|
||||
use appkit::layout::{Layout, LayoutConstraint};
|
||||
use appkit::view::View;
|
||||
use appkit::window::{Window, WindowConfig, WindowDelegate};
|
||||
|
||||
struct BasicApp {
|
||||
window: Window<AppWindow>
|
||||
}
|
||||
|
||||
impl AppDelegate for BasicApp {
|
||||
fn did_finish_launching(&self) {
|
||||
self.window.show();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct AppWindow {
|
||||
content: View,
|
||||
blue: View,
|
||||
red: View,
|
||||
green: View,
|
||||
window: Window
|
||||
}
|
||||
|
||||
impl WindowDelegate for AppWindow {
|
||||
fn did_load(&mut self, window: Window) {
|
||||
window.set_title("AutoLayout Example");
|
||||
window.set_minimum_content_size(300., 300.);
|
||||
self.window = window;
|
||||
|
||||
self.blue.set_background_color(rgb(105, 162, 176));
|
||||
self.content.add_subview(&self.blue);
|
||||
|
||||
self.red.set_background_color(rgb(224, 82, 99));
|
||||
self.content.add_subview(&self.red);
|
||||
|
||||
self.green.set_background_color(rgb(161, 192, 132));
|
||||
self.content.add_subview(&self.green);
|
||||
|
||||
self.window.set_content_view(&self.content);
|
||||
|
||||
LayoutConstraint::activate(&[
|
||||
self.blue.top.constraint_equal_to(&self.content.top).offset(16.),
|
||||
self.blue.leading.constraint_equal_to(&self.content.leading).offset(16.),
|
||||
self.blue.bottom.constraint_equal_to(&self.content.bottom).offset(-16.),
|
||||
self.blue.width.constraint_equal_to_constant(100.),
|
||||
|
||||
self.red.top.constraint_equal_to(&self.content.top).offset(16.),
|
||||
self.red.leading.constraint_equal_to(&self.blue.trailing).offset(16.),
|
||||
self.red.bottom.constraint_equal_to(&self.content.bottom).offset(-16.),
|
||||
|
||||
self.green.top.constraint_equal_to(&self.content.top).offset(16.),
|
||||
self.green.leading.constraint_equal_to(&self.red.trailing).offset(16.),
|
||||
self.green.trailing.constraint_equal_to(&self.content.trailing).offset(-16.),
|
||||
self.green.bottom.constraint_equal_to(&self.content.bottom).offset(-16.),
|
||||
self.green.width.constraint_equal_to_constant(100.),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
App::new("com.test.window", BasicApp {
|
||||
window: Window::with(WindowConfig::default(), AppWindow::default())
|
||||
}).run();
|
||||
}
|
Loading…
Reference in a new issue