Updates for recent versions of Rust.
* Added lots of dyns * Removed unused whitespace. * Removed rust-toolchain because stable rust compiles the project. * Fixed Doc-tests with ignore keyword.
This commit is contained in:
parent
f15cf258af
commit
5695ec9b94
23 changed files with 170 additions and 171 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
//! This module implements the Application structure and associated
|
//! This module implements the Application structure and associated
|
||||||
//! lifecycle methods. You typically never create this struct yourself;
|
//! lifecycle methods. You typically never create this struct yourself;
|
||||||
//! in Alchemy, there's a global `shared_app` that you should use to work
|
//! in Alchemy, there's a global `shared_app` that you should use to work
|
||||||
//! with the `App` struct.
|
//! with the `App` struct.
|
||||||
//!
|
//!
|
||||||
|
|
@ -28,7 +28,7 @@ impl AppDelegate for DefaultAppDelegate {}
|
||||||
/// also stored here for easy access.
|
/// also stored here for easy access.
|
||||||
pub struct App {
|
pub struct App {
|
||||||
pub(crate) bridge: Mutex<Option<PlatformAppBridge>>,
|
pub(crate) bridge: Mutex<Option<PlatformAppBridge>>,
|
||||||
pub delegate: Mutex<Box<AppDelegate>>,
|
pub delegate: Mutex<Box<dyn AppDelegate>>,
|
||||||
pub windows: WindowManager
|
pub windows: WindowManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ impl App {
|
||||||
*bridge = Some(PlatformAppBridge::new(ptr));
|
*bridge = Some(PlatformAppBridge::new(ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience method for registering one-off styles. Typically, you would want
|
/// Convenience method for registering one-off styles. Typically, you would want
|
||||||
/// to store your stylesheets as separate files, to enable hot-reloading - but it's
|
/// to store your stylesheets as separate files, to enable hot-reloading - but it's
|
||||||
/// conceivable that you might want to just have them in your app, too, and this enables
|
/// conceivable that you might want to just have them in your app, too, and this enables
|
||||||
/// that use case.
|
/// that use case.
|
||||||
|
|
@ -88,35 +88,35 @@ impl AppDelegate for App {
|
||||||
let mut delegate = self.delegate.lock().unwrap();
|
let mut delegate = self.delegate.lock().unwrap();
|
||||||
delegate.will_finish_launching();
|
delegate.will_finish_launching();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the application did finish launching.
|
/// Called when the application did finish launching.
|
||||||
fn did_finish_launching(&mut self) {
|
fn did_finish_launching(&mut self) {
|
||||||
let mut delegate = self.delegate.lock().unwrap();
|
let mut delegate = self.delegate.lock().unwrap();
|
||||||
delegate.did_finish_launching();
|
delegate.did_finish_launching();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the application will become active. We can use this, for instance,
|
/// Called when the application will become active. We can use this, for instance,
|
||||||
/// to resume rendering cycles and so on.
|
/// to resume rendering cycles and so on.
|
||||||
fn will_become_active(&mut self) {
|
fn will_become_active(&mut self) {
|
||||||
let mut delegate = self.delegate.lock().unwrap();
|
let mut delegate = self.delegate.lock().unwrap();
|
||||||
delegate.will_become_active();
|
delegate.will_become_active();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the application did become active. We can use this, for instance,
|
/// Called when the application did become active. We can use this, for instance,
|
||||||
/// to resume rendering cycles and so on.
|
/// to resume rendering cycles and so on.
|
||||||
fn did_become_active(&mut self) {
|
fn did_become_active(&mut self) {
|
||||||
let mut delegate = self.delegate.lock().unwrap();
|
let mut delegate = self.delegate.lock().unwrap();
|
||||||
delegate.did_become_active();
|
delegate.did_become_active();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the application will resigned active. We can use this, for instance,
|
/// Called when the application will resigned active. We can use this, for instance,
|
||||||
/// to pause rendering cycles and so on.
|
/// to pause rendering cycles and so on.
|
||||||
fn will_resign_active(&mut self) {
|
fn will_resign_active(&mut self) {
|
||||||
let mut delegate = self.delegate.lock().unwrap();
|
let mut delegate = self.delegate.lock().unwrap();
|
||||||
delegate.will_resign_active();
|
delegate.will_resign_active();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the application has resigned active. We can use this, for instance,
|
/// Called when the application has resigned active. We can use this, for instance,
|
||||||
/// to pause rendering cycles and so on.
|
/// to pause rendering cycles and so on.
|
||||||
fn did_resign_active(&mut self) {
|
fn did_resign_active(&mut self) {
|
||||||
let mut delegate = self.delegate.lock().unwrap();
|
let mut delegate = self.delegate.lock().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! A Fragment is for components that want to return or hoist multiple inner
|
//! A Fragment is for components that want to return or hoist multiple inner
|
||||||
//! child nodes. `impl IntoIterator` can't be used in trait returns right now,
|
//! child nodes. `impl IntoIterator` can't be used in trait returns right now,
|
||||||
//! and this API more or less matches what React presents, so I'm fine with it...
|
//! and this API more or less matches what React presents, so I'm fine with it...
|
||||||
//! but as the language stabilizes even further I'd love to get rid of this and
|
//! but as the language stabilizes even further I'd love to get rid of this and
|
||||||
//! just allow returning arbitrary iterators.
|
//! just allow returning arbitrary iterators.
|
||||||
|
|
||||||
use alchemy_lifecycle::ComponentKey;
|
use alchemy_lifecycle::ComponentKey;
|
||||||
|
|
@ -12,7 +12,7 @@ pub struct FragmentProps;
|
||||||
/// Fragments are special - you can do something like the following in cases where you
|
/// Fragments are special - you can do something like the following in cases where you
|
||||||
/// want to render some views without requiring an intermediate view.
|
/// want to render some views without requiring an intermediate view.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```ignore
|
||||||
/// <Fragment>
|
/// <Fragment>
|
||||||
/// <View />
|
/// <View />
|
||||||
/// <View />
|
/// <View />
|
||||||
|
|
@ -29,7 +29,7 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Props for Fragment {
|
impl Props for Fragment {
|
||||||
fn set_props(&mut self, _: &mut std::any::Any) {}
|
fn set_props(&mut self, _: &mut dyn std::any::Any) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Fragment {
|
impl Component for Fragment {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//! Handles hoisting per-platform specific Text components.
|
//! Handles hoisting per-platform specific Text components.
|
||||||
//! Each platform needs the freedom to do some specific things,
|
//! Each platform needs the freedom to do some specific things,
|
||||||
//! hence why they're all (somewhat annoyingly, but lovingly) re-implemented
|
//! hence why they're all (somewhat annoyingly, but lovingly) re-implemented
|
||||||
//! as bridges.
|
//! as bridges.
|
||||||
|
|
||||||
use std::sync::{Mutex};
|
use std::sync::{Mutex};
|
||||||
|
|
@ -22,7 +22,7 @@ pub struct TextProps;
|
||||||
///
|
///
|
||||||
/// Views accept styles and event callbacks as props. For example:
|
/// Views accept styles and event callbacks as props. For example:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```ignore
|
||||||
/// <Text styles=["styleKey1", "styleKey2"] />
|
/// <Text styles=["styleKey1", "styleKey2"] />
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Text(Mutex<PlatformTextBridge>);
|
pub struct Text(Mutex<PlatformTextBridge>);
|
||||||
|
|
@ -38,7 +38,7 @@ impl Text {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Props for Text {
|
impl Props for Text {
|
||||||
fn set_props(&mut self, _: &mut std::any::Any) {}
|
fn set_props(&mut self, _: &mut dyn std::any::Any) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Text {
|
impl Component for Text {
|
||||||
|
|
@ -47,7 +47,7 @@ impl Component for Text {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_native_backing_node(&self) -> bool { true }
|
fn has_native_backing_node(&self) -> bool { true }
|
||||||
|
|
||||||
fn borrow_native_backing_node(&self) -> Option<PlatformSpecificNodeType> {
|
fn borrow_native_backing_node(&self) -> Option<PlatformSpecificNodeType> {
|
||||||
let bridge = self.0.lock().unwrap();
|
let bridge = self.0.lock().unwrap();
|
||||||
Some(bridge.borrow_native_backing_node())
|
Some(bridge.borrow_native_backing_node())
|
||||||
|
|
@ -75,10 +75,10 @@ impl Component for Text {
|
||||||
RSX::VirtualText(s) => s.0.to_owned(),
|
RSX::VirtualText(s) => s.0.to_owned(),
|
||||||
_ => String::new()
|
_ => String::new()
|
||||||
}).collect::<String>();
|
}).collect::<String>();
|
||||||
|
|
||||||
let mut bridge = self.0.lock().unwrap();
|
let mut bridge = self.0.lock().unwrap();
|
||||||
bridge.set_text(text);
|
bridge.set_text(text);
|
||||||
|
|
||||||
Ok(RSX::None)
|
Ok(RSX::None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//! Handles hoisting per-platform specific View components.
|
//! Handles hoisting per-platform specific View components.
|
||||||
//! Each platform needs the freedom to do some specific things,
|
//! Each platform needs the freedom to do some specific things,
|
||||||
//! hence why they're all (somewhat annoyingly, but lovingly) re-implemented
|
//! hence why they're all (somewhat annoyingly, but lovingly) re-implemented
|
||||||
//! as bridges.
|
//! as bridges.
|
||||||
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
@ -24,7 +24,7 @@ pub struct ViewProps;
|
||||||
///
|
///
|
||||||
/// Views accept styles and event callbacks as props. For example:
|
/// Views accept styles and event callbacks as props. For example:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```ignore
|
||||||
/// <View styles=["styleKey1", "styleKey2"] />
|
/// <View styles=["styleKey1", "styleKey2"] />
|
||||||
/// ```
|
/// ```
|
||||||
pub struct View {
|
pub struct View {
|
||||||
|
|
@ -46,7 +46,7 @@ impl View {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Props for View {
|
impl Props for View {
|
||||||
fn set_props(&mut self, _: &mut std::any::Any) {}
|
fn set_props(&mut self, _: &mut dyn std::any::Any) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for View {
|
impl Component for View {
|
||||||
|
|
@ -55,7 +55,7 @@ impl Component for View {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_native_backing_node(&self) -> bool { true }
|
fn has_native_backing_node(&self) -> bool { true }
|
||||||
|
|
||||||
fn borrow_native_backing_node(&self) -> Option<PlatformSpecificNodeType> {
|
fn borrow_native_backing_node(&self) -> Option<PlatformSpecificNodeType> {
|
||||||
let bridge = self.bridge.lock().unwrap();
|
let bridge = self.bridge.lock().unwrap();
|
||||||
Some(bridge.borrow_native_backing_node())
|
Some(bridge.borrow_native_backing_node())
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
//! right?
|
//! right?
|
||||||
//!
|
//!
|
||||||
//! There's also the fact that a user could opt to close a window. If that happens, we want to be
|
//! There's also the fact that a user could opt to close a window. If that happens, we want to be
|
||||||
//! able to remove it from our structure... hence this manager that acts as a lightweight interface
|
//! able to remove it from our structure... hence this manager that acts as a lightweight interface
|
||||||
//! for managing per-platform Window instances.
|
//! for managing per-platform Window instances.
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
@ -32,7 +32,7 @@ impl WindowManager {
|
||||||
/// Adds an `AppWindow` to this instance.
|
/// Adds an `AppWindow` to this instance.
|
||||||
pub(crate) fn add(&self, window: Arc<Mutex<AppWindow>>) {
|
pub(crate) fn add(&self, window: Arc<Mutex<AppWindow>>) {
|
||||||
let mut windows = self.0.lock().unwrap();
|
let mut windows = self.0.lock().unwrap();
|
||||||
if let None = windows.iter().position(|w| Arc::ptr_eq(&w, &window)) {
|
if windows.iter().position(|w| Arc::ptr_eq(&w, &window)).is_none() {
|
||||||
windows.push(window);
|
windows.push(window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -46,7 +46,7 @@ impl WindowManager {
|
||||||
let mut windows = self.0.lock().unwrap();
|
let mut windows = self.0.lock().unwrap();
|
||||||
if let Some(index) = windows.iter().position(|window| {
|
if let Some(index) = windows.iter().position(|window| {
|
||||||
let mut w = window.lock().unwrap();
|
let mut w = window.lock().unwrap();
|
||||||
|
|
||||||
if w.id == window_id {
|
if w.id == window_id {
|
||||||
w.delegate.will_close();
|
w.delegate.will_close();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ pub struct AppWindow {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub dimensions: (f64, f64, f64, f64),
|
pub dimensions: (f64, f64, f64, f64),
|
||||||
pub bridge: PlatformWindowBridge,
|
pub bridge: PlatformWindowBridge,
|
||||||
pub delegate: Box<WindowDelegate>,
|
pub delegate: Box<dyn WindowDelegate>,
|
||||||
pub render_key: ComponentKey
|
pub render_key: ComponentKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,7 +92,7 @@ impl 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;
|
||||||
|
|
||||||
// This unwrap() is fine, since we implement View ourselves in Alchemy
|
// This unwrap() is fine, since we implement View ourselves in Alchemy
|
||||||
let backing_node = view.borrow_native_backing_node().unwrap();
|
let backing_node = view.borrow_native_backing_node().unwrap();
|
||||||
let bridge = PlatformWindowBridge::new(window_id, backing_node, shared_app_ptr);
|
let bridge = PlatformWindowBridge::new(window_id, backing_node, shared_app_ptr);
|
||||||
|
|
@ -101,13 +101,13 @@ impl Window {
|
||||||
Ok(key) => key,
|
Ok(key) => key,
|
||||||
Err(_e) => { panic!("Uhhhh this really messed up"); }
|
Err(_e) => { panic!("Uhhhh this really messed up"); }
|
||||||
};
|
};
|
||||||
|
|
||||||
Window(Arc::new(Mutex::new(AppWindow {
|
Window(Arc::new(Mutex::new(AppWindow {
|
||||||
id: window_id,
|
id: window_id,
|
||||||
style_keys: "".into(),
|
style_keys: "".into(),
|
||||||
title: "".into(),
|
title: "".into(),
|
||||||
dimensions: (0., 0., 0., 0.),
|
dimensions: (0., 0., 0., 0.),
|
||||||
bridge: bridge,
|
bridge,
|
||||||
delegate: Box::new(delegate),
|
delegate: Box::new(delegate),
|
||||||
render_key: key
|
render_key: key
|
||||||
})))
|
})))
|
||||||
|
|
@ -147,7 +147,7 @@ impl Window {
|
||||||
/// Closes the window, unregistering it from the window manager in the process and ensuring the
|
/// Closes the window, unregistering it from the window manager in the process and ensuring the
|
||||||
/// necessary delegate method(s) are fired.
|
/// necessary delegate method(s) are fired.
|
||||||
pub fn close(&self) {
|
pub fn close(&self) {
|
||||||
let window_id = self.0.lock().unwrap().id;
|
let window_id = self.0.lock().unwrap().id;
|
||||||
SHARED_APP.windows.will_close(window_id);
|
SHARED_APP.windows.will_close(window_id);
|
||||||
let mut window = self.0.lock().unwrap();
|
let mut window = self.0.lock().unwrap();
|
||||||
window.close();
|
window.close();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
cyclomatic-complexity-threshold = 30
|
cognitive-complexity-threshold = 30
|
||||||
doc-valid-idents = [
|
doc-valid-idents = [
|
||||||
"MiB", "GiB", "TiB", "PiB", "EiB",
|
"MiB", "GiB", "TiB", "PiB", "EiB",
|
||||||
"DirectX", "OpenGL", "TrueType",
|
"DirectX", "OpenGL", "TrueType",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! A wrapper for `NSApplication` on macOS. If you opt in to the `cocoa` feature on
|
//! A wrapper for `NSApplication` on macOS. If you opt in to the `cocoa` feature on
|
||||||
//! Alchemy, this will loop system-level application events back to your `AppDelegate`.
|
//! Alchemy, this will loop system-level application events back to your `AppDelegate`.
|
||||||
|
|
||||||
use std::sync::{Once, ONCE_INIT};
|
use std::sync::{Once};
|
||||||
|
|
||||||
use cocoa::base::{id, nil};
|
use cocoa::base::{id, nil};
|
||||||
use cocoa::appkit::{NSApplication, NSRunningApplication};
|
use cocoa::appkit::{NSApplication, NSRunningApplication};
|
||||||
|
|
@ -15,7 +15,7 @@ use alchemy_lifecycle::traits::AppDelegate;
|
||||||
|
|
||||||
static ALCHEMY_APP_PTR: &str = "alchemyParentAppPtr";
|
static ALCHEMY_APP_PTR: &str = "alchemyParentAppPtr";
|
||||||
|
|
||||||
/// A wrapper for `NSApplication`. It holds (retains) pointers for the Objective-C runtime,
|
/// A wrapper for `NSApplication`. It holds (retains) pointers for the Objective-C runtime,
|
||||||
/// which is where our application instance lives. It also injects an `NSObject` subclass,
|
/// which is where our application instance lives. It also injects an `NSObject` subclass,
|
||||||
/// which acts as the Delegate, looping back into our Alchemy shared application.
|
/// which acts as the Delegate, looping back into our Alchemy shared application.
|
||||||
pub struct App {
|
pub struct App {
|
||||||
|
|
@ -34,7 +34,7 @@ impl App {
|
||||||
app.setActivationPolicy_(cocoa::appkit::NSApplicationActivationPolicyRegular);
|
app.setActivationPolicy_(cocoa::appkit::NSApplicationActivationPolicyRegular);
|
||||||
Id::from_ptr(app)
|
Id::from_ptr(app)
|
||||||
};
|
};
|
||||||
|
|
||||||
let delegate = unsafe {
|
let delegate = unsafe {
|
||||||
let delegate_class = register_app_delegate_class::<T>();
|
let delegate_class = register_app_delegate_class::<T>();
|
||||||
let delegate: id = msg_send![delegate_class, new];
|
let delegate: id = msg_send![delegate_class, new];
|
||||||
|
|
@ -127,7 +127,7 @@ extern fn will_terminate<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
||||||
/// pointers we need to have.
|
/// pointers we need to have.
|
||||||
fn register_app_delegate_class<T: AppDelegate>() -> *const Class {
|
fn register_app_delegate_class<T: AppDelegate>() -> *const Class {
|
||||||
static mut DELEGATE_CLASS: *const Class = 0 as *const Class;
|
static mut DELEGATE_CLASS: *const Class = 0 as *const Class;
|
||||||
static INIT: Once = ONCE_INIT;
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
INIT.call_once(|| unsafe {
|
INIT.call_once(|| unsafe {
|
||||||
let superclass = Class::get("NSObject").unwrap();
|
let superclass = Class::get("NSObject").unwrap();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! This wraps NTextField on macOS, and configures it to act like a label
|
//! This wraps NTextField on macOS, and configures it to act like a label
|
||||||
//! with standard behavior that most users would expect.
|
//! with standard behavior that most users would expect.
|
||||||
|
|
||||||
use std::sync::{Once, ONCE_INIT};
|
use std::sync::{Once};
|
||||||
|
|
||||||
use objc_id::{Id, ShareId};
|
use objc_id::{Id, ShareId};
|
||||||
use objc::{msg_send, sel, sel_impl};
|
use objc::{msg_send, sel, sel_impl};
|
||||||
|
|
@ -19,7 +19,7 @@ use alchemy_lifecycle::traits::PlatformSpecificNodeType;
|
||||||
|
|
||||||
static ALCHEMY_DELEGATE: &str = "alchemyDelegate";
|
static ALCHEMY_DELEGATE: &str = "alchemyDelegate";
|
||||||
|
|
||||||
/// A wrapper for `NSText`. This holds retained pointers for the Objective-C
|
/// A wrapper for `NSText`. This holds retained pointers for the Objective-C
|
||||||
/// runtime - namely, the view itself, and associated things such as background
|
/// runtime - namely, the view itself, and associated things such as background
|
||||||
/// colors and so forth.
|
/// colors and so forth.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -83,7 +83,7 @@ impl Text {
|
||||||
|
|
||||||
self.background_color = appearance.background_color.into_nscolor();
|
self.background_color = appearance.background_color.into_nscolor();
|
||||||
self.text_color = appearance.text_color.into_nscolor();
|
self.text_color = appearance.text_color.into_nscolor();
|
||||||
|
|
||||||
msg_send![&*self.inner_mut, setFrame:rect];
|
msg_send![&*self.inner_mut, setFrame:rect];
|
||||||
msg_send![&*self.inner_mut, setBackgroundColor:&*self.background_color];
|
msg_send![&*self.inner_mut, setBackgroundColor:&*self.background_color];
|
||||||
msg_send![&*self.inner_mut, setTextColor:&*self.text_color];
|
msg_send![&*self.inner_mut, setTextColor:&*self.text_color];
|
||||||
|
|
@ -112,12 +112,12 @@ extern fn enforce_normalcy(_: &Object, _: Sel) -> BOOL {
|
||||||
/// to store.
|
/// to store.
|
||||||
fn register_class() -> *const Class {
|
fn register_class() -> *const Class {
|
||||||
static mut VIEW_CLASS: *const Class = 0 as *const Class;
|
static mut VIEW_CLASS: *const Class = 0 as *const Class;
|
||||||
static INIT: Once = ONCE_INIT;
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
INIT.call_once(|| unsafe {
|
INIT.call_once(|| unsafe {
|
||||||
let superclass = Class::get("NSTextField").unwrap();
|
let superclass = Class::get("NSTextField").unwrap();
|
||||||
let mut decl = ClassDecl::new("AlchemyTextField", superclass).unwrap();
|
let mut decl = ClassDecl::new("AlchemyTextField", superclass).unwrap();
|
||||||
|
|
||||||
// Force NSText to render from the top-left, not bottom-left
|
// Force NSText to render from the top-left, not bottom-left
|
||||||
//decl.add_method(sel!(isFlipped), enforce_normalcy as extern fn(&Object, _) -> BOOL);
|
//decl.add_method(sel!(isFlipped), enforce_normalcy as extern fn(&Object, _) -> BOOL);
|
||||||
|
|
||||||
|
|
@ -132,7 +132,7 @@ fn register_class() -> *const Class {
|
||||||
// Note that NSText's don't really have a "delegate", I'm just using it here
|
// Note that NSText's don't really have a "delegate", I'm just using it here
|
||||||
// for common terminology sake.
|
// for common terminology sake.
|
||||||
decl.add_ivar::<usize>(ALCHEMY_DELEGATE);
|
decl.add_ivar::<usize>(ALCHEMY_DELEGATE);
|
||||||
|
|
||||||
VIEW_CLASS = decl.register();
|
VIEW_CLASS = decl.register();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! Implements a View Component struct. The most common
|
//! Implements a View Component struct. The most common
|
||||||
//! basic building block of any app. Wraps NSView on macOS.
|
//! basic building block of any app. Wraps NSView on macOS.
|
||||||
|
|
||||||
use std::sync::{Once, ONCE_INIT};
|
use std::sync::{Once};
|
||||||
|
|
||||||
use objc_id::{Id, ShareId};
|
use objc_id::{Id, ShareId};
|
||||||
use objc::{msg_send, sel, sel_impl};
|
use objc::{msg_send, sel, sel_impl};
|
||||||
|
|
@ -20,7 +20,7 @@ use alchemy_lifecycle::traits::PlatformSpecificNodeType;
|
||||||
static ALCHEMY_DELEGATE: &str = "alchemyDelegate";
|
static ALCHEMY_DELEGATE: &str = "alchemyDelegate";
|
||||||
static BACKGROUND_COLOR: &str = "alchemyBackgroundColor";
|
static BACKGROUND_COLOR: &str = "alchemyBackgroundColor";
|
||||||
|
|
||||||
/// A wrapper for `NSView`. This holds retained pointers for the Objective-C
|
/// A wrapper for `NSView`. This holds retained pointers for the Objective-C
|
||||||
/// runtime - namely, the view itself, and associated things such as background
|
/// runtime - namely, the view itself, and associated things such as background
|
||||||
/// colors and so forth.
|
/// colors and so forth.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -76,8 +76,8 @@ impl View {
|
||||||
);
|
);
|
||||||
|
|
||||||
self.background_color = appearance.background_color.into_nscolor();
|
self.background_color = appearance.background_color.into_nscolor();
|
||||||
self.inner_mut.set_ivar(BACKGROUND_COLOR, &*self.background_color);
|
self.inner_mut.set_ivar(BACKGROUND_COLOR, &*self.background_color);
|
||||||
|
|
||||||
msg_send![&*self.inner_mut, setFrame:rect];
|
msg_send![&*self.inner_mut, setFrame:rect];
|
||||||
msg_send![&*self.inner_mut, setNeedsDisplay:YES];
|
msg_send![&*self.inner_mut, setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|
@ -107,12 +107,12 @@ extern fn update_layer(this: &Object, _: Sel) {
|
||||||
/// to store.
|
/// to store.
|
||||||
fn register_class() -> *const Class {
|
fn register_class() -> *const Class {
|
||||||
static mut VIEW_CLASS: *const Class = 0 as *const Class;
|
static mut VIEW_CLASS: *const Class = 0 as *const Class;
|
||||||
static INIT: Once = ONCE_INIT;
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
INIT.call_once(|| unsafe {
|
INIT.call_once(|| unsafe {
|
||||||
let superclass = Class::get("NSView").unwrap();
|
let superclass = Class::get("NSView").unwrap();
|
||||||
let mut decl = ClassDecl::new("AlchemyView", superclass).unwrap();
|
let mut decl = ClassDecl::new("AlchemyView", superclass).unwrap();
|
||||||
|
|
||||||
// Force NSView to render from the top-left, not bottom-left
|
// Force NSView to render from the top-left, not bottom-left
|
||||||
decl.add_method(sel!(isFlipped), enforce_normalcy as extern fn(&Object, _) -> BOOL);
|
decl.add_method(sel!(isFlipped), enforce_normalcy as extern fn(&Object, _) -> BOOL);
|
||||||
|
|
||||||
|
|
@ -131,7 +131,7 @@ fn register_class() -> *const Class {
|
||||||
// for common terminology sake.
|
// for common terminology sake.
|
||||||
decl.add_ivar::<usize>(ALCHEMY_DELEGATE);
|
decl.add_ivar::<usize>(ALCHEMY_DELEGATE);
|
||||||
decl.add_ivar::<id>(BACKGROUND_COLOR);
|
decl.add_ivar::<id>(BACKGROUND_COLOR);
|
||||||
|
|
||||||
VIEW_CLASS = decl.register();
|
VIEW_CLASS = decl.register();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
//! Cocoa and associated widgets. This also handles looping back
|
//! Cocoa and associated widgets. This also handles looping back
|
||||||
//! lifecycle events, such as window resizing or close events.
|
//! lifecycle events, such as window resizing or close events.
|
||||||
|
|
||||||
use std::sync::{Once, ONCE_INIT};
|
use std::sync::{Once};
|
||||||
|
|
||||||
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};
|
||||||
|
|
@ -19,7 +19,7 @@ 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";
|
||||||
|
|
||||||
/// A wrapper for `NSWindow`. Holds (retains) pointers for the Objective-C runtime
|
/// A wrapper for `NSWindow`. Holds (retains) pointers for the Objective-C runtime
|
||||||
/// where our `NSWindow` and associated delegate live.
|
/// where our `NSWindow` and associated delegate live.
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
pub inner: ShareId<Object>,
|
pub inner: ShareId<Object>,
|
||||||
|
|
@ -39,7 +39,7 @@ impl Window {
|
||||||
|
|
||||||
let inner = unsafe {
|
let inner = unsafe {
|
||||||
let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
|
let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
|
||||||
dimensions,
|
dimensions,
|
||||||
style,
|
style,
|
||||||
NSBackingStoreType::NSBackingStoreBuffered,
|
NSBackingStoreType::NSBackingStoreBuffered,
|
||||||
NO
|
NO
|
||||||
|
|
@ -52,14 +52,14 @@ impl Window {
|
||||||
// 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
|
||||||
// Objective-C runtime gets out of sync.
|
// Objective-C runtime gets out of sync.
|
||||||
msg_send![window, setReleasedWhenClosed:NO];
|
msg_send![window, setReleasedWhenClosed:NO];
|
||||||
|
|
||||||
//if let Some(view_ptr) = content_view.borrow_native_backing_node() {
|
//if let Some(view_ptr) = content_view.borrow_native_backing_node() {
|
||||||
msg_send![window, setContentView:content_view];
|
msg_send![window, setContentView:content_view];
|
||||||
//}
|
//}
|
||||||
|
|
||||||
ShareId::from_ptr(window)
|
ShareId::from_ptr(window)
|
||||||
};
|
};
|
||||||
|
|
||||||
let delegate = unsafe {
|
let delegate = unsafe {
|
||||||
let delegate_class = register_window_class::<T>();
|
let delegate_class = register_window_class::<T>();
|
||||||
let delegate: id = msg_send![delegate_class, new];
|
let delegate: id = msg_send![delegate_class, new];
|
||||||
|
|
@ -128,7 +128,7 @@ impl Drop for Window {
|
||||||
/// safer than sorry.
|
/// safer than sorry.
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// This bridging link needs to be broken on Drop.
|
// This bridging link needs to be broken on Drop.
|
||||||
unsafe {
|
unsafe {
|
||||||
msg_send![&*self.inner, setDelegate:nil];
|
msg_send![&*self.inner, setDelegate:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -149,7 +149,7 @@ extern fn will_close<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
||||||
/// need to do.
|
/// need to do.
|
||||||
fn register_window_class<T: AppDelegate>() -> *const Class {
|
fn register_window_class<T: AppDelegate>() -> *const Class {
|
||||||
static mut DELEGATE_CLASS: *const Class = 0 as *const Class;
|
static mut DELEGATE_CLASS: *const Class = 0 as *const Class;
|
||||||
static INIT: Once = ONCE_INIT;
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
INIT.call_once(|| unsafe {
|
INIT.call_once(|| unsafe {
|
||||||
let superclass = Class::get("NSObject").unwrap();
|
let superclass = Class::get("NSObject").unwrap();
|
||||||
|
|
@ -157,9 +157,9 @@ fn register_window_class<T: AppDelegate>() -> *const Class {
|
||||||
|
|
||||||
decl.add_ivar::<usize>(APP_PTR);
|
decl.add_ivar::<usize>(APP_PTR);
|
||||||
decl.add_ivar::<usize>(WINDOW_MANAGER_ID);
|
decl.add_ivar::<usize>(WINDOW_MANAGER_ID);
|
||||||
|
|
||||||
decl.add_method(sel!(windowWillClose:), will_close::<T> as extern fn(&Object, _, _));
|
decl.add_method(sel!(windowWillClose:), will_close::<T> as extern fn(&Object, _, _));
|
||||||
|
|
||||||
DELEGATE_CLASS = decl.register();
|
DELEGATE_CLASS = decl.register();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,4 @@
|
||||||
|
|
||||||
/// A generic Error type that we use. It currently just aliases to `Box<std::error::Error>`,
|
/// A generic Error type that we use. It currently just aliases to `Box<std::error::Error>`,
|
||||||
/// but could change in the future.
|
/// but could change in the future.
|
||||||
pub type Error = Box<std::error::Error>;
|
pub type Error = Box<dyn std::error::Error>;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ impl GenericRootView {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Props for GenericRootView {
|
impl Props for GenericRootView {
|
||||||
fn set_props(&mut self, _: &mut Any) {}
|
fn set_props(&mut self, _: &mut dyn Any) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for GenericRootView {
|
impl Component for GenericRootView {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//! Implements tree diffing, updating, and so on. Unlike a lot of the VDom implementations
|
//! Implements tree diffing, updating, and so on. Unlike a lot of the VDom implementations
|
||||||
//! you find littered around the web, this is a bit more ECS-ish, and expects Components to retain
|
//! you find littered around the web, this is a bit more ECS-ish, and expects Components to retain
|
||||||
//! their `ComponentKey` passed in their constructor if they want to update. Doing this
|
//! their `ComponentKey` passed in their constructor if they want to update. Doing this
|
||||||
//! enables us to avoid re-scanning or diffing an entire tree.
|
//! enables us to avoid re-scanning or diffing an entire tree.
|
||||||
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
@ -48,12 +48,12 @@ impl RenderEngine {
|
||||||
// pub fn queue_update_for(&self, component_ptr: usize, updater: Box<Fn() -> Component + Send + Sync + 'static>) {
|
// pub fn queue_update_for(&self, component_ptr: usize, updater: Box<Fn() -> Component + Send + Sync + 'static>) {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/// `Window`'s (or anything "root" in nature) need to register with the
|
/// `Window`'s (or anything "root" in nature) need to register with the
|
||||||
/// reconciler for things like setState to work properly. When they do so,
|
/// reconciler for things like setState to work properly. When they do so,
|
||||||
/// they get a key back. When they want to instruct the global `RenderEngine`
|
/// they get a key back. When they want to instruct the global `RenderEngine`
|
||||||
/// to re-render or update their tree, they pass that key and whatever the new tree
|
/// to re-render or update their tree, they pass that key and whatever the new tree
|
||||||
/// should be.
|
/// should be.
|
||||||
pub fn register_root_component<C: Component + 'static>(&self, component: C) -> Result<ComponentKey, Box<Error>> {
|
pub fn register_root_component<C: Component + 'static>(&self, component: C) -> Result<ComponentKey, Box<dyn Error>> {
|
||||||
// Conceivably, this doesn't NEED to be a thing... but for now it is. If you've stumbled
|
// Conceivably, this doesn't NEED to be a thing... but for now it is. If you've stumbled
|
||||||
// upon here, wayward traveler, in need of a non-native-root-component, please open an
|
// upon here, wayward traveler, in need of a non-native-root-component, please open an
|
||||||
// issue to discuss. :)
|
// issue to discuss. :)
|
||||||
|
|
@ -75,7 +75,7 @@ impl RenderEngine {
|
||||||
Ok(component_key)
|
Ok(component_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rendering the root node is a bit different than rendering or updating other nodes, as we
|
/// Rendering the root node is a bit different than rendering or updating other nodes, as we
|
||||||
/// never want to unmount it, and the results come from a non-`Component` entity (e.g, a
|
/// never want to unmount it, and the results come from a non-`Component` entity (e.g, a
|
||||||
/// `Window`). Thus, for this one, we do some manual mucking with what we know is the
|
/// `Window`). Thus, for this one, we do some manual mucking with what we know is the
|
||||||
/// root view (a `Window` or such root component would call this with it's registered
|
/// root view (a `Window` or such root component would call this with it's registered
|
||||||
|
|
@ -85,7 +85,7 @@ impl RenderEngine {
|
||||||
key: ComponentKey,
|
key: ComponentKey,
|
||||||
dimensions: (f64, f64),
|
dimensions: (f64, f64),
|
||||||
child: RSX
|
child: RSX
|
||||||
) -> Result<(), Box<Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
let mut component_store = self.components.lock().unwrap();
|
let mut component_store = self.components.lock().unwrap();
|
||||||
let mut layout_store = self.layouts.lock().unwrap();
|
let mut layout_store = self.layouts.lock().unwrap();
|
||||||
|
|
||||||
|
|
@ -122,7 +122,7 @@ impl RenderEngine {
|
||||||
width: Number::Defined(dimensions.0 as f32),
|
width: Number::Defined(dimensions.0 as f32),
|
||||||
height: Number::Defined(dimensions.1 as f32)
|
height: Number::Defined(dimensions.1 as f32)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
walk_and_apply_styles(key, &mut component_store, &mut layout_store)?;
|
walk_and_apply_styles(key, &mut component_store, &mut layout_store)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -138,8 +138,8 @@ fn recursively_diff_tree(
|
||||||
new_tree: RSX,
|
new_tree: RSX,
|
||||||
component_store: &mut ComponentStore,
|
component_store: &mut ComponentStore,
|
||||||
layout_store: &mut LayoutStore
|
layout_store: &mut LayoutStore
|
||||||
) -> Result<(), Box<Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
// First we need to determine if this node is being replaced or updated. A replace happens if
|
// First we need to determine if this node is being replaced or updated. A replace happens if
|
||||||
// two nodes are different types - in this case, we check their tag values. This is also a case
|
// two nodes are different types - in this case, we check their tag values. This is also a case
|
||||||
// where, for instance, if the RSX tag is `::None` or `::VirtualText`, we'll treat it as
|
// where, for instance, if the RSX tag is `::None` or `::VirtualText`, we'll treat it as
|
||||||
// replacing with nothing.
|
// replacing with nothing.
|
||||||
|
|
@ -173,7 +173,7 @@ fn recursively_diff_tree(
|
||||||
if let RSX::VirtualNode(mut child) = new_tree {
|
if let RSX::VirtualNode(mut child) = new_tree {
|
||||||
for new_child_tree in child.children {
|
for new_child_tree in child.children {
|
||||||
match old_children.pop() {
|
match old_children.pop() {
|
||||||
// If there's a key in the old children for this position, it's
|
// If there's a key in the old children for this position, it's
|
||||||
// something we need to update, so let's recurse right back into it.
|
// something we need to update, so let's recurse right back into it.
|
||||||
Some(old_child_key) => {
|
Some(old_child_key) => {
|
||||||
recursively_diff_tree(
|
recursively_diff_tree(
|
||||||
|
|
@ -184,7 +184,7 @@ fn recursively_diff_tree(
|
||||||
)?;
|
)?;
|
||||||
},
|
},
|
||||||
|
|
||||||
// If there's no matching old key in this position, then we've got a
|
// If there's no matching old key in this position, then we've got a
|
||||||
// new component instance to mount. This part now diverts into the Mount
|
// new component instance to mount. This part now diverts into the Mount
|
||||||
// phase.
|
// phase.
|
||||||
None => {
|
None => {
|
||||||
|
|
@ -218,17 +218,17 @@ fn recursively_diff_tree(
|
||||||
/// tree, emitting required lifecycle events and persisting values. This happens in an inward-out
|
/// tree, emitting required lifecycle events and persisting values. This happens in an inward-out
|
||||||
/// fashion, which helps avoid unnecessary reflow in environments where it can get tricky.
|
/// fashion, which helps avoid unnecessary reflow in environments where it can get tricky.
|
||||||
///
|
///
|
||||||
/// This method returns a Result, the `Ok` variant containing a tuple of Vecs. These are the child
|
/// This method returns a Result, the `Ok` variant containing a tuple of Vecs. These are the child
|
||||||
/// Component instances and Layout instances that need to be set in the stores.
|
/// Component instances and Layout instances that need to be set in the stores.
|
||||||
fn mount_component_tree(
|
fn mount_component_tree(
|
||||||
tree: VirtualNode,
|
tree: VirtualNode,
|
||||||
component_store: &mut ComponentStore,
|
component_store: &mut ComponentStore,
|
||||||
layout_store: &mut LayoutStore
|
layout_store: &mut LayoutStore
|
||||||
) -> Result<ComponentKey, Box<Error>> {
|
) -> Result<ComponentKey, Box<dyn Error>> {
|
||||||
let key = component_store.new_key();
|
let key = component_store.new_key();
|
||||||
let component = (tree.create_component_fn)(key);
|
let component = (tree.create_component_fn)(key);
|
||||||
let is_native_backed = component.has_native_backing_node();
|
let is_native_backed = component.has_native_backing_node();
|
||||||
|
|
||||||
// let state = get_derived_state_from_props()
|
// let state = get_derived_state_from_props()
|
||||||
let mut instance = Instance {
|
let mut instance = Instance {
|
||||||
tag: tree.tag,
|
tag: tree.tag,
|
||||||
|
|
@ -243,7 +243,7 @@ fn mount_component_tree(
|
||||||
THEME_ENGINE.configure_styles_for_keys(&instance.style_keys, &mut style, &mut instance.appearance);
|
THEME_ENGINE.configure_styles_for_keys(&instance.style_keys, &mut style, &mut instance.appearance);
|
||||||
instance.layout = Some(layout_store.new_node(style, vec![])?);
|
instance.layout = Some(layout_store.new_node(style, vec![])?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rendered = instance.component.render(tree.children);
|
let rendered = instance.component.render(tree.children);
|
||||||
// instance.get_snapshot_before_update()
|
// instance.get_snapshot_before_update()
|
||||||
component_store.insert(key, instance)?;
|
component_store.insert(key, instance)?;
|
||||||
|
|
@ -258,7 +258,7 @@ fn mount_component_tree(
|
||||||
for child_tree in child.children {
|
for child_tree in child.children {
|
||||||
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)?;
|
||||||
|
|
||||||
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)?;
|
||||||
|
|
@ -267,7 +267,7 @@ fn mount_component_tree(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
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)?;
|
||||||
|
|
@ -298,12 +298,12 @@ fn unmount_component_tree(
|
||||||
key: ComponentKey,
|
key: ComponentKey,
|
||||||
component_store: &mut ComponentStore,
|
component_store: &mut ComponentStore,
|
||||||
layout_store: &mut LayoutStore
|
layout_store: &mut LayoutStore
|
||||||
) -> Result<Vec<LayoutNode>, Box<Error>> {
|
) -> Result<Vec<LayoutNode>, Box<dyn Error>> {
|
||||||
let mut instance = component_store.remove(key)?;
|
let mut instance = component_store.remove(key)?;
|
||||||
instance.component.component_will_unmount();
|
instance.component.component_will_unmount();
|
||||||
|
|
||||||
let mut layout_nodes = vec![];
|
let mut layout_nodes = vec![];
|
||||||
|
|
||||||
let children = component_store.children(key)?;
|
let children = component_store.children(key)?;
|
||||||
for child in children {
|
for child in children {
|
||||||
match unmount_component_tree(child, component_store, layout_store) {
|
match unmount_component_tree(child, component_store, layout_store) {
|
||||||
|
|
@ -327,8 +327,8 @@ fn unmount_component_tree(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a tree, will walk the branches until it finds the next root nodes to connect.
|
/// Given a tree, will walk the branches until it finds the next root nodes to connect.
|
||||||
/// While this sounds slow, in practice it rarely has to go far in any direction. This could
|
/// While this sounds slow, in practice it rarely has to go far in any direction. This could
|
||||||
/// potentially be done away with some hoisting magic in the `mount()` recursion, but I couldn't
|
/// potentially be done away with some hoisting magic in the `mount()` recursion, but I couldn't
|
||||||
/// find a pattern that didn't feel like some utter magic in Rust.
|
/// find a pattern that didn't feel like some utter magic in Rust.
|
||||||
///
|
///
|
||||||
/// It might be because I'm writing this at 3AM. Feel free to improve it.
|
/// It might be because I'm writing this at 3AM. Feel free to improve it.
|
||||||
|
|
@ -337,7 +337,7 @@ fn link_layout_nodess(
|
||||||
child: ComponentKey,
|
child: ComponentKey,
|
||||||
components: &mut ComponentStore,
|
components: &mut ComponentStore,
|
||||||
layouts: &mut LayoutStore
|
layouts: &mut LayoutStore
|
||||||
) -> Result<(), Box<Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
if let (Ok(parent_instance), Ok(child_instance)) = (components.get(parent), components.get(child)) {
|
if let (Ok(parent_instance), Ok(child_instance)) = (components.get(parent), components.get(child)) {
|
||||||
if let (Some(parent_layout), Some(child_layout)) = (parent_instance.layout, child_instance.layout) {
|
if let (Some(parent_layout), Some(child_layout)) = (parent_instance.layout, child_instance.layout) {
|
||||||
layouts.add_child(parent_layout, child_layout)?;
|
layouts.add_child(parent_layout, child_layout)?;
|
||||||
|
|
@ -364,7 +364,7 @@ fn walk_and_apply_styles(
|
||||||
key: ComponentKey,
|
key: ComponentKey,
|
||||||
components: &mut ComponentStore,
|
components: &mut ComponentStore,
|
||||||
layouts: &mut LayoutStore
|
layouts: &mut LayoutStore
|
||||||
) -> Result<(), Box<Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
let instance = components.get_mut(key)?;
|
let instance = components.get_mut(key)?;
|
||||||
|
|
||||||
if let Some(layout_key) = instance.layout {
|
if let Some(layout_key) = instance.layout {
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ impl RSX {
|
||||||
pub fn node<P: Any + 'static>(
|
pub fn node<P: Any + 'static>(
|
||||||
tag: &'static str,
|
tag: &'static str,
|
||||||
styles: StylesList,
|
styles: StylesList,
|
||||||
create_fn: fn(key: ComponentKey) -> Box<Component>,
|
create_fn: fn(key: ComponentKey) -> Box<dyn Component>,
|
||||||
props: P,
|
props: P,
|
||||||
children: Vec<RSX>
|
children: Vec<RSX>
|
||||||
) -> RSX {
|
) -> RSX {
|
||||||
|
|
@ -43,9 +43,9 @@ impl RSX {
|
||||||
children: children
|
children: children
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shorthand method for creating a new `RSX::VirtualText` instance. Rarely should you call
|
/// Shorthand method for creating a new `RSX::VirtualText` instance. Rarely should you call
|
||||||
/// this yourself; the `rsx! {}` and `text!()` macros handle this for you.
|
/// this yourself; the `rsx! {}` and `text!()` macros handle this for you.
|
||||||
pub fn text(s: String) -> RSX {
|
pub fn text(s: String) -> RSX {
|
||||||
RSX::VirtualText(VirtualText(s))
|
RSX::VirtualText(VirtualText(s))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,12 @@ pub struct VirtualNode {
|
||||||
|
|
||||||
/// `Component` instances are created on-demand, if the reconciler deems it be so. This
|
/// `Component` instances are created on-demand, if the reconciler deems it be so. This
|
||||||
/// is a closure that should return an instance of the correct type.
|
/// is a closure that should return an instance of the correct type.
|
||||||
pub create_component_fn: fn(key: ComponentKey) -> Box<Component>,
|
pub create_component_fn: fn(key: ComponentKey) -> Box<dyn Component>,
|
||||||
|
|
||||||
/// When some RSX is returned, we scoop up the props inside a special block, and then shove
|
/// When some RSX is returned, we scoop up the props inside a special block, and then shove
|
||||||
/// them in here as an `Any` object. When you `derive(Props)` on a `Component` struct, it
|
/// them in here as an `Any` object. When you `derive(Props)` on a `Component` struct, it
|
||||||
/// creates a setter that specifically handles downcasting and persisting props for you.
|
/// creates a setter that specifically handles downcasting and persisting props for you.
|
||||||
pub props: Box<Any>,
|
pub props: Box<dyn Any>,
|
||||||
|
|
||||||
/// Child components for this node.
|
/// Child components for this node.
|
||||||
pub children: Vec<RSX>
|
pub children: Vec<RSX>
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ pub trait AppDelegate: Send + Sync {
|
||||||
fn will_resign_active(&mut self) {}
|
fn will_resign_active(&mut self) {}
|
||||||
|
|
||||||
/// Fired when an Application has resigned active.
|
/// Fired when an Application has resigned active.
|
||||||
fn did_resign_active(&mut self) {}
|
fn did_resign_active(&mut self) {}
|
||||||
|
|
||||||
/// Fired when an Application is going to terminate. You can use this to, say, instruct the
|
/// Fired when an Application is going to terminate. You can use this to, say, instruct the
|
||||||
/// system to "wait a minute, lemme finish".
|
/// system to "wait a minute, lemme finish".
|
||||||
|
|
@ -73,11 +73,11 @@ pub trait WindowDelegate: Send + Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Props {
|
pub trait Props {
|
||||||
fn set_props(&mut self, new_props: &mut Any);
|
fn set_props(&mut self, new_props: &mut dyn Any);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The `Component` lifecycle, mostly inspired from React, with a few extra methods for views that
|
/// The `Component` lifecycle, mostly inspired from React, with a few extra methods for views that
|
||||||
/// need to have a backing native layer. A good breakdown of the React Component lifecycle can be
|
/// need to have a backing native layer. A good breakdown of the React Component lifecycle can be
|
||||||
/// found [in this tweet](https://twitter.com/dan_abramov/status/981712092611989509?lang=en).
|
/// found [in this tweet](https://twitter.com/dan_abramov/status/981712092611989509?lang=en).
|
||||||
///
|
///
|
||||||
/// Alchemy does not currently implement Hooks, and at the moment has no plans to do so (the API
|
/// Alchemy does not currently implement Hooks, and at the moment has no plans to do so (the API
|
||||||
|
|
@ -106,7 +106,7 @@ pub trait Component: Props + Send + Sync {
|
||||||
/// `node`, you need to instruct the system how to remove it from the tree at your point.
|
/// `node`, you need to instruct the system how to remove it from the tree at your point.
|
||||||
fn remove_child_node(&self, _component: PlatformSpecificNodeType) {}
|
fn remove_child_node(&self, _component: PlatformSpecificNodeType) {}
|
||||||
|
|
||||||
/// Given a configured 'appearance' and computed `layout`, this method should transform them
|
/// Given a configured 'appearance' and computed `layout`, this method should transform them
|
||||||
/// into appropriate calls to the backing native node.
|
/// into appropriate calls to the backing native node.
|
||||||
fn apply_styles(&self, _appearance: &Appearance, _layout: &Layout) {}
|
fn apply_styles(&self, _appearance: &Appearance, _layout: &Layout) {}
|
||||||
|
|
||||||
|
|
@ -114,80 +114,80 @@ pub trait Component: Props + Send + Sync {
|
||||||
/// It should return an object to update the state, or null to update nothing.
|
/// It should return an object to update the state, or null to update nothing.
|
||||||
/// This method exists for rare use cases where the state depends on changes in props over time.
|
/// This method exists for rare use cases where the state depends on changes in props over time.
|
||||||
fn get_derived_state_from_props(&self) {}
|
fn get_derived_state_from_props(&self) {}
|
||||||
|
|
||||||
/// Invoked right before the most recently rendered output is committed to the backing layer tree.
|
/// Invoked right before the most recently rendered output is committed to the backing layer tree.
|
||||||
/// It enables your component to capture some information from the tree (e.g. scroll position) before it's
|
/// It enables your component to capture some information from the tree (e.g. scroll position) before it's
|
||||||
/// potentially changed. Any value returned by this lifecycle will be passed as a parameter
|
/// potentially changed. Any value returned by this lifecycle will be passed as a parameter
|
||||||
/// to component_did_update().
|
/// to component_did_update().
|
||||||
///
|
///
|
||||||
/// This use case is not common, but it may occur in UIs like a chat thread that need to handle scroll
|
/// This use case is not common, but it may occur in UIs like a chat thread that need to handle scroll
|
||||||
/// position in a special way. A snapshot value (or None) should be returned.
|
/// position in a special way. A snapshot value (or None) should be returned.
|
||||||
fn get_snapshot_before_update(&self) {}
|
fn get_snapshot_before_update(&self) {}
|
||||||
|
|
||||||
/// Invoked immediately after a component is mounted (inserted into the tree).
|
/// Invoked immediately after a component is mounted (inserted into the tree).
|
||||||
/// If you need to load data from a remote endpoint, this is a good place to instantiate the network request.
|
/// If you need to load data from a remote endpoint, this is a good place to instantiate the network request.
|
||||||
/// This method is also a good place to set up any subscriptions. If you do that, don’t forget to unsubscribe
|
/// This method is also a good place to set up any subscriptions. If you do that, don’t forget to unsubscribe
|
||||||
/// in component_will_unmount().
|
/// in component_will_unmount().
|
||||||
fn component_did_mount(&mut self) {}
|
fn component_did_mount(&mut self) {}
|
||||||
|
|
||||||
/// Invoked immediately after updating occurs. This method is not called for the initial render.
|
/// Invoked immediately after updating occurs. This method is not called for the initial render.
|
||||||
/// This is also a good place to do network requests as long as you compare the current props to previous props
|
/// This is also a good place to do network requests as long as you compare the current props to previous props
|
||||||
/// (e.g. a network request may not be necessary if the props have not changed).
|
/// (e.g. a network request may not be necessary if the props have not changed).
|
||||||
fn component_did_update(&mut self) {}
|
fn component_did_update(&mut self) {}
|
||||||
|
|
||||||
/// Invoked immediately before a component is unmounted and destroyed. Perform any necessary cleanup in this
|
/// Invoked immediately before a component is unmounted and destroyed. Perform any necessary cleanup in this
|
||||||
/// method, such as invalidating timers, canceling network requests, or cleaning up any subscriptions that
|
/// method, such as invalidating timers, canceling network requests, or cleaning up any subscriptions that
|
||||||
/// were created in component_did_mount().
|
/// were created in component_did_mount().
|
||||||
///
|
///
|
||||||
/// You should not call set state in this method because the component will never be re-rendered. Once a
|
/// You should not call set state in this method because the component will never be re-rendered. Once a
|
||||||
/// component instance is unmounted, it will never be mounted again.
|
/// component instance is unmounted, it will never be mounted again.
|
||||||
fn component_will_unmount(&mut self) {}
|
fn component_will_unmount(&mut self) {}
|
||||||
|
|
||||||
/// Invoked after an error has been thrown by a descendant component. Called during the "commit" phase,
|
/// Invoked after an error has been thrown by a descendant component. Called during the "commit" phase,
|
||||||
/// so side-effects are permitted. It should be used for things like logging errors (e.g,
|
/// so side-effects are permitted. It should be used for things like logging errors (e.g,
|
||||||
/// Sentry).
|
/// Sentry).
|
||||||
fn component_did_catch(&mut self /* error: */) {}
|
fn component_did_catch(&mut self /* error: */) {}
|
||||||
|
|
||||||
/// Use this to let Alchemy know if a component’s output is not affected by the current change in state
|
/// Use this to let Alchemy know if a component’s output is not affected by the current change in state
|
||||||
/// or props. The default behavior is to re-render on every state change, and in the vast majority of
|
/// or props. The default behavior is to re-render on every state change, and in the vast majority of
|
||||||
/// cases you should rely on the default behavior.
|
/// cases you should rely on the default behavior.
|
||||||
///
|
///
|
||||||
/// This is invoked before rendering when new props or state are being received. Defaults to true. This
|
/// This is invoked before rendering when new props or state are being received. Defaults to true. This
|
||||||
/// method is not called for the initial render or when force_update() is used. This method only exists
|
/// method is not called for the initial render or when force_update() is used. This method only exists
|
||||||
/// as a performance optimization. Do not rely on it to “prevent” a rendering, as this can lead to bugs.
|
/// as a performance optimization. Do not rely on it to “prevent” a rendering, as this can lead to bugs.
|
||||||
fn should_component_update(&self) -> bool { true }
|
fn should_component_update(&self) -> bool { true }
|
||||||
|
|
||||||
/// The only required method for a `Component`. Should return a Result of RSX nodes, or an
|
/// The only required method for a `Component`. Should return a Result of RSX nodes, or an
|
||||||
/// Error (in very rare cases, such as trying to get a key from a strange HashMap or
|
/// Error (in very rare cases, such as trying to get a key from a strange HashMap or
|
||||||
/// something).
|
/// something).
|
||||||
///
|
///
|
||||||
/// The render() function should be pure, meaning that it does not modify component state, it
|
/// The render() function should be pure, meaning that it does not modify component state, it
|
||||||
/// returns the same result each time it’s invoked, and it does not directly interact with the
|
/// returns the same result each time it’s invoked, and it does not directly interact with the
|
||||||
/// backing rendering framework.
|
/// backing rendering framework.
|
||||||
///
|
///
|
||||||
/// If you need to interact with the native layer, perform your work in component_did_mount() or the other
|
/// If you need to interact with the native layer, perform your work in component_did_mount() or the other
|
||||||
/// lifecycle methods instead. Keeping `render()` pure makes components easier to think about.
|
/// lifecycle methods instead. Keeping `render()` pure makes components easier to think about.
|
||||||
///
|
///
|
||||||
/// This method is not called if should_component_update() returns `false`.
|
/// This method is not called if should_component_update() returns `false`.
|
||||||
fn render(&self, children: Vec<RSX>) -> Result<RSX, Error> { Ok(RSX::None) }
|
fn render(&self, children: Vec<RSX>) -> Result<RSX, Error> { Ok(RSX::None) }
|
||||||
|
|
||||||
/// This lifecycle is invoked after an error has been thrown by a descendant component. It receives
|
/// This lifecycle is invoked after an error has been thrown by a descendant component. It receives
|
||||||
/// the error that was thrown as a parameter and should return a value to update state.
|
/// the error that was thrown as a parameter and should return a value to update state.
|
||||||
///
|
///
|
||||||
/// This is called during the "render" phase, so side-effects are not permitted.
|
/// This is called during the "render" phase, so side-effects are not permitted.
|
||||||
/// For those use cases, use component_did_catch() instead.
|
/// For those use cases, use component_did_catch() instead.
|
||||||
fn get_derived_state_from_error(&self, _error: ()) {}
|
fn get_derived_state_from_error(&self, _error: ()) {}
|
||||||
|
|
||||||
/// By default, when your component’s state or props change, your component will re-render.
|
/// By default, when your component’s state or props change, your component will re-render.
|
||||||
/// If your `render()` method depends on some other data, you can tell Alchemy that the component
|
/// If your `render()` method depends on some other data, you can tell Alchemy that the component
|
||||||
/// needs re-rendering by calling `force_update()`.
|
/// needs re-rendering by calling `force_update()`.
|
||||||
///
|
///
|
||||||
/// Calling `force_update()` will cause `render()` to be called on the component, skipping
|
/// Calling `force_update()` will cause `render()` to be called on the component, skipping
|
||||||
/// `should_component_update()`. This will trigger the normal lifecycle methods for child components,
|
/// `should_component_update()`. This will trigger the normal lifecycle methods for child components,
|
||||||
/// including the `should_component_update()` method of each child. Alchemy will still only update the
|
/// including the `should_component_update()` method of each child. Alchemy will still only update the
|
||||||
/// backing widget tree if the markup changes.
|
/// backing widget tree if the markup changes.
|
||||||
///
|
///
|
||||||
/// Normally, you should try to avoid all uses of `force_update()` and only read from `this.props`
|
/// Normally, you should try to avoid all uses of `force_update()` and only read from `this.props`
|
||||||
/// and `this.state` in `render()`.
|
/// and `this.state` in `render()`.
|
||||||
fn force_update(&self) {}
|
fn force_update(&self) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
1.35.0
|
|
||||||
|
|
@ -51,10 +51,10 @@ impl Color {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(red: u8, green: u8, blue: u8, alpha: u8) -> Self {
|
pub fn new(red: u8, green: u8, blue: u8, alpha: u8) -> Self {
|
||||||
Color {
|
Color {
|
||||||
red: red,
|
red,
|
||||||
green: green,
|
green,
|
||||||
blue: blue,
|
blue,
|
||||||
alpha: alpha,
|
alpha,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,7 +81,7 @@ impl Color {
|
||||||
pub fn alpha_f32(&self) -> f32 {
|
pub fn alpha_f32(&self) -> f32 {
|
||||||
self.alpha as f32 / 255.0
|
self.alpha as f32 / 255.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a <color> value, per CSS Color Module Level 3.
|
/// Parse a <color> value, per CSS Color Module Level 3.
|
||||||
///
|
///
|
||||||
/// FIXME(#2) Deprecated CSS2 System Colors are not supported yet.
|
/// FIXME(#2) Deprecated CSS2 System Colors are not supported yet.
|
||||||
|
|
@ -501,9 +501,9 @@ pub fn parse_color_keyword(ident: &str) -> Result<Color, ()> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_hex(c: u8) -> Result<u8, ()> {
|
fn from_hex(c: u8) -> Result<u8, ()> {
|
||||||
match c {
|
match c {
|
||||||
b'0'...b'9' => Ok(c - b'0'),
|
b'0'..=b'9' => Ok(c - b'0'),
|
||||||
b'a'...b'f' => Ok(c - b'a' + 10),
|
b'a'..=b'f' => Ok(c - b'a' + 10),
|
||||||
b'A'...b'F' => Ok(c - b'A' + 10),
|
b'A'..=b'F' => Ok(c - b'A' + 10),
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -663,5 +663,5 @@ where
|
||||||
let red = clamp_unit_f32(hue_to_rgb(m1, m2, hue_times_3 + 1.));
|
let red = clamp_unit_f32(hue_to_rgb(m1, m2, hue_times_3 + 1.));
|
||||||
let green = clamp_unit_f32(hue_to_rgb(m1, m2, hue_times_3));
|
let green = clamp_unit_f32(hue_to_rgb(m1, m2, hue_times_3));
|
||||||
let blue = clamp_unit_f32(hue_to_rgb(m1, m2, hue_times_3 - 1.));
|
let blue = clamp_unit_f32(hue_to_rgb(m1, m2, hue_times_3 - 1.));
|
||||||
return Ok((red, green, blue, uses_commas));
|
Ok((red, green, blue, uses_commas))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ struct FlexLine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stretch {
|
impl Stretch {
|
||||||
pub(crate) fn compute(&mut self, root: Node, size: Size<Number>) -> Result<(), Box<Any>> {
|
pub(crate) fn compute(&mut self, root: Node, size: Size<Number>) -> Result<(), Box<dyn Any>> {
|
||||||
let style = self.style[&root];
|
let style = self.style[&root];
|
||||||
let has_root_min_max = style.min_size.width.is_defined()
|
let has_root_min_max = style.min_size.width.is_defined()
|
||||||
|| style.min_size.height.is_defined()
|
|| style.min_size.height.is_defined()
|
||||||
|
|
@ -133,7 +133,7 @@ impl Stretch {
|
||||||
node_size: Size<Number>,
|
node_size: Size<Number>,
|
||||||
parent_size: Size<Number>,
|
parent_size: Size<Number>,
|
||||||
perform_layout: bool,
|
perform_layout: bool,
|
||||||
) -> Result<ComputeResult, Box<Any>> {
|
) -> Result<ComputeResult, Box<dyn Any>> {
|
||||||
*self.is_dirty.get_mut(node).unwrap() = false;
|
*self.is_dirty.get_mut(node).unwrap() = false;
|
||||||
|
|
||||||
// First we check if we have a result for the given input
|
// First we check if we have a result for the given input
|
||||||
|
|
@ -277,7 +277,7 @@ impl Stretch {
|
||||||
|
|
||||||
// TODO - this does not follow spec. See commented out code below
|
// TODO - this does not follow spec. See commented out code below
|
||||||
// 3. Determine the flex base size and hypothetical main size of each item:
|
// 3. Determine the flex base size and hypothetical main size of each item:
|
||||||
flex_items.iter_mut().try_for_each(|child| -> Result<(), Box<Any>> {
|
flex_items.iter_mut().try_for_each(|child| -> Result<(), Box<dyn Any>> {
|
||||||
let child_style = self.style[&child.node];
|
let child_style = self.style[&child.node];
|
||||||
|
|
||||||
// A. If the item has a definite used flex basis, that’s the flex base size.
|
// A. If the item has a definite used flex basis, that’s the flex base size.
|
||||||
|
|
@ -364,7 +364,7 @@ impl Stretch {
|
||||||
// The hypothetical main size is the item’s flex base size clamped according to its
|
// The hypothetical main size is the item’s flex base size clamped according to its
|
||||||
// used min and max main sizes (and flooring the content box size at zero).
|
// used min and max main sizes (and flooring the content box size at zero).
|
||||||
|
|
||||||
flex_items.iter_mut().try_for_each(|child| -> Result<(), Box<Any>> {
|
flex_items.iter_mut().try_for_each(|child| -> Result<(), Box<dyn Any>> {
|
||||||
child.inner_flex_basis = child.flex_basis - child.padding.main(dir) - child.border.main(dir);
|
child.inner_flex_basis = child.flex_basis - child.padding.main(dir) - child.border.main(dir);
|
||||||
|
|
||||||
// TODO - not really spec abiding but needs to be done somewhere. probably somewhere else though.
|
// TODO - not really spec abiding but needs to be done somewhere. probably somewhere else though.
|
||||||
|
|
@ -441,7 +441,7 @@ impl Stretch {
|
||||||
//
|
//
|
||||||
// 9.7. Resolving Flexible Lengths
|
// 9.7. Resolving Flexible Lengths
|
||||||
|
|
||||||
flex_lines.iter_mut().try_for_each(|line| -> Result<(), Box<Any>> {
|
flex_lines.iter_mut().try_for_each(|line| -> Result<(), Box<dyn Any>> {
|
||||||
// 1. Determine the used flex factor. Sum the outer hypothetical main sizes of all
|
// 1. Determine the used flex factor. Sum the outer hypothetical main sizes of all
|
||||||
// items on the line. If the sum is less than the flex container’s inner main size,
|
// items on the line. If the sum is less than the flex container’s inner main size,
|
||||||
// use the flex grow factor for the rest of this algorithm; otherwise, use the
|
// use the flex grow factor for the rest of this algorithm; otherwise, use the
|
||||||
|
|
@ -458,7 +458,7 @@ impl Stretch {
|
||||||
// - If using the flex shrink factor: any item that has a flex base size
|
// - If using the flex shrink factor: any item that has a flex base size
|
||||||
// smaller than its hypothetical main size
|
// smaller than its hypothetical main size
|
||||||
|
|
||||||
line.items.iter_mut().try_for_each(|child| -> Result<(), Box<Any>> {
|
line.items.iter_mut().try_for_each(|child| -> Result<(), Box<dyn Any>> {
|
||||||
// TODO - This is not found by reading the spec. Maybe this can be done in some other place
|
// TODO - This is not found by reading the spec. Maybe this can be done in some other place
|
||||||
// instead. This was found by trail and error fixing tests to align with webkit output.
|
// instead. This was found by trail and error fixing tests to align with webkit output.
|
||||||
if node_inner_size.main(dir).is_undefined() && is_row {
|
if node_inner_size.main(dir).is_undefined() && is_row {
|
||||||
|
|
@ -614,7 +614,7 @@ impl Stretch {
|
||||||
// item’s target main size was made smaller by this, it’s a max violation.
|
// item’s target main size was made smaller by this, it’s a max violation.
|
||||||
// If the item’s target main size was made larger by this, it’s a min violation.
|
// If the item’s target main size was made larger by this, it’s a min violation.
|
||||||
|
|
||||||
let total_violation = unfrozen.iter_mut().try_fold(0.0, |acc, child| -> Result<f32, Box<Any>> {
|
let total_violation = unfrozen.iter_mut().try_fold(0.0, |acc, child| -> Result<f32, Box<dyn Any>> {
|
||||||
// TODO - not really spec abiding but needs to be done somewhere. probably somewhere else though.
|
// TODO - not really spec abiding but needs to be done somewhere. probably somewhere else though.
|
||||||
// The following logic was developed not from the spec but by trail and error looking into how
|
// The following logic was developed not from the spec but by trail and error looking into how
|
||||||
// webkit handled various scenarios. Can probably be solved better by passing in
|
// webkit handled various scenarios. Can probably be solved better by passing in
|
||||||
|
|
@ -691,7 +691,7 @@ impl Stretch {
|
||||||
// used main size and the available space, treating auto as fit-content.
|
// used main size and the available space, treating auto as fit-content.
|
||||||
|
|
||||||
flex_lines.iter_mut().try_for_each(|line| {
|
flex_lines.iter_mut().try_for_each(|line| {
|
||||||
line.items.iter_mut().try_for_each(|child| -> Result<(), Box<Any>> {
|
line.items.iter_mut().try_for_each(|child| -> Result<(), Box<dyn Any>> {
|
||||||
let child_cross =
|
let child_cross =
|
||||||
child.size.cross(dir).maybe_max(child.min_size.cross(dir)).maybe_min(child.max_size.cross(dir));
|
child.size.cross(dir).maybe_max(child.min_size.cross(dir)).maybe_min(child.max_size.cross(dir));
|
||||||
|
|
||||||
|
|
@ -737,7 +737,7 @@ impl Stretch {
|
||||||
|
|
||||||
if has_baseline_child {
|
if has_baseline_child {
|
||||||
flex_lines.iter_mut().try_for_each(|line| {
|
flex_lines.iter_mut().try_for_each(|line| {
|
||||||
line.items.iter_mut().try_for_each(|child| -> Result<(), Box<Any>> {
|
line.items.iter_mut().try_for_each(|child| -> Result<(), Box<dyn Any>> {
|
||||||
let result = self.compute_internal(
|
let result = self.compute_internal(
|
||||||
child.node,
|
child.node,
|
||||||
Size {
|
Size {
|
||||||
|
|
@ -1148,12 +1148,12 @@ impl Stretch {
|
||||||
let mut lines: Vec<Vec<result::Layout>> = vec![];
|
let mut lines: Vec<Vec<result::Layout>> = vec![];
|
||||||
let mut total_offset_cross = padding_border.cross_start(dir);
|
let mut total_offset_cross = padding_border.cross_start(dir);
|
||||||
|
|
||||||
let layout_line = |line: &mut FlexLine| -> Result<(), Box<Any>> {
|
let layout_line = |line: &mut FlexLine| -> Result<(), Box<dyn Any>> {
|
||||||
let mut children: Vec<result::Layout> = vec![];
|
let mut children: Vec<result::Layout> = vec![];
|
||||||
let mut total_offset_main = padding_border.main_start(dir);
|
let mut total_offset_main = padding_border.main_start(dir);
|
||||||
let line_offset_cross = line.offset_cross;
|
let line_offset_cross = line.offset_cross;
|
||||||
|
|
||||||
let layout_item = |child: &mut FlexItem| -> Result<(), Box<Any>> {
|
let layout_item = |child: &mut FlexItem| -> Result<(), Box<dyn Any>> {
|
||||||
let result = self.compute_internal(
|
let result = self.compute_internal(
|
||||||
child.node,
|
child.node,
|
||||||
child.target_size.map(|s| s.to_number()),
|
child.target_size.map(|s| s.to_number()),
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use core::any::Any;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
InvalidNode(node::Node),
|
InvalidNode(node::Node),
|
||||||
Measure(Box<Any>),
|
Measure(Box<dyn Any>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Error {
|
impl std::fmt::Display for Error {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use crate::stretch::result::{Cache, Layout};
|
||||||
use crate::stretch::style::*;
|
use crate::stretch::style::*;
|
||||||
use crate::stretch::Error;
|
use crate::stretch::Error;
|
||||||
|
|
||||||
type MeasureFunc = Box<Fn(Size<Number>) -> Result<Size<f32>, Box<Any>> + Send + Sync + 'static>;
|
type MeasureFunc = Box<dyn Fn(Size<Number>) -> Result<Size<f32>, Box<dyn Any>> + Send + Sync + 'static>;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Global stretch instance id allocator.
|
/// Global stretch instance id allocator.
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ impl<'i> QualifiedRuleParser<'i> for RuleParser {
|
||||||
let styles = DeclarationListParser::new(input, StyleParser {}).collect::<Vec<_>>();
|
let styles = DeclarationListParser::new(input, StyleParser {}).collect::<Vec<_>>();
|
||||||
|
|
||||||
Ok(Rule {
|
Ok(Rule {
|
||||||
key: key,
|
key,
|
||||||
styles: styles.into_iter().filter_map(|decl| {
|
styles: styles.into_iter().filter_map(|decl| {
|
||||||
if !decl.is_ok() {
|
if !decl.is_ok() {
|
||||||
eprintln!("{:?}", decl);
|
eprintln!("{:?}", decl);
|
||||||
|
|
@ -119,7 +119,7 @@ impl<'i> DeclarationParser<'i> for StyleParser {
|
||||||
"space-around" => Styles::AlignContent(AlignContent::SpaceAround),
|
"space-around" => Styles::AlignContent(AlignContent::SpaceAround),
|
||||||
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
||||||
}},
|
}},
|
||||||
|
|
||||||
"align-items" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
"align-items" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
||||||
"flex-start" => Styles::AlignItems(AlignItems::FlexStart),
|
"flex-start" => Styles::AlignItems(AlignItems::FlexStart),
|
||||||
"flex-end" => Styles::AlignItems(AlignItems::FlexEnd),
|
"flex-end" => Styles::AlignItems(AlignItems::FlexEnd),
|
||||||
|
|
@ -128,7 +128,7 @@ impl<'i> DeclarationParser<'i> for StyleParser {
|
||||||
"stretch" => Styles::AlignItems(AlignItems::Stretch),
|
"stretch" => Styles::AlignItems(AlignItems::Stretch),
|
||||||
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
||||||
}},
|
}},
|
||||||
|
|
||||||
"align_self" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
"align_self" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
||||||
"auto" => Styles::AlignSelf(AlignSelf::Auto),
|
"auto" => Styles::AlignSelf(AlignSelf::Auto),
|
||||||
"flex-start" => Styles::AlignSelf(AlignSelf::FlexStart),
|
"flex-start" => Styles::AlignSelf(AlignSelf::FlexStart),
|
||||||
|
|
@ -149,14 +149,14 @@ impl<'i> DeclarationParser<'i> for StyleParser {
|
||||||
}},
|
}},
|
||||||
|
|
||||||
"background-color" => Styles::BackgroundColor(Color::parse(input)?),
|
"background-color" => Styles::BackgroundColor(Color::parse(input)?),
|
||||||
|
|
||||||
// Border values~
|
// Border values~
|
||||||
"border-color" => Styles::BorderColor(Color::parse(input)?),
|
"border-color" => Styles::BorderColor(Color::parse(input)?),
|
||||||
"border-top-color" => Styles::BorderTopColor(Color::parse(input)?),
|
"border-top-color" => Styles::BorderTopColor(Color::parse(input)?),
|
||||||
"border-bottom-color" => Styles::BorderBottomColor(Color::parse(input)?),
|
"border-bottom-color" => Styles::BorderBottomColor(Color::parse(input)?),
|
||||||
"border-left-color" => Styles::BorderLeftColor(Color::parse(input)?),
|
"border-left-color" => Styles::BorderLeftColor(Color::parse(input)?),
|
||||||
"border-right-color" => Styles::BorderRightColor(Color::parse(input)?),
|
"border-right-color" => Styles::BorderRightColor(Color::parse(input)?),
|
||||||
|
|
||||||
"bottom" => Styles::Bottom(parse_floaty_mcfloatface_value(input)?),
|
"bottom" => Styles::Bottom(parse_floaty_mcfloatface_value(input)?),
|
||||||
|
|
||||||
"color" => Styles::TextColor(Color::parse(input)?),
|
"color" => Styles::TextColor(Color::parse(input)?),
|
||||||
|
|
@ -173,11 +173,11 @@ impl<'i> DeclarationParser<'i> for StyleParser {
|
||||||
"none" => Styles::Display(Display::None),
|
"none" => Styles::Display(Display::None),
|
||||||
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
||||||
}},
|
}},
|
||||||
|
|
||||||
"end" => Styles::End(parse_floaty_mcfloatface_value(input)?),
|
"end" => Styles::End(parse_floaty_mcfloatface_value(input)?),
|
||||||
|
|
||||||
"flex-basis" => Styles::FlexBasis(parse_floaty_mcfloatface_value(input)?),
|
"flex-basis" => Styles::FlexBasis(parse_floaty_mcfloatface_value(input)?),
|
||||||
|
|
||||||
"flex-direction" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
"flex-direction" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
||||||
"row" => Styles::FlexDirection(FlexDirection::Row),
|
"row" => Styles::FlexDirection(FlexDirection::Row),
|
||||||
"row-reverse" => Styles::FlexDirection(FlexDirection::RowReverse),
|
"row-reverse" => Styles::FlexDirection(FlexDirection::RowReverse),
|
||||||
|
|
@ -188,17 +188,17 @@ impl<'i> DeclarationParser<'i> for StyleParser {
|
||||||
|
|
||||||
"flex-grow" => Styles::FlexGrow(parse_floaty_mcfloatface_value(input)?),
|
"flex-grow" => Styles::FlexGrow(parse_floaty_mcfloatface_value(input)?),
|
||||||
"flex-shrink" => Styles::FlexShrink(parse_floaty_mcfloatface_value(input)?),
|
"flex-shrink" => Styles::FlexShrink(parse_floaty_mcfloatface_value(input)?),
|
||||||
|
|
||||||
"flex-wrap" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
"flex-wrap" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
||||||
"no-wrap" => Styles::FlexWrap(FlexWrap::NoWrap),
|
"no-wrap" => Styles::FlexWrap(FlexWrap::NoWrap),
|
||||||
"wrap" => Styles::FlexWrap(FlexWrap::Wrap),
|
"wrap" => Styles::FlexWrap(FlexWrap::Wrap),
|
||||||
"wrap-reverse" => Styles::FlexWrap(FlexWrap::WrapReverse),
|
"wrap-reverse" => Styles::FlexWrap(FlexWrap::WrapReverse),
|
||||||
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
||||||
}},
|
}},
|
||||||
|
|
||||||
//FontFamily(FontFamily),
|
//FontFamily(FontFamily),
|
||||||
"font-size" => Styles::FontSize(parse_floaty_mcfloatface_value(input)?),
|
"font-size" => Styles::FontSize(parse_floaty_mcfloatface_value(input)?),
|
||||||
|
|
||||||
"font-style" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
"font-style" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
||||||
"normal" => Styles::FontStyle(FontStyle::Normal),
|
"normal" => Styles::FontStyle(FontStyle::Normal),
|
||||||
"italic" => Styles::FontStyle(FontStyle::Italic),
|
"italic" => Styles::FontStyle(FontStyle::Italic),
|
||||||
|
|
@ -211,7 +211,7 @@ impl<'i> DeclarationParser<'i> for StyleParser {
|
||||||
"bold" => Styles::FontWeight(FontWeight::Bold),
|
"bold" => Styles::FontWeight(FontWeight::Bold),
|
||||||
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
||||||
}},
|
}},
|
||||||
|
|
||||||
"height" => Styles::Height(parse_floaty_mcfloatface_value(input)?),
|
"height" => Styles::Height(parse_floaty_mcfloatface_value(input)?),
|
||||||
|
|
||||||
"justify-content" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
"justify-content" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
||||||
|
|
@ -223,7 +223,7 @@ impl<'i> DeclarationParser<'i> for StyleParser {
|
||||||
"space-evenly" => Styles::JustifyContent(JustifyContent::SpaceEvenly),
|
"space-evenly" => Styles::JustifyContent(JustifyContent::SpaceEvenly),
|
||||||
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
||||||
}},
|
}},
|
||||||
|
|
||||||
"left" => Styles::Left(parse_floaty_mcfloatface_value(input)?),
|
"left" => Styles::Left(parse_floaty_mcfloatface_value(input)?),
|
||||||
"line-height" => Styles::FontLineHeight(parse_floaty_mcfloatface_value(input)?),
|
"line-height" => Styles::FontLineHeight(parse_floaty_mcfloatface_value(input)?),
|
||||||
|
|
||||||
|
|
@ -236,35 +236,35 @@ impl<'i> DeclarationParser<'i> for StyleParser {
|
||||||
|
|
||||||
"max-height" => Styles::MaxHeight(parse_floaty_mcfloatface_value(input)?),
|
"max-height" => Styles::MaxHeight(parse_floaty_mcfloatface_value(input)?),
|
||||||
"max-width" => Styles::MaxWidth(parse_floaty_mcfloatface_value(input)?),
|
"max-width" => Styles::MaxWidth(parse_floaty_mcfloatface_value(input)?),
|
||||||
|
|
||||||
"min-height" => Styles::MinHeight(parse_floaty_mcfloatface_value(input)?),
|
"min-height" => Styles::MinHeight(parse_floaty_mcfloatface_value(input)?),
|
||||||
"min-width" => Styles::MinWidth(parse_floaty_mcfloatface_value(input)?),
|
"min-width" => Styles::MinWidth(parse_floaty_mcfloatface_value(input)?),
|
||||||
|
|
||||||
"opacity" => Styles::Opacity(parse_floaty_mcfloatface_value(input)?),
|
"opacity" => Styles::Opacity(parse_floaty_mcfloatface_value(input)?),
|
||||||
|
|
||||||
"overflow" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
"overflow" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
||||||
"visible" => Styles::Overflow(Overflow::Visible),
|
"visible" => Styles::Overflow(Overflow::Visible),
|
||||||
"hidden" => Styles::Overflow(Overflow::Hidden),
|
"hidden" => Styles::Overflow(Overflow::Hidden),
|
||||||
"scroll" => Styles::Overflow(Overflow::Scroll),
|
"scroll" => Styles::Overflow(Overflow::Scroll),
|
||||||
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
||||||
}},
|
}},
|
||||||
|
|
||||||
"padding-bottom" => Styles::PaddingBottom(parse_floaty_mcfloatface_value(input)?),
|
"padding-bottom" => Styles::PaddingBottom(parse_floaty_mcfloatface_value(input)?),
|
||||||
"padding-end" => Styles::PaddingEnd(parse_floaty_mcfloatface_value(input)?),
|
"padding-end" => Styles::PaddingEnd(parse_floaty_mcfloatface_value(input)?),
|
||||||
"padding-left" => Styles::PaddingLeft(parse_floaty_mcfloatface_value(input)?),
|
"padding-left" => Styles::PaddingLeft(parse_floaty_mcfloatface_value(input)?),
|
||||||
"padding-right" => Styles::PaddingRight(parse_floaty_mcfloatface_value(input)?),
|
"padding-right" => Styles::PaddingRight(parse_floaty_mcfloatface_value(input)?),
|
||||||
"padding-start" => Styles::PaddingStart(parse_floaty_mcfloatface_value(input)?),
|
"padding-start" => Styles::PaddingStart(parse_floaty_mcfloatface_value(input)?),
|
||||||
"padding-top" => Styles::PaddingTop(parse_floaty_mcfloatface_value(input)?),
|
"padding-top" => Styles::PaddingTop(parse_floaty_mcfloatface_value(input)?),
|
||||||
|
|
||||||
"position" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
"position" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
||||||
"absolute" => Styles::PositionType(PositionType::Absolute),
|
"absolute" => Styles::PositionType(PositionType::Absolute),
|
||||||
"relative" => Styles::PositionType(PositionType::Relative),
|
"relative" => Styles::PositionType(PositionType::Relative),
|
||||||
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
||||||
}},
|
}},
|
||||||
|
|
||||||
"right" => Styles::Right(parse_floaty_mcfloatface_value(input)?),
|
"right" => Styles::Right(parse_floaty_mcfloatface_value(input)?),
|
||||||
"start" => Styles::Start(parse_floaty_mcfloatface_value(input)?),
|
"start" => Styles::Start(parse_floaty_mcfloatface_value(input)?),
|
||||||
|
|
||||||
"text-align" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
"text-align" => { let s = input.current_source_location(); let t = input.next()?; match ident(&t) {
|
||||||
"auto" => Styles::TextAlignment(TextAlignment::Auto),
|
"auto" => Styles::TextAlignment(TextAlignment::Auto),
|
||||||
"left" => Styles::TextAlignment(TextAlignment::Left),
|
"left" => Styles::TextAlignment(TextAlignment::Left),
|
||||||
|
|
@ -273,14 +273,14 @@ impl<'i> DeclarationParser<'i> for StyleParser {
|
||||||
"justify" => Styles::TextAlignment(TextAlignment::Justify),
|
"justify" => Styles::TextAlignment(TextAlignment::Justify),
|
||||||
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
_ => { return Err(s.new_unexpected_token_error(t.clone())); }
|
||||||
}},
|
}},
|
||||||
|
|
||||||
"text-decoration-color" => Styles::TextDecorationColor(Color::parse(input)?),
|
"text-decoration-color" => Styles::TextDecorationColor(Color::parse(input)?),
|
||||||
"text-shadow-color" => Styles::TextShadowColor(Color::parse(input)?),
|
"text-shadow-color" => Styles::TextShadowColor(Color::parse(input)?),
|
||||||
"tint-color" => Styles::TintColor(Color::parse(input)?),
|
"tint-color" => Styles::TintColor(Color::parse(input)?),
|
||||||
|
|
||||||
"top" => Styles::Top(parse_floaty_mcfloatface_value(input)?),
|
"top" => Styles::Top(parse_floaty_mcfloatface_value(input)?),
|
||||||
"width" => Styles::Width(parse_floaty_mcfloatface_value(input)?),
|
"width" => Styles::Width(parse_floaty_mcfloatface_value(input)?),
|
||||||
|
|
||||||
t => {
|
t => {
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
return Err(location.new_unexpected_token_error(Token::Ident(t.to_string().into())));
|
return Err(location.new_unexpected_token_error(Token::Ident(t.to_string().into())));
|
||||||
|
|
@ -298,7 +298,7 @@ fn parse_floaty_mcfloatface_value<'i, 't>(input: &mut Parser<'i, 't>) -> Result<
|
||||||
let token = input.next()?;
|
let token = input.next()?;
|
||||||
|
|
||||||
match token {
|
match token {
|
||||||
Token::Number { value, .. } => Ok(*value),
|
Token::Number { value, .. } => Ok(*value),
|
||||||
_ => Err(location.new_basic_unexpected_token_error(token.clone()))
|
_ => Err(location.new_basic_unexpected_token_error(token.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Reference in a new issue