mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-07-27 07:34:27 +02:00
tuice tuice tuice tuice
This commit is contained in:
parent
b6b0493333
commit
58f78731b3
@ -236,9 +236,7 @@ impl Application for AppState {
|
|||||||
|
|
||||||
fn view(&mut self) -> Element<'static, Self::Message> {
|
fn view(&mut self) -> Element<'static, Self::Message> {
|
||||||
use crate::tuice::TextTable;
|
use crate::tuice::TextTable;
|
||||||
Element::from(Row::with_children(vec![Element::from(TextTable::new(
|
Row::with_children(vec![Element::from(TextTable::new(vec!["A", "B", "C"]))]).into()
|
||||||
vec!["A", "B", "C"],
|
|
||||||
))]))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy(&mut self) {
|
fn destroy(&mut self) {
|
||||||
|
@ -7,14 +7,14 @@ pub use widget::*;
|
|||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use tui::{layout::Rect, Frame};
|
use tui::{layout::Rect, Frame};
|
||||||
|
|
||||||
use super::{Bounds, Event, LayoutNode, Size, Status};
|
use super::{Bounds, DrawContext, Event, LayoutNode, Size, Status};
|
||||||
|
|
||||||
/// A component displays information and can be interacted with.
|
/// A component displays information and can be interacted with.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
pub trait TmpComponent<Message> {
|
pub trait TmpComponent<Message> {
|
||||||
/// Draws the component.
|
/// Draws the component.
|
||||||
fn draw<Backend>(&mut self, area: Rect, frame: &mut Frame<'_, Backend>)
|
fn draw<Backend>(&mut self, context: DrawContext<'_>, frame: &mut Frame<'_, Backend>)
|
||||||
where
|
where
|
||||||
Backend: tui::backend::Backend;
|
Backend: tui::backend::Backend;
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use crate::tuice::{Event, Status, TmpComponent};
|
use crate::tuice::{DrawContext, Event, Status, TmpComponent};
|
||||||
|
|
||||||
pub struct Block {}
|
pub struct Block {}
|
||||||
|
|
||||||
impl<Message> TmpComponent<Message> for Block {
|
impl<Message> TmpComponent<Message> for Block {
|
||||||
fn draw<B>(&mut self, _area: Rect, _frame: &mut Frame<'_, B>)
|
fn draw<B>(&mut self, _context: DrawContext<'_>, _frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use crate::tuice::{Event, Status, TmpComponent};
|
use crate::tuice::{DrawContext, Event, Status, TmpComponent};
|
||||||
|
|
||||||
pub struct Carousel {}
|
pub struct Carousel {}
|
||||||
|
|
||||||
impl<Message> TmpComponent<Message> for Carousel {
|
impl<Message> TmpComponent<Message> for Carousel {
|
||||||
fn draw<B>(&mut self, _area: Rect, _frame: &mut Frame<'_, B>)
|
fn draw<B>(&mut self, _context: DrawContext<'_>, _frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use crate::tuice::{Event, Status, TmpComponent};
|
use crate::tuice::{DrawContext, Event, Status, TmpComponent};
|
||||||
|
|
||||||
pub struct Column {}
|
pub struct Column {}
|
||||||
|
|
||||||
impl<Message> TmpComponent<Message> for Column {
|
impl<Message> TmpComponent<Message> for Column {
|
||||||
fn draw<B>(&mut self, _area: Rect, _frame: &mut Frame<'_, B>)
|
fn draw<B>(&mut self, _context: DrawContext<'_>, _frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use crate::tuice::{Bounds, Element, Event, LayoutNode, Size, Status, TmpComponent};
|
use crate::tuice::{Bounds, DrawContext, Element, Event, LayoutNode, Size, Status, TmpComponent};
|
||||||
|
|
||||||
/// A [`Container`] just contains a child, as well as being able to be sized.
|
/// A [`Container`] just contains a child, as well as being able to be sized.
|
||||||
///
|
///
|
||||||
@ -38,7 +38,7 @@ impl<'a, Message> Container<'a, Message> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message> TmpComponent<Message> for Container<'a, Message> {
|
impl<'a, Message> TmpComponent<Message> for Container<'a, Message> {
|
||||||
fn draw<B>(&mut self, area: Rect, _frame: &mut Frame<'_, B>)
|
fn draw<B>(&mut self, context: DrawContext<'_>, _frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use crate::tuice::{Bounds, Element, Event, LayoutNode, Size, Status, TmpComponent};
|
use crate::tuice::{Bounds, DrawContext, Element, Event, LayoutNode, Size, Status, TmpComponent};
|
||||||
|
|
||||||
pub struct FlexElement<'a, Message> {
|
pub struct FlexElement<'a, Message> {
|
||||||
/// Represents a ratio with other [`FlexElement`]s on how far to expand.
|
/// Represents a ratio with other [`FlexElement`]s on how far to expand.
|
||||||
@ -35,11 +35,11 @@ impl<'a, Message> FlexElement<'a, Message> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn draw<B>(&mut self, area: Rect, frame: &mut Frame<'_, B>)
|
pub(crate) fn draw<B>(&mut self, context: DrawContext<'_>, frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
self.element.draw(area, frame)
|
self.element.draw(context, frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn on_event(
|
pub(crate) fn on_event(
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
|
use itertools::izip;
|
||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use crate::tuice::{Bounds, Event, FlexElement, LayoutNode, Size, Status, TmpComponent};
|
use crate::tuice::{
|
||||||
|
Bounds, DrawContext, Element, Event, FlexElement, LayoutNode, Size, Status, TmpComponent,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Row<'a, Message> {
|
pub struct Row<'a, Message> {
|
||||||
@ -18,23 +21,35 @@ impl<'a, Message> Row<'a, Message> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_child(mut self) -> Self {
|
pub fn with_child<E>(mut self, child: E) -> Self
|
||||||
|
where
|
||||||
|
E: Into<Element<'a, Message>>,
|
||||||
|
{
|
||||||
|
self.children.push(FlexElement::with_no_flex(child.into()));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_flex_child(mut self) -> Self {
|
pub fn with_flex_child<E>(mut self, child: E, flex: u16) -> Self
|
||||||
|
where
|
||||||
|
E: Into<Element<'a, Message>>,
|
||||||
|
{
|
||||||
|
self.children
|
||||||
|
.push(FlexElement::with_flex(child.into(), flex));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message> TmpComponent<Message> for Row<'a, Message> {
|
impl<'a, Message> TmpComponent<Message> for Row<'a, Message> {
|
||||||
fn draw<B>(&mut self, area: Rect, frame: &mut Frame<'_, B>)
|
fn draw<B>(&mut self, context: DrawContext<'_>, frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
self.children.iter_mut().for_each(|child| {
|
self.children
|
||||||
child.draw(area, frame);
|
.iter_mut()
|
||||||
})
|
.zip(context.children())
|
||||||
|
.for_each(|(child, child_node)| {
|
||||||
|
child.draw(child_node, frame);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_event(&mut self, _area: Rect, _event: Event, _messages: &mut Vec<Message>) -> Status {
|
fn on_event(&mut self, _area: Rect, _event: Event, _messages: &mut Vec<Message>) -> Status {
|
||||||
@ -43,17 +58,75 @@ impl<'a, Message> TmpComponent<Message> for Row<'a, Message> {
|
|||||||
|
|
||||||
fn layout(&self, bounds: Bounds, node: &mut LayoutNode) -> Size {
|
fn layout(&self, bounds: Bounds, node: &mut LayoutNode) -> Size {
|
||||||
let mut remaining_bounds = bounds;
|
let mut remaining_bounds = bounds;
|
||||||
|
let mut children = vec![LayoutNode::default(); self.children.len()];
|
||||||
|
let mut inflexible_children_indexes = vec![];
|
||||||
|
let mut offsets = vec![];
|
||||||
|
let mut current_x = 0;
|
||||||
|
let mut current_y = 0;
|
||||||
|
let mut sizes = Vec::with_capacity(self.children.len());
|
||||||
|
let mut current_size = Size::default();
|
||||||
|
|
||||||
let child_nodes: Vec<LayoutNode> = self
|
let mut get_child_size = |child: &FlexElement<'_, Message>,
|
||||||
.children
|
child_node: &mut LayoutNode,
|
||||||
|
remaining_bounds: &mut Bounds| {
|
||||||
|
let size = child.layout(*remaining_bounds, child_node);
|
||||||
|
current_size += size;
|
||||||
|
remaining_bounds.shrink_size(size);
|
||||||
|
offsets.push((current_x, current_y));
|
||||||
|
current_x += size.width;
|
||||||
|
current_y += size.height;
|
||||||
|
|
||||||
|
size
|
||||||
|
};
|
||||||
|
|
||||||
|
// We handle inflexible children first, then distribute all remaining
|
||||||
|
// space to flexible children.
|
||||||
|
self.children
|
||||||
.iter()
|
.iter()
|
||||||
.map(|child| {
|
.zip(children.iter_mut())
|
||||||
let mut child_node = LayoutNode::default();
|
.enumerate()
|
||||||
let size = child.layout(remaining_bounds, &mut child_node);
|
.for_each(|(index, (child, child_node))| {
|
||||||
child_node
|
if child.flex == 0 && remaining_bounds.has_space() {
|
||||||
})
|
let size = get_child_size(child, child_node, &mut remaining_bounds);
|
||||||
.collect();
|
sizes.push(size);
|
||||||
|
} else {
|
||||||
|
inflexible_children_indexes.push(index);
|
||||||
|
sizes.push(Size::default());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
todo!()
|
inflexible_children_indexes.into_iter().for_each(|index| {
|
||||||
|
// The index accesses are safe by above definitions, so we can use unsafe operations.
|
||||||
|
// If you EVER make changes to above, ensure this invariant still holds!
|
||||||
|
let child = unsafe { self.children.get_unchecked(index) };
|
||||||
|
let child_node = unsafe { children.get_unchecked_mut(index) };
|
||||||
|
let size = unsafe { sizes.get_unchecked_mut(index) };
|
||||||
|
|
||||||
|
*size = get_child_size(child, child_node, &mut remaining_bounds);
|
||||||
|
});
|
||||||
|
|
||||||
|
// If there is still remaining space after, distribute the rest if
|
||||||
|
// appropriate (e.x. current_size is too small for the bounds).
|
||||||
|
if current_size.width < bounds.min_width {
|
||||||
|
// For now, we'll cheat and just set it to be equal.
|
||||||
|
current_size.width = bounds.min_width;
|
||||||
|
}
|
||||||
|
if current_size.height < bounds.min_height {
|
||||||
|
// For now, we'll cheat and just set it to be equal.
|
||||||
|
current_size.height = bounds.min_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we're done determining sizes, convert all children into the appropriate
|
||||||
|
// layout nodes. Remember - parents determine children, and so, we determine
|
||||||
|
// children here!
|
||||||
|
izip!(sizes, offsets, children.iter_mut()).for_each(
|
||||||
|
|(size, offset, child): (Size, (u16, u16), &mut LayoutNode)| {
|
||||||
|
let rect = Rect::new(offset.0, offset.1, size.width, size.height);
|
||||||
|
child.rect = rect;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
node.children = children;
|
||||||
|
|
||||||
|
current_size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use crate::tuice::{Event, Status, TmpComponent};
|
use crate::tuice::{DrawContext, Event, Status, TmpComponent};
|
||||||
|
|
||||||
/// A [`Component`] to handle keyboard shortcuts and assign actions to them.
|
/// A [`Component`] to handle keyboard shortcuts and assign actions to them.
|
||||||
///
|
///
|
||||||
@ -8,7 +8,7 @@ use crate::tuice::{Event, Status, TmpComponent};
|
|||||||
pub struct Shortcut {}
|
pub struct Shortcut {}
|
||||||
|
|
||||||
impl<Message> TmpComponent<Message> for Shortcut {
|
impl<Message> TmpComponent<Message> for Shortcut {
|
||||||
fn draw<B>(&mut self, _area: Rect, _frame: &mut Frame<'_, B>)
|
fn draw<B>(&mut self, _context: DrawContext<'_>, _frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
|
@ -14,7 +14,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::TABLE_GAP_HEIGHT_LIMIT,
|
constants::TABLE_GAP_HEIGHT_LIMIT,
|
||||||
tuice::{Event, Status, TmpComponent},
|
tuice::{DrawContext, Event, Status, TmpComponent},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::table_column::{TextColumn, TextColumnConstraint};
|
pub use self::table_column::{TextColumn, TextColumnConstraint};
|
||||||
@ -166,12 +166,14 @@ impl<'a, Message> TextTable<'a, Message> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message> TmpComponent<Message> for TextTable<'a, Message> {
|
impl<'a, Message> TmpComponent<Message> for TextTable<'a, Message> {
|
||||||
fn draw<B>(&mut self, area: Rect, frame: &mut Frame<'_, B>)
|
fn draw<B>(&mut self, context: DrawContext<'_>, frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
|
let rect = context.rect();
|
||||||
|
|
||||||
self.table_gap = if !self.show_gap
|
self.table_gap = if !self.show_gap
|
||||||
|| (self.rows.len() + 2 > area.height.into() && area.height < TABLE_GAP_HEIGHT_LIMIT)
|
|| (self.rows.len() + 2 > rect.height.into() && rect.height < TABLE_GAP_HEIGHT_LIMIT)
|
||||||
{
|
{
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
@ -179,8 +181,8 @@ impl<'a, Message> TmpComponent<Message> for TextTable<'a, Message> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let table_extras = 1 + self.table_gap;
|
let table_extras = 1 + self.table_gap;
|
||||||
let scrollable_height = area.height.saturating_sub(table_extras);
|
let scrollable_height = rect.height.saturating_sub(table_extras);
|
||||||
self.update_column_widths(area);
|
self.update_column_widths(rect);
|
||||||
|
|
||||||
// Calculate widths first, since we need them later.
|
// Calculate widths first, since we need them later.
|
||||||
let widths = self
|
let widths = self
|
||||||
@ -195,7 +197,7 @@ impl<'a, Message> TmpComponent<Message> for TextTable<'a, Message> {
|
|||||||
// Note: `get_list_start` already ensures `start` is within the bounds of the number of items, so no need to check!
|
// Note: `get_list_start` already ensures `start` is within the bounds of the number of items, so no need to check!
|
||||||
let start = self
|
let start = self
|
||||||
.state
|
.state
|
||||||
.display_start_index(area, scrollable_height as usize);
|
.display_start_index(rect, scrollable_height as usize);
|
||||||
let end = min(self.state.num_items(), start + scrollable_height as usize);
|
let end = min(self.state.num_items(), start + scrollable_height as usize);
|
||||||
|
|
||||||
self.rows[start..end].to_vec()
|
self.rows[start..end].to_vec()
|
||||||
@ -214,7 +216,7 @@ impl<'a, Message> TmpComponent<Message> for TextTable<'a, Message> {
|
|||||||
table = table.highlight_style(self.style_sheet.selected_text);
|
table = table.highlight_style(self.style_sheet.selected_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.render_stateful_widget(table.widths(&widths), area, self.state.tui_state());
|
frame.render_stateful_widget(table.widths(&widths), rect, self.state.tui_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_event(&mut self, area: Rect, event: Event, messages: &mut Vec<Message>) -> Status {
|
fn on_event(&mut self, area: Rect, event: Event, messages: &mut Vec<Message>) -> Status {
|
||||||
|
31
src/tuice/context.rs
Normal file
31
src/tuice/context.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use tui::layout::Rect;
|
||||||
|
|
||||||
|
use super::LayoutNode;
|
||||||
|
|
||||||
|
pub struct DrawContext<'a> {
|
||||||
|
current_node: &'a LayoutNode,
|
||||||
|
current_offset: (u16, u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DrawContext<'_> {
|
||||||
|
pub(crate) fn new() {}
|
||||||
|
|
||||||
|
pub(crate) fn rect(&self) -> Rect {
|
||||||
|
self.current_node.rect
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn children(&self) -> impl Iterator<Item = DrawContext<'_>> {
|
||||||
|
let new_offset = (
|
||||||
|
self.current_offset.0 + self.current_node.rect.x,
|
||||||
|
self.current_offset.1 + self.current_node.rect.y,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.current_node
|
||||||
|
.children
|
||||||
|
.iter()
|
||||||
|
.map(move |layout_node| DrawContext {
|
||||||
|
current_node: layout_node,
|
||||||
|
current_offset: new_offset,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,8 @@ use enum_dispatch::enum_dispatch;
|
|||||||
use tui::{layout::Rect, Frame};
|
use tui::{layout::Rect, Frame};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Block, Bounds, Carousel, Column, Container, Event, LayoutNode, Row, Shortcut, Size, Status,
|
Block, Bounds, Carousel, Column, Container, DrawContext, Event, LayoutNode, Row, Shortcut,
|
||||||
TextTable, TmpComponent,
|
Size, Status, TextTable, TmpComponent,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An [`Element`] is an instantiated [`Component`].
|
/// An [`Element`] is an instantiated [`Component`].
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use crate::tuice::Size;
|
||||||
|
|
||||||
/// [`Bounds`] represent minimal and maximal widths/height constraints while laying things out.
|
/// [`Bounds`] represent minimal and maximal widths/height constraints while laying things out.
|
||||||
///
|
///
|
||||||
/// These are sent from a parent component to a child to determine the [`Size`](super::Size)
|
/// These are sent from a parent component to a child to determine the [`Size`](super::Size)
|
||||||
@ -18,12 +20,23 @@ pub struct Bounds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Bounds {
|
impl Bounds {
|
||||||
pub fn with_two_bounds(width: u16, height: u16) -> Self {
|
/// Shrinks the current bounds by some amount.
|
||||||
Self {
|
pub fn shrink(&mut self, width: u16, height: u16) {
|
||||||
min_width: width,
|
self.max_width = self.max_width.saturating_sub(width);
|
||||||
min_height: height,
|
self.max_height = self.max_height.saturating_sub(height);
|
||||||
max_width: width,
|
}
|
||||||
max_height: height,
|
|
||||||
}
|
/// Shrinks by a given [`Size`].
|
||||||
|
pub fn shrink_size(&mut self, size: Size) {
|
||||||
|
self.max_width = self.max_width.saturating_sub(size.width);
|
||||||
|
self.max_height = self.max_height.saturating_sub(size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether there is any space left in this bound for laying out things.
|
||||||
|
pub fn has_space(&self) -> bool {
|
||||||
|
self.min_width > self.max_width
|
||||||
|
|| self.min_height > self.max_height
|
||||||
|
|| self.max_width == 0
|
||||||
|
|| self.max_height == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use tui::layout::Rect;
|
|||||||
use crate::tuice::{Bounds, Element, LayoutNode, TmpComponent};
|
use crate::tuice::{Bounds, Element, LayoutNode, TmpComponent};
|
||||||
|
|
||||||
pub fn build_layout_tree<Message>(area: Rect, root: &Element<'_, Message>) -> LayoutNode {
|
pub fn build_layout_tree<Message>(area: Rect, root: &Element<'_, Message>) -> LayoutNode {
|
||||||
let mut root_layout_node = LayoutNode::from_area(area);
|
let mut root_layout_node = LayoutNode::from_rect(area);
|
||||||
let bounds = Bounds {
|
let bounds = Bounds {
|
||||||
min_width: 0,
|
min_width: 0,
|
||||||
min_height: 0,
|
min_height: 0,
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
use tui::layout::Rect;
|
use tui::layout::Rect;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct LayoutNode {
|
pub struct LayoutNode {
|
||||||
pub area: Rect,
|
pub rect: Rect,
|
||||||
pub children: Vec<LayoutNode>,
|
pub children: Vec<LayoutNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutNode {
|
impl LayoutNode {
|
||||||
pub fn from_area(area: Rect) -> Self {
|
pub fn from_rect(rect: Rect) -> Self {
|
||||||
Self {
|
Self {
|
||||||
area,
|
rect,
|
||||||
children: vec![],
|
children: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,34 @@
|
|||||||
|
use std::ops::{Add, AddAssign};
|
||||||
|
|
||||||
/// A [`Size`] represents calculated widths and heights for a component.
|
/// A [`Size`] represents calculated widths and heights for a component.
|
||||||
///
|
///
|
||||||
/// A [`Size`] is sent from a child component back up to its parents after
|
/// A [`Size`] is sent from a child component back up to its parents after
|
||||||
/// first being given a [`Bounds`](super::Bounds) from the parent.
|
/// first being given a [`Bounds`](super::Bounds) from the parent.
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
pub struct Size {
|
pub struct Size {
|
||||||
/// The given width.
|
/// The width that the component has determined.
|
||||||
pub width: u16,
|
pub width: u16,
|
||||||
|
|
||||||
/// The given height.
|
/// The height that the component has determined.
|
||||||
pub height: u16,
|
pub height: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Add for Size {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
width: self.width + rhs.width,
|
||||||
|
height: self.height + rhs.height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for Size {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
*self = Self {
|
||||||
|
width: self.width + rhs.width,
|
||||||
|
height: self.height + rhs.height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -17,3 +17,6 @@ pub use layout::*;
|
|||||||
|
|
||||||
pub mod element;
|
pub mod element;
|
||||||
pub use element::*;
|
pub use element::*;
|
||||||
|
|
||||||
|
pub mod context;
|
||||||
|
pub use context::*;
|
||||||
|
@ -24,8 +24,8 @@ pub(crate) fn launch<A: Application + 'static>(
|
|||||||
RuntimeEvent::UserInterface(event) => {
|
RuntimeEvent::UserInterface(event) => {
|
||||||
let mut messages = vec![];
|
let mut messages = vec![];
|
||||||
|
|
||||||
let bounds = Rect::default(); // TODO: TEMP
|
let rect = Rect::default(); // FIXME: TEMP
|
||||||
match user_interface.on_event(bounds, event, &mut messages) {
|
match user_interface.on_event(rect, event, &mut messages) {
|
||||||
Status::Captured => {}
|
Status::Captured => {}
|
||||||
Status::Ignored => {
|
Status::Ignored => {
|
||||||
application.global_event_handler(event, &mut messages);
|
application.global_event_handler(event, &mut messages);
|
||||||
@ -38,6 +38,7 @@ pub(crate) fn launch<A: Application + 'static>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
user_interface = application.view();
|
user_interface = application.view();
|
||||||
|
// FIXME: Draw!
|
||||||
}
|
}
|
||||||
RuntimeEvent::Custom(message) => {
|
RuntimeEvent::Custom(message) => {
|
||||||
application.update(message);
|
application.update(message);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user