Browse Source

updates: move to stable versions

Jonathan Kelley 3 years ago
parent
commit
395558232e
13 changed files with 233 additions and 65 deletions
  1. 4 3
      Cargo.toml
  2. 1 4
      examples/frame.rs
  3. 59 0
      examples/keys.rs
  4. 1 4
      examples/list.rs
  5. 3 12
      examples/margin.rs
  6. 1 4
      examples/quadrants.rs
  7. 1 4
      examples/readme.rs
  8. 1 4
      examples/task.rs
  9. 1 4
      examples/text.rs
  10. 5 0
      examples/ui.rsx
  11. 104 0
      src/hooks.rs
  12. 20 3
      src/layout.rs
  13. 32 23
      src/lib.rs

+ 4 - 3
Cargo.toml

@@ -10,11 +10,12 @@ tui = { version = "0.16.0", features = ["crossterm"] }
 crossterm = "0.22.1"
 crossterm = "0.22.1"
 anyhow = "1.0.42"
 anyhow = "1.0.42"
 thiserror = "1.0.24"
 thiserror = "1.0.24"
-dioxus = { path = "../../dioxus" }
+# dioxus = { path = "../../dioxus" }
+dioxus = { version = "0.1.7" }
 hecs = "0.7.3"
 hecs = "0.7.3"
 ctrlc = "3.2.1"
 ctrlc = "3.2.1"
 bumpalo = { version = "3.8.0", features = ["boxed"] }
 bumpalo = { version = "3.8.0", features = ["boxed"] }
-stretch2 = { path = "../../Tinkering/stretch2" }
+# stretch2 = { path = "../../Tinkering/stretch2" }
 tokio = { version = "1.15.0", features = ["full"] }
 tokio = { version = "1.15.0", features = ["full"] }
 futures = "0.3.19"
 futures = "0.3.19"
-# stretch2 = { git = "https://github.com/elbaro/stretch2.git" }
+stretch2 = { git = "https://github.com/DioxusLabs/stretch" }

+ 1 - 4
examples/frame.rs

@@ -1,10 +1,7 @@
 use dioxus::prelude::*;
 use dioxus::prelude::*;
 
 
 fn main() {
 fn main() {
-    let mut dom = VirtualDom::new(app);
-    dom.rebuild();
-
-    rink::render_vdom(&mut dom).unwrap();
+    rink::launch(app);
 }
 }
 
 
 fn app(cx: Scope) -> Element {
 fn app(cx: Scope) -> Element {

+ 59 - 0
examples/keys.rs

@@ -0,0 +1,59 @@
+use std::cell::RefCell;
+
+use crossterm::event::KeyEvent;
+use dioxus::prelude::*;
+use rink::InputHandler;
+
+fn main() {
+    rink::launch(app);
+}
+
+fn app(cx: Scope) -> Element {
+    let count = use_state(&cx, || 0);
+
+    cx.render(rsx! {
+        div {
+            width: "100%",
+            height: "10px",
+            background_color: "red",
+            justify_content: "center",
+            align_items: "center",
+            "Hello world!",
+
+            // todo: enabling this will panic
+            // rink::InputHandler {
+            //     onkeydown: move |evt: KeyEvent| {
+            //         use crossterm::event::KeyCode::*;
+            //         match evt.code {
+            //             Left => count += 1,
+            //             Right => count -= 1,
+            //             Up => count += 10,
+            //             Down => count -= 10,
+            //             _ => {},
+            //         }
+            //     },
+            //     onmousedown: move |evt| {},
+            //     onresize: move |dims| {
+            //         println!("{:?}", dims);
+            //     },
+            // }
+        }
+    })
+}
+
+fn app2<'a>(cx: Scope<'a>) -> Element<'a> {
+    let mut count = use_state(&cx, || 0);
+
+    cx.render(rsx! {
+        div {
+            width: "100%",
+            height: "10px",
+            background_color: "red",
+            justify_content: "center",
+            align_items: "center",
+            oninput: move |_| count += 1,
+            "Hello world!",
+            h1 {},
+        }
+    })
+}

+ 1 - 4
examples/list.rs

