product editor: grid layout
This commit is contained in:
parent
d8e8f763a6
commit
55eb594521
4 changed files with 160 additions and 65 deletions
|
@ -4,7 +4,7 @@ use {
|
|||
index::{IndexArea, IndexView},
|
||||
},
|
||||
std::sync::RwLock,
|
||||
std::{collections::HashMap, hash::Hash, sync::Arc},
|
||||
std::{collections::HashMap, hash::Hash, sync::Arc, ops::{Deref, DerefMut}},
|
||||
};
|
||||
|
||||
pub struct IndexBufferView<Key, Item>(Arc<RwLock<HashMap<Key, Item>>>)
|
||||
|
@ -36,6 +36,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct IndexBuffer<Key, Item>
|
||||
where
|
||||
Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||
|
@ -68,6 +69,27 @@ where
|
|||
self.port.0.outer()
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &Key) -> Option<Item> {
|
||||
self.data.read().unwrap().get(key).cloned()
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, key: &Key) -> MutableIndexAccess<Key, Item> {
|
||||
MutableIndexAccess {
|
||||
buf: self.clone(),
|
||||
key: key.clone(),
|
||||
val: self.get(key)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, key: Key, item: Option<Item>) {
|
||||
if let Some(item) = item {
|
||||
self.data.write().unwrap().insert(key.clone(), item);
|
||||
} else {
|
||||
self.data.write().unwrap().remove(&key);
|
||||
}
|
||||
self.port.notify(&IndexArea::Set(vec![key]));
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: Key, item: Item) {
|
||||
self.data.write().unwrap().insert(key.clone(), item);
|
||||
self.port.notify(&IndexArea::Set(vec![key]));
|
||||
|
@ -87,3 +109,48 @@ where
|
|||
self.port.notify(&IndexArea::Set(vec![key]));
|
||||
}
|
||||
}
|
||||
|
||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||
|
||||
pub struct MutableIndexAccess<Key, Item>
|
||||
where
|
||||
Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||
Item: Clone + Send + Sync + 'static,
|
||||
{
|
||||
buf: IndexBuffer<Key, Item>,
|
||||
key: Key,
|
||||
val: Option<Item>,
|
||||
}
|
||||
|
||||
impl<Key, Item> Deref for MutableIndexAccess<Key, Item>
|
||||
where
|
||||
Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||
Item: Clone + Send + Sync + 'static,
|
||||
{
|
||||
type Target = Option<Item>;
|
||||
|
||||
fn deref(&self) -> &Option<Item> {
|
||||
&self.val
|
||||
}
|
||||
}
|
||||
|
||||
impl<Key, Item> DerefMut for MutableIndexAccess<Key, Item>
|
||||
where
|
||||
Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||
Item: Clone + Send + Sync + 'static,
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.val
|
||||
}
|
||||
}
|
||||
|
||||
impl<Key, Item> Drop for MutableIndexAccess<Key, Item>
|
||||
where
|
||||
Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||
Item: Clone + Send + Sync + 'static,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.buf.update(self.key.clone(), self.val.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use {
|
|||
product::editor::ProductEditor,
|
||||
char_editor::CharEditor
|
||||
},
|
||||
cgmath::Vector2,
|
||||
cgmath::{Vector2, Point2},
|
||||
std::sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
|
@ -90,26 +90,46 @@ pub fn make_editor(ctx: Arc<RwLock<Context>>, t: &TypeLadder, depth: usize) -> A
|
|||
|
||||
} else if t[0] == c.type_term_from_str("( RGB )").unwrap() {
|
||||
Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
|
||||
.with_t("{ r: ")
|
||||
.with_n( vec![ ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap() ] )
|
||||
.with_t(", g: ")
|
||||
.with_n( vec![ ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap() ] )
|
||||
.with_t(", b: ")
|
||||
.with_n( vec![ ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap() ] )
|
||||
.with_t(" }")
|
||||
.with_t(Point2::new(0, 0), "{")
|
||||
.with_t(Point2::new(1, 1), "r: ")
|
||||
.with_n(Point2::new(2, 1), vec![ ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap() ] )
|
||||
.with_t(Point2::new(1, 2), "g: ")
|
||||
.with_n(Point2::new(2, 2), vec![ ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap() ] )
|
||||
.with_t(Point2::new(1, 3), "b: ")
|
||||
.with_n(Point2::new(2, 3), vec![ ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap() ] )
|
||||
.with_t(Point2::new(0, 4), " }")
|
||||
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
||||
|
||||
} else if t[0] == c.type_term_from_str("( Vec3i )").unwrap() {
|
||||
Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
|
||||
.with_t("{ x: ")
|
||||
.with_n( vec![ ctx.read().unwrap().type_term_from_str("( PosInt 10 BigEndian )").unwrap() ] )
|
||||
.with_t(", y: ")
|
||||
.with_n( vec![ ctx.read().unwrap().type_term_from_str("( PosInt 10 BigEndian )").unwrap() ] )
|
||||
.with_t(", z: ")
|
||||
.with_n( vec![ ctx.read().unwrap().type_term_from_str("( PosInt 10 BigEndian )").unwrap() ] )
|
||||
.with_t(" }")
|
||||
.with_t(Point2::new(0, 0), "{")
|
||||
.with_t(Point2::new(1, 1), "x: ")
|
||||
.with_n(Point2::new(2, 1), vec![ ctx.read().unwrap().type_term_from_str("( PosInt 10 BigEndian )").unwrap() ] )
|
||||
.with_t(Point2::new(1, 2), "y: ")
|
||||
.with_n(Point2::new(2, 2), vec![ ctx.read().unwrap().type_term_from_str("( PosInt 10 BigEndian )").unwrap() ] )
|
||||
.with_t(Point2::new(1, 3), "z: ")
|
||||
.with_n(Point2::new(2, 3), vec![ ctx.read().unwrap().type_term_from_str("( PosInt 10 BigEndian )").unwrap() ] )
|
||||
.with_t(Point2::new(0, 4), " }")
|
||||
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
||||
|
||||
} else if t[0] == c.type_term_from_str("( Json )").unwrap() {
|
||||
Arc::new(RwLock::new(
|
||||
PTYListEditor::<dyn TerminalTreeEditor + Send + Sync>::new(
|
||||
Box::new({
|
||||
let ctx = ctx.clone();
|
||||
move || {
|
||||
Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
|
||||
.with_n(Point2::new(0, 0), vec![ ctx.read().unwrap().type_term_from_str("( String )").unwrap() ] )
|
||||
.with_t(Point2::new(1, 0), ": ")
|
||||
.with_n(Point2::new(2, 0), vec![ ctx.read().unwrap().type_term_from_str("( Json )").unwrap() ] )
|
||||
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
||||
}
|
||||
}),
|
||||
SeqDecorStyle::VerticalSexpr,
|
||||
depth
|
||||
)
|
||||
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
||||
|
||||
} else if t[0] == c.type_term_from_str("( List Term )").unwrap() {
|
||||
Arc::new(RwLock::new(
|
||||
PTYListEditor::<dyn TerminalTreeEditor + Send + Sync>::new(
|
||||
|
@ -126,10 +146,15 @@ pub fn make_editor(ctx: Arc<RwLock<Context>>, t: &TypeLadder, depth: usize) -> A
|
|||
|
||||
} else { // else: term
|
||||
Arc::new(RwLock::new(
|
||||
ProductEditor::new(depth, ctx.clone())
|
||||
.with_n( vec![ c.type_term_from_str("( List Char )").unwrap() ] )
|
||||
.with_n( vec![ c.type_term_from_str("( List Term )").unwrap() ] )
|
||||
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
||||
PTYListEditor::new(
|
||||
Box::new(|| {
|
||||
Arc::new(RwLock::new(CharEditor::new()))
|
||||
}),
|
||||
SeqDecorStyle::DoubleQuote,
|
||||
depth
|
||||
)
|
||||
))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,19 +8,21 @@ use {
|
|||
sequence::{SequenceView},
|
||||
tree_nav::{TreeNav, TerminalTreeEditor, TreeNavResult},
|
||||
vec::{VecBuffer, MutableVecAccess},
|
||||
index::{buffer::{IndexBuffer, MutableIndexAccess}, IndexView},
|
||||
list::ListCursorMode,
|
||||
product::{segment::ProductEditorSegment},
|
||||
make_editor::make_editor
|
||||
},
|
||||
cgmath::Vector2,
|
||||
cgmath::{Vector2, Point2},
|
||||
std::sync::{Arc, RwLock},
|
||||
termion::event::{Event, Key},
|
||||
std::ops::{Deref, DerefMut}
|
||||
};
|
||||
|
||||
pub struct ProductEditor {
|
||||
segments: VecBuffer<ProductEditorSegment>,
|
||||
pub(super) n_indices: Vec<usize>,
|
||||
|
||||
segments: IndexBuffer<Point2<i16>, ProductEditorSegment>,
|
||||
pub(super) n_indices: Vec<Point2<i16>>,
|
||||
|
||||
pub(super) ctx: Arc<RwLock<Context>>,
|
||||
pub(super) cursor: Option<isize>,
|
||||
pub(super) depth: usize,
|
||||
|
@ -29,7 +31,7 @@ pub struct ProductEditor {
|
|||
impl ProductEditor {
|
||||
pub fn new(depth: usize, ctx: Arc<RwLock<Context>>) -> Self {
|
||||
ProductEditor {
|
||||
segments: VecBuffer::new(),
|
||||
segments: IndexBuffer::new(),
|
||||
n_indices: Vec::new(),
|
||||
ctx,
|
||||
cursor: None,
|
||||
|
@ -37,53 +39,52 @@ impl ProductEditor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn with_t(mut self, t: &str) -> Self {
|
||||
self.segments.push(ProductEditorSegment::T(t.to_string(), self.depth));
|
||||
pub fn with_t(mut self, pos: Point2<i16>, t: &str) -> Self {
|
||||
self.segments.insert(pos, ProductEditorSegment::T(t.to_string(), self.depth));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_n(mut self, n: TypeLadder) -> Self {
|
||||
let elem_idx = self.segments.len();
|
||||
self.segments.push(ProductEditorSegment::N{
|
||||
pub fn with_n(mut self, pos: Point2<i16>, n: TypeLadder) -> Self {
|
||||
self.segments.insert(pos, ProductEditorSegment::N{
|
||||
t: n,
|
||||
editor: None,
|
||||
cur_depth: 0
|
||||
});
|
||||
self.n_indices.push(elem_idx);
|
||||
self.n_indices.push(pos);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get_editor_element(&self, mut idx: isize) -> Option<ProductEditorSegment> {
|
||||
pub fn get_editor_segment(&self, mut idx: isize) -> ProductEditorSegment {
|
||||
idx = crate::modulo(idx, self.n_indices.len() as isize);
|
||||
if let Some(i) = self.n_indices.get(idx as usize) {
|
||||
Some(self.segments.get(*i))
|
||||
if let Some(pos) = self.n_indices.get(idx as usize) {
|
||||
self.segments.get(pos).unwrap()
|
||||
} else {
|
||||
None
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_editor_element_mut(&mut self, mut idx: isize) -> Option<MutableVecAccess<ProductEditorSegment>> {
|
||||
pub fn get_editor_segment_mut(&mut self, mut idx: isize) -> MutableIndexAccess<Point2<i16>, ProductEditorSegment> {
|
||||
idx = crate::modulo(idx, self.n_indices.len() as isize);
|
||||
if let Some(i) = self.n_indices.get(idx as usize) {
|
||||
Some(self.segments.get_mut(*i))
|
||||
if let Some(pos) = self.n_indices.get(idx as usize) {
|
||||
self.segments.get_mut(pos)
|
||||
} else {
|
||||
None
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cur_element(&self) -> Option<ProductEditorSegment> {
|
||||
self.get_editor_element(self.cursor?)
|
||||
pub fn get_cur_segment(&self) -> Option<ProductEditorSegment> {
|
||||
Some(self.get_editor_segment(self.cursor?))
|
||||
}
|
||||
|
||||
pub fn get_cur_element_mut(&mut self) -> Option<MutableVecAccess<ProductEditorSegment>> {
|
||||
self.get_editor_element_mut(self.cursor?)
|
||||
pub fn get_cur_segment_mut(&mut self) -> Option<MutableIndexAccess<Point2<i16>, ProductEditorSegment>> {
|
||||
Some(self.get_editor_segment_mut(self.cursor?))
|
||||
}
|
||||
|
||||
pub fn get_editor(&self, idx: isize) -> Option<Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>> {
|
||||
if let Some(ProductEditorSegment::N{ t: _, editor, cur_depth: _ }) = self.get_editor_element(idx) {
|
||||
if let ProductEditorSegment::N{ t: _, editor, cur_depth: _ } = self.get_editor_segment(idx) {
|
||||
editor
|
||||
} else {
|
||||
None
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,14 +104,13 @@ impl TerminalEditor for ProductEditor {
|
|||
let ctx = self.ctx.clone();
|
||||
self.segments
|
||||
.get_port()
|
||||
.to_sequence()
|
||||
.map(move |e: &ProductEditorSegment| { e.get_view(ctx.clone()) })
|
||||
.to_grid_horizontal()
|
||||
.map_item(move |_pos, e: &ProductEditorSegment| { e.get_view(ctx.clone()) })
|
||||
.flatten()
|
||||
}
|
||||
|
||||
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||
if let Some(ProductEditorSegment::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
|
||||
if let Some(mut segment) = self.get_cur_segment_mut().as_deref_mut() {
|
||||
if let Some(ProductEditorSegment::N{ t, editor, cur_depth }) = segment.deref_mut() {
|
||||
*cur_depth = self.get_cursor().tree_addr.len();
|
||||
if let Some(e) = editor.clone() {
|
||||
let mut ce = e.write().unwrap();
|
||||
|
@ -141,6 +141,9 @@ impl TerminalEditor for ProductEditor {
|
|||
*cur_depth = self.get_cursor().tree_addr.len()+1;
|
||||
x
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
} else {
|
||||
TerminalEditorResult::Exit
|
||||
}
|
||||
|
|
|
@ -52,8 +52,8 @@ impl TreeNav for ProductEditor {
|
|||
}
|
||||
|
||||
fn goto(&mut self, mut c: TreeCursor) -> TreeNavResult {
|
||||
if let Some(mut element) = self.get_cur_element_mut() {
|
||||
if let ProductEditorSegment::N{ t: _t, editor, cur_depth } = element.deref_mut() {
|
||||
if let Some(mut segment) = self.get_cur_segment_mut() {
|
||||
if let Some(ProductEditorSegment::N{ t: _t, editor, cur_depth }) = segment.deref_mut() {
|
||||
if let Some(e) = editor {
|
||||
let mut e = e.write().unwrap();
|
||||
e.goto(TreeCursor::none());
|
||||
|
@ -65,8 +65,8 @@ impl TreeNav for ProductEditor {
|
|||
if c.tree_addr.len() > 0 {
|
||||
self.cursor = Some(crate::modulo(c.tree_addr.remove(0), self.n_indices.len() as isize));
|
||||
|
||||
if let Some(mut element) = self.get_cur_element_mut() {
|
||||
if let ProductEditorSegment::N{ t: _t, editor, cur_depth } = element.deref_mut() {
|
||||
if let Some(mut element) = self.get_cur_segment_mut() {
|
||||
if let Some(ProductEditorSegment::N{ t: _t, editor, cur_depth }) = element.deref_mut() {
|
||||
if let Some(e) = editor {
|
||||
e.write().unwrap().goto(c.clone());
|
||||
}
|
||||
|
@ -89,8 +89,8 @@ impl TreeNav for ProductEditor {
|
|||
if direction.y > 0 {
|
||||
self.cursor = Some(0);
|
||||
|
||||
if let Some(mut element) = self.get_cur_element_mut() {
|
||||
if let ProductEditorSegment::N{ t, editor, cur_depth } = element.deref_mut() {
|
||||
if let Some(mut element) = self.get_cur_segment_mut() {
|
||||
if let Some(ProductEditorSegment::N{ t, editor, cur_depth }) = element.deref_mut() {
|
||||
*cur_depth = 1;
|
||||
}
|
||||
}
|
||||
|
@ -106,8 +106,8 @@ impl TreeNav for ProductEditor {
|
|||
1 => {
|
||||
if direction.y > 0 {
|
||||
// dn
|
||||
if let Some(mut element) = self.get_cur_element_mut() {
|
||||
if let ProductEditorSegment::N{ t, editor, cur_depth } = element.deref_mut() {
|
||||
if let Some(mut element) = self.get_cur_segment_mut() {
|
||||
if let Some(ProductEditorSegment::N{ t, editor, cur_depth }) = element.deref_mut() {
|
||||
if let Some(e) = editor {
|
||||
let mut e = e.write().unwrap();
|
||||
e.goby(direction);
|
||||
|
@ -125,8 +125,8 @@ impl TreeNav for ProductEditor {
|
|||
TreeNavResult::Continue
|
||||
} else if direction.y < 0 {
|
||||
// up
|
||||
if let Some(mut element) = self.get_cur_element_mut() {
|
||||
if let ProductEditorSegment::N{ t, editor, cur_depth } = element.deref_mut() {
|
||||
if let Some(mut element) = self.get_cur_segment_mut() {
|
||||
if let Some(ProductEditorSegment::N{ t, editor, cur_depth }) = element.deref_mut() {
|
||||
*cur_depth = 0;
|
||||
}
|
||||
}
|
||||
|
@ -137,14 +137,14 @@ impl TreeNav for ProductEditor {
|
|||
if (cur.tree_addr[0]+direction.x >= 0) &&
|
||||
(cur.tree_addr[0]+direction.x < self.n_indices.len() as isize)
|
||||
{
|
||||
if let Some(mut element) = self.get_cur_element_mut() {
|
||||
if let ProductEditorSegment::N{ t, editor, cur_depth } = element.deref_mut() {
|
||||
if let Some(mut element) = self.get_cur_segment_mut() {
|
||||
if let Some(ProductEditorSegment::N{ t, editor, cur_depth }) = element.deref_mut() {
|
||||
*cur_depth = 0;
|
||||
}
|
||||
}
|
||||
self.cursor = Some(cur.tree_addr[0] + direction.x);
|
||||
if let Some(mut element) = self.get_cur_element_mut() {
|
||||
if let ProductEditorSegment::N{ t, editor, cur_depth } = element.deref_mut() {
|
||||
if let Some(mut element) = self.get_cur_segment_mut() {
|
||||
if let Some(ProductEditorSegment::N{ t, editor, cur_depth }) = element.deref_mut() {
|
||||
*cur_depth = 1;
|
||||
}
|
||||
}
|
||||
|
@ -156,8 +156,8 @@ impl TreeNav for ProductEditor {
|
|||
}
|
||||
}
|
||||
depth => {
|
||||
if let Some(mut element) = self.get_cur_element_mut() {
|
||||
if let ProductEditorSegment::N{ t, editor, cur_depth } = element.deref_mut() {
|
||||
if let Some(mut element) = self.get_cur_segment_mut() {
|
||||
if let Some(ProductEditorSegment::N{ t, editor, cur_depth }) = element.deref_mut() {
|
||||
if let Some(e) = editor {
|
||||
let mut ce = e.write().unwrap();
|
||||
//\\//\\//\\//\\
|
||||
|
|
Loading…
Reference in a new issue