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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
#![deny(warnings)] use std::any::Any; use std::cmp::{min, max}; use std::ops::Range; use tuifw_screen_base::*; use tuifw_screen_base::Screen as base_Screen; use unicode_segmentation::UnicodeSegmentation; pub struct Screen { buf: Vec<(char, Color, Option<Color>, Attr)>, out: Vec<(char, Color, Option<Color>, Attr)>, size: Vector, invalidated: Rect, cursor: Option<Point>, } impl Screen { pub fn new(size: Vector) -> Self { let mut s = Screen { buf: Vec::new(), out: Vec::new(), size: Vector::null(), invalidated: Rect { tl: Point { x: 0, y: 0 }, size: Vector::null() }, cursor: None, }; s.resize(size); s } fn resize(&mut self, out_size: Vector) { self.buf.resize(out_size.rect_area() as usize, (' ', Color::White, None, Attr::empty())); self.out.resize(out_size.rect_area() as usize, (' ', Color::White, None, Attr::empty())); self.size = out_size; self.invalidated = Rect { tl: Point { x: 0, y: 0 }, size: self.size }; } } impl base_Screen for Screen { fn size(&self) -> Vector { self.size } fn out( &mut self, p: Point, fg: Color, bg: Option<Color>, attr: Attr, text: &str, hard: Range<i16>, soft: Range<i16> ) -> Range<i16> { assert!(p.y >= 0 && p.y < self.size().y); assert!(hard.start >= 0 && hard.end > hard.start && hard.end <= self.size().x); assert!(soft.start >= 0 && soft.end > soft.start && soft.end <= self.size().x); let text_end = if soft.end <= p.x { return 0 .. 0 } else { soft.end.saturating_sub(p.x) }; let text_start = if soft.start <= p.x { 0 } else { soft.start.saturating_sub(p.x) }; let size = self.size; let line = (p.y as u16 as usize) * (size.x as u16 as usize); let line = &mut self.buf[line .. line + size.x as u16 as usize]; let mut before_hard_start = min(p.x, hard.start); let mut before_text_start = 0i16; let x0 = max(hard.start, p.x); let mut x = x0; for g in text.graphemes(true).map(|g| g.chars().next().unwrap()).take(text_end as u16 as usize) { if x >= hard.end { break; } let visible_1 = if before_text_start < text_start { before_text_start += 1; false } else { true }; let visible_2 = if before_hard_start < hard.start { before_hard_start += 1; false } else { true }; if visible_1 && visible_2 { let col = &mut line[x as u16 as usize]; *col = (g, fg, bg, attr); } x += 1; } self.invalidated = self.invalidated .union(Rect::with_tl_br(Point { x: x0, y: p.y }, Point { x, y: p.y + 1 })) .unwrap().right().unwrap() ; x0 .. x } fn update(&mut self, cursor: Option<Point>, _wait: bool) -> Result<Option<Event>, Box<dyn Any>> { for y in self.invalidated.t() .. self.invalidated.b() { let line = (y as u16 as usize) * (self.size.x as u16 as usize); let s = line + self.invalidated.l() as u16 as usize; let f = line + self.invalidated.r() as u16 as usize; (&mut self.out[s .. f]).copy_from_slice(&self.buf[s .. f]); } self.invalidated.size = Vector::null(); self.cursor = cursor.and_then(|cursor| { if (Rect { tl: Point { x: 0, y: 0 }, size: self.size() }).contains(cursor) { Some(cursor) } else { None } }); Ok(None) } }