summaryrefslogtreecommitdiffstats
path: root/src/tuice/runtime.rs
blob: 1666c21dac8bae5c37ddeab2b7322edf20969a4b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use std::sync::mpsc::Receiver;

use tui::{backend::Backend, layout::Rect, Terminal};

use crate::tuice::Status;

use super::{build_layout_tree, Application, Element, Event, TmpComponent};

#[derive(Clone, Copy, Debug)]
pub enum RuntimeEvent<Message> {
    UserInterface(Event),
    Resize { width: u16, height: u16 },
    Custom(Message),
}

pub(crate) fn launch<A, B>(
    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();
    draw(&mut user_interface, terminal)?;

    while !application.is_terminated() {
        if let Ok(event) = receiver.recv() {
            match event {
                RuntimeEvent::UserInterface(event) => {
                    let mut messages = vec![];

                    let rect = Rect::default(); // FIXME: TEMP
                    match user_interface.on_event(rect, event, &mut messages) {
                        Status::Captured => {}
                        Status::Ignored => {
                            application.global_event_handler(event, &mut messages);
                        }
                    }

                    for msg in messages {
                        debug!("Message: {:?}", msg); // FIXME: Remove this debug line!
                        application.update(msg);
                    }

                    user_interface = application.view();
                    draw(&mut user_interface, terminal)?;
                }
                RuntimeEvent::Custom(message) => {
                    application.update(message);
                }
                RuntimeEvent::Resize {
                    width: _,
                    height: _,
                } => {
                    user_interface = application.view();
                    // FIXME: Also nuke any cache and the like...
                    draw(&mut user_interface, terminal)?;
                }
            }
        } else {
            break;
        }
    }

    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(())
}