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=Foundation");
|
||||||
println!("cargo:rustc-link-lib=framework=Cocoa");
|
println!("cargo:rustc-link-lib=framework=Cocoa");
|
||||||
println!("cargo:rustc-link-lib=framework=CoreGraphics");
|
println!("cargo:rustc-link-lib=framework=CoreGraphics");
|
||||||
|
println!("cargo:rustc-link-lib=framework=QuartzCore");
|
||||||
|
|
||||||
println!("cargo:rustc-link-lib=framework=Security");
|
println!("cargo:rustc-link-lib=framework=Security");
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ pub mod printing;
|
||||||
pub mod toolbar;
|
pub mod toolbar;
|
||||||
pub mod user_activity;
|
pub mod user_activity;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
//pub mod view;
|
pub mod view;
|
||||||
|
|
||||||
#[cfg(feature = "webview")]
|
#[cfg(feature = "webview")]
|
||||||
pub mod webview;
|
pub mod webview;
|
||||||
|
|
|
@ -134,8 +134,8 @@ pub(crate) fn register_view_class() -> *const Class {
|
||||||
|
|
||||||
decl.add_ivar::<id>(BACKGROUND_COLOR);
|
decl.add_ivar::<id>(BACKGROUND_COLOR);
|
||||||
decl.add_method(sel!(isFlipped), enforce_normalcy as extern fn(&Object, _) -> BOOL);
|
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!(wantsUpdateLayer), enforce_normalcy as extern fn(&Object, _) -> BOOL);
|
||||||
decl.add_method(sel!(updateLayer), update_layer as extern fn(&Object, _));
|
//decl.add_method(sel!(updateLayer), update_layer as extern fn(&Object, _));
|
||||||
|
|
||||||
VIEW_CLASS = decl.register();
|
VIEW_CLASS = decl.register();
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,7 @@ use class::register_view_controller_class;
|
||||||
//#[derive(Debug)]
|
//#[derive(Debug)]
|
||||||
pub struct ViewController {
|
pub struct ViewController {
|
||||||
pub objc: ShareId<Object>,
|
pub objc: ShareId<Object>,
|
||||||
pub view: Box<ViewDelegate>
|
pub view: Box<dyn ViewDelegate>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ViewController {
|
impl ViewController {
|
||||||
|
|
|
@ -79,6 +79,7 @@ impl View {
|
||||||
let view: id = unsafe {
|
let view: id = unsafe {
|
||||||
let view: id = msg_send![register_view_class(), new];
|
let view: id = msg_send![register_view_class(), new];
|
||||||
let _: () = msg_send![view, setTranslatesAutoresizingMaskIntoConstraints:NO];
|
let _: () = msg_send![view, setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||||
|
let _: () = msg_send![view, setWantsLayer:YES];
|
||||||
view
|
view
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -93,45 +94,9 @@ impl View {
|
||||||
height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }),
|
height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }),
|
||||||
center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }),
|
center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }),
|
||||||
center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }),
|
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 {
|
impl<T> View<T> where T: ViewDelegate + 'static {
|
||||||
|
@ -152,9 +117,9 @@ impl<T> View<T> where T: ViewDelegate + 'static {
|
||||||
view
|
view
|
||||||
};
|
};
|
||||||
|
|
||||||
let view = View {
|
let mut view = View {
|
||||||
internal_callback_ptr: Some(internal_callback_ptr),
|
internal_callback_ptr: Some(internal_callback_ptr),
|
||||||
delegate: Some(delegate),
|
delegate: None,
|
||||||
top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }),
|
top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }),
|
||||||
leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }),
|
leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }),
|
||||||
trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }),
|
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] }),
|
height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }),
|
||||||
center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }),
|
center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }),
|
||||||
center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }),
|
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
|
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> {
|
fn get_backing_node(&self) -> ShareId<Object> {
|
||||||
self.objc.clone()
|
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> {
|
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.
|
/// Shows the window.
|
||||||
pub fn show(&self) {
|
pub fn show(&self) {
|
||||||
unsafe {
|
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