Shortcut with generic

This commit is contained in:
ClementTsang 2021-12-24 21:33:41 -05:00
parent 68d2e9ae5b
commit f56d70b9ee
8 changed files with 73 additions and 27 deletions

View File

@ -29,7 +29,7 @@ use frozen_state::FrozenState;
use crate::{ use crate::{
canvas::Painter, canvas::Painter,
constants, constants,
tuine::{Application, Element, Flex, Shortcut, ViewContext}, tuine::{Application, Element, Flex, ViewContext},
units::data_units::DataUnit, units::data_units::DataUnit,
Pid, Pid,
}; };
@ -236,15 +236,13 @@ impl Application for AppState {
fn view<'b>(&mut self, ctx: &mut ViewContext<'_>) -> Element<'static, Self::Message> { fn view<'b>(&mut self, ctx: &mut ViewContext<'_>) -> Element<'static, Self::Message> {
use crate::tuine::FlexElement; use crate::tuine::FlexElement;
use crate::tuine::TempTable;
use crate::tuine::TextTable; use crate::tuine::TextTable;
Flex::column() Flex::column()
.with_flex_child( .with_flex_child(
Flex::row_with_children(vec![ Flex::row_with_children(vec![
FlexElement::new(Shortcut::with_child(TextTable::new( FlexElement::new(TempTable::new(ctx)),
ctx,
vec!["A", "B", "C"],
))),
FlexElement::new(TextTable::new(ctx, vec!["D", "E", "F"])), FlexElement::new(TextTable::new(ctx, vec!["D", "E", "F"])),
]), ]),
1, 1,

View File

@ -2,20 +2,23 @@ use rustc_hash::FxHashMap;
use tui::{backend::Backend, layout::Rect, Frame}; use tui::{backend::Backend, layout::Rect, Frame};
use crate::tuine::{ use crate::tuine::{
Bounds, DrawContext, Element, Event, LayoutNode, Size, StateContext, Status, TmpComponent, Bounds, DrawContext, Event, LayoutNode, Size, StateContext, 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).
#[derive(Default)] #[derive(Default)]
pub struct Shortcut<'a, Message> { pub struct Shortcut<Message, Child>
child: Option<Box<Element<'a, Message>>>, where
Child: TmpComponent<Message>,
{
child: Option<Child>,
shortcuts: FxHashMap< shortcuts: FxHashMap<
Event, Event,
Box< Box<
dyn Fn( dyn Fn(
&mut Element<'a, Message>, &mut Child,
&mut StateContext<'_>, &mut StateContext<'_>,
&DrawContext<'_>, &DrawContext<'_>,
Event, Event,
@ -25,22 +28,19 @@ pub struct Shortcut<'a, Message> {
>, >,
} }
impl<'a, Message> Shortcut<'a, Message> { impl<Message, Child> Shortcut<Message, Child>
pub fn with_child<C>(child: C) -> Self where
where Child: TmpComponent<Message>,
C: Into<Element<'a, Message>>, {
{ pub fn with_child(child: Child) -> Self {
Self { Self {
child: Some(Box::new(child.into())), child: Some(child),
shortcuts: Default::default(), shortcuts: Default::default(),
} }
} }
pub fn child<C>(mut self, child: Option<C>) -> Self pub fn child(mut self, child: Option<Child>) -> Self {
where self.child = child;
C: Into<Element<'a, Message>>,
{
self.child = child.map(|c| Box::new(c.into()));
self self
} }
@ -48,7 +48,7 @@ impl<'a, Message> Shortcut<'a, Message> {
mut self, event: Event, mut self, event: Event,
f: Box< f: Box<
dyn Fn( dyn Fn(
&mut Element<'a, Message>, &mut Child,
&mut StateContext<'_>, &mut StateContext<'_>,
&DrawContext<'_>, &DrawContext<'_>,
Event, Event,
@ -66,7 +66,10 @@ impl<'a, Message> Shortcut<'a, Message> {
} }
} }
impl<'a, Message> TmpComponent<Message> for Shortcut<'a, Message> { impl<'a, Message, Child> TmpComponent<Message> for Shortcut<Message, Child>
where
Child: TmpComponent<Message>,
{
fn draw<B>( fn draw<B>(
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, &mut self, state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>,
frame: &mut Frame<'_, B>, frame: &mut Frame<'_, B>,

View File

@ -246,7 +246,7 @@ impl<'a, Message> TmpComponent<Message> for TextTable<'a, Message> {
let y = mouse_event.row - rect.top(); let y = mouse_event.row - rect.top();
if self.sortable && y == 0 { if self.sortable && y == 0 {
todo!() todo!() // Sort by the clicked column!
} else if y > self.table_gap { } else if y > self.table_gap {
let visual_index = usize::from(y - self.table_gap); let visual_index = usize::from(y - self.table_gap);
state.set_visual_index(visual_index) state.set_visual_index(visual_index)

View File

@ -1 +1,2 @@
pub mod temp_table;
pub use temp_table::*;

View File

@ -0,0 +1,40 @@
use crate::tuine::{Shortcut, TextTable, TmpComponent, ViewContext};
/// A [`TempTable`] is a text table that is meant to display temperature data.
pub struct TempTable<'a, Message> {
inner: Shortcut<Message, TextTable<'a, Message>>,
}
impl<'a, Message> TempTable<'a, Message> {
#[track_caller]
pub fn new(ctx: &mut ViewContext<'_>) -> Self {
Self {
inner: Shortcut::with_child(TextTable::new(ctx, vec!["Sensor", "Temp"])),
}
}
}
impl<'a, Message> TmpComponent<Message> for TempTable<'a, Message> {
fn draw<Backend>(
&mut self, state_ctx: &mut crate::tuine::StateContext<'_>,
draw_ctx: &crate::tuine::DrawContext<'_>, frame: &mut tui::Frame<'_, Backend>,
) where
Backend: tui::backend::Backend,
{
self.inner.draw(state_ctx, draw_ctx, frame);
}
fn on_event(
&mut self, state_ctx: &mut crate::tuine::StateContext<'_>,
draw_ctx: &crate::tuine::DrawContext<'_>, event: crate::tuine::Event,
messages: &mut Vec<Message>,
) -> crate::tuine::Status {
self.inner.on_event(state_ctx, draw_ctx, event, messages)
}
fn layout(
&self, bounds: crate::tuine::Bounds, node: &mut crate::tuine::LayoutNode,
) -> crate::tuine::Size {
self.inner.layout(bounds, node)
}
}

View File

@ -3,17 +3,21 @@ use tui::Frame;
use super::{ use super::{
Block, Bounds, Carousel, Container, DrawContext, Empty, Event, Flex, LayoutNode, Shortcut, Block, Bounds, Carousel, Container, DrawContext, Empty, Event, Flex, LayoutNode, Shortcut,
Size, StateContext, Status, TextTable, TmpComponent, Size, StateContext, Status, TempTable, TextTable, TmpComponent,
}; };
/// An [`Element`] is an instantiated [`Component`]. /// An [`Element`] is an instantiated [`Component`].
#[enum_dispatch(TmpComponent<Message>)] #[enum_dispatch(TmpComponent<Message>)]
pub enum Element<'a, Message> { pub enum Element<'a, Message, C = Empty>
where
C: TmpComponent<Message>,
{
Block, Block,
Carousel, Carousel,
Container(Container<'a, Message>), Container(Container<'a, Message>),
Flex(Flex<'a, Message>), Flex(Flex<'a, Message>),
Shortcut(Shortcut<'a, Message>), Shortcut(Shortcut<Message, C>),
TextTable(TextTable<'a, Message>), TextTable(TextTable<'a, Message>),
Empty, Empty,
TempTable(TempTable<'a, Message>),
} }