1use std::io;
2use crossterm::event::{Event, KeyCode};
3use teng::components::Component;
4use teng::rendering::pixel::Pixel;
5use teng::rendering::render::Render;
6use teng::rendering::renderer::Renderer;
7use teng::{install_panic_handler, terminal_cleanup, terminal_setup, BreakingAction, Game, SetupInfo, SharedState, UpdateInfo};
8use teng::components::ui::{UiComponent, UiElement};
9
10struct MyWindow {
11 title_bar_height: usize,
12 width: usize,
13 height: usize,
14 text_box: String,
15 background_color: [u8; 3],
16}
17
18impl MyWindow {
19 fn new() -> Self {
20 let background_color = [rand::random::<u8>(), rand::random::<u8>(), rand::random::<u8>()];
21 Self {
22 title_bar_height: 1,
23 width: 20,
24 height: 10,
25 text_box: String::new(),
26 background_color,
27 }
28 }
29}
30
31impl UiElement for MyWindow {
32 fn is_hover_drag(&self, x: usize, y: usize) -> bool {
33 y < self.title_bar_height
34 }
35
36 fn is_resizing_drag(&self, x: usize, y: usize) -> bool {
37 x >= self.width - 1 && y >= self.height - 1
38 }
39
40 fn on_resize(&mut self, width: usize, height: usize, shared_state: &mut SharedState<()>) {
41 self.width = width;
42 self.height = height;
43 }
44
45 fn get_size(&self) -> (usize, usize) {
46 (self.width, self.height)
47 }
48
49 fn on_event(&mut self, event: Event, shared_state: &mut SharedState<()>) -> Option<BreakingAction> {
50 if let Event::Key(key_event) = event {
51 if let KeyCode::Char(c) = key_event.code {
52 self.text_box.push(c);
53 }
54 if key_event.code == KeyCode::Backspace {
55 self.text_box.pop();
56 }
57 if key_event.code == KeyCode::Enter {
58 self.text_box.push('\n');
59 }
60 }
61 None
62 }
63
64 fn render(&self, renderer: &mut dyn Renderer, depth_base: i32) {
65 let depth_text_box = depth_base + 1;
66 let depth_title_bar = depth_base + 2;
67
68 let pixel = Pixel::new(' ').with_bg_color(self.background_color);
69
70 for x in 0..self.width {
71 for y in 1..self.height {
72 renderer.render_pixel(x, y, pixel, depth_base);
73 }
74 }
75
76 self.text_box.render(renderer, 0, 1, depth_text_box);
78
79 for x in 0..self.width {
81 renderer.render_pixel(x, 0, Pixel::new(' ').with_bg_color([150, 150, 150]), depth_base);
82 }
83 "My Window".render(renderer, 0, 0, depth_title_bar);
84
85 let corner_expand_pixel = Pixel::new('⤡').with_bg_color([150, 150, 150]);
87 renderer.render_pixel(self.width - 1, self.height - 1, corner_expand_pixel, depth_text_box);
88 }
89}
90
91struct Setup;
92
93impl Component for Setup {
94 fn setup(&mut self, setup_info: &SetupInfo, shared_state: &mut SharedState<()>) {
95 let width = shared_state.display_info.width();
97 let height = shared_state.display_info.height();
98
99 shared_state.ui.add_window(30, 15, Box::new(MyWindow::new()));
100
101 }
102
103 fn update(&mut self, update_info: UpdateInfo, shared_state: &mut SharedState<()>) {
104 if shared_state.pressed_keys.did_press_char_ignore_case(' ') {
105 let width = shared_state.display_info.width();
106 let height = shared_state.display_info.height();
107
108 let anchor_x = rand::random::<usize>() % width;
109 let anchor_y = rand::random::<usize>() % height;
110
111 shared_state.ui.add_window(anchor_x, anchor_y, Box::new(MyWindow::new()));
112 }
113 }
114}
115
116fn main() -> io::Result<()> {
117 terminal_setup()?;
118 install_panic_handler();
119
120 let mut game = Game::new_with_custom_buf_writer();
121 game.install_recommended_components();
124 game.add_component(Box::new(UiComponent::new()));
125 game.add_component(Box::new(Setup));
126 game.run()?;
127
128 terminal_cleanup()?;
129
130 Ok(())
131}