First display!

This commit is contained in:
ClementTsang 2021-12-12 20:51:09 -05:00
parent 58f78731b3
commit 37b3d235b9
6 changed files with 54 additions and 18 deletions

View File

@ -102,7 +102,7 @@ fn main() -> Result<()> {
// TODO: [Threads, Panic] Make this close all the child threads too! // TODO: [Threads, Panic] Make this close all the child threads too!
panic::set_hook(Box::new(|info| panic_hook(info))); panic::set_hook(Box::new(|info| panic_hook(info)));
tuice::launch_with_application(app, receiver); tuice::launch_with_application(app, receiver, &mut terminal)?; // FIXME: Move terminal construction INSIDE
// I think doing it in this order is safe... // I think doing it in this order is safe...
*thread_termination_lock.lock().unwrap() = true; *thread_termination_lock.lock().unwrap() = true;

View File

@ -1,5 +1,7 @@
use std::{fmt::Debug, sync::mpsc::Receiver}; use std::{fmt::Debug, sync::mpsc::Receiver};
use tui::Terminal;
use super::{ use super::{
runtime::{self, RuntimeEvent}, runtime::{self, RuntimeEvent},
Element, Event, Element, Event,
@ -32,9 +34,13 @@ pub trait Application: Sized {
fn global_event_handler(&mut self, event: Event, messages: &mut Vec<Self::Message>) {} fn global_event_handler(&mut self, event: Event, messages: &mut Vec<Self::Message>) {}
} }
/// Launches some application with tuice. /// Launches some application with tuice. Note this will take over the calling thread.
pub fn launch_with_application<A: Application + 'static>( pub fn launch_with_application<A, B>(
application: A, receiver: Receiver<RuntimeEvent<A::Message>>, application: A, receiver: Receiver<RuntimeEvent<A::Message>>, terminal: &mut Terminal<B>,
) { ) -> anyhow::Result<()>
runtime::launch(application, receiver); where
A: Application + 'static,
B: tui::backend::Backend,
{
runtime::launch(application, receiver, terminal)
} }

View File

@ -49,7 +49,7 @@ impl<'a, Message> FlexElement<'a, Message> {
} }
pub(crate) fn layout(&self, bounds: Bounds, node: &mut LayoutNode) -> Size { pub(crate) fn layout(&self, bounds: Bounds, node: &mut LayoutNode) -> Size {
todo!() self.element.layout(bounds, node)
} }
} }

View File

@ -8,7 +8,13 @@ pub struct DrawContext<'a> {
} }
impl<'a> DrawContext<'_> { impl<'a> DrawContext<'_> {
pub(crate) fn new() {} /// Creates a new [`DrawContext`], with the offset set to `(0, 0)`.
pub(crate) fn root(root: &'a LayoutNode) -> DrawContext<'a> {
DrawContext {
current_node: root,
current_offset: (0, 0),
}
}
pub(crate) fn rect(&self) -> Rect { pub(crate) fn rect(&self) -> Rect {
self.current_node.rect self.current_node.rect

View File

@ -2,13 +2,13 @@ use tui::layout::Rect;
use crate::tuice::{Bounds, Element, LayoutNode, TmpComponent}; use crate::tuice::{Bounds, Element, LayoutNode, TmpComponent};
pub fn build_layout_tree<Message>(area: Rect, root: &Element<'_, Message>) -> LayoutNode { pub fn build_layout_tree<Message>(rect: Rect, root: &Element<'_, Message>) -> LayoutNode {
let mut root_layout_node = LayoutNode::from_rect(area); let mut root_layout_node = LayoutNode::from_rect(rect);
let bounds = Bounds { let bounds = Bounds {
min_width: 0, min_width: 0,
min_height: 0, min_height: 0,
max_width: area.width, max_width: rect.width,
max_height: area.height, max_height: rect.height,
}; };
let _ = root.layout(bounds, &mut root_layout_node); let _ = root.layout(bounds, &mut root_layout_node);

View File

@ -1,10 +1,10 @@
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
use tui::layout::Rect; use tui::{backend::Backend, layout::Rect, Terminal};
use crate::tuice::Status; use crate::tuice::Status;
use super::{Application, Event, TmpComponent}; use super::{build_layout_tree, Application, Element, Event, TmpComponent};
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub enum RuntimeEvent<Message> { pub enum RuntimeEvent<Message> {
@ -13,10 +13,15 @@ pub enum RuntimeEvent<Message> {
Custom(Message), Custom(Message),
} }
pub(crate) fn launch<A: Application + 'static>( pub(crate) fn launch<A, B>(
mut application: A, receiver: Receiver<RuntimeEvent<A::Message>>, mut application: A, receiver: Receiver<RuntimeEvent<A::Message>>, terminal: &mut Terminal<B>,
) { ) -> anyhow::Result<()>
where
A: Application + 'static,
B: Backend,
{
let mut user_interface = application.view(); let mut user_interface = application.view();
draw(&mut user_interface, terminal)?;
while !application.is_terminated() { while !application.is_terminated() {
if let Ok(event) = receiver.recv() { if let Ok(event) = receiver.recv() {
@ -38,7 +43,7 @@ pub(crate) fn launch<A: Application + 'static>(
} }
user_interface = application.view(); user_interface = application.view();
// FIXME: Draw! draw(&mut user_interface, terminal)?;
} }
RuntimeEvent::Custom(message) => { RuntimeEvent::Custom(message) => {
application.update(message); application.update(message);
@ -48,6 +53,8 @@ pub(crate) fn launch<A: Application + 'static>(
height: _, height: _,
} => { } => {
user_interface = application.view(); user_interface = application.view();
// FIXME: Also nuke any cache and the like...
draw(&mut user_interface, terminal)?;
} }
} }
} else { } else {
@ -56,4 +63,21 @@ pub(crate) fn launch<A: Application + 'static>(
} }
application.destroy(); application.destroy();
Ok(())
}
fn draw<M, B>(user_interface: &mut Element<'_, M>, terminal: &mut Terminal<B>) -> anyhow::Result<()>
where
B: Backend,
{
terminal.draw(|frame| {
let rect = frame.size();
let layout = build_layout_tree(rect, &user_interface);
let context = super::DrawContext::root(&layout);
user_interface.draw(context, frame);
})?;
Ok(())
} }