@@ -1,10 +1,7 @@
 use dioxus::prelude::*;
 use dioxus::prelude::*;
 
 
 fn main() {
 fn main() {
-    let mut dom = VirtualDom::new(app);
-    dom.rebuild();
-
-    rink::render_vdom(&mut dom).unwrap();
+    rink::launch(app);
 }
 }
 
 
 fn app(cx: Scope) -> Element {
 fn app(cx: Scope) -> Element {

+ 3 - 12
examples/margin.rs

@@ -1,10 +1,7 @@
 use dioxus::prelude::*;
 use dioxus::prelude::*;
 
 
 fn main() {
 fn main() {
-    let mut dom = VirtualDom::new(app);
-    dom.rebuild();
-
-    rink::render_vdom(&mut dom).unwrap();
+    rink::launch(app);
 }
 }
 
 
 fn app(cx: Scope) -> Element {
 fn app(cx: Scope) -> Element {
@@ -16,44 +13,38 @@ fn app(cx: Scope) -> Element {
             background_color: "black",
             background_color: "black",
             // margin_right: "10px",
             // margin_right: "10px",
 
 
-
-
             div {
             div {
                 width: "70%",
                 width: "70%",
                 height: "70%",
                 height: "70%",
-                // margin_left: "4px",
                 background_color: "green",
                 background_color: "green",
+                // margin_left: "4px",
 
 
                 div {
                 div {
                     width: "100%",
                     width: "100%",
                     height: "100%",
                     height: "100%",
 
 
-
                     margin_top: "2px",
                     margin_top: "2px",
                     margin_bottom: "2px",
                     margin_bottom: "2px",
                     margin_left: "2px",
                     margin_left: "2px",
                     margin_right: "2px",
                     margin_right: "2px",
-                    // flex_shrink: "0",
+                    flex_shrink: "0",
 
 
                     background_color: "red",
                     background_color: "red",
                     justify_content: "center",
                     justify_content: "center",
                     align_items: "center",
                     align_items: "center",
                     flex_direction: "column",
                     flex_direction: "column",
 
 
-
                     // padding_top: "2px",
                     // padding_top: "2px",
                     // padding_bottom: "2px",
                     // padding_bottom: "2px",
                     // padding_left: "4px",
                     // padding_left: "4px",
                     // padding_right: "4px",
                     // padding_right: "4px",
 
 
-
                     "[A]"
                     "[A]"
                     "[A]"
                     "[A]"
                     "[A]"
                     "[A]"
                     "[A]"
                     "[A]"
                 }
                 }
             }
             }
-
         }
         }
     })
     })
 }
 }

+ 1 - 4
examples/quadrants.rs

