A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/menu/generic.rs')
-rw-r--r--src/menu/generic.rs129
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
+ }
+}