Tweak Window API to fit a bit better
This commit is contained in:
parent
2a73b399d9
commit
896702287f
8 changed files with 90 additions and 29 deletions
|
|
@ -41,6 +41,8 @@ struct AppState {
|
||||||
|
|
||||||
impl AppDelegate for AppState {
|
impl AppDelegate for AppState {
|
||||||
fn did_finish_launching(&mut self) {
|
fn did_finish_launching(&mut self) {
|
||||||
|
self.window.set_title("Test");
|
||||||
|
self.window.set_dimensions(10., 10., 600., 600.);
|
||||||
self.window.show();
|
self.window.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +79,9 @@ fn main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
app.run(AppState {
|
app.run(AppState {
|
||||||
window: Window::new("Le Appy App", (0., 0., 600., 600.), WindowState {})
|
window: Window::new(WindowState {
|
||||||
|
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,6 @@ impl Component for View {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&self, props: &Props) -> Result<RSX, Error> {
|
fn render(&self, props: &Props) -> Result<RSX, Error> {
|
||||||
println!("WTF: {}", props.children.len());
|
|
||||||
Ok(RSX::node("Fragment", |key| Box::new(Fragment::constructor(key)), Props {
|
Ok(RSX::node("Fragment", |key| Box::new(Fragment::constructor(key)), Props {
|
||||||
attributes: std::collections::HashMap::new(),
|
attributes: std::collections::HashMap::new(),
|
||||||
key: "".into(),
|
key: "".into(),
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ use alchemy_lifecycle::{ComponentKey, RENDER_ENGINE};
|
||||||
use alchemy_lifecycle::rsx::RSX;
|
use alchemy_lifecycle::rsx::RSX;
|
||||||
use alchemy_lifecycle::traits::WindowDelegate;
|
use alchemy_lifecycle::traits::WindowDelegate;
|
||||||
|
|
||||||
|
use alchemy_styles::{Appearance, Style, StylesList, THEME_ENGINE};
|
||||||
|
|
||||||
use crate::{App, SHARED_APP};
|
use crate::{App, SHARED_APP};
|
||||||
use crate::components::View;
|
use crate::components::View;
|
||||||
|
|
||||||
|
|
@ -18,7 +20,9 @@ use alchemy_cocoa::window::{Window as PlatformWindowBridge};
|
||||||
/// it holds.
|
/// it holds.
|
||||||
pub struct AppWindow {
|
pub struct AppWindow {
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
|
pub style_keys: StylesList,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
pub dimensions: (f64, f64, f64, f64),
|
||||||
pub bridge: PlatformWindowBridge,
|
pub bridge: PlatformWindowBridge,
|
||||||
pub delegate: Box<WindowDelegate>,
|
pub delegate: Box<WindowDelegate>,
|
||||||
pub render_key: ComponentKey
|
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
|
/// This method is called on the `show` event, and in rare cases can be useful to call
|
||||||
/// directly.
|
/// directly.
|
||||||
pub fn render(&mut self) {
|
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() {
|
let children = match self.delegate.render() {
|
||||||
Ok(opt) => opt,
|
Ok(opt) => opt,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -42,11 +52,21 @@ impl AppWindow {
|
||||||
};
|
};
|
||||||
|
|
||||||
match RENDER_ENGINE.diff_and_render_root(self.render_key, children) {
|
match RENDER_ENGINE.diff_and_render_root(self.render_key, children) {
|
||||||
Ok(_) => { println!("RENDERED!!!!"); }
|
Ok(_) => { }
|
||||||
Err(e) => { eprintln!("Error rendering window! {}", e); }
|
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.
|
/// Renders and calls through to the native platform window show method.
|
||||||
pub fn show(&mut self) {
|
pub fn show(&mut self) {
|
||||||
self.render();
|
self.render();
|
||||||
|
|
@ -65,11 +85,11 @@ pub struct Window(pub(crate) Arc<Mutex<AppWindow>>);
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
/// Creates a new 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 window_id = SHARED_APP.windows.allocate_new_window_id();
|
||||||
let view = View::default();
|
let view = View::default();
|
||||||
let shared_app_ptr: *const App = &**SHARED_APP;
|
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) {
|
let key = match RENDER_ENGINE.register_root_component(view) {
|
||||||
Ok(key) => key,
|
Ok(key) => key,
|
||||||
Err(_e) => { panic!("Uhhhh this really messed up"); }
|
Err(_e) => { panic!("Uhhhh this really messed up"); }
|
||||||
|
|
@ -77,7 +97,9 @@ impl Window {
|
||||||
|
|
||||||
Window(Arc::new(Mutex::new(AppWindow {
|
Window(Arc::new(Mutex::new(AppWindow {
|
||||||
id: window_id,
|
id: window_id,
|
||||||
title: title.into(),
|
style_keys: "".into(),
|
||||||
|
title: "".into(),
|
||||||
|
dimensions: (0., 0., 0., 0.),
|
||||||
bridge: bridge,
|
bridge: bridge,
|
||||||
delegate: Box::new(delegate),
|
delegate: Box::new(delegate),
|
||||||
render_key: key
|
render_key: key
|
||||||
|
|
@ -92,6 +114,16 @@ impl Window {
|
||||||
window.render();
|
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.
|
/// Registers this window with the window manager, renders it, and shows it.
|
||||||
pub fn show(&self) {
|
pub fn show(&self) {
|
||||||
SHARED_APP.windows.add(self.0.clone());
|
SHARED_APP.windows.add(self.0.clone());
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use std::sync::{Once, ONCE_INIT};
|
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::appkit::{NSWindow, NSWindowStyleMask, NSBackingStoreType};
|
||||||
use cocoa::foundation::{NSRect, NSPoint, NSSize, NSString, NSAutoreleasePool};
|
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 objc::{msg_send, sel, sel_impl};
|
||||||
|
|
||||||
use alchemy_lifecycle::traits::{AppDelegate, Component};
|
use alchemy_lifecycle::traits::{AppDelegate, Component};
|
||||||
|
use alchemy_styles::Appearance;
|
||||||
|
|
||||||
static APP_PTR: &str = "alchemyAppPtr";
|
static APP_PTR: &str = "alchemyAppPtr";
|
||||||
static WINDOW_MANAGER_ID: &str = "alchemyWindowManagerID";
|
static WINDOW_MANAGER_ID: &str = "alchemyWindowManagerID";
|
||||||
|
|
@ -29,13 +30,12 @@ impl Window {
|
||||||
/// Creates a new `NSWindow` instance, configures it appropriately (e.g, titlebar appearance),
|
/// Creates a new `NSWindow` instance, configures it appropriately (e.g, titlebar appearance),
|
||||||
/// injects an `NSObject` delegate wrapper, and retains the necessary Objective-C runtime
|
/// injects an `NSObject` delegate wrapper, and retains the necessary Objective-C runtime
|
||||||
/// pointers.
|
/// pointers.
|
||||||
pub fn new<T: AppDelegate>(window_id: usize, title: &str, dimensions: (f64, f64, f64, f64), content_view: &Component, app_ptr: *const T) -> Window {
|
pub fn new<T: AppDelegate>(window_id: usize, content_view: &Component, app_ptr: *const T) -> Window {
|
||||||
let (top, left, width, height) = dimensions;
|
let dimensions = NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.));
|
||||||
let dimensions = NSRect::new(NSPoint::new(top, left), NSSize::new(width, height));
|
|
||||||
|
|
||||||
let style = NSWindowStyleMask::NSResizableWindowMask |
|
let style = NSWindowStyleMask::NSResizableWindowMask |
|
||||||
NSWindowStyleMask::NSUnifiedTitleAndToolbarWindowMask | NSWindowStyleMask::NSMiniaturizableWindowMask |
|
NSWindowStyleMask::NSUnifiedTitleAndToolbarWindowMask | NSWindowStyleMask::NSMiniaturizableWindowMask |
|
||||||
NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask;
|
NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask | NSWindowStyleMask::NSFullSizeContentViewWindowMask;
|
||||||
|
|
||||||
let inner = unsafe {
|
let inner = unsafe {
|
||||||
let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
|
let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
|
||||||
|
|
@ -45,10 +45,8 @@ impl Window {
|
||||||
NO
|
NO
|
||||||
).autorelease();
|
).autorelease();
|
||||||
|
|
||||||
let title = NSString::alloc(nil).init_str(title);
|
msg_send![window, setTitlebarAppearsTransparent:YES];
|
||||||
window.setTitle_(title);
|
//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
|
// 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
|
// 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
|
/// 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
|
/// 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.
|
/// else, feel free to open an issue to discuss.
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ pub struct AppState {
|
||||||
|
|
||||||
impl AppDelegate for AppState {
|
impl AppDelegate for AppState {
|
||||||
fn did_finish_launching(&mut self) {
|
fn did_finish_launching(&mut self) {
|
||||||
|
self.window.set_title("Layout Test");
|
||||||
|
self.window.set_dimensions(100., 100., 600., 600.);
|
||||||
self.window.show();
|
self.window.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -72,15 +74,19 @@ fn main() {
|
||||||
let app = alchemy::shared_app();
|
let app = alchemy::shared_app();
|
||||||
|
|
||||||
app.register_styles("default", styles! {
|
app.register_styles("default", styles! {
|
||||||
message { width: 500; height: 100; background-color: yellow; color: black; }
|
root { background-color: #000; }
|
||||||
|
|
||||||
LOL {
|
LOL {
|
||||||
background-color: #307ace;
|
background-color: #307ace;
|
||||||
width: 500;
|
width: 500;
|
||||||
height: 230;
|
height: 230;
|
||||||
padding-top: 20;
|
padding-top: 20;
|
||||||
padding-left: 20;
|
padding-left: 20;
|
||||||
|
padding-right: 40;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message { width: 500; height: 100; background-color: yellow; color: black; }
|
||||||
|
|
||||||
boxxx {
|
boxxx {
|
||||||
background-color: rgba(245, 217, 28, .8);
|
background-color: rgba(245, 217, 28, .8);
|
||||||
width: 100;
|
width: 100;
|
||||||
|
|
@ -109,6 +115,8 @@ fn main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
app.run(AppState {
|
app.run(AppState {
|
||||||
window: Window::new("Testing...", (0., 0., 600., 600.), WindowState {})
|
window: Window::new(WindowState {
|
||||||
|
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,6 @@ impl RenderEngine {
|
||||||
if node.tag == "Fragment" {
|
if node.tag == "Fragment" {
|
||||||
node.props.children
|
node.props.children
|
||||||
} else {
|
} else {
|
||||||
println!("Def here...");
|
|
||||||
vec![RSX::VirtualNode(node)]
|
vec![RSX::VirtualNode(node)]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -113,6 +112,7 @@ impl RenderEngine {
|
||||||
let mut root_instance = component_store.get_mut(key)?;
|
let mut root_instance = component_store.get_mut(key)?;
|
||||||
let layout = root_instance.layout.unwrap();
|
let layout = root_instance.layout.unwrap();
|
||||||
let mut style = Style::default();
|
let mut style = Style::default();
|
||||||
|
THEME_ENGINE.configure_styles_for_keys(&root_instance.props.styles, &mut style, &mut root_instance.appearance);
|
||||||
style.size = Size {
|
style.size = Size {
|
||||||
width: Dimension::Points(600.),
|
width: Dimension::Points(600.),
|
||||||
height: Dimension::Points(600.)
|
height: Dimension::Points(600.)
|
||||||
|
|
@ -126,7 +126,6 @@ impl RenderEngine {
|
||||||
height: Number::Defined(600.)
|
height: Number::Defined(600.)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
println!("Applying layout...");
|
|
||||||
walk_and_apply_styles(key, &mut component_store, &mut layout_store)?;
|
walk_and_apply_styles(key, &mut component_store, &mut layout_store)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -161,7 +160,6 @@ fn recursively_diff_tree(
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_replace {
|
if is_replace {
|
||||||
println!("here, what?!");
|
|
||||||
unmount_component_tree(key, component_store, layout_store)?;
|
unmount_component_tree(key, component_store, layout_store)?;
|
||||||
//mount_component_tree(
|
//mount_component_tree(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -244,7 +242,6 @@ fn mount_component_tree(
|
||||||
|
|
||||||
let rendered = instance.component.render(&instance.props);
|
let rendered = instance.component.render(&instance.props);
|
||||||
// instance.get_snapshot_before_update()
|
// instance.get_snapshot_before_update()
|
||||||
println!("Rendered... {}", instance.tag);
|
|
||||||
component_store.insert(key, instance)?;
|
component_store.insert(key, instance)?;
|
||||||
|
|
||||||
match rendered {
|
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
|
// tag similar to what React does, which just hoists the children out of it and
|
||||||
// discards the rest.
|
// discards the rest.
|
||||||
if child.tag == "Fragment" {
|
if child.tag == "Fragment" {
|
||||||
println!(" In Fragment {}", child.props.children.len());
|
|
||||||
for child_tree in child.props.children {
|
for child_tree in child.props.children {
|
||||||
println!(" > WHAT");
|
|
||||||
if let RSX::VirtualNode(child_tree) = child_tree {
|
if let RSX::VirtualNode(child_tree) = child_tree {
|
||||||
let child_key = mount_component_tree(child_tree, component_store, layout_store)?;
|
let child_key = mount_component_tree(child_tree, component_store, layout_store)?;
|
||||||
|
|
||||||
|
|
@ -267,14 +262,14 @@ fn mount_component_tree(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!(" In regular");
|
|
||||||
let child_key = mount_component_tree(child, component_store, layout_store)?;
|
let child_key = mount_component_tree(child, component_store, layout_store)?;
|
||||||
|
|
||||||
component_store.add_child(key, child_key)?;
|
component_store.add_child(key, child_key)?;
|
||||||
if is_native_backed {
|
if is_native_backed {
|
||||||
link_layout_nodess(key, child_key, component_store, layout_store)?;
|
link_layout_nodess(key, child_key, component_store, layout_store)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { println!("WTF"); },
|
},
|
||||||
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// return an RSX::VirtualNode(ErrorComponentView) or something?
|
// return an RSX::VirtualNode(ErrorComponentView) or something?
|
||||||
|
|
@ -372,7 +367,6 @@ fn walk_and_apply_styles(
|
||||||
}
|
}
|
||||||
|
|
||||||
for child in components.children(key)? {
|
for child in components.children(key)? {
|
||||||
println!("Nesting");
|
|
||||||
walk_and_apply_styles(child, components, layouts)?;
|
walk_and_apply_styles(child, components, layouts)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ pub use style_keys::StyleKey;
|
||||||
pub type StylesList = SpacedSet<StyleKey>;
|
pub type StylesList = SpacedSet<StyleKey>;
|
||||||
|
|
||||||
pub mod styles;
|
pub mod styles;
|
||||||
pub use styles::{Appearance, Styles};
|
pub use styles::{Appearance, Styles, Style};
|
||||||
|
|
||||||
pub mod stylesheet;
|
pub mod stylesheet;
|
||||||
pub use stylesheet::StyleSheet;
|
pub use stylesheet::StyleSheet;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ struct AppState {
|
||||||
|
|
||||||
impl AppDelegate for AppState {
|
impl AppDelegate for AppState {
|
||||||
fn did_finish_launching(&mut self) {
|
fn did_finish_launching(&mut self) {
|
||||||
|
self.window.set_title("LOL");
|
||||||
|
self.window.set_dimensions(10., 10., 600., 600.);
|
||||||
self.window.show();
|
self.window.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -55,9 +57,10 @@ fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let dimensions = (0., 0., 600., 600.);
|
|
||||||
app.run(AppState {
|
app.run(AppState {
|
||||||
window: Window::new("Le Appy App", dimensions, WindowState {})
|
window: Window::new(WindowState {
|
||||||
|
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
Reference in a new issue