Skip to main content

screens/
screens.rs

1use std::sync::mpsc;
2
3use ascii_assets::TerminalChar;
4use common_stdx::Rect;
5use crossterm::{event::KeyCode, terminal::size};
6use log::info;
7use ltrender::{
8    DrawObjectBuilder, Renderer, ScreenKey,
9    display_screen::AreaRect,
10    drawable_register::ObjectLifetime,
11    error::AppError,
12    init_logger, init_terminal,
13    input_handler::{
14        hook::InputButton,
15        manager::{MouseButtons, TargetScreen},
16    },
17    rendering::{
18        render_handle::RenderHandle,
19        render_thread::start_renderer_with_input,
20        renderer::{Instant, RenderModeBehavior},
21    },
22    terminal_buffer::{
23        buffer_and_celldrawer::{CrosstermCellDrawer, DefaultScreenBuffer},
24        standard_drawables::{rect_drawable::ScreenFitType, videostream_drawable::StreamFrame},
25    },
26};
27
28pub struct AdjustableScreens {
29    screens: Vec<Vec<ScreenKey>>,
30    current: usize,
31}
32
33impl AdjustableScreens {
34    pub fn new_uniform_grid<M>(
35        amount_screens_x: usize,
36        amount_screens_y: usize,
37        r: &mut RenderHandle<M>,
38    ) -> Result<Self, AppError>
39    where
40        M: RenderModeBehavior,
41    {
42        let mut screens = Vec::new();
43        for _ in 0..amount_screens_y {
44            let mut screen_row = Vec::new();
45            for _ in 0..amount_screens_x {
46                let screen =
47                    r.create_screen(AreaRect::FromPoints((0, 0).into(), (0, 0).into()), 0)?;
48                screen_row.push(screen);
49            }
50            screens.push(screen_row);
51        }
52        let ad_screens = AdjustableScreens {
53            screens,
54            current: 0,
55        };
56        ad_screens.place_screens_uniformly(r)?;
57        Ok(ad_screens)
58    }
59    pub fn place_screens_uniformly<M>(&self, r: &mut RenderHandle<M>) -> Result<(), AppError>
60    where
61        M: RenderModeBehavior,
62    {
63        let current_size = r.get_terminal_size()?;
64        if current_size.0 <= self.screens.len() as u16
65            || current_size.1 <= self.screens[0].len() as u16
66        {
67            return Ok(());
68        }
69        let screens_each_height = current_size.1 as usize / self.screens.len();
70        for (i, screen_row) in &mut self.screens.iter().enumerate() {
71            let screens_each_width = current_size.0 as usize / screen_row.len();
72            for (j, screen) in screen_row.iter().enumerate() {
73                r.change_screen_area(
74                    *screen,
75                    AreaRect::FromPoints(
76                        (j * screens_each_width, i * screens_each_height).into(),
77                        (
78                            (j + 1) * screens_each_width - 1,
79                            (i + 1) * screens_each_height - 1,
80                        )
81                            .into(),
82                    ),
83                )?;
84            }
85        }
86        Ok(())
87    }
88}
89
90impl Iterator for AdjustableScreens {
91    type Item = ScreenKey;
92
93    fn next(&mut self) -> Option<Self::Item> {
94        let mut count = 0;
95
96        for row in &self.screens {
97            for &screen_id in row {
98                if count == self.current {
99                    self.current += 1;
100                    return Some(screen_id);
101                }
102                count += 1;
103            }
104        }
105
106        None
107    }
108}
109
110const WIDTH: usize = 7;
111const HEIGHT: usize = 7;
112
113pub fn main() -> Result<(), AppError> {
114    init_terminal!();
115    init_logger("./screens_showcase.log")?;
116
117    let (cols, rows) = size()?;
118    let renderer = Renderer::<DefaultScreenBuffer<CrosstermCellDrawer>, Instant>::create_renderer(
119        (cols, rows),
120    );
121    let (mut r, ev_handler, _ev_manager) = start_renderer_with_input(renderer);
122    r.set_update_interval(1)?;
123
124    let mut hook = ev_handler.create_hook();
125
126    let mut ad_screens = AdjustableScreens::new_uniform_grid(WIDTH, HEIGHT, &mut r)?;
127
128    for screen in &mut ad_screens {
129        let builder = DrawObjectBuilder::default();
130        let d_key = builder
131            .layer(100)
132            .rect_drawable(|r| {
133                r.border_style(
134                ltrender::terminal_buffer::standard_drawables::rect_drawable::BorderStyle::Custom {
135                    top: TerminalChar::from_char('T'),
136                    bottom: TerminalChar::from_char('B'),
137                    left: TerminalChar::from_char('L'),
138                    right: TerminalChar::from_char('R'),
139                },
140            )
141            .border_thickness(1)
142            .fill_style(' ')
143            .rect(Rect::from_coords(0, 0, 2, 2))
144            .screen_fit(ScreenFitType::Full)
145            })?
146            .add_lifetime(ObjectLifetime::ExplicitRemove)
147            .screen(screen)
148            .build_and_register(&mut r)?;
149        info!("manually rendering drawable: {:?}", d_key);
150        r.render_drawable(d_key)?;
151    }
152
153    let (s, recv) = mpsc::channel();
154    let builder = DrawObjectBuilder::default();
155    let text_stream = builder
156        .layer(200)
157        .videostream_drawable(|b| b.position((0, 0)).recv(recv))?
158        .add_lifetime(ObjectLifetime::ExplicitRemove)
159        .screen(0)
160        .build_and_register(&mut r)?;
161    let callback_hook = ev_handler.create_hook();
162    let callback_renderh: RenderHandle<Instant> = r.clone();
163    hook.on_mouse_button_press(MouseButtons::Left, move |_| {
164        if let TargetScreen::Screen(id) = callback_hook.current_selected_screen() {
165            let msg = format!("selected_screen: {}", id);
166            info!("{}", msg);
167            let mut data = Vec::new();
168            for chr in msg.chars() {
169                data.push(Some(TerminalChar::from_char(chr)));
170            }
171            let _ = s.send(StreamFrame {
172                size: (data.len() as u16, 1),
173                data,
174            });
175            let _ = callback_renderh.render_drawable(text_stream);
176        }
177    })?;
178    loop {
179        if hook.is_pressed(InputButton::Key(KeyCode::Char('c'))) {
180            info!("breaking out of the loop");
181            break;
182        }
183
184        let cur_size = size()?;
185        let rendered_size = r.get_terminal_size()?;
186        if cur_size != rendered_size {
187            info!(
188                "redrawing with cur_size: {:?}, rendered: {:?}",
189                cur_size, rendered_size
190            );
191            r.handle_resize(cur_size)?;
192            ad_screens.place_screens_uniformly(&mut r)?;
193        }
194    }
195    restore_terminal()?;
196    info!("returning with ok");
197    Ok(())
198}