A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/menu/generic.rs')
| -rw-r--r-- | src/menu/generic.rs | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/src/menu/generic.rs b/src/menu/generic.rs new file mode 100644 index 0000000..ba48d76 --- /dev/null +++ b/src/menu/generic.rs @@ -0,0 +1,129 @@ +use std::fmt::Debug; +use std::path::Path; + +use Default::default; +use dsb::Cell; + +use crate::menu::{Key, back, filter, next, score}; +use crate::text::TextArea; + +pub struct GenericMenu<T: MenuData> { + pub data: T::Data, + pub tedit: TextArea, + pub selection: usize, + pub vo: usize, +} +impl<T: MenuData<Data: Clone>> Clone for GenericMenu<T> { + fn clone(&self) -> Self { + Self { + data: self.data.clone(), + tedit: self.tedit.clone(), + selection: self.selection.clone(), + vo: self.vo.clone(), + } + } +} +impl<T: MenuData<Data: Default>> Default for GenericMenu<T> { + fn default() -> Self { + Self { + data: default(), + tedit: default(), + selection: default(), + vo: default(), + } + } +} +impl<T: MenuData<Data: Debug>> Debug for GenericMenu<T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct(&format!( + "GenericMenu<{}>", + std::any::type_name::<T>() + )) + .field("data", &self.data) + .field("tedit", &self.tedit) + .field("selection", &self.selection) + .field("vo", &self.vo) + .finish() + } +} +pub trait MenuData { + const HEIGHT: usize = 30; + type Data; + type Element<'a>: Key<'a>; + + fn gn<'a>( + x: &'a Self::Data, + ) -> impl Iterator<Item = Self::Element<'a>>; + fn r( + data: &'_ Self::Data, + elem: Self::Element<'_>, + workspace: &Path, + columns: usize, + selected: bool, + indices: &[u32], + to: &mut Vec<Cell>, + ); + fn filter_c<'a>( + x: &'a Self::Data, + f: &str, + ) -> impl Iterator<Item = Self::Element<'a>> { + filter(Self::gn(x), f) + } + fn score_c<'a>( + x: impl Iterator<Item = Self::Element<'a>>, + f: &str, + ) -> Vec<(u32, Self::Element<'a>, Vec<u32>)> { + score(x, f) + } +} + +impl<T: MenuData> GenericMenu<T> { + fn f(&self) -> String { + self.tedit.rope.to_string() + } + pub fn next(&mut self) + where + [(); T::HEIGHT]:, + { + let n = T::filter_c(&self.data, &self.f()).count(); + // coz its bottom up + back::<{ T::HEIGHT }>(n, &mut self.selection, &mut self.vo); + } + + pub fn sel(&self) -> T::Element<'_> { + let f = self.f(); + T::score_c(T::filter_c(&self.data, &f), &f) + .swap_remove(self.selection) + .1 + } + + pub fn back(&mut self) + where + [(); T::HEIGHT]:, + { + let n = T::filter_c(&self.data, &self.f()).count(); + next::<{ T::HEIGHT }>(n, &mut self.selection, &mut self.vo); + } + pub fn cells(&self, c: usize, ws: &Path) -> Vec<Cell> { + let f = self.f(); + let mut out = vec![]; + let v = T::score_c(T::filter_c(&self.data, &f), &f); + let vlen = v.len(); + let i = + v.into_iter().zip(0..vlen).skip(self.vo).take(T::HEIGHT).rev(); + + i.for_each(|((_, x, indices), i)| { + T::r( + &self.data, + x, + ws, + c, + i == self.selection, + &indices, + &mut out, + ) + }); + + out + } +} |