improve ergonomics of custom drivers and add a counter example to rink
This commit is contained in:
1 parent
b255800511
commit
ae1300b015
8 files changed
+338
-364
No files matched your search
@@ -12,8 +12,8 @@ use dioxus_html::EventData;
|
|||||||
use dioxus_native_core::dioxus::{DioxusState, NodeImmutableDioxusExt};
|
use dioxus_native_core::dioxus::{DioxusState, NodeImmutableDioxusExt};
|
||||||
use dioxus_native_core::prelude::*;
|
use dioxus_native_core::prelude::*;
|
||||||
|
|
||||||
pub use rink::{query::Query, Config, Size, TuiContext, RenderingMode};
|
pub use rink::{query::Query, Config, RenderingMode, Size, TuiContext};
|
||||||
use rink::{render, Renderer};
|
use rink::{render, Driver};
|
||||||
|
|
||||||
pub fn launch(app: Component<()>) {
|
pub fn launch(app: Component<()>) {
|
||||||
launch_cfg(app, Config::default())
|
launch_cfg(app, Config::default())
|
||||||
@@ -66,8 +66,8 @@ struct DioxusRenderer {
|
|||||||
hot_reload_rx: tokio::sync::mpsc::UnboundedReceiver<dioxus_hot_reload::HotReloadMsg>,
|
hot_reload_rx: tokio::sync::mpsc::UnboundedReceiver<dioxus_hot_reload::HotReloadMsg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer for DioxusRenderer {
|
impl Driver for DioxusRenderer {
|
||||||
fn render(&mut self, rdom: &Arc<RwLock<RealDom>>) {
|
fn update(&mut self, rdom: &Arc<RwLock<RealDom>>) {
|
||||||
let muts = self.vdom.render_immediate();
|
let muts = self.vdom.render_immediate();
|
||||||
{
|
{
|
||||||
let mut rdom = rdom.write().unwrap();
|
let mut rdom = rdom.write().unwrap();
|
||||||
|
|||||||
@@ -62,6 +62,24 @@ pub struct OwnedAttributeDiscription {
|
|||||||
pub namespace: Option<String>,
|
pub namespace: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<String> for OwnedAttributeDiscription {
|
||||||
|
fn from(name: String) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
namespace: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Into<String>, N: Into<String>> From<(S, N)> for OwnedAttributeDiscription {
|
||||||
|
fn from(name: (S, N)) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.0.into(),
|
||||||
|
namespace: Some(name.1.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An attribute on a DOM node, such as `id="my-thing"` or
|
/// An attribute on a DOM node, such as `id="my-thing"` or
|
||||||
/// `href="https://example.com"`.
|
/// `href="https://example.com"`.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
@@ -88,6 +106,36 @@ pub enum OwnedAttributeValue<V: FromAnyValue = ()> {
|
|||||||
Custom(V),
|
Custom(V),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<String> for OwnedAttributeValue {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
Self::Text(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f64> for OwnedAttributeValue {
|
||||||
|
fn from(value: f64) -> Self {
|
||||||
|
Self::Float(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i64> for OwnedAttributeValue {
|
||||||
|
fn from(value: i64) -> Self {
|
||||||
|
Self::Int(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for OwnedAttributeValue {
|
||||||
|
fn from(value: bool) -> Self {
|
||||||
|
Self::Bool(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: FromAnyValue> From<V> for OwnedAttributeValue<V> {
|
||||||
|
fn from(value: V) -> Self {
|
||||||
|
Self::Custom(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Something that can be converted from a borrowed [Any] value.
|
/// Something that can be converted from a borrowed [Any] value.
|
||||||
pub trait FromAnyValue: Clone + 'static {
|
pub trait FromAnyValue: Clone + 'static {
|
||||||
/// Convert from an [Any] value.
|
/// Convert from an [Any] value.
|
||||||
|
|||||||
@@ -933,9 +933,11 @@ impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
|
|||||||
/// Set an attribute in the element
|
/// Set an attribute in the element
|
||||||
pub fn set_attribute(
|
pub fn set_attribute(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: OwnedAttributeDiscription,
|
name: impl Into<OwnedAttributeDiscription>,
|
||||||
value: OwnedAttributeValue<V>,
|
value: impl Into<OwnedAttributeValue<V>>,
|
||||||
) -> Option<OwnedAttributeValue<V>> {
|
) -> Option<OwnedAttributeValue<V>> {
|
||||||
|
let name = name.into();
|
||||||
|
let value = value.into();
|
||||||
self.dirty_nodes.mark_dirty(
|
self.dirty_nodes.mark_dirty(
|
||||||
self.id,
|
self.id,
|
||||||
NodeMaskBuilder::new()
|
NodeMaskBuilder::new()
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
use dioxus_html::EventData;
|
||||||
|
use dioxus_native_core::{
|
||||||
|
node::TextNode,
|
||||||
|
prelude::*,
|
||||||
|
real_dom::{NodeImmutable, NodeTypeMut},
|
||||||
|
NodeId,
|
||||||
|
};
|
||||||
|
use rink::{render, Config, Driver};
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Counter {
|
||||||
|
count: usize,
|
||||||
|
counter_id: NodeId,
|
||||||
|
button_id: NodeId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Counter {
|
||||||
|
fn create(mut root: NodeMut) -> Self {
|
||||||
|
let mut myself = Self::default();
|
||||||
|
|
||||||
|
let root_id = root.id();
|
||||||
|
let rdom = root.real_dom_mut();
|
||||||
|
|
||||||
|
// create the counter
|
||||||
|
let count = myself.count;
|
||||||
|
myself.counter_id = rdom
|
||||||
|
.create_node(NodeType::Text(TextNode::new(count.to_string())))
|
||||||
|
.id();
|
||||||
|
let mut button = rdom.create_node(NodeType::Element(ElementNode {
|
||||||
|
tag: "div".to_string(),
|
||||||
|
attributes: [
|
||||||
|
("display".to_string().into(), "flex".to_string().into()),
|
||||||
|
(
|
||||||
|
("background-color", "style").into(),
|
||||||
|
format!("rgb({}, {}, {})", count * 10, 0, 0,).into(),
|
||||||
|
),
|
||||||
|
(("width", "style").into(), "100%".to_string().into()),
|
||||||
|
(("height", "style").into(), "100%".to_string().into()),
|
||||||
|
(("flex-direction", "style").into(), "row".to_string().into()),
|
||||||
|
(
|
||||||
|
("justify-content", "style").into(),
|
||||||
|
"center".to_string().into(),
|
||||||
|
),
|
||||||
|
(("align-items", "style").into(), "center".to_string().into()),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
button.add_event_listener("click");
|
||||||
|
button.add_event_listener("wheel");
|
||||||
|
button.add_child(myself.counter_id);
|
||||||
|
myself.button_id = button.id();
|
||||||
|
rdom.get_mut(root_id).unwrap().add_child(myself.button_id);
|
||||||
|
|
||||||
|
myself
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Driver for Counter {
|
||||||
|
fn update(&mut self, rdom: &Arc<RwLock<RealDom>>) {
|
||||||
|
// update the counter
|
||||||
|
let mut rdom = rdom.write().unwrap();
|
||||||
|
let mut node = rdom.get_mut(self.button_id).unwrap();
|
||||||
|
if let NodeTypeMut::Element(mut el) = node.node_type_mut() {
|
||||||
|
el.set_attribute(
|
||||||
|
("background-color", "style"),
|
||||||
|
format!("rgb({}, {}, {})", self.count * 10, 0, 0,),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let mut text = rdom.get_mut(self.counter_id).unwrap();
|
||||||
|
let type_mut = text.node_type_mut();
|
||||||
|
if let NodeTypeMut::Text(mut text) = type_mut {
|
||||||
|
*text = self.count.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_event(
|
||||||
|
&mut self,
|
||||||
|
_: &Arc<RwLock<RealDom>>,
|
||||||
|
_: NodeId,
|
||||||
|
_: &str,
|
||||||
|
_: Rc<EventData>,
|
||||||
|
_: bool,
|
||||||
|
) {
|
||||||
|
// when a click or wheel event is fired, increment the counter
|
||||||
|
self.count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_async(&mut self) -> std::pin::Pin<Box<dyn futures::Future<Output = ()> + '_>> {
|
||||||
|
Box::pin(async move { tokio::time::sleep(std::time::Duration::from_millis(1000)).await })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
render(Config::new(), |rdom, _, _| {
|
||||||
|
let mut rdom = rdom.write().unwrap();
|
||||||
|
let root = rdom.root_id();
|
||||||
|
Counter::create(rdom.get_mut(root).unwrap())
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
@@ -1,260 +0,0 @@
|
|||||||
use dioxus_html::EventData;
|
|
||||||
use dioxus_native_core::{
|
|
||||||
node::{OwnedAttributeDiscription, OwnedAttributeValue, TextNode},
|
|
||||||
prelude::*,
|
|
||||||
real_dom::{NodeImmutable, NodeTypeMut},
|
|
||||||
NodeId,
|
|
||||||
};
|
|
||||||
use dioxus_tui::{self, render, Config, Renderer};
|
|
||||||
use rustc_hash::FxHashSet;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::{Arc, RwLock};
|
|
||||||
|
|
||||||
const SIZE: usize = 10;
|
|
||||||
|
|
||||||
struct Test {
|
|
||||||
node_states: [[usize; SIZE]; SIZE],
|
|
||||||
dirty: FxHashSet<(usize, usize)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Test {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
node_states: [[0; SIZE]; SIZE],
|
|
||||||
dirty: FxHashSet::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Test {
|
|
||||||
fn create(mut root: NodeMut) -> Self {
|
|
||||||
let myself = Self::default();
|
|
||||||
|
|
||||||
// Set the root node to be a flexbox with a column direction.
|
|
||||||
if let NodeTypeMut::Element(mut el) = root.node_type_mut() {
|
|
||||||
el.set_attribute(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "display".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("flex".into()),
|
|
||||||
);
|
|
||||||
el.set_attribute(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "flex-direction".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("column".into()),
|
|
||||||
);
|
|
||||||
el.set_attribute(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "width".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("100%".into()),
|
|
||||||
);
|
|
||||||
el.set_attribute(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "height".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("100%".into()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let root_id = root.id();
|
|
||||||
let rdom = root.real_dom_mut();
|
|
||||||
|
|
||||||
// create the grid
|
|
||||||
for (x, row) in myself.node_states.iter().copied().enumerate() {
|
|
||||||
let row_node = rdom
|
|
||||||
.create_node(NodeType::Element(ElementNode {
|
|
||||||
tag: "div".to_string(),
|
|
||||||
attributes: [
|
|
||||||
(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "display".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("flex".into()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "flex-direction".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("row".into()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "width".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("100%".into()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "height".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("100%".into()),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.collect(),
|
|
||||||
..Default::default()
|
|
||||||
}))
|
|
||||||
.id();
|
|
||||||
for (y, count) in row.iter().copied().enumerate() {
|
|
||||||
let node = rdom
|
|
||||||
.create_node(NodeType::Text(TextNode::new(count.to_string())))
|
|
||||||
.id();
|
|
||||||
let mut button = rdom.create_node(NodeType::Element(ElementNode {
|
|
||||||
tag: "div".to_string(),
|
|
||||||
attributes: [
|
|
||||||
(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "background-color".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text(format!(
|
|
||||||
"rgb({}, {}, {})",
|
|
||||||
count * 10,
|
|
||||||
0,
|
|
||||||
(x + y) * 10,
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "width".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("100%".into()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "height".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("100%".into()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "display".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("flex".into()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "flex-direction".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("row".into()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "justify-content".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("center".into()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "align-items".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text("center".into()),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.collect(),
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
button.add_event_listener("click");
|
|
||||||
button.add_event_listener("wheel");
|
|
||||||
button.add_child(node);
|
|
||||||
let button_id = button.id();
|
|
||||||
rdom.get_mut(row_node).unwrap().add_child(button_id);
|
|
||||||
}
|
|
||||||
rdom.get_mut(root_id).unwrap().add_child(row_node);
|
|
||||||
}
|
|
||||||
myself
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Renderer for Test {
|
|
||||||
fn render(&mut self, rdom: &Arc<RwLock<RealDom>>) {
|
|
||||||
let mut rdom = rdom.write().unwrap();
|
|
||||||
let root_id = rdom.root_id();
|
|
||||||
let mut root = rdom.get_mut(root_id).unwrap();
|
|
||||||
for (x, y) in self.dirty.drain() {
|
|
||||||
let row_id = root.child_ids()[x];
|
|
||||||
let rdom = root.real_dom_mut();
|
|
||||||
let row = rdom.get(row_id).unwrap();
|
|
||||||
let node_id = row.child_ids()[y];
|
|
||||||
let mut node = rdom.get_mut(node_id).unwrap();
|
|
||||||
if let NodeTypeMut::Element(mut el) = node.node_type_mut() {
|
|
||||||
el.set_attribute(
|
|
||||||
OwnedAttributeDiscription {
|
|
||||||
name: "background-color".into(),
|
|
||||||
namespace: None,
|
|
||||||
},
|
|
||||||
OwnedAttributeValue::Text(format!(
|
|
||||||
"rgb({}, {}, {})",
|
|
||||||
self.node_states[x][y] * 10,
|
|
||||||
0,
|
|
||||||
(x + y) * 10,
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let text_id = *node.child_ids().first().unwrap();
|
|
||||||
let mut text = rdom.get_mut(text_id).unwrap();
|
|
||||||
let type_mut = text.node_type_mut();
|
|
||||||
if let NodeTypeMut::Text(mut text) = type_mut {
|
|
||||||
*text = self.node_states[x][y].to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_event(
|
|
||||||
&mut self,
|
|
||||||
rdom: &Arc<RwLock<RealDom>>,
|
|
||||||
id: NodeId,
|
|
||||||
_: &str,
|
|
||||||
_: Rc<EventData>,
|
|
||||||
_: bool,
|
|
||||||
) {
|
|
||||||
let rdom = rdom.read().unwrap();
|
|
||||||
let node = rdom.get(id).unwrap();
|
|
||||||
if let Some(parent) = node.parent() {
|
|
||||||
let child_number = parent
|
|
||||||
.child_ids()
|
|
||||||
.iter()
|
|
||||||
.position(|id| *id == node.id())
|
|
||||||
.unwrap();
|
|
||||||
if let Some(parents_parent) = parent.parent() {
|
|
||||||
let parents_child_number = parents_parent
|
|
||||||
.child_ids()
|
|
||||||
.iter()
|
|
||||||
.position(|id| *id == parent.id())
|
|
||||||
.unwrap();
|
|
||||||
self.node_states[parents_child_number][child_number] += 1;
|
|
||||||
self.dirty.insert((parents_child_number, child_number));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_async(&mut self) -> std::pin::Pin<Box<dyn futures::Future<Output = ()> + '_>> {
|
|
||||||
Box::pin(async move { tokio::time::sleep(std::time::Duration::from_millis(1000)).await })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
render(Config::new(), |rdom, _, _| {
|
|
||||||
let mut rdom = rdom.write().unwrap();
|
|
||||||
let root = rdom.root_id();
|
|
||||||
Test::create(rdom.get_mut(root).unwrap())
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
use dioxus_html::EventData;
|
||||||
|
use dioxus_native_core::{
|
||||||
|
node::TextNode,
|
||||||
|
prelude::*,
|
||||||
|
real_dom::{NodeImmutable, NodeTypeMut},
|
||||||
|
NodeId,
|
||||||
|
};
|
||||||
|
use rink::{render, Config, Driver};
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
|
const SIZE: usize = 20;
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Copy)]
|
||||||
|
struct Node {
|
||||||
|
container_id: Option<NodeId>,
|
||||||
|
text_id: Option<NodeId>,
|
||||||
|
count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Test {
|
||||||
|
node_states: [[Node; SIZE]; SIZE],
|
||||||
|
dirty: FxHashSet<(usize, usize)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Test {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
node_states: [[Node {
|
||||||
|
container_id: None,
|
||||||
|
text_id: None,
|
||||||
|
count: 0,
|
||||||
|
}; SIZE]; SIZE],
|
||||||
|
dirty: FxHashSet::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Test {
|
||||||
|
fn create(mut root: NodeMut) -> Self {
|
||||||
|
let mut myself = Self::default();
|
||||||
|
|
||||||
|
// Set the root node to be a flexbox with a column direction.
|
||||||
|
if let NodeTypeMut::Element(mut el) = root.node_type_mut() {
|
||||||
|
el.set_attribute("display".to_string(), "flex".to_string());
|
||||||
|
el.set_attribute(("flex-direction", "style"), "column".to_string());
|
||||||
|
el.set_attribute(("width", "style"), "100%".to_string());
|
||||||
|
el.set_attribute(("height", "style"), "100%".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let root_id = root.id();
|
||||||
|
let rdom = root.real_dom_mut();
|
||||||
|
|
||||||
|
// create the grid
|
||||||
|
for (x, row) in myself.node_states.iter_mut().enumerate() {
|
||||||
|
let row_node = rdom
|
||||||
|
.create_node(NodeType::Element(ElementNode {
|
||||||
|
tag: "div".to_string(),
|
||||||
|
attributes: [
|
||||||
|
("display".to_string().into(), "flex".to_string().into()),
|
||||||
|
(("flex-direction", "style").into(), "row".to_string().into()),
|
||||||
|
(("width", "style").into(), "100%".to_string().into()),
|
||||||
|
(("height", "style").into(), "100%".to_string().into()),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
..Default::default()
|
||||||
|
}))
|
||||||
|
.id();
|
||||||
|
for (y, node) in row.iter_mut().enumerate() {
|
||||||
|
let count = node.count;
|
||||||
|
let id = rdom
|
||||||
|
.create_node(NodeType::Text(TextNode::new(count.to_string())))
|
||||||
|
.id();
|
||||||
|
let mut button = rdom.create_node(NodeType::Element(ElementNode {
|
||||||
|
tag: "div".to_string(),
|
||||||
|
attributes: [
|
||||||
|
("display".to_string().into(), "flex".to_string().into()),
|
||||||
|
(
|
||||||
|
("background-color", "style").into(),
|
||||||
|
format!("rgb({}, {}, {})", count * 10, 0, (x + y),).into(),
|
||||||
|
),
|
||||||
|
(("width", "style").into(), "100%".to_string().into()),
|
||||||
|
(("height", "style").into(), "100%".to_string().into()),
|
||||||
|
(("flex-direction", "style").into(), "row".to_string().into()),
|
||||||
|
(
|
||||||
|
("justify-content", "style").into(),
|
||||||
|
"center".to_string().into(),
|
||||||
|
),
|
||||||
|
(("align-items", "style").into(), "center".to_string().into()),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
button.add_event_listener("click");
|
||||||
|
button.add_event_listener("wheel");
|
||||||
|
button.add_child(id);
|
||||||
|
let button_id = button.id();
|
||||||
|
rdom.get_mut(row_node).unwrap().add_child(button_id);
|
||||||
|
node.container_id = Some(button_id);
|
||||||
|
node.text_id = Some(id);
|
||||||
|
}
|
||||||
|
rdom.get_mut(root_id).unwrap().add_child(row_node);
|
||||||
|
}
|
||||||
|
myself
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Driver for Test {
|
||||||
|
fn update(&mut self, rdom: &Arc<RwLock<RealDom>>) {
|
||||||
|
let mut rdom = rdom.write().unwrap();
|
||||||
|
for (x, y) in self.dirty.drain() {
|
||||||
|
let node = self.node_states[x][y];
|
||||||
|
let node_id = node.container_id.unwrap();
|
||||||
|
let mut container = rdom.get_mut(node_id).unwrap();
|
||||||
|
if let NodeTypeMut::Element(mut el) = container.node_type_mut() {
|
||||||
|
el.set_attribute(
|
||||||
|
("background-color", "style"),
|
||||||
|
format!("rgb({}, {}, {})", node.count * 10, 0, (x + y),),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let text_id = node.text_id.unwrap();
|
||||||
|
let mut text = rdom.get_mut(text_id).unwrap();
|
||||||
|
let type_mut = text.node_type_mut();
|
||||||
|
if let NodeTypeMut::Text(mut text) = type_mut {
|
||||||
|
*text = node.count.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_event(
|
||||||
|
&mut self,
|
||||||
|
rdom: &Arc<RwLock<RealDom>>,
|
||||||
|
id: NodeId,
|
||||||
|
_: &str,
|
||||||
|
_: Rc<EventData>,
|
||||||
|
_: bool,
|
||||||
|
) {
|
||||||
|
let rdom = rdom.read().unwrap();
|
||||||
|
let node = rdom.get(id).unwrap();
|
||||||
|
if let Some(parent) = node.parent() {
|
||||||
|
let child_number = parent
|
||||||
|
.child_ids()
|
||||||
|
.iter()
|
||||||
|
.position(|id| *id == node.id())
|
||||||
|
.unwrap();
|
||||||
|
if let Some(parents_parent) = parent.parent() {
|
||||||
|
let parents_child_number = parents_parent
|
||||||
|
.child_ids()
|
||||||
|
.iter()
|
||||||
|
.position(|id| *id == parent.id())
|
||||||
|
.unwrap();
|
||||||
|
self.node_states[parents_child_number][child_number].count += 1;
|
||||||
|
self.dirty.insert((parents_child_number, child_number));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_async(&mut self) -> std::pin::Pin<Box<dyn futures::Future<Output = ()> + '_>> {
|
||||||
|
Box::pin(async move { tokio::time::sleep(std::time::Duration::from_millis(1000)).await })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
render(Config::new(), |rdom, _, _| {
|
||||||
|
let mut rdom = rdom.write().unwrap();
|
||||||
|
let root = rdom.root_id();
|
||||||
|
Test::create(rdom.get_mut(root).unwrap())
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
use dioxus::prelude::*;
|
|
||||||
use dioxus_html::FormData;
|
|
||||||
use dioxus_tui::prelude::*;
|
|
||||||
use dioxus_tui::Config;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
dioxus_tui::launch_cfg(app, Config::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
|
||||||
let bg_green = use_state(cx, || false);
|
|
||||||
|
|
||||||
let color = if *bg_green.get() { "green" } else { "red" };
|
|
||||||
cx.render(rsx! {
|
|
||||||
div{
|
|
||||||
width: "100%",
|
|
||||||
background_color: "{color}",
|
|
||||||
flex_direction: "column",
|
|
||||||
align_items: "center",
|
|
||||||
justify_content: "center",
|
|
||||||
|
|
||||||
Input{
|
|
||||||
oninput: |data: FormData| if &data.value == "good"{
|
|
||||||
bg_green.set(true);
|
|
||||||
} else{
|
|
||||||
bg_green.set(false);
|
|
||||||
},
|
|
||||||
r#type: "checkbox",
|
|
||||||
value: "good",
|
|
||||||
width: "50%",
|
|
||||||
height: "10%",
|
|
||||||
checked: "true",
|
|
||||||
}
|
|
||||||
Input{
|
|
||||||
oninput: |data: FormData| if &data.value == "hello world"{
|
|
||||||
bg_green.set(true);
|
|
||||||
} else{
|
|
||||||
bg_green.set(false);
|
|
||||||
},
|
|
||||||
width: "50%",
|
|
||||||
height: "10%",
|
|
||||||
maxlength: "11",
|
|
||||||
}
|
|
||||||
Input{
|
|
||||||
oninput: |data: FormData| {
|
|
||||||
if (data.value.parse::<f32>().unwrap() - 40.0).abs() < 5.0 {
|
|
||||||
bg_green.set(true);
|
|
||||||
} else{
|
|
||||||
bg_green.set(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
r#type: "range",
|
|
||||||
width: "50%",
|
|
||||||
height: "10%",
|
|
||||||
min: "20",
|
|
||||||
max: "80",
|
|
||||||
}
|
|
||||||
Input{
|
|
||||||
oninput: |data: FormData| {
|
|
||||||
if data.value == "10"{
|
|
||||||
bg_green.set(true);
|
|
||||||
} else{
|
|
||||||
bg_green.set(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
r#type: "number",
|
|
||||||
width: "50%",
|
|
||||||
height: "10%",
|
|
||||||
maxlength: "4",
|
|
||||||
}
|
|
||||||
Input{
|
|
||||||
oninput: |data: FormData| {
|
|
||||||
if data.value == "hello world"{
|
|
||||||
bg_green.set(true);
|
|
||||||
} else{
|
|
||||||
bg_green.set(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
r#type: "password",
|
|
||||||
width: "50%",
|
|
||||||
height: "10%",
|
|
||||||
maxlength: "11",
|
|
||||||
}
|
|
||||||
Input{
|
|
||||||
onclick: |_: FormData| bg_green.set(true),
|
|
||||||
r#type: "button",
|
|
||||||
value: "green",
|
|
||||||
width: "50%",
|
|
||||||
height: "10%",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -76,7 +76,7 @@ impl TuiContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render<R: Renderer>(
|
pub fn render<R: Driver>(
|
||||||
cfg: Config,
|
cfg: Config,
|
||||||
create_renderer: impl FnOnce(
|
create_renderer: impl FnOnce(
|
||||||
&Arc<RwLock<RealDom>>,
|
&Arc<RwLock<RealDom>>,
|
||||||
@@ -115,7 +115,7 @@ pub fn render<R: Renderer>(
|
|||||||
let mut renderer = create_renderer(&rdom, &taffy, event_tx_clone);
|
let mut renderer = create_renderer(&rdom, &taffy, event_tx_clone);
|
||||||
|
|
||||||
{
|
{
|
||||||
renderer.render(&rdom);
|
renderer.update(&rdom);
|
||||||
let mut any_map = SendAnyMap::new();
|
let mut any_map = SendAnyMap::new();
|
||||||
any_map.insert(taffy.clone());
|
any_map.insert(taffy.clone());
|
||||||
let mut rdom = rdom.write().unwrap();
|
let mut rdom = rdom.write().unwrap();
|
||||||
@@ -261,7 +261,7 @@ pub fn render<R: Renderer>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// updates the dom's nodes
|
// updates the dom's nodes
|
||||||
renderer.render(&rdom);
|
renderer.update(&rdom);
|
||||||
// update the style and layout
|
// update the style and layout
|
||||||
let mut rdom = rdom.write().unwrap();
|
let mut rdom = rdom.write().unwrap();
|
||||||
let mut any_map = SendAnyMap::new();
|
let mut any_map = SendAnyMap::new();
|
||||||
@@ -297,8 +297,8 @@ pub enum InputEvent {
|
|||||||
Close,
|
Close,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Renderer {
|
pub trait Driver {
|
||||||
fn render(&mut self, rdom: &Arc<RwLock<RealDom>>);
|
fn update(&mut self, rdom: &Arc<RwLock<RealDom>>);
|
||||||
fn handle_event(
|
fn handle_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
rdom: &Arc<RwLock<RealDom>>,
|
rdom: &Arc<RwLock<RealDom>>,
|
||||||
|
|||||||
Reference in new issue
Block a user