This commit is contained in:
ClementTsang 2021-12-24 18:38:11 -05:00
parent b7d73746ad
commit 68d2e9ae5b
13 changed files with 114 additions and 40 deletions

View File

@ -29,7 +29,7 @@ use frozen_state::FrozenState;
use crate::{
canvas::Painter,
constants,
tuine::{Application, Element, Flex, ViewContext},
tuine::{Application, Element, Flex, Shortcut, ViewContext},
units::data_units::DataUnit,
Pid,
};
@ -241,7 +241,10 @@ impl Application for AppState {
Flex::column()
.with_flex_child(
Flex::row_with_children(vec![
FlexElement::new(TextTable::new(ctx, vec!["A", "B", "C"])),
FlexElement::new(Shortcut::with_child(TextTable::new(
ctx,
vec!["A", "B", "C"],
))),
FlexElement::new(TextTable::new(ctx, vec!["D", "E", "F"])),
]),
1,

View File

@ -15,7 +15,7 @@ use super::{Bounds, DrawContext, Event, LayoutNode, Size, StateContext, Status};
pub trait TmpComponent<Message> {
/// Draws the component.
fn draw<Backend>(
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: DrawContext<'_>,
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>,
frame: &mut Frame<'_, Backend>,
) where
Backend: tui::backend::Backend;
@ -24,7 +24,7 @@ pub trait TmpComponent<Message> {
///
/// Defaults to just ignoring the event.
fn on_event(
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: DrawContext<'_>, event: Event,
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, event: Event,
messages: &mut Vec<Message>,
) -> Status {
Status::Ignored

View File

@ -6,7 +6,7 @@ pub struct Block {}
impl<Message> TmpComponent<Message> for Block {
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>,
) where
B: Backend,
@ -15,7 +15,7 @@ impl<Message> TmpComponent<Message> for Block {
}
fn on_event(
&mut self, _state_ctx: &mut StateContext<'_>, _draw_ctx: DrawContext<'_>, _event: Event,
&mut self, _state_ctx: &mut StateContext<'_>, _draw_ctx: &DrawContext<'_>, _event: Event,
_messages: &mut Vec<Message>,
) -> Status {
Status::Ignored

View File

@ -6,7 +6,7 @@ pub struct Carousel {}
impl<Message> TmpComponent<Message> for Carousel {
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>,
) where
B: Backend,
@ -15,7 +15,7 @@ impl<Message> TmpComponent<Message> for Carousel {
}
fn on_event(
&mut self, _state_ctx: &mut StateContext<'_>, _draw_ctx: DrawContext<'_>, _event: Event,
&mut self, _state_ctx: &mut StateContext<'_>, _draw_ctx: &DrawContext<'_>, _event: Event,
_messages: &mut Vec<Message>,
) -> Status {
Status::Ignored

View File

@ -1,4 +1,4 @@
use tui::{backend::Backend, Frame};
use tui::{backend::Backend, layout::Rect, Frame};
use crate::tuine::{
Bounds, DrawContext, Element, Event, LayoutNode, Size, StateContext, Status, TmpComponent,
@ -15,16 +15,22 @@ pub struct Container<'a, Message> {
}
impl<'a, Message> Container<'a, Message> {
pub fn with_child(child: Element<'a, Message>) -> Self {
pub fn with_child<C>(child: C) -> Self
where
C: Into<Element<'a, Message>>,
{
Self {
width: None,
height: None,
child: Some(child.into()),
child: Some(Box::new(child.into())),
}
}
pub fn child(mut self, child: Option<Element<'a, Message>>) -> Self {
self.child = child.map(|c| c.into());
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()));
self
}
@ -41,25 +47,25 @@ impl<'a, Message> Container<'a, Message> {
impl<'a, Message> TmpComponent<Message> for Container<'a, Message> {
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>,
) where
B: Backend,
{
if let Some(child) = &mut self.child {
if let Some(child_draw_ctx) = draw_ctx.children().next() {
child.draw(state_ctx, child_draw_ctx, frame)
child.draw(state_ctx, &child_draw_ctx, frame)
}
}
}
fn on_event(
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: DrawContext<'_>, event: Event,
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, event: Event,
messages: &mut Vec<Message>,
) -> Status {
if let Some(child) = &mut self.child {
if let Some(child_draw_ctx) = draw_ctx.children().next() {
return child.on_event(state_ctx, child_draw_ctx, event, messages);
return child.on_event(state_ctx, &child_draw_ctx, event, messages);
}
}
@ -94,6 +100,7 @@ impl<'a, Message> TmpComponent<Message> for Container<'a, Message> {
};
let child_size = child.layout(child_bounds, &mut child_node);
child_node.rect = Rect::new(0, 0, child_size.width, child_size.height);
node.children = vec![child_node];
// Note that this is implicitly bounded by our above calculations,

View File

@ -0,0 +1,16 @@
use tui::{backend::Backend, Frame};
use crate::tuine::{DrawContext, StateContext, TmpComponent};
#[derive(Default)]
pub struct Empty {}
impl<Message> TmpComponent<Message> for Empty {
fn draw<B>(
&mut self, _state_ctx: &mut StateContext<'_>, _draw_ctx: &DrawContext<'_>,
_frame: &mut Frame<'_, B>,
) where
B: Backend,
{
}
}

View File

@ -87,7 +87,7 @@ impl<'a, Message> Flex<'a, Message> {
impl<'a, Message> TmpComponent<Message> for Flex<'a, Message> {
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>,
) where
B: Backend,
@ -97,17 +97,17 @@ impl<'a, Message> TmpComponent<Message> for Flex<'a, Message> {
.zip(draw_ctx.children())
.for_each(|(child, child_draw_ctx)| {
if child_draw_ctx.should_draw() {
child.draw(state_ctx, child_draw_ctx, frame);
child.draw(state_ctx, &child_draw_ctx, frame);
}
});
}
fn on_event(
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: DrawContext<'_>, event: Event,
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, event: Event,
messages: &mut Vec<Message>,
) -> Status {
for (child, child_draw_ctx) in self.children.iter_mut().zip(draw_ctx.children()) {
match child.on_event(state_ctx, child_draw_ctx, event, messages) {
match child.on_event(state_ctx, &child_draw_ctx, event, messages) {
Status::Captured => {
return Status::Captured;
}

View File

@ -40,7 +40,7 @@ impl<'a, Message> FlexElement<'a, Message> {
}
pub(crate) 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>,
) where
B: Backend,
@ -49,7 +49,7 @@ impl<'a, Message> FlexElement<'a, Message> {
}
pub(crate) fn on_event(
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: DrawContext<'_>, event: Event,
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, event: Event,
messages: &mut Vec<Message>,
) -> Status {
self.element.on_event(state_ctx, draw_ctx, event, messages)

View File

@ -15,3 +15,6 @@ pub use carousel::Carousel;
pub mod container;
pub use container::Container;
pub mod empty;
pub use empty::Empty;

View File

@ -1,6 +1,5 @@
use crossterm::event::KeyEvent;
use rustc_hash::FxHashMap;
use tui::{backend::Backend, Frame};
use tui::{backend::Backend, layout::Rect, Frame};
use crate::tuine::{
Bounds, DrawContext, Element, Event, LayoutNode, Size, StateContext, Status, TmpComponent,
@ -18,7 +17,7 @@ pub struct Shortcut<'a, Message> {
dyn Fn(
&mut Element<'a, Message>,
&mut StateContext<'_>,
DrawContext<'_>,
&DrawContext<'_>,
Event,
&mut Vec<Message>,
) -> Status,
@ -27,41 +26,73 @@ pub struct Shortcut<'a, Message> {
}
impl<'a, Message> Shortcut<'a, Message> {
pub fn with_child(child: Element<'a, Message>) -> Self {
pub fn with_child<C>(child: C) -> Self
where
C: Into<Element<'a, Message>>,
{
Self {
child: Some(child.into()),
child: Some(Box::new(child.into())),
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()));
self
}
pub fn shortcut(
mut self, event: Event,
f: Box<
dyn Fn(
&mut Element<'a, Message>,
&mut StateContext<'_>,
&DrawContext<'_>,
Event,
&mut Vec<Message>,
) -> Status,
>,
) -> Self {
self.shortcuts.insert(event, f);
self
}
pub fn remove_shortcut(mut self, event: &Event) -> Self {
self.shortcuts.remove(event);
self
}
}
impl<'a, Message> TmpComponent<Message> for Shortcut<'a, Message> {
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>,
) where
B: Backend,
{
if let Some(child) = &mut self.child {
if let Some(child_draw_ctx) = draw_ctx.children().next() {
child.draw(state_ctx, child_draw_ctx, frame)
child.draw(state_ctx, &child_draw_ctx, frame)
}
}
}
fn on_event(
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: DrawContext<'_>, event: Event,
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, event: Event,
messages: &mut Vec<Message>,
) -> Status {
if let Some(child_draw_ctx) = draw_ctx.children().next() {
if let Some(child) = &mut self.child {
match child.on_event(state_ctx, child_draw_ctx, event, messages) {
match child.on_event(state_ctx, &child_draw_ctx, event, messages) {
Status::Captured => {
return Status::Captured;
}
Status::Ignored => {
if let Some(f) = self.shortcuts.get(&event) {
return f(child, state_ctx, child_draw_ctx, event, messages);
return f(child, state_ctx, &child_draw_ctx, event, messages);
}
}
}
@ -72,6 +103,19 @@ impl<'a, Message> TmpComponent<Message> for Shortcut<'a, Message> {
}
fn layout(&self, bounds: Bounds, node: &mut LayoutNode) -> Size {
todo!()
if let Some(child) = &self.child {
let mut child_node = LayoutNode::default();
let child_size = child.layout(bounds, &mut child_node);
child_node.rect = Rect::new(0, 0, child_size.width, child_size.height);
node.children = vec![child_node];
child_size
} else {
Size {
width: 0,
height: 0,
}
}
}
}

View File

@ -166,7 +166,7 @@ impl<'a, Message> TextTable<'a, Message> {
impl<'a, Message> TmpComponent<Message> for TextTable<'a, Message> {
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>,
) where
B: Backend,
@ -220,7 +220,7 @@ impl<'a, Message> TmpComponent<Message> for TextTable<'a, Message> {
}
fn on_event(
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: DrawContext<'_>, event: Event,
&mut self, state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, event: Event,
messages: &mut Vec<Message>,
) -> Status {
use crate::tuine::MouseBoundIntersect;

View File

@ -2,8 +2,8 @@ use enum_dispatch::enum_dispatch;
use tui::Frame;
use super::{
Block, Bounds, Carousel, Container, DrawContext, Event, Flex, LayoutNode, Shortcut, Size,
StateContext, Status, TextTable, TmpComponent,
Block, Bounds, Carousel, Container, DrawContext, Empty, Event, Flex, LayoutNode, Shortcut,
Size, StateContext, Status, TextTable, TmpComponent,
};
/// An [`Element`] is an instantiated [`Component`].
@ -15,4 +15,5 @@ pub enum Element<'a, Message> {
Flex(Flex<'a, Message>),
Shortcut(Shortcut<'a, Message>),
TextTable(TextTable<'a, Message>),
Empty,
}

View File

@ -84,7 +84,7 @@ fn on_event<A>(
let mut state_ctx = StateContext::new(&mut app_data.state_map);
let draw_ctx = DrawContext::root(&layout);
match user_interface.on_event(&mut state_ctx, draw_ctx, event, &mut messages) {
match user_interface.on_event(&mut state_ctx, &draw_ctx, event, &mut messages) {
Status::Captured => {
// TODO: What to do on capture?
}
@ -124,7 +124,7 @@ where
let mut state_ctx = StateContext::new(&mut app_data.state_map);
let draw_ctx = DrawContext::root(&layout);
user_interface.draw(&mut state_ctx, draw_ctx, frame);
user_interface.draw(&mut state_ctx, &draw_ctx, frame);
})?;
Ok(())