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

View File

@ -2,20 +2,23 @@ use rustc_hash::FxHashMap;
use tui::{backend::Backend, layout::Rect, Frame};
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.
///
/// Inspired by [Flutter's approach](https://docs.flutter.dev/development/ui/advanced/actions_and_shortcuts).
#[derive(Default)]
pub struct Shortcut<'a, Message> {
child: Option<Box<Element<'a, Message>>>,
pub struct Shortcut<Message, Child>
where
Child: TmpComponent<Message>,
{
child: Option<Child>,
shortcuts: FxHashMap<
Event,
Box<
dyn Fn(
&mut Element<'a, Message>,
&mut Child,
&mut StateContext<'_>,
&DrawContext<'_>,
Event,
@ -25,22 +28,19 @@ pub struct Shortcut<'a, Message> {
>,
}
impl<'a, Message> Shortcut<'a, Message> {
pub fn with_child<C>(child: C) -> Self
where
C: Into<Element<'a, Message>>,
{
impl<Message, Child> Shortcut<Message, Child>
where
Child: TmpComponent<Message>,
{
pub fn with_child(child: Child) -> Self {
Self {
child: Some(Box::new(child.into())),
child: Some(child),
shortcuts: Default::default(),
}
}
pub fn child<C>(mut self, child: Option<C>) -> Self
where
C: Into<Element<'a, Message>>,
{
self.child = child.map(|c| Box::new(c.into()));
pub fn child(mut self, child: Option<Child>) -> Self {
self.child = child;
self
}
@ -48,7 +48,7 @@ impl<'a, Message> Shortcut<'a, Message> {
mut self, event: Event,
f: Box<
dyn Fn(
&mut Element<'a, Message>,
&mut Child,
&mut StateContext<'_>,
&DrawContext<'_>,
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>(
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>,
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();
if self.sortable && y == 0 {
todo!()
todo!() // Sort by the clicked column!
} else if y > self.table_gap {
let visual_index = usize::from(y - self.table_gap);
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::{
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`].
#[enum_dispatch(TmpComponent<Message>)]
pub enum Element<'a, Message> {
pub enum Element<'a, Message, C = Empty>
where
C: TmpComponent<Message>,
{
Block,
Carousel,
Container(Container<'a, Message>),
Flex(Flex<'a, Message>),
Shortcut(Shortcut<'a, Message>),
Shortcut(Shortcut<Message, C>),
TextTable(TextTable<'a, Message>),
Empty,
TempTable(TempTable<'a, Message>),
}