summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClementTsang <cjhtsang@uwaterloo.ca>2021-12-15 23:30:18 -0500
committerClementTsang <cjhtsang@uwaterloo.ca>2021-12-15 23:30:18 -0500
commitfd291575a618b10bb4e730ae0522f104d94e93d3 (patch)
treec50074fd91899267ccf5719d246f0ea4fe568784
parentc002a3fa3a3276464502e0b1ea2bd29a1b8e315b (diff)
Switch back to dyn for nowtuice
-rw-r--r--src/tuice/application.rs15
-rw-r--r--src/tuice/component.rs11
-rw-r--r--src/tuice/component/base/block.rs6
-rw-r--r--src/tuice/component/base/carousel.rs9
-rw-r--r--src/tuice/component/base/container.rs9
-rw-r--r--src/tuice/component/base/flex.rs33
-rw-r--r--src/tuice/component/base/flex/flex_element.rs23
-rw-r--r--src/tuice/component/base/mod.rs2
-rw-r--r--src/tuice/component/base/shortcut.rs9
-rw-r--r--src/tuice/component/base/text_table.rs26
-rw-r--r--src/tuice/component/properties.rs19
-rw-r--r--src/tuice/element.rs51
-rw-r--r--src/tuice/layout/build_layout.rs8
-rw-r--r--src/tuice/runtime.rs8
14 files changed, 142 insertions, 87 deletions
diff --git a/src/tuice/application.rs b/src/tuice/application.rs
index 540c8a3c..68457e6f 100644
--- a/src/tuice/application.rs
+++ b/src/tuice/application.rs
@@ -1,6 +1,6 @@
use std::{fmt::Debug, sync::mpsc::Receiver};
-use tui::Terminal;
+use tui::{backend::Backend, Terminal};
use super::{
runtime::{self, RuntimeEvent},
@@ -8,10 +8,13 @@ use super::{
};
/// An alias to the [`tui::backend::CrosstermBackend`] writing to [`std::io::Stdout`].
-pub type CrosstermBackend = tui::backend::CrosstermBackend<std::io::Stdout>;
+pub(crate) type CrosstermBackend = tui::backend::CrosstermBackend<std::io::Stdout>;
#[allow(unused_variables)]
-pub trait Application: Sized {
+pub trait Application<B = CrosstermBackend>: Sized
+where
+ B: Backend,
+{
type Message: Debug;
/// Determines how to handle a given message.
@@ -21,7 +24,7 @@ pub trait Application: Sized {
/// always returning false.
fn is_terminated(&self) -> bool;
- fn view(&mut self) -> Element<'static, Self::Message>;
+ fn view(&mut self) -> Element<'static, Self::Message, B>;
/// To run upon stopping the application.
fn destroy(&mut self) {}
@@ -39,8 +42,8 @@ pub fn launch_with_application<A, B>(
application: A, receiver: Receiver<RuntimeEvent<A::Message>>, terminal: &mut Terminal<B>,
) -> anyhow::Result<()>
where
- A: Application + 'static,
- B: tui::backend::Backend,
+ A: Application<B> + 'static,
+ B: Backend,
{
runtime::launch(application, receiver, terminal)
}
diff --git a/src/tuice/component.rs b/src/tuice/component.rs
index 753f36ba..d479a188 100644
--- a/src/tuice/component.rs
+++ b/src/tuice/component.rs
@@ -7,19 +7,18 @@ pub use widget::*;
pub mod properties;
pub use properties::*;
-use enum_dispatch::enum_dispatch;
use tui::{layout::Rect, Frame};
use super::{Bounds, DrawContext, Event, LayoutNode, Size, Status};
/// A component displays information and can be interacted with.
#[allow(unused_variables)]
-#[enum_dispatch]
-pub trait TmpComponent<Message> {
+pub trait Component<Message, Backend>
+where
+ Backend: tui::backend::Backend,
+{
/// Draws the component.
- fn draw<Backend>(&mut self, context: DrawContext<'_>, frame: &mut Frame<'_, Backend>)
- where
- Backend: tui::backend::Backend;
+ fn draw(&mut self, context: DrawContext<'_>, frame: &mut Frame<'_, Backend>);
/// How a component should react to an [`Event`].
///
diff --git a/src/tuice/component/base/block.rs b/src/tuice/component/base/block.rs
index d1a7e2b9..c9386112 100644
--- a/src/tuice/component/base/block.rs
+++ b/src/tuice/component/base/block.rs
@@ -1,11 +1,11 @@
use tui::{backend::Backend, layout::Rect, Frame};
-use crate::tuice::{DrawContext, Event, Status, TmpComponent};
+use crate::tuice::{Component, DrawContext, Event, Status};
pub struct Block {}
-impl<Message> TmpComponent<Message> for Block {
- fn draw<B>(&mut self, _context: DrawContext<'_>, _frame: &mut Frame<'_, B>)
+impl<Message, B: Backend> Component<Message, B> for Block {
+ fn draw(&mut self, _context: DrawContext<'_>, _frame: &mut Frame<'_, B>)
where
B: Backend,
{
diff --git a/src/tuice/component/base/carousel.rs b/src/tuice/component/base/carousel.rs
index 2790e372..468774fc 100644
--- a/src/tuice/component/base/carousel.rs
+++ b/src/tuice/component/base/carousel.rs
@@ -1,14 +1,11 @@
use tui::{backend::Backend, layout::Rect, Frame};
-use crate::tuice::{DrawContext, Event, Status, TmpComponent};
+use crate::tuice::{Component, DrawContext, Event, Status};
pub struct Carousel {}
-impl<Message> TmpComponent<Message> for Carousel {
- fn draw<B>(&mut self, _context: DrawContext<'_>, _frame: &mut Frame<'_, B>)
- where
- B: Backend,
- {
+impl<Message, B: Backend> Component<Message, B> for Carousel {
+ fn draw(&mut self, _context: DrawContext<'_>, _frame: &mut Frame<'_, B>) {
todo!()
}
diff --git a/src/tuice/component/base/container.rs b/src/tuice/component/base/container.rs
index f30937ca..67872d8e 100644
--- a/src/tuice/component/base/container.rs
+++ b/src/tuice/component/base/container.rs
@@ -1,6 +1,6 @@
use tui::{backend::Backend, layout::Rect, Frame};
-use crate::tuice::{Bounds, DrawContext, Element, Event, LayoutNode, Size, Status, TmpComponent};
+use crate::tuice::{Bounds, Component, DrawContext, Element, Event, LayoutNode, Size, Status};
/// A [`Container`] just contains a child, as well as being able to be sized.
///
@@ -37,11 +37,8 @@ impl<'a, Message> Container<'a, Message> {
}
}
-impl<'a, Message> TmpComponent<Message> for Container<'a, Message> {
- fn draw<B>(&mut self, context: DrawContext<'_>, _frame: &mut Frame<'_, B>)
- where
- B: Backend,
- {
+impl<'a, Message, B: Backend> Component<Message, B> for Container<'a, Message> {
+ fn draw(&mut self, context: DrawContext<'_>, _frame: &mut Frame<'_, B>) {
todo!()
}
diff --git a/src/tuice/component/base/flex.rs b/src/tuice/component/base/flex.rs
index 1aefca0e..98172955 100644
--- a/src/tuice/component/base/flex.rs
+++ b/src/tuice/component/base/flex.rs
@@ -3,7 +3,7 @@ use tui::{backend::Backend, layout::Rect, Frame};
pub mod flex_element;
pub use flex_element::FlexElement;
-use crate::tuice::{Bounds, DrawContext, Element, Event, LayoutNode, Size, Status, TmpComponent};
+use crate::tuice::{Bounds, Component, DrawContext, Element, Event, LayoutNode, Size, Status};
#[derive(Clone, Copy, Debug)]
pub enum Axis {
@@ -14,12 +14,12 @@ pub enum Axis {
Vertical,
}
-pub struct Flex<'a, Message> {
- children: Vec<FlexElement<'a, Message>>,
+pub struct Flex<'a, Message, B: Backend> {
+ children: Vec<FlexElement<'a, Message, B>>,
alignment: Axis,
}
-impl<'a, Message> Flex<'a, Message> {
+impl<'a, Message, B: Backend> Flex<'a, Message, B> {
pub fn new(alignment: Axis) -> Self {
Self {
children: vec![],
@@ -38,7 +38,7 @@ impl<'a, Message> Flex<'a, Message> {
/// Creates a new [`Flex`] with a horizontal alignment with the given children.
pub fn row_with_children<C>(children: Vec<C>) -> Self
where
- C: Into<FlexElement<'a, Message>>,
+ C: Into<FlexElement<'a, Message, B>>,
{
Self {
children: children.into_iter().map(Into::into).collect(),
@@ -57,7 +57,7 @@ impl<'a, Message> Flex<'a, Message> {
/// Creates a new [`Flex`] with a vertical alignment with the given children.
pub fn column_with_children<C>(children: Vec<C>) -> Self
where
- C: Into<FlexElement<'a, Message>>,
+ C: Into<FlexElement<'a, Message, B>>,
{
Self {
children: children.into_iter().map(Into::into).collect(),
@@ -67,7 +67,7 @@ impl<'a, Message> Flex<'a, Message> {
pub fn with_child<E>(mut self, child: E) -> Self
where
- E: Into<Element<'a, Message>>,
+ E: Into<Element<'a, Message, B>>,
{
self.children.push(FlexElement::with_no_flex(child.into()));
self
@@ -75,7 +75,7 @@ impl<'a, Message> Flex<'a, Message> {
pub fn with_flex_child<E>(mut self, child: E, flex: u16) -> Self
where
- E: Into<Element<'a, Message>>,
+ E: Into<Element<'a, Message, B>>,
{
self.children
.push(FlexElement::with_flex(child.into(), flex));
@@ -83,11 +83,8 @@ impl<'a, Message> Flex<'a, Message> {
}
}
-impl<'a, Message> TmpComponent<Message> for Flex<'a, Message> {
- fn draw<B>(&mut self, context: DrawContext<'_>, frame: &mut Frame<'_, B>)
- where
- B: Backend,
- {
+impl<'a, Message, B: Backend> Component<Message, B> for Flex<'a, Message, B> {
+ fn draw(&mut self, context: DrawContext<'_>, frame: &mut Frame<'_, B>) {
self.children
.iter_mut()
.zip(context.children())
@@ -194,3 +191,13 @@ impl<'a, Message> TmpComponent<Message> for Flex<'a, Message> {
current_size
}
}
+
+impl<'a, Message, B: Backend> From<Flex<'a, Message, B>> for Element<'a, Message, B>
+where
+ Message: 'a,
+ B: 'a,
+{
+ fn from(flex: Flex<'a, Message, B>) -> Self {
+ Element::new(flex)
+ }
+}
diff --git a/src/tuice/component/base/flex/flex_element.rs b/src/tuice/component/base/flex/flex_element.rs
index 43982f56..b961f281 100644
--- a/src/tuice/component/base/flex/flex_element.rs
+++ b/src/tuice/component/base/flex/flex_element.rs
@@ -1,31 +1,31 @@
use tui::{backend::Backend, layout::Rect, Frame};
-use crate::tuice::{Bounds, DrawContext, Element, Event, LayoutNode, Size, Status, TmpComponent};
+use crate::tuice::{Bounds, DrawContext, Element, Event, LayoutNode, Size, Status};
use super::Axis;
-pub struct FlexElement<'a, Message> {
+pub struct FlexElement<'a, Message, B: Backend> {
/// Represents a ratio with other [`FlexElement`]s on how far to expand.
pub flex: u16,
- element: Element<'a, Message>,
+ element: Element<'a, Message, B>,
}
-impl<'a, Message> FlexElement<'a, Message> {
- pub fn new<I: Into<Element<'a, Message>>>(element: I) -> Self {
+impl<'a, Message, B: Backend> FlexElement<'a, Message, B> {
+ pub fn new<I: Into<Element<'a, Message, B>>>(element: I) -> Self {
Self {
flex: 1,
element: element.into(),
}
}
- pub fn with_flex<I: Into<Element<'a, Message>>>(element: I, flex: u16) -> Self {
+ pub fn with_flex<I: Into<Element<'a, Message, B>>>(element: I, flex: u16) -> Self {
Self {
flex,
element: element.into(),
}
}
- pub fn with_no_flex<I: Into<Element<'a, Message>>>(element: I) -> Self {
+ pub fn with_no_flex<I: Into<Element<'a, Message, B>>>(element: I) -> Self {
Self {
flex: 0,
element: element.into(),
@@ -37,10 +37,7 @@ impl<'a, Message> FlexElement<'a, Message> {
self
}
- pub(crate) fn draw<B>(&mut self, context: DrawContext<'_>, frame: &mut Frame<'_, B>)
- where
- B: Backend,
- {
+ pub(crate) fn draw(&mut self, context: DrawContext<'_>, frame: &mut Frame<'_, B>) {
self.element.draw(context, frame)
}
@@ -81,8 +78,8 @@ impl<'a, Message> FlexElement<'a, Message> {
}
}
-impl<'a, Message> From<Element<'a, Message>> for FlexElement<'a, Message> {
- fn from(element: Element<'a, Message>) -> Self {
+impl<'a, Message, B: Backend> From<Element<'a, Message, B>> for FlexElement<'a, Message, B> {
+ fn from(element: Element<'a, Message, B>) -> Self {
Self { flex: 0, element }
}
}
diff --git a/src/tuice/component/base/mod.rs b/src/tuice/component/base/mod.rs
index 7e7932c4..a72b4a39 100644
--- a/src/tuice/component/base/mod.rs
+++ b/src/tuice/component/base/mod.rs
@@ -1,5 +1,5 @@
pub mod text_table;
-pub use text_table::{TextColumn, TextColumnConstraint, TextTable};
+pub use text_table::{TextColumn, TextColumnConstraint, TextTable, TextTableProps};
pub mod shortcut;
pub use shortcut::Shortcut;
diff --git a/src/tuice/component/base/shortcut.rs b/src/tuice/component/base/shortcut.rs
index 661c45d7..7354f609 100644
--- a/src/tuice/component/base/shortcut.rs
+++ b/src/tuice/component/base/shortcut.rs
@@ -1,17 +1,14 @@
use tui::{backend::Backend, layout::Rect, Frame};
-use crate::tuice::{DrawContext, Event, Status, TmpComponent};
+use crate::tuice::{Component, DrawContext, Event, Status};
/// 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).
pub struct Shortcut {}
-impl<Message> TmpComponent<Message> for Shortcut {
- fn draw<B>(&mut self, _context: DrawContext<'_>, _frame: &mut Frame<'_, B>)
- where
- B: Backend,
- {
+impl<Message, B: Backend> Component<Message, B> for Shortcut {
+ fn draw(&mut self, _context: DrawContext<'_>, _frame: &mut Frame<'_, B>) {
todo!()
}
diff --git a/src/tuice/component/base/text_table.rs b/src/tuice/component/base/text_table.rs
index b6d04a77..782313b9 100644
--- a/src/tuice/component/base/text_table.rs
+++ b/src/tuice/component/base/text_table.rs
@@ -14,12 +14,13 @@ use unicode_segmentation::UnicodeSegmentation;
use crate::{
constants::TABLE_GAP_HEIGHT_LIMIT,
- tuice::{DrawContext, Event, Status, TmpComponent},
+ tuice::{Component, DrawContext, Element, Event, Properties, Status},
};
pub use self::table_column::{TextColumn, TextColumnConstraint};
use self::table_scroll_state::ScrollState as TextTableState;
+/// Styles for a [`TextTable`].
#[derive(Clone, Debug, Default)]
pub struct StyleSheet {
text: Style,
@@ -27,7 +28,11 @@ pub struct StyleSheet {
table_header: Style,
}
-pub enum TextTableMsg {}
+/// Properties for a [`TextTable`].
+#[derive(PartialEq, Clone, Debug)]
+pub struct TextTableProps {}
+
+impl Properties for TextTableProps {}
/// A sortable, scrollable table for text data.
pub struct TextTable<'a, Message> {
@@ -165,11 +170,8 @@ impl<'a, Message> TextTable<'a, Message> {
}
}
-impl<'a, Message> TmpComponent<Message> for TextTable<'a, Message> {
- fn draw<B>(&mut self, context: DrawContext<'_>, frame: &mut Frame<'_, B>)
- where
- B: Backend,
- {
+impl<'a, Message, B: Backend> Component<Message, B> for TextTable<'a, Message> {
+ fn draw(&mut self, context: DrawContext<'_>, frame: &mut Frame<'_, B>) {
let rect = context.rect();
self.table_gap = if !self.show_gap
@@ -272,5 +274,15 @@ impl<'a, Message> TmpComponent<Message> for TextTable<'a, Message> {
}
}
+impl<'a, Message, B: Backend> From<TextTable<'a, Message>> for Element<'a, Message, B>
+where
+ Message: 'a,
+ B: 'a,
+{
+ fn from(text_table: TextTable<'a, Message>) -> Self {
+ Element::new(text_table)
+ }
+}
+
#[cfg(test)]
mod tests {}
diff --git a/src/tuice/component/properties.rs b/src/tuice/component/properties.rs
index d44ab368..5b6d6fc1 100644
--- a/src/tuice/component/properties.rs
+++ b/src/tuice/component/properties.rs
@@ -1,3 +1,20 @@
+use enum_dispatch::enum_dispatch;
+
+use crate::tuice::*;
+
/// A trait that the properties of a [`Component`](super::Component)
/// should implement.
-pub trait Properties: PartialEq {}
+#[enum_dispatch]
+pub trait Properties: PartialEq + Clone {}
+
+#[derive(PartialEq, Clone, Debug)]
+pub struct DefaultProp;
+
+impl Properties for DefaultProp {}
+
+#[enum_dispatch(Properties)]
+#[derive(PartialEq, Clone)]
+pub enum Props {
+ DefaultProp,
+ TextTableProps,
+}
diff --git a/src/tuice/element.rs b/src/tuice/element.rs
index fe859e79..d7c1b432 100644
--- a/src/tuice/element.rs
+++ b/src/tuice/element.rs
@@ -1,18 +1,43 @@
-use enum_dispatch::enum_dispatch;
-use tui::{layout::Rect, Frame};
+use std::io::Stdout;
-use super::{
- Block, Bounds, Carousel, Container, DrawContext, Event, Flex, LayoutNode, Shortcut, Size,
- Status, TextTable, TmpComponent,
+use tui::{
+ backend::{Backend, CrosstermBackend},
+ layout::Rect,
+ Frame,
};
+use super::*;
+
/// An [`Element`] is an instantiated [`Component`].
-#[enum_dispatch(TmpComponent<Message>)]
-pub enum Element<'a, Message> {
- Block,
- Carousel,
- Container(Container<'a, Message>),
- Flex(Flex<'a, Message>),
- Shortcut,
- TextTable(TextTable<'a, Message>),
+pub struct Element<'a, Message, B = CrosstermBackend<Stdout>>
+where
+ B: Backend,
+{
+ component: Box<dyn Component<Message, B> + 'a>,
+}
+
+impl<'a, Message, B> Element<'a, Message, B>
+where
+ B: Backend,
+{
+ pub fn new<C: Component<Message, B> + 'a>(component: C) -> Self {
+ Self {
+ component: Box::new(component),
+ }
+ }
+
+ /// Draws the element.
+ pub fn draw(&mut self, context: DrawContext<'_>, frame: &mut Frame<'_, B>) {
+ self.component.draw(context, frame)
+ }
+
+ /// How an element should react to an [`Event`].
+ pub fn on_event(&mut self, area: Rect, event: Event, messages: &mut Vec<Message>) -> Status {
+ self.component.on_event(area, event, messages)
+ }
+
+ /// How an element should size itself and its children, given some [`Bounds`].
+ pub fn layout(&self, bounds: Bounds, node: &mut LayoutNode) -> Size {
+ self.component.layout(bounds, node)
+ }
}
diff --git a/src/tuice/layout/build_layout.rs b/src/tuice/layout/build_layout.rs
index d9fdddae..0002b0fc 100644
--- a/src/tuice/layout/build_layout.rs
+++ b/src/tuice/layout/build_layout.rs
@@ -1,8 +1,10 @@
-use tui::layout::Rect;
+use tui::{backend::Backend, layout::Rect};
-use crate::tuice::{Bounds, Element, LayoutNode, TmpComponent};
+use crate::tuice::{Bounds, Element, LayoutNode};
-pub fn build_layout_tree<Message>(rect: Rect, root: &Element<'_, Message>) -> LayoutNode {
+pub fn build_layout_tree<Message, B: Backend>(
+ rect: Rect, root: &Element<'_, Message, B>,
+) -> LayoutNode {
let mut root_layout_node = LayoutNode::from_rect(rect);
let bounds = Bounds {
min_width: 0,
diff --git a/src/tuice/runtime.rs b/src/tuice/runtime.rs
index 1666c21d..c592dba7 100644
--- a/src/tuice/runtime.rs
+++ b/src/tuice/runtime.rs
@@ -4,7 +4,7 @@ use tui::{backend::Backend, layout::Rect, Terminal};
use crate::tuice::Status;
-use super::{build_layout_tree, Application, Element, Event, TmpComponent};
+use super::{build_layout_tree, Application, Element, Event};
#[derive(Clone, Copy, Debug)]
pub enum RuntimeEvent<Message> {
@@ -17,7 +17,7 @@ pub(crate) fn launch<A, B>(
mut application: A, receiver: Receiver<RuntimeEvent<A::Message>>, terminal: &mut Terminal<B>,
) -> anyhow::Result<()>
where
- A: Application + 'static,
+ A: Application<B> + 'static,
B: Backend,
{
let mut user_interface = application.view();
@@ -67,7 +67,9 @@ where
Ok(())
}
-fn draw<M, B>(user_interface: &mut Element<'_, M>, terminal: &mut Terminal<B>) -> anyhow::Result<()>
+fn draw<M, B>(
+ user_interface: &mut Element<'_, M, B>, terminal: &mut Terminal<B>,
+) -> anyhow::Result<()>
where
B: Backend,
{