fix gaps in layout

This commit is contained in:
Evan Almloff 2022-12-06 09:08:25 -06:00
parent 6ee4f7df4f
commit 4be64cb9f0
6 changed files with 57 additions and 33 deletions

View file

@ -125,7 +125,7 @@ impl PersistantElementIter {
/// get the next element /// get the next element
pub fn next<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced { pub fn next<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
let r = if self.stack.is_empty() { if self.stack.is_empty() {
let id = NodeId(0); let id = NodeId(0);
let new = (id, NodePosition::AtNode); let new = (id, NodePosition::AtNode);
self.stack.push(new); self.stack.push(new);
@ -156,9 +156,7 @@ impl PersistantElementIter {
ElementProduced::Progressed(self.pop()) ElementProduced::Progressed(self.pop())
} }
} }
}; }
println!("next: {:?}", r);
r
} }
/// get the previous element /// get the previous element

View file

@ -23,7 +23,7 @@ use std::{
use taffy::geometry::{Point, Size}; use taffy::geometry::{Point, Size};
use taffy::{prelude::Layout, Taffy}; use taffy::{prelude::Layout, Taffy};
use crate::FocusState; use crate::{layout_to_screen_space, FocusState};
use crate::{TuiDom, TuiNode}; use crate::{TuiDom, TuiNode};
pub(crate) struct Event { pub(crate) struct Event {
@ -243,7 +243,15 @@ impl InnerInputState {
) { ) {
fn layout_contains_point(layout: &Layout, point: ScreenPoint) -> bool { fn layout_contains_point(layout: &Layout, point: ScreenPoint) -> bool {
let Point { x, y } = layout.location; let Point { x, y } = layout.location;
let (x, y) = (
layout_to_screen_space(x).round(),
layout_to_screen_space(y).round(),
);
let Size { width, height } = layout.size; let Size { width, height } = layout.size;
let (width, height) = (
layout_to_screen_space(width).round(),
layout_to_screen_space(height).round(),
);
let layout_rect = Rect::new(Point2D::new(x, y), Size2D::new(width, height)); let layout_rect = Rect::new(Point2D::new(x, y), Size2D::new(width, height));
layout_rect.contains(point.cast()) layout_rect.contains(point.cast())

View file

@ -7,6 +7,8 @@ use dioxus_native_core::state::ChildDepState;
use dioxus_native_core_macro::sorted_str_slice; use dioxus_native_core_macro::sorted_str_slice;
use taffy::prelude::*; use taffy::prelude::*;
use crate::screen_to_layout_space;
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) enum PossiblyUninitalized<T> { pub(crate) enum PossiblyUninitalized<T> {
Uninitalized, Uninitalized,
@ -66,10 +68,10 @@ impl ChildDepState for TaffyLayout {
style = Style { style = Style {
size: Size { size: Size {
// characters are 1 point tall // characters are 1 point tall
height: Dimension::Points(1.0), height: Dimension::Points(screen_to_layout_space(1)),
// text is as long as it is declared // text is as long as it is declared
width: Dimension::Points(char_len as f32), width: Dimension::Points(screen_to_layout_space(char_len as u16)),
}, },
..Default::default() ..Default::default()
}; };

View file

@ -35,6 +35,15 @@ pub use config::*;
pub use hooks::*; pub use hooks::*;
pub(crate) use node::*; pub(crate) use node::*;
// the layout space has a multiplier of 10 to minimize rounding errors
pub(crate)fn screen_to_layout_space(screen: u16) -> f32{
screen as f32 * 10.0
}
pub(crate)fn layout_to_screen_space(layout: f32) -> f32{
layout / 10.0
}
#[derive(Clone)] #[derive(Clone)]
pub struct TuiContext { pub struct TuiContext {
tx: UnboundedSender<InputEvent>, tx: UnboundedSender<InputEvent>,
@ -149,22 +158,22 @@ fn render_vdom(
if !to_rerender.is_empty() || updated { if !to_rerender.is_empty() || updated {
updated = false; updated = false;
fn resize(dims: Rect, taffy: &mut Taffy, rdom: &TuiDom) { fn resize(dims: Rect, taffy: &mut Taffy, rdom: &TuiDom) {
let width = dims.width; let width = screen_to_layout_space(dims.width );
let height = dims.height; let height = screen_to_layout_space(dims.height);
let root_node = rdom[NodeId(0)].state.layout.node.unwrap(); let root_node = rdom[NodeId(0)].state.layout.node.unwrap();
// the root node fills the entire area // the root node fills the entire area
let mut style=*taffy.style(root_node).unwrap(); let mut style=*taffy.style(root_node).unwrap();
style.size=Size { style.size=Size {
width: Dimension::Points(width as f32), width: Dimension::Points(width ),
height: Dimension::Points(height as f32), height: Dimension::Points(height ),
}; };
taffy.set_style(root_node, style).unwrap(); taffy.set_style(root_node, style).unwrap();
let size =Size { let size =Size {
width: AvailableSpace::Definite(width as f32), width: AvailableSpace::Definite(width),
height: AvailableSpace::Definite(height as f32), height: AvailableSpace::Definite(height),
}; };
taffy taffy
.compute_layout( .compute_layout(
@ -195,8 +204,8 @@ fn render_vdom(
Rect { Rect {
x: 0, x: 0,
y: 0, y: 0,
width: 100, width: 1000,
height: 100, height: 1000,
}, },
&mut taffy.lock().expect("taffy lock poisoned"), &mut taffy.lock().expect("taffy lock poisoned"),
&rdom, &rdom,

View file

@ -11,7 +11,7 @@ use taffy::{
Taffy, Taffy,
}; };
use crate::TuiDom; use crate::{layout_to_screen_space, TuiDom};
/// Allows querying the layout of nodes after rendering. It will only provide a correct value after a node is rendered. /// Allows querying the layout of nodes after rendering. It will only provide a correct value after a node is rendered.
/// Provided as a root context for all tui applictions. /// Provided as a root context for all tui applictions.
@ -72,19 +72,28 @@ impl<'a> ElementRef<'a> {
} }
pub fn size(&self) -> Option<Size<u32>> { pub fn size(&self) -> Option<Size<u32>> {
self.layout().map(|l| l.size.map(|v| v as u32)) self.layout().map(|l| l.size.map(|v| v.round() as u32))
} }
pub fn pos(&self) -> Option<Point<u32>> { pub fn pos(&self) -> Option<Point<u32>> {
self.layout().map(|l| Point { self.layout().map(|l| Point {
x: l.location.x as u32, x: l.location.x.round() as u32,
y: l.location.y as u32, y: l.location.y.round() as u32,
}) })
} }
pub fn layout(&self) -> Option<&Layout> { pub fn layout(&self) -> Option<Layout> {
self.stretch let layout = self
.stretch
.layout(self.inner[self.id].state.layout.node.ok()?) .layout(self.inner[self.id].state.layout.node.ok()?)
.ok() .ok();
layout.map(|layout| Layout {
order: layout.order,
size: layout.size.map(|v| layout_to_screen_space(v)),
location: Point {
x: layout_to_screen_space(layout.location.x),
y: layout_to_screen_space(layout.location.y),
},
})
} }
} }

View file

@ -8,6 +8,7 @@ use taffy::{
use tui::{backend::CrosstermBackend, layout::Rect, style::Color}; use tui::{backend::CrosstermBackend, layout::Rect, style::Color};
use crate::{ use crate::{
layout_to_screen_space,
style::{RinkColor, RinkStyle}, style::{RinkColor, RinkStyle},
style_attributes::{BorderEdge, BorderStyle}, style_attributes::{BorderEdge, BorderStyle},
widget::{RinkBuffer, RinkCell, RinkWidget, WidgetWithContext}, widget::{RinkBuffer, RinkCell, RinkWidget, WidgetWithContext},
@ -36,15 +37,12 @@ pub(crate) fn render_vnode(
location.x += parent_location.x; location.x += parent_location.x;
location.y += parent_location.y; location.y += parent_location.y;
let Point { mut x, mut y } = location; let Point { x: fx, y: fy } = location;
x = x.floor(); let x = layout_to_screen_space(fx).round() as u16;
y = y.floor(); let y = layout_to_screen_space(fy).round() as u16;
let Size { let Size { width, height } = *size;
mut width, let width = layout_to_screen_space(fx + width).round() as u16 + x;
mut height, let height = layout_to_screen_space(fy + height).round() as u16 - y;
} = size;
width = width.ceil();
height = height.ceil();
match &node.node_data.node_type { match &node.node_data.node_type {
NodeType::Text { text } => { NodeType::Text { text } => {
@ -69,7 +67,7 @@ pub(crate) fn render_vnode(
text, text,
style: node.state.style.core, style: node.state.style.core,
}; };
let area = Rect::new(x as u16, y as u16, width as u16, height as u16); let area = Rect::new(x, y, width, height);
// the renderer will panic if a node is rendered out of range even if the size is zero // the renderer will panic if a node is rendered out of range even if the size is zero
if area.width > 0 && area.height > 0 { if area.width > 0 && area.height > 0 {
@ -77,7 +75,7 @@ pub(crate) fn render_vnode(
} }
} }
NodeType::Element { .. } => { NodeType::Element { .. } => {
let area = Rect::new(x as u16, y as u16, width as u16, height as u16); let area = Rect::new(x, y, width, height);
// the renderer will panic if a node is rendered out of range even if the size is zero // the renderer will panic if a node is rendered out of range even if the size is zero
if area.width > 0 && area.height > 0 { if area.width > 0 && area.height > 0 {