Added pane resizing

This commit is contained in:
Joshua Barretto 2025-11-20 15:23:39 +00:00
parent 41965454c7
commit 34c7fec4de
2 changed files with 104 additions and 33 deletions

View file

@ -17,36 +17,66 @@ pub enum Dir {
#[derive(Clone, Debug)]
pub enum Action {
Char(char), // Insert a character
Indent(bool), // Indent (indent vs deindent)
Move(Dir, Dist, bool, bool), // Move the cursor (dir, dist, retain_base, word)
PaneMove(Dir), // Move panes
PaneOpen(Dir), // Create a new pane
PaneClose, // Close the current pane
Cancel, // Cancels the current action
Continue, // Continue past an info-only element (like a help screen)
Go, // Search, accept, or select the current option
Yes, // A binary confirmation is answered 'yes'
No, // A binary confirmation is answered 'no'
Quit, // Quit the application
OpenPrompt, // Open the command prompt
Show(Option<String>, String), // Display an optionally titled informational text box to the user
OpenSwitcher, // Open the buffer switcher
OpenOpener(PathBuf), // Open the file opener
OpenFinder(Option<String>), // Open the finder, with the given default query
SwitchBuffer(BufferId), // Switch the current pane to the given buffer
OpenFile(PathBuf, usize), // Open the file (on the given line) and switch the current pane to it
CreateFile(PathBuf), // Create a new file and switch the current pane to it
CommandStart(&'static str), // Start a new command
GotoLine(isize), // Go to the specified file line
BeginSearch(String), // Request to begin a search with the given needle
OpenSearcher(PathBuf, String), // Start a project-wide search with the given location and needle
SelectToken, // Fully select the token under the cursor
SelectAll, // Fully select the entire input
Save, // Save the current buffer
Overwrite, // Save the current buffer, forcefully
Reload, // Reload the current file from disk, losing unsaved changes
Mouse(MouseAction, [isize; 2], bool, usize), // (action, pos, is_ctrl, drag_id)
// Insert a character
Char(char),
// Indent (indent vs deindent)
Indent(bool),
// Move the cursor (dir, dist, retain_base, word)
Move(Dir, Dist, bool, bool),
// Move panes
PaneMove(Dir),
// Create a new pane
PaneOpen(Dir),
// Close the current pane
PaneClose,
// Cancels the current action
Cancel,
// Continue past an info-only element (like a help screen)
Continue,
// Search, accept, or select the current option
Go,
// A binary confirmation is answered 'yes'
Yes,
// A binary confirmation is answered 'no'
No,
// Quit the application
Quit,
// Open the command prompt
OpenPrompt,
// Display an optionally titled informational text box to the user
Show(Option<String>, String),
// Open the buffer switcher
OpenSwitcher,
// Open the file opener
OpenOpener(PathBuf),
// Open the finder, with the given default query
OpenFinder(Option<String>),
// Switch the current pane to the given buffer
SwitchBuffer(BufferId),
// Open the file (on the given line) and switch the current pane to it
OpenFile(PathBuf, usize),
// Create a new file and switch the current pane to it
CreateFile(PathBuf),
// Start a new command
CommandStart(&'static str),
// Go to the specified file line
GotoLine(isize),
// Request to begin a search with the given needle
BeginSearch(String),
// Start a project-wide search with the given location and needle
OpenSearcher(PathBuf, String),
// Fully select the token under the cursor
SelectToken,
// Fully select the entire input
SelectAll,
// Save the current buffer
Save,
// Save the current buffer, forcefully
Overwrite,
// Reload the current file from disk, losing unsaved changes
Reload,
// (action, pos, is_ctrl, drag_id)
Mouse(MouseAction, [isize; 2], bool, usize),
Confirm(String, Box<Self>),
Undo,
Redo,
@ -55,6 +85,8 @@ pub enum Action {
Paste,
Duplicate,
Comment,
// Resize the current pane
PaneResize(i32),
}
/// How far should movement go?
@ -435,6 +467,24 @@ impl RawEvent {
}
}
pub fn to_pane_resize(&self) -> Option<Action> {
match &self.0 {
TerminalEvent::Key(KeyEvent {
code: KeyCode::Char('='),
modifiers: KeyModifiers::ALT,
kind: KeyEventKind::Press,
..
}) => Some(Action::PaneResize(1)),
TerminalEvent::Key(KeyEvent {
code: KeyCode::Char('-'),
modifiers: KeyModifiers::ALT,
kind: KeyEventKind::Press,
..
}) => Some(Action::PaneResize(-1)),
_ => None,
}
}
pub fn to_edit(&self) -> Option<Action> {
match &self.0 {
TerminalEvent::Key(KeyEvent {

View file

@ -87,8 +87,11 @@ pub struct HBox {
selected: usize,
panes: Vec<Pane>,
last_area: Area,
size_weight: usize,
}
const DEFAULT_WEIGHT: usize = 4;
impl Element<()> for HBox {
fn handle(&mut self, state: &mut State, event: Event) -> Result<Resp<()>, Event> {
match event.to_action(|e| {
@ -96,6 +99,7 @@ impl Element<()> for HBox {
.map(Action::PaneMove)
.or_else(|| e.to_pane_open().map(Action::PaneOpen))
.or_else(|| e.to_pane_close())
.or_else(|| e.to_pane_resize())
}) {
Some(Action::PaneMove(Dir::Left)) => {
self.selected = (self.selected + self.panes.len() - 1) % self.panes.len();
@ -142,6 +146,11 @@ impl Element<()> for HBox {
self.selected = new_idx;
Ok(Resp::handled(None))
}
Some(Action::PaneResize(by)) => {
self.size_weight =
(self.size_weight as i32 + by).clamp(1, DEFAULT_WEIGHT.pow(2) as i32) as usize;
Ok(Resp::handled(None))
}
Some(action @ Action::Mouse(m_action, pos, is_ctrl, drag_id)) => {
for (i, pane) in self.panes.iter_mut().enumerate() {
if pane.last_area.contains(pos).is_some() {
@ -212,6 +221,7 @@ impl Panes {
task: None,
}],
last_area: Area::default(),
size_weight: DEFAULT_WEIGHT,
})
.collect(),
last_area: Default::default(),
@ -264,6 +274,7 @@ impl Element for Panes {
task: None,
}],
last_area: Area::default(),
size_weight: DEFAULT_WEIGHT,
},
);
self.selected = new_idx;
@ -321,19 +332,29 @@ impl Element for Panes {
impl Visual for Panes {
fn render(&mut self, state: &State, frame: &mut Rect) {
let n = self.hboxes.len();
let frame_h = frame.size()[1];
let boundary = |i| frame_h * i / n;
if n == 0 {
return;
}
let total_weight = self.hboxes.iter().map(|h| h.size_weight).sum::<usize>();
self.last_area = frame.area();
let mut y0 = 0;
for (i, hbox) in self.hboxes.iter_mut().enumerate() {
let (y0, y1) = (boundary(i), boundary(i + 1));
let y1 = if i == n - 1 {
frame.size()[1]
} else {
y0 + hbox.size_weight * frame.size()[1] / total_weight
};
// Draw pane contents
frame
.rect([0, y0], [frame.size()[0], y1 - y0])
.with_focus(self.selected == i)
.with(|frame| hbox.render(state, frame));
y0 = y1;
}
}
}