mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-07-27 07:34:27 +02:00
Enum dispatch time
This commit is contained in:
parent
65a1ee5202
commit
b6b0493333
11
src/app.rs
11
src/app.rs
@ -29,7 +29,7 @@ use frozen_state::FrozenState;
|
|||||||
use crate::{
|
use crate::{
|
||||||
canvas::Painter,
|
canvas::Painter,
|
||||||
constants,
|
constants,
|
||||||
tuice::{Application, Row},
|
tuice::{Application, Element, Row},
|
||||||
units::data_units::DataUnit,
|
units::data_units::DataUnit,
|
||||||
Pid,
|
Pid,
|
||||||
};
|
};
|
||||||
@ -234,12 +234,11 @@ impl Application for AppState {
|
|||||||
self.terminator.load(SeqCst)
|
self.terminator.load(SeqCst)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(
|
fn view(&mut self) -> Element<'static, Self::Message> {
|
||||||
&mut self,
|
use crate::tuice::TextTable;
|
||||||
) -> Box<dyn crate::tuice::Component<Self::Message, crate::tuice::CrosstermBackend>> {
|
Element::from(Row::with_children(vec![Element::from(TextTable::new(
|
||||||
Box::new(Row::with_children(vec![crate::tuice::TextTable::new(
|
|
||||||
vec!["A", "B", "C"],
|
vec!["A", "B", "C"],
|
||||||
)]))
|
))]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy(&mut self) {
|
fn destroy(&mut self) {
|
||||||
|
@ -2,7 +2,7 @@ use std::{fmt::Debug, sync::mpsc::Receiver};
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
runtime::{self, RuntimeEvent},
|
runtime::{self, RuntimeEvent},
|
||||||
Component, Event,
|
Element, Event,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An alias to the [`tui::backend::CrosstermBackend`] writing to [`std::io::Stdout`].
|
/// An alias to the [`tui::backend::CrosstermBackend`] writing to [`std::io::Stdout`].
|
||||||
@ -19,7 +19,7 @@ pub trait Application: Sized {
|
|||||||
/// always returning false.
|
/// always returning false.
|
||||||
fn is_terminated(&self) -> bool;
|
fn is_terminated(&self) -> bool;
|
||||||
|
|
||||||
fn view(&mut self) -> Box<dyn Component<Self::Message, CrosstermBackend>>;
|
fn view(&mut self) -> Element<'static, Self::Message>;
|
||||||
|
|
||||||
/// To run upon stopping the application.
|
/// To run upon stopping the application.
|
||||||
fn destroy(&mut self) {}
|
fn destroy(&mut self) {}
|
||||||
|
@ -4,18 +4,19 @@ pub use base::*;
|
|||||||
pub mod widget;
|
pub mod widget;
|
||||||
pub use widget::*;
|
pub use widget::*;
|
||||||
|
|
||||||
|
use enum_dispatch::enum_dispatch;
|
||||||
use tui::{layout::Rect, Frame};
|
use tui::{layout::Rect, Frame};
|
||||||
|
|
||||||
use super::{Bounds, DrawContext, Event, LayoutNode, Size, Status};
|
use super::{Bounds, 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)]
|
||||||
pub trait Component<Message, Backend>
|
#[enum_dispatch]
|
||||||
where
|
pub trait TmpComponent<Message> {
|
||||||
Backend: tui::backend::Backend,
|
|
||||||
{
|
|
||||||
/// Draws the component.
|
/// Draws the component.
|
||||||
fn draw(&mut self, area: Rect, context: &DrawContext, frame: &mut Frame<'_, Backend>);
|
fn draw<Backend>(&mut self, area: Rect, frame: &mut Frame<'_, Backend>)
|
||||||
|
where
|
||||||
|
Backend: tui::backend::Backend;
|
||||||
|
|
||||||
/// How a component should react to an [`Event`].
|
/// How a component should react to an [`Event`].
|
||||||
///
|
///
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use crate::tuice::{Component, DrawContext, Event, Status};
|
use crate::tuice::{Event, Status, TmpComponent};
|
||||||
|
|
||||||
pub struct Block {}
|
pub struct Block {}
|
||||||
|
|
||||||
impl<Message, B> Component<Message, B> for Block
|
impl<Message> TmpComponent<Message> for Block {
|
||||||
|
fn draw<B>(&mut self, _area: Rect, _frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
fn draw(&mut self, _area: Rect, _context: &DrawContext, _frame: &mut Frame<'_, B>) {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use crate::tuice::{Component, DrawContext, Event, Status};
|
use crate::tuice::{Event, Status, TmpComponent};
|
||||||
|
|
||||||
pub struct Carousel {}
|
pub struct Carousel {}
|
||||||
|
|
||||||
impl<Message, B> Component<Message, B> for Carousel
|
impl<Message> TmpComponent<Message> for Carousel {
|
||||||
|
fn draw<B>(&mut self, _area: Rect, _frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
fn draw(&mut self, _area: Rect, _context: &DrawContext, _frame: &mut Frame<'_, B>) {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use crate::tuice::{Component, DrawContext, Event, Status};
|
use crate::tuice::{Event, Status, TmpComponent};
|
||||||
|
|
||||||
pub struct Column {}
|
pub struct Column {}
|
||||||
|
|
||||||
impl<Message, B> Component<Message, B> for Column
|
impl<Message> TmpComponent<Message> for Column {
|
||||||
|
fn draw<B>(&mut self, _area: Rect, _frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
fn draw(&mut self, _area: Rect, _context: &DrawContext, _frame: &mut Frame<'_, B>) {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,34 +1,47 @@
|
|||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use crate::tuice::{Bounds, Component, DrawContext, Event, Length, Size, Status, LayoutNode};
|
use crate::tuice::{Bounds, Element, Event, LayoutNode, Size, Status, TmpComponent};
|
||||||
|
|
||||||
pub struct Container<'a, Message, B>
|
/// A [`Container`] just contains a child, as well as being able to be sized.
|
||||||
where
|
///
|
||||||
B: Backend,
|
/// Inspired by Flutter's [Container class](https://api.flutter.dev/flutter/widgets/Container-class.html).
|
||||||
{
|
#[derive(Default)]
|
||||||
width: Length,
|
pub struct Container<'a, Message> {
|
||||||
height: Length,
|
width: Option<u16>,
|
||||||
child: Box<dyn Component<Message, B> + 'a>,
|
height: Option<u16>,
|
||||||
|
child: Option<Box<Element<'a, Message>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, B> Container<'a, Message, B>
|
impl<'a, Message> Container<'a, Message> {
|
||||||
where
|
pub fn with_child(child: Element<'a, Message>) -> Self {
|
||||||
B: Backend,
|
|
||||||
{
|
|
||||||
pub fn new(child: Box<dyn Component<Message, B> + 'a>) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
width: Length::Flex,
|
width: None,
|
||||||
height: Length::Flex,
|
height: None,
|
||||||
child,
|
child: Some(child.into()),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, B> Component<Message, B> for Container<'a, Message, B>
|
pub fn child(mut self, child: Option<Element<'a, Message>>) -> Self {
|
||||||
|
self.child = child.map(|c| c.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn width(mut self, width: Option<u16>) -> Self {
|
||||||
|
self.width = width;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(mut self, height: Option<u16>) -> Self {
|
||||||
|
self.height = height;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message> TmpComponent<Message> for Container<'a, Message> {
|
||||||
|
fn draw<B>(&mut self, area: Rect, _frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
fn draw(&mut self, area: Rect, _context: &DrawContext, _frame: &mut Frame<'_, B>) {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,30 +50,39 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn layout(&self, bounds: Bounds, node: &mut LayoutNode) -> Size {
|
fn layout(&self, bounds: Bounds, node: &mut LayoutNode) -> Size {
|
||||||
let width = match self.width {
|
let (width, height) = if let Some(child) = &self.child {
|
||||||
Length::Flex => {
|
let mut child_node = LayoutNode::default();
|
||||||
todo!()
|
|
||||||
|
fn bounds_if_exist(val: Option<u16>, min_bound: u16, max_bound: u16) -> (u16, u16) {
|
||||||
|
if let Some(val) = val {
|
||||||
|
let val = val.clamp(min_bound, max_bound);
|
||||||
|
(val, val)
|
||||||
|
} else {
|
||||||
|
(min_bound, max_bound)
|
||||||
}
|
}
|
||||||
Length::FlexRatio(ratio) => {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
Length::Fixed(length) => length.clamp(bounds.min_width, bounds.max_width),
|
|
||||||
Length::Child => {
|
let child_bounds = {
|
||||||
todo!()
|
let (min_width, max_width) =
|
||||||
|
bounds_if_exist(self.width, bounds.min_width, bounds.max_width);
|
||||||
|
let (min_height, max_height) =
|
||||||
|
bounds_if_exist(self.height, bounds.min_height, bounds.max_height);
|
||||||
|
|
||||||
|
Bounds {
|
||||||
|
min_width,
|
||||||
|
min_height,
|
||||||
|
max_width,
|
||||||
|
max_height,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let height = match self.height {
|
let child_size = child.layout(child_bounds, &mut child_node);
|
||||||
Length::Flex => {
|
|
||||||
todo!()
|
// Note that this is implicitly bounded by our above calculations,
|
||||||
}
|
// no need to recheck if it's valid!
|
||||||
Length::FlexRatio(ratio) => {
|
(child_size.width, child_size.height)
|
||||||
todo!()
|
} else {
|
||||||
}
|
(bounds.min_width, bounds.min_height)
|
||||||
Length::Fixed(length) => length.clamp(bounds.min_height, bounds.max_height),
|
|
||||||
Length::Child => {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Size { height, width }
|
Size { height, width }
|
||||||
|
60
src/tuice/component/base/flex.rs
Normal file
60
src/tuice/component/base/flex.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
|
use crate::tuice::{Bounds, Element, Event, LayoutNode, Size, Status, TmpComponent};
|
||||||
|
|
||||||
|
pub struct FlexElement<'a, Message> {
|
||||||
|
/// Represents a ratio with other [`FlexElement`]s on how far to expand.
|
||||||
|
pub flex: u16,
|
||||||
|
element: Element<'a, Message>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message> FlexElement<'a, Message> {
|
||||||
|
pub fn new<I: Into<Element<'a, Message>>>(element: I) -> Self {
|
||||||
|
Self {
|
||||||
|
flex: 1,
|
||||||
|
element: element.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_flex<I: Into<Element<'a, Message>>>(element: I, flex: u16) -> Self {
|
||||||
|
Self {
|
||||||
|
flex,
|
||||||
|
element: element.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_no_flex<I: Into<Element<'a, Message>>>(element: I) -> Self {
|
||||||
|
Self {
|
||||||
|
flex: 0,
|
||||||
|
element: element.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flex(mut self, flex: u16) -> Self {
|
||||||
|
self.flex = flex;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn draw<B>(&mut self, area: Rect, frame: &mut Frame<'_, B>)
|
||||||
|
where
|
||||||
|
B: Backend,
|
||||||
|
{
|
||||||
|
self.element.draw(area, frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn on_event(
|
||||||
|
&mut self, area: Rect, event: Event, messages: &mut Vec<Message>,
|
||||||
|
) -> Status {
|
||||||
|
self.element.on_event(area, event, messages)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn layout(&self, bounds: Bounds, node: &mut LayoutNode) -> Size {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message> From<Element<'a, Message>> for FlexElement<'a, Message> {
|
||||||
|
fn from(element: Element<'a, Message>) -> Self {
|
||||||
|
Self { flex: 0, element }
|
||||||
|
}
|
||||||
|
}
|
@ -16,8 +16,8 @@ pub use block::Block;
|
|||||||
pub mod carousel;
|
pub mod carousel;
|
||||||
pub use carousel::Carousel;
|
pub use carousel::Carousel;
|
||||||
|
|
||||||
pub mod sized_box;
|
|
||||||
pub use sized_box::SizedBox;
|
|
||||||
|
|
||||||
pub mod container;
|
pub mod container;
|
||||||
pub use container::Container;
|
pub use container::Container;
|
||||||
|
|
||||||
|
pub mod flex;
|
||||||
|
pub use flex::*;
|
||||||
|
@ -1,42 +1,59 @@
|
|||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use crate::tuice::{Bounds, Component, DrawContext, Event, Size, Status};
|
use crate::tuice::{Bounds, Event, FlexElement, LayoutNode, Size, Status, TmpComponent};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Row<'a, Message, B>
|
pub struct Row<'a, Message> {
|
||||||
where
|
children: Vec<FlexElement<'a, Message>>,
|
||||||
B: Backend,
|
|
||||||
{
|
|
||||||
children: Vec<Box<dyn Component<Message, B> + 'a>>, // FIXME: For performance purposes, let's cheat and use enum-dispatch
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, B> Row<'a, Message, B>
|
impl<'a, Message> Row<'a, Message> {
|
||||||
where
|
|
||||||
B: Backend,
|
|
||||||
{
|
|
||||||
/// Creates a new [`Row`] with the given children.
|
/// Creates a new [`Row`] with the given children.
|
||||||
pub fn with_children<C>(children: Vec<C>) -> Self
|
pub fn with_children<C>(children: Vec<C>) -> Self
|
||||||
where
|
where
|
||||||
C: Into<Box<dyn Component<Message, B> + 'a>>,
|
C: Into<FlexElement<'a, Message>>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
children: children.into_iter().map(Into::into).collect(),
|
children: children.into_iter().map(Into::into).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_child(mut self) -> Self {
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, B> Component<Message, B> for Row<'a, Message, B>
|
pub fn with_flex_child(mut self) -> Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message> TmpComponent<Message> for Row<'a, Message> {
|
||||||
|
fn draw<B>(&mut self, area: Rect, frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
fn draw(&mut self, area: Rect, context: &DrawContext, frame: &mut Frame<'_, B>) {
|
|
||||||
self.children.iter_mut().for_each(|child| {
|
self.children.iter_mut().for_each(|child| {
|
||||||
// TODO: This is just temp! We need layout!
|
child.draw(area, frame);
|
||||||
child.draw(area, context, 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 {
|
||||||
Status::Ignored
|
Status::Ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn layout(&self, bounds: Bounds, node: &mut LayoutNode) -> Size {
|
||||||
|
let mut remaining_bounds = bounds;
|
||||||
|
|
||||||
|
let child_nodes: Vec<LayoutNode> = self
|
||||||
|
.children
|
||||||
|
.iter()
|
||||||
|
.map(|child| {
|
||||||
|
let mut child_node = LayoutNode::default();
|
||||||
|
let size = child.layout(remaining_bounds, &mut child_node);
|
||||||
|
child_node
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
use crate::tuice::{Component, DrawContext, Event, Status};
|
use crate::tuice::{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.
|
||||||
///
|
///
|
||||||
/// Inspired by [Flutter's approach](https://docs.flutter.dev/development/ui/advanced/actions_and_shortcuts).
|
/// Inspired by [Flutter's approach](https://docs.flutter.dev/development/ui/advanced/actions_and_shortcuts).
|
||||||
pub struct Shortcut {}
|
pub struct Shortcut {}
|
||||||
|
|
||||||
impl<Message, B> Component<Message, B> for Shortcut
|
impl<Message> TmpComponent<Message> for Shortcut {
|
||||||
|
fn draw<B>(&mut self, _area: Rect, _frame: &mut Frame<'_, B>)
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
fn draw(&mut self, _area: Rect, _context: &DrawContext, _frame: &mut Frame<'_, B>) {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
use tui::backend::Backend;
|
|
||||||
|
|
||||||
use crate::tuice::{Component, Length};
|
|
||||||
|
|
||||||
pub struct SizedBox<'a, Message, B>
|
|
||||||
where
|
|
||||||
B: Backend,
|
|
||||||
{
|
|
||||||
width: Length,
|
|
||||||
height: Length,
|
|
||||||
child: Box<dyn Component<Message, B> + 'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Message, B> SizedBox<'a, Message, B>
|
|
||||||
where
|
|
||||||
B: Backend,
|
|
||||||
{
|
|
||||||
/// Creates a new [`SizedBox`] for a child component
|
|
||||||
/// with a [`Length::Flex`] width and height.
|
|
||||||
pub fn new(child: Box<dyn Component<Message, B> + 'a>) -> Self {
|
|
||||||
Self {
|
|
||||||
width: Length::Flex,
|
|
||||||
height: Length::Flex,
|
|
||||||
child,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new [`SizedBox`] for a child component
|
|
||||||
/// with a [`Length::Flex`] height.
|
|
||||||
pub fn with_width(child: Box<dyn Component<Message, B> + 'a>, width: Length) -> Self {
|
|
||||||
Self {
|
|
||||||
width,
|
|
||||||
height: Length::Flex,
|
|
||||||
child,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new [`SizedBox`] for a child component
|
|
||||||
/// with a [`Length::Flex`] width.
|
|
||||||
pub fn with_height(child: Box<dyn Component<Message, B> + 'a>, height: Length) -> Self {
|
|
||||||
Self {
|
|
||||||
width: Length::Flex,
|
|
||||||
height,
|
|
||||||
child,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the width of the [`SizedBox`].
|
|
||||||
pub fn width(mut self, width: Length) -> Self {
|
|
||||||
self.width = width;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the height of the [`SizedBox`].
|
|
||||||
pub fn height(mut self, height: Length) -> Self {
|
|
||||||
self.height = height;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,7 +14,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::TABLE_GAP_HEIGHT_LIMIT,
|
constants::TABLE_GAP_HEIGHT_LIMIT,
|
||||||
tuice::{Component, DrawContext, Event, Status},
|
tuice::{Event, Status, TmpComponent},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::table_column::{TextColumn, TextColumnConstraint};
|
pub use self::table_column::{TextColumn, TextColumnConstraint};
|
||||||
@ -165,21 +165,11 @@ impl<'a, Message> TextTable<'a, Message> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, B> From<TextTable<'a, Message>> for Box<dyn Component<Message, B> + 'a>
|
impl<'a, Message> TmpComponent<Message> for TextTable<'a, Message> {
|
||||||
where
|
fn draw<B>(&mut self, area: Rect, frame: &mut Frame<'_, B>)
|
||||||
Message: 'a,
|
|
||||||
B: Backend,
|
|
||||||
{
|
|
||||||
fn from(table: TextTable<'a, Message>) -> Self {
|
|
||||||
Box::new(table)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Message, B> Component<Message, B> for TextTable<'a, Message>
|
|
||||||
where
|
where
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
fn draw(&mut self, area: Rect, context: &DrawContext, frame: &mut Frame<'_, B>) {
|
|
||||||
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 > area.height.into() && area.height < TABLE_GAP_HEIGHT_LIMIT)
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
|
@ -1 +0,0 @@
|
|||||||
pub struct DrawContext {}
|
|
19
src/tuice/element.rs
Normal file
19
src/tuice/element.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use enum_dispatch::enum_dispatch;
|
||||||
|
use tui::{layout::Rect, Frame};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
Block, Bounds, Carousel, Column, Container, Event, LayoutNode, Row, Shortcut, Size, Status,
|
||||||
|
TextTable, TmpComponent,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// An [`Element`] is an instantiated [`Component`].
|
||||||
|
#[enum_dispatch(TmpComponent<Message>)]
|
||||||
|
pub enum Element<'a, Message> {
|
||||||
|
Block,
|
||||||
|
Carousel,
|
||||||
|
Column,
|
||||||
|
Container(Container<'a, Message>),
|
||||||
|
Row(Row<'a, Message>),
|
||||||
|
Shortcut,
|
||||||
|
TextTable(TextTable<'a, Message>),
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
///
|
///
|
||||||
/// 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)
|
||||||
/// of a child, which is passed back up to the parent.
|
/// of a child, which is passed back up to the parent.
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
pub struct Bounds {
|
pub struct Bounds {
|
||||||
/// The minimal width available.
|
/// The minimal width available.
|
||||||
pub min_width: u16,
|
pub min_width: u16,
|
||||||
@ -15,3 +16,14 @@ pub struct Bounds {
|
|||||||
/// The maximal height available.
|
/// The maximal height available.
|
||||||
pub max_height: u16,
|
pub max_height: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Bounds {
|
||||||
|
pub fn with_two_bounds(width: u16, height: u16) -> Self {
|
||||||
|
Self {
|
||||||
|
min_width: width,
|
||||||
|
min_height: height,
|
||||||
|
max_width: width,
|
||||||
|
max_height: height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,13 +1,8 @@
|
|||||||
use tui::layout::Rect;
|
use tui::layout::Rect;
|
||||||
|
|
||||||
use crate::tuice::{Bounds, Component, LayoutNode};
|
use crate::tuice::{Bounds, Element, LayoutNode, TmpComponent};
|
||||||
|
|
||||||
pub fn build_layout_tree<Message, Backend>(
|
pub fn build_layout_tree<Message>(area: Rect, root: &Element<'_, Message>) -> LayoutNode {
|
||||||
area: Rect, root: &Box<dyn Component<Message, Backend>>,
|
|
||||||
) -> LayoutNode
|
|
||||||
where
|
|
||||||
Backend: tui::backend::Backend,
|
|
||||||
{
|
|
||||||
let mut root_layout_node = LayoutNode::from_area(area);
|
let mut root_layout_node = LayoutNode::from_area(area);
|
||||||
let bounds = Bounds {
|
let bounds = Bounds {
|
||||||
min_width: 0,
|
min_width: 0,
|
||||||
@ -16,7 +11,7 @@ where
|
|||||||
max_height: area.height,
|
max_height: area.height,
|
||||||
};
|
};
|
||||||
|
|
||||||
root.layout(bounds, &mut root_layout_node);
|
let _ = root.layout(bounds, &mut root_layout_node);
|
||||||
|
|
||||||
root_layout_node
|
root_layout_node
|
||||||
}
|
}
|
||||||
|
@ -15,5 +15,5 @@ pub use runtime::RuntimeEvent;
|
|||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub use layout::*;
|
pub use layout::*;
|
||||||
|
|
||||||
pub mod draw_context;
|
pub mod element;
|
||||||
pub use draw_context::*;
|
pub use element::*;
|
||||||
|
@ -4,7 +4,7 @@ use tui::layout::Rect;
|
|||||||
|
|
||||||
use crate::tuice::Status;
|
use crate::tuice::Status;
|
||||||
|
|
||||||
use super::{Application, Event};
|
use super::{Application, Event, TmpComponent};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum RuntimeEvent<Message> {
|
pub enum RuntimeEvent<Message> {
|
||||||
|
@ -3,4 +3,3 @@ pub enum DataUnit {
|
|||||||
Byte,
|
Byte,
|
||||||
Bit,
|
Bit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user