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}