Implement swapping panels

This commit is contained in:
Condorra 2024-11-28 22:28:53 +11:00
parent b36bcbf2ac
commit 13225859a1
3 changed files with 103 additions and 0 deletions

View File

@ -227,6 +227,7 @@ pub fn install_lua_globals(
register_command!(cmd_list_logs, "listlogs");
register_command!(mud_log, "log");
register_command!(panel_merge);
register_command!(panel_swap);
register_command!(sendmud_raw);
register_stateless_command!(storage);
register_command!(tick);

View File

@ -290,6 +290,32 @@ pub fn panel_merge<'gc>(
})
}
pub fn panel_swap<'gc>(
ctx: Context<'gc>,
global_memo: &GlobalMemoCell,
global_layout: &UseStateSetter<GlobalLayoutCell>,
) -> Callback<'gc> {
let global_layout = global_layout.clone();
let global_memo = global_memo.clone();
Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
let path1: String = stack.from_front(ctx)?;
let path2: String = stack.from_front(ctx)?;
let new_splits = global_memo
.layout
.borrow()
.term_splits
.swap(&path1, &path2)
.map_err(|e| e.into_value(ctx))?;
let new_layout = Rc::new(GlobalLayoutState {
term_splits: new_splits.clone(),
..(*(global_memo.layout.borrow().as_ref())).clone()
});
global_layout.set(new_layout.clone());
*(global_memo.layout.borrow_mut()) = new_layout;
Ok(piccolo::CallbackReturn::Return)
})
}
pub fn try_unwrap_frame<'gc>(
ctx: Context<'gc>,
value: &Value<'gc>,

View File

@ -112,6 +112,31 @@ impl TermSplit {
}
}
pub fn get_at_pathstr(&self, pathstr: &str) -> Result<&Self, String> {
self.get_at_pathstr_vec(&pathstr.chars().collect::<Vec<char>>())
}
fn get_at_pathstr_vec(&self, pathstr: &[char]) -> Result<&Self, String> {
match self {
TermSplit::Horizontal { left, right } => match pathstr.split_first() {
None => Ok(self),
Some(('l', path_rest)) => left.get_at_pathstr_vec(path_rest),
Some(('r', path_rest)) => right.get_at_pathstr_vec(path_rest),
Some((c, path_rest)) => Err(format!("In split path, found {} before {}, which was unexpected for a horizontal split", c, path_rest.iter().collect::<String>()))
},
TermSplit::Vertical { top, bottom } => match pathstr.split_first() {
None => Ok(self),
Some(('t', path_rest)) => top.get_at_pathstr_vec(path_rest),
Some(('b', path_rest)) => bottom.get_at_pathstr_vec(path_rest),
Some((c, path_rest)) => Err(format!("In split path, found {} before {}, which was unexpected for a vertical split", c, path_rest.iter().collect::<String>()))
},
TermSplit::Term { .. } => match pathstr.split_first() {
None => Ok(self),
Some(_) => Err(format!("In split path, found trailing junk {} after addressing terminal", pathstr.iter().collect::<String>()))
}
}
}
pub fn hsplit(&self, pathstr: &str, new_frame: FrameId) -> Result<TermSplit, String> {
let new = self.modify_at_pathstr(pathstr, move |n| {
Ok(TermSplit::Horizontal {
@ -143,6 +168,17 @@ impl TermSplit {
TermSplit::Vertical { top, .. } => Ok((**top).clone()),
})
}
pub fn swap(&self, pathstr1: &str, pathstr2: &str) -> Result<TermSplit, String> {
let split1 = self.get_at_pathstr(pathstr1)?;
let split2 = self.get_at_pathstr(pathstr2)?;
let new = self
.modify_at_pathstr(pathstr1, |_t| Ok(split2.clone()))?
.modify_at_pathstr(pathstr2, |_t| Ok(split1.clone()))?;
// It can fail if one path nests the other.
new.validate()?;
Ok(new)
}
}
pub struct AccessibleSplitIter<'t> {
@ -303,4 +339,44 @@ mod tests {
]
);
}
#[test]
fn swapping_works() {
use TermSplit::*;
let t = Vertical {
top: Horizontal {
left: Horizontal {
left: Term { frame: FrameId(42) }.into(),
right: Term { frame: FrameId(64) }.into(),
}
.into(),
right: Term { frame: FrameId(46) }.into(),
}
.into(),
bottom: Vertical {
top: Term { frame: FrameId(43) }.into(),
bottom: Term { frame: FrameId(44) }.into(),
}
.into(),
};
assert_eq!(
t.swap("tl", "b"),
Ok(Vertical {
top: Horizontal {
left: Vertical {
top: Term { frame: FrameId(43) }.into(),
bottom: Term { frame: FrameId(44) }.into(),
}
.into(),
right: Term { frame: FrameId(46) }.into(),
}
.into(),
bottom: Horizontal {
left: Term { frame: FrameId(42) }.into(),
right: Term { frame: FrameId(64) }.into(),
}
.into(),
})
);
}
}