From 896702287ffaecec188c7328c1047e3b87926497 Mon Sep 17 00:00:00 2001 From: Ryan McGrath Date: Tue, 28 May 2019 20:27:37 -0700 Subject: [PATCH] Tweak Window API to fit a bit better --- README.md | 6 ++++- alchemy/src/components/view.rs | 1 - alchemy/src/window/window.rs | 40 +++++++++++++++++++++++++++++---- cocoa/src/window.rs | 39 ++++++++++++++++++++++++-------- examples/layout/src/main.rs | 12 ++++++++-- lifecycle/src/reconciler/mod.rs | 12 +++------- styles/src/lib.rs | 2 +- website/content/_index.md | 7 ++++-- 8 files changed, 90 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index bfb95cc..c6c57bc 100644 --- a/README.md +++ b/README.md @@ -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 { + + }) }); } ``` diff --git a/alchemy/src/components/view.rs b/alchemy/src/components/view.rs index 5171957..9ddc064 100644 --- a/alchemy/src/components/view.rs +++ b/alchemy/src/components/view.rs @@ -58,7 +58,6 @@ impl Component for View { } fn render(&self, props: &Props) -> Result { - println!("WTF: {}", props.children.len()); Ok(RSX::node("Fragment", |key| Box::new(Fragment::constructor(key)), Props { attributes: std::collections::HashMap::new(), key: "".into(), diff --git a/alchemy/src/window/window.rs b/alchemy/src/window/window.rs index d4d383d..5d5bd5e 100644 --- a/alchemy/src/window/window.rs +++ b/alchemy/src/window/window.rs @@ -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, 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>); impl Window { /// Creates a new window. - pub fn new(title: &str, dimensions: (f64, f64, f64, f64), delegate: S) -> Window { + pub fn new(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()); diff --git a/cocoa/src/window.rs b/cocoa/src/window.rs index fc8e43a..6f57320 100644 --- a/cocoa/src/window.rs +++ b/cocoa/src/window.rs @@ -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(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(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. diff --git a/examples/layout/src/main.rs b/examples/layout/src/main.rs index f0b8fc1..3f35c07 100644 --- a/examples/layout/src/main.rs +++ b/examples/layout/src/main.rs @@ -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,14 +74,18 @@ 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); @@ -109,6 +115,8 @@ fn main() { }); app.run(AppState { - window: Window::new("Testing...", (0., 0., 600., 600.), WindowState {}) + window: Window::new(WindowState { + + }) }); } diff --git a/lifecycle/src/reconciler/mod.rs b/lifecycle/src/reconciler/mod.rs index 06600b4..8a9f810 100644 --- a/lifecycle/src/reconciler/mod.rs +++ b/lifecycle/src/reconciler/mod.rs @@ -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)?; } diff --git a/styles/src/lib.rs b/styles/src/lib.rs index 71245a6..d6e60b0 100644 --- a/styles/src/lib.rs +++ b/styles/src/lib.rs @@ -29,7 +29,7 @@ pub use style_keys::StyleKey; pub type StylesList = SpacedSet; pub mod styles; -pub use styles::{Appearance, Styles}; +pub use styles::{Appearance, Styles, Style}; pub mod stylesheet; pub use stylesheet::StyleSheet; diff --git a/website/content/_index.md b/website/content/_index.md index 30c4c96..fcb2f1a 100644 --- a/website/content/_index.md +++ b/website/content/_index.md @@ -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 { + + }) }); } ```