Skip to content
Merged
1 change: 0 additions & 1 deletion macros/src/vtui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use quote::{ToTokens, quote};
use syn::{
Token, braced,
parse::{Parse, ParseStream, discouraged::Speculative},
punctuated::Punctuated,
spanned::Spanned,
};

Expand Down
129 changes: 75 additions & 54 deletions src/arena.rs
Original file line number Diff line number Diff line change
@@ -1,82 +1,77 @@
use ratatui::buffer::Buffer;
use ratatui::{Frame, buffer::Buffer};
use slotmap::{SlotMap, new_key_type};

use crate::{
canvas::{Canvas, LogicalRect},
component::{Child, Node},
context::Context,
events::Message,
context::{Context, UpdatePass, UpdateState},
layout::Measure,
transport::Message,
};

new_key_type! { struct NodeId; }

#[derive(Default)]
pub(crate) struct Arena {
root: NodeId,
inner: SlotMap<NodeId, ArenaNode>,
nodes: SlotMap<NodeId, ArenaNode>,
traversal: Option<Vec<NodeId>>,
}

impl Arena {
pub fn new(root: Node) -> Self {
let mut arena = Self::default();
let mut arena = Self {
root: NodeId::default(),
nodes: SlotMap::default(),
traversal: None,
};

arena.root = arena.push(root);
arena.compute_traversal();

arena
}

pub fn update_for_each<F>(&mut self, mut update_fn: F)
where
F: FnMut(&mut ArenaNode),
{
let mut stack = vec![(self.root, false)];

while let Some((id, visited)) = stack.pop() {
if visited {
let node = &mut self.inner[id];
update_fn(node);
} else {
stack.push((id, true));
for &(child, _) in self.inner[id].children.iter().rev() {
stack.push((child, false));
}
}
pub fn dispatch(&mut self, msg: &Message, ctx: &mut Context) {
if self.traversal.is_none() {
self.compute_traversal();
}
}

pub fn draw_for_each<F>(&mut self, rect: LogicalRect, mut draw_fn: F)
where
F: FnMut(&ArenaNode),
{
let mut stack = vec![self.root];
let order = self.traversal.as_ref().unwrap().iter().rev();
let mut state = UpdateState::default();

self.compute_layout(rect);
for &id in order {
let node = &mut self.nodes[id];
let pass = UpdatePass::new(ctx, &mut state, node.rect);
node.dispatch(msg, pass);
}
}

while let Some(id) = stack.pop() {
let node = &self.inner[id];
draw_fn(node);
pub fn render(&mut self, frame: &mut Frame) {
if self.traversal.is_none() {
self.compute_traversal();
}

let mut children = self.inner[id]
.children
.iter()
.map(|(c, _)| *c)
.collect::<Vec<_>>();
let rect = frame.area().into();
let buf = frame.buffer_mut();

children.sort_by_key(|&child_id| self.inner[child_id].inner.get_layer());
self.compute_layout(rect);

for &child in children.iter().rev() {
stack.push(child);
}
let order = self.traversal.as_ref().unwrap();

for &id in order {
let node = &self.nodes[id];
node.render(buf);
}
}
}

impl Arena {
fn compute_layout(&mut self, rect: LogicalRect) {
let root = self.root;
self.inner[root].rect = rect;
self.nodes[root].rect = rect;

fn visit(arena: &mut Arena, id: NodeId) {
let node = &arena.inner[id];
let node = &arena.nodes[id];

let rect = node.rect;
let composition = node.inner.composition();
Expand All @@ -91,23 +86,47 @@ impl Arena {
debug_assert_eq!(rects.len(), children.len());

for ((child_id, _), rect) in children.iter().zip(rects) {
arena.inner[*child_id].rect = rect;
arena.nodes[*child_id].rect = rect;
visit(arena, *child_id);
}
}

visit(self, root);
}

fn compute_traversal(&mut self) {
let root = self.root;

let mut order = Vec::with_capacity(self.nodes.len());
let mut stack = vec![root];

while let Some(id) = stack.pop() {
order.push(id);

let mut children = self.nodes[id]
.children
.iter()
.map(|(c, _)| *c)
.collect::<Vec<_>>();

children.sort_by_key(|&child_id| self.nodes[child_id].inner.get_layer());

for &child in children.iter().rev() {
stack.push(child);
}
}

self.traversal = Some(order);
}

fn push(&mut self, node: Node) -> NodeId {
let id = self.inner.insert(ArenaNode {
let id = self.nodes.insert(ArenaNode {
inner: node,
parent: None,
children: Vec::new(),
rect: LogicalRect::new(0, 0, 0, 0),
});

let children = self.inner[id]
let children = self.nodes[id]
.inner
.composition()
.children()
Expand All @@ -121,32 +140,34 @@ impl Arena {

for (child, measure) in children {
let child_id = self.push(child);
self.inner[child_id].parent = Some(id);
self.inner[id].children.push((child_id, measure));
let parent = &mut self.nodes[id];

parent.children.push((child_id, measure));
}

self.traversal = None;

id
}
}

pub(crate) struct ArenaNode {
struct ArenaNode {
inner: Node,
parent: Option<NodeId>,
children: Vec<(NodeId, Measure)>,
rect: LogicalRect,
}

impl ArenaNode {
pub(crate) fn render(&self, buffer: &mut Buffer) {
fn render(&self, buffer: &mut Buffer) {
if let Some(renderer) = &self.inner.get_renderer() {
let mut canvas = Canvas::new(self.rect, buffer);
renderer(&mut canvas);
}
}

pub(crate) fn dispatch(&mut self, msg: &Message, ctx: &mut Context) {
fn dispatch(&mut self, msg: &Message, pass: UpdatePass<'_>) {
if let Some(listeners) = self.inner.get_listeners(msg) {
listeners.dispatch(msg, ctx);
listeners.dispatch(msg, pass);
}
}
}
3 changes: 2 additions & 1 deletion src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ use std::cell::{RefCell, RefMut};
use crate::{
canvas::{Canvas, LogicalRect},
context::EventContext,
events::{Event, Message},
events::Event,
layout::{Flow, Layer, Measure, compute_split},
listeners::{DrawListener, ErasedListenerBucket, ListenerStore},
state::{State, StateOwner},
transport::Message,
};

pub type FactoryFn<P> = fn(Component, P) -> Node;
Expand Down
51 changes: 41 additions & 10 deletions src/context.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,62 @@
use std::ops::Deref;

use crate::events::Event;
use crate::{
canvas::LogicalRect,
events::{Event, MouseEvent},
};

pub struct EventContext<'rt, E: Event> {
event: &'rt E,
context: &'rt mut Context,
pub struct EventContext<'e, E: Event> {
event: &'e E,
pass: UpdatePass<'e>,
}

impl<'rt, E: Event> Deref for EventContext<'rt, E> {
impl<'e, E: Event> Deref for EventContext<'e, E> {
type Target = E;

fn deref(&self) -> &'rt Self::Target {
fn deref(&self) -> &'e Self::Target {
self.event
}
}

impl<'rt, E: Event> EventContext<'rt, E> {
pub(crate) fn new(event: &'rt E, context: &'rt mut Context) -> Self {
Self { event, context }
impl<'e, E: Event> EventContext<'e, E> {
pub(crate) fn new(event: &'e E, pass: UpdatePass<'e>) -> Self {
Self { event, pass }
}

pub fn request_shutdown(&mut self) {
self.context.shutdown_requested = true;
self.pass.context.shutdown_requested = true;
}
}

impl<'e, E: MouseEvent> EventContext<'e, E> {
pub fn is_mouse_hit<F>(&self) -> bool {
let (x, y) = self.coords();
let cursor = LogicalRect::new(x as i32, y as i32, 1, 1);

self.pass.rect.intersects(cursor)
}
}

#[derive(Default)]
pub(crate) struct Context {
pub shutdown_requested: bool,
}

pub(crate) struct UpdatePass<'e> {
context: &'e mut Context,
state: &'e mut UpdateState,
rect: LogicalRect,
}

impl<'e> UpdatePass<'e> {
pub fn new(context: &'e mut Context, state: &'e mut UpdateState, rect: LogicalRect) -> Self {
Self {
context,
state,
rect,
}
}
}

#[derive(Default)]
pub(crate) struct UpdateState {}
Loading