mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-22 02:01:55 +07:00
Implement preset window heights
This commit is contained in:
committed by
Ivan Molodetskikh
parent
087a50a19c
commit
d0e624e615
+30
-12
@@ -392,9 +392,11 @@ pub struct Layout {
|
||||
#[knuffel(child, default)]
|
||||
pub border: Border,
|
||||
#[knuffel(child, unwrap(children), default)]
|
||||
pub preset_column_widths: Vec<PresetWidth>,
|
||||
pub preset_column_widths: Vec<PresetSize>,
|
||||
#[knuffel(child)]
|
||||
pub default_column_width: Option<DefaultColumnWidth>,
|
||||
pub default_column_width: Option<DefaultPresetSize>,
|
||||
#[knuffel(child, unwrap(children), default)]
|
||||
pub preset_window_heights: Vec<PresetSize>,
|
||||
#[knuffel(child, unwrap(argument), default)]
|
||||
pub center_focused_column: CenterFocusedColumn,
|
||||
#[knuffel(child)]
|
||||
@@ -416,6 +418,7 @@ impl Default for Layout {
|
||||
always_center_single_column: false,
|
||||
gaps: FloatOrInt(16.),
|
||||
struts: Default::default(),
|
||||
preset_window_heights: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -624,13 +627,13 @@ impl Default for Cursor {
|
||||
}
|
||||
|
||||
#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
|
||||
pub enum PresetWidth {
|
||||
pub enum PresetSize {
|
||||
Proportion(#[knuffel(argument)] f64),
|
||||
Fixed(#[knuffel(argument)] i32),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct DefaultColumnWidth(pub Option<PresetWidth>);
|
||||
pub struct DefaultPresetSize(pub Option<PresetSize>);
|
||||
|
||||
#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq)]
|
||||
pub struct Struts {
|
||||
@@ -898,7 +901,7 @@ pub struct WindowRule {
|
||||
|
||||
// Rules applied at initial configure.
|
||||
#[knuffel(child)]
|
||||
pub default_column_width: Option<DefaultColumnWidth>,
|
||||
pub default_column_width: Option<DefaultPresetSize>,
|
||||
#[knuffel(child, unwrap(argument))]
|
||||
pub open_on_output: Option<String>,
|
||||
#[knuffel(child, unwrap(argument))]
|
||||
@@ -1155,6 +1158,7 @@ pub enum Action {
|
||||
#[knuffel(skip)]
|
||||
ResetWindowHeightById(u64),
|
||||
SwitchPresetColumnWidth,
|
||||
SwitchPresetWindowHeight,
|
||||
MaximizeColumn,
|
||||
SetColumnWidth(#[knuffel(argument, str)] SizeChange),
|
||||
SwitchLayout(#[knuffel(argument, str)] LayoutSwitchTarget),
|
||||
@@ -1266,6 +1270,7 @@ impl From<niri_ipc::Action> for Action {
|
||||
niri_ipc::Action::ResetWindowHeight { id: None } => Self::ResetWindowHeight,
|
||||
niri_ipc::Action::ResetWindowHeight { id: Some(id) } => Self::ResetWindowHeightById(id),
|
||||
niri_ipc::Action::SwitchPresetColumnWidth {} => Self::SwitchPresetColumnWidth,
|
||||
niri_ipc::Action::SwitchPresetWindowHeight {} => Self::SwitchPresetWindowHeight,
|
||||
niri_ipc::Action::MaximizeColumn {} => Self::MaximizeColumn,
|
||||
niri_ipc::Action::SetColumnWidth { change } => Self::SetColumnWidth(change),
|
||||
niri_ipc::Action::SwitchLayout { layout } => Self::SwitchLayout(layout),
|
||||
@@ -1882,7 +1887,7 @@ impl OutputName {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> knuffel::Decode<S> for DefaultColumnWidth
|
||||
impl<S> knuffel::Decode<S> for DefaultPresetSize
|
||||
where
|
||||
S: knuffel::traits::ErrorSpan,
|
||||
{
|
||||
@@ -1902,7 +1907,7 @@ where
|
||||
"expected no more than one child",
|
||||
));
|
||||
}
|
||||
PresetWidth::decode_node(child, ctx).map(Some).map(Self)
|
||||
PresetSize::decode_node(child, ctx).map(Some).map(Self)
|
||||
} else {
|
||||
Ok(Self(None))
|
||||
}
|
||||
@@ -2914,6 +2919,13 @@ mod tests {
|
||||
fixed 1280
|
||||
}
|
||||
|
||||
preset-window-heights {
|
||||
proportion 0.25
|
||||
proportion 0.5
|
||||
fixed 960
|
||||
fixed 1280
|
||||
}
|
||||
|
||||
default-column-width { proportion 0.25; }
|
||||
|
||||
gaps 8
|
||||
@@ -3104,14 +3116,20 @@ mod tests {
|
||||
inactive_gradient: None,
|
||||
},
|
||||
preset_column_widths: vec![
|
||||
PresetWidth::Proportion(0.25),
|
||||
PresetWidth::Proportion(0.5),
|
||||
PresetWidth::Fixed(960),
|
||||
PresetWidth::Fixed(1280),
|
||||
PresetSize::Proportion(0.25),
|
||||
PresetSize::Proportion(0.5),
|
||||
PresetSize::Fixed(960),
|
||||
PresetSize::Fixed(1280),
|
||||
],
|
||||
default_column_width: Some(DefaultColumnWidth(Some(PresetWidth::Proportion(
|
||||
default_column_width: Some(DefaultPresetSize(Some(PresetSize::Proportion(
|
||||
0.25,
|
||||
)))),
|
||||
preset_window_heights: vec![
|
||||
PresetSize::Proportion(0.25),
|
||||
PresetSize::Proportion(0.5),
|
||||
PresetSize::Fixed(960),
|
||||
PresetSize::Fixed(1280),
|
||||
],
|
||||
gaps: FloatOrInt(8.),
|
||||
struts: Struts {
|
||||
left: FloatOrInt(1.),
|
||||
|
||||
@@ -350,6 +350,8 @@ pub enum Action {
|
||||
},
|
||||
/// Switch between preset column widths.
|
||||
SwitchPresetColumnWidth {},
|
||||
/// Switch between preset window heights.
|
||||
SwitchPresetWindowHeight {},
|
||||
/// Toggle the maximized state of the focused column.
|
||||
MaximizeColumn {},
|
||||
/// Change the width of the focused column.
|
||||
|
||||
@@ -1035,6 +1035,9 @@ impl State {
|
||||
Action::SwitchPresetColumnWidth => {
|
||||
self.niri.layout.toggle_width();
|
||||
}
|
||||
Action::SwitchPresetWindowHeight => {
|
||||
self.niri.layout.toggle_window_height();
|
||||
}
|
||||
Action::CenterColumn => {
|
||||
self.niri.layout.center_column();
|
||||
// FIXME: granular
|
||||
|
||||
+71
-13
@@ -34,7 +34,9 @@ use std::mem;
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
|
||||
use niri_config::{CenterFocusedColumn, Config, FloatOrInt, Struts, Workspace as WorkspaceConfig};
|
||||
use niri_config::{
|
||||
CenterFocusedColumn, Config, FloatOrInt, PresetSize, Struts, Workspace as WorkspaceConfig,
|
||||
};
|
||||
use niri_ipc::SizeChange;
|
||||
use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement;
|
||||
use smithay::backend::renderer::element::Id;
|
||||
@@ -238,11 +240,12 @@ pub struct Options {
|
||||
pub center_focused_column: CenterFocusedColumn,
|
||||
pub always_center_single_column: bool,
|
||||
/// Column widths that `toggle_width()` switches between.
|
||||
pub preset_widths: Vec<ColumnWidth>,
|
||||
pub preset_column_widths: Vec<ColumnWidth>,
|
||||
/// Initial width for new columns.
|
||||
pub default_width: Option<ColumnWidth>,
|
||||
pub default_column_width: Option<ColumnWidth>,
|
||||
/// Window height that `toggle_window_height()` switches between.
|
||||
pub preset_window_heights: Vec<PresetSize>,
|
||||
pub animations: niri_config::Animations,
|
||||
|
||||
// Debug flags.
|
||||
pub disable_resize_throttling: bool,
|
||||
pub disable_transactions: bool,
|
||||
@@ -257,15 +260,20 @@ impl Default for Options {
|
||||
border: Default::default(),
|
||||
center_focused_column: Default::default(),
|
||||
always_center_single_column: false,
|
||||
preset_widths: vec![
|
||||
preset_column_widths: vec![
|
||||
ColumnWidth::Proportion(1. / 3.),
|
||||
ColumnWidth::Proportion(0.5),
|
||||
ColumnWidth::Proportion(2. / 3.),
|
||||
],
|
||||
default_width: None,
|
||||
default_column_width: None,
|
||||
animations: Default::default(),
|
||||
disable_resize_throttling: false,
|
||||
disable_transactions: false,
|
||||
preset_window_heights: vec![
|
||||
PresetSize::Proportion(1. / 3.),
|
||||
PresetSize::Proportion(0.5),
|
||||
PresetSize::Proportion(2. / 3.),
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -273,21 +281,26 @@ impl Default for Options {
|
||||
impl Options {
|
||||
fn from_config(config: &Config) -> Self {
|
||||
let layout = &config.layout;
|
||||
let preset_column_widths = &layout.preset_column_widths;
|
||||
|
||||
let preset_widths = if preset_column_widths.is_empty() {
|
||||
Options::default().preset_widths
|
||||
let preset_column_widths = if layout.preset_column_widths.is_empty() {
|
||||
Options::default().preset_column_widths
|
||||
} else {
|
||||
preset_column_widths
|
||||
layout
|
||||
.preset_column_widths
|
||||
.iter()
|
||||
.copied()
|
||||
.map(ColumnWidth::from)
|
||||
.collect()
|
||||
};
|
||||
let preset_window_heights = if layout.preset_window_heights.is_empty() {
|
||||
Options::default().preset_window_heights
|
||||
} else {
|
||||
layout.preset_window_heights.clone()
|
||||
};
|
||||
|
||||
// Missing default_column_width maps to Some(ColumnWidth::Proportion(0.5)),
|
||||
// while present, but empty, maps to None.
|
||||
let default_width = layout
|
||||
let default_column_width = layout
|
||||
.default_column_width
|
||||
.as_ref()
|
||||
.map(|w| w.0.map(ColumnWidth::from))
|
||||
@@ -300,11 +313,12 @@ impl Options {
|
||||
border: layout.border,
|
||||
center_focused_column: layout.center_focused_column,
|
||||
always_center_single_column: layout.always_center_single_column,
|
||||
preset_widths,
|
||||
default_width,
|
||||
preset_column_widths,
|
||||
default_column_width,
|
||||
animations: config.animations.clone(),
|
||||
disable_resize_throttling: config.debug.disable_resize_throttling,
|
||||
disable_transactions: config.debug.disable_transactions,
|
||||
preset_window_heights,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1937,6 +1951,13 @@ impl<W: LayoutElement> Layout<W> {
|
||||
monitor.toggle_width();
|
||||
}
|
||||
|
||||
pub fn toggle_window_height(&mut self) {
|
||||
let Some(monitor) = self.active_monitor() else {
|
||||
return;
|
||||
};
|
||||
monitor.toggle_window_height();
|
||||
}
|
||||
|
||||
pub fn toggle_full_width(&mut self) {
|
||||
let Some(monitor) = self.active_monitor() else {
|
||||
return;
|
||||
@@ -3027,6 +3048,7 @@ mod tests {
|
||||
},
|
||||
MoveColumnToOutput(#[proptest(strategy = "1..=5u8")] u8),
|
||||
SwitchPresetColumnWidth,
|
||||
SwitchPresetWindowHeight,
|
||||
MaximizeColumn,
|
||||
SetColumnWidth(#[proptest(strategy = "arbitrary_size_change()")] SizeChange),
|
||||
SetWindowHeight {
|
||||
@@ -3453,6 +3475,7 @@ mod tests {
|
||||
Op::MoveWorkspaceDown => layout.move_workspace_down(),
|
||||
Op::MoveWorkspaceUp => layout.move_workspace_up(),
|
||||
Op::SwitchPresetColumnWidth => layout.toggle_width(),
|
||||
Op::SwitchPresetWindowHeight => layout.toggle_window_height(),
|
||||
Op::MaximizeColumn => layout.toggle_full_width(),
|
||||
Op::SetColumnWidth(change) => layout.set_column_width(change),
|
||||
Op::SetWindowHeight { id, change } => {
|
||||
@@ -4415,6 +4438,41 @@ mod tests {
|
||||
layout.verify_invariants();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preset_height_change_removes_preset() {
|
||||
let mut config = Config::default();
|
||||
config.layout.preset_window_heights = vec![PresetSize::Fixed(1), PresetSize::Fixed(2)];
|
||||
|
||||
let mut layout = Layout::new(&config);
|
||||
|
||||
let ops = [
|
||||
Op::AddOutput(1),
|
||||
Op::AddWindow {
|
||||
id: 1,
|
||||
bbox: Rectangle::from_loc_and_size((0, 0), (1280, 200)),
|
||||
min_max_size: Default::default(),
|
||||
},
|
||||
Op::AddWindow {
|
||||
id: 2,
|
||||
bbox: Rectangle::from_loc_and_size((0, 0), (1280, 200)),
|
||||
min_max_size: Default::default(),
|
||||
},
|
||||
Op::ConsumeOrExpelWindowLeft,
|
||||
Op::SwitchPresetWindowHeight,
|
||||
Op::SwitchPresetWindowHeight,
|
||||
];
|
||||
for op in ops {
|
||||
op.apply(&mut layout);
|
||||
}
|
||||
|
||||
// Leave only one.
|
||||
config.layout.preset_window_heights = vec![PresetSize::Fixed(1)];
|
||||
|
||||
layout.update_config(&config);
|
||||
|
||||
layout.verify_invariants();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn working_area_starts_at_physical_pixel() {
|
||||
let struts = Struts {
|
||||
|
||||
@@ -740,6 +740,10 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
self.active_workspace().toggle_width();
|
||||
}
|
||||
|
||||
pub fn toggle_window_height(&mut self) {
|
||||
self.active_workspace().toggle_window_height();
|
||||
}
|
||||
|
||||
pub fn toggle_full_width(&mut self) {
|
||||
self.active_workspace().toggle_full_width();
|
||||
}
|
||||
|
||||
+126
-26
@@ -4,7 +4,7 @@ use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
|
||||
use niri_config::{
|
||||
CenterFocusedColumn, OutputName, PresetWidth, Struts, Workspace as WorkspaceConfig,
|
||||
CenterFocusedColumn, OutputName, PresetSize, Struts, Workspace as WorkspaceConfig,
|
||||
};
|
||||
use niri_ipc::SizeChange;
|
||||
use ordered_float::NotNan;
|
||||
@@ -202,16 +202,17 @@ pub enum ColumnWidth {
|
||||
|
||||
/// Height of a window in a column.
|
||||
///
|
||||
/// Proportional height is intentionally omitted. With column widths you frequently want e.g. two
|
||||
/// columns side-by-side with 50% width each, and you want them to remain this way when moving to a
|
||||
/// differently sized monitor. Windows in a column, however, already auto-size to fill the available
|
||||
/// height, giving you this behavior. The only reason to set a different window height, then, is
|
||||
/// when you want something in the window to fit exactly, e.g. to fit 30 lines in a terminal, which
|
||||
/// corresponds to the `Fixed` variant.
|
||||
/// Every window but one in a column must be `Auto`-sized so that the total height can add up to
|
||||
/// the workspace height. Resizing a window converts all other windows to `Auto`, weighted to
|
||||
/// preserve their visual heights at the moment of the conversion.
|
||||
///
|
||||
/// This does not preclude the usual set of binds to set or resize a window proportionally. Just,
|
||||
/// they are converted to, and stored as fixed height right away, so that once you resize a window
|
||||
/// to fit the desired content, it can never become smaller than that when moving between monitors.
|
||||
/// In contrast to column widths, proportional height changes are converted to, and stored as,
|
||||
/// fixed height right away. With column widths you frequently want e.g. two columns side-by-side
|
||||
/// with 50% width each, and you want them to remain this way when moving to a differently sized
|
||||
/// monitor. Windows in a column, however, already auto-size to fill the available height, giving
|
||||
/// you this behavior. The main reason to set a different window height, then, is when you want
|
||||
/// something in the window to fit exactly, e.g. to fit 30 lines in a terminal, which corresponds
|
||||
/// to the `Fixed` variant.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum WindowHeight {
|
||||
/// Automatically computed *tile* height, distributed across the column according to weights.
|
||||
@@ -221,6 +222,16 @@ pub enum WindowHeight {
|
||||
Auto { weight: f64 },
|
||||
/// Fixed *window* height in logical pixels.
|
||||
Fixed(f64),
|
||||
/// One of the *tile* height proportion presets.
|
||||
Preset(usize),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ResolvedSize {
|
||||
/// Size of the tile including borders.
|
||||
Tile(f64),
|
||||
/// Size of the window excluding borders.
|
||||
Window(f64),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -319,21 +330,32 @@ impl ColumnWidth {
|
||||
ColumnWidth::Proportion(proportion) => {
|
||||
(view_width - options.gaps) * proportion - options.gaps
|
||||
}
|
||||
ColumnWidth::Preset(idx) => options.preset_widths[idx].resolve(options, view_width),
|
||||
ColumnWidth::Preset(idx) => {
|
||||
options.preset_column_widths[idx].resolve(options, view_width)
|
||||
}
|
||||
ColumnWidth::Fixed(width) => width,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PresetWidth> for ColumnWidth {
|
||||
fn from(value: PresetWidth) -> Self {
|
||||
impl From<PresetSize> for ColumnWidth {
|
||||
fn from(value: PresetSize) -> Self {
|
||||
match value {
|
||||
PresetWidth::Proportion(p) => Self::Proportion(p.clamp(0., 10000.)),
|
||||
PresetWidth::Fixed(f) => Self::Fixed(f64::from(f.clamp(1, 100000))),
|
||||
PresetSize::Proportion(p) => Self::Proportion(p.clamp(0., 10000.)),
|
||||
PresetSize::Fixed(f) => Self::Fixed(f64::from(f.clamp(1, 100000))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_preset_size(preset: PresetSize, options: &Options, view_size: f64) -> ResolvedSize {
|
||||
match preset {
|
||||
PresetSize::Proportion(proportion) => {
|
||||
ResolvedSize::Tile((view_size - options.gaps) * proportion - options.gaps)
|
||||
}
|
||||
PresetSize::Fixed(width) => ResolvedSize::Window(f64::from(width)),
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowHeight {
|
||||
const fn auto_1() -> Self {
|
||||
Self::Auto { weight: 1. }
|
||||
@@ -650,7 +672,7 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
match default_width {
|
||||
Some(Some(width)) => Some(width),
|
||||
Some(None) => None,
|
||||
None => self.options.default_width,
|
||||
None => self.options.default_column_width,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2351,6 +2373,17 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
cancel_resize_for_column(&mut self.interactive_resize, col);
|
||||
}
|
||||
|
||||
pub fn toggle_window_height(&mut self) {
|
||||
if self.columns.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let col = &mut self.columns[self.active_column_idx];
|
||||
col.toggle_window_height(None, true);
|
||||
|
||||
cancel_resize_for_column(&mut self.interactive_resize, col);
|
||||
}
|
||||
|
||||
pub fn set_fullscreen(&mut self, window: &W::Id, is_fullscreen: bool) {
|
||||
let (mut col_idx, tile_idx) = self
|
||||
.columns
|
||||
@@ -3016,12 +3049,18 @@ impl<W: LayoutElement> Column<W> {
|
||||
let mut update_sizes = false;
|
||||
|
||||
// If preset widths changed, make our width non-preset.
|
||||
if self.options.preset_widths != options.preset_widths {
|
||||
if self.options.preset_column_widths != options.preset_column_widths {
|
||||
if let ColumnWidth::Preset(idx) = self.width {
|
||||
self.width = self.options.preset_widths[idx];
|
||||
self.width = self.options.preset_column_widths[idx];
|
||||
}
|
||||
}
|
||||
|
||||
// If preset heights changed, make our heights non-preset.
|
||||
if self.options.preset_window_heights != options.preset_window_heights {
|
||||
self.convert_heights_to_auto();
|
||||
update_sizes = true;
|
||||
}
|
||||
|
||||
if self.options.gaps != options.gaps {
|
||||
update_sizes = true;
|
||||
}
|
||||
@@ -3220,6 +3259,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
|
||||
let width = width.resolve(&self.options, self.working_area.size.w);
|
||||
let width = f64::max(f64::min(width, max_width), min_width);
|
||||
let height = self.working_area.size.h;
|
||||
|
||||
// Compute the tile heights. Start by converting window heights to tile heights.
|
||||
let mut heights = zip(&self.tiles, &self.data)
|
||||
@@ -3228,8 +3268,19 @@ impl<W: LayoutElement> Column<W> {
|
||||
WindowHeight::Fixed(height) => {
|
||||
WindowHeight::Fixed(tile.tile_height_for_window_height(height.round().max(1.)))
|
||||
}
|
||||
WindowHeight::Preset(idx) => {
|
||||
let preset = self.options.preset_window_heights[idx];
|
||||
let window_height = match resolve_preset_size(preset, &self.options, height) {
|
||||
ResolvedSize::Tile(h) => tile.window_height_for_tile_height(h),
|
||||
ResolvedSize::Window(h) => h,
|
||||
};
|
||||
let tile_height = tile
|
||||
.tile_height_for_window_height(window_height.round().clamp(1., 100000.));
|
||||
WindowHeight::Fixed(tile_height)
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let gaps_left = self.options.gaps * (self.tiles.len() + 1) as f64;
|
||||
let mut height_left = self.working_area.size.h - gaps_left;
|
||||
let mut auto_tiles_left = self.tiles.len();
|
||||
@@ -3283,6 +3334,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
let weight = match *h {
|
||||
WindowHeight::Auto { weight } => weight,
|
||||
WindowHeight::Fixed(_) => continue,
|
||||
WindowHeight::Preset(_) => unreachable!(),
|
||||
};
|
||||
let factor = weight / total_weight_2;
|
||||
|
||||
@@ -3321,6 +3373,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
let weight = match *h {
|
||||
WindowHeight::Auto { weight } => weight,
|
||||
WindowHeight::Fixed(_) => continue,
|
||||
WindowHeight::Preset(_) => unreachable!(),
|
||||
};
|
||||
let factor = weight / total_weight;
|
||||
|
||||
@@ -3456,6 +3509,10 @@ impl<W: LayoutElement> Column<W> {
|
||||
);
|
||||
found_fixed = true;
|
||||
}
|
||||
|
||||
if let WindowHeight::Preset(idx) = data.height {
|
||||
assert!(self.options.preset_window_heights.len() > idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3467,11 +3524,11 @@ impl<W: LayoutElement> Column<W> {
|
||||
};
|
||||
|
||||
let idx = match width {
|
||||
ColumnWidth::Preset(idx) => (idx + 1) % self.options.preset_widths.len(),
|
||||
ColumnWidth::Preset(idx) => (idx + 1) % self.options.preset_column_widths.len(),
|
||||
_ => {
|
||||
let current = self.width();
|
||||
self.options
|
||||
.preset_widths
|
||||
.preset_column_widths
|
||||
.iter()
|
||||
.position(|prop| {
|
||||
let resolved = prop.resolve(&self.options, self.working_area.size.w);
|
||||
@@ -3500,7 +3557,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
let current_px = width.resolve(&self.options, self.working_area.size.w);
|
||||
|
||||
let current = match width {
|
||||
ColumnWidth::Preset(idx) => self.options.preset_widths[idx],
|
||||
ColumnWidth::Preset(idx) => self.options.preset_column_widths[idx],
|
||||
current => current,
|
||||
};
|
||||
|
||||
@@ -3551,17 +3608,18 @@ impl<W: LayoutElement> Column<W> {
|
||||
let tile_idx = tile_idx.unwrap_or(self.active_tile_idx);
|
||||
|
||||
// Start by converting all heights to automatic, since only one window in the column can be
|
||||
// fixed-height. If the current tile is already fixed, however, we can skip that step.
|
||||
// Which is not only for optimization, but also preserves automatic weights in case one
|
||||
// window is resized in such a way that other windows hit their min size, and then back.
|
||||
if !matches!(self.data[tile_idx].height, WindowHeight::Fixed(_)) {
|
||||
// non-auto-height. If the current tile is already non-auto, however, we can skip that
|
||||
// step. Which is not only for optimization, but also preserves automatic weights in case
|
||||
// one window is resized in such a way that other windows hit their min size, and then
|
||||
// back.
|
||||
if matches!(self.data[tile_idx].height, WindowHeight::Auto { .. }) {
|
||||
self.convert_heights_to_auto();
|
||||
}
|
||||
|
||||
let current = self.data[tile_idx].height;
|
||||
let tile = &self.tiles[tile_idx];
|
||||
let current_window_px = match current {
|
||||
WindowHeight::Auto { .. } => tile.window_size().h,
|
||||
WindowHeight::Auto { .. } | WindowHeight::Preset(_) => tile.window_size().h,
|
||||
WindowHeight::Fixed(height) => height,
|
||||
};
|
||||
let current_tile_px = tile.tile_height_for_window_height(current_window_px);
|
||||
@@ -3631,6 +3689,48 @@ impl<W: LayoutElement> Column<W> {
|
||||
self.update_tile_sizes(animate);
|
||||
}
|
||||
|
||||
fn toggle_window_height(&mut self, tile_idx: Option<usize>, animate: bool) {
|
||||
let tile_idx = tile_idx.unwrap_or(self.active_tile_idx);
|
||||
|
||||
// Start by converting all heights to automatic, since only one window in the column can be
|
||||
// non-auto-height. If the current tile is already non-auto, however, we can skip that
|
||||
// step. Which is not only for optimization, but also preserves automatic weights in case
|
||||
// one window is resized in such a way that other windows hit their min size, and then
|
||||
// back.
|
||||
if matches!(self.data[tile_idx].height, WindowHeight::Auto { .. }) {
|
||||
self.convert_heights_to_auto();
|
||||
}
|
||||
|
||||
let preset_idx = match self.data[tile_idx].height {
|
||||
WindowHeight::Preset(idx) => (idx + 1) % self.options.preset_window_heights.len(),
|
||||
_ => {
|
||||
let current = self.data[tile_idx].size.h;
|
||||
let tile = &self.tiles[tile_idx];
|
||||
self.options
|
||||
.preset_window_heights
|
||||
.iter()
|
||||
.copied()
|
||||
.position(|preset| {
|
||||
let resolved =
|
||||
resolve_preset_size(preset, &self.options, self.working_area.size.h);
|
||||
let window_height = match resolved {
|
||||
ResolvedSize::Tile(h) => tile.window_height_for_tile_height(h),
|
||||
ResolvedSize::Window(h) => h,
|
||||
};
|
||||
let resolved = tile.tile_height_for_window_height(
|
||||
window_height.round().clamp(1., 100000.),
|
||||
);
|
||||
|
||||
// Some allowance for fractional scaling purposes.
|
||||
current + 1. < resolved
|
||||
})
|
||||
.unwrap_or(0)
|
||||
}
|
||||
};
|
||||
self.data[tile_idx].height = WindowHeight::Preset(preset_idx);
|
||||
self.update_tile_sizes(animate);
|
||||
}
|
||||
|
||||
/// Converts all heights in the column to automatic, preserving the apparent heights.
|
||||
///
|
||||
/// All weights are recomputed to preserve the current tile heights while "centering" the
|
||||
|
||||
Reference in New Issue
Block a user