use std::vec; use std::vec::Vec; use crate::components::Component; use crate::framebuffer::{ Dimensions, Point }; use crate::themes::ThemeInfo; use crate::messages::WindowMessage; use crate::window_manager::DrawInstructions; use crate::utils::calc_actual_lines; const MONO_WIDTH: u8 = 10; const LINE_HEIGHT: usize = 18; pub struct Paragraph { name_: String, actual_lines: Vec<(bool, usize, String)>, //first, line #, actual line top_left: Point, size: Dimensions, line_pos: usize, key_return: T, } impl Component for Paragraph { fn handle_message(&mut self, message: WindowMessage) -> Option { if let WindowMessage::KeyPress(key_press) = message { if key_press.key == 'j' { //down if self.line_pos != self.actual_lines.len() - 1 { self.line_pos += 1; } Some(self.key_return) } else if key_press.key == 'k' { //up if self.line_pos != 0 { self.line_pos -= 1; } Some(self.key_return) } else { None } } else { None } } fn draw(&self, theme_info: &ThemeInfo) -> Vec { let mut instructions = Vec::new(); let max_lines = self.size[1] / LINE_HEIGHT; let mut start_y = self.top_left[1]; for line in self.actual_lines.iter().skip(self.line_pos).take(max_lines) { instructions.push(DrawInstructions::Text([self.top_left[0], start_y], vec!["times-new-romono".to_string()], line.2.clone(), theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH))); start_y += LINE_HEIGHT; } instructions } //properties fn focusable(&self) -> bool { true } fn clickable(&self) -> bool { false } fn name(&self) -> &String { &self.name_ } } impl Paragraph { pub fn new(name_: String, top_left: Point, size: Dimensions, text: String, key_return: T) -> Self { let mut s = Self { name_, actual_lines: Vec::new(), top_left, size, line_pos: 0, key_return, }; s.new_text(text); s } pub fn new_text(&mut self, text: String) { let max_chars_per_line = self.size[0] / MONO_WIDTH as usize; let lines: Vec = text.split("\n").map(|s| s.to_string()).collect(); self.actual_lines = calc_actual_lines(lines.iter(), max_chars_per_line, true); } }