@@ -1,10 +1,7 @@
 use dioxus::prelude::*;
 use dioxus::prelude::*;
 
 
 fn main() {
 fn main() {
-    let mut dom = VirtualDom::new(app);
-    dom.rebuild();
-
-    rink::render_vdom(&mut dom).unwrap();
+    rink::launch(app);
 }
 }
 
 
 fn app(cx: Scope) -> Element {
 fn app(cx: Scope) -> Element {

+ 1 - 4
examples/readme.rs

@@ -1,10 +1,7 @@
 use dioxus::prelude::*;
 use dioxus::prelude::*;
 
 
 fn main() {
 fn main() {
-    let mut dom = VirtualDom::new(app);
-    dom.rebuild();
-
-    rink::render_vdom(&mut dom).unwrap();
+    rink::launch(app);
 }
 }
 
 
 fn app(cx: Scope) -> Element {
 fn app(cx: Scope) -> Element {

+ 1 - 4
examples/task.rs

@@ -1,10 +1,7 @@
 use dioxus::prelude::*;
 use dioxus::prelude::*;
 
 
 fn main() {
 fn main() {
-    let mut dom = VirtualDom::new(app);
-    dom.rebuild();
-
-    rink::render_vdom(&mut dom).unwrap();
+    rink::launch(app);
 }
 }
 
 
 fn app(cx: Scope) -> Element {
 fn app(cx: Scope) -> Element {

+ 1 - 4
examples/text.rs

@@ -1,10 +1,7 @@
 use dioxus::prelude::*;
 use dioxus::prelude::*;
 
 
 fn main() {
 fn main() {
-    let mut dom = VirtualDom::new(app);
-    dom.rebuild();
-
-    rink::render_vdom(&mut dom).unwrap();
+    rink::launch(app);
 }
 }
 
 
 fn app(cx: Scope) -> Element {
 fn app(cx: Scope) -> Element {

+ 5 - 0
examples/ui.rsx

@@ -0,0 +1,5 @@
+div {
+    div {
+
+    }    
+}

+ 104 - 0
src/hooks.rs

@@ -0,0 +1,104 @@
+use anyhow::Result;
+use crossterm::{
+    event::{
+        DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyEvent, MouseEvent,
+    },
+    execute,
+    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
+};
+use dioxus::{core::exports::futures_channel::mpsc::unbounded, prelude::Props};
+use dioxus::{core::*, prelude::*};
+use futures::{channel::mpsc::UnboundedReceiver, future::Either, pin_mut, StreamExt};
+use std::{
+    cell::{Cell, RefCell},
+    collections::HashMap,
+    io,
+    rc::Rc,
+    time::{Duration, Instant},
+};
+use stretch2::{prelude::Size, Stretch};
+use tui::{backend::CrosstermBackend, style::Style as TuiStyle, Terminal};
+
+pub struct RinkContext {
+    last_event: RefCell<Option<TermEvent>>,
+    receiver: Rc<Cell<Option<UnboundedReceiver<TermEvent>>>>,
+}
+
+impl RinkContext {
+    pub fn new(receiver: UnboundedReceiver<TermEvent>) -> Self {
+        Self {
+            last_event: RefCell::new(None),
+            receiver: Rc::new(Cell::new(Some(receiver))),
+        }
+    }
+    pub fn subscribe_to_events(&self, scope: ScopeId) {
+        //
+    }
+}
+
+#[derive(Props)]
+pub struct AppHandlerProps<'a> {
+    // #[props(setter(strip_option), default)]
+    onkeydown: EventHandler<'a, KeyEvent>,
+
+    // #[props(setter(strip_option), default)]
+    onmousedown: EventHandler<'a, MouseEvent>,
+
+    #[props(setter(strip_option), default)]
+    onresize: Option<EventHandler<'a, (u16, u16)>>,
+}
+
+/// This component lets you handle input events
+///
+/// Once attached to the DOM, it will listen for input events from the terminal
+///
+///
+pub fn InputHandler<'a>(cx: Scope<'a, AppHandlerProps<'a>>) -> Element {
+    let rcx = cx.use_hook(|_| {
+        let rcx = cx
+            .consume_context::<RinkContext>()
+            .unwrap_or_else(|| panic!("Rink InputHandlers can only be used in Rink apps!"));
+
+        // our component will only re-render if new events are received ... or if the parent is updated
+        // todo: if update was not caused by a new event, we should not re-render
+        // perhaps add some tracking to context?
+        rcx.subscribe_to_events(cx.scope_id());
+
+        let mut rec = rcx.receiver.take().unwrap();
+        let updater = cx.schedule_update();
+        let rc2 = rcx.clone();
+        cx.push_future(async move {
+            while let Some(evt) = rec.next().await {
+                rc2.last_event.borrow_mut().replace(evt);
+                println!("{:?}", evt);
+                updater();
+            }
+            //
+        });
+
+        rcx
+    });
+
+    if let Some(evet) = rcx.last_event.borrow().as_ref() {
+        match evet {
+            TermEvent::Key(key) => {
+                cx.props.onkeydown.call(key.clone());
+                // let mut handler = cx.props.keydown.borrow_mut();
+                // handler(*key);
+                // if let Some(handler) = cx.props.onkeydown {
+                //     handler(*key);
+                // }
+            }
+            TermEvent::Mouse(mouse) => {
+                cx.props.onmousedown.call(mouse.clone());
+            }
+            TermEvent::Resize(x, y) => {
+                // if let Some(handler) = cx.props.onresize {
+                //     handler((*x, *y));
+                // }
+            }
+        }
+    }
+
+    None
+}

+ 20 - 3
src/layout.rs

@@ -67,7 +67,17 @@ pub fn collect_layout<'a>(
             for el in el.children {
             for el in el.children {
                 let ite = ElementIdIterator::new(vdom, el);
                 let ite = ElementIdIterator::new(vdom, el);
                 for node in ite {
                 for node in ite {
-                    child_layout.push(nodes[&node.mounted_id()].layout)
+                    match node {
+                        VNode::Element(_) | VNode::Text(_) => {
+                            //
+                            child_layout.push(nodes[&node.mounted_id()].layout)
+                        }
+                        VNode::Placeholder(_) => {}
+                        VNode::Fragment(_) => todo!(),
+                        VNode::Component(_) => todo!(),
+                    }
+
+                    // child_layout.push(nodes[&node.mounted_id()].layout)
                 }
                 }
             }
             }
 
 
@@ -86,7 +96,14 @@ pub fn collect_layout<'a>(
                 collect_layout(layout, nodes, vdom, child);
                 collect_layout(layout, nodes, vdom, child);
             }
             }
         }
         }
-        VNode::Component(_) => todo!(),
-        VNode::Placeholder(_) => todo!(),
+        VNode::Component(sc) => {
+            //
+            let scope = vdom.get_scope(sc.scope.get().unwrap()).unwrap();
+            let root = scope.root_node();
+            collect_layout(layout, nodes, vdom, root);
+        }
+        VNode::Placeholder(_) => {
+            //
+        }
     };
     };
 }
 }

+ 32 - 23
src/lib.rs

