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 {
|
||||
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 {
|
||||
|
||||
})
|
||||
});
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
})
|
||||
});
|
||||
}
|
||||
```
|
||||
|
|
|
|||
Reference in a new issue