diff --git a/src/ui.rs b/src/ui.rs index c0acdd8..14ad1fc 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,4 +1,5 @@ mod chat; +mod chat2; mod euph; mod input; mod rooms; diff --git a/src/ui/chat2.rs b/src/ui/chat2.rs new file mode 100644 index 0000000..25a94de --- /dev/null +++ b/src/ui/chat2.rs @@ -0,0 +1 @@ +mod blocks; diff --git a/src/ui/chat2/blocks.rs b/src/ui/chat2/blocks.rs new file mode 100644 index 0000000..0705cf8 --- /dev/null +++ b/src/ui/chat2/blocks.rs @@ -0,0 +1,223 @@ +//! Common rendering logic. + +use std::collections::{vec_deque, VecDeque}; + +use toss::widgets::Predrawn; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Range { + pub top: T, + pub bottom: T, +} + +impl Range { + pub fn new(top: T, bottom: T) -> Self { + Self { top, bottom } + } +} + +impl Range { + pub fn shifted(self, delta: i32) -> Self { + Self::new(self.top + delta, self.bottom + delta) + } + + pub fn with_top(self, top: i32) -> Self { + self.shifted(top - self.top) + } + + pub fn with_bottom(self, bottom: i32) -> Self { + self.shifted(bottom - self.bottom) + } +} + +pub struct Block { + id: Id, + widget: Predrawn, + focus: Range, + can_be_cursor: bool, +} + +impl Block { + pub fn new(id: Id, widget: Predrawn, can_be_cursor: bool) -> Self { + let height: i32 = widget.size().height.into(); + Self { + id, + widget, + focus: Range::new(0, height), + can_be_cursor, + } + } + + pub fn id(&self) -> &Id { + &self.id + } + + pub fn into_widget(self) -> Predrawn { + self.widget + } + + fn height(&self) -> i32 { + self.widget.size().height.into() + } + + pub fn set_focus(&mut self, focus: Range) { + assert!(0 <= focus.top); + assert!(focus.top <= focus.bottom); + assert!(focus.bottom <= self.height()); + self.focus = focus; + } + + pub fn focus(&self, range: Range) -> Range { + Range::new(range.top + self.focus.top, range.top + self.focus.bottom) + } + + pub fn can_be_cursor(&self) -> bool { + self.can_be_cursor + } +} + +pub struct Blocks { + blocks: VecDeque>, + range: Range, + end: Range, +} + +impl Blocks { + pub fn new(at: i32) -> Self { + Self { + blocks: VecDeque::new(), + range: Range::new(at, at), + end: Range::new(false, false), + } + } + + pub fn range(&self) -> Range { + self.range + } + + pub fn end(&self) -> Range { + self.end + } + + pub fn iter(&self) -> Iter<'_, Id> { + Iter { + iter: self.blocks.iter(), + range: self.range, + } + } + + pub fn into_iter(self) -> IntoIter { + IntoIter { + iter: self.blocks.into_iter(), + range: self.range, + } + } + + // TODO Remove index from search result + pub fn find_block(&self, id: &Id) -> Option<(Range, &Block)> + where + Id: Eq, + { + self.iter().find(|(_, block)| block.id == *id) + } + + pub fn push_top(&mut self, block: Block) { + assert!(!self.end.top); + self.range.top -= block.height(); + self.blocks.push_front(block); + } + + pub fn push_bottom(&mut self, block: Block) { + assert!(!self.end.bottom); + self.range.bottom += block.height(); + self.blocks.push_back(block); + } + + pub fn append_top(&mut self, other: Self) { + assert!(!self.end.top); + assert!(!other.end.bottom); + for block in other.blocks.into_iter().rev() { + self.push_top(block); + } + self.end.top = other.end.top; + } + + pub fn append_bottom(&mut self, other: Self) { + assert!(!self.end.bottom); + assert!(!other.end.top); + for block in other.blocks { + self.push_bottom(block); + } + self.end.bottom = other.end.bottom; + } + + pub fn end_top(&mut self) { + self.end.top = true; + } + + pub fn end_bottom(&mut self) { + self.end.bottom = true; + } + + pub fn shift(&mut self, delta: i32) { + self.range = self.range.shifted(delta); + } + + pub fn set_top(&mut self, top: i32) { + self.shift(top - self.range.top); + } + + pub fn set_bottom(&mut self, bottom: i32) { + self.shift(bottom - self.range.bottom); + } +} + +pub struct Iter<'a, Id> { + iter: vec_deque::Iter<'a, Block>, + range: Range, +} + +impl<'a, Id> Iterator for Iter<'a, Id> { + type Item = (Range, &'a Block); + + fn next(&mut self) -> Option { + let block = self.iter.next()?; + let range = Range::new(self.range.top, self.range.top + block.height()); + self.range.top = range.bottom; + Some((range, block)) + } +} + +impl DoubleEndedIterator for Iter<'_, Id> { + fn next_back(&mut self) -> Option { + let block = self.iter.next_back()?; + let range = Range::new(self.range.bottom - block.height(), self.range.bottom); + self.range.bottom = range.top; + Some((range, block)) + } +} + +pub struct IntoIter { + iter: vec_deque::IntoIter>, + range: Range, +} + +impl Iterator for IntoIter { + type Item = (Range, Block); + + fn next(&mut self) -> Option { + let block = self.iter.next()?; + let range = Range::new(self.range.top, self.range.top + block.height()); + self.range.top = range.bottom; + Some((range, block)) + } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + let block = self.iter.next_back()?; + let range = Range::new(self.range.bottom - block.height(), self.range.bottom); + self.range.bottom = range.top; + Some((range, block)) + } +}