@@ -4,35 +4,52 @@ use crossterm::{
     execute,
     execute,
     terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
     terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
 };
 };
-use dioxus::core::exports::futures_channel::mpsc::unbounded;
-use dioxus::core::*;
-use futures::{future::Either, pin_mut, StreamExt};
+use dioxus::{core::exports::futures_channel::mpsc::unbounded, prelude::Props};
+use dioxus::{core::*, prelude::*};
+use futures::{
+    channel::mpsc::{UnboundedReceiver, UnboundedSender},
+    future::Either,
+    pin_mut, StreamExt,
+};
 use std::{
 use std::{
+    cell::Cell,
     collections::HashMap,
     collections::HashMap,
     io,
     io,
+    rc::Rc,
     time::{Duration, Instant},
     time::{Duration, Instant},
 };
 };
 use stretch2::{prelude::Size, Stretch};
 use stretch2::{prelude::Size, Stretch};
 use tui::{backend::CrosstermBackend, style::Style as TuiStyle, Terminal};
 use tui::{backend::CrosstermBackend, style::Style as TuiStyle, Terminal};
 
 
 mod attributes;
 mod attributes;
+mod hooks;
 mod layout;
 mod layout;
 mod render;
 mod render;
 
 
 pub use attributes::*;
 pub use attributes::*;
+pub use hooks::*;
 pub use layout::*;
 pub use layout::*;
 pub use render::*;
 pub use render::*;
 
 
+pub fn launch(app: Component<()>) {
+    let mut dom = VirtualDom::new(app);
+    let (tx, rx) = unbounded();
+
+    dom.base_scope().provide_context(RinkContext::new(rx));
+    dom.rebuild();
+
+    render_vdom(&mut dom, tx).unwrap();
+}
+
 pub struct TuiNode<'a> {
 pub struct TuiNode<'a> {
     pub layout: stretch2::node::Node,
     pub layout: stretch2::node::Node,
     pub block_style: TuiStyle,
     pub block_style: TuiStyle,
     pub node: &'a VNode<'a>,
     pub node: &'a VNode<'a>,
 }
 }
 
 
-pub fn render_vdom(vdom: &mut VirtualDom) -> Result<()> {
+pub fn render_vdom(vdom: &mut VirtualDom, ctx: UnboundedSender<TermEvent>) -> Result<()> {
     // Setup input handling
     // Setup input handling
     let (tx, mut rx) = unbounded();
     let (tx, mut rx) = unbounded();
-
     std::thread::spawn(move || {
     std::thread::spawn(move || {
         let tick_rate = Duration::from_millis(100);
         let tick_rate = Duration::from_millis(100);
         let mut last_tick = Instant::now();
         let mut last_tick = Instant::now();
@@ -117,35 +134,27 @@ pub fn render_vdom(vdom: &mut VirtualDom) -> Result<()> {
 
 
                     match select(wait, rx.next()).await {
                     match select(wait, rx.next()).await {
                         Either::Left((a, b)) => {
                         Either::Left((a, b)) => {
-                            // println!("work");
+                            //
                         }
                         }
                         Either::Right((evt, o)) => {
                         Either::Right((evt, o)) => {
-                            // println!("event");
-                            match evt.unwrap() {
+                            //
+                            match evt.as_ref().unwrap() {
                                 InputEvent::UserInput(event) => match event {
                                 InputEvent::UserInput(event) => match event {
                                     TermEvent::Key(key) => {
                                     TermEvent::Key(key) => {
                                         match key.code {
                                         match key.code {
-                                            KeyCode::Char('q') => {
-                                                disable_raw_mode()?;
-                                                execute!(
-                                                    terminal.backend_mut(),
-                                                    LeaveAlternateScreen,
-                                                    DisableMouseCapture
-                                                )?;
-                                                terminal.show_cursor()?;
-                                                break;
-                                            }
+                                            KeyCode::Char('q') => break,
                                             _ => {} // handle event
                                             _ => {} // handle event
                                         }
                                         }
                                     }
                                     }
-                                    TermEvent::Mouse(_) => {}
-                                    TermEvent::Resize(_, _) => {}
+                                    TermEvent::Resize(_, _) | TermEvent::Mouse(_) => {}
                                 },
                                 },
                                 InputEvent::Tick => {} // tick
                                 InputEvent::Tick => {} // tick
-                                InputEvent::Close => {
-                                    break;
-                                }
+                                InputEvent::Close => break,
                             };
                             };
+
+                            if let InputEvent::UserInput(evt) = evt.unwrap() {
+                                ctx.unbounded_send(evt).unwrap();
+                            }
                         }
                         }
                     }
                     }
                 }
                 }