mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-04-08 17:05:59 +02:00
Switch back to dyn for now
This commit is contained in:
parent
c002a3fa3a
commit
40a92e2562
@ -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)
|
||||
}
|
||||
|
@ -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`].
|
||||
///
|
||||
|
@ -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,
|
||||
{
|
||||
|
@ -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!()
|
||||
}
|
||||
|
||||
|
@ -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!()
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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!()
|
||||
}
|
||||
|
||||
|
@ -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 {}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user