mirror of
https://github.com/zellij-org/zellij.git
synced 2024-11-23 08:57:14 +03:00
Getting back to where we started... (Buggy Resizing)
This commit is contained in:
parent
fe299325eb
commit
f2c5ee44f7
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -271,6 +271,12 @@ version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
|
||||
|
||||
[[package]]
|
||||
name = "cassowary"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.67"
|
||||
@ -2345,6 +2351,7 @@ version = "0.13.0"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1",
|
||||
"async-trait",
|
||||
"cassowary",
|
||||
"daemonize",
|
||||
"insta",
|
||||
"serde_json",
|
||||
|
@ -135,7 +135,7 @@ impl ZellijPlugin for State {
|
||||
fn load(&mut self) {
|
||||
set_selectable(false);
|
||||
set_invisible_borders(true);
|
||||
set_max_height(2);
|
||||
set_fixed_height(2);
|
||||
subscribe(&[EventType::ModeUpdate]);
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ impl ZellijPlugin for State {
|
||||
fn load(&mut self) {
|
||||
set_selectable(false);
|
||||
set_invisible_borders(true);
|
||||
set_max_height(1);
|
||||
set_fixed_height(1);
|
||||
subscribe(&[EventType::TabUpdate, EventType::ModeUpdate]);
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ serde_json = "1.0"
|
||||
unicode-width = "0.1.8"
|
||||
wasmer = "1.0.0"
|
||||
wasmer-wasi = "1.0.0"
|
||||
cassowary = "0.3.0"
|
||||
zellij-utils = { path = "../zellij-utils/", version = "0.13.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -112,6 +112,8 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
||||
daemonize::Daemonize::new()
|
||||
.working_directory(std::env::current_dir().unwrap())
|
||||
.umask(0o077)
|
||||
// FIXME: My cherished `dbg!` was broken, so this is a hack to bring it back
|
||||
.stderr(std::fs::File::create("dbg.log").unwrap())
|
||||
.start()
|
||||
.expect("could not daemonize the server process");
|
||||
|
||||
|
@ -16,8 +16,6 @@ pub(crate) struct PluginPane {
|
||||
pub position_and_size: PositionAndSize,
|
||||
pub position_and_size_override: Option<PositionAndSize>,
|
||||
pub send_plugin_instructions: SenderWithContext<PluginInstruction>,
|
||||
pub max_height: Option<usize>,
|
||||
pub max_width: Option<usize>,
|
||||
pub active_at: Instant,
|
||||
}
|
||||
|
||||
@ -35,8 +33,6 @@ impl PluginPane {
|
||||
position_and_size,
|
||||
position_and_size_override: None,
|
||||
send_plugin_instructions,
|
||||
max_height: None,
|
||||
max_width: None,
|
||||
active_at: Instant::now(),
|
||||
}
|
||||
}
|
||||
@ -95,7 +91,9 @@ impl Pane for PluginPane {
|
||||
fn adjust_input_to_terminal(&self, _input_bytes: Vec<u8>) -> Vec<u8> {
|
||||
unimplemented!() // FIXME: Shouldn't need this implmented?
|
||||
}
|
||||
|
||||
fn position_and_size(&self) -> PositionAndSize {
|
||||
self.position_and_size
|
||||
}
|
||||
fn position_and_size_override(&self) -> Option<PositionAndSize> {
|
||||
self.position_and_size_override
|
||||
}
|
||||
@ -114,11 +112,13 @@ impl Pane for PluginPane {
|
||||
fn set_invisible_borders(&mut self, invisible_borders: bool) {
|
||||
self.invisible_borders = invisible_borders;
|
||||
}
|
||||
fn set_max_height(&mut self, max_height: usize) {
|
||||
self.max_height = Some(max_height);
|
||||
fn set_fixed_height(&mut self, fixed_height: usize) {
|
||||
self.position_and_size.rows = fixed_height;
|
||||
self.position_and_size.rows_fixed = true;
|
||||
}
|
||||
fn set_max_width(&mut self, max_width: usize) {
|
||||
self.max_width = Some(max_width);
|
||||
fn set_fixed_width(&mut self, fixed_width: usize) {
|
||||
self.position_and_size.columns = fixed_width;
|
||||
self.position_and_size.cols_fixed = true;
|
||||
}
|
||||
fn render(&mut self) -> Option<String> {
|
||||
// if self.should_render {
|
||||
@ -204,11 +204,21 @@ impl Pane for PluginPane {
|
||||
fn clear_scroll(&mut self) {
|
||||
unimplemented!()
|
||||
}
|
||||
// FIXME: This need to be reevaluated and deleted if possible.
|
||||
// `max` doesn't make sense when things are fixed...
|
||||
fn max_height(&self) -> Option<usize> {
|
||||
self.max_height
|
||||
if self.position_and_size.rows_fixed {
|
||||
Some(self.position_and_size.rows)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
fn max_width(&self) -> Option<usize> {
|
||||
self.max_width
|
||||
if self.position_and_size.cols_fixed {
|
||||
Some(self.position_and_size.columns)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
fn invisible_borders(&self) -> bool {
|
||||
self.invisible_borders
|
||||
|
@ -27,8 +27,6 @@ pub struct TerminalPane {
|
||||
pub selectable: bool,
|
||||
pub position_and_size: PositionAndSize,
|
||||
pub position_and_size_override: Option<PositionAndSize>,
|
||||
pub max_height: Option<usize>,
|
||||
pub max_width: Option<usize>,
|
||||
pub active_at: Instant,
|
||||
pub colors: Palette,
|
||||
vte_parser: vte::Parser,
|
||||
@ -52,8 +50,7 @@ impl Pane for TerminalPane {
|
||||
self.reflow_lines();
|
||||
}
|
||||
fn change_pos_and_size(&mut self, position_and_size: &PositionAndSize) {
|
||||
self.position_and_size.columns = position_and_size.columns;
|
||||
self.position_and_size.rows = position_and_size.rows;
|
||||
self.position_and_size = *position_and_size;
|
||||
self.reflow_lines();
|
||||
}
|
||||
fn override_size_and_position(&mut self, x: usize, y: usize, size: &PositionAndSize) {
|
||||
@ -119,7 +116,9 @@ impl Pane for TerminalPane {
|
||||
};
|
||||
input_bytes
|
||||
}
|
||||
|
||||
fn position_and_size(&self) -> PositionAndSize {
|
||||
self.position_and_size
|
||||
}
|
||||
fn position_and_size_override(&self) -> Option<PositionAndSize> {
|
||||
self.position_and_size_override
|
||||
}
|
||||
@ -135,21 +134,17 @@ impl Pane for TerminalPane {
|
||||
fn set_selectable(&mut self, selectable: bool) {
|
||||
self.selectable = selectable;
|
||||
}
|
||||
fn set_max_height(&mut self, max_height: usize) {
|
||||
self.max_height = Some(max_height);
|
||||
fn set_fixed_height(&mut self, fixed_height: usize) {
|
||||
self.position_and_size.rows = fixed_height;
|
||||
self.position_and_size.rows_fixed = true;
|
||||
}
|
||||
fn set_max_width(&mut self, max_width: usize) {
|
||||
self.max_width = Some(max_width);
|
||||
fn set_fixed_width(&mut self, fixed_width: usize) {
|
||||
self.position_and_size.columns = fixed_width;
|
||||
self.position_and_size.cols_fixed = true;
|
||||
}
|
||||
fn set_invisible_borders(&mut self, _invisible_borders: bool) {
|
||||
unimplemented!();
|
||||
}
|
||||
fn max_height(&self) -> Option<usize> {
|
||||
self.max_height
|
||||
}
|
||||
fn max_width(&self) -> Option<usize> {
|
||||
self.max_width
|
||||
}
|
||||
fn render(&mut self) -> Option<String> {
|
||||
if self.should_render() {
|
||||
let mut vte_output = String::new();
|
||||
@ -294,8 +289,6 @@ impl TerminalPane {
|
||||
selectable: true,
|
||||
position_and_size,
|
||||
position_and_size_override: None,
|
||||
max_height: None,
|
||||
max_width: None,
|
||||
vte_parser: vte::Parser::new(),
|
||||
active_at: Instant::now(),
|
||||
colors: palette,
|
||||
|
@ -55,7 +55,8 @@ pub(crate) enum ScreenInstruction {
|
||||
CloseFocusedPane,
|
||||
ToggleActiveTerminalFullscreen,
|
||||
SetSelectable(PaneId, bool),
|
||||
SetMaxHeight(PaneId, usize),
|
||||
SetFixedHeight(PaneId, usize),
|
||||
SetFixedWidth(PaneId, usize),
|
||||
SetInvisibleBorders(PaneId, bool),
|
||||
ClosePane(PaneId),
|
||||
ApplyLayout(Layout, Vec<RawFd>),
|
||||
@ -106,7 +107,8 @@ impl From<&ScreenInstruction> for ScreenContext {
|
||||
}
|
||||
ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable,
|
||||
ScreenInstruction::SetInvisibleBorders(..) => ScreenContext::SetInvisibleBorders,
|
||||
ScreenInstruction::SetMaxHeight(..) => ScreenContext::SetMaxHeight,
|
||||
ScreenInstruction::SetFixedHeight(..) => ScreenContext::SetFixedHeight,
|
||||
ScreenInstruction::SetFixedWidth(..) => ScreenContext::SetFixedWidth,
|
||||
ScreenInstruction::ClosePane(_) => ScreenContext::ClosePane,
|
||||
ScreenInstruction::ApplyLayout(..) => ScreenContext::ApplyLayout,
|
||||
ScreenInstruction::NewTab(_) => ScreenContext::NewTab,
|
||||
@ -574,11 +576,17 @@ pub(crate) fn screen_thread_main(
|
||||
.unwrap()
|
||||
.set_pane_selectable(id, selectable);
|
||||
}
|
||||
ScreenInstruction::SetMaxHeight(id, max_height) => {
|
||||
ScreenInstruction::SetFixedHeight(id, fixed_height) => {
|
||||
screen
|
||||
.get_active_tab_mut()
|
||||
.unwrap()
|
||||
.set_pane_max_height(id, max_height);
|
||||
.set_pane_fixed_height(id, fixed_height);
|
||||
}
|
||||
ScreenInstruction::SetFixedWidth(id, fixed_width) => {
|
||||
screen
|
||||
.get_active_tab_mut()
|
||||
.unwrap()
|
||||
.set_pane_fixed_width(id, fixed_width);
|
||||
}
|
||||
ScreenInstruction::SetInvisibleBorders(id, invisible_borders) => {
|
||||
screen
|
||||
|
@ -104,15 +104,15 @@ pub trait Pane {
|
||||
fn handle_pty_bytes(&mut self, bytes: VteBytes);
|
||||
fn cursor_coordinates(&self) -> Option<(usize, usize)>;
|
||||
fn adjust_input_to_terminal(&self, input_bytes: Vec<u8>) -> Vec<u8>;
|
||||
|
||||
fn position_and_size(&self) -> PositionAndSize;
|
||||
fn position_and_size_override(&self) -> Option<PositionAndSize>;
|
||||
fn should_render(&self) -> bool;
|
||||
fn set_should_render(&mut self, should_render: bool);
|
||||
fn selectable(&self) -> bool;
|
||||
fn set_selectable(&mut self, selectable: bool);
|
||||
fn set_invisible_borders(&mut self, invisible_borders: bool);
|
||||
fn set_max_height(&mut self, max_height: usize);
|
||||
fn set_max_width(&mut self, max_width: usize);
|
||||
fn set_fixed_height(&mut self, fixed_height: usize);
|
||||
fn set_fixed_width(&mut self, fixed_width: usize);
|
||||
fn render(&mut self) -> Option<String>;
|
||||
fn pid(&self) -> PaneId;
|
||||
fn reduce_height_down(&mut self, count: usize);
|
||||
@ -178,15 +178,6 @@ pub trait Pane {
|
||||
std::cmp::min(self.x() + self.columns(), other.x() + other.columns())
|
||||
- std::cmp::max(self.x(), other.x())
|
||||
}
|
||||
fn position_and_size(&self) -> PositionAndSize {
|
||||
PositionAndSize {
|
||||
x: self.x(),
|
||||
y: self.y(),
|
||||
columns: self.columns(),
|
||||
rows: self.rows(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
fn can_increase_height_by(&self, increase_by: usize) -> bool {
|
||||
self.max_height()
|
||||
.map(|max_height| self.rows() + increase_by <= max_height)
|
||||
@ -294,12 +285,6 @@ impl Tab {
|
||||
match positions_and_size.next() {
|
||||
Some((_, position_and_size)) => {
|
||||
terminal_pane.reset_size_and_position_override();
|
||||
if let Some(max_rows) = position_and_size.max_rows {
|
||||
terminal_pane.set_max_height(max_rows);
|
||||
}
|
||||
if let Some(max_columns) = position_and_size.max_columns {
|
||||
terminal_pane.set_max_width(max_columns);
|
||||
}
|
||||
terminal_pane.change_pos_and_size(&position_and_size);
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
*pid,
|
||||
@ -317,24 +302,18 @@ impl Tab {
|
||||
}
|
||||
let mut new_pids = new_pids.iter();
|
||||
for (layout, position_and_size) in positions_and_size {
|
||||
// Just a regular terminal
|
||||
// A plugin pane
|
||||
if let Some(plugin) = &layout.plugin {
|
||||
let (pid_tx, pid_rx) = channel();
|
||||
self.senders
|
||||
.send_to_plugin(PluginInstruction::Load(pid_tx, plugin.clone()))
|
||||
.unwrap();
|
||||
let pid = pid_rx.recv().unwrap();
|
||||
let mut new_plugin = PluginPane::new(
|
||||
let new_plugin = PluginPane::new(
|
||||
pid,
|
||||
*position_and_size,
|
||||
self.senders.to_plugin.as_ref().unwrap().clone(),
|
||||
);
|
||||
if let Some(max_rows) = position_and_size.max_rows {
|
||||
new_plugin.set_max_height(max_rows);
|
||||
}
|
||||
if let Some(max_columns) = position_and_size.max_columns {
|
||||
new_plugin.set_max_width(max_columns);
|
||||
}
|
||||
self.panes.insert(PaneId::Plugin(pid), Box::new(new_plugin));
|
||||
// Send an initial mode update to the newly loaded plugin only!
|
||||
self.senders
|
||||
@ -2121,9 +2100,14 @@ impl Tab {
|
||||
pane.set_invisible_borders(invisible_borders);
|
||||
}
|
||||
}
|
||||
pub fn set_pane_max_height(&mut self, id: PaneId, max_height: usize) {
|
||||
pub fn set_pane_fixed_height(&mut self, id: PaneId, fixed_height: usize) {
|
||||
if let Some(pane) = self.panes.get_mut(&id) {
|
||||
pane.set_max_height(max_height);
|
||||
pane.set_fixed_height(fixed_height);
|
||||
}
|
||||
}
|
||||
pub fn set_pane_fixed_width(&mut self, id: PaneId, fixed_width: usize) {
|
||||
if let Some(pane) = self.panes.get_mut(&id) {
|
||||
pane.set_fixed_width(fixed_width);
|
||||
}
|
||||
}
|
||||
pub fn close_pane(&mut self, id: PaneId) {
|
||||
|
@ -19,17 +19,14 @@ fn split_space_to_parts_vertically(
|
||||
|
||||
// First fit in the parameterized sizes
|
||||
for size in sizes {
|
||||
let (columns, max_columns) = match size {
|
||||
let columns = match size {
|
||||
Some(SplitSize::Percent(percent)) => {
|
||||
((max_width as f32 * (percent as f32 / 100.0)) as usize, None)
|
||||
(max_width as f32 * (percent as f32 / 100.0)) as usize
|
||||
} // TODO: round properly
|
||||
Some(SplitSize::Fixed(size)) => (size as usize, Some(size as usize)),
|
||||
Some(SplitSize::Fixed(size)) => size as usize,
|
||||
None => {
|
||||
parts_to_grow.push(current_x_position);
|
||||
(
|
||||
1, // This is grown later on
|
||||
None,
|
||||
)
|
||||
1 // This is grown later on
|
||||
}
|
||||
};
|
||||
split_parts.push(PositionAndSize {
|
||||
@ -37,7 +34,6 @@ fn split_space_to_parts_vertically(
|
||||
y: space_to_split.y,
|
||||
columns,
|
||||
rows: space_to_split.rows,
|
||||
max_columns,
|
||||
..Default::default()
|
||||
});
|
||||
current_width += columns;
|
||||
@ -87,18 +83,14 @@ fn split_space_to_parts_horizontally(
|
||||
let mut parts_to_grow = Vec::new();
|
||||
|
||||
for size in sizes {
|
||||
let (rows, max_rows) = match size {
|
||||
Some(SplitSize::Percent(percent)) => (
|
||||
(max_height as f32 * (percent as f32 / 100.0)) as usize,
|
||||
None,
|
||||
), // TODO: round properly
|
||||
Some(SplitSize::Fixed(size)) => (size as usize, Some(size as usize)),
|
||||
let rows = match size {
|
||||
Some(SplitSize::Percent(percent)) => {
|
||||
(max_height as f32 * (percent as f32 / 100.0)) as usize
|
||||
} // TODO: round properly
|
||||
Some(SplitSize::Fixed(size)) => size as usize,
|
||||
None => {
|
||||
parts_to_grow.push(current_y_position);
|
||||
(
|
||||
1, // This is grown later on
|
||||
None,
|
||||
)
|
||||
1 // This is grown later on
|
||||
}
|
||||
};
|
||||
split_parts.push(PositionAndSize {
|
||||
@ -106,7 +98,6 @@ fn split_space_to_parts_horizontally(
|
||||
y: current_y_position,
|
||||
columns: space_to_split.columns,
|
||||
rows,
|
||||
max_rows,
|
||||
..Default::default()
|
||||
});
|
||||
current_height += rows;
|
||||
|
@ -1,531 +1,247 @@
|
||||
use crate::{os_input_output::ServerOsApi, panes::PaneId, tab::Pane};
|
||||
use cassowary::{
|
||||
strength::{REQUIRED, STRONG},
|
||||
Constraint, Solver, Variable,
|
||||
WeightedRelation::*,
|
||||
};
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::{BTreeMap, HashSet},
|
||||
ops::Not,
|
||||
};
|
||||
use zellij_utils::pane_size::PositionAndSize;
|
||||
|
||||
pub(crate) struct PaneResizer<'a> {
|
||||
const GAP_SIZE: usize = 1; // Panes are separated by this number of rows / columns
|
||||
|
||||
pub struct PaneResizer<'a> {
|
||||
panes: &'a mut BTreeMap<PaneId, Box<dyn Pane>>,
|
||||
vars: BTreeMap<PaneId, (Variable, Variable)>,
|
||||
solver: Solver,
|
||||
os_api: &'a mut Box<dyn ServerOsApi>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum Direction {
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
impl Not for Direction {
|
||||
type Output = Self;
|
||||
|
||||
fn not(self) -> Self::Output {
|
||||
match self {
|
||||
Direction::Horizontal => Direction::Vertical,
|
||||
Direction::Vertical => Direction::Horizontal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct Span {
|
||||
pid: PaneId,
|
||||
direction: Direction,
|
||||
fixed: bool,
|
||||
pos: usize,
|
||||
size: usize,
|
||||
pos_var: Variable,
|
||||
size_var: Variable,
|
||||
}
|
||||
|
||||
// TODO: currently there are some functions here duplicated with Tab
|
||||
// all resizing functions should move here
|
||||
|
||||
// FIXME:
|
||||
// 1. Rounding causes a loss of ratios, I need to store an internal f64 for
|
||||
// each pane as well as the displayed usize and add custom rounding logic.
|
||||
// 2. Vertical resizing doesn't seem to respect the space consumed by the tab
|
||||
// and status bars?
|
||||
// 3. A 2x2 layout and simultaneous vertical + horizontal resizing sometimes
|
||||
// leads to unsolvable constraints? Maybe related to 2 (and possibly 1).
|
||||
// I should sanity-check the `spans_in_boundary()` here!
|
||||
|
||||
impl<'a> PaneResizer<'a> {
|
||||
pub fn new(
|
||||
panes: &'a mut BTreeMap<PaneId, Box<dyn Pane>>,
|
||||
os_api: &'a mut Box<dyn ServerOsApi>,
|
||||
) -> Self {
|
||||
PaneResizer { panes, os_api }
|
||||
let mut vars = BTreeMap::new();
|
||||
for &k in panes.keys() {
|
||||
vars.insert(k, (Variable::new(), Variable::new()));
|
||||
}
|
||||
PaneResizer {
|
||||
panes,
|
||||
vars,
|
||||
solver: Solver::new(),
|
||||
os_api,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resize(
|
||||
&mut self,
|
||||
mut current_size: PositionAndSize,
|
||||
current_size: PositionAndSize,
|
||||
new_size: PositionAndSize,
|
||||
) -> Option<(isize, isize)> {
|
||||
// (column_difference, row_difference)
|
||||
let mut successfully_resized = false;
|
||||
let mut column_difference: isize = 0;
|
||||
let mut row_difference: isize = 0;
|
||||
match new_size.columns.cmp(¤t_size.columns) {
|
||||
Ordering::Greater => {
|
||||
let increase_by = new_size.columns - current_size.columns;
|
||||
if let Some(panes_to_resize) = find_increasable_vertical_chain(
|
||||
&self.panes,
|
||||
increase_by,
|
||||
current_size.columns,
|
||||
current_size.rows,
|
||||
) {
|
||||
self.increase_panes_right_and_push_adjacents_right(
|
||||
panes_to_resize,
|
||||
increase_by,
|
||||
);
|
||||
column_difference = new_size.columns as isize - current_size.columns as isize;
|
||||
current_size.columns =
|
||||
(current_size.columns as isize + column_difference) as usize;
|
||||
successfully_resized = true;
|
||||
};
|
||||
}
|
||||
Ordering::Less => {
|
||||
let reduce_by = current_size.columns - new_size.columns;
|
||||
if let Some(panes_to_resize) = find_reducible_vertical_chain(
|
||||
&self.panes,
|
||||
reduce_by,
|
||||
current_size.columns,
|
||||
current_size.rows,
|
||||
) {
|
||||
self.reduce_panes_left_and_pull_adjacents_left(panes_to_resize, reduce_by);
|
||||
column_difference = new_size.columns as isize - current_size.columns as isize;
|
||||
current_size.columns =
|
||||
(current_size.columns as isize + column_difference) as usize;
|
||||
successfully_resized = true;
|
||||
};
|
||||
}
|
||||
Ordering::Equal => (),
|
||||
let col_delta = new_size.columns as isize - current_size.columns as isize;
|
||||
let row_delta = new_size.rows as isize - current_size.rows as isize;
|
||||
if col_delta != 0 {
|
||||
let spans = self.solve_direction(Direction::Horizontal, new_size.columns)?;
|
||||
self.collapse_spans(&spans);
|
||||
}
|
||||
match new_size.rows.cmp(¤t_size.rows) {
|
||||
Ordering::Greater => {
|
||||
let increase_by = new_size.rows - current_size.rows;
|
||||
if let Some(panes_to_resize) = find_increasable_horizontal_chain(
|
||||
&self.panes,
|
||||
increase_by,
|
||||
current_size.columns,
|
||||
current_size.rows,
|
||||
) {
|
||||
self.increase_panes_down_and_push_down_adjacents(panes_to_resize, increase_by);
|
||||
row_difference = new_size.rows as isize - current_size.rows as isize;
|
||||
current_size.rows = (current_size.rows as isize + row_difference) as usize;
|
||||
successfully_resized = true;
|
||||
};
|
||||
}
|
||||
Ordering::Less => {
|
||||
let reduce_by = current_size.rows - new_size.rows;
|
||||
if let Some(panes_to_resize) = find_reducible_horizontal_chain(
|
||||
&self.panes,
|
||||
reduce_by,
|
||||
current_size.columns,
|
||||
current_size.rows,
|
||||
) {
|
||||
self.reduce_panes_up_and_pull_adjacents_up(panes_to_resize, reduce_by);
|
||||
row_difference = new_size.rows as isize - current_size.rows as isize;
|
||||
current_size.rows = (current_size.rows as isize + row_difference) as usize;
|
||||
successfully_resized = true;
|
||||
};
|
||||
}
|
||||
Ordering::Equal => (),
|
||||
self.solver.reset();
|
||||
if row_delta != 0 {
|
||||
let spans = self.solve_direction(Direction::Vertical, new_size.rows)?;
|
||||
self.collapse_spans(&spans);
|
||||
}
|
||||
if successfully_resized {
|
||||
Some((column_difference, row_difference))
|
||||
Some((col_delta, row_delta))
|
||||
}
|
||||
|
||||
fn solve_direction(&mut self, direction: Direction, space: usize) -> Option<Vec<Span>> {
|
||||
let mut grid = Vec::new();
|
||||
for boundary in self.grid_boundaries(direction) {
|
||||
grid.push(self.spans_in_boundary(direction, boundary));
|
||||
}
|
||||
|
||||
let constraints: Vec<_> = grid
|
||||
.iter()
|
||||
.flat_map(|s| constrain_spans(space, s))
|
||||
.collect();
|
||||
|
||||
// FIXME: This line needs to be restored before merging!
|
||||
//self.solver.add_constraints(&constraints).ok()?;
|
||||
self.solver.add_constraints(&constraints).unwrap();
|
||||
Some(grid.into_iter().flatten().collect())
|
||||
}
|
||||
|
||||
fn grid_boundaries(&self, direction: Direction) -> Vec<(usize, usize)> {
|
||||
// Select the spans running *perpendicular* to the direction of resize
|
||||
let spans: Vec<Span> = self
|
||||
.panes
|
||||
.values()
|
||||
.map(|p| self.get_span(!direction, p.as_ref()))
|
||||
.collect();
|
||||
|
||||
let mut last_edge = 0;
|
||||
let mut bounds = Vec::new();
|
||||
loop {
|
||||
let mut spans_on_edge: Vec<&Span> =
|
||||
spans.iter().filter(|p| p.pos == last_edge).collect();
|
||||
spans_on_edge.sort_unstable_by_key(|s| s.size);
|
||||
if let Some(next) = spans_on_edge.first() {
|
||||
let next_edge = last_edge + next.size;
|
||||
bounds.push((last_edge, next_edge));
|
||||
last_edge = next_edge + GAP_SIZE;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
bounds
|
||||
}
|
||||
|
||||
fn spans_in_boundary(&self, direction: Direction, boundary: (usize, usize)) -> Vec<Span> {
|
||||
let (start, end) = boundary;
|
||||
let bwn = |v| start <= v && v < end;
|
||||
let mut spans: Vec<_> = self
|
||||
.panes
|
||||
.values()
|
||||
.filter(|p| {
|
||||
let s = self.get_span(!direction, p.as_ref());
|
||||
bwn(s.pos) || bwn(s.pos + s.size)
|
||||
})
|
||||
.map(|p| self.get_span(direction, p.as_ref()))
|
||||
.collect();
|
||||
spans.sort_unstable_by_key(|s| s.pos);
|
||||
spans
|
||||
}
|
||||
|
||||
fn get_span(&self, direction: Direction, pane: &dyn Pane) -> Span {
|
||||
let pas = pane.position_and_size();
|
||||
let (pos_var, size_var) = self.vars[&pane.pid()];
|
||||
match direction {
|
||||
Direction::Horizontal => Span {
|
||||
pid: pane.pid(),
|
||||
direction,
|
||||
fixed: pas.cols_fixed,
|
||||
pos: pas.x,
|
||||
size: pas.columns,
|
||||
pos_var,
|
||||
size_var,
|
||||
},
|
||||
Direction::Vertical => Span {
|
||||
pid: pane.pid(),
|
||||
direction,
|
||||
fixed: pas.rows_fixed,
|
||||
pos: pas.y,
|
||||
size: pas.rows,
|
||||
pos_var,
|
||||
size_var,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn collapse_spans(&mut self, spans: &[Span]) {
|
||||
for span in spans {
|
||||
let solver = &self.solver; // Hand-holding the borrow-checker
|
||||
let pane = self.panes.get_mut(&span.pid).unwrap();
|
||||
let fetch_usize = |v| solver.get_value(v).round() as usize;
|
||||
match span.direction {
|
||||
Direction::Horizontal => pane.change_pos_and_size(&PositionAndSize {
|
||||
x: fetch_usize(span.pos_var),
|
||||
columns: fetch_usize(span.size_var),
|
||||
..pane.position_and_size()
|
||||
}),
|
||||
Direction::Vertical => pane.change_pos_and_size(&PositionAndSize {
|
||||
y: fetch_usize(span.pos_var),
|
||||
rows: fetch_usize(span.size_var),
|
||||
..pane.position_and_size()
|
||||
}),
|
||||
}
|
||||
if let PaneId::Terminal(pid) = pane.pid() {
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
pid,
|
||||
pane.columns() as u16,
|
||||
pane.rows() as u16,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn constrain_spans(space: usize, spans: &[Span]) -> HashSet<Constraint> {
|
||||
let mut constraints = HashSet::new();
|
||||
|
||||
// The first span needs to start at 0
|
||||
constraints.insert(spans[0].pos_var | EQ(REQUIRED) | 0.0);
|
||||
|
||||
// Calculating "flexible" space (space not consumed by fixed-size spans)
|
||||
let gap_space = GAP_SIZE * (spans.len() - 1);
|
||||
let old_flex_space = spans
|
||||
.iter()
|
||||
.fold(0, |a, s| if !s.fixed { a + s.size } else { a });
|
||||
let new_flex_space = spans.iter().fold(
|
||||
space - gap_space,
|
||||
|a, s| if s.fixed { a - s.size } else { a },
|
||||
);
|
||||
|
||||
// Keep spans stuck together
|
||||
for pair in spans.windows(2) {
|
||||
let (ls, rs) = (pair[0], pair[1]);
|
||||
constraints
|
||||
.insert((ls.pos_var + ls.size_var + GAP_SIZE as f64) | EQ(REQUIRED) | rs.pos_var);
|
||||
}
|
||||
|
||||
// Try to maintain ratios and lock non-flexible sizes
|
||||
for span in spans {
|
||||
if span.fixed {
|
||||
constraints.insert(span.size_var | EQ(REQUIRED) | span.size as f64);
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
fn reduce_panes_left_and_pull_adjacents_left(
|
||||
&mut self,
|
||||
panes_to_reduce: Vec<PaneId>,
|
||||
reduce_by: usize,
|
||||
) {
|
||||
let mut pulled_panes: HashSet<PaneId> = HashSet::new();
|
||||
for pane_id in panes_to_reduce {
|
||||
let (pane_x, pane_y, pane_columns, pane_rows) = {
|
||||
let pane = self.panes.get(&pane_id).unwrap();
|
||||
(pane.x(), pane.y(), pane.columns(), pane.rows())
|
||||
};
|
||||
let panes_to_pull = self.panes.values_mut().filter(|p| {
|
||||
p.x() > pane_x + pane_columns
|
||||
&& (p.y() <= pane_y && p.y() + p.rows() >= pane_y
|
||||
|| p.y() >= pane_y && p.y() + p.rows() <= pane_y + pane_rows)
|
||||
});
|
||||
for pane in panes_to_pull {
|
||||
if !pulled_panes.contains(&pane.pid()) {
|
||||
pane.pull_left(reduce_by);
|
||||
pulled_panes.insert(pane.pid());
|
||||
}
|
||||
}
|
||||
self.reduce_pane_width_left(&pane_id, reduce_by);
|
||||
}
|
||||
}
|
||||
fn reduce_panes_up_and_pull_adjacents_up(
|
||||
&mut self,
|
||||
panes_to_reduce: Vec<PaneId>,
|
||||
reduce_by: usize,
|
||||
) {
|
||||
let mut pulled_panes: HashSet<PaneId> = HashSet::new();
|
||||
for pane_id in panes_to_reduce {
|
||||
let (pane_x, pane_y, pane_columns, pane_rows) = {
|
||||
let pane = self.panes.get(&pane_id).unwrap();
|
||||
(pane.x(), pane.y(), pane.columns(), pane.rows())
|
||||
};
|
||||
let panes_to_pull = self.panes.values_mut().filter(|p| {
|
||||
p.y() > pane_y + pane_rows
|
||||
&& (p.x() <= pane_x && p.x() + p.columns() >= pane_x
|
||||
|| p.x() >= pane_x && p.x() + p.columns() <= pane_x + pane_columns)
|
||||
});
|
||||
for pane in panes_to_pull {
|
||||
if !pulled_panes.contains(&pane.pid()) {
|
||||
pane.pull_up(reduce_by);
|
||||
pulled_panes.insert(pane.pid());
|
||||
}
|
||||
}
|
||||
self.reduce_pane_height_up(&pane_id, reduce_by);
|
||||
}
|
||||
}
|
||||
fn increase_panes_down_and_push_down_adjacents(
|
||||
&mut self,
|
||||
panes_to_increase: Vec<PaneId>,
|
||||
increase_by: usize,
|
||||
) {
|
||||
let mut pushed_panes: HashSet<PaneId> = HashSet::new();
|
||||
for pane_id in panes_to_increase {
|
||||
let (pane_x, pane_y, pane_columns, pane_rows) = {
|
||||
let pane = self.panes.get(&pane_id).unwrap();
|
||||
(pane.x(), pane.y(), pane.columns(), pane.rows())
|
||||
};
|
||||
let panes_to_push = self.panes.values_mut().filter(|p| {
|
||||
p.y() > pane_y + pane_rows
|
||||
&& (p.x() <= pane_x && p.x() + p.columns() >= pane_x
|
||||
|| p.x() >= pane_x && p.x() + p.columns() <= pane_x + pane_columns)
|
||||
});
|
||||
for pane in panes_to_push {
|
||||
if !pushed_panes.contains(&pane.pid()) {
|
||||
pane.push_down(increase_by);
|
||||
pushed_panes.insert(pane.pid());
|
||||
}
|
||||
}
|
||||
self.increase_pane_height_down(&pane_id, increase_by);
|
||||
}
|
||||
}
|
||||
fn increase_panes_right_and_push_adjacents_right(
|
||||
&mut self,
|
||||
panes_to_increase: Vec<PaneId>,
|
||||
increase_by: usize,
|
||||
) {
|
||||
let mut pushed_panes: HashSet<PaneId> = HashSet::new();
|
||||
for pane_id in panes_to_increase {
|
||||
let (pane_x, pane_y, pane_columns, pane_rows) = {
|
||||
let pane = self.panes.get(&pane_id).unwrap();
|
||||
(pane.x(), pane.y(), pane.columns(), pane.rows())
|
||||
};
|
||||
let panes_to_push = self.panes.values_mut().filter(|p| {
|
||||
p.x() > pane_x + pane_columns
|
||||
&& (p.y() <= pane_y && p.y() + p.rows() >= pane_y
|
||||
|| p.y() >= pane_y && p.y() + p.rows() <= pane_y + pane_rows)
|
||||
});
|
||||
for pane in panes_to_push {
|
||||
if !pushed_panes.contains(&pane.pid()) {
|
||||
pane.push_right(increase_by);
|
||||
pushed_panes.insert(pane.pid());
|
||||
}
|
||||
}
|
||||
self.increase_pane_width_right(&pane_id, increase_by);
|
||||
}
|
||||
}
|
||||
fn reduce_pane_height_up(&mut self, id: &PaneId, count: usize) {
|
||||
let pane = self.panes.get_mut(id).unwrap();
|
||||
pane.reduce_height_up(count);
|
||||
if let PaneId::Terminal(pid) = id {
|
||||
self.os_api
|
||||
.set_terminal_size_using_fd(*pid, pane.columns() as u16, pane.rows() as u16);
|
||||
}
|
||||
}
|
||||
fn increase_pane_height_down(&mut self, id: &PaneId, count: usize) {
|
||||
let pane = self.panes.get_mut(id).unwrap();
|
||||
pane.increase_height_down(count);
|
||||
if let PaneId::Terminal(pid) = pane.pid() {
|
||||
self.os_api
|
||||
.set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16);
|
||||
}
|
||||
}
|
||||
fn increase_pane_width_right(&mut self, id: &PaneId, count: usize) {
|
||||
let pane = self.panes.get_mut(id).unwrap();
|
||||
pane.increase_width_right(count);
|
||||
if let PaneId::Terminal(pid) = pane.pid() {
|
||||
self.os_api
|
||||
.set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16);
|
||||
}
|
||||
}
|
||||
fn reduce_pane_width_left(&mut self, id: &PaneId, count: usize) {
|
||||
let pane = self.panes.get_mut(id).unwrap();
|
||||
pane.reduce_width_left(count);
|
||||
if let PaneId::Terminal(pid) = pane.pid() {
|
||||
self.os_api
|
||||
.set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_next_increasable_horizontal_pane(
|
||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||
right_of: &dyn Pane,
|
||||
increase_by: usize,
|
||||
) -> Option<PaneId> {
|
||||
let next_pane_candidates = panes.values().filter(
|
||||
|p| {
|
||||
p.x() == right_of.x() + right_of.columns() + 1 && p.horizontally_overlaps_with(right_of)
|
||||
}, // TODO: the name here is wrong, it should be vertically_overlaps_with
|
||||
);
|
||||
let resizable_candidates =
|
||||
next_pane_candidates.filter(|p| p.can_increase_height_by(increase_by));
|
||||
resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
|
||||
Some(next_pane) => {
|
||||
let next_pane = panes.get(&next_pane).unwrap();
|
||||
if next_pane.y() < p.y() {
|
||||
next_pane_id
|
||||
} else {
|
||||
Some(p.pid())
|
||||
}
|
||||
}
|
||||
None => Some(p.pid()),
|
||||
})
|
||||
}
|
||||
|
||||
fn find_next_increasable_vertical_pane(
|
||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||
below: &dyn Pane,
|
||||
increase_by: usize,
|
||||
) -> Option<PaneId> {
|
||||
let next_pane_candidates = panes.values().filter(
|
||||
|p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below), // TODO: the name here is wrong, it should be horizontally_overlaps_with
|
||||
);
|
||||
let resizable_candidates =
|
||||
next_pane_candidates.filter(|p| p.can_increase_width_by(increase_by));
|
||||
resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
|
||||
Some(next_pane) => {
|
||||
let next_pane = panes.get(&next_pane).unwrap();
|
||||
if next_pane.x() < p.x() {
|
||||
next_pane_id
|
||||
} else {
|
||||
Some(p.pid())
|
||||
}
|
||||
}
|
||||
None => Some(p.pid()),
|
||||
})
|
||||
}
|
||||
|
||||
fn find_next_reducible_vertical_pane(
|
||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||
below: &dyn Pane,
|
||||
reduce_by: usize,
|
||||
) -> Option<PaneId> {
|
||||
let next_pane_candidates = panes.values().filter(
|
||||
|p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below), // TODO: the name here is wrong, it should be horizontally_overlaps_with
|
||||
);
|
||||
let resizable_candidates = next_pane_candidates.filter(|p| p.can_reduce_width_by(reduce_by));
|
||||
resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
|
||||
Some(next_pane) => {
|
||||
let next_pane = panes.get(&next_pane).unwrap();
|
||||
if next_pane.x() < p.x() {
|
||||
next_pane_id
|
||||
} else {
|
||||
Some(p.pid())
|
||||
}
|
||||
}
|
||||
None => Some(p.pid()),
|
||||
})
|
||||
}
|
||||
|
||||
fn find_next_reducible_horizontal_pane(
|
||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||
right_of: &dyn Pane,
|
||||
reduce_by: usize,
|
||||
) -> Option<PaneId> {
|
||||
let next_pane_candidates = panes.values().filter(
|
||||
|p| {
|
||||
p.x() == right_of.x() + right_of.columns() + 1 && p.horizontally_overlaps_with(right_of)
|
||||
}, // TODO: the name here is wrong, it should be vertically_overlaps_with
|
||||
);
|
||||
let resizable_candidates = next_pane_candidates.filter(|p| p.can_reduce_height_by(reduce_by));
|
||||
resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id {
|
||||
Some(next_pane) => {
|
||||
let next_pane = panes.get(&next_pane).unwrap();
|
||||
if next_pane.y() < p.y() {
|
||||
next_pane_id
|
||||
} else {
|
||||
Some(p.pid())
|
||||
}
|
||||
}
|
||||
None => Some(p.pid()),
|
||||
})
|
||||
}
|
||||
|
||||
fn find_increasable_horizontal_chain(
|
||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||
increase_by: usize,
|
||||
screen_width: usize,
|
||||
screen_height: usize, // TODO: this is the previous size (make this clearer)
|
||||
) -> Option<Vec<PaneId>> {
|
||||
let mut horizontal_coordinate = 0;
|
||||
loop {
|
||||
if horizontal_coordinate == screen_height {
|
||||
return None;
|
||||
}
|
||||
|
||||
match panes
|
||||
.values()
|
||||
.find(|p| p.x() == 0 && p.y() == horizontal_coordinate)
|
||||
{
|
||||
Some(leftmost_pane) => {
|
||||
if !leftmost_pane.can_increase_height_by(increase_by) {
|
||||
horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
|
||||
continue;
|
||||
}
|
||||
let mut panes_to_resize = vec![];
|
||||
let mut current_pane = leftmost_pane;
|
||||
loop {
|
||||
panes_to_resize.push(current_pane.pid());
|
||||
if current_pane.x() + current_pane.columns() == screen_width {
|
||||
return Some(panes_to_resize);
|
||||
}
|
||||
match find_next_increasable_horizontal_pane(
|
||||
panes,
|
||||
current_pane.as_ref(),
|
||||
increase_by,
|
||||
) {
|
||||
Some(next_pane_id) => {
|
||||
current_pane = panes.get(&next_pane_id).unwrap();
|
||||
}
|
||||
None => {
|
||||
horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_increasable_vertical_chain(
|
||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||
increase_by: usize,
|
||||
screen_width: usize,
|
||||
screen_height: usize, // TODO: this is the previous size (make this clearer)
|
||||
) -> Option<Vec<PaneId>> {
|
||||
let mut vertical_coordinate = 0;
|
||||
loop {
|
||||
if vertical_coordinate == screen_width {
|
||||
return None;
|
||||
}
|
||||
|
||||
match panes
|
||||
.values()
|
||||
.find(|p| p.y() == 0 && p.x() == vertical_coordinate)
|
||||
{
|
||||
Some(topmost_pane) => {
|
||||
if !topmost_pane.can_increase_width_by(increase_by) {
|
||||
vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
|
||||
continue;
|
||||
}
|
||||
let mut panes_to_resize = vec![];
|
||||
let mut current_pane = topmost_pane;
|
||||
loop {
|
||||
panes_to_resize.push(current_pane.pid());
|
||||
if current_pane.y() + current_pane.rows() == screen_height {
|
||||
return Some(panes_to_resize);
|
||||
}
|
||||
match find_next_increasable_vertical_pane(
|
||||
panes,
|
||||
current_pane.as_ref(),
|
||||
increase_by,
|
||||
) {
|
||||
Some(next_pane_id) => {
|
||||
current_pane = panes.get(&next_pane_id).unwrap();
|
||||
}
|
||||
None => {
|
||||
vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_reducible_horizontal_chain(
|
||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||
reduce_by: usize,
|
||||
screen_width: usize,
|
||||
screen_height: usize, // TODO: this is the previous size (make this clearer)
|
||||
) -> Option<Vec<PaneId>> {
|
||||
let mut horizontal_coordinate = 0;
|
||||
loop {
|
||||
if horizontal_coordinate == screen_height {
|
||||
return None;
|
||||
}
|
||||
|
||||
match panes
|
||||
.values()
|
||||
.find(|p| p.x() == 0 && p.y() == horizontal_coordinate)
|
||||
{
|
||||
Some(leftmost_pane) => {
|
||||
if !leftmost_pane.can_reduce_height_by(reduce_by) {
|
||||
horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
|
||||
continue;
|
||||
}
|
||||
let mut panes_to_resize = vec![];
|
||||
let mut current_pane = leftmost_pane;
|
||||
loop {
|
||||
panes_to_resize.push(current_pane.pid());
|
||||
if current_pane.x() + current_pane.columns() == screen_width {
|
||||
return Some(panes_to_resize);
|
||||
}
|
||||
match find_next_reducible_horizontal_pane(
|
||||
panes,
|
||||
current_pane.as_ref(),
|
||||
reduce_by,
|
||||
) {
|
||||
Some(next_pane_id) => {
|
||||
current_pane = panes.get(&next_pane_id).unwrap();
|
||||
}
|
||||
None => {
|
||||
horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_reducible_vertical_chain(
|
||||
panes: &BTreeMap<PaneId, Box<dyn Pane>>,
|
||||
increase_by: usize,
|
||||
screen_width: usize,
|
||||
screen_height: usize, // TODO: this is the previous size (make this clearer)
|
||||
) -> Option<Vec<PaneId>> {
|
||||
let mut vertical_coordinate = 0;
|
||||
loop {
|
||||
if vertical_coordinate == screen_width {
|
||||
return None;
|
||||
}
|
||||
|
||||
match panes
|
||||
.values()
|
||||
.find(|p| p.y() == 0 && p.x() == vertical_coordinate)
|
||||
{
|
||||
Some(topmost_pane) => {
|
||||
if !topmost_pane.can_reduce_width_by(increase_by) {
|
||||
vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
|
||||
continue;
|
||||
}
|
||||
let mut panes_to_resize = vec![];
|
||||
let mut current_pane = topmost_pane;
|
||||
loop {
|
||||
panes_to_resize.push(current_pane.pid());
|
||||
if current_pane.y() + current_pane.rows() == screen_height {
|
||||
return Some(panes_to_resize);
|
||||
}
|
||||
match find_next_reducible_vertical_pane(
|
||||
panes,
|
||||
current_pane.as_ref(),
|
||||
increase_by,
|
||||
) {
|
||||
Some(next_pane_id) => {
|
||||
current_pane = panes.get(&next_pane_id).unwrap();
|
||||
}
|
||||
None => {
|
||||
vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
let ratio = span.size as f64 / old_flex_space as f64;
|
||||
constraints.insert((span.size_var / new_flex_space as f64) | EQ(STRONG) | ratio);
|
||||
}
|
||||
}
|
||||
|
||||
// The last pane needs to end at the end of the space
|
||||
let last = spans.last().unwrap();
|
||||
constraints.insert((last.pos_var + last.size_var) | EQ(REQUIRED) | space as f64);
|
||||
|
||||
constraints
|
||||
}
|
||||
|
@ -158,7 +158,8 @@ pub(crate) fn zellij_exports(store: &Store, plugin_env: &PluginEnv) -> ImportObj
|
||||
host_subscribe,
|
||||
host_unsubscribe,
|
||||
host_set_invisible_borders,
|
||||
host_set_max_height,
|
||||
host_set_fixed_height,
|
||||
host_set_fixed_width,
|
||||
host_set_selectable,
|
||||
host_get_plugin_ids,
|
||||
host_open_file,
|
||||
@ -189,13 +190,24 @@ fn host_set_selectable(plugin_env: &PluginEnv, selectable: i32) {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn host_set_max_height(plugin_env: &PluginEnv, max_height: i32) {
|
||||
let max_height = max_height as usize;
|
||||
fn host_set_fixed_height(plugin_env: &PluginEnv, fixed_height: i32) {
|
||||
let fixed_height = fixed_height as usize;
|
||||
plugin_env
|
||||
.senders
|
||||
.send_to_screen(ScreenInstruction::SetMaxHeight(
|
||||
.send_to_screen(ScreenInstruction::SetFixedHeight(
|
||||
PaneId::Plugin(plugin_env.plugin_id),
|
||||
max_height,
|
||||
fixed_height,
|
||||
))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn host_set_fixed_width(plugin_env: &PluginEnv, fixed_width: i32) {
|
||||
let fixed_width = fixed_width as usize;
|
||||
plugin_env
|
||||
.senders
|
||||
.send_to_screen(ScreenInstruction::SetFixedWidth(
|
||||
PaneId::Plugin(plugin_env.plugin_id),
|
||||
fixed_width,
|
||||
))
|
||||
.unwrap()
|
||||
}
|
||||
|
@ -17,8 +17,12 @@ pub fn unsubscribe(event_types: &[EventType]) {
|
||||
|
||||
// Plugin Settings
|
||||
|
||||
pub fn set_max_height(max_height: i32) {
|
||||
unsafe { host_set_max_height(max_height) };
|
||||
pub fn set_fixed_height(fixed_height: i32) {
|
||||
unsafe { host_set_fixed_height(fixed_height) };
|
||||
}
|
||||
|
||||
pub fn set_fixed_width(fixed_width: i32) {
|
||||
unsafe { host_set_fixed_width(fixed_width) };
|
||||
}
|
||||
|
||||
pub fn set_selectable(selectable: bool) {
|
||||
@ -64,7 +68,8 @@ pub fn object_to_stdout(object: &impl Serialize) {
|
||||
extern "C" {
|
||||
fn host_subscribe();
|
||||
fn host_unsubscribe();
|
||||
fn host_set_max_height(max_height: i32);
|
||||
fn host_set_fixed_height(fixed_height: i32);
|
||||
fn host_set_fixed_width(fixed_width: i32);
|
||||
fn host_set_selectable(selectable: i32);
|
||||
fn host_set_invisible_borders(invisible_borders: i32);
|
||||
fn host_get_plugin_ids();
|
||||
|
@ -207,7 +207,8 @@ pub enum ScreenContext {
|
||||
ToggleActiveTerminalFullscreen,
|
||||
SetSelectable,
|
||||
SetInvisibleBorders,
|
||||
SetMaxHeight,
|
||||
SetFixedHeight,
|
||||
SetFixedWidth,
|
||||
ClosePane,
|
||||
ApplyLayout,
|
||||
NewTab,
|
||||
|
@ -9,8 +9,11 @@ pub struct PositionAndSize {
|
||||
pub y: usize,
|
||||
pub rows: usize,
|
||||
pub columns: usize,
|
||||
pub max_rows: Option<usize>,
|
||||
pub max_columns: Option<usize>,
|
||||
// FIXME: Honestly, these shouldn't exist and rows / columns should be enums like:
|
||||
// Dimension::Flex(usize) / Dimension::Fixed(usize), but 400+ compiler errors is more than
|
||||
// I'm in the mood for right now...
|
||||
pub rows_fixed: bool,
|
||||
pub cols_fixed: bool,
|
||||
}
|
||||
|
||||
impl From<Winsize> for PositionAndSize {
|
||||
|
Loading…
Reference in New Issue
Block a user