Tweak Window API to fit a bit better

This commit is contained in:
Ryan McGrath 2019-05-28 20:27:37 -07:00
parent 2a73b399d9
commit 896702287f
No known key found for this signature in database
GPG key ID: 811674B62B666830
8 changed files with 90 additions and 29 deletions

View file

@ -41,6 +41,8 @@ struct AppState {
impl AppDelegate for AppState {
fn did_finish_launching(&mut self) {
self.window.set_title("Test");
self.window.set_dimensions(10., 10., 600., 600.);
self.window.show();
}
}
@ -77,7 +79,9 @@ fn main() {
});
app.run(AppState {
window: Window::new("Le Appy App", (0., 0., 600., 600.), WindowState {})
window: Window::new(WindowState {
})
});
}
```

View file

@ -58,7 +58,6 @@ impl Component for View {
}
fn render(&self, props: &Props) -> Result<RSX, Error> {
println!("WTF: {}", props.children.len());
Ok(RSX::node("Fragment", |key| Box::new(Fragment::constructor(key)), Props {
attributes: std::collections::HashMap::new(),
key: "".into(),

View file

@ -7,6 +7,8 @@ use alchemy_lifecycle::{ComponentKey, RENDER_ENGINE};
use alchemy_lifecycle::rsx::RSX;
use alchemy_lifecycle::traits::WindowDelegate;
use alchemy_styles::{Appearance, Style, StylesList, THEME_ENGINE};
use crate::{App, SHARED_APP};
use crate::components::View;
@ -18,7 +20,9 @@ use alchemy_cocoa::window::{Window as PlatformWindowBridge};
/// it holds.
pub struct AppWindow {
pub id: usize,
pub style_keys: StylesList,
pub title: String,
pub dimensions: (f64, f64, f64, f64),
pub bridge: PlatformWindowBridge,
pub delegate: Box<WindowDelegate>,
pub render_key: ComponentKey
@ -33,6 +37,12 @@ impl AppWindow {
/// This method is called on the `show` event, and in rare cases can be useful to call
/// directly.
pub fn render(&mut self) {
let mut style = Style::default();
let mut appearance = Appearance::default();
THEME_ENGINE.configure_styles_for_keys(&self.style_keys, &mut style, &mut appearance);
self.bridge.apply_styles(&appearance);
let children = match self.delegate.render() {
Ok(opt) => opt,
Err(e) => {
@ -42,11 +52,21 @@ impl AppWindow {
};
match RENDER_ENGINE.diff_and_render_root(self.render_key, children) {
Ok(_) => { println!("RENDERED!!!!"); }
Ok(_) => { }
Err(e) => { eprintln!("Error rendering window! {}", e); }
}
}
pub fn set_title(&mut self, title: &str) {
self.title = title.into();
self.bridge.set_title(title);
}
pub fn set_dimensions(&mut self, x: f64, y: f64, width: f64, height: f64) {
self.dimensions = (x, y, width, height);
self.bridge.set_dimensions(x, y, width, height);
}
/// Renders and calls through to the native platform window show method.
pub fn show(&mut self) {
self.render();
@ -65,11 +85,11 @@ pub struct Window(pub(crate) Arc<Mutex<AppWindow>>);
impl Window {
/// Creates a new window.
pub fn new<S: 'static + WindowDelegate>(title: &str, dimensions: (f64, f64, f64, f64), delegate: S) -> Window {
pub fn new<S: 'static + WindowDelegate>(delegate: S) -> Window {
let window_id = SHARED_APP.windows.allocate_new_window_id();
let view = View::default();
let shared_app_ptr: *const App = &**SHARED_APP;
let bridge = PlatformWindowBridge::new(window_id, title, dimensions, &view, shared_app_ptr);
let bridge = PlatformWindowBridge::new(window_id, &view, shared_app_ptr);
let key = match RENDER_ENGINE.register_root_component(view) {
Ok(key) => key,
Err(_e) => { panic!("Uhhhh this really messed up"); }
@ -77,7 +97,9 @@ impl Window {
Window(Arc::new(Mutex::new(AppWindow {
id: window_id,
title: title.into(),
style_keys: "".into(),
title: "".into(),
dimensions: (0., 0., 0., 0.),
bridge: bridge,
delegate: Box::new(delegate),
render_key: key
@ -92,6 +114,16 @@ impl Window {
window.render();
}
pub fn set_title(&self, title: &str) {
let mut window = self.0.lock().unwrap();
window.set_title(title);
}
pub fn set_dimensions(&mut self, x: f64, y: f64, width: f64, height: f64) {
let mut window = self.0.lock().unwrap();
window.set_dimensions(x, y, width, height);
}
/// Registers this window with the window manager, renders it, and shows it.
pub fn show(&self) {
SHARED_APP.windows.add(self.0.clone());

View file

@ -4,7 +4,7 @@
use std::sync::{Once, ONCE_INIT};
use cocoa::base::{id, nil, /*YES,*/ NO};
use cocoa::base::{id, nil, YES, NO};
use cocoa::appkit::{NSWindow, NSWindowStyleMask, NSBackingStoreType};
use cocoa::foundation::{NSRect, NSPoint, NSSize, NSString, NSAutoreleasePool};
@ -14,6 +14,7 @@ use objc::runtime::{Class, Object, Sel};
use objc::{msg_send, sel, sel_impl};
use alchemy_lifecycle::traits::{AppDelegate, Component};
use alchemy_styles::Appearance;
static APP_PTR: &str = "alchemyAppPtr";
static WINDOW_MANAGER_ID: &str = "alchemyWindowManagerID";
@ -29,13 +30,12 @@ impl Window {
/// Creates a new `NSWindow` instance, configures it appropriately (e.g, titlebar appearance),
/// injects an `NSObject` delegate wrapper, and retains the necessary Objective-C runtime
/// pointers.
pub fn new<T: AppDelegate>(window_id: usize, title: &str, dimensions: (f64, f64, f64, f64), content_view: &Component, app_ptr: *const T) -> Window {
let (top, left, width, height) = dimensions;
let dimensions = NSRect::new(NSPoint::new(top, left), NSSize::new(width, height));
pub fn new<T: AppDelegate>(window_id: usize, content_view: &Component, app_ptr: *const T) -> Window {
let dimensions = NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.));
let style = NSWindowStyleMask::NSResizableWindowMask |
NSWindowStyleMask::NSUnifiedTitleAndToolbarWindowMask | NSWindowStyleMask::NSMiniaturizableWindowMask |
NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask;
NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask | NSWindowStyleMask::NSFullSizeContentViewWindowMask;
let inner = unsafe {
let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
@ -45,10 +45,8 @@ impl Window {
NO
).autorelease();
let title = NSString::alloc(nil).init_str(title);
window.setTitle_(title);
//msg_send![window, setTitlebarAppearsTransparent:YES];
msg_send![window, setTitleVisibility:1];
msg_send![window, setTitlebarAppearsTransparent:YES];
//msg_send![window, setTitleVisibility:1];
// This is very important! NSWindow is an old class and has some behavior that we need
// to disable, like... this. If we don't set this, we'll segfault entirely because the
@ -77,6 +75,29 @@ impl Window {
}
}
pub fn set_title(&mut self, title: &str) {
unsafe {
let title = NSString::alloc(nil).init_str(title);
msg_send![&*self.inner, setTitle:title];
}
}
pub fn set_dimensions(&mut self, x: f64, y: f64, width: f64, height: f64) {
unsafe {
let dimensions = NSRect::new(
NSPoint::new(x.into(), y.into()),
NSSize::new(width.into(), height.into())
);
msg_send![&*self.inner, setFrame:dimensions display:YES];
}
}
/// Normally used for setting platform-specific styles; on macOS we choose not to do this and
/// just have the content view handle the background color, as calling window
/// setBackgroundColor causes some notable lag on resizing.
pub fn apply_styles(&mut self, _appearance: &Appearance) { }
/// On macOS, calling `show()` is equivalent to calling `makeKeyAndOrderFront`. This is the
/// most common use case, hence why this method was chosen - if you want or need something
/// else, feel free to open an issue to discuss.

View file

@ -18,6 +18,8 @@ pub struct AppState {
impl AppDelegate for AppState {
fn did_finish_launching(&mut self) {
self.window.set_title("Layout Test");
self.window.set_dimensions(100., 100., 600., 600.);
self.window.show();
}
}
@ -72,15 +74,19 @@ fn main() {
let app = alchemy::shared_app();
app.register_styles("default", styles! {
message { width: 500; height: 100; background-color: yellow; color: black; }
root { background-color: #000; }
LOL {
background-color: #307ace;
width: 500;
height: 230;
padding-top: 20;
padding-left: 20;
padding-right: 40;
}
message { width: 500; height: 100; background-color: yellow; color: black; }
boxxx {
background-color: rgba(245, 217, 28, .8);
width: 100;
@ -109,6 +115,8 @@ fn main() {
});
app.run(AppState {
window: Window::new("Testing...", (0., 0., 600., 600.), WindowState {})
window: Window::new(WindowState {
})
});
}

View file

@ -99,7 +99,6 @@ impl RenderEngine {
if node.tag == "Fragment" {
node.props.children
} else {
println!("Def here...");
vec![RSX::VirtualNode(node)]
}
},
@ -113,6 +112,7 @@ impl RenderEngine {
let mut root_instance = component_store.get_mut(key)?;
let layout = root_instance.layout.unwrap();
let mut style = Style::default();
THEME_ENGINE.configure_styles_for_keys(&root_instance.props.styles, &mut style, &mut root_instance.appearance);
style.size = Size {
width: Dimension::Points(600.),
height: Dimension::Points(600.)
@ -126,7 +126,6 @@ impl RenderEngine {
height: Number::Defined(600.)
})?;
println!("Applying layout...");
walk_and_apply_styles(key, &mut component_store, &mut layout_store)?;
Ok(())
@ -161,7 +160,6 @@ fn recursively_diff_tree(
};
if is_replace {
println!("here, what?!");
unmount_component_tree(key, component_store, layout_store)?;
//mount_component_tree(
return Ok(());
@ -244,7 +242,6 @@ fn mount_component_tree(
let rendered = instance.component.render(&instance.props);
// instance.get_snapshot_before_update()
println!("Rendered... {}", instance.tag);
component_store.insert(key, instance)?;
match rendered {
@ -254,9 +251,7 @@ fn mount_component_tree(
// tag similar to what React does, which just hoists the children out of it and
// discards the rest.
if child.tag == "Fragment" {
println!(" In Fragment {}", child.props.children.len());
for child_tree in child.props.children {
println!(" > WHAT");
if let RSX::VirtualNode(child_tree) = child_tree {
let child_key = mount_component_tree(child_tree, component_store, layout_store)?;
@ -267,14 +262,14 @@ fn mount_component_tree(
}
}
} else {
println!(" In regular");
let child_key = mount_component_tree(child, component_store, layout_store)?;
component_store.add_child(key, child_key)?;
if is_native_backed {
link_layout_nodess(key, child_key, component_store, layout_store)?;
}
}
} else { println!("WTF"); },
},
Err(e) => {
// return an RSX::VirtualNode(ErrorComponentView) or something?
@ -372,7 +367,6 @@ fn walk_and_apply_styles(
}
for child in components.children(key)? {
println!("Nesting");
walk_and_apply_styles(child, components, layouts)?;
}

View file

@ -29,7 +29,7 @@ pub use style_keys::StyleKey;
pub type StylesList = SpacedSet<StyleKey>;
pub mod styles;
pub use styles::{Appearance, Styles};
pub use styles::{Appearance, Styles, Style};
pub mod stylesheet;
pub use stylesheet::StyleSheet;

View file

@ -20,6 +20,8 @@ struct AppState {
impl AppDelegate for AppState {
fn did_finish_launching(&mut self) {
self.window.set_title("LOL");
self.window.set_dimensions(10., 10., 600., 600.);
self.window.show();
}
}
@ -55,9 +57,10 @@ fn main() {
}
});
let dimensions = (0., 0., 600., 600.);
app.run(AppState {
window: Window::new("Le Appy App", dimensions, WindowState {})
window: Window::new(WindowState {
})
});
}
```